ソースを参照

(PIX) Reduce msaa to single-sample (#427)

This pass will be used in PIX for "Dr. PIX experiments", wherein a workload is re-rendered with MSAA turned off in order to get an approximate understanding of the performance impact of MSAA.
Jeff Noyle 8 年 前
コミット
82fcc7ca0f

+ 2 - 0
include/dxc/HLSL/DxilGenerationPass.h

@@ -54,6 +54,7 @@ FunctionPass *createDxilLegalizeSampleOffsetPass();
 FunctionPass *createSimplifyInstPass();
 ModulePass *createDxilOutputColorBecomesConstantPass();
 ModulePass *createDxilRemoveDiscardsPass();
+ModulePass *createDxilReduceMSAAToSingleSamplePass();
 
 void initializeDxilCondenseResourcesPass(llvm::PassRegistry&);
 void initializeDxilEliminateOutputDynamicIndexingPass(llvm::PassRegistry&);
@@ -72,6 +73,7 @@ void initializeDxilLegalizeSampleOffsetPassPass(llvm::PassRegistry&);
 void initializeSimplifyInstPass(llvm::PassRegistry&);
 void initializeDxilOutputColorBecomesConstantPass(llvm::PassRegistry&);
 void initializeDxilRemoveDiscardsPass(llvm::PassRegistry&);
+void initializeDxilReduceMSAAToSingleSamplePass(llvm::PassRegistry&);
 
 bool AreDxilResourcesDense(llvm::Module *M, hlsl::DxilResourceBase **ppNonDense);
 

+ 1 - 0
lib/HLSL/CMakeLists.txt

@@ -20,6 +20,7 @@ add_llvm_library(LLVMHLSL
   DxilOperations.cpp
   DxilOutputColorBecomesConstant.cpp
   DxilRemoveDiscards.cpp
+  DxilReduceMSAAToSingleSample.cpp
   DxilPreserveAllOutputs.cpp
   DxilResource.cpp
   DxilResourceBase.cpp

+ 1 - 0
lib/HLSL/DxcOptimizer.cpp

@@ -95,6 +95,7 @@ HRESULT SetupRegistryPassForHLSL() {
     initializeDxilOutputColorBecomesConstantPass(Registry);
     initializeDxilPrecisePropagatePassPass(Registry);
     initializeDxilPreserveAllOutputsPass(Registry);
+    initializeDxilReduceMSAAToSingleSamplePass(Registry);
     initializeDxilRemoveDiscardsPass(Registry);
     initializeDynamicIndexingVectorToArrayPass(Registry);
     initializeEarlyCSELegacyPassPass(Registry);

+ 83 - 0
lib/HLSL/DxilReduceMSAAToSingleSample.cpp

@@ -0,0 +1,83 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// DxilReduceMSAAToSingleSample.cpp                                          //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Provides a pass to reduce all MSAA writes to single-sample writes         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "dxc/HLSL/DxilGenerationPass.h"
+#include "dxc/HLSL/DxilOperations.h"
+#include "dxc/HLSL/DxilModule.h"
+#include "dxc/HLSL/DxilInstructions.h"
+
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/PassManager.h"
+#include "llvm/IR/Constants.h"
+
+using namespace llvm;
+using namespace hlsl;
+
+class DxilReduceMSAAToSingleSample : public ModulePass {
+
+public:
+  static char ID; // Pass identification, replacement for typeid
+  explicit DxilReduceMSAAToSingleSample() : ModulePass(ID) {}
+  const char *getPassName() const override { return "HLSL DXIL Reduce all MSAA reads to single-sample reads"; }
+  bool runOnModule(Module &M) override;
+};
+
+bool DxilReduceMSAAToSingleSample::runOnModule(Module &M)
+{
+  DxilModule &DM = M.GetOrCreateDxilModule();
+
+  LLVMContext & Ctx = M.getContext();
+  OP *HlslOP = DM.GetOP();
+
+  // FP16 type doesn't have its own identity, and is covered by float type... 
+  auto TextureLoadOverloads = std::vector<Type*>{ Type::getFloatTy(Ctx), Type::getInt16Ty(Ctx), Type::getInt32Ty(Ctx) };
+
+  bool Modified = false;
+
+  for (const auto & Overload : TextureLoadOverloads) {
+
+    Function * TexLoadFunction = HlslOP->GetOpFunc(DXIL::OpCode::TextureLoad, Overload);
+    auto TexLoadFunctionUses = TexLoadFunction->uses();
+
+    for (auto FI = TexLoadFunctionUses.begin(); FI != TexLoadFunctionUses.end(); ) {
+      auto & FunctionUse = *FI++;
+      auto FunctionUser = FunctionUse.getUser();
+      auto instruction = cast<Instruction>(FunctionUser);
+      DxilInst_TextureLoad LoadInstruction(instruction);
+      auto TextureHandle = LoadInstruction.get_srv();
+      auto TextureHandleInst = cast<CallInst>(TextureHandle);
+      DxilInst_CreateHandle createHandle(TextureHandleInst);
+      // Dynamic rangeId is not supported 
+      if (isa<ConstantInt>(createHandle.get_rangeId())){
+        unsigned rangeId = cast<ConstantInt>(createHandle.get_rangeId())->getLimitedValue();
+        if (static_cast<DXIL::ResourceClass>(createHandle.get_resourceClass_val()) == DXIL::ResourceClass::SRV) {
+          auto Resource = DM.GetSRV(rangeId);
+          if (Resource.GetKind() == DXIL::ResourceKind::Texture2DMS || Resource.GetKind() == DXIL::ResourceKind::Texture2DMSArray) {
+            // "2" is the mip-level/sample-index operand index:
+            // https://github.com/Microsoft/DirectXShaderCompiler/blob/master/docs/DXIL.rst#textureload
+            instruction->setOperand(2, HlslOP->GetI32Const(0));
+            Modified = true;
+          }
+        }
+      }
+    }
+  }
+
+  return Modified;
+}
+
+char DxilReduceMSAAToSingleSample::ID = 0;
+
+ModulePass *llvm::createDxilReduceMSAAToSingleSamplePass() {
+  return new DxilReduceMSAAToSingleSample();
+}
+
+INITIALIZE_PASS(DxilReduceMSAAToSingleSample, "hlsl-dxil-reduce-msaa-to-single", "HLSL DXIL Reduce all MSAA writes to single-sample writes", false, false)

+ 46 - 0
tools/clang/test/HLSL/pix/msaaLoad.hlsl

@@ -0,0 +1,46 @@
+// RUN: %dxc -Emain -Tps_6_0 %s | %opt -S -hlsl-dxil-reduce-msaa-to-single | %FileCheck %s
+
+// Check that we overrode the sample index with 0 Here: -------------------------------------------------------------------V
+// CHECK: %TextureLoad = call %dx.types.ResRet.i32 @dx.op.textureLoad.i32(i32 66, %dx.types.Handle %texi_texture_2dMS, i32 0, i32 %4, i32 %5, i32 undef, i32 undef, i32 undef, i32 undef)
+
+// Check for integer and half-float loads:
+// CHECK: %TextureLoad1 = call %dx.types.ResRet.f32 @dx.op.textureLoad.f32(i32 66, %dx.types.Handle %texh_texture_2dMS, i32 0, i32 %add.i0, i32 %add.i1, i32 undef, i32 undef, i32 undef, i32 undef)
+// CHECK: %TextureLoad2 = call %dx.types.ResRet.f32 @dx.op.textureLoad.f32(i32 66, %dx.types.Handle %tex_texture_2dMS, i32 0, i32 %add.i0, i32 %add.i1, i32 undef, i32 undef, i32 undef, i32 undef)
+
+// Check texture load from single-sampled wasn't altered: (This should be 1) ---------------------------------------------------------V
+// CHECK: %TextureLoad3 = call %dx.types.ResRet.f32 @dx.op.textureLoad.f32(i32 66, %dx.types.Handle %singleSampledTex_texture_2d, i32 1, i32 1, i32 1, i32 undef, i32 undef, i32 undef, i32 undef)
+
+// Check texture load from UAV wasn't altered: (This should be 1) ---------------------------------------------------------------------V
+// CHECK: %TextureLoad4 = call %dx.types.ResRet.f32 @dx.op.textureLoad.f32(i32 66, %dx.types.Handle %floatRWUAV_UAV_2d, i32 undef, i32 1, i32 1, i32 undef, i32 undef, i32 undef, i32 undef)
+
+Texture2DMS<float4> tex : register(t2);
+Texture2DMS<half4> texh : register(t3);
+Texture2DMS<int4> texi : register(t4);
+Texture2D<float4> singleSampledTex: register(t5);
+RWTexture2D<float4> floatRWUAV: register(u0);
+
+struct PSInput
+{
+  float4 position : SV_POSITION;
+  float4 color : COLOR;
+};
+
+float4 main(PSInput input) : SV_TARGET
+{
+  uint width, height, samples;
+  tex.GetDimensions(width, height, samples);
+
+  float4 resolved = float4(0, 0, 0, 0);
+  for (uint i = 0; i < samples; ++i)
+  {
+    int2 iPos = int2(input.position.xy);
+
+    //nonsensical loads from half and integer, just for test:
+    iPos += texi.Load(iPos, i).x;
+    resolved.g += texh.Load(iPos, i).g;
+
+    resolved += tex.Load(iPos, i);
+  }
+  // Add a load from a single-sampled resource to check we didn't override that one's mip-level too:
+  return resolved / samples + singleSampledTex.Load(int3(1, 1, 1)) + floatRWUAV.Load(int3(1,1,1));
+}

+ 5 - 0
tools/clang/unittests/HLSL/CompilerTest.cpp

@@ -371,6 +371,7 @@ public:
   TEST_METHOD(CompileHlsl2017ThenOK)
   TEST_METHOD(CompileHlsl2018ThenFail)
 
+  TEST_METHOD(PixMSAAToSample0)
   TEST_METHOD(PixRemoveDiscards)
   TEST_METHOD(PixConstantColor)
   TEST_METHOD(PixConstantColorInt)
@@ -2471,6 +2472,10 @@ TEST_F(CompilerTest, CompileHlsl2018ThenFail) {
   CheckOperationResultMsgs(pResult, &pErrorMsg, 1, false, false);
 }
 
+TEST_F(CompilerTest, PixMSAAToSample0) {
+  CodeGenTestCheck(L"pix\\msaaLoad.hlsl");
+}
+
 TEST_F(CompilerTest, PixRemoveDiscards) {
   CodeGenTestCheck(L"pix\\removeDiscards.hlsl");
 }

+ 1 - 0
utils/hct/hctdb.py

@@ -1275,6 +1275,7 @@ class db_dxil(object):
             {'n':'constant-blue','t':'float','c':1},
             {'n':'constant-alpha','t':'float','c':1}])
         add_pass('hlsl-dxil-remove-discards', 'DxilRemoveDiscards', 'HLSL DXIL Remove all discard instructions', [])
+        add_pass('hlsl-dxil-reduce-msaa-to-single', 'DxilReduceMSAAToSingleSample', 'HLSL DXIL Reduce all MSAA reads to single-sample reads', [])
         add_pass('hlsl-dxilemit', 'DxilEmitMetadata', 'HLSL DXIL Metadata Emit', [])
         add_pass('hlsl-dxilload', 'DxilLoadMetadata', 'HLSL DXIL Metadata Load', [])
         add_pass('hlsl-dxil-expand-trig', 'DxilExpandTrigIntrinsics', 'DXIL expand trig intrinsics', [])