Browse Source

[spirv] Translate intrinsic D3DCOLORtoUBYTE4. (#799)

Ehsan 7 years ago
parent
commit
b32bc384a3

+ 3 - 0
docs/SPIR-V.rst

@@ -1418,6 +1418,9 @@ extended instruction mapping, so they are handled with additional steps:
 - ``lit``: Returns a lighting coefficient vector. This vector is a float4 with
   components of (ambient, diffuse, specular, 1). How ``diffuse`` and ``specular``
   are calculated are explained `here <https://msdn.microsoft.com/en-us/library/windows/desktop/bb509619(v=vs.85).aspx>`_.
+- ``D3DCOLORtoUBYTE4``: Converts a floating-point, 4D vector set by a D3DCOLOR to a UBYTE4.
+  This is achieved by performing ``int4(input.zyxw * 255.002)`` using SPIR-V ``OpVectorShuffle``,
+  ``OpVectorTimesScalar``, and ``OpConvertFToS``, respectively.
 
 Using SPIR-V opcode
 ~~~~~~~~~~~~~~~~~~~

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

@@ -4137,6 +4137,8 @@ uint32_t SPIRVEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
                                            GLSLstd450::GLSLstd450SSign,
                                            /*actPerRowForMatrices*/ true);
   }
+  case hlsl::IntrinsicOp::IOP_D3DCOLORtoUBYTE4:
+    return processD3DCOLORtoUBYTE4(callExpr);
   case hlsl::IntrinsicOp::IOP_isfinite: {
     return processIntrinsicIsFinite(callExpr);
   }
@@ -5112,6 +5114,22 @@ uint32_t SPIRVEmitter::processIntrinsicAsType(const CallExpr *callExpr) {
   }
 }
 
+uint32_t SPIRVEmitter::processD3DCOLORtoUBYTE4(const CallExpr *callExpr) {
+  // Should take a float4 and return an int4 by doing:
+  // int4 result = input.zyxw * 255.001953;
+  // Maximum float precision makes the scaling factor 255.002.
+  const auto arg = callExpr->getArg(0);
+  const auto argId = doExpr(arg);
+  const auto argTypeId = typeTranslator.translateType(arg->getType());
+  const auto swizzle =
+      theBuilder.createVectorShuffle(argTypeId, argId, argId, {2, 1, 0, 3});
+  const auto scaled = theBuilder.createBinaryOp(
+      spv::Op::OpVectorTimesScalar, argTypeId, swizzle,
+      theBuilder.getConstantFloat32(255.002f));
+  return castToInt(scaled, arg->getType(), callExpr->getType(),
+                   callExpr->getExprLoc());
+}
+
 uint32_t SPIRVEmitter::processIntrinsicIsFinite(const CallExpr *callExpr) {
   // Since OpIsFinite needs the Kernel capability, translation is instead done
   // using OpIsNan and OpIsInf:

+ 3 - 0
tools/clang/lib/SPIRV/SPIRVEmitter.h

@@ -267,6 +267,9 @@ private:
   /// Processes the 'frexp' intrinsic function.
   uint32_t processIntrinsicFrexp(const CallExpr *);
 
+  /// Processes the 'D3DCOLORtoUBYTE4' intrinsic function.
+  uint32_t processD3DCOLORtoUBYTE4(const CallExpr *);
+
   /// Processes the 'lit' intrinsic function.
   uint32_t processIntrinsicLit(const CallExpr *);
 

+ 13 - 0
tools/clang/test/CodeGenSPIRV/intrinsics.D3DCOLORtoUBYTE4.hlsl

@@ -0,0 +1,13 @@
+// Run: %dxc -T vs_6_0 -E main
+
+// CHECK: %float_255_002 = OpConstant %float 255.002
+
+void main() {
+  float4 input;
+
+// CHECK:         [[input:%\d+]] = OpLoad %v4float %input
+// CHECK-NEXT: [[swizzled:%\d+]] = OpVectorShuffle %v4float [[input]] [[input]] 2 1 0 3
+// CHECK-NEXT:   [[scaled:%\d+]] = OpVectorTimesScalar %v4float [[swizzled]] %float_255_002
+// CHECK-NEXT:          {{%\d+}} = OpConvertFToS %v4int [[scaled]]
+  int4 result = D3DCOLORtoUBYTE4(input);
+}

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

@@ -639,6 +639,9 @@ TEST_F(FileTest, IntrinsicsCross) { runFileTest("intrinsics.cross.hlsl"); }
 TEST_F(FileTest, IntrinsicsCeil) { runFileTest("intrinsics.ceil.hlsl"); }
 TEST_F(FileTest, IntrinsicsClamp) { runFileTest("intrinsics.clamp.hlsl"); }
 TEST_F(FileTest, IntrinsicsClip) { runFileTest("intrinsics.clip.hlsl"); }
+TEST_F(FileTest, IntrinsicsD3DCOLORtoUBYTE4) {
+  runFileTest("intrinsics.D3DCOLORtoUBYTE4.hlsl");
+}
 TEST_F(FileTest, IntrinsicsDegrees) { runFileTest("intrinsics.degrees.hlsl"); }
 TEST_F(FileTest, IntrinsicsDistance) {
   runFileTest("intrinsics.distance.hlsl");