Commit 4455258a by John Kessenich Committed by GitHub

HLSL: Merge pull request #515 from steve-lunarg/flatten-uniform-array

HLSL: Flatten uniform arrays
parents 6714bcc2 e0b9debd
...@@ -81,6 +81,7 @@ enum TOptions { ...@@ -81,6 +81,7 @@ enum TOptions {
EOptionReadHlsl = (1 << 17), EOptionReadHlsl = (1 << 17),
EOptionCascadingErrors = (1 << 18), EOptionCascadingErrors = (1 << 18),
EOptionAutoMapBindings = (1 << 19), EOptionAutoMapBindings = (1 << 19),
EOptionFlattenUniformArrays = (1 << 20),
}; };
// //
...@@ -285,6 +286,10 @@ void ProcessArguments(int argc, char* argv[]) ...@@ -285,6 +286,10 @@ void ProcessArguments(int argc, char* argv[])
lowerword == "auto-map-binding" || lowerword == "auto-map-binding" ||
lowerword == "amb") { lowerword == "amb") {
Options |= EOptionAutoMapBindings; Options |= EOptionAutoMapBindings;
} else if (lowerword == "flatten-uniform-arrays" || // synonyms
lowerword == "flatten-uniform-array" ||
lowerword == "fua") {
Options |= EOptionFlattenUniformArrays;
} else { } else {
usage(); usage();
} }
...@@ -407,6 +412,10 @@ void ProcessArguments(int argc, char* argv[]) ...@@ -407,6 +412,10 @@ void ProcessArguments(int argc, char* argv[])
// -o or -x makes no sense if there is no target binary // -o or -x makes no sense if there is no target binary
if (binaryFileName && (Options & EOptionSpv) == 0) if (binaryFileName && (Options & EOptionSpv) == 0)
Error("no binary generation requested (e.g., -V)"); Error("no binary generation requested (e.g., -V)");
if ((Options & EOptionFlattenUniformArrays) != 0 &&
(Options & EOptionReadHlsl) == 0)
Error("uniform array flattening only valid when compiling HLSL source.");
} }
// //
...@@ -532,6 +541,7 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits) ...@@ -532,6 +541,7 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
shader->setShiftSamplerBinding(baseSamplerBinding[compUnit.stage]); shader->setShiftSamplerBinding(baseSamplerBinding[compUnit.stage]);
shader->setShiftTextureBinding(baseTextureBinding[compUnit.stage]); shader->setShiftTextureBinding(baseTextureBinding[compUnit.stage]);
shader->setShiftUboBinding(baseUboBinding[compUnit.stage]); shader->setShiftUboBinding(baseUboBinding[compUnit.stage]);
shader->setFlattenUniformArrays((Options & EOptionFlattenUniformArrays) != 0);
if (Options & EOptionAutoMapBindings) if (Options & EOptionAutoMapBindings)
shader->setAutoMapBindings(true); shader->setAutoMapBindings(true);
...@@ -930,6 +940,9 @@ void usage() ...@@ -930,6 +940,9 @@ void usage()
" --auto-map-bindings automatically bind uniform variables without\n" " --auto-map-bindings automatically bind uniform variables without\n"
" explicit bindings.\n" " explicit bindings.\n"
" --amb synonym for --auto-map-bindings\n" " --amb synonym for --auto-map-bindings\n"
"\n"
" --flatten-uniform-arrays flatten uniform array references to scalars\n"
" --fua synonym for --flatten-uniform-arrays\n"
); );
exit(EFailUsage); exit(EFailUsage);
......
// uniform Texture1D g_tex3[3][2]; // TODO: legal in HLSL, but we don't handle it yet.
uniform Texture1D g_tex[3];
uniform Texture1D g_tex_explicit[3] : register(t1);
SamplerState g_samp[3];
SamplerState g_samp_explicit[3] : register(s5);
uniform float3x3 g_mats[4];
uniform float3x3 g_mats_explicit[4] : register(b10);
uniform float g_floats[4];
// uniform float g_floats[4] = { 10, 11, 12, 13 }; // TODO: ... add when initializer lists can be flattened.
float4 TestFn1()
{
return g_tex[1].Sample(g_samp[1], 0.2);
}
float4 TestFn2(Texture1D l_tex[3], SamplerState l_samp[3])
{
return l_tex[2].Sample(l_samp[2], 0.2);
}
int not_flattened_a[5] = { 1, 2, 3, 4, 5 };
struct PS_OUTPUT { float4 color : SV_Target0; };
void main(out PS_OUTPUT ps_output)
{
// test flattening for local assignment initialization
SamplerState local_sampler_array[3] = g_samp;
Texture1D local_texture_array[3] = g_tex;
float local_float_array[4] = g_floats;
ps_output.color = TestFn1() + TestFn2(g_tex, g_samp);
}
...@@ -424,6 +424,11 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt ...@@ -424,6 +424,11 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt
// opaque types can be passed to functions // opaque types can be passed to functions
if (op == EOpFunction) if (op == EOpFunction)
break; break;
// HLSL can assign samplers directly (no constructor)
if (source == EShSourceHlsl && node->getBasicType() == EbtSampler)
break;
// samplers can get assigned via a sampler constructor // samplers can get assigned via a sampler constructor
// (well, not yet, but code in the rest of this function is ready for it) // (well, not yet, but code in the rest of this function is ready for it)
if (node->getBasicType() == EbtSampler && op == EOpAssign && if (node->getBasicType() == EbtSampler && op == EOpAssign &&
......
...@@ -1493,6 +1493,8 @@ void TShader::setShiftSamplerBinding(unsigned int base) { intermediate->setShift ...@@ -1493,6 +1493,8 @@ void TShader::setShiftSamplerBinding(unsigned int base) { intermediate->setShift
void TShader::setShiftTextureBinding(unsigned int base) { intermediate->setShiftTextureBinding(base); } void TShader::setShiftTextureBinding(unsigned int base) { intermediate->setShiftTextureBinding(base); }
void TShader::setShiftUboBinding(unsigned int base) { intermediate->setShiftUboBinding(base); } void TShader::setShiftUboBinding(unsigned int base) { intermediate->setShiftUboBinding(base); }
void TShader::setAutoMapBindings(bool map) { intermediate->setAutoMapBindings(map); } void TShader::setAutoMapBindings(bool map) { intermediate->setAutoMapBindings(map); }
void TShader::setFlattenUniformArrays(bool flatten) { intermediate->setFlattenUniformArrays(flatten); }
// //
// Turn the shader strings into a parse tree in the TIntermediate. // Turn the shader strings into a parse tree in the TIntermediate.
// //
......
...@@ -145,7 +145,8 @@ public: ...@@ -145,7 +145,8 @@ public:
shiftSamplerBinding(0), shiftSamplerBinding(0),
shiftTextureBinding(0), shiftTextureBinding(0),
shiftUboBinding(0), shiftUboBinding(0),
autoMapBindings(false) autoMapBindings(false),
flattenUniformArrays(false)
{ {
localSize[0] = 1; localSize[0] = 1;
localSize[1] = 1; localSize[1] = 1;
...@@ -176,6 +177,8 @@ public: ...@@ -176,6 +177,8 @@ public:
unsigned int getShiftUboBinding() const { return shiftUboBinding; } unsigned int getShiftUboBinding() const { return shiftUboBinding; }
void setAutoMapBindings(bool map) { autoMapBindings = map; } void setAutoMapBindings(bool map) { autoMapBindings = map; }
bool getAutoMapBindings() const { return autoMapBindings; } bool getAutoMapBindings() const { return autoMapBindings; }
void setFlattenUniformArrays(bool flatten) { flattenUniformArrays = flatten; }
bool getFlattenUniformArrays() const { return flattenUniformArrays; }
void setVersion(int v) { version = v; } void setVersion(int v) { version = v; }
int getVersion() const { return version; } int getVersion() const { return version; }
...@@ -385,6 +388,7 @@ protected: ...@@ -385,6 +388,7 @@ protected:
unsigned int shiftTextureBinding; unsigned int shiftTextureBinding;
unsigned int shiftUboBinding; unsigned int shiftUboBinding;
bool autoMapBindings; bool autoMapBindings;
bool flattenUniformArrays;
EProfile profile; EProfile profile;
int version; int version;
......
...@@ -304,6 +304,7 @@ public: ...@@ -304,6 +304,7 @@ public:
void setShiftTextureBinding(unsigned int base); void setShiftTextureBinding(unsigned int base);
void setShiftUboBinding(unsigned int base); void setShiftUboBinding(unsigned int base);
void setAutoMapBindings(bool map); void setAutoMapBindings(bool map);
void setFlattenUniformArrays(bool flatten);
// Interface to #include handlers. // Interface to #include handlers.
// //
......
...@@ -58,6 +58,7 @@ std::string FileNameAsCustomTestSuffix( ...@@ -58,6 +58,7 @@ std::string FileNameAsCustomTestSuffix(
} }
using HlslCompileTest = GlslangTest<::testing::TestWithParam<FileNameEntryPointPair>>; using HlslCompileTest = GlslangTest<::testing::TestWithParam<FileNameEntryPointPair>>;
using HlslCompileAndFlattenTest = GlslangTest<::testing::TestWithParam<FileNameEntryPointPair>>;
// Compiling HLSL to SPIR-V under Vulkan semantics. Expected to successfully // Compiling HLSL to SPIR-V under Vulkan semantics. Expected to successfully
// generate both AST and SPIR-V. // generate both AST and SPIR-V.
...@@ -68,6 +69,13 @@ TEST_P(HlslCompileTest, FromFile) ...@@ -68,6 +69,13 @@ TEST_P(HlslCompileTest, FromFile)
Target::BothASTAndSpv, GetParam().entryPoint); Target::BothASTAndSpv, GetParam().entryPoint);
} }
TEST_P(HlslCompileAndFlattenTest, FromFile)
{
loadFileCompileFlattenUniformsAndCheck(GLSLANG_TEST_DIRECTORY, GetParam().fileName,
Source::HLSL, Semantics::Vulkan,
Target::BothASTAndSpv, GetParam().entryPoint);
}
// clang-format off // clang-format off
INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P(
ToSpirv, HlslCompileTest, ToSpirv, HlslCompileTest,
...@@ -181,5 +189,15 @@ INSTANTIATE_TEST_CASE_P( ...@@ -181,5 +189,15 @@ INSTANTIATE_TEST_CASE_P(
); );
// clang-format on // clang-format on
// clang-format off
INSTANTIATE_TEST_CASE_P(
ToSpirv, HlslCompileAndFlattenTest,
::testing::ValuesIn(std::vector<FileNameEntryPointPair>{
{"hlsl.array.flatten.frag", "main"},
}),
FileNameAsCustomTestSuffix
);
// clang-format on
} // anonymous namespace } // anonymous namespace
} // namespace glslangtest } // namespace glslangtest
...@@ -204,11 +204,14 @@ public: ...@@ -204,11 +204,14 @@ public:
// the result and returns disassembly text. // the result and returns disassembly text.
GlslangResult compileAndLink( GlslangResult compileAndLink(
const std::string shaderName, const std::string& code, const std::string shaderName, const std::string& code,
const std::string& entryPointName, EShMessages controls) const std::string& entryPointName, EShMessages controls,
bool flattenUniformArrays = false)
{ {
const EShLanguage kind = GetShaderStage(GetSuffix(shaderName)); const EShLanguage kind = GetShaderStage(GetSuffix(shaderName));
glslang::TShader shader(kind); glslang::TShader shader(kind);
shader.setFlattenUniformArrays(flattenUniformArrays);
bool success = compile(&shader, code, entryPointName, controls); bool success = compile(&shader, code, entryPointName, controls);
glslang::TProgram program; glslang::TProgram program;
...@@ -395,6 +398,32 @@ public: ...@@ -395,6 +398,32 @@ public:
expectedOutputFname); expectedOutputFname);
} }
void loadFileCompileFlattenUniformsAndCheck(const std::string& testDir,
const std::string& testName,
Source source,
Semantics semantics,
Target target,
const std::string& entryPointName="")
{
const std::string inputFname = testDir + "/" + testName;
const std::string expectedOutputFname =
testDir + "/baseResults/" + testName + ".out";
std::string input, expectedOutput;
tryLoadFile(inputFname, "input", &input);
tryLoadFile(expectedOutputFname, "expected output", &expectedOutput);
const EShMessages controls = DeriveOptions(source, semantics, target);
GlslangResult result = compileAndLink(testName, input, entryPointName, controls, true);
// Generate the hybrid output in the way of glslangValidator.
std::ostringstream stream;
outputResultToStream(&stream, result, controls);
checkEqAndUpdateIfRequested(expectedOutput, stream.str(),
expectedOutputFname);
}
void loadFileCompileIoMapAndCheck(const std::string& testDir, void loadFileCompileIoMapAndCheck(const std::string& testDir,
const std::string& testName, const std::string& testName,
Source source, Source source,
......
...@@ -83,9 +83,6 @@ public: ...@@ -83,9 +83,6 @@ public:
TIntermTyped* handleBinaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* left, TIntermTyped* right); TIntermTyped* handleBinaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* left, TIntermTyped* right);
TIntermTyped* handleUnaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* childNode); TIntermTyped* handleUnaryMath(const TSourceLoc&, const char* str, TOperator op, TIntermTyped* childNode);
TIntermTyped* handleDotDereference(const TSourceLoc&, TIntermTyped* base, const TString& field); TIntermTyped* handleDotDereference(const TSourceLoc&, TIntermTyped* base, const TString& field);
bool shouldFlatten(const TType&) const;
void flatten(const TVariable& variable);
TIntermTyped* flattenAccess(TIntermTyped* base, int member);
void assignLocations(TVariable& variable); void assignLocations(TVariable& variable);
TFunction& handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype); TFunction& handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype);
TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&); TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&);
...@@ -181,6 +178,15 @@ protected: ...@@ -181,6 +178,15 @@ protected:
const char* szExtraInfoFormat, TPrefixType prefix, const char* szExtraInfoFormat, TPrefixType prefix,
va_list args); va_list args);
// Array and struct flattening
bool shouldFlatten(const TType& type) const { return shouldFlattenIO(type) || shouldFlattenUniform(type); }
TIntermTyped* flattenAccess(TIntermTyped* base, int member);
bool shouldFlattenIO(const TType&) const;
bool shouldFlattenUniform(const TType&) const;
void flatten(const TSourceLoc& loc, const TVariable& variable);
void flattenStruct(const TVariable& variable);
void flattenArray(const TSourceLoc& loc, const TVariable& variable);
// Current state of parsing // Current state of parsing
struct TPragma contextPragma; struct TPragma contextPragma;
int loopNestingLevel; // 0 if outside all loops int loopNestingLevel; // 0 if outside all loops
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment