diff --git a/3rdparty/glslang/SPIRV/GlslangToSpv.cpp b/3rdparty/glslang/SPIRV/GlslangToSpv.cpp index b6c9705df..a82867a4a 100755 --- a/3rdparty/glslang/SPIRV/GlslangToSpv.cpp +++ b/3rdparty/glslang/SPIRV/GlslangToSpv.cpp @@ -3529,6 +3529,11 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg const glslang::TIntermSequence& glslangArgs = node->getSequence(); const glslang::TQualifierList& qualifiers = node->getQualifierList(); + // Encapsulate lvalue logic, used in two places below, for safety. + const auto isLValue = [](int qualifier, const glslang::TType& paramType) -> bool { + return qualifier != glslang::EvqConstReadOnly || paramType.containsOpaque(); + }; + // See comments in makeFunctions() for details about the semantics for parameter passing. // // These imply we need a four step process: @@ -3548,7 +3553,7 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg glslangArgs[a]->traverse(this); argTypes.push_back(¶mType); // keep outputs and opaque objects as l-values, evaluate input-only as r-values - if (qualifiers[a] != glslang::EvqConstReadOnly || paramType.containsOpaque()) { + if (isLValue(qualifiers[a], paramType)) { // save l-value lValues.push_back(builder.getAccessChain()); } else { @@ -3573,7 +3578,7 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg builder.setAccessChain(lValues[lValueCount]); arg = builder.accessChainGetLValue(); ++lValueCount; - } else if (qualifiers[a] != glslang::EvqConstReadOnly) { + } else if (isLValue(qualifiers[a], paramType)) { // need space to hold the copy arg = builder.createVariable(spv::StorageClassFunction, convertGlslangToSpvType(paramType), "param"); if (qualifiers[a] == glslang::EvqIn || qualifiers[a] == glslang::EvqInOut) { @@ -3600,7 +3605,7 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg lValueCount = 0; for (int a = 0; a < (int)glslangArgs.size(); ++a) { const glslang::TType& paramType = glslangArgs[a]->getAsTyped()->getType(); - if (qualifiers[a] != glslang::EvqConstReadOnly) { + if (isLValue(qualifiers[a], paramType)) { if (qualifiers[a] == glslang::EvqOut || qualifiers[a] == glslang::EvqInOut) { spv::Id copy = builder.createLoad(spvArgs[a]); builder.setAccessChain(lValues[lValueCount]); diff --git a/3rdparty/glslang/StandAlone/StandAlone.cpp b/3rdparty/glslang/StandAlone/StandAlone.cpp index 53a33b8a7..58be28ef4 100644 --- a/3rdparty/glslang/StandAlone/StandAlone.cpp +++ b/3rdparty/glslang/StandAlone/StandAlone.cpp @@ -94,6 +94,7 @@ enum TOptions { EOptionHlslIoMapping = (1 << 24), EOptionAutoMapLocations = (1 << 25), EOptionDebug = (1 << 26), + EOptionStdin = (1 << 27), }; // @@ -469,6 +470,9 @@ void ProcessArguments(std::vector>& workItem sourceEntryPointName = argv[1]; bumpArg(); break; + } else if (lowerword == "stdin") { + Options |= EOptionStdin; + shaderStageName = argv[1]; } else if (lowerword == "suppress-warnings") { Options |= EOptionSuppressWarnings; } else if (lowerword == "target-env") { @@ -606,6 +610,10 @@ void ProcessArguments(std::vector>& workItem } } + // Make sure that -S is always specified if --stdin is specified + if ((Options & EOptionStdin) && shaderStageName == nullptr) + Error("must provide -S when --stdin is given"); + // Make sure that -E is not specified alongside linking (which includes SPV generation) if ((Options & EOptionOutputPreprocessed) && (Options & EOptionLinkProgram)) Error("can't use -E when linking is selected"); @@ -654,17 +662,31 @@ void SetMessageOptions(EShMessages& messages) void CompileShaders(glslang::TWorklist& worklist) { glslang::TWorkItem* workItem; - while (worklist.remove(workItem)) { - ShHandle compiler = ShConstructCompiler(FindLanguage(workItem->name), Options); + if (Options & EOptionStdin) { + worklist.remove(workItem); + ShHandle compiler = ShConstructCompiler(FindLanguage("stdin"), Options); if (compiler == 0) return; - CompileFile(workItem->name.c_str(), compiler); + CompileFile("stdin", compiler); - if (! (Options & EOptionSuppressInfolog)) - workItem->results = ShGetInfoLog(compiler); + if (! (Options & EOptionSuppressInfolog)) + workItem->results = ShGetInfoLog(compiler); ShDestruct(compiler); + } else { + while (worklist.remove(workItem)) { + ShHandle compiler = ShConstructCompiler(FindLanguage(workItem->name), Options); + if (compiler == 0) + return; + + CompileFile(workItem->name.c_str(), compiler); + + if (! (Options & EOptionSuppressInfolog)) + workItem->results = ShGetInfoLog(compiler); + + ShDestruct(compiler); + } } } @@ -908,19 +930,32 @@ void CompileAndLinkShaderFiles(glslang::TWorklist& Worklist) { std::vector compUnits; - // Transfer all the work items from to a simple list of - // of compilation units. (We don't care about the thread - // work-item distribution properties in this path, which - // is okay due to the limited number of shaders, know since - // they are all getting linked together.) - glslang::TWorkItem* workItem; - while (Worklist.remove(workItem)) { - ShaderCompUnit compUnit(FindLanguage(workItem->name)); - char* fileText = ReadFileData(workItem->name.c_str()); - if (fileText == nullptr) - usage(); - compUnit.addString(workItem->name, fileText); + // If this is using stdin, we can't really detect multiple different file + // units by input type. We need to assume that we're just being given one + // file of a certain type. + if ((Options & EOptionStdin) != 0) { + ShaderCompUnit compUnit(FindLanguage("stdin")); + std::istreambuf_iterator begin(std::cin), end; + std::string tempString(begin, end); + char* fileText = strdup(tempString.c_str()); + std::string fileName = "stdin"; + compUnit.addString(fileName, fileText); compUnits.push_back(compUnit); + } else { + // Transfer all the work items from to a simple list of + // of compilation units. (We don't care about the thread + // work-item distribution properties in this path, which + // is okay due to the limited number of shaders, know since + // they are all getting linked together.) + glslang::TWorkItem* workItem; + while (Worklist.remove(workItem)) { + ShaderCompUnit compUnit(FindLanguage(workItem->name)); + char* fileText = ReadFileData(workItem->name.c_str()); + if (fileText == nullptr) + usage(); + compUnit.addString(workItem->name, fileText); + compUnits.push_back(compUnit); + } } // Actual call to programmatic processing of compile and link, @@ -973,10 +1008,15 @@ int C_DECL main(int argc, char* argv[]) return ESuccess; } - if (workList.empty()) { + if (workList.empty() && ((Options & EOptionStdin) == 0)) { usage(); } + if (Options & EOptionStdin) { + workItems.push_back(std::unique_ptr{new glslang::TWorkItem("stdin")}); + workList.add(workItems.back().get()); + } + ProcessConfigFile(); // @@ -1087,7 +1127,14 @@ EShLanguage FindLanguage(const std::string& name, bool parseSuffix) void CompileFile(const char* fileName, ShHandle compiler) { int ret = 0; - char* shaderString = ReadFileData(fileName); + char* shaderString; + if ((Options & EOptionStdin) != 0) { + std::istreambuf_iterator begin(std::cin), end; + std::string tempString(begin, end); + shaderString = strdup(tempString.c_str()); + } else { + shaderString = ReadFileData(fileName); + } // move to length-based strings, rather than null-terminated strings int* lengths = new int[1]; @@ -1220,6 +1267,9 @@ void usage() " --source-entrypoint name the given shader source function is\n" " renamed to be the entry point given in -e\n" " --sep synonym for --source-entrypoint\n" + " --stdin Read from stdin instead of from a file.\n" + " You'll have to provide the shader stage\n" + " using -S.\n" " --suppress-warnings suppress GLSL warnings\n" " (except as required by #extension : warn)\n" " --target-env {vulkan1.0|opengl} set the execution environment code will\n" diff --git a/3rdparty/glslang/Test/baseResults/hlsl.opaque-type-bug.frag.out b/3rdparty/glslang/Test/baseResults/hlsl.opaque-type-bug.frag.out new file mode 100644 index 000000000..3eed75240 --- /dev/null +++ b/3rdparty/glslang/Test/baseResults/hlsl.opaque-type-bug.frag.out @@ -0,0 +1,111 @@ +hlsl.opaque-type-bug.frag +Shader version: 500 +gl_FragCoord origin is upper left +0:? Sequence +0:6 Function Definition: TexFunc(t21;vf3; ( temp void) +0:6 Function Parameters: +0:6 't2D' ( const (read only) texture2D) +0:6 'RGB' ( out 3-component vector of float) +0:? Sequence +0:7 move second child to first child ( temp 3-component vector of float) +0:7 'RGB' ( out 3-component vector of float) +0:7 Constant: +0:7 0.000000 +0:7 0.000000 +0:7 0.000000 +0:12 Function Definition: @main( ( temp void) +0:12 Function Parameters: +0:? Sequence +0:15 Function Call: TexFunc(t21;vf3; ( temp void) +0:15 'MyTexture' (layout( binding=0) uniform texture2D) +0:15 'final_RGB' ( temp 3-component vector of float) +0:12 Function Definition: main( ( temp void) +0:12 Function Parameters: +0:? Sequence +0:12 Function Call: @main( ( temp void) +0:? Linker Objects +0:? 'MyTexture' (layout( binding=0) uniform texture2D) + + +Linked fragment stage: + + +Shader version: 500 +gl_FragCoord origin is upper left +0:? Sequence +0:6 Function Definition: TexFunc(t21;vf3; ( temp void) +0:6 Function Parameters: +0:6 't2D' ( const (read only) texture2D) +0:6 'RGB' ( out 3-component vector of float) +0:? Sequence +0:7 move second child to first child ( temp 3-component vector of float) +0:7 'RGB' ( out 3-component vector of float) +0:7 Constant: +0:7 0.000000 +0:7 0.000000 +0:7 0.000000 +0:12 Function Definition: @main( ( temp void) +0:12 Function Parameters: +0:? Sequence +0:15 Function Call: TexFunc(t21;vf3; ( temp void) +0:15 'MyTexture' (layout( binding=0) uniform texture2D) +0:15 'final_RGB' ( temp 3-component vector of float) +0:12 Function Definition: main( ( temp void) +0:12 Function Parameters: +0:? Sequence +0:12 Function Call: @main( ( temp void) +0:? Linker Objects +0:? 'MyTexture' (layout( binding=0) uniform texture2D) + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 26 + + Capability Shader + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "main" + ExecutionMode 4 OriginUpperLeft + Source HLSL 500 + Name 4 "main" + Name 14 "TexFunc(t21;vf3;" + Name 12 "t2D" + Name 13 "RGB" + Name 16 "@main(" + Name 20 "MyTexture" + Name 21 "final_RGB" + Name 22 "param" + Decorate 20(MyTexture) DescriptorSet 0 + Decorate 20(MyTexture) Binding 0 + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeFloat 32 + 7: TypeImage 6(float) 2D sampled format:Unknown + 8: TypePointer UniformConstant 7 + 9: TypeVector 6(float) 3 + 10: TypePointer Function 9(fvec3) + 11: TypeFunction 2 8(ptr) 10(ptr) + 18: 6(float) Constant 0 + 19: 9(fvec3) ConstantComposite 18 18 18 + 20(MyTexture): 8(ptr) Variable UniformConstant + 4(main): 2 Function None 3 + 5: Label + 25: 2 FunctionCall 16(@main() + Return + FunctionEnd +14(TexFunc(t21;vf3;): 2 Function None 11 + 12(t2D): 8(ptr) FunctionParameter + 13(RGB): 10(ptr) FunctionParameter + 15: Label + Store 13(RGB) 19 + Return + FunctionEnd + 16(@main(): 2 Function None 3 + 17: Label + 21(final_RGB): 10(ptr) Variable Function + 22(param): 10(ptr) Variable Function + 23: 2 FunctionCall 14(TexFunc(t21;vf3;) 20(MyTexture) 22(param) + 24: 9(fvec3) Load 22(param) + Store 21(final_RGB) 24 + Return + FunctionEnd diff --git a/3rdparty/glslang/Test/hlsl.opaque-type-bug.frag b/3rdparty/glslang/Test/hlsl.opaque-type-bug.frag new file mode 100644 index 000000000..f4ccaea29 --- /dev/null +++ b/3rdparty/glslang/Test/hlsl.opaque-type-bug.frag @@ -0,0 +1,16 @@ + +Texture2D MyTexture : register(t0); + +//---------------------------------------------------------------------------------------- +void TexFunc(in const Texture2D t2D, out float3 RGB) +{ + RGB = 0; +} + +//----------------------------------------------------------------------------------- +void main() +{ + float3 final_RGB; + + TexFunc(MyTexture, final_RGB); +} diff --git a/3rdparty/glslang/gtests/Hlsl.FromFile.cpp b/3rdparty/glslang/gtests/Hlsl.FromFile.cpp index 4079d8358..4dfe7d797 100644 --- a/3rdparty/glslang/gtests/Hlsl.FromFile.cpp +++ b/3rdparty/glslang/gtests/Hlsl.FromFile.cpp @@ -226,6 +226,7 @@ INSTANTIATE_TEST_CASE_P( {"hlsl.numericsuffixes.frag", "main"}, {"hlsl.numthreads.comp", "main_aux1"}, {"hlsl.overload.frag", "PixelShaderFunction"}, + {"hlsl.opaque-type-bug.frag", "main"}, {"hlsl.params.default.frag", "main"}, {"hlsl.params.default.negative.frag", "main"}, {"hlsl.partialInit.frag", "PixelShaderFunction"},