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 {
EOptionReadHlsl = (1 << 17),
EOptionCascadingErrors = (1 << 18),
EOptionAutoMapBindings = (1 << 19),
EOptionFlattenUniformArrays = (1 << 20),
};
//
......@@ -285,6 +286,10 @@ void ProcessArguments(int argc, char* argv[])
lowerword == "auto-map-binding" ||
lowerword == "amb") {
Options |= EOptionAutoMapBindings;
} else if (lowerword == "flatten-uniform-arrays" || // synonyms
lowerword == "flatten-uniform-array" ||
lowerword == "fua") {
Options |= EOptionFlattenUniformArrays;
} else {
usage();
}
......@@ -407,6 +412,10 @@ void ProcessArguments(int argc, char* argv[])
// -o or -x makes no sense if there is no target binary
if (binaryFileName && (Options & EOptionSpv) == 0)
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)
shader->setShiftSamplerBinding(baseSamplerBinding[compUnit.stage]);
shader->setShiftTextureBinding(baseTextureBinding[compUnit.stage]);
shader->setShiftUboBinding(baseUboBinding[compUnit.stage]);
shader->setFlattenUniformArrays((Options & EOptionFlattenUniformArrays) != 0);
if (Options & EOptionAutoMapBindings)
shader->setAutoMapBindings(true);
......@@ -930,6 +940,9 @@ void usage()
" --auto-map-bindings automatically bind uniform variables without\n"
" explicit 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);
......
// 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
// opaque types can be passed to functions
if (op == EOpFunction)
break;
// HLSL can assign samplers directly (no constructor)
if (source == EShSourceHlsl && node->getBasicType() == EbtSampler)
break;
// samplers can get assigned via a sampler constructor
// (well, not yet, but code in the rest of this function is ready for it)
if (node->getBasicType() == EbtSampler && op == EOpAssign &&
......
......@@ -1493,6 +1493,8 @@ void TShader::setShiftSamplerBinding(unsigned int base) { intermediate->setShift
void TShader::setShiftTextureBinding(unsigned int base) { intermediate->setShiftTextureBinding(base); }
void TShader::setShiftUboBinding(unsigned int base) { intermediate->setShiftUboBinding(base); }
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.
//
......
......@@ -145,7 +145,8 @@ public:
shiftSamplerBinding(0),
shiftTextureBinding(0),
shiftUboBinding(0),
autoMapBindings(false)
autoMapBindings(false),
flattenUniformArrays(false)
{
localSize[0] = 1;
localSize[1] = 1;
......@@ -176,6 +177,8 @@ public:
unsigned int getShiftUboBinding() const { return shiftUboBinding; }
void setAutoMapBindings(bool map) { autoMapBindings = map; }
bool getAutoMapBindings() const { return autoMapBindings; }
void setFlattenUniformArrays(bool flatten) { flattenUniformArrays = flatten; }
bool getFlattenUniformArrays() const { return flattenUniformArrays; }
void setVersion(int v) { version = v; }
int getVersion() const { return version; }
......@@ -385,6 +388,7 @@ protected:
unsigned int shiftTextureBinding;
unsigned int shiftUboBinding;
bool autoMapBindings;
bool flattenUniformArrays;
EProfile profile;
int version;
......
......@@ -304,6 +304,7 @@ public:
void setShiftTextureBinding(unsigned int base);
void setShiftUboBinding(unsigned int base);
void setAutoMapBindings(bool map);
void setFlattenUniformArrays(bool flatten);
// Interface to #include handlers.
//
......
......@@ -58,6 +58,7 @@ std::string FileNameAsCustomTestSuffix(
}
using HlslCompileTest = GlslangTest<::testing::TestWithParam<FileNameEntryPointPair>>;
using HlslCompileAndFlattenTest = GlslangTest<::testing::TestWithParam<FileNameEntryPointPair>>;
// Compiling HLSL to SPIR-V under Vulkan semantics. Expected to successfully
// generate both AST and SPIR-V.
......@@ -68,6 +69,13 @@ TEST_P(HlslCompileTest, FromFile)
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
INSTANTIATE_TEST_CASE_P(
ToSpirv, HlslCompileTest,
......@@ -181,5 +189,15 @@ INSTANTIATE_TEST_CASE_P(
);
// 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
} // namespace glslangtest
......@@ -204,11 +204,14 @@ public:
// the result and returns disassembly text.
GlslangResult compileAndLink(
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));
glslang::TShader shader(kind);
shader.setFlattenUniformArrays(flattenUniformArrays);
bool success = compile(&shader, code, entryPointName, controls);
glslang::TProgram program;
......@@ -395,6 +398,32 @@ public:
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,
const std::string& testName,
Source source,
......
......@@ -83,9 +83,6 @@ public:
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* 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);
TFunction& handleFunctionDeclarator(const TSourceLoc&, TFunction& function, bool prototype);
TIntermAggregate* handleFunctionDefinition(const TSourceLoc&, TFunction&);
......@@ -181,6 +178,15 @@ protected:
const char* szExtraInfoFormat, TPrefixType prefix,
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
struct TPragma contextPragma;
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