소스 검색

[spirv] Access and assigment for RWTexture types. (#622)

Ehsan 8 년 전
부모
커밋
76a835bbd1

+ 8 - 2
tools/clang/lib/SPIRV/DeclResultIdMapper.h

@@ -175,13 +175,19 @@ public:
 public:
   /// The struct containing SPIR-V information of a AST Decl.
   struct DeclSpirvInfo {
+    DeclSpirvInfo(uint32_t result = 0,
+                  spv::StorageClass sc = spv::StorageClass::Function,
+                  LayoutRule lr = LayoutRule::Void, int indexInCTB = -1)
+        : resultId(result), storageClass(sc), layoutRule(lr),
+          indexInCTBuffer(indexInCTB) {}
+
     uint32_t resultId;
     spv::StorageClass storageClass;
     /// Layout rule for this decl.
-    LayoutRule layoutRule = LayoutRule::Void;
+    LayoutRule layoutRule;
     /// Value >= 0 means that this decl is a VarDecl inside a cbuffer/tbuffer
     /// and this is the index; value < 0 means this is just a standalone decl.
-    int indexInCTBuffer = -1;
+    int indexInCTBuffer;
   };
 
   /// \brief Returns the SPIR-V information for the given decl.

+ 22 - 18
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -1156,15 +1156,16 @@ uint32_t SPIRVEmitter::doCastExpr(const CastExpr *expr) {
   case CastKind::CK_LValueToRValue: {
     const uint32_t fromValue = doExpr(subExpr);
     if (isVectorShuffle(subExpr) || isa<ExtMatrixElementExpr>(subExpr) ||
-        isBufferIndexing(dyn_cast<CXXOperatorCallExpr>(subExpr))) {
-      // By reaching here, it means the vector/matrix/Buffer/RWBuffer element
-      // accessing operation is an lvalue. For vector element accessing, if we
-      // generated a vector shuffle for it and trying to use it as a rvalue, we
-      // cannot do the load here as normal. Need the upper nodes in the AST tree
-      // to handle it properly. For matrix element accessing, load should have
-      // already happened after creating access chain for each element.
-      // For (RW)Buffer element accessing, load should have already happened
-      // using OpImageFetch.
+        isBufferRWBufferRWTextureIndexing(
+            dyn_cast<CXXOperatorCallExpr>(subExpr))) {
+      // By reaching here, it means the vector/matrix/Buffer/RWBuffer/RWTexture
+      // element accessing operation is an lvalue. For vector element accessing,
+      // if we generated a vector shuffle for it and trying to use it as a
+      // rvalue, we cannot do the load here as normal. Need the upper nodes in
+      // the AST tree to handle it properly. For matrix element accessing, load
+      // should have already happened after creating access chain for each
+      // element. For (RW)Buffer/RWTexture element accessing, load should have
+      // already happened using OpImageFetch.
 
       return fromValue;
     }
@@ -1777,11 +1778,11 @@ uint32_t SPIRVEmitter::doCXXMemberCallExpr(const CXXMemberCallExpr *expr) {
 }
 
 uint32_t SPIRVEmitter::doCXXOperatorCallExpr(const CXXOperatorCallExpr *expr) {
-  { // Handle Buffer/RWBuffer indexing
+  { // Handle Buffer/RWBuffer/RWTexture indexing
     const Expr *baseExpr = nullptr;
     const Expr *indexExpr = nullptr;
 
-    if (isBufferIndexing(expr, &baseExpr, &indexExpr)) {
+    if (isBufferRWBufferRWTextureIndexing(expr, &baseExpr, &indexExpr)) {
       return processBufferTextureLoad(baseExpr, indexExpr);
     }
   }
@@ -2173,7 +2174,7 @@ uint32_t SPIRVEmitter::processAssignment(const Expr *lhs, const uint32_t rhs,
     return result;
   }
   // Assigning to a RWBuffer should be handled differently.
-  if (const uint32_t result = tryToAssignToRWBuffer(lhs, rhs)) {
+  if (const uint32_t result = tryToAssignToRWBufferRWTexture(lhs, rhs)) {
     return result;
   }
 
@@ -2390,8 +2391,9 @@ bool SPIRVEmitter::isVectorShuffle(const Expr *expr) {
   return false;
 }
 
-bool SPIRVEmitter::isBufferIndexing(const CXXOperatorCallExpr *indexExpr,
-                                    const Expr **base, const Expr **index) {
+bool SPIRVEmitter::isBufferRWBufferRWTextureIndexing(
+    const CXXOperatorCallExpr *indexExpr, const Expr **base,
+    const Expr **index) {
   if (!indexExpr)
     return false;
 
@@ -2401,7 +2403,8 @@ bool SPIRVEmitter::isBufferIndexing(const CXXOperatorCallExpr *indexExpr,
   const Expr *object = indexExpr->getArg(0);
   const auto objectType = object->getType();
   if (TypeTranslator::isBuffer(objectType) ||
-      TypeTranslator::isRWBuffer(objectType)) {
+      TypeTranslator::isRWBuffer(objectType) ||
+      TypeTranslator::isRWTexture(objectType)) {
     if (base)
       *base = object;
     if (index)
@@ -2683,11 +2686,12 @@ uint32_t SPIRVEmitter::tryToAssignToVectorElements(const Expr *lhs,
   return rhs;
 }
 
-uint32_t SPIRVEmitter::tryToAssignToRWBuffer(const Expr *lhs, uint32_t rhs) {
+uint32_t SPIRVEmitter::tryToAssignToRWBufferRWTexture(const Expr *lhs,
+                                                      uint32_t rhs) {
   const Expr *baseExpr = nullptr;
   const Expr *indexExpr = nullptr;
-  if (isBufferIndexing(dyn_cast<CXXOperatorCallExpr>(lhs), &baseExpr,
-                       &indexExpr)) {
+  const auto lhsExpr = dyn_cast<CXXOperatorCallExpr>(lhs);
+  if (isBufferRWBufferRWTextureIndexing(lhsExpr, &baseExpr, &indexExpr)) {
     const uint32_t locId = doExpr(indexExpr);
     const uint32_t imageId = theBuilder.createLoad(
         typeTranslator.translateType(baseExpr->getType()), doExpr(baseExpr));

+ 7 - 7
tools/clang/lib/SPIRV/SPIRVEmitter.h

@@ -150,12 +150,12 @@ private:
   bool isVectorShuffle(const Expr *expr);
 
   /// \brief Returns true if the given CXXOperatorCallExpr is indexing into a
-  /// Buffer/RWBuffer using operator[].
+  /// Buffer/RWBuffer/RWTexture using operator[].
   /// On success, writes the base buffer into *base if base is not nullptr, and
   /// writes the index into *index if index is not nullptr.
-  bool isBufferIndexing(const CXXOperatorCallExpr *,
-                        const Expr **base = nullptr,
-                        const Expr **index = nullptr);
+  bool isBufferRWBufferRWTextureIndexing(const CXXOperatorCallExpr *,
+                                         const Expr **base = nullptr,
+                                         const Expr **index = nullptr);
 
   /// Condenses a sequence of HLSLVectorElementExpr starting from the given
   /// expr into one. Writes the original base into *basePtr and the condensed
@@ -200,9 +200,9 @@ private:
   /// are generated.
   uint32_t tryToAssignToMatrixElements(const Expr *lhs, uint32_t rhs);
 
-  /// Tries to emit instructions for assigning to the given RWBuffer object.
-  /// Returns 0 if the trial fails and no instructions are generated.
-  uint32_t tryToAssignToRWBuffer(const Expr *lhs, uint32_t rhs);
+  /// Tries to emit instructions for assigning to the given RWBuffer/RWTexture
+  /// object. Returns 0 if the trial fails and no instructions are generated.
+  uint32_t tryToAssignToRWBufferRWTexture(const Expr *lhs, uint32_t rhs);
 
   /// Processes each vector within the given matrix by calling actOnEachVector.
   /// matrixVal should be the loaded value of the matrix. actOnEachVector takes

+ 38 - 0
tools/clang/test/CodeGenSPIRV/op.rwtexture.access.hlsl

@@ -0,0 +1,38 @@
+// Run: %dxc -T ps_6_0 -E main
+
+RWTexture1D      <float>  t1;
+RWTexture2D      <int2>   t2;
+RWTexture3D      <uint3>  t3;
+RWTexture1DArray <float4> t4;
+RWTexture2DArray <int3>   t5;
+
+// CHECK:  [[c01:%\d+]] = OpConstantComposite %v2uint %uint_0 %uint_1
+// CHECK: [[c012:%\d+]] = OpConstantComposite %v3uint %uint_0 %uint_1 %uint_2
+
+void main() {
+
+// CHECK:      [[t1:%\d+]] = OpLoad %type_1d_image %t1
+// CHECK-NEXT: [[img1:%\d+]] = OpImageRead %float [[t1]] %uint_0 None
+// CHECK-NEXT: OpStore %a [[img1]]
+  float  a = t1[0];
+
+// CHECK-NEXT: [[t2:%\d+]] = OpLoad %type_2d_image %t2
+// CHECK-NEXT: [[img2:%\d+]] = OpImageRead %v2int [[t2]] [[c01]] None
+// CHECK-NEXT: OpStore %b [[img2]]
+  int2   b = t2[uint2(0,1)];
+
+// CHECK-NEXT: [[t3:%\d+]] = OpLoad %type_3d_image %t3
+// CHECK-NEXT: [[img3:%\d+]] = OpImageRead %v3uint [[t3]] [[c012]] None
+// CHECK-NEXT: OpStore %c [[img3]]
+  uint3  c = t3[uint3(0,1,2)];
+
+// CHECK-NEXT: [[t4:%\d+]] = OpLoad %type_1d_image_array %t4
+// CHECK-NEXT: [[img4:%\d+]] = OpImageRead %v4float [[t4]] [[c01]] None
+// CHECK-NEXT: OpStore %d [[img4]]
+  float4 d = t4[uint2(0,1)];
+
+// CHECK-NEXT: [[t5:%\d+]] = OpLoad %type_2d_image_array %t5
+// CHECK-NEXT: [[img5:%\d+]] = OpImageRead %v3int [[t5]] [[c012]] None
+// CHECK-NEXT: OpStore %e [[img5]]
+  int3   e = t5[uint3(0,1,2)];
+}

+ 38 - 0
tools/clang/test/CodeGenSPIRV/rwtexture.write.hlsl

@@ -0,0 +1,38 @@
+// Run: %dxc -T ps_6_0 -E main
+
+RWTexture1D        <float>  t1;
+RWTexture2D        <int2>   t2;
+RWTexture3D        <uint3>  t3;
+RWTexture1DArray   <float4> t4;
+RWTexture2DArray   <int3>   t5;
+
+// CHECK:   [[ci12:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
+// CHECK:   [[cu01:%\d+]] = OpConstantComposite %v2uint %uint_0 %uint_1
+// CHECK:  [[cu123:%\d+]] = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
+// CHECK:  [[cu012:%\d+]] = OpConstantComposite %v3uint %uint_0 %uint_1 %uint_2
+// CHECK: [[cf1234:%\d+]] = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4
+// CHECK:  [[ci123:%\d+]] = OpConstantComposite %v3int %int_1 %int_2 %int_3
+
+void main() {
+
+// CHECK:      [[t1:%\d+]] = OpLoad %type_1d_image %t1
+// CHECK-NEXT: OpImageWrite [[t1]] %uint_0 %float_1
+  t1[0] = 1.0;
+
+// CHECK-NEXT: [[t2:%\d+]] = OpLoad %type_2d_image %t2
+// CHECK-NEXT: OpImageWrite [[t2]] [[cu01]] [[ci12]]
+  t2[uint2(0,1)] = int2(1,2);
+
+// CHECK-NEXT: [[t3:%\d+]] = OpLoad %type_3d_image %t3
+// CHECK-NEXT: OpImageWrite [[t3]] [[cu012]] [[cu123]]
+  t3[uint3(0,1,2)] = uint3(1,2,3);
+
+// CHECK-NEXT: [[t4:%\d+]] = OpLoad %type_1d_image_array %t4
+// CHECK-NEXT: OpImageWrite [[t4]] [[cu01]] [[cf1234]]
+  t4[uint2(0,1)] = float4(1,2,3,4);
+
+// CHECK-NEXT: [[t5:%\d+]] = OpLoad %type_2d_image_array %t5
+// CHECK-NEXT: OpImageWrite [[t5]] [[cu012]] [[ci123]]
+  t5[uint3(0,1,2)] = int3(1,2,3);
+
+}

+ 4 - 0
tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp

@@ -225,6 +225,9 @@ TEST_F(FileTest, OpRWStructuredBufferAccess) {
   runFileTest("op.rw-structured-buffer.access.hlsl");
 }
 
+// For RWTexture accessing operator
+TEST_F(FileTest, OpRWTextureAccess) { runFileTest("op.rwtexture.access.hlsl"); }
+
 // For casting
 TEST_F(FileTest, CastNoOp) { runFileTest("cast.no-op.hlsl"); }
 TEST_F(FileTest, CastImplicit2Bool) { runFileTest("cast.2bool.implicit.hlsl"); }
@@ -386,6 +389,7 @@ TEST_F(FileTest, BufferWrite) { runFileTest("buffer.write.hlsl"); }
 
 // For RWTexture methods
 TEST_F(FileTest, RWTextureLoad) { runFileTest("rwtexture.load.hlsl"); }
+TEST_F(FileTest, RWTextureWrite) { runFileTest("rwtexture.write.hlsl"); }
 
 // For intrinsic functions
 TEST_F(FileTest, IntrinsicsDot) { runFileTest("intrinsics.dot.hlsl"); }