diff --git a/Test/baseResults/hlsl.rw.swizzle.frag.out b/Test/baseResults/hlsl.rw.swizzle.frag.out new file mode 100644 index 00000000..807fa681 --- /dev/null +++ b/Test/baseResults/hlsl.rw.swizzle.frag.out @@ -0,0 +1,286 @@ +hlsl.rw.swizzle.frag +Shader version: 450 +gl_FragCoord origin is upper left +0:? Sequence +0:4 Function Definition: SomeValue( (temp 3-component vector of float) +0:4 Function Parameters: +0:? Sequence +0:4 Branch: Return with expression +0:? Constant: +0:? 1.000000 +0:? 2.000000 +0:? 3.000000 +0:7 Function Definition: main( (temp 4-component vector of float) +0:7 Function Parameters: +0:? Sequence +0:8 Sequence +0:8 move second child to first child (temp 2-component vector of int) +0:8 'tc2' (temp 2-component vector of int) +0:8 Constant: +0:8 0 (const int) +0:8 0 (const int) +0:9 Sequence +0:9 move second child to first child (temp int) +0:9 'tc' (temp int) +0:9 Constant: +0:9 0 (const int) +0:12 Sequence +0:12 move second child to first child (temp 3-component vector of float) +0:12 vector swizzle (temp 3-component vector of float) +0:12 'storeTemp' (temp 3-component vector of float) +0:12 Sequence +0:12 Constant: +0:12 2 (const int) +0:12 Constant: +0:12 1 (const int) +0:12 Constant: +0:12 0 (const int) +0:? Constant: +0:? 1.000000 +0:? 2.000000 +0:? 3.000000 +0:12 imageStore (temp void) +0:12 'rwtx' (layout(rgba32f ) uniform image2D) +0:12 'tc2' (temp 2-component vector of int) +0:12 'storeTemp' (temp 3-component vector of float) +0:12 'storeTemp' (temp 3-component vector of float) +0:13 Sequence +0:13 move second child to first child (temp 3-component vector of float) +0:13 vector swizzle (temp 3-component vector of float) +0:13 'storeTemp' (temp 3-component vector of float) +0:13 Sequence +0:13 Constant: +0:13 2 (const int) +0:13 Constant: +0:13 1 (const int) +0:13 Constant: +0:13 0 (const int) +0:13 Function Call: SomeValue( (temp 3-component vector of float) +0:13 imageStore (temp void) +0:13 'rwtx' (layout(rgba32f ) uniform image2D) +0:13 'tc2' (temp 2-component vector of int) +0:13 'storeTemp' (temp 3-component vector of float) +0:13 'storeTemp' (temp 3-component vector of float) +0:14 Sequence +0:14 move second child to first child (temp 3-component vector of float) +0:14 vector swizzle (temp 3-component vector of float) +0:14 'storeTemp' (temp 3-component vector of float) +0:14 Sequence +0:14 Constant: +0:14 2 (const int) +0:14 Constant: +0:14 1 (const int) +0:14 Constant: +0:14 0 (const int) +0:14 Constant: +0:14 2.000000 +0:14 2.000000 +0:14 2.000000 +0:14 imageStore (temp void) +0:14 'rwtx' (layout(rgba32f ) uniform image2D) +0:14 'tc2' (temp 2-component vector of int) +0:14 'storeTemp' (temp 3-component vector of float) +0:14 'storeTemp' (temp 3-component vector of float) +0:27 Sequence +0:27 move second child to first child (temp 4-component vector of float) +0:? '@entryPointOutput' (layout(location=0 ) out 4-component vector of float) +0:27 Constant: +0:27 0.000000 +0:27 0.000000 +0:27 0.000000 +0:27 0.000000 +0:27 Branch: Return +0:? Linker Objects +0:? '@entryPointOutput' (layout(location=0 ) out 4-component vector of float) +0:? 'rwtx' (layout(rgba32f ) uniform image2D) +0:? 'buf' (layout(rgba32f ) uniform imageBuffer) + + +Linked fragment stage: + + +Shader version: 450 +gl_FragCoord origin is upper left +0:? Sequence +0:4 Function Definition: SomeValue( (temp 3-component vector of float) +0:4 Function Parameters: +0:? Sequence +0:4 Branch: Return with expression +0:? Constant: +0:? 1.000000 +0:? 2.000000 +0:? 3.000000 +0:7 Function Definition: main( (temp 4-component vector of float) +0:7 Function Parameters: +0:? Sequence +0:8 Sequence +0:8 move second child to first child (temp 2-component vector of int) +0:8 'tc2' (temp 2-component vector of int) +0:8 Constant: +0:8 0 (const int) +0:8 0 (const int) +0:9 Sequence +0:9 move second child to first child (temp int) +0:9 'tc' (temp int) +0:9 Constant: +0:9 0 (const int) +0:12 Sequence +0:12 move second child to first child (temp 3-component vector of float) +0:12 vector swizzle (temp 3-component vector of float) +0:12 'storeTemp' (temp 3-component vector of float) +0:12 Sequence +0:12 Constant: +0:12 2 (const int) +0:12 Constant: +0:12 1 (const int) +0:12 Constant: +0:12 0 (const int) +0:? Constant: +0:? 1.000000 +0:? 2.000000 +0:? 3.000000 +0:12 imageStore (temp void) +0:12 'rwtx' (layout(rgba32f ) uniform image2D) +0:12 'tc2' (temp 2-component vector of int) +0:12 'storeTemp' (temp 3-component vector of float) +0:12 'storeTemp' (temp 3-component vector of float) +0:13 Sequence +0:13 move second child to first child (temp 3-component vector of float) +0:13 vector swizzle (temp 3-component vector of float) +0:13 'storeTemp' (temp 3-component vector of float) +0:13 Sequence +0:13 Constant: +0:13 2 (const int) +0:13 Constant: +0:13 1 (const int) +0:13 Constant: +0:13 0 (const int) +0:13 Function Call: SomeValue( (temp 3-component vector of float) +0:13 imageStore (temp void) +0:13 'rwtx' (layout(rgba32f ) uniform image2D) +0:13 'tc2' (temp 2-component vector of int) +0:13 'storeTemp' (temp 3-component vector of float) +0:13 'storeTemp' (temp 3-component vector of float) +0:14 Sequence +0:14 move second child to first child (temp 3-component vector of float) +0:14 vector swizzle (temp 3-component vector of float) +0:14 'storeTemp' (temp 3-component vector of float) +0:14 Sequence +0:14 Constant: +0:14 2 (const int) +0:14 Constant: +0:14 1 (const int) +0:14 Constant: +0:14 0 (const int) +0:14 Constant: +0:14 2.000000 +0:14 2.000000 +0:14 2.000000 +0:14 imageStore (temp void) +0:14 'rwtx' (layout(rgba32f ) uniform image2D) +0:14 'tc2' (temp 2-component vector of int) +0:14 'storeTemp' (temp 3-component vector of float) +0:14 'storeTemp' (temp 3-component vector of float) +0:27 Sequence +0:27 move second child to first child (temp 4-component vector of float) +0:? '@entryPointOutput' (layout(location=0 ) out 4-component vector of float) +0:27 Constant: +0:27 0.000000 +0:27 0.000000 +0:27 0.000000 +0:27 0.000000 +0:27 Branch: Return +0:? Linker Objects +0:? '@entryPointOutput' (layout(location=0 ) out 4-component vector of float) +0:? 'rwtx' (layout(rgba32f ) uniform image2D) +0:? 'buf' (layout(rgba32f ) uniform imageBuffer) + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 58 + + Capability Shader + Capability SampledBuffer + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "main" 51 + ExecutionMode 4 OriginUpperLeft + Name 4 "main" + Name 9 "SomeValue(" + Name 20 "tc2" + Name 24 "tc" + Name 26 "storeTemp" + Name 31 "rwtx" + Name 35 "storeTemp" + Name 42 "storeTemp" + Name 51 "@entryPointOutput" + Name 57 "buf" + Decorate 31(rwtx) DescriptorSet 0 + Decorate 51(@entryPointOutput) Location 0 + Decorate 57(buf) DescriptorSet 0 + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeFloat 32 + 7: TypeVector 6(float) 3 + 8: TypeFunction 7(fvec3) + 11: 6(float) Constant 1065353216 + 12: 6(float) Constant 1073741824 + 13: 6(float) Constant 1077936128 + 14: 7(fvec3) ConstantComposite 11 12 13 + 17: TypeInt 32 1 + 18: TypeVector 17(int) 2 + 19: TypePointer Function 18(ivec2) + 21: 17(int) Constant 0 + 22: 18(ivec2) ConstantComposite 21 21 + 23: TypePointer Function 17(int) + 25: TypePointer Function 7(fvec3) + 29: TypeImage 6(float) 2D nonsampled format:Rgba32f + 30: TypePointer UniformConstant 29 + 31(rwtx): 30(ptr) Variable UniformConstant + 43: 7(fvec3) ConstantComposite 12 12 12 + 49: TypeVector 6(float) 4 + 50: TypePointer Output 49(fvec4) +51(@entryPointOutput): 50(ptr) Variable Output + 52: 6(float) Constant 0 + 53: 49(fvec4) ConstantComposite 52 52 52 52 + 55: TypeImage 6(float) Buffer nonsampled format:Rgba32f + 56: TypePointer UniformConstant 55 + 57(buf): 56(ptr) Variable UniformConstant + 4(main): 2 Function None 3 + 5: Label + 20(tc2): 19(ptr) Variable Function + 24(tc): 23(ptr) Variable Function + 26(storeTemp): 25(ptr) Variable Function + 35(storeTemp): 25(ptr) Variable Function + 42(storeTemp): 25(ptr) Variable Function + Store 20(tc2) 22 + Store 24(tc) 21 + 27: 7(fvec3) Load 26(storeTemp) + 28: 7(fvec3) VectorShuffle 27 14 5 4 3 + Store 26(storeTemp) 28 + 32: 29 Load 31(rwtx) + 33: 18(ivec2) Load 20(tc2) + 34: 7(fvec3) Load 26(storeTemp) + ImageWrite 32 33 34 + 36: 7(fvec3) FunctionCall 9(SomeValue() + 37: 7(fvec3) Load 35(storeTemp) + 38: 7(fvec3) VectorShuffle 37 36 5 4 3 + Store 35(storeTemp) 38 + 39: 29 Load 31(rwtx) + 40: 18(ivec2) Load 20(tc2) + 41: 7(fvec3) Load 35(storeTemp) + ImageWrite 39 40 41 + 44: 7(fvec3) Load 42(storeTemp) + 45: 7(fvec3) VectorShuffle 44 43 5 4 3 + Store 42(storeTemp) 45 + 46: 29 Load 31(rwtx) + 47: 18(ivec2) Load 20(tc2) + 48: 7(fvec3) Load 42(storeTemp) + ImageWrite 46 47 48 + Store 51(@entryPointOutput) 53 + Return + FunctionEnd + 9(SomeValue(): 7(fvec3) Function None 8 + 10: Label + ReturnValue 14 + FunctionEnd diff --git a/Test/hlsl.rw.swizzle.frag b/Test/hlsl.rw.swizzle.frag new file mode 100644 index 00000000..356ed73d --- /dev/null +++ b/Test/hlsl.rw.swizzle.frag @@ -0,0 +1,28 @@ +RWTexture2D rwtx; +RWBuffer buf; + +float3 SomeValue() { return float3(1,2,3); } + +float4 main() : SV_Target0 +{ + int2 tc2 = { 0, 0 }; + int tc = 0; + + // Test swizzles and partial updates of L-values when writing to buffers and writable textures. + rwtx[tc2].zyx = float3(1,2,3); // full swizzle, simple RHS + rwtx[tc2].zyx = SomeValue(); // full swizzle, complex RHS + rwtx[tc2].zyx = 2; // full swizzle, modify op + + // Partial updates not yet supported. + // Partial values, which will use swizzles. + // buf[tc].yz = 42; // partial swizzle, simple RHS + // buf[tc].yz = SomeValue().x; // partial swizzle, complex RHS + // buf[tc].yz += 43; // partial swizzle, modify op + + // // Partial values, which will use index. + // buf[tc].y = 44; // single index, simple RHS + // buf[tc].y = SomeValue().x; // single index, complex RHS + // buf[tc].y += 45; // single index, modify op + + return 0.0; +} diff --git a/gtests/Hlsl.FromFile.cpp b/gtests/Hlsl.FromFile.cpp index f0332aac..8ec6f5e5 100644 --- a/gtests/Hlsl.FromFile.cpp +++ b/gtests/Hlsl.FromFile.cpp @@ -171,6 +171,7 @@ INSTANTIATE_TEST_CASE_P( {"hlsl.rw.bracket.frag", "main"}, {"hlsl.rw.register.frag", "main"}, {"hlsl.rw.scalar.bracket.frag", "main"}, + {"hlsl.rw.swizzle.frag", "main"}, {"hlsl.rw.vec2.bracket.frag", "main"}, {"hlsl.sample.array.dx10.frag", "main"}, {"hlsl.sample.basic.dx10.frag", "main"}, diff --git a/hlsl/hlslParseHelper.cpp b/hlsl/hlslParseHelper.cpp index 62dac4bf..c7d38c6d 100755 --- a/hlsl/hlslParseHelper.cpp +++ b/hlsl/hlslParseHelper.cpp @@ -47,6 +47,7 @@ #include #include #include +#include namespace glslang { @@ -144,6 +145,12 @@ bool HlslParseContext::shouldConvertLValue(const TIntermNode* node) const return false; const TIntermAggregate* lhsAsAggregate = node->getAsAggregate(); + const TIntermBinary* lhsAsBinary = node->getAsBinaryNode(); + + // If it's a swizzled/indexed aggregate, look at the left node instead. + if (lhsAsBinary != nullptr && + (lhsAsBinary->getOp() == EOpVectorSwizzle || lhsAsBinary->getOp() == EOpIndexDirect)) + lhsAsAggregate = lhsAsBinary->getLeft()->getAsAggregate(); if (lhsAsAggregate != nullptr && lhsAsAggregate->getOp() == EOpImageLoad) return true; @@ -282,14 +289,59 @@ TIntermTyped* HlslParseContext::handleLvalue(const TSourceLoc& loc, const char* loc); }; + // Return true if swizzle or index writes all components of the given variable. + const auto writesAllComponents = [&](TIntermSymbol* var, TIntermBinary* swizzle) -> bool { + if (swizzle == nullptr) // not a swizzle or index + return true; + + // Track which components are being set. + std::array compIsSet; + compIsSet.fill(false); + + const TIntermConstantUnion* asConst = swizzle->getRight()->getAsConstantUnion(); + const TIntermAggregate* asAggregate = swizzle->getRight()->getAsAggregate(); + + // This could be either a direct index, or a swizzle. + if (asConst) { + compIsSet[asConst->getConstArray()[0].getIConst()] = true; + } else if (asAggregate) { + const TIntermSequence& seq = asAggregate->getSequence(); + for (int comp=0; compgetAsConstantUnion()->getConstArray()[0].getIConst()] = true; + } else { + assert(0); + } + + // Return true if all components are being set by the index or swizzle + return std::all_of(compIsSet.begin(), compIsSet.begin() + var->getType().getVectorSize(), + [](bool isSet) { return isSet; } ); + }; + // helper to create a temporary variable const auto addTmpVar = [&](const char* name, const TType& derefType) -> TIntermSymbol* { TVariable* tmpVar = makeInternalVariable(name, derefType); tmpVar->getWritableType().getQualifier().makeTemporary(); return intermediate.addSymbol(*tmpVar, loc); }; - + + // Create swizzle matching input swizzle + const auto addSwizzle = [&](TIntermSymbol* var, TIntermBinary* swizzle) -> TIntermTyped* { + if (swizzle) + return intermediate.addBinaryNode(swizzle->getOp(), var, swizzle->getRight(), loc, swizzle->getType()); + else + return var; + }; + + TIntermBinary* lhsAsBinary = lhs->getAsBinaryNode(); TIntermAggregate* lhsAsAggregate = lhs->getAsAggregate(); + bool lhsIsSwizzle = false; + + // If it's a swizzled L-value, remember the swizzle, and use the LHS. + if (lhsAsBinary != nullptr && (lhsAsBinary->getOp() == EOpVectorSwizzle || lhsAsBinary->getOp() == EOpIndexDirect)) { + lhsAsAggregate = lhsAsBinary->getLeft()->getAsAggregate(); + lhsIsSwizzle = true; + } + TIntermTyped* object = lhsAsAggregate->getSequence()[0]->getAsTyped(); TIntermTyped* coord = lhsAsAggregate->getSequence()[1]->getAsTyped(); @@ -336,16 +388,26 @@ TIntermTyped* HlslParseContext::handleLvalue(const TSourceLoc& loc, const char* // OpSequence // coordtmp = load's param1 // rhsTmp = OpImageLoad(object, coordTmp) - // rhsTmp op= rhs + // rhsTmp op = rhs // OpImageStore(object, coordTmp, rhsTmp) // rhsTmp + // + // If the lvalue is swizzled, we apply that when writing the temp variable, like so: + // ... + // rhsTmp.some_swizzle = ... + // For partial writes, an error is generated. TIntermSymbol* rhsTmp = rhs->getAsSymbolNode(); TIntermTyped* coordTmp = coord; - if (rhsTmp == nullptr || isModifyOp) { + if (rhsTmp == nullptr || isModifyOp || lhsIsSwizzle) { rhsTmp = addTmpVar("storeTemp", objDerefType); + // Partial updates not yet supported + if (!writesAllComponents(rhsTmp, lhsAsBinary)) { + error(loc, "unimplemented: partial image updates", "", ""); + } + // Assign storeTemp = rhs if (isModifyOp) { // We have to make a temp var for the coordinate, to avoid evaluating it twice. @@ -355,7 +417,7 @@ TIntermTyped* HlslParseContext::handleLvalue(const TSourceLoc& loc, const char* } // rhsTmp op= rhs. - makeBinary(assignOp, intermediate.addSymbol(*rhsTmp), rhs); + makeBinary(assignOp, addSwizzle(intermediate.addSymbol(*rhsTmp), lhsAsBinary), rhs); } makeStore(object, coordTmp, rhsTmp); // add a store