瀏覽代碼

[spirv] Translate intrinsic Lit function. (#744)

Ehsan 8 年之前
父節點
當前提交
c5dc49a7fd

+ 5 - 2
docs/SPIR-V.rst

@@ -1145,11 +1145,14 @@ extended instruction mapping, so they are handled with additional steps:
   Uses conditional control flow as well as SPIR-V ``OpKill``.
 - ``rcp``: Calculates a fast, approximate, per-component reciprocal.
   Uses SIR-V ``OpFDiv``.
+- ``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>`_.
 
 Using SPIR-V opcode
 ~~~~~~~~~~~~~~~~~~~
 
-the following intrinsic HLSL functions have direct SPIR-V opcodes for them:
+The following intrinsic HLSL functions have direct SPIR-V opcodes for them:
 
 ============================== =================================
    HLSL Intrinsic Function              SPIR-V Opcode
@@ -1181,7 +1184,7 @@ the following intrinsic HLSL functions have direct SPIR-V opcodes for them:
 Using GLSL extended instructions
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-the following intrinsic HLSL functions are translated using their equivalent
+The following intrinsic HLSL functions are translated using their equivalent
 instruction in the `GLSL extended instruction set <https://www.khronos.org/registry/spir-v/specs/1.0/GLSL.std.450.html>`_.
 
 ======================= ===================================

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

@@ -3813,6 +3813,8 @@ uint32_t SPIRVEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
     return processIntrinsicClamp(callExpr);
   case hlsl::IntrinsicOp::IOP_frexp:
     return processIntrinsicFrexp(callExpr);
+  case hlsl::IntrinsicOp::IOP_lit:
+    return processIntrinsicLit(callExpr);
   case hlsl::IntrinsicOp::IOP_modf:
     return processIntrinsicModf(callExpr);
   case hlsl::IntrinsicOp::IOP_sign: {
@@ -4116,6 +4118,37 @@ uint32_t SPIRVEmitter::processIntrinsicModf(const CallExpr *callExpr) {
   return 0;
 }
 
+uint32_t SPIRVEmitter::processIntrinsicLit(const CallExpr *callExpr) {
+  // Signature is: float4 lit(float n_dot_l, float n_dot_h, float m)
+  //
+  // This function returns a lighting coefficient vector
+  // (ambient, diffuse, specular, 1) where:
+  // ambient  = 1.
+  // diffuse  = (n_dot_l < 0) ? 0 : n_dot_l
+  // specular = (n_dot_l < 0 || n_dot_h < 0) ? 0 : ((n_dot_h) * m)
+  const uint32_t glslInstSetId = theBuilder.getGLSLExtInstSet();
+  const uint32_t nDotL = doExpr(callExpr->getArg(0));
+  const uint32_t nDotH = doExpr(callExpr->getArg(1));
+  const uint32_t m = doExpr(callExpr->getArg(2));
+  const uint32_t floatType = theBuilder.getFloat32Type();
+  const uint32_t boolType = theBuilder.getBoolType();
+  const uint32_t floatZero = theBuilder.getConstantFloat32(0);
+  const uint32_t floatOne = theBuilder.getConstantFloat32(1);
+  const uint32_t retType = typeTranslator.translateType(callExpr->getType());
+  const uint32_t diffuse = theBuilder.createExtInst(
+      floatType, glslInstSetId, GLSLstd450::GLSLstd450FMax, {floatZero, nDotL});
+  const uint32_t min = theBuilder.createExtInst(
+      floatType, glslInstSetId, GLSLstd450::GLSLstd450FMin, {nDotL, nDotH});
+  const uint32_t isNeg = theBuilder.createBinaryOp(spv::Op::OpFOrdLessThan,
+                                                   boolType, min, floatZero);
+  const uint32_t mul =
+      theBuilder.createBinaryOp(spv::Op::OpFMul, floatType, nDotH, m);
+  const uint32_t specular =
+      theBuilder.createSelect(floatType, isNeg, floatZero, mul);
+  return theBuilder.createCompositeConstruct(
+      retType, {floatOne, diffuse, specular, floatOne});
+}
+
 uint32_t SPIRVEmitter::processIntrinsicFrexp(const CallExpr *callExpr) {
   // Signature is: ret frexp(x, exp)
   // [in]   x: the input floating-point value.

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

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

+ 21 - 0
tools/clang/test/CodeGenSPIRV/intrinsics.lit.hlsl

@@ -0,0 +1,21 @@
+// Run: %dxc -T vs_6_0 -E main
+
+// The signature for 'lit' intrinsic function is as follows:
+// float4 lit(float n_dot_l, float n_dot_h, float m)
+
+// CHECK: [[glsl:%\d+]] = OpExtInstImport "GLSL.std.450"
+
+void main() {
+  float n_dot_l, n_dot_h, m;
+  
+// CHECK:      [[n_dot_l:%\d+]] = OpLoad %float %n_dot_l
+// CHECK-NEXT: [[n_dot_h:%\d+]] = OpLoad %float %n_dot_h
+// CHECK-NEXT:       [[m:%\d+]] = OpLoad %float %m
+// CHECK-NEXT: [[diffuse:%\d+]] = OpExtInst %float [[glsl]] FMax %float_0 [[n_dot_l]]
+// CHECK-NEXT:     [[min:%\d+]] = OpExtInst %float [[glsl]] FMin [[n_dot_l]] [[n_dot_h]]
+// CHECK-NEXT:  [[is_neg:%\d+]] = OpFOrdLessThan %bool [[min]] %float_0
+// CHECK-NEXT:     [[mul:%\d+]] = OpFMul %float [[n_dot_h]] [[m]]
+// CHECK-NEXT:[[specular:%\d+]] = OpSelect %float [[is_neg]] %float_0 [[mul]]
+// CHECK-NEXT:         {{%\d+}} = OpCompositeConstruct %v4float %float_1 [[diffuse]] [[specular]] %float_1
+  float4 result = lit(n_dot_l, n_dot_h, m);
+}

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

@@ -611,6 +611,7 @@ TEST_F(FileTest, IntrinsicsLog) { runFileTest("intrinsics.log.hlsl"); }
 TEST_F(FileTest, IntrinsicsLog10) { runFileTest("intrinsics.log10.hlsl"); }
 TEST_F(FileTest, IntrinsicsLog2) { runFileTest("intrinsics.log2.hlsl"); }
 TEST_F(FileTest, IntrinsicsMin) { runFileTest("intrinsics.min.hlsl"); }
+TEST_F(FileTest, IntrinsicsLit) { runFileTest("intrinsics.lit.hlsl"); }
 TEST_F(FileTest, IntrinsicsModf) { runFileTest("intrinsics.modf.hlsl"); }
 TEST_F(FileTest, IntrinsicsMad) { runFileTest("intrinsics.mad.hlsl"); }
 TEST_F(FileTest, IntrinsicsMax) { runFileTest("intrinsics.max.hlsl"); }