DxilOutputColorBecomesConstant.cpp 11 KB

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