From baf570efa59d2a1bb3a0271bee0effd348436efd Mon Sep 17 00:00:00 2001 From: "t.jung" Date: Tue, 25 Apr 2017 23:31:03 +0200 Subject: [PATCH] Pure Texture to Sampled Texture Transform Adds a transformation step to the post processing step. Two modes are available: 1) keep - Keeps samplers, textures and sampled textures as is 2) transform pure texture into sampled texture and remove pure samplers - removes all pure samplers - transforms all pure textures into its sampled counter part Change-Id: If54972e8052961db66c23f4b7e719d363cf6edbd --- .../spv.texture.sampler.transform.frag.out | 38 ++++++++++++++++ Test/spv.texture.sampler.transform.frag | 13 ++++++ glslang/Include/Types.h | 1 + glslang/MachineIndependent/Intermediate.cpp | 45 +++++++++++++++++++ glslang/MachineIndependent/ShaderLang.cpp | 1 + .../MachineIndependent/localintermediate.h | 7 ++- glslang/Public/ShaderLang.h | 9 ++++ gtests/Spv.FromFile.cpp | 18 ++++++++ gtests/TestFixture.h | 29 +++++++++++- 9 files changed, 159 insertions(+), 2 deletions(-) create mode 100644 Test/baseResults/spv.texture.sampler.transform.frag.out create mode 100644 Test/spv.texture.sampler.transform.frag diff --git a/Test/baseResults/spv.texture.sampler.transform.frag.out b/Test/baseResults/spv.texture.sampler.transform.frag.out new file mode 100644 index 00000000..198c4819 --- /dev/null +++ b/Test/baseResults/spv.texture.sampler.transform.frag.out @@ -0,0 +1,38 @@ +spv.texture.sampler.transform.frag +Warning, version 440 is not yet complete; most version-specific features are present, but some are missing. + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 19 + + Capability Shader + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "main" 9 16 + ExecutionMode 4 OriginUpperLeft + Source GLSL 440 + Name 4 "main" + Name 9 "color" + Name 12 "tex" + Name 16 "coord" + Decorate 12(tex) DescriptorSet 0 + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeFloat 32 + 7: TypeVector 6(float) 4 + 8: TypePointer Output 7(fvec4) + 9(color): 8(ptr) Variable Output + 10: TypeImage 6(float) 2D sampled format:Unknown + 11: TypePointer UniformConstant 10 + 12(tex): 11(ptr) Variable UniformConstant + 14: TypeVector 6(float) 2 + 15: TypePointer Input 14(fvec2) + 16(coord): 15(ptr) Variable Input + 4(main): 2 Function None 3 + 5: Label + 13: 10 Load 12(tex) + 17: 14(fvec2) Load 16(coord) + 18: 7(fvec4) ImageSampleImplicitLod 13 17 + Store 9(color) 18 + Return + FunctionEnd diff --git a/Test/spv.texture.sampler.transform.frag b/Test/spv.texture.sampler.transform.frag new file mode 100644 index 00000000..872d9b04 --- /dev/null +++ b/Test/spv.texture.sampler.transform.frag @@ -0,0 +1,13 @@ +#version 440 + +uniform sampler smp; +uniform texture2D tex; + +in vec2 coord; + +out vec4 color; + +void main() +{ + color = texture(sampler2D(tex, smp), coord); +} diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h index 6bcbe408..5eac73e0 100644 --- a/glslang/Include/Types.h +++ b/glslang/Include/Types.h @@ -1310,6 +1310,7 @@ public: virtual TBasicType getBasicType() const { return basicType; } virtual const TSampler& getSampler() const { return sampler; } + virtual TSampler& getSampler() { return sampler; } virtual TQualifier& getQualifier() { return qualifier; } virtual const TQualifier& getQualifier() const { return qualifier; } diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp index 663e30c6..ad9720c0 100644 --- a/glslang/MachineIndependent/Intermediate.cpp +++ b/glslang/MachineIndependent/Intermediate.cpp @@ -1776,6 +1776,14 @@ bool TIntermediate::postProcess(TIntermNode* root, EShLanguage /*language*/) // Propagate 'noContraction' label in backward from 'precise' variables. glslang::PropagateNoContraction(*this); + switch (textureSamplerTransformMode) { + case EShTexSampTransKeep: + break; + case EShTexSampTransUpgradeTextureRemoveSampler: + performTextureUpgradeAndSamplerRemovalTransformation(root); + break; + } + return true; } @@ -2943,4 +2951,41 @@ bool TIntermediate::specConstantPropagates(const TIntermTyped& node1, const TInt (node2.getType().getQualifier().isSpecConstant() && node1.getType().getQualifier().isConstant()); } +struct TextureUpgradeAndSamplerRemovalTransform : public TIntermTraverser { + bool visitAggregate(TVisit, TIntermAggregate* ag) override { + using namespace std; + TIntermSequence& seq = ag->getSequence(); + // remove pure sampler variables + TIntermSequence::iterator newEnd = remove_if(seq.begin(), seq.end(), [](TIntermNode* node) { + TIntermSymbol* symbol = node->getAsSymbolNode(); + if (!symbol) + return false; + + return (symbol->getBasicType() == EbtSampler && symbol->getType().getSampler().isPureSampler()); + }); + seq.erase(newEnd, seq.end()); + // replace constructors with sampler/textures + // update textures into sampled textures + for_each(seq.begin(), seq.end(), [](TIntermNode*& node) { + TIntermSymbol* symbol = node->getAsSymbolNode(); + if (!symbol) { + TIntermAggregate *constructor = node->getAsAggregate(); + if (constructor && constructor->getOp() == EOpConstructTextureSampler) { + if (!constructor->getSequence().empty()) + node = constructor->getSequence()[0]; + } + } else if (symbol->getBasicType() == EbtSampler && symbol->getType().getSampler().isTexture()) { + symbol->getWritableType().getSampler().combined = true; + } + }); + return true; + } +}; + +void TIntermediate::performTextureUpgradeAndSamplerRemovalTransformation(TIntermNode* root) +{ + TextureUpgradeAndSamplerRemovalTransform transform; + root->traverse(&transform); +} + } // end namespace glslang diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp index 1f7c005f..d563bc2c 100644 --- a/glslang/MachineIndependent/ShaderLang.cpp +++ b/glslang/MachineIndependent/ShaderLang.cpp @@ -1578,6 +1578,7 @@ void TShader::setHlslIoMapping(bool hlslIoMap) { intermediate->setHlslI void TShader::setFlattenUniformArrays(bool flatten) { intermediate->setFlattenUniformArrays(flatten); } void TShader::setNoStorageFormat(bool useUnknownFormat) { intermediate->setNoStorageFormat(useUnknownFormat); } void TShader::setResourceSetBinding(const std::vector& base) { intermediate->setResourceSetBinding(base); } +void TShader::setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode) { intermediate->setTextureSamplerTransformMode(mode); } // // Turn the shader strings into a parse tree in the TIntermediate. diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h index 444d341d..8f6fdffe 100644 --- a/glslang/MachineIndependent/localintermediate.h +++ b/glslang/MachineIndependent/localintermediate.h @@ -182,7 +182,8 @@ public: useUnknownFormat(false), hlslOffsets(false), useStorageBuffer(false), - hlslIoMapping(false) + hlslIoMapping(false), + textureSamplerTransformMode(EShTexSampTransKeep) { localSize[0] = 1; localSize[1] = 1; @@ -233,6 +234,7 @@ public: bool usingStorageBuffer() const { return useStorageBuffer; } void setHlslIoMapping(bool b) { hlslIoMapping = b; } bool usingHlslIoMapping() { return hlslIoMapping; } + void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode) { textureSamplerTransformMode = mode; } void setVersion(int v) { version = v; } int getVersion() const { return version; } @@ -472,6 +474,7 @@ protected: void pushSelector(TIntermSequence&, const TVectorSelector&, const TSourceLoc&); void pushSelector(TIntermSequence&, const TMatrixSelector&, const TSourceLoc&); bool specConstantPropagates(const TIntermTyped&, const TIntermTyped&); + void performTextureUpgradeAndSamplerRemovalTransformation(TIntermNode* root); const EShLanguage language; // stage, known at construction time EShSource source; // source language, known a bit later @@ -536,6 +539,8 @@ protected: std::unordered_set usedConstantId; // specialization constant ids used std::set semanticNameSet; + EShTextureSamplerTransformMode textureSamplerTransformMode; + private: void operator=(TIntermediate&); // prevent assignments }; diff --git a/glslang/Public/ShaderLang.h b/glslang/Public/ShaderLang.h index 3be66d43..9cd999ba 100644 --- a/glslang/Public/ShaderLang.h +++ b/glslang/Public/ShaderLang.h @@ -134,6 +134,14 @@ typedef enum { EShOptFull, // Optimizations that will take more time } EShOptimizationLevel; +// +// Texture and Sampler transformation mode. +// +typedef enum { + EShTexSampTransKeep, // keep textures and samplers as is (default) + EShTexSampTransUpgradeTextureRemoveSampler, // change texture w/o embeded sampler into sampled texture and throw away all samplers +} EShTextureSamplerTransformMode; + // // Message choices for what errors and warnings are given. // @@ -313,6 +321,7 @@ public: void setHlslIoMapping(bool hlslIoMap); void setFlattenUniformArrays(bool flatten); void setNoStorageFormat(bool useUnknownFormat); + void setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode); // Interface to #include handlers. // diff --git a/gtests/Spv.FromFile.cpp b/gtests/Spv.FromFile.cpp index fd9c585c..b551d646 100644 --- a/gtests/Spv.FromFile.cpp +++ b/gtests/Spv.FromFile.cpp @@ -75,6 +75,7 @@ using CompileVulkanToSpirvTestAMD = GlslangTest<::testing::TestWithParam>; #endif +using CompileUpgradeTextureToSampledTextureAndDropSamplersTest = GlslangTest<::testing::TestWithParam>; // Compiling GLSL to SPIR-V under Vulkan semantics. Expected to successfully // generate SPIR-V. @@ -172,6 +173,15 @@ TEST_P(CompileVulkanToSpirvTestNV, FromFile) } #endif +TEST_P(CompileUpgradeTextureToSampledTextureAndDropSamplersTest, FromFile) +{ + loadCompileUpgradeTextureToSampledTextureAndDropSamplersAndCheck(GlobalTestSettings.testRoot, + GetParam(), + Source::GLSL, + Semantics::Vulkan, + Target::Spv); +} + // clang-format off INSTANTIATE_TEST_CASE_P( Glsl, CompileVulkanToSpirvTest, @@ -407,6 +417,14 @@ INSTANTIATE_TEST_CASE_P( FileNameAsCustomTestSuffix ); #endif + +INSTANTIATE_TEST_CASE_P( + Glsl, CompileUpgradeTextureToSampledTextureAndDropSamplersTest, + ::testing::ValuesIn(std::vector({ + "spv.texture.sampler.transform.frag", + })), + FileNameAsCustomTestSuffix +); // clang-format on } // anonymous namespace diff --git a/gtests/TestFixture.h b/gtests/TestFixture.h index c00645be..a503b5fb 100644 --- a/gtests/TestFixture.h +++ b/gtests/TestFixture.h @@ -197,12 +197,14 @@ public: GlslangResult compileAndLink( const std::string shaderName, const std::string& code, const std::string& entryPointName, EShMessages controls, - bool flattenUniformArrays = false) + bool flattenUniformArrays = false, + EShTextureSamplerTransformMode texSampTransMode = EShTexSampTransKeep) { const EShLanguage kind = GetShaderStage(GetSuffix(shaderName)); glslang::TShader shader(kind); shader.setAutoMapLocations(true); + shader.setTextureSamplerTransformMode(texSampTransMode); shader.setFlattenUniformArrays(flattenUniformArrays); bool success = compile(&shader, code, entryPointName, controls); @@ -570,6 +572,31 @@ public: expectedErrorFname); } + void loadCompileUpgradeTextureToSampledTextureAndDropSamplersAndCheck(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, false, EShTexSampTransUpgradeTextureRemoveSampler); + + // Generate the hybrid output in the way of glslangValidator. + std::ostringstream stream; + outputResultToStream(&stream, result, controls); + + checkEqAndUpdateIfRequested(expectedOutput, stream.str(), + expectedOutputFname); + } + private: const int defaultVersion; const EProfile defaultProfile; -- 2.34.1