From 726bf96a72634c54ac1f48d8ba9fb7b4652497e3 Mon Sep 17 00:00:00 2001 From: LoopDawg Date: Fri, 12 May 2017 17:14:31 -0600 Subject: [PATCH] HLSL: add .mips[][] operator for texture types This implements mytex.mips[mip][coord] for texture types. There is some error testing, but not comprehensive. The constructs can be nested, e.g in this case the inner .mips is parsed before the completion of the outer [][] operator. tx.mips[tx.mips[a][b].x][c] --- Test/baseResults/hlsl.mip.negative.frag.out | 68 ++++++ Test/baseResults/hlsl.mip.negative2.frag.out | 74 +++++++ Test/baseResults/hlsl.mip.operator.frag.out | 209 +++++++++++++++++++ Test/hlsl.mip.negative.frag | 9 + Test/hlsl.mip.negative2.frag | 9 + Test/hlsl.mip.operator.frag | 14 ++ Test/remap.specconst.comp | 7 + gtests/Hlsl.FromFile.cpp | 3 + hlsl/hlslParseHelper.cpp | 53 ++++- hlsl/hlslParseHelper.h | 11 + 10 files changed, 446 insertions(+), 11 deletions(-) create mode 100644 Test/baseResults/hlsl.mip.negative.frag.out create mode 100644 Test/baseResults/hlsl.mip.negative2.frag.out create mode 100644 Test/baseResults/hlsl.mip.operator.frag.out create mode 100644 Test/hlsl.mip.negative.frag create mode 100644 Test/hlsl.mip.negative2.frag create mode 100644 Test/hlsl.mip.operator.frag create mode 100644 Test/remap.specconst.comp 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