mirror of
https://github.com/KhronosGroup/glslang
synced 2024-11-09 12:00:05 +00:00
HLSL: allow destination swizzles when writing RWTexture/RWBuffer objects.
Reads and write syntax to UAV objects is turned into EOpImageLoad/Store operations. This translation did not support destination swizzles, for example, "mybuffer[tc].zyx = 3;", so such statements would fail to compile. Now they work. Parial updates are explicitly prohibited. New test: hlsl.rw.swizzle.frag
This commit is contained in:
parent
807a0d9e2f
commit
cd6829ba81
286
Test/baseResults/hlsl.rw.swizzle.frag.out
Normal file
286
Test/baseResults/hlsl.rw.swizzle.frag.out
Normal file
@ -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
|
28
Test/hlsl.rw.swizzle.frag
Normal file
28
Test/hlsl.rw.swizzle.frag
Normal file
@ -0,0 +1,28 @@
|
||||
RWTexture2D<float3> rwtx;
|
||||
RWBuffer<float3> 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;
|
||||
}
|
@ -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"},
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <cctype>
|
||||
#include <array>
|
||||
|
||||
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<bool, 4> 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; comp<int(seq.size()); ++comp)
|
||||
compIsSet[seq[comp]->getAsConstantUnion()->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
|
||||
|
Loading…
Reference in New Issue
Block a user