diff --git a/StandAlone/StandAlone.cpp b/StandAlone/StandAlone.cpp index 0ac72d3ba..377e7cb33 100644 --- a/StandAlone/StandAlone.cpp +++ b/StandAlone/StandAlone.cpp @@ -164,6 +164,7 @@ const char* shaderStageName = nullptr; std::array baseSamplerBinding; std::array baseTextureBinding; +std::array baseImageBinding; std::array baseUboBinding; // @@ -252,6 +253,7 @@ void ProcessArguments(int argc, char* argv[]) { baseSamplerBinding.fill(0); baseTextureBinding.fill(0); + baseImageBinding.fill(0); baseUboBinding.fill(0); ExecutableName = argv[0]; @@ -279,6 +281,10 @@ void ProcessArguments(int argc, char* argv[]) lowerword == "shift-texture-binding" || lowerword == "stb") { ProcessBindingBase(argc, argv, baseTextureBinding); + } else if (lowerword == "shift-image-bindings" || // synonyms + lowerword == "shift-image-binding" || + lowerword == "sib") { + ProcessBindingBase(argc, argv, baseImageBinding); } else if (lowerword == "shift-ubo-bindings" || // synonyms lowerword == "shift-ubo-binding" || lowerword == "sub") { @@ -544,6 +550,7 @@ void CompileAndLinkShaderUnits(std::vector compUnits) shader->setShiftSamplerBinding(baseSamplerBinding[compUnit.stage]); shader->setShiftTextureBinding(baseTextureBinding[compUnit.stage]); + shader->setShiftImageBinding(baseImageBinding[compUnit.stage]); shader->setShiftUboBinding(baseUboBinding[compUnit.stage]); shader->setFlattenUniformArrays((Options & EOptionFlattenUniformArrays) != 0); shader->setNoStorageFormat((Options & EOptionNoStorageFormat) != 0); @@ -941,6 +948,9 @@ void usage() " --shift-texture-binding [stage] num set base binding number for textures\n" " --stb [stage] num synonym for --shift-texture-binding\n" "\n" + " --shift-image-binding [stage] num set base binding number for images (uav)\n" + " --sib [stage] num synonym for --shift-image-binding\n" + "\n" " --shift-UBO-binding [stage] num set base binding number for UBOs\n" " --sub [stage] num synonym for --shift-UBO-binding\n" "\n" diff --git a/Test/baseResults/hlsl.rw.register.frag.out b/Test/baseResults/hlsl.rw.register.frag.out new file mode 100644 index 000000000..b2d8f2990 --- /dev/null +++ b/Test/baseResults/hlsl.rw.register.frag.out @@ -0,0 +1,158 @@ +hlsl.rw.register.frag +Shader version: 450 +gl_FragCoord origin is upper left +0:? Sequence +0:11 Function Definition: main( (temp structure{temp 4-component vector of float Color}) +0:11 Function Parameters: +0:? Sequence +0:12 Sequence +0:12 move second child to first child (temp float) +0:12 'r00' (temp float) +0:12 imageLoad (temp float) +0:12 'g_tTex1df1' (layout(binding=2 r32f ) uniform image1D) +0:12 Constant: +0:12 0 (const int) +0:13 Sequence +0:13 move second child to first child (temp uint) +0:13 'r01' (temp uint) +0:13 imageLoad (temp uint) +0:13 'g_tBuf1du1' (layout(binding=3 r32ui ) uniform uimageBuffer) +0:13 Constant: +0:13 0 (const int) +0:16 move second child to first child (temp 4-component vector of float) +0:16 Color: direct index for structure (temp 4-component vector of float) +0:16 'psout' (temp structure{temp 4-component vector of float Color}) +0:16 Constant: +0:16 0 (const int) +0:16 Constant: +0:16 1.000000 +0:16 1.000000 +0:16 1.000000 +0:16 1.000000 +0:17 Sequence +0:17 Sequence +0:17 move second child to first child (temp 4-component vector of float) +0:? 'Color' (layout(location=0 ) out 4-component vector of float) +0:17 Color: direct index for structure (temp 4-component vector of float) +0:17 'psout' (temp structure{temp 4-component vector of float Color}) +0:17 Constant: +0:17 0 (const int) +0:17 Branch: Return +0:? Linker Objects +0:? 'g_tTex1df1' (layout(binding=2 r32f ) uniform image1D) +0:? 'g_tBuf1du1' (layout(binding=3 r32ui ) uniform uimageBuffer) +0:? 'Color' (layout(location=0 ) out 4-component vector of float) + + +Linked fragment stage: + + +Shader version: 450 +gl_FragCoord origin is upper left +0:? Sequence +0:11 Function Definition: main( (temp structure{temp 4-component vector of float Color}) +0:11 Function Parameters: +0:? Sequence +0:12 Sequence +0:12 move second child to first child (temp float) +0:12 'r00' (temp float) +0:12 imageLoad (temp float) +0:12 'g_tTex1df1' (layout(binding=2 r32f ) uniform image1D) +0:12 Constant: +0:12 0 (const int) +0:13 Sequence +0:13 move second child to first child (temp uint) +0:13 'r01' (temp uint) +0:13 imageLoad (temp uint) +0:13 'g_tBuf1du1' (layout(binding=3 r32ui ) uniform uimageBuffer) +0:13 Constant: +0:13 0 (const int) +0:16 move second child to first child (temp 4-component vector of float) +0:16 Color: direct index for structure (temp 4-component vector of float) +0:16 'psout' (temp structure{temp 4-component vector of float Color}) +0:16 Constant: +0:16 0 (const int) +0:16 Constant: +0:16 1.000000 +0:16 1.000000 +0:16 1.000000 +0:16 1.000000 +0:17 Sequence +0:17 Sequence +0:17 move second child to first child (temp 4-component vector of float) +0:? 'Color' (layout(location=0 ) out 4-component vector of float) +0:17 Color: direct index for structure (temp 4-component vector of float) +0:17 'psout' (temp structure{temp 4-component vector of float Color}) +0:17 Constant: +0:17 0 (const int) +0:17 Branch: Return +0:? Linker Objects +0:? 'g_tTex1df1' (layout(binding=2 r32f ) uniform image1D) +0:? 'g_tBuf1du1' (layout(binding=3 r32ui ) uniform uimageBuffer) +0:? 'Color' (layout(location=0 ) out 4-component vector of float) + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 37 + + Capability Shader + Capability Sampled1D + Capability SampledBuffer + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "main" 33 + ExecutionMode 4 OriginUpperLeft + Name 4 "main" + Name 8 "r00" + Name 11 "g_tTex1df1" + Name 18 "r01" + Name 21 "g_tBuf1du1" + Name 25 "PS_OUTPUT" + MemberName 25(PS_OUTPUT) 0 "Color" + Name 27 "psout" + Name 33 "Color" + Decorate 11(g_tTex1df1) DescriptorSet 0 + Decorate 11(g_tTex1df1) Binding 2 + Decorate 21(g_tBuf1du1) DescriptorSet 0 + Decorate 21(g_tBuf1du1) Binding 3 + Decorate 33(Color) Location 0 + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeFloat 32 + 7: TypePointer Function 6(float) + 9: TypeImage 6(float) 1D nonsampled format:R32f + 10: TypePointer UniformConstant 9 + 11(g_tTex1df1): 10(ptr) Variable UniformConstant + 13: TypeInt 32 1 + 14: 13(int) Constant 0 + 16: TypeInt 32 0 + 17: TypePointer Function 16(int) + 19: TypeImage 16(int) Buffer nonsampled format:R32ui + 20: TypePointer UniformConstant 19 + 21(g_tBuf1du1): 20(ptr) Variable UniformConstant + 24: TypeVector 6(float) 4 + 25(PS_OUTPUT): TypeStruct 24(fvec4) + 26: TypePointer Function 25(PS_OUTPUT) + 28: 6(float) Constant 1065353216 + 29: 24(fvec4) ConstantComposite 28 28 28 28 + 30: TypePointer Function 24(fvec4) + 32: TypePointer Output 24(fvec4) + 33(Color): 32(ptr) Variable Output + 4(main): 2 Function None 3 + 5: Label + 8(r00): 7(ptr) Variable Function + 18(r01): 17(ptr) Variable Function + 27(psout): 26(ptr) Variable Function + 12: 9 Load 11(g_tTex1df1) + 15: 6(float) ImageRead 12 14 + Store 8(r00) 15 + 22: 19 Load 21(g_tBuf1du1) + 23: 16(int) ImageRead 22 14 + Store 18(r01) 23 + 31: 30(ptr) AccessChain 27(psout) 14 + Store 31 29 + 34: 30(ptr) AccessChain 27(psout) 14 + 35: 24(fvec4) Load 34 + Store 33(Color) 35 + Return + FunctionEnd diff --git a/Test/baseResults/spv.rw.autoassign.frag.out b/Test/baseResults/spv.rw.autoassign.frag.out new file mode 100644 index 000000000..851ef4638 --- /dev/null +++ b/Test/baseResults/spv.rw.autoassign.frag.out @@ -0,0 +1,70 @@ +spv.rw.autoassign.frag + +Linked fragment stage: + + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 37 + + Capability Shader + Capability Sampled1D + Capability SampledBuffer + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "main" 33 + ExecutionMode 4 OriginUpperLeft + Name 4 "main" + Name 8 "r00" + Name 11 "g_tTex1df1" + Name 18 "r01" + Name 21 "g_tBuf1du1" + Name 25 "PS_OUTPUT" + MemberName 25(PS_OUTPUT) 0 "Color" + Name 27 "psout" + Name 33 "Color" + Decorate 11(g_tTex1df1) DescriptorSet 0 + Decorate 11(g_tTex1df1) Binding 20 + Decorate 21(g_tBuf1du1) DescriptorSet 0 + Decorate 21(g_tBuf1du1) Binding 21 + Decorate 33(Color) Location 0 + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeFloat 32 + 7: TypePointer Function 6(float) + 9: TypeImage 6(float) 1D nonsampled format:R32f + 10: TypePointer UniformConstant 9 + 11(g_tTex1df1): 10(ptr) Variable UniformConstant + 13: TypeInt 32 1 + 14: 13(int) Constant 0 + 16: TypeInt 32 0 + 17: TypePointer Function 16(int) + 19: TypeImage 16(int) Buffer nonsampled format:R32ui + 20: TypePointer UniformConstant 19 + 21(g_tBuf1du1): 20(ptr) Variable UniformConstant + 24: TypeVector 6(float) 4 + 25(PS_OUTPUT): TypeStruct 24(fvec4) + 26: TypePointer Function 25(PS_OUTPUT) + 28: 6(float) Constant 0 + 29: 24(fvec4) ConstantComposite 28 28 28 28 + 30: TypePointer Function 24(fvec4) + 32: TypePointer Output 24(fvec4) + 33(Color): 32(ptr) Variable Output + 4(main): 2 Function None 3 + 5: Label + 8(r00): 7(ptr) Variable Function + 18(r01): 17(ptr) Variable Function + 27(psout): 26(ptr) Variable Function + 12: 9 Load 11(g_tTex1df1) + 15: 6(float) ImageRead 12 14 + Store 8(r00) 15 + 22: 19 Load 21(g_tBuf1du1) + 23: 16(int) ImageRead 22 14 + Store 18(r01) 23 + 31: 30(ptr) AccessChain 27(psout) 14 + Store 31 29 + 34: 30(ptr) AccessChain 27(psout) 14 + 35: 24(fvec4) Load 34 + Store 33(Color) 35 + Return + FunctionEnd diff --git a/Test/hlsl.rw.register.frag b/Test/hlsl.rw.register.frag new file mode 100644 index 000000000..e82e419a0 --- /dev/null +++ b/Test/hlsl.rw.register.frag @@ -0,0 +1,18 @@ + +RWTexture1D g_tTex1df1 : register(u2); +RWBuffer g_tBuf1du1 : register(U3); + +struct PS_OUTPUT +{ + float4 Color : SV_Target0; +}; + +PS_OUTPUT main() +{ + float r00 = g_tTex1df1[0]; + uint r01 = g_tBuf1du1[0]; + + PS_OUTPUT psout; + psout.Color = 1.0; + return psout; +} diff --git a/Test/spv.rw.autoassign.frag b/Test/spv.rw.autoassign.frag new file mode 100644 index 000000000..5c7d0d3f5 --- /dev/null +++ b/Test/spv.rw.autoassign.frag @@ -0,0 +1,18 @@ + +RWTexture1D g_tTex1df1; +RWBuffer g_tBuf1du1; + +struct PS_OUTPUT +{ + float4 Color : SV_Target0; +}; + +PS_OUTPUT main() +{ + float r00 = g_tTex1df1[0]; + uint r01 = g_tBuf1du1[0]; + + PS_OUTPUT psout; + psout.Color = 0; + return psout; +} diff --git a/glslang/MachineIndependent/ShaderLang.cpp b/glslang/MachineIndependent/ShaderLang.cpp index eb4a17d4e..b7152a652 100644 --- a/glslang/MachineIndependent/ShaderLang.cpp +++ b/glslang/MachineIndependent/ShaderLang.cpp @@ -1494,6 +1494,7 @@ void TShader::setEntryPoint(const char* entryPoint) void TShader::setShiftSamplerBinding(unsigned int base) { intermediate->setShiftSamplerBinding(base); } void TShader::setShiftTextureBinding(unsigned int base) { intermediate->setShiftTextureBinding(base); } +void TShader::setShiftImageBinding(unsigned int base) { intermediate->setShiftImageBinding(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); } diff --git a/glslang/MachineIndependent/iomapper.cpp b/glslang/MachineIndependent/iomapper.cpp index 2ee6caef2..269d65495 100644 --- a/glslang/MachineIndependent/iomapper.cpp +++ b/glslang/MachineIndependent/iomapper.cpp @@ -222,6 +222,7 @@ struct TDefaultIoResolver : public glslang::TIoMapResolver { int baseSamplerBinding; int baseTextureBinding; + int baseImageBinding; int baseUboBinding; bool doAutoMapping; typedef std::vector TSlotSet; @@ -294,6 +295,9 @@ struct TDefaultIoResolver : public glslang::TIoMapResolver if (type.getQualifier().hasBinding()) { if (type.getBasicType() == glslang::EbtSampler) { const glslang::TSampler& sampler = type.getSampler(); + if (sampler.isImage()) + return reserveSlot(set, baseImageBinding + type.getQualifier().layoutBinding); + if (sampler.isPureSampler()) return reserveSlot(set, baseSamplerBinding + type.getQualifier().layoutBinding); @@ -308,6 +312,9 @@ struct TDefaultIoResolver : public glslang::TIoMapResolver // first and now all are passed that do not have a binding and needs one if (type.getBasicType() == glslang::EbtSampler) { const glslang::TSampler& sampler = type.getSampler(); + if (sampler.isImage()) + return getFreeSlot(set, baseImageBinding); + if (sampler.isPureSampler()) return getFreeSlot(set, baseSamplerBinding); @@ -339,9 +346,10 @@ bool TIoMapper::addStage(EShLanguage stage, TIntermediate &intermediate, TInfoSi // Trivial return if there is nothing to do. if (intermediate.getShiftSamplerBinding() == 0 && intermediate.getShiftTextureBinding() == 0 && + intermediate.getShiftImageBinding() == 0 && intermediate.getShiftUboBinding() == 0 && intermediate.getAutoMapBindings() == false && - resolver == NULL) + resolver == nullptr) return true; if (intermediate.getNumEntryPoints() != 1 || intermediate.isRecursive()) @@ -353,9 +361,10 @@ bool TIoMapper::addStage(EShLanguage stage, TIntermediate &intermediate, TInfoSi // if no resolver is provided, use the default resolver with the given shifts and auto map settings TDefaultIoResolver defaultResolver; - if (resolver == NULL) { + if (resolver == nullptr) { defaultResolver.baseSamplerBinding = intermediate.getShiftSamplerBinding(); defaultResolver.baseTextureBinding = intermediate.getShiftTextureBinding(); + defaultResolver.baseImageBinding = intermediate.getShiftImageBinding(); defaultResolver.baseUboBinding = intermediate.getShiftUboBinding(); defaultResolver.doAutoMapping = intermediate.getAutoMapBindings(); diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h index 1dd14403b..53c03ac8d 100644 --- a/glslang/MachineIndependent/localintermediate.h +++ b/glslang/MachineIndependent/localintermediate.h @@ -144,6 +144,7 @@ public: multiStream(false), xfbMode(false), shiftSamplerBinding(0), shiftTextureBinding(0), + shiftImageBinding(0), shiftUboBinding(0), autoMapBindings(false), flattenUniformArrays(false), @@ -174,6 +175,8 @@ public: unsigned int getShiftSamplerBinding() const { return shiftSamplerBinding; } void setShiftTextureBinding(unsigned int shift) { shiftTextureBinding = shift; } unsigned int getShiftTextureBinding() const { return shiftTextureBinding; } + void setShiftImageBinding(unsigned int shift) { shiftImageBinding = shift; } + unsigned int getShiftImageBinding() const { return shiftImageBinding; } void setShiftUboBinding(unsigned int shift) { shiftUboBinding = shift; } unsigned int getShiftUboBinding() const { return shiftUboBinding; } void setAutoMapBindings(bool map) { autoMapBindings = map; } @@ -403,6 +406,7 @@ protected: std::string entryPointMangledName; unsigned int shiftSamplerBinding; unsigned int shiftTextureBinding; + unsigned int shiftImageBinding; unsigned int shiftUboBinding; bool autoMapBindings; bool flattenUniformArrays; diff --git a/glslang/Public/ShaderLang.h b/glslang/Public/ShaderLang.h index acde8b015..9a76b40a0 100644 --- a/glslang/Public/ShaderLang.h +++ b/glslang/Public/ShaderLang.h @@ -306,6 +306,7 @@ public: void setEntryPoint(const char* entryPoint); void setShiftSamplerBinding(unsigned int base); void setShiftTextureBinding(unsigned int base); + void setShiftImageBinding(unsigned int base); void setShiftUboBinding(unsigned int base); void setAutoMapBindings(bool map); void setFlattenUniformArrays(bool flatten); diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp index 66fba2e7e..918a431b5 100644 --- a/gtests/Hlsl.FromFile.cpp +++ b/gtests/Hlsl.FromFile.cpp @@ -159,6 +159,7 @@ INSTANTIATE_TEST_CASE_P( {"hlsl.promotions.frag", "main"}, {"hlsl.rw.atomics.frag", "main"}, {"hlsl.rw.bracket.frag", "main"}, + {"hlsl.rw.register.frag", "main"}, {"hlsl.rw.scalar.bracket.frag", "main"}, {"hlsl.rw.vec2.bracket.frag", "main"}, {"hlsl.sample.array.dx10.frag", "main"}, diff --git a/gtests/Spv.FromFile.cpp b/gtests/Spv.FromFile.cpp index a55af5187..1e0f7976f 100644 --- a/gtests/Spv.FromFile.cpp +++ b/gtests/Spv.FromFile.cpp @@ -46,6 +46,7 @@ struct IoMapData { const char* entryPoint; int baseSamplerBinding; int baseTextureBinding; + int baseImageBinding; int baseUboBinding; bool autoMapBindings; bool flattenUniforms; @@ -123,6 +124,7 @@ TEST_P(HlslIoMap, FromFile) Target::Spv, GetParam().entryPoint, GetParam().baseSamplerBinding, GetParam().baseTextureBinding, + GetParam().baseImageBinding, GetParam().baseUboBinding, GetParam().autoMapBindings, GetParam().flattenUniforms); @@ -136,6 +138,7 @@ TEST_P(GlslIoMap, FromFile) Target::Spv, GetParam().entryPoint, GetParam().baseSamplerBinding, GetParam().baseTextureBinding, + GetParam().baseImageBinding, GetParam().baseUboBinding, GetParam().autoMapBindings, GetParam().flattenUniforms); @@ -283,10 +286,11 @@ INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P( Hlsl, HlslIoMap, ::testing::ValuesIn(std::vector{ - { "spv.register.autoassign.frag", "main_ep", 5, 10, 20, true, false }, - { "spv.register.noautoassign.frag", "main_ep", 5, 10, 15, false, false }, - { "spv.register.autoassign-2.frag", "main", 5, 10, 15, true, true }, - { "spv.buffer.autoassign.frag", "main", 5, 10, 15, true, true }, + { "spv.register.autoassign.frag", "main_ep", 5, 10, 0, 20, true, false }, + { "spv.register.noautoassign.frag", "main_ep", 5, 10, 0, 15, false, false }, + { "spv.register.autoassign-2.frag", "main", 5, 10, 0, 15, true, true }, + { "spv.buffer.autoassign.frag", "main", 5, 10, 0, 15, true, true }, + { "spv.rw.autoassign.frag", "main", 5, 10, 20, 15, true, true }, { "spv.register.autoassign.rangetest.frag", "main", glslang::TQualifier::layoutBindingEnd-2, glslang::TQualifier::layoutBindingEnd+5, @@ -299,8 +303,8 @@ INSTANTIATE_TEST_CASE_P( INSTANTIATE_TEST_CASE_P( Hlsl, GlslIoMap, ::testing::ValuesIn(std::vector{ - { "spv.glsl.register.autoassign.frag", "main", 5, 10, 20, true, false }, - { "spv.glsl.register.noautoassign.frag", "main", 5, 10, 15, false, false }, + { "spv.glsl.register.autoassign.frag", "main", 5, 10, 0, 20, true, false }, + { "spv.glsl.register.noautoassign.frag", "main", 5, 10, 0, 15, false, false }, }), FileNameAsCustomTestSuffixIoMap ); diff --git a/gtests/TestFixture.h b/gtests/TestFixture.h index c08c6cc52..e795e8dc9 100644 --- a/gtests/TestFixture.h +++ b/gtests/TestFixture.h @@ -239,6 +239,7 @@ public: const std::string& entryPointName, EShMessages controls, int baseSamplerBinding, int baseTextureBinding, + int baseImageBinding, int baseUboBinding, bool autoMapBindings, bool flattenUniformArrays) @@ -248,6 +249,7 @@ public: glslang::TShader shader(kind); shader.setShiftSamplerBinding(baseSamplerBinding); shader.setShiftTextureBinding(baseTextureBinding); + shader.setShiftImageBinding(baseImageBinding); shader.setShiftUboBinding(baseUboBinding); shader.setAutoMapBindings(autoMapBindings); shader.setFlattenUniformArrays(flattenUniformArrays); @@ -426,6 +428,7 @@ public: const std::string& entryPointName, int baseSamplerBinding, int baseTextureBinding, + int baseImageBinding, int baseUboBinding, bool autoMapBindings, bool flattenUniformArrays) @@ -440,7 +443,7 @@ public: const EShMessages controls = DeriveOptions(source, semantics, target); GlslangResult result = compileLinkIoMap(testName, input, entryPointName, controls, - baseSamplerBinding, baseTextureBinding, baseUboBinding, + baseSamplerBinding, baseTextureBinding, baseImageBinding, baseUboBinding, autoMapBindings, flattenUniformArrays); diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp index cf97ec7e4..5bca3ec92 100755 --- a/hlsl/hlslParseHelper.cpp +++ b/hlsl/hlslParseHelper.cpp @@ -45,6 +45,7 @@ #include "../glslang/OSDependent/osinclude.h" #include +#include namespace glslang { @@ -3085,11 +3086,12 @@ void HlslParseContext::handleRegister(const TSourceLoc& loc, TQualifier& qualifi } // TODO: learn what all these really mean and how they interact with regNumber and subComponent - switch (desc[0]) { + switch (std::tolower(desc[0])) { case 'b': case 't': case 'c': case 's': + case 'u': qualifier.layoutBinding = regNumber + subComponent; break; default: