123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- ///////////////////////////////////////////////////////////////////////////////
- // //
- // DxilOutputColorBecomesConstant.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 stomp a pixel shader's output color to a given //
- // constant value //
- // //
- ///////////////////////////////////////////////////////////////////////////////
- #include "dxc/DXIL/DxilModule.h"
- #include "dxc/DXIL/DxilOperations.h"
- #include "dxc/DxilPIXPasses/DxilPIXPasses.h"
- #include "dxc/HLSL/DxilGenerationPass.h"
- #include "dxc/HLSL/DxilSpanAllocator.h"
- #include "llvm/IR/PassManager.h"
- #include "llvm/Transforms/Utils/Local.h"
- #include <array>
- #include "PixPassHelpers.h"
- using namespace llvm;
- using namespace hlsl;
- class DxilOutputColorBecomesConstant : public ModulePass {
- enum VisualizerInstrumentationMode {
- FromLiteralConstant,
- FromConstantBuffer
- };
- float Red = 1.f;
- float Green = 1.f;
- float Blue = 1.f;
- float Alpha = 1.f;
- VisualizerInstrumentationMode Mode = FromLiteralConstant;
- void visitOutputInstructionCallers(Function *OutputFunction,
- const hlsl::DxilSignature &OutputSignature,
- OP *HlslOP,
- std::function<void(CallInst *)> Visitor);
- public:
- static char ID; // Pass identification, replacement for typeid
- explicit DxilOutputColorBecomesConstant() : ModulePass(ID) {}
- const char *getPassName() const override { return "DXIL Constant Color Mod"; }
- void applyOptions(PassOptions O) override;
- bool runOnModule(Module &M) override;
- };
- void DxilOutputColorBecomesConstant::applyOptions(PassOptions O) {
- GetPassOptionFloat(O, "constant-red", &Red, 1.f);
- GetPassOptionFloat(O, "constant-green", &Green, 1.f);
- GetPassOptionFloat(O, "constant-blue", &Blue, 1.f);
- GetPassOptionFloat(O, "constant-alpha", &Alpha, 1.f);
- int mode = 0;
- GetPassOptionInt(O, "mod-mode", &mode, 0);
- Mode = static_cast<VisualizerInstrumentationMode>(mode);
- }
- void DxilOutputColorBecomesConstant::visitOutputInstructionCallers(
- Function *OutputFunction, const hlsl::DxilSignature &OutputSignature,
- OP *HlslOP, std::function<void(CallInst *)> Visitor) {
- auto OutputFunctionUses = OutputFunction->uses();
- for (Use &FunctionUse : OutputFunctionUses) {
- iterator_range<Value::user_iterator> FunctionUsers = FunctionUse->users();
- for (User *FunctionUser : FunctionUsers) {
- if (isa<Instruction>(FunctionUser)) {
- auto CallInstruction = cast<CallInst>(FunctionUser);
- // Check if the instruction writes to a render target (as opposed to a
- // system-value, such as RenderTargetArrayIndex)
- Value *OutputID = CallInstruction->getArgOperand(
- DXIL::OperandIndex::kStoreOutputIDOpIdx);
- unsigned SignatureElementIndex =
- cast<ConstantInt>(OutputID)->getLimitedValue();
- const DxilSignatureElement &SignatureElement =
- OutputSignature.GetElement(SignatureElementIndex);
- // We only modify the output color for RTV0
- if (SignatureElement.GetSemantic()->GetKind() ==
- DXIL::SemanticKind::Target &&
- SignatureElement.GetSemanticStartIndex() == 0) {
- // Replace the source operand with the appropriate constant value
- Visitor(CallInstruction);
- }
- }
- }
- }
- }
- bool DxilOutputColorBecomesConstant::runOnModule(Module &M) {
- // This pass finds all users of the "StoreOutput" function, and replaces their
- // source operands with a constant value.
- DxilModule &DM = M.GetOrCreateDxilModule();
- LLVMContext &Ctx = M.getContext();
- OP *HlslOP = DM.GetOP();
- const hlsl::DxilSignature &OutputSignature = DM.GetOutputSignature();
- Function *FloatOutputFunction =
- HlslOP->GetOpFunc(DXIL::OpCode::StoreOutput, Type::getFloatTy(Ctx));
- Function *IntOutputFunction =
- HlslOP->GetOpFunc(DXIL::OpCode::StoreOutput, Type::getInt32Ty(Ctx));
- bool hasFloatOutputs = false;
- bool hasIntOutputs = false;
- visitOutputInstructionCallers(
- FloatOutputFunction, OutputSignature, HlslOP,
- [&hasFloatOutputs](CallInst *) { hasFloatOutputs = true; });
- visitOutputInstructionCallers(
- IntOutputFunction, OutputSignature, HlslOP,
- [&hasIntOutputs](CallInst *) { hasIntOutputs = true; });
- if (!hasFloatOutputs && !hasIntOutputs) {
- return false;
- }
- // Otherwise, we assume the shader outputs only one or the other (because the
- // 0th RTV can't have a mixed type)
- DXASSERT(!hasFloatOutputs || !hasIntOutputs,
- "Only one or the other type of output: float or int");
- std::array<llvm::Value *, 4> ReplacementColors;
- switch (Mode) {
- case FromLiteralConstant: {
- if (hasFloatOutputs) {
- ReplacementColors[0] = HlslOP->GetFloatConst(Red);
- ReplacementColors[1] = HlslOP->GetFloatConst(Green);
- ReplacementColors[2] = HlslOP->GetFloatConst(Blue);
- ReplacementColors[3] = HlslOP->GetFloatConst(Alpha);
- }
- if (hasIntOutputs) {
- ReplacementColors[0] = HlslOP->GetI32Const(static_cast<int>(Red));
- ReplacementColors[1] = HlslOP->GetI32Const(static_cast<int>(Green));
- ReplacementColors[2] = HlslOP->GetI32Const(static_cast<int>(Blue));
- ReplacementColors[3] = HlslOP->GetI32Const(static_cast<int>(Alpha));
- }
- } break;
- case FromConstantBuffer: {
- // Setup a constant buffer with a single float4 in it:
- SmallVector<llvm::Type *, 4> Elements{
- Type::getFloatTy(Ctx), Type::getFloatTy(Ctx), Type::getFloatTy(Ctx),
- Type::getFloatTy(Ctx)};
- llvm::StructType *CBStructTy =
- llvm::StructType::create(Elements, "PIX_ConstantColorCB_Type");
- std::unique_ptr<DxilCBuffer> pCBuf = llvm::make_unique<DxilCBuffer>();
- pCBuf->SetGlobalName("PIX_ConstantColorCBName");
- pCBuf->SetGlobalSymbol(UndefValue::get(CBStructTy));
- pCBuf->SetID(0);
- pCBuf->SetSpaceID(
- (unsigned int)-2); // This is the reserved-for-tools register space
- pCBuf->SetLowerBound(0);
- pCBuf->SetRangeSize(1);
- pCBuf->SetSize(4);
- Instruction *entryPointInstruction =
- &*(DM.GetEntryFunction()->begin()->begin());
- IRBuilder<> Builder(entryPointInstruction);
- // Create handle for the newly-added constant buffer (which is achieved via
- // a function call)
- auto ConstantBufferName = "PIX_Constant_Color_CB_Handle";
- CallInst* callCreateHandle = PIXPassHelpers::CreateHandleForResource(DM, Builder, pCBuf.get(), ConstantBufferName);
- DM.AddCBuffer(std::move(pCBuf));
- DM.ReEmitDxilResources();
- #define PIX_CONSTANT_VALUE "PIX_Constant_Color_Value"
- // Insert the Buffer load instruction:
- Function *CBLoad = HlslOP->GetOpFunc(
- OP::OpCode::CBufferLoadLegacy,
- hasFloatOutputs ? Type::getFloatTy(Ctx) : Type::getInt32Ty(Ctx));
- Constant *OpArg =
- HlslOP->GetU32Const((unsigned)OP::OpCode::CBufferLoadLegacy);
- Value *ResourceHandle = callCreateHandle;
- Constant *RowIndex = HlslOP->GetU32Const(0);
- CallInst *loadLegacy = Builder.CreateCall(
- CBLoad, {OpArg, ResourceHandle, RowIndex}, PIX_CONSTANT_VALUE);
- // Now extract four color values:
- ReplacementColors[0] =
- Builder.CreateExtractValue(loadLegacy, 0, PIX_CONSTANT_VALUE "0");
- ReplacementColors[1] =
- Builder.CreateExtractValue(loadLegacy, 1, PIX_CONSTANT_VALUE "1");
- ReplacementColors[2] =
- Builder.CreateExtractValue(loadLegacy, 2, PIX_CONSTANT_VALUE "2");
- ReplacementColors[3] =
- Builder.CreateExtractValue(loadLegacy, 3, PIX_CONSTANT_VALUE "3");
- } break;
- default:
- assert(false);
- return 0;
- }
- bool Modified = false;
- // The StoreOutput function can store either a float or an integer, depending
- // on the intended output render-target resource view.
- if (hasFloatOutputs) {
- visitOutputInstructionCallers(
- FloatOutputFunction, OutputSignature, HlslOP,
- [&ReplacementColors, &Modified](CallInst *CallInstruction) {
- Modified = true;
- // The output column is the channel (red, green, blue or alpha) within
- // the output pixel
- Value *OutputColumnOperand = CallInstruction->getOperand(
- hlsl::DXIL::OperandIndex::kStoreOutputColOpIdx);
- ConstantInt *OutputColumnConstant =
- cast<ConstantInt>(OutputColumnOperand);
- APInt OutputColumn = OutputColumnConstant->getValue();
- CallInstruction->setOperand(
- hlsl::DXIL::OperandIndex::kStoreOutputValOpIdx,
- ReplacementColors[*OutputColumn.getRawData()]);
- });
- }
- if (hasIntOutputs) {
- visitOutputInstructionCallers(
- IntOutputFunction, OutputSignature, HlslOP,
- [&ReplacementColors, &Modified](CallInst *CallInstruction) {
- Modified = true;
- // The output column is the channel (red, green, blue or alpha) within
- // the output pixel
- Value *OutputColumnOperand = CallInstruction->getOperand(
- hlsl::DXIL::OperandIndex::kStoreOutputColOpIdx);
- ConstantInt *OutputColumnConstant =
- cast<ConstantInt>(OutputColumnOperand);
- APInt OutputColumn = OutputColumnConstant->getValue();
- CallInstruction->setOperand(
- hlsl::DXIL::OperandIndex::kStoreOutputValOpIdx,
- ReplacementColors[*OutputColumn.getRawData()]);
- });
- }
- return Modified;
- }
- char DxilOutputColorBecomesConstant::ID = 0;
- ModulePass *llvm::createDxilOutputColorBecomesConstantPass() {
- return new DxilOutputColorBecomesConstant();
- }
- INITIALIZE_PASS(DxilOutputColorBecomesConstant, "hlsl-dxil-constantColor",
- "DXIL Constant Color Mod", false, false)
|