From 5d43c4aac776f1504dc5c364bae49251eadb8111 Mon Sep 17 00:00:00 2001 From: greg-lunarg Date: Fri, 7 Dec 2018 17:36:33 -0700 Subject: [PATCH] SPV: Fix #1575, fix #1593: Support HLSL #line SPIR-V OpLines now contain filenames from HLSL-style #lines. --- SPIRV/GlslangToSpv.cpp | 24 +-- SPIRV/SpvBuilder.cpp | 38 +++- SPIRV/SpvBuilder.h | 19 +- Test/baseResults/hlsl.pp.line2.frag.out | 183 ++++++++++++++++++ Test/baseResults/hlsl.pp.line3.frag.out | 172 ++++++++++++++++ Test/baseResults/spv.pp.line.frag.out | 144 ++++++++++++++ Test/hlsl.pp.line2.frag | 40 ++++ Test/hlsl.pp.line3.frag | 34 ++++ Test/i1.h | 1 + Test/runtests | 2 + Test/spv.pp.line.frag | 25 +++ glslang/Include/Common.h | 20 +- glslang/MachineIndependent/Scan.h | 12 +- .../preprocessor/PpContext.h | 10 +- gtests/Hlsl.FromFile.cpp | 21 ++ gtests/Spv.FromFile.cpp | 21 ++ gtests/TestFixture.h | 25 ++- hlsl/hlslParseHelper.cpp | 2 +- 18 files changed, 754 insertions(+), 39 deletions(-) create mode 100644 Test/baseResults/hlsl.pp.line2.frag.out create mode 100644 Test/baseResults/hlsl.pp.line3.frag.out create mode 100644 Test/baseResults/spv.pp.line.frag.out create mode 100644 Test/hlsl.pp.line2.frag create mode 100644 Test/hlsl.pp.line3.frag create mode 100644 Test/i1.h create mode 100644 Test/spv.pp.line.frag diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp index 4c1dbd4a..b72f7aeb 100755 --- a/SPIRV/GlslangToSpv.cpp +++ b/SPIRV/GlslangToSpv.cpp @@ -1594,7 +1594,7 @@ void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol) bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::TIntermBinary* node) { - builder.setLine(node->getLoc().line); + builder.setLine(node->getLoc().line, node->getLoc().getFilename()); SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder); if (node->getType().getQualifier().isSpecConstant()) @@ -1789,7 +1789,7 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node) { - builder.setLine(node->getLoc().line); + builder.setLine(node->getLoc().line, node->getLoc().getFilename()); SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder); if (node->getType().getQualifier().isSpecConstant()) @@ -2053,7 +2053,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt return false; case glslang::EOpFunctionCall: { - builder.setLine(node->getLoc().line); + builder.setLine(node->getLoc().line, node->getLoc().getFilename()); if (node->isUserDefined()) result = handleUserFunctionCall(node); // assert(result); // this can happen for bad shaders because the call graph completeness checking is not yet done @@ -2172,7 +2172,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt case glslang::EOpConstructStruct: case glslang::EOpConstructTextureSampler: { - builder.setLine(node->getLoc().line); + builder.setLine(node->getLoc().line, node->getLoc().getFilename()); std::vector arguments; translateArguments(*node, arguments); spv::Id constructed; @@ -2317,7 +2317,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt right->traverse(this); spv::Id rightId = accessChainLoad(right->getType()); - builder.setLine(node->getLoc().line); + builder.setLine(node->getLoc().line, node->getLoc().getFilename()); OpDecorations decorations = { precision, TranslateNoContractionDecoration(node->getType().getQualifier()), TranslateNonUniformDecoration(node->getType().getQualifier()) }; @@ -2405,12 +2405,12 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt if (lvalue) operands.push_back(builder.accessChainGetLValue()); else { - builder.setLine(node->getLoc().line); + builder.setLine(node->getLoc().line, node->getLoc().getFilename()); operands.push_back(accessChainLoad(glslangOperands[arg]->getAsTyped()->getType())); } } - builder.setLine(node->getLoc().line); + builder.setLine(node->getLoc().line, node->getLoc().getFilename()); if (atomic) { // Handle all atomics result = createAtomicOperation(node->getOp(), precision, resultType(), operands, node->getBasicType()); @@ -2511,7 +2511,7 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang node->getFalseBlock()->traverse(this); spv::Id falseValue = accessChainLoad(node->getTrueBlock()->getAsTyped()->getType()); - builder.setLine(node->getLoc().line); + builder.setLine(node->getLoc().line, node->getLoc().getFilename()); // done if void if (node->getBasicType() == glslang::EbtVoid) @@ -2685,7 +2685,7 @@ bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIn // by a block-ending branch. But we don't want to put any other body/test // instructions in it, since the body/test may have arbitrary instructions, // including merges of its own. - builder.setLine(node->getLoc().line); + builder.setLine(node->getLoc().line, node->getLoc().getFilename()); builder.setBuildPoint(&blocks.head); builder.createLoopMerge(&blocks.merge, &blocks.continue_target, control, dependencyLength); if (node->testFirst() && node->getTest()) { @@ -2709,7 +2709,7 @@ bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIn node->getTerminal()->traverse(this); builder.createBranch(&blocks.head); } else { - builder.setLine(node->getLoc().line); + builder.setLine(node->getLoc().line, node->getLoc().getFilename()); builder.createBranch(&blocks.body); breakForLoop.push(true); @@ -2744,7 +2744,7 @@ bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::T if (node->getExpression()) node->getExpression()->traverse(this); - builder.setLine(node->getLoc().line); + builder.setLine(node->getLoc().line, node->getLoc().getFilename()); switch (node->getFlowOp()) { case glslang::EOpKill: @@ -3913,7 +3913,7 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO if (! node->isImage() && ! node->isTexture()) return spv::NoResult; - builder.setLine(node->getLoc().line); + builder.setLine(node->getLoc().line, node->getLoc().getFilename()); // Process a GLSL texturing op (will be SPV image) diff --git a/SPIRV/SpvBuilder.cpp b/SPIRV/SpvBuilder.cpp index 951d1049..aff65406 100755 --- a/SPIRV/SpvBuilder.cpp +++ b/SPIRV/SpvBuilder.cpp @@ -60,6 +60,7 @@ Builder::Builder(unsigned int spvVersion, unsigned int magicNumber, SpvBuildLogg sourceVersion(0), sourceFileStringId(NoResult), currentLine(0), + currentFile(nullptr), emitOpLines(false), addressModel(AddressingModelLogical), memoryModel(MemoryModelGLSL450), @@ -87,8 +88,9 @@ Id Builder::import(const char* name) return import->getResultId(); } -// Emit an OpLine if we've been asked to emit OpLines and the line number -// has changed since the last time, and is a valid line number. +// Emit instruction for non-filename-based #line directives (ie. no filename +// seen yet): emit an OpLine if we've been asked to emit OpLines and the line +// number has changed since the last time, and is a valid line number. void Builder::setLine(int lineNum) { if (lineNum != 0 && lineNum != currentLine) { @@ -98,6 +100,38 @@ void Builder::setLine(int lineNum) } } +// If no filename, do non-filename-based #line emit. Else do filename-based emit. +// Emit OpLine if we've been asked to emit OpLines and the line number or filename +// has changed since the last time, and line number is valid. +void Builder::setLine(int lineNum, const char* filename) +{ + if (filename == nullptr) { + setLine(lineNum); + return; + } + if ((lineNum != 0 && lineNum != currentLine) || currentFile == nullptr || + strncmp(filename, currentFile, strlen(currentFile) + 1) != 0) { + currentLine = lineNum; + currentFile = filename; + if (emitOpLines) { + // If filename previously seen, use its id, else create a string + // and put it in the map. + auto sItr = stringIds.find(filename); + if (sItr != stringIds.end()) { + addLine(sItr->second, currentLine, 0); + } else { + Instruction* fileString = + new Instruction(getUniqueId(), NoType, OpString); + fileString->addStringOperand(filename); + spv::Id stringId = fileString->getResultId(); + strings.push_back(std::unique_ptr(fileString)); + addLine(stringId, currentLine, 0); + stringIds[filename] = stringId; + } + } + } +} + void Builder::addLine(Id fileName, int lineNum, int column) { Instruction* line = new Instruction(OpLine); diff --git a/SPIRV/SpvBuilder.h b/SPIRV/SpvBuilder.h index 7c1d421b..d74d6f8c 100644 --- a/SPIRV/SpvBuilder.h +++ b/SPIRV/SpvBuilder.h @@ -77,9 +77,11 @@ public: void setSourceFile(const std::string& file) { Instruction* fileString = new Instruction(getUniqueId(), NoType, OpString); - fileString->addStringOperand(file.c_str()); + const char* file_c_str = file.c_str(); + fileString->addStringOperand(file_c_str); sourceFileStringId = fileString->getResultId(); strings.push_back(std::unique_ptr(fileString)); + stringIds[file_c_str] = sourceFileStringId; } void setSourceText(const std::string& text) { sourceText = text; } void addSourceExtension(const char* ext) { sourceExtensions.push_back(ext); } @@ -106,9 +108,16 @@ public: return id; } - // Log the current line, and if different than the last one, - // issue a new OpLine, using the current file name. + // Generate OpLine for non-filename-based #line directives (ie no filename + // seen yet): Log the current line, and if different than the last one, + // issue a new OpLine using the new line and current source file name. void setLine(int line); + + // If filename null, generate OpLine for non-filename-based line directives, + // else do filename-based: Log the current line and file, and if different + // than the last one, issue a new OpLine using the new line and file + // name. + void setLine(int line, const char* filename); // Low-level OpLine. See setLine() for a layered helper. void addLine(Id fileName, int line, int column); @@ -658,6 +667,7 @@ public: spv::Id sourceFileStringId; std::string sourceText; int currentLine; + const char* currentFile; bool emitOpLines; std::set extensions; std::vector sourceExtensions; @@ -695,6 +705,9 @@ public: // Our loop stack. std::stack loops; + // map from strings to their string ids + std::unordered_map stringIds; + // The stream for outputting warnings and errors. SpvBuildLogger* logger; }; // end Builder class diff --git a/Test/baseResults/hlsl.pp.line2.frag.out b/Test/baseResults/hlsl.pp.line2.frag.out new file mode 100644 index 00000000..478440a0 --- /dev/null +++ b/Test/baseResults/hlsl.pp.line2.frag.out @@ -0,0 +1,183 @@ +hlsl.pp.line2.frag +// Module Version 10000 +// Generated by (magic number): 80007 +// Id's are bound by 80 + + Capability Shader + 2: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 5 "MainPs" 71 75 + ExecutionMode 5 OriginUpperLeft + 1: String "hlsl.pp.line2.frag" + 17: String "foo.frag" + 32: String "foo.h" + 42: String "foo2.h" + Source HLSL 500 1 "// OpModuleProcessed auto-map-locations +// OpModuleProcessed auto-map-bindings +// OpModuleProcessed entry-point MainPs +// OpModuleProcessed client vulkan100 +// OpModuleProcessed target-env vulkan1.0 +// OpModuleProcessed keep-uncalled +// OpModuleProcessed hlsl-offsets +#line 1 +#line 1 "foo.frag" +Texture2D g_tColor[ 128 ] ; + +layout (push_constant) cbuffer PerViewConstantBuffer_t +{ + uint g_nDataIdx; + uint g_nDataIdx2; + bool g_B; +} ; + +SamplerState g_sAniso; + +struct PS_INPUT +{ + float2 vTextureCoords : TEXCOORD2 ; +} ; + +struct PS_OUTPUT +{ + float4 vColor : SV_Target0 ; +} ; + +PS_OUTPUT MainPs ( PS_INPUT i ) +{ + PS_OUTPUT ps_output ; + + uint u; +#line 47 + if (g_B) +#line 3 "foo.h" + u = g_nDataIdx; + else +#line 67 + u = g_nDataIdx2; +#line 7 "foo2.h" + ps_output . vColor = g_tColor [ u ] . Sample ( g_sAniso , i . vTextureCoords . xy ); +#line 105 + return ps_output ; +} + +" + Name 5 "MainPs" + Name 9 "PS_INPUT" + MemberName 9(PS_INPUT) 0 "vTextureCoords" + Name 12 "PS_OUTPUT" + MemberName 12(PS_OUTPUT) 0 "vColor" + Name 15 "@MainPs(struct-PS_INPUT-vf21;" + Name 14 "i" + Name 19 "PerViewConstantBuffer_t" + MemberName 19(PerViewConstantBuffer_t) 0 "g_nDataIdx" + MemberName 19(PerViewConstantBuffer_t) 1 "g_nDataIdx2" + MemberName 19(PerViewConstantBuffer_t) 2 "g_B" + Name 21 "" + Name 34 "u" + Name 44 "ps_output" + Name 49 "g_tColor" + Name 56 "g_sAniso" + Name 69 "i" + Name 71 "i.vTextureCoords" + Name 75 "@entryPointOutput.vColor" + Name 76 "param" + MemberDecorate 19(PerViewConstantBuffer_t) 0 Offset 0 + MemberDecorate 19(PerViewConstantBuffer_t) 1 Offset 4 + MemberDecorate 19(PerViewConstantBuffer_t) 2 Offset 8 + Decorate 19(PerViewConstantBuffer_t) Block + Decorate 49(g_tColor) DescriptorSet 0 + Decorate 56(g_sAniso) DescriptorSet 0 + Decorate 71(i.vTextureCoords) Location 0 + Decorate 75(@entryPointOutput.vColor) Location 0 + 3: TypeVoid + 4: TypeFunction 3 + 7: TypeFloat 32 + 8: TypeVector 7(float) 2 + 9(PS_INPUT): TypeStruct 8(fvec2) + 10: TypePointer Function 9(PS_INPUT) + 11: TypeVector 7(float) 4 + 12(PS_OUTPUT): TypeStruct 11(fvec4) + 13: TypeFunction 12(PS_OUTPUT) 10(ptr) + 18: TypeInt 32 0 +19(PerViewConstantBuffer_t): TypeStruct 18(int) 18(int) 18(int) + 20: TypePointer PushConstant 19(PerViewConstantBuffer_t) + 21: 20(ptr) Variable PushConstant + 22: TypeInt 32 1 + 23: 22(int) Constant 2 + 24: TypePointer PushConstant 18(int) + 27: TypeBool + 28: 18(int) Constant 0 + 33: TypePointer Function 18(int) + 35: 22(int) Constant 0 + 39: 22(int) Constant 1 + 43: TypePointer Function 12(PS_OUTPUT) + 45: TypeImage 7(float) 2D sampled format:Unknown + 46: 18(int) Constant 128 + 47: TypeArray 45 46 + 48: TypePointer UniformConstant 47 + 49(g_tColor): 48(ptr) Variable UniformConstant + 51: TypePointer UniformConstant 45 + 54: TypeSampler + 55: TypePointer UniformConstant 54 + 56(g_sAniso): 55(ptr) Variable UniformConstant + 58: TypeSampledImage 45 + 60: TypePointer Function 8(fvec2) + 64: TypePointer Function 11(fvec4) + 70: TypePointer Input 8(fvec2) +71(i.vTextureCoords): 70(ptr) Variable Input + 74: TypePointer Output 11(fvec4) +75(@entryPointOutput.vColor): 74(ptr) Variable Output + 5(MainPs): 3 Function None 4 + 6: Label + 69(i): 10(ptr) Variable Function + 76(param): 10(ptr) Variable Function + Line 17 23 0 + 72: 8(fvec2) Load 71(i.vTextureCoords) + 73: 60(ptr) AccessChain 69(i) 35 + Store 73 72 + 77: 9(PS_INPUT) Load 69(i) + Store 76(param) 77 + 78:12(PS_OUTPUT) FunctionCall 15(@MainPs(struct-PS_INPUT-vf21;) 76(param) + 79: 11(fvec4) CompositeExtract 78 0 + Store 75(@entryPointOutput.vColor) 79 + Return + FunctionEnd +15(@MainPs(struct-PS_INPUT-vf21;):12(PS_OUTPUT) Function None 13 + 14(i): 10(ptr) FunctionParameter + 16: Label + 34(u): 33(ptr) Variable Function + 44(ps_output): 43(ptr) Variable Function + Line 17 47 0 + 25: 24(ptr) AccessChain 21 23 + 26: 18(int) Load 25 + 29: 27(bool) INotEqual 26 28 + SelectionMerge 31 None + BranchConditional 29 30 38 + 30: Label + Line 32 3 0 + 36: 24(ptr) AccessChain 21 35 + 37: 18(int) Load 36 + Store 34(u) 37 + Branch 31 + 38: Label + Line 32 67 0 + 40: 24(ptr) AccessChain 21 39 + 41: 18(int) Load 40 + Store 34(u) 41 + Branch 31 + 31: Label + Line 42 7 0 + 50: 18(int) Load 34(u) + 52: 51(ptr) AccessChain 49(g_tColor) 50 + 53: 45 Load 52 + 57: 54 Load 56(g_sAniso) + 59: 58 SampledImage 53 57 + 61: 60(ptr) AccessChain 14(i) 35 + 62: 8(fvec2) Load 61 + 63: 11(fvec4) ImageSampleImplicitLod 59 62 + 65: 64(ptr) AccessChain 44(ps_output) 35 + Store 65 63 + Line 42 105 0 + 66:12(PS_OUTPUT) Load 44(ps_output) + ReturnValue 66 + FunctionEnd diff --git a/Test/baseResults/hlsl.pp.line3.frag.out b/Test/baseResults/hlsl.pp.line3.frag.out new file mode 100644 index 00000000..5aa2699e --- /dev/null +++ b/Test/baseResults/hlsl.pp.line3.frag.out @@ -0,0 +1,172 @@ +hlsl.pp.line3.frag +// Module Version 10000 +// Generated by (magic number): 80007 +// Id's are bound by 78 + + Capability Shader + 2: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 5 "MainPs" 69 73 + ExecutionMode 5 OriginUpperLeft + 1: String "hlsl.pp.line3.frag" + 31: String "./i1.h" + Source HLSL 500 1 "// OpModuleProcessed entry-point MainPs +// OpModuleProcessed client vulkan100 +// OpModuleProcessed target-env vulkan1.0 +// OpModuleProcessed hlsl-offsets +#line 1 +Texture2D g_tColor[ 128 ] ; + +layout (push_constant) cbuffer PerViewConstantBuffer_t +{ + uint g_nDataIdx; + uint g_nDataIdx2; + bool g_B; +} ; + +SamplerState g_sAniso; + +struct PS_INPUT +{ + float2 vTextureCoords : TEXCOORD2 ; +} ; + +struct PS_OUTPUT +{ + float4 vColor : SV_Target0 ; +} ; + +PS_OUTPUT MainPs ( PS_INPUT i ) +{ + PS_OUTPUT ps_output ; + + uint u; + if (g_B) +#include "i1.h" + else + u = g_nDataIdx2; + ps_output . vColor = g_tColor [ u ] . Sample ( g_sAniso , i . vTextureCoords . xy ); + return ps_output ; +} + +" + Name 5 "MainPs" + Name 9 "PS_INPUT" + MemberName 9(PS_INPUT) 0 "vTextureCoords" + Name 12 "PS_OUTPUT" + MemberName 12(PS_OUTPUT) 0 "vColor" + Name 15 "@MainPs(struct-PS_INPUT-vf21;" + Name 14 "i" + Name 18 "PerViewConstantBuffer_t" + MemberName 18(PerViewConstantBuffer_t) 0 "g_nDataIdx" + MemberName 18(PerViewConstantBuffer_t) 1 "g_nDataIdx2" + MemberName 18(PerViewConstantBuffer_t) 2 "g_B" + Name 20 "" + Name 33 "u" + Name 42 "ps_output" + Name 47 "g_tColor" + Name 54 "g_sAniso" + Name 67 "i" + Name 69 "i.vTextureCoords" + Name 73 "@entryPointOutput.vColor" + Name 74 "param" + MemberDecorate 18(PerViewConstantBuffer_t) 0 Offset 0 + MemberDecorate 18(PerViewConstantBuffer_t) 1 Offset 4 + MemberDecorate 18(PerViewConstantBuffer_t) 2 Offset 8 + Decorate 18(PerViewConstantBuffer_t) Block + Decorate 47(g_tColor) DescriptorSet 0 + Decorate 54(g_sAniso) DescriptorSet 0 + Decorate 69(i.vTextureCoords) Location 0 + Decorate 73(@entryPointOutput.vColor) Location 0 + 3: TypeVoid + 4: TypeFunction 3 + 7: TypeFloat 32 + 8: TypeVector 7(float) 2 + 9(PS_INPUT): TypeStruct 8(fvec2) + 10: TypePointer Function 9(PS_INPUT) + 11: TypeVector 7(float) 4 + 12(PS_OUTPUT): TypeStruct 11(fvec4) + 13: TypeFunction 12(PS_OUTPUT) 10(ptr) + 17: TypeInt 32 0 +18(PerViewConstantBuffer_t): TypeStruct 17(int) 17(int) 17(int) + 19: TypePointer PushConstant 18(PerViewConstantBuffer_t) + 20: 19(ptr) Variable PushConstant + 21: TypeInt 32 1 + 22: 21(int) Constant 2 + 23: TypePointer PushConstant 17(int) + 26: TypeBool + 27: 17(int) Constant 0 + 32: TypePointer Function 17(int) + 34: 21(int) Constant 0 + 38: 21(int) Constant 1 + 41: TypePointer Function 12(PS_OUTPUT) + 43: TypeImage 7(float) 2D sampled format:Unknown + 44: 17(int) Constant 128 + 45: TypeArray 43 44 + 46: TypePointer UniformConstant 45 + 47(g_tColor): 46(ptr) Variable UniformConstant + 49: TypePointer UniformConstant 43 + 52: TypeSampler + 53: TypePointer UniformConstant 52 + 54(g_sAniso): 53(ptr) Variable UniformConstant + 56: TypeSampledImage 43 + 58: TypePointer Function 8(fvec2) + 62: TypePointer Function 11(fvec4) + 68: TypePointer Input 8(fvec2) +69(i.vTextureCoords): 68(ptr) Variable Input + 72: TypePointer Output 11(fvec4) +73(@entryPointOutput.vColor): 72(ptr) Variable Output + 5(MainPs): 3 Function None 4 + 6: Label + 67(i): 10(ptr) Variable Function + 74(param): 10(ptr) Variable Function + Line 1 23 0 + 70: 8(fvec2) Load 69(i.vTextureCoords) + 71: 58(ptr) AccessChain 67(i) 34 + Store 71 70 + 75: 9(PS_INPUT) Load 67(i) + Store 74(param) 75 + 76:12(PS_OUTPUT) FunctionCall 15(@MainPs(struct-PS_INPUT-vf21;) 74(param) + 77: 11(fvec4) CompositeExtract 76 0 + Store 73(@entryPointOutput.vColor) 77 + Return + FunctionEnd +15(@MainPs(struct-PS_INPUT-vf21;):12(PS_OUTPUT) Function None 13 + 14(i): 10(ptr) FunctionParameter + 16: Label + 33(u): 32(ptr) Variable Function + 42(ps_output): 41(ptr) Variable Function + Line 1 27 0 + 24: 23(ptr) AccessChain 20 22 + 25: 17(int) Load 24 + 28: 26(bool) INotEqual 25 27 + SelectionMerge 30 None + BranchConditional 28 29 37 + 29: Label + Line 31 1 0 + 35: 23(ptr) AccessChain 20 34 + 36: 17(int) Load 35 + Store 33(u) 36 + Branch 30 + 37: Label + Line 1 30 0 + 39: 23(ptr) AccessChain 20 38 + 40: 17(int) Load 39 + Store 33(u) 40 + Branch 30 + 30: Label + Line 1 31 0 + 48: 17(int) Load 33(u) + 50: 49(ptr) AccessChain 47(g_tColor) 48 + 51: 43 Load 50 + 55: 52 Load 54(g_sAniso) + 57: 56 SampledImage 51 55 + 59: 58(ptr) AccessChain 14(i) 34 + 60: 8(fvec2) Load 59 + 61: 11(fvec4) ImageSampleImplicitLod 57 60 + 63: 62(ptr) AccessChain 42(ps_output) 34 + Store 63 61 + Line 1 32 0 + 64:12(PS_OUTPUT) Load 42(ps_output) + ReturnValue 64 + FunctionEnd diff --git a/Test/baseResults/spv.pp.line.frag.out b/Test/baseResults/spv.pp.line.frag.out new file mode 100644 index 00000000..61008d65 --- /dev/null +++ b/Test/baseResults/spv.pp.line.frag.out @@ -0,0 +1,144 @@ +spv.pp.line.frag +WARNING: spv.pp.line.frag:6: varying deprecated in version 130; may be removed in future release +WARNING: spv.pp.line.frag:7: varying deprecated in version 130; may be removed in future release + +// Module Version 10000 +// Generated by (magic number): 80007 +// Id's are bound by 65 + + Capability Shader + Capability Sampled1D + 2: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 5 "main" 41 53 56 59 + ExecutionMode 5 OriginUpperLeft + 1: String "spv.pp.line.frag" + Source GLSL 140 1 "// OpModuleProcessed auto-map-locations +// OpModuleProcessed auto-map-bindings +// OpModuleProcessed client vulkan100 +// OpModuleProcessed target-env vulkan1.0 +// OpModuleProcessed keep-uncalled +// OpModuleProcessed entry-point main +#line 1 +#version 140 + +uniform sampler1D texSampler1D; +uniform sampler2D texSampler2D; + +varying float blend; +varying vec4 u; + +in vec2 coords2D; + +void main() +{ + float blendscale = 1.789; + float bias = 2.0; + float coords1D = 1.789; + vec4 color = vec4(0.0, 0.0, 0.0, 0.0); +#line 53 + color += texture (texSampler1D, coords1D); + color += texture (texSampler1D, coords1D, bias); +#line 102 + color += texture (texSampler2D, coords2D); + color += texture (texSampler2D, coords2D, bias); + + gl_FragColor = mix(color, u, blend * blendscale); +} +" + Name 5 "main" + Name 9 "blendscale" + Name 11 "bias" + Name 13 "coords1D" + Name 16 "color" + Name 22 "texSampler1D" + Name 37 "texSampler2D" + Name 41 "coords2D" + Name 53 "gl_FragColor" + Name 56 "u" + Name 59 "blend" + Decorate 22(texSampler1D) DescriptorSet 0 + Decorate 37(texSampler2D) DescriptorSet 0 + Decorate 53(gl_FragColor) Location 0 + 3: TypeVoid + 4: TypeFunction 3 + 7: TypeFloat 32 + 8: TypePointer Function 7(float) + 10: 7(float) Constant 1071971828 + 12: 7(float) Constant 1073741824 + 14: TypeVector 7(float) 4 + 15: TypePointer Function 14(fvec4) + 17: 7(float) Constant 0 + 18: 14(fvec4) ConstantComposite 17 17 17 17 + 19: TypeImage 7(float) 1D sampled format:Unknown + 20: TypeSampledImage 19 + 21: TypePointer UniformConstant 20 +22(texSampler1D): 21(ptr) Variable UniformConstant + 34: TypeImage 7(float) 2D sampled format:Unknown + 35: TypeSampledImage 34 + 36: TypePointer UniformConstant 35 +37(texSampler2D): 36(ptr) Variable UniformConstant + 39: TypeVector 7(float) 2 + 40: TypePointer Input 39(fvec2) + 41(coords2D): 40(ptr) Variable Input + 52: TypePointer Output 14(fvec4) +53(gl_FragColor): 52(ptr) Variable Output + 55: TypePointer Input 14(fvec4) + 56(u): 55(ptr) Variable Input + 58: TypePointer Input 7(float) + 59(blend): 58(ptr) Variable Input + 5(main): 3 Function None 4 + 6: Label + 9(blendscale): 8(ptr) Variable Function + 11(bias): 8(ptr) Variable Function + 13(coords1D): 8(ptr) Variable Function + 16(color): 15(ptr) Variable Function + Line 1 13 0 + Store 9(blendscale) 10 + Line 1 14 0 + Store 11(bias) 12 + Line 1 15 0 + Store 13(coords1D) 10 + Line 1 16 0 + Store 16(color) 18 + Line 1 54 0 + 23: 20 Load 22(texSampler1D) + 24: 7(float) Load 13(coords1D) + 25: 14(fvec4) ImageSampleImplicitLod 23 24 + 26: 14(fvec4) Load 16(color) + 27: 14(fvec4) FAdd 26 25 + Store 16(color) 27 + Line 1 55 0 + 28: 20 Load 22(texSampler1D) + 29: 7(float) Load 13(coords1D) + 30: 7(float) Load 11(bias) + 31: 14(fvec4) ImageSampleImplicitLod 28 29 Bias 30 + 32: 14(fvec4) Load 16(color) + 33: 14(fvec4) FAdd 32 31 + Store 16(color) 33 + Line 1 103 0 + 38: 35 Load 37(texSampler2D) + 42: 39(fvec2) Load 41(coords2D) + 43: 14(fvec4) ImageSampleImplicitLod 38 42 + 44: 14(fvec4) Load 16(color) + 45: 14(fvec4) FAdd 44 43 + Store 16(color) 45 + Line 1 104 0 + 46: 35 Load 37(texSampler2D) + 47: 39(fvec2) Load 41(coords2D) + 48: 7(float) Load 11(bias) + 49: 14(fvec4) ImageSampleImplicitLod 46 47 Bias 48 + 50: 14(fvec4) Load 16(color) + 51: 14(fvec4) FAdd 50 49 + Store 16(color) 51 + Line 1 106 0 + 54: 14(fvec4) Load 16(color) + 57: 14(fvec4) Load 56(u) + 60: 7(float) Load 59(blend) + 61: 7(float) Load 9(blendscale) + 62: 7(float) FMul 60 61 + 63: 14(fvec4) CompositeConstruct 62 62 62 62 + 64: 14(fvec4) ExtInst 2(GLSL.std.450) 46(FMix) 54 57 63 + Store 53(gl_FragColor) 64 + Return + FunctionEnd diff --git a/Test/hlsl.pp.line2.frag b/Test/hlsl.pp.line2.frag new file mode 100644 index 00000000..2d16db21 --- /dev/null +++ b/Test/hlsl.pp.line2.frag @@ -0,0 +1,40 @@ +#line 1 "foo.frag" +Texture2D g_tColor[ 128 ] ; + +layout (push_constant) cbuffer PerViewConstantBuffer_t +{ + uint g_nDataIdx; + uint g_nDataIdx2; + bool g_B; +} ; + +SamplerState g_sAniso; + +struct PS_INPUT +{ + float2 vTextureCoords : TEXCOORD2 ; +} ; + +struct PS_OUTPUT +{ + float4 vColor : SV_Target0 ; +} ; + +PS_OUTPUT MainPs ( PS_INPUT i ) +{ + PS_OUTPUT ps_output ; + + uint u; +#line 47 + if (g_B) +#line 3 "foo.h" + u = g_nDataIdx; + else +#line 67 + u = g_nDataIdx2; +#line 7 "foo2.h" + ps_output . vColor = g_tColor [ u ] . Sample ( g_sAniso , i . vTextureCoords . xy ); +#line 105 + return ps_output ; +} + diff --git a/Test/hlsl.pp.line3.frag b/Test/hlsl.pp.line3.frag new file mode 100644 index 00000000..7d85630f --- /dev/null +++ b/Test/hlsl.pp.line3.frag @@ -0,0 +1,34 @@ +Texture2D g_tColor[ 128 ] ; + +layout (push_constant) cbuffer PerViewConstantBuffer_t +{ + uint g_nDataIdx; + uint g_nDataIdx2; + bool g_B; +} ; + +SamplerState g_sAniso; + +struct PS_INPUT +{ + float2 vTextureCoords : TEXCOORD2 ; +} ; + +struct PS_OUTPUT +{ + float4 vColor : SV_Target0 ; +} ; + +PS_OUTPUT MainPs ( PS_INPUT i ) +{ + PS_OUTPUT ps_output ; + + uint u; + if (g_B) +#include "i1.h" + else + u = g_nDataIdx2; + ps_output . vColor = g_tColor [ u ] . Sample ( g_sAniso , i . vTextureCoords . xy ); + return ps_output ; +} + diff --git a/Test/i1.h b/Test/i1.h new file mode 100644 index 00000000..e068ff70 --- /dev/null +++ b/Test/i1.h @@ -0,0 +1 @@ + u = g_nDataIdx; diff --git a/Test/runtests b/Test/runtests index 8cc8b7a8..c88cb590 100755 --- a/Test/runtests +++ b/Test/runtests @@ -152,6 +152,8 @@ $EXE -l -i include.vert > $TARGETDIR/include.vert.out diff -b $BASEDIR/include.vert.out $TARGETDIR/include.vert.out || HASERROR=1 $EXE -D -Od -e main -H -Od -Iinc1/path1 -Iinc1/path2 hlsl.dashI.vert > $TARGETDIR/hlsl.dashI.vert.out diff -b $BASEDIR/hlsl.dashI.vert.out $TARGETDIR/hlsl.dashI.vert.out || HASERROR=1 +$EXE -D -Od -e MainPs -H -Od -g hlsl.pp.line3.frag > $TARGETDIR/hlsl.pp.line3.frag.out +diff -b $BASEDIR/hlsl.pp.line3.frag.out $TARGETDIR/hlsl.pp.line3.frag.out || HASERROR=1 # # Testing -D and -U diff --git a/Test/spv.pp.line.frag b/Test/spv.pp.line.frag new file mode 100644 index 00000000..464463c3 --- /dev/null +++ b/Test/spv.pp.line.frag @@ -0,0 +1,25 @@ +#version 140 + +uniform sampler1D texSampler1D; +uniform sampler2D texSampler2D; + +varying float blend; +varying vec4 u; + +in vec2 coords2D; + +void main() +{ + float blendscale = 1.789; + float bias = 2.0; + float coords1D = 1.789; + vec4 color = vec4(0.0, 0.0, 0.0, 0.0); +#line 53 + color += texture (texSampler1D, coords1D); + color += texture (texSampler1D, coords1D, bias); +#line 102 + color += texture (texSampler2D, coords2D); + color += texture (texSampler2D, coords2D, bias); + + gl_FragColor = mix(color, u, blend * blendscale); +} diff --git a/glslang/Include/Common.h b/glslang/Include/Common.h index 35eaa310..b136dde4 100644 --- a/glslang/Include/Common.h +++ b/glslang/Include/Common.h @@ -229,16 +229,28 @@ inline const TString String(const int i, const int /*base*/ = 10) #endif struct TSourceLoc { - void init() { name = nullptr; string = 0; line = 0; column = 0; } + void init() + { + name = nullptr; string = 0; line = 0; column = 0; + } void init(int stringNum) { init(); string = stringNum; } // Returns the name if it exists. Otherwise, returns the string number. std::string getStringNameOrNum(bool quoteStringName = true) const { - if (name != nullptr) - return quoteStringName ? ("\"" + std::string(name) + "\"") : name; + if (name != nullptr) { + TString qstr = quoteStringName ? ("\"" + *name + "\"") : *name; + std::string ret_str(qstr.c_str()); + return ret_str; + } return std::to_string((long long)string); } - const char* name; // descriptive name for this string + const char* getFilename() const + { + if (name == nullptr) + return nullptr; + return name->c_str(); + } + TString* name; // descriptive name for this string int string; int line; int column; diff --git a/glslang/MachineIndependent/Scan.h b/glslang/MachineIndependent/Scan.h index 2c26c2ef..24b75cf7 100644 --- a/glslang/MachineIndependent/Scan.h +++ b/glslang/MachineIndependent/Scan.h @@ -65,7 +65,7 @@ public: } if (names != nullptr) { for (int i = 0; i < numSources; ++i) - loc[i].name = names[i]; + loc[i].name = names[i] != nullptr ? NewPoolTString(names[i]) : nullptr; } loc[currentSource].line = 1; logicalSourceLoc.init(1); @@ -170,16 +170,18 @@ public: // for #line override in filename based parsing void setFile(const char* filename) { - logicalSourceLoc.name = filename; - loc[getLastValidSourceIndex()].name = filename; + TString* fn_tstr = NewPoolTString(filename); + logicalSourceLoc.name = fn_tstr; + loc[getLastValidSourceIndex()].name = fn_tstr; } void setFile(const char* filename, int i) { + TString* fn_tstr = NewPoolTString(filename); if (i == getLastValidSourceIndex()) { - logicalSourceLoc.name = filename; + logicalSourceLoc.name = fn_tstr; } - loc[i].name = filename; + loc[i].name = fn_tstr; } void setString(int newString) diff --git a/glslang/MachineIndependent/preprocessor/PpContext.h b/glslang/MachineIndependent/preprocessor/PpContext.h index 64681fc3..2559e4d2 100644 --- a/glslang/MachineIndependent/preprocessor/PpContext.h +++ b/glslang/MachineIndependent/preprocessor/PpContext.h @@ -533,7 +533,7 @@ protected: prologue_(prologue), epilogue_(epilogue), includedFile_(includedFile), - scanner(3, strings, lengths, names, 0, 0, true), + scanner(3, strings, lengths, nullptr, 0, 0, true), prevScanner(nullptr), stringInput(pp, scanner) { @@ -548,9 +548,9 @@ protected: scanner.setLine(startLoc.line); scanner.setString(startLoc.string); - scanner.setFile(startLoc.name, 0); - scanner.setFile(startLoc.name, 1); - scanner.setFile(startLoc.name, 2); + scanner.setFile(startLoc.name->c_str(), 0); + scanner.setFile(startLoc.name->c_str(), 1); + scanner.setFile(startLoc.name->c_str(), 2); } // tInput methods: @@ -590,8 +590,6 @@ protected: const char* strings[3]; // Length of str_, passed to scanner constructor. size_t lengths[3]; - // String names - const char* names[3]; // Scans over str_. TInputScanner scanner; // The previous effective scanner before the scanner in this instance diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp index 809e5257..d4c2202e 100644 --- a/gtests/Hlsl.FromFile.cpp +++ b/gtests/Hlsl.FromFile.cpp @@ -61,6 +61,7 @@ using HlslCompileTest = GlslangTest<::testing::TestWithParam>; using HlslCompileAndFlattenTest = GlslangTest<::testing::TestWithParam>; using HlslLegalizeTest = GlslangTest<::testing::TestWithParam>; +using HlslDebugTest = GlslangTest<::testing::TestWithParam>; // Compiling HLSL to pre-legalized SPIR-V under Vulkan semantics. Expected // to successfully generate both AST and SPIR-V. @@ -95,6 +96,16 @@ TEST_P(HlslLegalizeTest, FromFile) "/baseLegalResults/", true); } +// Compiling HLSL to pre-legalized SPIR-V. Expected to successfully generate +// SPIR-V with debug instructions, particularly line info. +TEST_P(HlslDebugTest, FromFile) +{ + loadFileCompileAndCheck(GlobalTestSettings.testRoot, GetParam().fileName, + Source::HLSL, Semantics::Vulkan, glslang::EShTargetVulkan_1_0, + Target::Spv, true, GetParam().entryPoint, + "/baseResults/", false, true); +} + // clang-format off INSTANTIATE_TEST_CASE_P( ToSpirv, HlslCompileTest, @@ -437,5 +448,15 @@ INSTANTIATE_TEST_CASE_P( // clang-format on #endif +// clang-format off +INSTANTIATE_TEST_CASE_P( + ToSpirv, HlslDebugTest, + ::testing::ValuesIn(std::vector{ + {"hlsl.pp.line2.frag", "MainPs"} + }), + FileNameAsCustomTestSuffix +); + +// clang-format on } // anonymous namespace } // namespace glslangtest diff --git a/gtests/Spv.FromFile.cpp b/gtests/Spv.FromFile.cpp index 1e17736f..77a30811 100755 --- a/gtests/Spv.FromFile.cpp +++ b/gtests/Spv.FromFile.cpp @@ -63,6 +63,7 @@ std::string FileNameAsCustomTestSuffixIoMap( } using CompileVulkanToSpirvTest = GlslangTest<::testing::TestWithParam>; +using CompileVulkanToDebugSpirvTest = GlslangTest<::testing::TestWithParam>; using CompileVulkan1_1ToSpirvTest = GlslangTest<::testing::TestWithParam>; using CompileOpenGLToSpirvTest = GlslangTest<::testing::TestWithParam>; using VulkanSemantics = GlslangTest<::testing::TestWithParam>; @@ -87,6 +88,17 @@ TEST_P(CompileVulkanToSpirvTest, FromFile) Target::Spv); } +// Compiling GLSL to SPIR-V with debug info under Vulkan semantics. Expected +// to successfully generate SPIR-V. +TEST_P(CompileVulkanToDebugSpirvTest, FromFile) +{ + loadFileCompileAndCheck(GlobalTestSettings.testRoot, GetParam(), + Source::GLSL, Semantics::Vulkan, + glslang::EShTargetVulkan_1_0, + Target::Spv, true, "", + "/baseResults/", false, true); +} + TEST_P(CompileVulkan1_1ToSpirvTest, FromFile) { loadFileCompileAndCheck(GlobalTestSettings.testRoot, GetParam(), @@ -369,6 +381,15 @@ INSTANTIATE_TEST_CASE_P( FileNameAsCustomTestSuffix ); +// clang-format off +INSTANTIATE_TEST_CASE_P( + Glsl, CompileVulkanToDebugSpirvTest, + ::testing::ValuesIn(std::vector({ + "spv.pp.line.frag", + })), + FileNameAsCustomTestSuffix +); + // clang-format off INSTANTIATE_TEST_CASE_P( Glsl, CompileVulkan1_1ToSpirvTest, diff --git a/gtests/TestFixture.h b/gtests/TestFixture.h index a3a8eb12..49320126 100755 --- a/gtests/TestFixture.h +++ b/gtests/TestFixture.h @@ -184,12 +184,19 @@ public: // and modifies |shader| on success. bool compile(glslang::TShader* shader, const std::string& code, const std::string& entryPointName, EShMessages controls, - const TBuiltInResource* resources=nullptr) + const TBuiltInResource* resources=nullptr, + const std::string* shaderName=nullptr) { const char* shaderStrings = code.data(); const int shaderLengths = static_cast(code.size()); + const char* shaderNames = nullptr; - shader->setStringsWithLengths(&shaderStrings, &shaderLengths, 1); + if ((controls & EShMsgDebugInfo) && shaderName != nullptr) { + shaderNames = shaderName->data(); + shader->setStringsWithLengthsAndNames( + &shaderStrings, &shaderLengths, &shaderNames, 1); + } else + shader->setStringsWithLengths(&shaderStrings, &shaderLengths, 1); if (!entryPointName.empty()) shader->setEntryPoint(entryPointName.c_str()); return shader->parse( (resources ? resources : &glslang::DefaultTBuiltInResource), @@ -202,12 +209,13 @@ public: // during the process. If the target includes SPIR-V, also disassembles // the result and returns disassembly text. GlslangResult compileAndLink( - const std::string shaderName, const std::string& code, + const std::string& shaderName, const std::string& code, const std::string& entryPointName, EShMessages controls, glslang::EShTargetClientVersion clientTargetVersion, bool flattenUniformArrays = false, EShTextureSamplerTransformMode texSampTransMode = EShTexSampTransKeep, bool enableOptimizer = false, + bool enableDebug = false, bool automap = true) { const EShLanguage stage = GetShaderStage(GetSuffix(shaderName)); @@ -238,7 +246,8 @@ public: } } - bool success = compile(&shader, code, entryPointName, controls); + bool success = compile( + &shader, code, entryPointName, controls, nullptr, &shaderName); glslang::TProgram program; program.addShader(&shader); @@ -249,6 +258,7 @@ public: if (success && (controls & EShMsgSpvRules)) { std::vector spirv_binary; options().disableOptimizer = !enableOptimizer; + options().generateDebugInfo = enableDebug; glslang::GlslangToSpv(*program.getIntermediate(stage), spirv_binary, &logger, &options()); @@ -423,7 +433,8 @@ public: bool automap = true, const std::string& entryPointName="", const std::string& baseDir="/baseResults/", - const bool enableOptimizer = false) + const bool enableOptimizer = false, + const bool enableDebug = false) { const std::string inputFname = testDir + "/" + testName; const std::string expectedOutputFname = @@ -436,8 +447,10 @@ public: EShMessages controls = DeriveOptions(source, semantics, target); if (enableOptimizer) controls = static_cast(controls & ~EShMsgHlslLegalization); + if (enableDebug) + controls = static_cast(controls | EShMsgDebugInfo); GlslangResult result = compileAndLink(testName, input, entryPointName, controls, clientTargetVersion, false, - EShTexSampTransKeep, enableOptimizer, automap); + EShTexSampTransKeep, enableOptimizer, enableDebug, automap); // Generate the hybrid output in the way of glslangValidator. std::ostringstream stream; diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp index b536cc9d..699c524b 100755 --- a/hlsl/hlslParseHelper.cpp +++ b/hlsl/hlslParseHelper.cpp @@ -133,7 +133,7 @@ bool HlslParseContext::parseShaderStrings(TPpContext& ppContext, TInputScanner& // Print a message formated such that if you click on the message it will take you right to // the line through most UIs. const glslang::TSourceLoc& sourceLoc = input.getSourceLoc(); - infoSink.info << sourceLoc.name << "(" << sourceLoc.line << "): error at column " << sourceLoc.column + infoSink.info << sourceLoc.name->c_str() << "(" << sourceLoc.line << "): error at column " << sourceLoc.column << ", HLSL parsing failed.\n"; ++numErrors; return false;