DxilOutputColorBecomesConstant.cpp 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // DxilOutputColorBecomesConstant.cpp //
  4. // Copyright (C) Microsoft Corporation. All rights reserved. //
  5. // This file is distributed under the University of Illinois Open Source //
  6. // License. See LICENSE.TXT for details. //
  7. // //
  8. // Provides a pass to stomp a pixel shader's output color to a given //
  9. // constant value //
  10. // //
  11. ///////////////////////////////////////////////////////////////////////////////
  12. #include "dxc/DXIL/DxilModule.h"
  13. #include "dxc/DXIL/DxilOperations.h"
  14. #include "dxc/DxilPIXPasses/DxilPIXPasses.h"
  15. #include "dxc/HLSL/DxilGenerationPass.h"
  16. #include "dxc/HLSL/DxilSpanAllocator.h"
  17. #include "llvm/IR/PassManager.h"
  18. #include "llvm/Transforms/Utils/Local.h"
  19. #include <array>
  20. #include "PixPassHelpers.h"
  21. using namespace llvm;
  22. using namespace hlsl;
  23. class DxilOutputColorBecomesConstant : public ModulePass {
  24. enum VisualizerInstrumentationMode {
  25. FromLiteralConstant,
  26. FromConstantBuffer
  27. };
  28. float Red = 1.f;
  29. float Green = 1.f;
  30. float Blue = 1.f;
  31. float Alpha = 1.f;
  32. VisualizerInstrumentationMode Mode = FromLiteralConstant;
  33. void visitOutputInstructionCallers(Function *OutputFunction,
  34. const hlsl::DxilSignature &OutputSignature,
  35. OP *HlslOP,
  36. std::function<void(CallInst *)> Visitor);
  37. public:
  38. static char ID; // Pass identification, replacement for typeid
  39. explicit DxilOutputColorBecomesConstant() : ModulePass(ID) {}
  40. const char *getPassName() const override { return "DXIL Constant Color Mod"; }
  41. void applyOptions(PassOptions O) override;
  42. bool runOnModule(Module &M) override;
  43. };
  44. void DxilOutputColorBecomesConstant::applyOptions(PassOptions O) {
  45. GetPassOptionFloat(O, "constant-red", &Red, 1.f);
  46. GetPassOptionFloat(O, "constant-green", &Green, 1.f);
  47. GetPassOptionFloat(O, "constant-blue", &Blue, 1.f);
  48. GetPassOptionFloat(O, "constant-alpha", &Alpha, 1.f);
  49. int mode = 0;
  50. GetPassOptionInt(O, "mod-mode", &mode, 0);
  51. Mode = static_cast<VisualizerInstrumentationMode>(mode);
  52. }
  53. void DxilOutputColorBecomesConstant::visitOutputInstructionCallers(
  54. Function *OutputFunction, const hlsl::DxilSignature &OutputSignature,
  55. OP *HlslOP, std::function<void(CallInst *)> Visitor) {
  56. auto OutputFunctionUses = OutputFunction->uses();
  57. for (Use &FunctionUse : OutputFunctionUses) {
  58. iterator_range<Value::user_iterator> FunctionUsers = FunctionUse->users();
  59. for (User *FunctionUser : FunctionUsers) {
  60. if (isa<Instruction>(FunctionUser)) {
  61. auto CallInstruction = cast<CallInst>(FunctionUser);
  62. // Check if the instruction writes to a render target (as opposed to a
  63. // system-value, such as RenderTargetArrayIndex)
  64. Value *OutputID = CallInstruction->getArgOperand(
  65. DXIL::OperandIndex::kStoreOutputIDOpIdx);
  66. unsigned SignatureElementIndex =
  67. cast<ConstantInt>(OutputID)->getLimitedValue();
  68. const DxilSignatureElement &SignatureElement =
  69. OutputSignature.GetElement(SignatureElementIndex);
  70. // We only modify the output color for RTV0
  71. if (SignatureElement.GetSemantic()->GetKind() ==
  72. DXIL::SemanticKind::Target &&
  73. SignatureElement.GetSemanticStartIndex() == 0) {
  74. // Replace the source operand with the appropriate constant value
  75. Visitor(CallInstruction);
  76. }
  77. }
  78. }
  79. }
  80. }
  81. bool DxilOutputColorBecomesConstant::runOnModule(Module &M) {
  82. // This pass finds all users of the "StoreOutput" function, and replaces their
  83. // source operands with a constant value.
  84. DxilModule &DM = M.GetOrCreateDxilModule();
  85. LLVMContext &Ctx = M.getContext();
  86. OP *HlslOP = DM.GetOP();
  87. const hlsl::DxilSignature &OutputSignature = DM.GetOutputSignature();
  88. Function *FloatOutputFunction =
  89. HlslOP->GetOpFunc(DXIL::OpCode::StoreOutput, Type::getFloatTy(Ctx));
  90. Function *IntOutputFunction =
  91. HlslOP->GetOpFunc(DXIL::OpCode::StoreOutput, Type::getInt32Ty(Ctx));
  92. bool hasFloatOutputs = false;
  93. bool hasIntOutputs = false;
  94. visitOutputInstructionCallers(
  95. FloatOutputFunction, OutputSignature, HlslOP,
  96. [&hasFloatOutputs](CallInst *) { hasFloatOutputs = true; });
  97. visitOutputInstructionCallers(
  98. IntOutputFunction, OutputSignature, HlslOP,
  99. [&hasIntOutputs](CallInst *) { hasIntOutputs = true; });
  100. if (!hasFloatOutputs && !hasIntOutputs) {
  101. return false;
  102. }
  103. // Otherwise, we assume the shader outputs only one or the other (because the
  104. // 0th RTV can't have a mixed type)
  105. DXASSERT(!hasFloatOutputs || !hasIntOutputs,
  106. "Only one or the other type of output: float or int");
  107. std::array<llvm::Value *, 4> ReplacementColors;
  108. switch (Mode) {
  109. case FromLiteralConstant: {
  110. if (hasFloatOutputs) {
  111. ReplacementColors[0] = HlslOP->GetFloatConst(Red);
  112. ReplacementColors[1] = HlslOP->GetFloatConst(Green);
  113. ReplacementColors[2] = HlslOP->GetFloatConst(Blue);
  114. ReplacementColors[3] = HlslOP->GetFloatConst(Alpha);
  115. }
  116. if (hasIntOutputs) {
  117. ReplacementColors[0] = HlslOP->GetI32Const(static_cast<int>(Red));
  118. ReplacementColors[1] = HlslOP->GetI32Const(static_cast<int>(Green));
  119. ReplacementColors[2] = HlslOP->GetI32Const(static_cast<int>(Blue));
  120. ReplacementColors[3] = HlslOP->GetI32Const(static_cast<int>(Alpha));
  121. }
  122. } break;
  123. case FromConstantBuffer: {
  124. // Setup a constant buffer with a single float4 in it:
  125. SmallVector<llvm::Type *, 4> Elements{
  126. Type::getFloatTy(Ctx), Type::getFloatTy(Ctx), Type::getFloatTy(Ctx),
  127. Type::getFloatTy(Ctx)};
  128. llvm::StructType *CBStructTy =
  129. llvm::StructType::create(Elements, "PIX_ConstantColorCB_Type");
  130. std::unique_ptr<DxilCBuffer> pCBuf = llvm::make_unique<DxilCBuffer>();
  131. pCBuf->SetGlobalName("PIX_ConstantColorCBName");
  132. pCBuf->SetGlobalSymbol(UndefValue::get(CBStructTy));
  133. pCBuf->SetID(0);
  134. pCBuf->SetSpaceID(
  135. (unsigned int)-2); // This is the reserved-for-tools register space
  136. pCBuf->SetLowerBound(0);
  137. pCBuf->SetRangeSize(1);
  138. pCBuf->SetSize(4);
  139. Instruction *entryPointInstruction =
  140. &*(DM.GetEntryFunction()->begin()->begin());
  141. IRBuilder<> Builder(entryPointInstruction);
  142. // Create handle for the newly-added constant buffer (which is achieved via
  143. // a function call)
  144. auto ConstantBufferName = "PIX_Constant_Color_CB_Handle";
  145. CallInst* callCreateHandle = PIXPassHelpers::CreateHandleForResource(DM, Builder, pCBuf.get(), ConstantBufferName);
  146. DM.AddCBuffer(std::move(pCBuf));
  147. DM.ReEmitDxilResources();
  148. #define PIX_CONSTANT_VALUE "PIX_Constant_Color_Value"
  149. // Insert the Buffer load instruction:
  150. Function *CBLoad = HlslOP->GetOpFunc(
  151. OP::OpCode::CBufferLoadLegacy,
  152. hasFloatOutputs ? Type::getFloatTy(Ctx) : Type::getInt32Ty(Ctx));
  153. Constant *OpArg =
  154. HlslOP->GetU32Const((unsigned)OP::OpCode::CBufferLoadLegacy);
  155. Value *ResourceHandle = callCreateHandle;
  156. Constant *RowIndex = HlslOP->GetU32Const(0);
  157. CallInst *loadLegacy = Builder.CreateCall(
  158. CBLoad, {OpArg, ResourceHandle, RowIndex}, PIX_CONSTANT_VALUE);
  159. // Now extract four color values:
  160. ReplacementColors[0] =
  161. Builder.CreateExtractValue(loadLegacy, 0, PIX_CONSTANT_VALUE "0");
  162. ReplacementColors[1] =
  163. Builder.CreateExtractValue(loadLegacy, 1, PIX_CONSTANT_VALUE "1");
  164. ReplacementColors[2] =
  165. Builder.CreateExtractValue(loadLegacy, 2, PIX_CONSTANT_VALUE "2");
  166. ReplacementColors[3] =
  167. Builder.CreateExtractValue(loadLegacy, 3, PIX_CONSTANT_VALUE "3");
  168. } break;
  169. default:
  170. assert(false);
  171. return 0;
  172. }
  173. bool Modified = false;
  174. // The StoreOutput function can store either a float or an integer, depending
  175. // on the intended output render-target resource view.
  176. if (hasFloatOutputs) {
  177. visitOutputInstructionCallers(
  178. FloatOutputFunction, OutputSignature, HlslOP,
  179. [&ReplacementColors, &Modified](CallInst *CallInstruction) {
  180. Modified = true;
  181. // The output column is the channel (red, green, blue or alpha) within
  182. // the output pixel
  183. Value *OutputColumnOperand = CallInstruction->getOperand(
  184. hlsl::DXIL::OperandIndex::kStoreOutputColOpIdx);
  185. ConstantInt *OutputColumnConstant =
  186. cast<ConstantInt>(OutputColumnOperand);
  187. APInt OutputColumn = OutputColumnConstant->getValue();
  188. CallInstruction->setOperand(
  189. hlsl::DXIL::OperandIndex::kStoreOutputValOpIdx,
  190. ReplacementColors[*OutputColumn.getRawData()]);
  191. });
  192. }
  193. if (hasIntOutputs) {
  194. visitOutputInstructionCallers(
  195. IntOutputFunction, OutputSignature, HlslOP,
  196. [&ReplacementColors, &Modified](CallInst *CallInstruction) {
  197. Modified = true;
  198. // The output column is the channel (red, green, blue or alpha) within
  199. // the output pixel
  200. Value *OutputColumnOperand = CallInstruction->getOperand(
  201. hlsl::DXIL::OperandIndex::kStoreOutputColOpIdx);
  202. ConstantInt *OutputColumnConstant =
  203. cast<ConstantInt>(OutputColumnOperand);
  204. APInt OutputColumn = OutputColumnConstant->getValue();
  205. CallInstruction->setOperand(
  206. hlsl::DXIL::OperandIndex::kStoreOutputValOpIdx,
  207. ReplacementColors[*OutputColumn.getRawData()]);
  208. });
  209. }
  210. return Modified;
  211. }
  212. char DxilOutputColorBecomesConstant::ID = 0;
  213. ModulePass *llvm::createDxilOutputColorBecomesConstantPass() {
  214. return new DxilOutputColorBecomesConstant();
  215. }
  216. INITIALIZE_PASS(DxilOutputColorBecomesConstant, "hlsl-dxil-constantColor",
  217. "DXIL Constant Color Mod", false, false)