291 строка
11 KiB
C++
291 строка
11 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// DxilPIXDXRInvocationsLog.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. //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "dxc/DXIL/DxilFunctionProps.h"
|
|
#include "dxc/DXIL/DxilOperations.h"
|
|
#include "dxc/DXIL/DxilUtil.h"
|
|
|
|
#include "dxc/DXIL/DxilInstructions.h"
|
|
#include "dxc/DXIL/DxilModule.h"
|
|
#include "dxc/DxilPIXPasses/DxilPIXPasses.h"
|
|
|
|
#include "llvm/IR/InstIterator.h"
|
|
#include "llvm/IR/PassManager.h"
|
|
#include "llvm/Support/FormattedStream.h"
|
|
#include "llvm/Transforms/Utils/Local.h"
|
|
|
|
#include "PixPassHelpers.h"
|
|
|
|
using namespace llvm;
|
|
using namespace hlsl;
|
|
using namespace PIXPassHelpers;
|
|
|
|
class DxilPIXDXRInvocationsLog : public ModulePass {
|
|
uint64_t m_MaxNumEntriesInLog = 1;
|
|
|
|
public:
|
|
static char ID;
|
|
DxilPIXDXRInvocationsLog() : ModulePass(ID) {}
|
|
StringRef getPassName() const override {
|
|
return "DXIL Logs all non-RayGen DXR 1.0 invocations into a UAV";
|
|
}
|
|
|
|
void applyOptions(PassOptions O) override;
|
|
bool runOnModule(Module &M) override;
|
|
};
|
|
|
|
static DXIL::ShaderKind GetShaderKind(DxilModule const &DM,
|
|
llvm::Function const *entryFunction) {
|
|
DXIL::ShaderKind ShaderKind = DXIL::ShaderKind::Invalid;
|
|
if (!DM.HasDxilFunctionProps(entryFunction)) {
|
|
auto ShaderModel = DM.GetShaderModel();
|
|
ShaderKind = ShaderModel->GetKind();
|
|
} else {
|
|
auto const &Props = DM.GetDxilFunctionProps(entryFunction);
|
|
ShaderKind = Props.shaderKind;
|
|
}
|
|
|
|
return ShaderKind;
|
|
}
|
|
|
|
void DxilPIXDXRInvocationsLog::applyOptions(PassOptions O) {
|
|
GetPassOptionUInt64(
|
|
O, "maxNumEntriesInLog", &m_MaxNumEntriesInLog,
|
|
1); // Use a silly default value. PIX should set a better value here.
|
|
}
|
|
|
|
bool DxilPIXDXRInvocationsLog::runOnModule(Module &M) {
|
|
|
|
DxilModule &DM = M.GetOrCreateDxilModule();
|
|
LLVMContext &Ctx = M.getContext();
|
|
OP *HlslOP = DM.GetOP();
|
|
|
|
bool Modified = false;
|
|
|
|
for (auto entryFunction : DM.GetExportedFunctions()) {
|
|
|
|
DXIL::ShaderKind ShaderKind = GetShaderKind(DM, entryFunction);
|
|
|
|
switch (ShaderKind) {
|
|
case DXIL::ShaderKind::Intersection:
|
|
case DXIL::ShaderKind::AnyHit:
|
|
case DXIL::ShaderKind::ClosestHit:
|
|
case DXIL::ShaderKind::Miss:
|
|
break;
|
|
|
|
default:
|
|
continue;
|
|
}
|
|
|
|
Modified = true;
|
|
|
|
IRBuilder<> Builder(dxilutil::FirstNonAllocaInsertionPt(entryFunction));
|
|
|
|
// Add the UAVs that we're going to write to
|
|
CallInst *HandleForCountUAV = PIXPassHelpers::CreateUAV(
|
|
DM, Builder, /* registerID */ 0, "PIX_CountUAV_Handle");
|
|
CallInst *HandleForUAV = PIXPassHelpers::CreateUAV(
|
|
DM, Builder, /* registerID */ 1, "PIX_UAV_Handle");
|
|
|
|
DM.ReEmitDxilResources();
|
|
|
|
auto DispatchRaysIndexOpFunc = HlslOP->GetOpFunc(
|
|
DXIL::OpCode::DispatchRaysIndex, Type::getInt32Ty(Ctx));
|
|
auto WorldRayOriginOpFunc =
|
|
HlslOP->GetOpFunc(DXIL::OpCode::WorldRayOrigin, Type::getFloatTy(Ctx));
|
|
auto WorldRayDirectionOpFunc = HlslOP->GetOpFunc(
|
|
DXIL::OpCode::WorldRayDirection, Type::getFloatTy(Ctx));
|
|
auto CurrentRayTFunc =
|
|
HlslOP->GetOpFunc(DXIL::OpCode::RayTCurrent, Type::getFloatTy(Ctx));
|
|
auto MinRayTFunc =
|
|
HlslOP->GetOpFunc(DXIL::OpCode::RayTMin, Type::getFloatTy(Ctx));
|
|
auto RayFlagsFunc =
|
|
HlslOP->GetOpFunc(DXIL::OpCode::RayFlags, Type::getInt32Ty(Ctx));
|
|
|
|
auto *DispatchRaysIndexOpcode =
|
|
HlslOP->GetU32Const((unsigned)DXIL::OpCode::DispatchRaysIndex);
|
|
auto *WorldRayOriginOpcode =
|
|
HlslOP->GetU32Const((unsigned)DXIL::OpCode::WorldRayOrigin);
|
|
auto *WorldRayDirectionOpcode =
|
|
HlslOP->GetU32Const((unsigned)DXIL::OpCode::WorldRayDirection);
|
|
auto *CurrentRayTOpcode =
|
|
HlslOP->GetU32Const((unsigned)DXIL::OpCode::RayTCurrent);
|
|
auto *MinRayTOpcode = HlslOP->GetU32Const((unsigned)DXIL::OpCode::RayTMin);
|
|
auto *RayFlagsOpcode =
|
|
HlslOP->GetU32Const((unsigned)DXIL::OpCode::RayFlags);
|
|
|
|
auto DispatchRaysX = Builder.CreateCall(
|
|
DispatchRaysIndexOpFunc,
|
|
{DispatchRaysIndexOpcode, HlslOP->GetI8Const(0)}, "DispatchRaysX");
|
|
auto DispatchRaysY = Builder.CreateCall(
|
|
DispatchRaysIndexOpFunc,
|
|
{DispatchRaysIndexOpcode, HlslOP->GetI8Const(1)}, "DispatchRaysY");
|
|
auto DispatchRaysZ = Builder.CreateCall(
|
|
DispatchRaysIndexOpFunc,
|
|
{DispatchRaysIndexOpcode, HlslOP->GetI8Const(2)}, "DispatchRaysZ");
|
|
|
|
auto WorldRayOriginX = Builder.CreateCall(
|
|
WorldRayOriginOpFunc, {WorldRayOriginOpcode, HlslOP->GetI8Const(0)},
|
|
"WorldRayOriginX");
|
|
auto WorldRayOriginY = Builder.CreateCall(
|
|
WorldRayOriginOpFunc, {WorldRayOriginOpcode, HlslOP->GetI8Const(1)},
|
|
"WorldRayOriginY");
|
|
auto WorldRayOriginZ = Builder.CreateCall(
|
|
WorldRayOriginOpFunc, {WorldRayOriginOpcode, HlslOP->GetI8Const(2)},
|
|
"WorldRayOriginZ");
|
|
|
|
auto WorldRayDirectionX = Builder.CreateCall(
|
|
WorldRayDirectionOpFunc,
|
|
{WorldRayDirectionOpcode, HlslOP->GetI8Const(0)}, "WorldRayDirectionX");
|
|
auto WorldRayDirectionY = Builder.CreateCall(
|
|
WorldRayDirectionOpFunc,
|
|
{WorldRayDirectionOpcode, HlslOP->GetI8Const(1)}, "WorldRayDirectionY");
|
|
auto WorldRayDirectionZ = Builder.CreateCall(
|
|
WorldRayDirectionOpFunc,
|
|
{WorldRayDirectionOpcode, HlslOP->GetI8Const(2)}, "WorldRayDirectionZ");
|
|
|
|
auto CurrentRayT =
|
|
Builder.CreateCall(CurrentRayTFunc, {CurrentRayTOpcode}, "CurrentRayT");
|
|
auto MinRayT = Builder.CreateCall(MinRayTFunc, {MinRayTOpcode}, "MinRayT");
|
|
auto RayFlags =
|
|
Builder.CreateCall(RayFlagsFunc, {RayFlagsOpcode}, "RayFlags");
|
|
|
|
Function *AtomicOpFunc =
|
|
HlslOP->GetOpFunc(OP::OpCode::AtomicBinOp, Type::getInt32Ty(Ctx));
|
|
Constant *AtomicBinOpcode =
|
|
HlslOP->GetU32Const((unsigned)OP::OpCode::AtomicBinOp);
|
|
Constant *AtomicAdd =
|
|
HlslOP->GetU32Const((unsigned)DXIL::AtomicBinOpCode::Add);
|
|
|
|
Function *UMinOpFunc =
|
|
HlslOP->GetOpFunc(OP::OpCode::UMin, Type::getInt32Ty(Ctx));
|
|
Constant *UMinOpCode = HlslOP->GetU32Const((unsigned)OP::OpCode::UMin);
|
|
|
|
Function *StoreFuncFloat =
|
|
HlslOP->GetOpFunc(OP::OpCode::BufferStore, Type::getFloatTy(Ctx));
|
|
Function *StoreFuncInt =
|
|
HlslOP->GetOpFunc(OP::OpCode::BufferStore, Type::getInt32Ty(Ctx));
|
|
Constant *StoreOpcode =
|
|
HlslOP->GetU32Const((unsigned)OP::OpCode::BufferStore);
|
|
|
|
Constant *WriteMask_XYZW = HlslOP->GetI8Const(15);
|
|
Constant *WriteMask_X = HlslOP->GetI8Const(1);
|
|
Constant *ShaderKindAsConstant = HlslOP->GetU32Const((uint32_t)ShaderKind);
|
|
Constant *MaxEntryIndexAsConstant =
|
|
HlslOP->GetU32Const((uint32_t)m_MaxNumEntriesInLog - 1u);
|
|
Constant *Zero32Arg = HlslOP->GetU32Const(0);
|
|
Constant *One32Arg = HlslOP->GetU32Const(1);
|
|
UndefValue *UndefArg = UndefValue::get(Type::getInt32Ty(Ctx));
|
|
|
|
// Firstly we read this invocation's index within the invocations log
|
|
// buffer, and atomically increment it for the next invocation
|
|
auto *EntryIndex = Builder.CreateCall(
|
|
AtomicOpFunc,
|
|
{
|
|
AtomicBinOpcode, // i32, ; opcode
|
|
HandleForCountUAV, // %dx.types.Handle, ; resource handle
|
|
AtomicAdd, // i32, ; binary operation code
|
|
Zero32Arg, // i32, ; coordinate c0: byte offset
|
|
UndefArg, // i32, ; coordinate c1 (unused)
|
|
UndefArg, // i32, ; coordinate c2 (unused)
|
|
One32Arg // i32); increment value
|
|
},
|
|
"EntryIndexResult");
|
|
|
|
// Clamp the index so that we don't write off the end of the UAV. If we
|
|
// clamp, then it's up to PIX to replay the work again with a larger log
|
|
// buffer.
|
|
auto *EntryIndexClamped = Builder.CreateCall(
|
|
UMinOpFunc, {UMinOpCode, EntryIndex, MaxEntryIndexAsConstant});
|
|
|
|
const auto numBytesPerEntry =
|
|
4 + (3 * 4) + (3 * 4) + (3 * 4) + 4 + 4 +
|
|
4; // See number of bytes we store per shader invocation below
|
|
|
|
auto EntryOffset =
|
|
Builder.CreateMul(EntryIndexClamped,
|
|
HlslOP->GetU32Const(numBytesPerEntry), "EntryOffset");
|
|
auto EntryOffsetPlus16 = Builder.CreateAdd(
|
|
EntryOffset, HlslOP->GetU32Const(16), "EntryOffsetPlus16");
|
|
auto EntryOffsetPlus32 = Builder.CreateAdd(
|
|
EntryOffset, HlslOP->GetU32Const(32), "EntryOffsetPlus32");
|
|
auto EntryOffsetPlus48 = Builder.CreateAdd(
|
|
EntryOffset, HlslOP->GetU32Const(48), "EntryOffsetPlus48");
|
|
|
|
// Then we start storing the invocation's info into the main UAV buffer
|
|
(void)Builder.CreateCall(
|
|
StoreFuncInt,
|
|
{
|
|
StoreOpcode, // i32, ; opcode
|
|
HandleForUAV, // %dx.types.Handle, ; resource handle
|
|
EntryOffset, // i32, ; coordinate c0: byte offset
|
|
UndefArg, // i32, ; coordinate c1 (unused)
|
|
ShaderKindAsConstant, // i32, ; value v0
|
|
DispatchRaysX, // i32, ; value v1
|
|
DispatchRaysY, // i32, ; value v2
|
|
DispatchRaysZ, // i32, ; value v3
|
|
WriteMask_XYZW // i8 ;
|
|
});
|
|
|
|
(void)Builder.CreateCall(
|
|
StoreFuncFloat,
|
|
{
|
|
StoreOpcode, // i32, ; opcode
|
|
HandleForUAV, // %dx.types.Handle, ; resource handle
|
|
EntryOffsetPlus16, // i32, ; coordinate c0: byte offset
|
|
UndefArg, // i32, ; coordinate c1 (unused)
|
|
WorldRayOriginX, // f32, ; value v0
|
|
WorldRayOriginY, // f32, ; value v1
|
|
WorldRayOriginZ, // f32, ; value v2
|
|
WorldRayDirectionX, // f32, ; value v3
|
|
WriteMask_XYZW // i8 ;
|
|
});
|
|
|
|
(void)Builder.CreateCall(
|
|
StoreFuncFloat,
|
|
{
|
|
StoreOpcode, // i32, ; opcode
|
|
HandleForUAV, // %dx.types.Handle, ; resource handle
|
|
EntryOffsetPlus32, // i32, ; coordinate c0: byte offset
|
|
UndefArg, // i32, ; coordinate c1 (unused)
|
|
WorldRayDirectionY, // f32, ; value v0
|
|
WorldRayDirectionZ, // f32, ; value v1
|
|
MinRayT, // f32, ; value v2
|
|
CurrentRayT, // f32, ; value v3
|
|
WriteMask_XYZW // i8 ;
|
|
});
|
|
|
|
(void)Builder.CreateCall(
|
|
StoreFuncInt,
|
|
{
|
|
StoreOpcode, // i32, ; opcode
|
|
HandleForUAV, // %dx.types.Handle, ; resource handle
|
|
EntryOffsetPlus48, // i32, ; coordinate c0: byte offset
|
|
UndefArg, // i32, ; coordinate c1 (unused)
|
|
RayFlags, // i32, ; value v0
|
|
UndefArg, // i32, ; value v1
|
|
UndefArg, // i32, ; value v2
|
|
UndefArg, // i32, ; value v3
|
|
WriteMask_X // i8 ;
|
|
});
|
|
}
|
|
|
|
return Modified;
|
|
}
|
|
|
|
char DxilPIXDXRInvocationsLog::ID = 0;
|
|
|
|
ModulePass *llvm::createDxilPIXDXRInvocationsLogPass() {
|
|
return new DxilPIXDXRInvocationsLog();
|
|
}
|
|
|
|
INITIALIZE_PASS(DxilPIXDXRInvocationsLog, "hlsl-dxil-pix-dxr-invocations-log",
|
|
"HLSL DXIL Logs all non-RayGen DXR 1.0 invocations into a UAV",
|
|
false, false)
|