diff --git a/Test/baseResults/hlsl.mip.negative.frag.out b/Test/baseResults/hlsl.mip.negative.frag.out new file mode 100644 index 000000000..36f41377d --- /dev/null +++ b/Test/baseResults/hlsl.mip.negative.frag.out @@ -0,0 +1,68 @@ +hlsl.mip.negative.frag +ERROR: 0:5: '' : unterminated mips operator: +ERROR: 1 compilation errors. No code generated. + + +Shader version: 500 +gl_FragCoord origin is upper left +ERROR: node is still EOpNull! +0:4 Function Definition: @main( ( temp 4-component vector of float) +0:4 Function Parameters: +0:? Sequence +0:? textureFetch ( temp 4-component vector of float) +0:5 'g_tTex2df4' ( uniform texture2D) +0:? Constant: +0:? 3 (const uint) +0:? 4 (const uint) +0:5 Constant: +0:5 2 (const int) +0:7 Branch: Return with expression +0:7 Constant: +0:7 0.000000 +0:7 0.000000 +0:7 0.000000 +0:7 0.000000 +0:4 Function Definition: main( ( temp void) +0:4 Function Parameters: +0:? Sequence +0:4 move second child to first child ( temp 4-component vector of float) +0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) +0:4 Function Call: @main( ( temp 4-component vector of float) +0:? Linker Objects +0:? 'g_tTex2df4' ( uniform texture2D) +0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) + + +Linked fragment stage: + + +Shader version: 500 +gl_FragCoord origin is upper left +ERROR: node is still EOpNull! +0:4 Function Definition: @main( ( temp 4-component vector of float) +0:4 Function Parameters: +0:? Sequence +0:? textureFetch ( temp 4-component vector of float) +0:5 'g_tTex2df4' ( uniform texture2D) +0:? Constant: +0:? 3 (const uint) +0:? 4 (const uint) +0:5 Constant: +0:5 2 (const int) +0:7 Branch: Return with expression +0:7 Constant: +0:7 0.000000 +0:7 0.000000 +0:7 0.000000 +0:7 0.000000 +0:4 Function Definition: main( ( temp void) +0:4 Function Parameters: +0:? Sequence +0:4 move second child to first child ( temp 4-component vector of float) +0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) +0:4 Function Call: @main( ( temp 4-component vector of float) +0:? Linker Objects +0:? 'g_tTex2df4' ( uniform texture2D) +0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) + +SPIR-V is not generated for failed compile or link diff --git a/Test/baseResults/hlsl.mip.negative2.frag.out b/Test/baseResults/hlsl.mip.negative2.frag.out new file mode 100644 index 000000000..75cf95fc5 --- /dev/null +++ b/Test/baseResults/hlsl.mip.negative2.frag.out @@ -0,0 +1,74 @@ +hlsl.mip.negative2.frag +ERROR: 0:5: 'r' : unexpected operator on texture type: uniform texture2D +ERROR: 1 compilation errors. No code generated. + + +Shader version: 500 +gl_FragCoord origin is upper left +ERROR: node is still EOpNull! +0:4 Function Definition: @main( ( temp 4-component vector of float) +0:4 Function Parameters: +0:? Sequence +0:5 direct index ( temp float) +0:5 textureFetch ( temp 4-component vector of float) +0:5 'g_tTex2df4' ( uniform texture2D) +0:5 Constant: +0:5 2 (const int) +0:5 Constant: +0:5 0 (const int) +0:? Constant: +0:? 3 (const uint) +0:? 4 (const uint) +0:7 Branch: Return with expression +0:7 Constant: +0:7 0.000000 +0:7 0.000000 +0:7 0.000000 +0:7 0.000000 +0:4 Function Definition: main( ( temp void) +0:4 Function Parameters: +0:? Sequence +0:4 move second child to first child ( temp 4-component vector of float) +0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) +0:4 Function Call: @main( ( temp 4-component vector of float) +0:? Linker Objects +0:? 'g_tTex2df4' ( uniform texture2D) +0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) + + +Linked fragment stage: + + +Shader version: 500 +gl_FragCoord origin is upper left +ERROR: node is still EOpNull! +0:4 Function Definition: @main( ( temp 4-component vector of float) +0:4 Function Parameters: +0:? Sequence +0:5 direct index ( temp float) +0:5 textureFetch ( temp 4-component vector of float) +0:5 'g_tTex2df4' ( uniform texture2D) +0:5 Constant: +0:5 2 (const int) +0:5 Constant: +0:5 0 (const int) +0:? Constant: +0:? 3 (const uint) +0:? 4 (const uint) +0:7 Branch: Return with expression +0:7 Constant: +0:7 0.000000 +0:7 0.000000 +0:7 0.000000 +0:7 0.000000 +0:4 Function Definition: main( ( temp void) +0:4 Function Parameters: +0:? Sequence +0:4 move second child to first child ( temp 4-component vector of float) +0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) +0:4 Function Call: @main( ( temp 4-component vector of float) +0:? Linker Objects +0:? 'g_tTex2df4' ( uniform texture2D) +0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) + +SPIR-V is not generated for failed compile or link diff --git a/Test/baseResults/hlsl.mip.operator.frag.out b/Test/baseResults/hlsl.mip.operator.frag.out new file mode 100644 index 000000000..3c68fd97e --- /dev/null +++ b/Test/baseResults/hlsl.mip.operator.frag.out @@ -0,0 +1,209 @@ +hlsl.mip.operator.frag +Shader version: 500 +gl_FragCoord origin is upper left +0:? Sequence +0:5 Function Definition: @main( ( temp 4-component vector of float) +0:5 Function Parameters: +0:? Sequence +0:13 Branch: Return with expression +0:9 add ( temp 4-component vector of float) +0:6 add ( temp 4-component vector of float) +0:? textureFetch ( temp 4-component vector of float) +0:6 'g_tTex2df4' ( uniform texture2D) +0:? Constant: +0:? 3 (const uint) +0:? 4 (const uint) +0:6 Constant: +0:6 2 (const int) +0:? textureFetch ( temp 4-component vector of float) +0:9 'g_tTex2df4a' ( uniform texture2DArray) +0:? Constant: +0:? 6 (const uint) +0:? 7 (const uint) +0:? 8 (const uint) +0:9 Constant: +0:9 5 (const uint) +0:13 textureFetch ( temp 4-component vector of float) +0:13 'g_tTex2df4' ( uniform texture2D) +0:13 Convert float to uint ( temp 2-component vector of uint) +0:13 vector swizzle ( temp 2-component vector of float) +0:? textureFetch ( temp 4-component vector of float) +0:13 'g_tTex2df4' ( uniform texture2D) +0:? Constant: +0:? 14 (const uint) +0:? 15 (const uint) +0:13 Constant: +0:13 13 (const int) +0:13 Sequence +0:13 Constant: +0:13 0 (const int) +0:13 Constant: +0:13 1 (const int) +0:13 Convert float to uint ( temp uint) +0:13 direct index ( temp float) +0:? textureFetch ( temp 4-component vector of float) +0:13 'g_tTex2df4' ( uniform texture2D) +0:? Constant: +0:? 10 (const uint) +0:? 11 (const uint) +0:13 Constant: +0:13 9 (const int) +0:13 Constant: +0:13 0 (const int) +0:5 Function Definition: main( ( temp void) +0:5 Function Parameters: +0:? Sequence +0:5 move second child to first child ( temp 4-component vector of float) +0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) +0:5 Function Call: @main( ( temp 4-component vector of float) +0:? Linker Objects +0:? 'g_tTex2df4a' ( uniform texture2DArray) +0:? 'g_tTex2df4' ( uniform texture2D) +0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) + + +Linked fragment stage: + + +Shader version: 500 +gl_FragCoord origin is upper left +0:? Sequence +0:5 Function Definition: @main( ( temp 4-component vector of float) +0:5 Function Parameters: +0:? Sequence +0:13 Branch: Return with expression +0:9 add ( temp 4-component vector of float) +0:6 add ( temp 4-component vector of float) +0:? textureFetch ( temp 4-component vector of float) +0:6 'g_tTex2df4' ( uniform texture2D) +0:? Constant: +0:? 3 (const uint) +0:? 4 (const uint) +0:6 Constant: +0:6 2 (const int) +0:? textureFetch ( temp 4-component vector of float) +0:9 'g_tTex2df4a' ( uniform texture2DArray) +0:? Constant: +0:? 6 (const uint) +0:? 7 (const uint) +0:? 8 (const uint) +0:9 Constant: +0:9 5 (const uint) +0:13 textureFetch ( temp 4-component vector of float) +0:13 'g_tTex2df4' ( uniform texture2D) +0:13 Convert float to uint ( temp 2-component vector of uint) +0:13 vector swizzle ( temp 2-component vector of float) +0:? textureFetch ( temp 4-component vector of float) +0:13 'g_tTex2df4' ( uniform texture2D) +0:? Constant: +0:? 14 (const uint) +0:? 15 (const uint) +0:13 Constant: +0:13 13 (const int) +0:13 Sequence +0:13 Constant: +0:13 0 (const int) +0:13 Constant: +0:13 1 (const int) +0:13 Convert float to uint ( temp uint) +0:13 direct index ( temp float) +0:? textureFetch ( temp 4-component vector of float) +0:13 'g_tTex2df4' ( uniform texture2D) +0:? Constant: +0:? 10 (const uint) +0:? 11 (const uint) +0:13 Constant: +0:13 9 (const int) +0:13 Constant: +0:13 0 (const int) +0:5 Function Definition: main( ( temp void) +0:5 Function Parameters: +0:? Sequence +0:5 move second child to first child ( temp 4-component vector of float) +0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) +0:5 Function Call: @main( ( temp 4-component vector of float) +0:? Linker Objects +0:? 'g_tTex2df4a' ( uniform texture2DArray) +0:? 'g_tTex2df4' ( uniform texture2D) +0:? '@entryPointOutput' (layout( location=0) out 4-component vector of float) + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 61 + + Capability Shader + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "main" 59 + ExecutionMode 4 OriginUpperLeft + Source HLSL 500 + Name 4 "main" + Name 9 "@main(" + Name 13 "g_tTex2df4" + Name 25 "g_tTex2df4a" + Name 59 "@entryPointOutput" + Decorate 13(g_tTex2df4) DescriptorSet 0 + Decorate 25(g_tTex2df4a) DescriptorSet 0 + Decorate 59(@entryPointOutput) Location 0 + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeFloat 32 + 7: TypeVector 6(float) 4 + 8: TypeFunction 7(fvec4) + 11: TypeImage 6(float) 2D sampled format:Unknown + 12: TypePointer UniformConstant 11 + 13(g_tTex2df4): 12(ptr) Variable UniformConstant + 15: TypeInt 32 0 + 16: TypeVector 15(int) 2 + 17: 15(int) Constant 3 + 18: 15(int) Constant 4 + 19: 16(ivec2) ConstantComposite 17 18 + 20: TypeInt 32 1 + 21: 20(int) Constant 2 + 23: TypeImage 6(float) 2D array sampled format:Unknown + 24: TypePointer UniformConstant 23 + 25(g_tTex2df4a): 24(ptr) Variable UniformConstant + 27: TypeVector 15(int) 3 + 28: 15(int) Constant 6 + 29: 15(int) Constant 7 + 30: 15(int) Constant 8 + 31: 27(ivec3) ConstantComposite 28 29 30 + 32: 15(int) Constant 5 + 37: 15(int) Constant 14 + 38: 15(int) Constant 15 + 39: 16(ivec2) ConstantComposite 37 38 + 40: 20(int) Constant 13 + 42: TypeVector 6(float) 2 + 46: 15(int) Constant 10 + 47: 15(int) Constant 11 + 48: 16(ivec2) ConstantComposite 46 47 + 49: 20(int) Constant 9 + 51: 15(int) Constant 0 + 58: TypePointer Output 7(fvec4) +59(@entryPointOutput): 58(ptr) Variable Output + 4(main): 2 Function None 3 + 5: Label + 60: 7(fvec4) FunctionCall 9(@main() + Store 59(@entryPointOutput) 60 + Return + FunctionEnd + 9(@main(): 7(fvec4) Function None 8 + 10: Label + 14: 11 Load 13(g_tTex2df4) + 22: 7(fvec4) ImageFetch 14 19 Lod 21 + 26: 23 Load 25(g_tTex2df4a) + 33: 7(fvec4) ImageFetch 26 31 Lod 32 + 34: 7(fvec4) FAdd 22 33 + 35: 11 Load 13(g_tTex2df4) + 36: 11 Load 13(g_tTex2df4) + 41: 7(fvec4) ImageFetch 36 39 Lod 40 + 43: 42(fvec2) VectorShuffle 41 41 0 1 + 44: 16(ivec2) ConvertFToU 43 + 45: 11 Load 13(g_tTex2df4) + 50: 7(fvec4) ImageFetch 45 48 Lod 49 + 52: 6(float) CompositeExtract 50 0 + 53: 15(int) ConvertFToU 52 + 54: 7(fvec4) ImageFetch 35 44 Lod 53 + 55: 7(fvec4) FAdd 34 54 + ReturnValue 55 + FunctionEnd diff --git a/Test/hlsl.mip.negative.frag b/Test/hlsl.mip.negative.frag new file mode 100644 index 000000000..900d38506 --- /dev/null +++ b/Test/hlsl.mip.negative.frag @@ -0,0 +1,9 @@ +Texture2D g_tTex2df4; + +float4 main() : SV_Target0 +{ + g_tTex2df4.mips.mips[2][uint2(3, 4)]; // error to chain like this + + return 0; +} + diff --git a/Test/hlsl.mip.negative2.frag b/Test/hlsl.mip.negative2.frag new file mode 100644 index 000000000..c07179eb2 --- /dev/null +++ b/Test/hlsl.mip.negative2.frag @@ -0,0 +1,9 @@ +Texture2D g_tTex2df4; + +float4 main() : SV_Target0 +{ + g_tTex2df4.r[2][uint2(3, 4)]; // '.r' not valid on texture object + + return 0; +} + diff --git a/Test/hlsl.mip.operator.frag b/Test/hlsl.mip.operator.frag new file mode 100644 index 000000000..af4f15013 --- /dev/null +++ b/Test/hlsl.mip.operator.frag @@ -0,0 +1,14 @@ +Texture2DArray g_tTex2df4a; +Texture2D g_tTex2df4; + +float4 main() : SV_Target0 +{ + return g_tTex2df4.mips[2][uint2(3, 4)] + + + // test float->uint cast on the mip arg + g_tTex2df4a.mips[5.2][uint3(6, 7, 8)] + + + // Test nesting involving .mips operators: + // ....outer operator mip level...... .....outer operator coordinate.... + g_tTex2df4.mips[ g_tTex2df4.mips[9][uint2(10,11)][0] ][ g_tTex2df4.mips[13][uint2(14,15)].xy ]; +} diff --git a/Test/remap.specconst.comp b/Test/remap.specconst.comp new file mode 100644 index 000000000..52ac07aa0 --- /dev/null +++ b/Test/remap.specconst.comp @@ -0,0 +1,7 @@ +#version 450 + +layout (local_size_x_id = 0, local_size_y_id = 1, local_size_z_id = 2) in; + +shared int foo[gl_WorkGroupSize.x + gl_WorkGroupSize.y * gl_WorkGroupSize.z]; + +void main () {} diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp index 7dbed5e0b..9612a4cfb 100644 --- a/gtests/Hlsl.FromFile.cpp +++ b/gtests/Hlsl.FromFile.cpp @@ -177,6 +177,9 @@ INSTANTIATE_TEST_CASE_P( {"hlsl.logicalConvert.frag", "main"}, {"hlsl.logical.unary.frag", "main"}, {"hlsl.loopattr.frag", "main"}, + {"hlsl.mip.operator.frag", "main"}, + {"hlsl.mip.negative.frag", "main"}, + {"hlsl.mip.negative2.frag", "main"}, {"hlsl.namespace.frag", "main"}, {"hlsl.nonint-index.frag", "main"}, {"hlsl.matNx1.frag", "main"}, diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp index 54be46766..75115f837 100755 --- a/hlsl/hlslParseHelper.cpp +++ b/hlsl/hlslParseHelper.cpp @@ -677,19 +677,30 @@ TIntermTyped* HlslParseContext::handleBracketOperator(const TSourceLoc& loc, TIn if (base->getType().getBasicType() == EbtSampler && !base->isArray()) { const TSampler& sampler = base->getType().getSampler(); if (sampler.isImage() || sampler.isTexture()) { - TIntermAggregate* load = new TIntermAggregate(sampler.isImage() ? EOpImageLoad : EOpTextureFetch); + if (! mipsOperatorMipArg.empty() && mipsOperatorMipArg.back().mipLevel == nullptr) { + // The first operator[] to a .mips[] sequence is the mip level. We'll remember it. + mipsOperatorMipArg.back().mipLevel = index; + return base; // next [] index is to the same base. + } else { + TIntermAggregate* load = new TIntermAggregate(sampler.isImage() ? EOpImageLoad : EOpTextureFetch); - load->setType(TType(sampler.type, EvqTemporary, sampler.vectorSize)); - load->setLoc(loc); - load->getSequence().push_back(base); - load->getSequence().push_back(index); + load->setType(TType(sampler.type, EvqTemporary, sampler.vectorSize)); + load->setLoc(loc); + load->getSequence().push_back(base); + load->getSequence().push_back(index); - // Textures need a MIP. First indirection is always to mip 0. If there's another, we'll add it - // later. - if (sampler.isTexture()) - load->getSequence().push_back(intermediate.addConstantUnion(0, loc, true)); + // Textures need a MIP. If we saw one go by, use it. Otherwise, use zero. + if (sampler.isTexture()) { + if (! mipsOperatorMipArg.empty()) { + load->getSequence().push_back(mipsOperatorMipArg.back().mipLevel); + mipsOperatorMipArg.pop_back(); + } else { + load->getSequence().push_back(intermediate.addConstantUnion(0, loc, true)); + } + } - return load; + return load; + } } } @@ -874,7 +885,21 @@ TIntermTyped* HlslParseContext::handleDotDereference(const TSourceLoc& loc, TInt } TIntermTyped* result = base; - if (base->isVector() || base->isScalar()) { + + if (base->getType().getBasicType() == EbtSampler) { + // Handle .mips[mipid][pos] operation on textures + const TSampler& sampler = base->getType().getSampler(); + if (sampler.isTexture() && field == "mips") { + // Push a null to signify that we expect a mip level under operator[] next. + mipsOperatorMipArg.push_back(tMipsOperatorData(loc, nullptr)); + // Keep 'result' pointing to 'base', since we expect an operator[] to go by next. + } else { + if (field == "mips") + error(loc, "unexpected texture type for .mips[][] operator:", base->getType().getCompleteString().c_str(), ""); + else + error(loc, "unexpected operator on texture type:", field.c_str(), base->getType().getCompleteString().c_str()); + } + } else if (base->isVector() || base->isScalar()) { TSwizzleSelectors selectors; parseSwizzleSelector(loc, field, base->getVectorSize(), selectors); @@ -8426,6 +8451,12 @@ void HlslParseContext::removeUnusedStructBufferCounters() // post-processing void HlslParseContext::finish() { + // Error check: There was a dangling .mips operator. These are not nested constructs in the grammar, so + // cannot be detected there. This is not strictly needed in a non-validating parser; it's just helpful. + if (! mipsOperatorMipArg.empty()) { + error(mipsOperatorMipArg.back().loc, "unterminated mips operator:", "", ""); + } + removeUnusedStructBufferCounters(); addPatchConstantInvocation(); addInterstageIoToLinkage(); diff --git a/hlsl/hlslParseHelper.h b/hlsl/hlslParseHelper.h index d5cbc0633..4b5c0b75f 100755 --- a/hlsl/hlslParseHelper.h +++ b/hlsl/hlslParseHelper.h @@ -429,6 +429,17 @@ protected: TVector implicitThisStack; // currently active 'this' variables for nested structures TVariable* gsStreamOutput; // geometry shader stream outputs, for emit (Append method) + + // This tracks the first (mip level) argument to the .mips[][] operator. Since this can be nested as + // in tx.mips[tx.mips[0][1].x][2], we need a stack. We also track the TSourceLoc for error reporting + // purposes. + struct tMipsOperatorData { + tMipsOperatorData(TSourceLoc l, TIntermTyped* m) : loc(l), mipLevel(m) { } + TSourceLoc loc; + TIntermTyped* mipLevel; + }; + + TVector mipsOperatorMipArg; }; // This is the prefix we use for builtin methods to avoid namespace collisions with