Browse Source

[spirv] Add -fvk-invert-w (#1429)

This option reciprocates (multiplicatively inverts) SV_Position.w
after reading it from stage input in PS. This is used to accommodate
the difference between Vulkan and DirectX.
Lei Zhang 7 years ago
parent
commit
ef6c9eff15

+ 7 - 3
docs/SPIR-V.rst

@@ -2716,9 +2716,13 @@ codegen for Vulkan:
 - ``-fvk-use-gl-layout``: Uses strict OpenGL ``std140``/``std430``
   layout rules for resources.
 - ``-fvk-use-dx-layout``: Uses DirectX layout rules for resources.
-- ``-fvk-invert-y``: Inverts SV_Position.y before writing to stage output.
-  Used to accommodate the difference between Vulkan's coordinate system and
-  DirectX's. Only allowed in VS/DS/GS.
+- ``-fvk-invert-y``: Negates (additively inverts) SV_Position.y before writing
+  to stage output. Used to accommodate the difference between Vulkan's
+  coordinate system and DirectX's. Only allowed in VS/DS/GS.
+- ``-fvk-invert-w``: Reciprocates (multiplicatively inverts) SV_Position.w after
+  reading from stage input. Used to accommodate the difference between Vulkan
+  DirectX: the w component of SV_Position in PS is stored as 1/w in Vulkan.
+  Only allowed in PS.
 - ``-fvk-stage-io-order={alpha|decl}``: Assigns the stage input/output variable
   location number according to alphabetical order or declaration order. See
   `HLSL semantic and Vulkan Location`_ for more details.

+ 1 - 0
include/dxc/Support/HLSLOptions.h

@@ -162,6 +162,7 @@ public:
 #ifdef ENABLE_SPIRV_CODEGEN
   bool GenSPIRV;                           // OPT_spirv
   bool VkInvertY;                          // OPT_fvk_invert_y
+  bool VkInvertW;                          // OPT_fvk_invert_w
   bool VkUseGlLayout;                      // OPT_fvk_use_gl_layout
   bool VkUseDxLayout;                      // OPT_fvk_use_dx_layout
   bool SpvEnableReflect;                   // OPT_fspv_reflect

+ 3 - 1
include/dxc/Support/HLSLOptions.td

@@ -247,7 +247,9 @@ def fvk_s_shift : MultiArg<["-"], "fvk-s-shift", 2>, MetaVarName<"<shift> <space
 def fvk_u_shift : MultiArg<["-"], "fvk-u-shift", 2>, MetaVarName<"<shift> <space>">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
   HelpText<"Specify Vulkan binding number shift for u-type register">;
 def fvk_invert_y: Flag<["-"], "fvk-invert-y">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
-  HelpText<"Invert SV_Position.y in VS/DS/GS to accommodate Vulkan's coordinate system">;
+  HelpText<"Negate SV_Position.y before writing to stage output in VS/DS/GS to accommodate Vulkan's coordinate system">;
+def fvk_invert_w: Flag<["-"], "fvk-invert-w">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
+  HelpText<"Reciprocate SV_Position.w after reading from stage input in PS to accommodate the difference between Vulkan and DirectX">;
 def fvk_use_gl_layout: Flag<["-"], "fvk-use-gl-layout">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
   HelpText<"Use strict OpenGL std140/std430 memory layout for Vulkan resources">;
 def fvk_use_dx_layout: Flag<["-"], "fvk-use-dx-layout">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,

+ 2 - 0
lib/DxcSupport/HLSLOptions.cpp

@@ -505,6 +505,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
 #ifdef ENABLE_SPIRV_CODEGEN
   const bool genSpirv = opts.GenSPIRV = Args.hasFlag(OPT_spirv, OPT_INVALID, false);
   opts.VkInvertY = Args.hasFlag(OPT_fvk_invert_y, OPT_INVALID, false);
+  opts.VkInvertW = Args.hasFlag(OPT_fvk_invert_w, OPT_INVALID, false);
   opts.VkUseGlLayout = Args.hasFlag(OPT_fvk_use_gl_layout, OPT_INVALID, false);
   opts.VkUseDxLayout = Args.hasFlag(OPT_fvk_use_dx_layout, OPT_INVALID, false);
   opts.SpvEnableReflect = Args.hasFlag(OPT_fspv_reflect, OPT_INVALID, false);
@@ -570,6 +571,7 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
 #else
   if (Args.hasFlag(OPT_spirv, OPT_INVALID, false) ||
       Args.hasFlag(OPT_fvk_invert_y, OPT_INVALID, false) ||
+      Args.hasFlag(OPT_fvk_invert_w, OPT_INVALID, false) ||
       Args.hasFlag(OPT_fvk_use_gl_layout, OPT_INVALID, false) ||
       Args.hasFlag(OPT_fvk_use_dx_layout, OPT_INVALID, false) ||
       Args.hasFlag(OPT_fspv_reflect, OPT_INVALID, false) ||

+ 2 - 1
tools/clang/include/clang/SPIRV/EmitSPIRVOptions.h

@@ -32,7 +32,8 @@ struct EmitSPIRVOptions {
   bool codeGenHighLevel;
   bool defaultRowMajor;
   bool disableValidation;
-  bool invertY;
+  bool invertY; // Additive inverse
+  bool invertW; // Multiplicative inverse
   bool useGlLayout;
   bool useDxLayout;
   bool enable16BitTypes;

+ 18 - 1
tools/clang/lib/SPIRV/DeclResultIdMapper.cpp

@@ -1498,12 +1498,16 @@ bool DeclResultIdMapper::createStageVars(const hlsl::SigPoint *sigPoint,
               theBuilder.getVecType(srcVecElemTypeId, 2), *value, *value,
               {0, 1});
       }
+
+      // Reciprocate SV_Position.w if requested
+      if (semanticKind == hlsl::Semantic::Kind::Position)
+        *value = invertWIfRequested(*value);
     } else {
       if (noWriteBack)
         return true;
 
       // Negate SV_Position.y if requested
-      if (semanticToUse->semantic->GetKind() == hlsl::Semantic::Kind::Position)
+      if (semanticKind == hlsl::Semantic::Kind::Position)
         *value = invertYIfRequested(*value);
 
       uint32_t ptr = varId;
@@ -1790,6 +1794,19 @@ uint32_t DeclResultIdMapper::invertYIfRequested(uint32_t position) {
   return position;
 }
 
+uint32_t DeclResultIdMapper::invertWIfRequested(uint32_t position) {
+  // Reciprocate SV_Position.w if requested
+  if (spirvOptions.invertW) {
+    const auto f32Type = theBuilder.getFloat32Type();
+    const auto v4f32Type = theBuilder.getVecType(f32Type, 4);
+    const auto oldW = theBuilder.createCompositeExtract(f32Type, position, {3});
+    const auto newW = theBuilder.createBinaryOp(
+        spv::Op::OpFDiv, f32Type, theBuilder.getConstantFloat32(1), oldW);
+    position = theBuilder.createCompositeInsert(v4f32Type, position, {3}, newW);
+  }
+  return position;
+}
+
 void DeclResultIdMapper::decoratePSInterpolationMode(const NamedDecl *decl,
                                                      QualType type,
                                                      uint32_t varId) {

+ 7 - 3
tools/clang/lib/SPIRV/DeclResultIdMapper.h

@@ -433,9 +433,13 @@ public:
   bool writeBackOutputStream(const NamedDecl *decl, QualType type,
                              uint32_t value);
 
-  /// \brief Inverts SV_Position.y is requested.
+  /// \brief Negates to get the additive inverse of SV_Position.y if requested.
   uint32_t invertYIfRequested(uint32_t position);
 
+  /// \brief Reciprocates to get the multiplicative inverse of SV_Position.w
+  /// if requested.
+  uint32_t invertWIfRequested(uint32_t position);
+
   /// \brief Decorates all stage input and output variables with proper
   /// location and returns true on success.
   ///
@@ -744,8 +748,8 @@ DeclResultIdMapper::DeclResultIdMapper(const hlsl::ShaderModel &model,
                                        const EmitSPIRVOptions &options)
     : shaderModel(model), theBuilder(builder), spirvOptions(options),
       astContext(context), diags(context.getDiagnostics()),
-      typeTranslator(translator), entryFunctionId(0),
-      laneCountBuiltinId(0), laneIndexBuiltinId(0), needsLegalization(false),
+      typeTranslator(translator), entryFunctionId(0), laneCountBuiltinId(0),
+      laneIndexBuiltinId(0), needsLegalization(false),
       glPerVertex(model, context, builder, typeTranslator) {}
 
 bool DeclResultIdMapper::decorateStageIOLocations() {

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

@@ -597,6 +597,8 @@ SPIRVEmitter::SPIRVEmitter(CompilerInstance &ci, EmitSPIRVOptions &options)
   if (options.invertY && !shaderModel.IsVS() && !shaderModel.IsDS() &&
       !shaderModel.IsGS())
     emitError("-fvk-invert-y can only be used in VS/DS/GS", {});
+  if (options.invertW && !shaderModel.IsPS())
+    emitError("-fvk-invert-w can only be used in PS", {});
 
   if (options.useGlLayout && options.useDxLayout)
     emitError("cannot specify both -fvk-use-dx-layout and -fvk-use-gl-layout",

+ 12 - 0
tools/clang/test/CodeGenSPIRV/vk.cloption.invert-w.ps.hlsl

@@ -0,0 +1,12 @@
+// Run: %dxc -T ps_6_0 -E main -fvk-invert-w
+
+float4 main(float4 pos: SV_Position) : SV_Target {
+    return pos;
+}
+
+// CHECK:       [[old:%\d+]] = OpLoad %v4float %gl_FragCoord
+// CHECK-NEXT: [[oldW:%\d+]] = OpCompositeExtract %float [[old]] 3
+// CHECK-NEXT: [[newW:%\d+]] = OpFDiv %float %float_1 [[oldW]]
+// CHECK-NEXT:  [[new:%\d+]] = OpCompositeInsert %v4float [[newW]] [[old]] 3
+// CHECK-NEXT:                 OpStore %param_var_pos [[new]]
+// CHECK-NEXT:                 OpFunctionCall %v4float %src_main %param_var_pos

+ 1 - 0
tools/clang/tools/dxcompiler/dxcompilerobj.cpp

@@ -485,6 +485,7 @@ public:
           spirvOpts.codeGenHighLevel = opts.CodeGenHighLevel;
           spirvOpts.disableValidation = opts.DisableValidation;
           spirvOpts.invertY = opts.VkInvertY;
+          spirvOpts.invertW = opts.VkInvertW;
           spirvOpts.useGlLayout = opts.VkUseGlLayout;
           spirvOpts.useDxLayout = opts.VkUseDxLayout;
           spirvOpts.enableReflect = opts.SpvEnableReflect;

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

@@ -1332,6 +1332,10 @@ TEST_F(FileTest, VulkanCLOptionInvertYGS) {
   runFileTest("vk.cloption.invert-y.gs.hlsl");
 }
 
+TEST_F(FileTest, VulkanCLOptionInvertWPS) {
+  runFileTest("vk.cloption.invert-w.ps.hlsl");
+}
+
 // Vulkan specific
 TEST_F(FileTest, VulkanLocation) { runFileTest("vk.location.hlsl"); }
 TEST_F(FileTest, VulkanLocationInputExplicitOutputImplicit) {