Files
UnrealEngine/Engine/Source/Runtime/D3D12RHI/Private/D3D12CommandContext.h
2025-05-18 13:04:45 +08:00

1222 lines
50 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
D3D12CommandContext.h: D3D12 Command Context Interfaces
=============================================================================*/
#pragma once
#include "D3D12Allocation.h"
#include "D3D12BindlessDescriptors.h"
#include "D3D12CommandList.h"
#include "D3D12Queue.h"
#include "D3D12Query.h"
#include "D3D12Resources.h"
#include "D3D12StateCachePrivate.h"
#include "D3D12Submission.h"
#include "D3D12Texture.h"
#include "Experimental/Containers/RobinHoodHashTable.h"
#include "RHICoreShader.h"
#include "RHICore.h"
#include "RHIShaderBindingLayout.h"
#include "GPUProfiler.h"
#if USE_PIX
#include "Windows/AllowWindowsPlatformTypes.h"
THIRD_PARTY_INCLUDES_START
#include <pix3.h>
#include "Windows/HideWindowsPlatformTypes.h"
THIRD_PARTY_INCLUDES_END
#endif
enum class ED3D12PipelineType : uint8;
struct FD3D12DescriptorHeap;
struct FRayTracingShaderBindings;
struct FD3D12ViewSubset;
class FD3D12Device;
class FD3D12Resource;
class FD3D12Heap;
struct FD3D12DescriptorHeap;
class FD3D12ResourceLocation;
class FD3D12RootSignature;
class FD3D12ExplicitDescriptorCache;
struct FD3D12DeferredDeleteObject
{
enum class EType
{
RHIObject,
D3DObject,
Heap,
DescriptorHeap,
#if PLATFORM_SUPPORTS_BINDLESS_RENDERING
BindlessDescriptor,
BindlessDescriptorHeap,
#endif
CPUAllocation,
DescriptorBlock,
VirtualAllocation,
Func,
TextureStagingBuffer
} Type;
union
{
FD3D12Resource* RHIObject;
FD3D12Heap* Heap;
FD3D12DescriptorHeap* DescriptorHeap;
ID3D12Object* D3DObject;
TUniqueFunction<void()>* Func;
struct
{
FRHIDescriptorHandle Handle;
FD3D12Device* Device;
} BindlessDescriptor;
void* CPUAllocation;
struct
{
FD3D12OnlineDescriptorBlock* Block;
FD3D12OnlineDescriptorManager* Manager;
} DescriptorBlock;
struct
{
FPlatformMemory::FPlatformVirtualMemoryBlock VirtualBlock;
ETextureCreateFlags Flags;
uint64 CommittedTextureSize;
void* RawMemory;
} VirtualAllocDescriptor;
struct
{
FD3D12Texture* Texture;
alignas(alignof(TUniquePtr<FD3D12LockedResource>)) uint8 LockedResourceStorage[sizeof(TUniquePtr<FD3D12LockedResource>)];
uint32 Subresource;
} TextureStagingBufferData;
};
explicit FD3D12DeferredDeleteObject(FD3D12Resource* RHIObject)
: Type(EType::RHIObject)
, RHIObject(RHIObject)
{}
explicit FD3D12DeferredDeleteObject(FD3D12Heap* InHeap)
: Type(EType::Heap)
, Heap(InHeap)
{}
explicit FD3D12DeferredDeleteObject(FD3D12DescriptorHeap* InDescriptorHeap, EType Type)
: Type(Type)
, DescriptorHeap(InDescriptorHeap)
{
#if PLATFORM_SUPPORTS_BINDLESS_RENDERING
check(Type == EType::BindlessDescriptorHeap || Type == EType::DescriptorHeap);
#else
check(Type == EType::DescriptorHeap);
#endif
}
explicit FD3D12DeferredDeleteObject(ID3D12Object* D3DObject)
: Type(EType::D3DObject)
, D3DObject(D3DObject)
{}
#if PLATFORM_SUPPORTS_BINDLESS_RENDERING
explicit FD3D12DeferredDeleteObject(FRHIDescriptorHandle Handle, FD3D12Device* Device)
: Type(EType::BindlessDescriptor)
, BindlessDescriptor({ Handle, Device })
{}
#endif
explicit FD3D12DeferredDeleteObject(void* Ptr, EType Type)
: Type(Type)
, CPUAllocation(Ptr)
{
check(Type == EType::CPUAllocation);
}
explicit FD3D12DeferredDeleteObject(FD3D12OnlineDescriptorBlock* Block, FD3D12OnlineDescriptorManager* Manager)
: Type(EType::DescriptorBlock)
, DescriptorBlock({ Block, Manager })
{}
explicit FD3D12DeferredDeleteObject(FPlatformMemory::FPlatformVirtualMemoryBlock& VirtualBlock, ETextureCreateFlags Flags, uint64 CommittedTextureSize, void* RawMemory)
: Type(EType::VirtualAllocation)
, VirtualAllocDescriptor({ VirtualBlock, Flags, CommittedTextureSize, RawMemory })
{}
explicit FD3D12DeferredDeleteObject(TUniqueFunction<void()>&& Func)
: Type(EType::Func)
, Func(new TUniqueFunction<void()>(MoveTemp(Func)))
{}
explicit FD3D12DeferredDeleteObject(FD3D12Texture* InTexture, TUniquePtr<FD3D12LockedResource>&& InLockedResource, uint32 InSubresource)
: Type(EType::TextureStagingBuffer)
{
// Add a ref, in case texture gets destroyed while this deferred delete is in flight. We can't use TRefCountPtr in the union.
TextureStagingBufferData.Texture = InTexture;
InTexture->AddRef();
// We can't use TUniquePtr in the union, so do placement new.
TUniquePtr<FD3D12LockedResource>* LockedResource = new (TextureStagingBufferData.LockedResourceStorage) TUniquePtr<FD3D12LockedResource>();
*LockedResource = MoveTemp(InLockedResource);
TextureStagingBufferData.Subresource = InSubresource;
}
};
enum class ED3D12Units
{
Raw,
Microseconds
};
enum class ED3D12FlushFlags
{
None = 0,
// Block the calling thread until the submission thread has dispatched all work.
WaitForSubmission = 1,
// Both the calling thread until the GPU has signaled completion of all dispatched work.
WaitForCompletion = 2
};
ENUM_CLASS_FLAGS(ED3D12FlushFlags)
//
// Base class that manages the recording of FD3D12FinalizedCommands instances.
// Manages the logic for creating and recycling command lists and allocators.
//
class FD3D12ContextCommon
{
friend class FScopedResourceBarrier;
protected:
FD3D12ContextCommon(FD3D12Device* Device, ED3D12QueueType QueueType, bool bIsDefaultContext);
public:
virtual ~FD3D12ContextCommon() = default;
protected:
virtual void OpenCommandList();
virtual void CloseCommandList();
public:
enum class EClearStateMode
{
TransientOnly,
All
};
virtual void ClearState(EClearStateMode ClearStateMode = EClearStateMode::All) {}
virtual void ConditionalClearShaderResource(FD3D12ResourceLocation* Resource, EShaderParameterTypeMask ShaderParameterTypeMask) {}
// Inserts a command to signal the specified sync point
void SignalSyncPoint(FD3D12SyncPoint* SyncPoint);
// Inserts a command that blocks the GPU queue until the specified sync point is signaled.
void WaitSyncPoint(FD3D12SyncPoint* SyncPoint);
// Inserts a command that signals the specified D3D12 fence object.
void SignalManualFence(ID3D12Fence* Fence, uint64 Value);
// Inserts a command that waits the specified D3D12 fence object.
void WaitManualFence(ID3D12Fence* Fence, uint64 Value);
// Inserts a timestamp query command. "Target" specifies the optional
// location the result will be written to by the interrupt handler thread.
FD3D12QueryLocation InsertTimestamp(ED3D12Units Units, uint64* Target);
// Allocates a query of the specified type, returning its location.
FD3D12QueryLocation AllocateQuery(ED3D12QueryType Type, void* Target);
// Resizes physical memory allocation for a buffer. Allocates new backing heaps as necessary.
// Causes the command list to be split, as reserved resource update operations are performed on the D3D12 queue.
// The actual work is deferred via FD3D12Payload.
void SetReservedBufferCommitSize(FD3D12Buffer* Buffer, uint64 CommitSizeInBytes);
// Complete recording of the current command list set, and appends the resulting
// payloads to the given array. Resets the context so new commands can be recorded.
virtual void Finalize(TArray<FD3D12Payload*>& OutPayloads);
// The owner device of this context
FD3D12Device* const Device;
// The type of command lists this context records.
ED3D12QueueType const QueueType;
bool IsAsyncComputeContext() const { return QueueType == ED3D12QueueType::Async; }
// True for the immediate context (@todo remove this)
bool const bIsDefaultContext;
bool IsDefaultContext() const { return bIsDefaultContext; }
bool IsOpen() const { return CommandList != nullptr; }
bool IsPendingCommands() const { return IsOpen() || ResourceBarrierBatcher.Num(); }
FD3D12SyncPoint* GetContextSyncPoint()
{
if (!ContextSyncPoint)
{
ContextSyncPoint = FD3D12SyncPoint::Create(ED3D12SyncPointType::GPUAndCPU);
BatchedSyncPoints.ToSignal.Add(ContextSyncPoint);
}
return ContextSyncPoint;
}
// Sync points which are waited at the start / signaled at the end
// of the whole batch of command lists this context recorded.
struct
{
TArray<FD3D12SyncPointRef> ToWait;
TArray<FD3D12SyncPointRef> ToSignal;
} BatchedSyncPoints;
void BindDiagnosticBuffer(FD3D12RootSignature const* RootSignature, ED3D12PipelineType PipelineType);
private:
// Allocators to manage query heaps
FD3D12QueryAllocator TimestampQueries;
FD3D12QueryAllocator OcclusionQueries;
FD3D12QueryAllocator PipelineStatsQueries;
// Batches resource barriers together until it's explicitly flushed
FD3D12ResourceBarrierBatcher ResourceBarrierBatcher;
// The active D3D12 command list where recorded D3D commands are directed.
// This is swapped when command lists are split (e.g. when signalling a fence).
FD3D12CommandList* CommandList = nullptr;
// The command allocator used to open command lists within this context.
// The allocator is reused for each new command list until the context is finalized.
FD3D12CommandAllocator* CommandAllocator = nullptr;
// The array of recorded payloads the submission thread will process.
// These are returned when the context is finalized.
TArray<FD3D12Payload*> Payloads;
// A sync point signaled when all payloads in this context have completed.
FD3D12SyncPointRef ContextSyncPoint;
public:
void BeginRecursiveCommand()
{
// Nothing to do
}
protected:
// Returns the current command list (or creates a new one if the command list was not open).
FD3D12CommandList& GetCommandList()
{
OpenIfNotAlready();
return *CommandList;
}
enum class EMarkerType { In, Out };
void WriteMarker(D3D12_GPU_VIRTUAL_ADDRESS Address, uint32 Value, EMarkerType Type);
enum class EPhase
{
Wait,
UpdateReservedResources,
Execute,
Signal
} CurrentPhase = EPhase::Wait;
FD3D12Payload* GetPayload(EPhase Phase)
{
if (Payloads.Num() == 0 || Phase < CurrentPhase)
{
NewPayload();
}
CurrentPhase = Phase;
return Payloads.Last();
}
void NewPayload();
uint32 ActiveQueries = 0;
public:
// Open the command list if it's not already open.
void OpenIfNotAlready()
{
if (!CommandList)
{
OpenCommandList();
}
}
// Flushes any pending commands in this context to the GPU.
void FlushCommands(ED3D12FlushFlags FlushFlags = ED3D12FlushFlags::None);
// Closes the current command list if the number of enqueued commands exceeds
// the threshold defined by the "D3D12.MaxCommandsPerCommandList" cvar.
void ConditionalSplitCommandList();
auto BaseCommandList () { return GetCommandList().BaseCommandList(); }
auto CopyCommandList () { return GetCommandList().CopyCommandList(); }
auto GraphicsCommandList () { return GetCommandList().GraphicsCommandList(); }
#if D3D12_MAX_COMMANDLIST_INTERFACE >= 1
auto GraphicsCommandList1 () { return GetCommandList().GraphicsCommandList1(); }
#endif
#if D3D12_MAX_COMMANDLIST_INTERFACE >= 2
auto GraphicsCommandList2 () { return GetCommandList().GraphicsCommandList2(); }
#endif
#if D3D12_MAX_COMMANDLIST_INTERFACE >= 3
auto GraphicsCommandList3 () { return GetCommandList().GraphicsCommandList3(); }
#endif
#if D3D12_MAX_COMMANDLIST_INTERFACE >= 4
auto GraphicsCommandList4 () { return GetCommandList().GraphicsCommandList4(); }
#endif
#if D3D12_MAX_COMMANDLIST_INTERFACE >= 5
auto GraphicsCommandList5 () { return GetCommandList().GraphicsCommandList5(); }
#endif
#if D3D12_MAX_COMMANDLIST_INTERFACE >= 6
auto GraphicsCommandList6 () { return GetCommandList().GraphicsCommandList6(); }
#endif
#if D3D12_MAX_COMMANDLIST_INTERFACE >= 7
auto GraphicsCommandList7 () { return GetCommandList().GraphicsCommandList7(); }
#endif
#if D3D12_MAX_COMMANDLIST_INTERFACE >= 8
auto GraphicsCommandList8 () { return GetCommandList().GraphicsCommandList8(); }
#endif
#if D3D12_MAX_COMMANDLIST_INTERFACE >= 9
auto GraphicsCommandList9 () { return GetCommandList().GraphicsCommandList9(); }
#endif
#if D3D12_MAX_COMMANDLIST_INTERFACE >= 10
auto GraphicsCommandList10() { return GetCommandList().GraphicsCommandList10(); }
#endif
#if D3D12_SUPPORTS_DEBUG_COMMAND_LIST
auto DebugCommandList () { return GetCommandList().DebugCommandList(); }
#endif
#if D3D12_RHI_RAYTRACING
auto RayTracingCommandList() { return GetCommandList().RayTracingCommandList(); }
#endif
#if NV_AFTERMATH
auto AftermathHandle () { return GetCommandList().AftermathHandle(); }
#endif
void BeginQuery(FD3D12QueryLocation const& Location) { GetCommandList().BeginQuery(Location); }
void EndQuery (FD3D12QueryLocation const& Location) { GetCommandList().EndQuery (Location); }
#if ENABLE_RESIDENCY_MANAGEMENT
void UpdateResidency(const FD3D12Resource* Resource) { check(Resource); GetCommandList().UpdateResidency(Resource); }
#else
void UpdateResidency(const FD3D12Resource* Resource) { }
#endif
// Resource transition / barrier functions. These get batched and recorded into the command list when FlushResourceBarriers() is called.
void AddTransitionBarrier(FD3D12Resource* pResource, D3D12_RESOURCE_STATES Before, D3D12_RESOURCE_STATES After, uint32 Subresource);
void AddAliasingBarrier(ID3D12Resource* InResourceBefore, ID3D12Resource* InResourceAfter);
void AddUAVBarrier();
// Flushes the batched resource barriers to the current command list
void FlushResourceBarriers();
// Functions for transitioning a resource. The Before and After state cannot be D3D12_RESOURCE_STATE_TBD, needs be known at the time of the call
void TransitionResource(FD3D12Resource* Resource, D3D12_RESOURCE_STATES Before, D3D12_RESOURCE_STATES After, uint32 Subresource);
private:
void TransitionResource(FD3D12Resource* InResource, uint32 InSubresourceIndex, D3D12_RESOURCE_STATES InBeforeState, D3D12_RESOURCE_STATES InAfterState);
};
//
// Context for the copy queue. Doesn't implement an RHI interface
// since the copy queue is not directly exposed to the renderer.
//
class FD3D12ContextCopy final : public FD3D12ContextCommon
{
public:
FD3D12ContextCopy(FD3D12Device* Device)
: FD3D12ContextCommon(Device, ED3D12QueueType::Copy, false)
{}
};
//
// Helper for recording and submitting copy queue work.
// Used for buffer / texture data upload etc.
//
class FD3D12CopyScope final
{
private:
FD3D12Device* const Device;
FD3D12SyncPointRef SyncPoint;
#if DO_CHECK
mutable bool bSyncPointRetrieved = false;
#endif
public:
FD3D12ContextCopy& Context;
FD3D12SyncPoint* GetSyncPoint() const;
FD3D12CopyScope(FD3D12Device* Device, ED3D12SyncPointType SyncPointType, FD3D12SyncPointRef const& WaitSyncPoint = {});
~FD3D12CopyScope();
};
// Base class used to define commands that are not device specific, or that broadcast to all devices.
// @todo mgpu - try to remove this class
class FD3D12CommandContextBase : public IRHICommandContext, public FD3D12AdapterChild
{
public:
FD3D12CommandContextBase(FD3D12Adapter* InParent, FRHIGPUMask InGPUMask);
void RHIBeginDrawingViewport(FRHIViewport* Viewport, FRHITexture* RenderTargetRHI) final override;
void RHIEndDrawingViewport(FRHIViewport* Viewport, bool bPresent, bool bLockToVsync) final override;
FRHIGPUMask GetGPUMask() const { return GPUMask; }
FRHIGPUMask GetPhysicalGPUMask() const { return PhysicalGPUMask; }
virtual void RHISetAsyncComputeBudget(EAsyncComputeBudget Budget) {}
virtual class FD3D12CommandContextRedirector* AsRedirector() { return nullptr; }
static FD3D12CommandContextBase& Get(FRHICommandListBase& RHICmdList)
{
return static_cast<FD3D12CommandContextBase&>(RHICmdList.GetComputeContext().GetLowestLevelContext());
}
static FD3D12CommandContextBase* Get(IRHIComputeContext* RHIContext)
{
return RHIContext ? static_cast<FD3D12CommandContextBase*>(&RHIContext->GetLowestLevelContext()) : nullptr;
}
virtual FD3D12CommandContext* GetSingleDeviceContext(uint32 InGPUIndex) = 0;
protected:
friend class FD3D12CommandContext;
FRHIGPUMask GPUMask;
FRHIGPUMask PhysicalGPUMask;
};
// RHI Context type used for graphics and async compute command lists.
class FD3D12CommandContext : public FD3D12ContextCommon, public FD3D12CommandContextBase, public FD3D12DeviceChild
{
public:
FD3D12CommandContext(class FD3D12Device* InParent, ED3D12QueueType QueueType, bool InIsDefaultContext);
virtual ~FD3D12CommandContext();
static FD3D12CommandContext& Get(FRHICommandListBase& RHICmdList, uint32 GPUIndex)
{
FD3D12CommandContextBase& Base = FD3D12CommandContextBase::Get(RHICmdList);
#if WITH_MGPU
return *Base.GetSingleDeviceContext(GPUIndex);
#else
return static_cast<FD3D12CommandContext&>(Base);
#endif
}
virtual void OpenCommandList() override;
virtual void CloseCommandList() override final;
virtual ERHIPipeline GetPipeline() const override
{
return QueueType == ED3D12QueueType::Direct
? ERHIPipeline::Graphics
: ERHIPipeline::AsyncCompute;
}
virtual void ClearState(EClearStateMode ClearStateMode = EClearStateMode::All) override final;
virtual void ConditionalClearShaderResource(FD3D12ResourceLocation* Resource, EShaderParameterTypeMask ShaderParameterTypeMask) override final;
void ClearShaderResources(FD3D12UnorderedAccessView* UAV, EShaderParameterTypeMask ShaderParameterTypeMask);
void ClearShaderResources(FD3D12BaseShaderResource* Resource, EShaderParameterTypeMask ShaderParameterTypeMask);
void ClearAllShaderResources();
#if RHI_NEW_GPU_PROFILER
void FlushProfilerStats()
{
// Flush accumulated draw stats
if (StatEvent)
{
GetCommandList().EmplaceProfilerEvent<UE::RHI::GPUProfiler::FEvent::FStats>() = StatEvent;
StatEvent = {};
}
}
#endif
FD3D12FastConstantAllocator ConstantsAllocator;
// Current GPU event stack
TArray<uint32> GPUEventStack;
FD3D12StateCache StateCache;
/** Track the currently bound uniform buffers. */
FD3D12UniformBuffer* BoundUniformBuffers[SF_NumStandardFrequencies][MAX_CBS] = {};
/** Bit array to track which uniform buffers have changed since the last draw call. */
uint16 DirtyUniformBuffers[SF_NumStandardFrequencies] = {};
/** Handle for the dummy outer occlusion query we optionally insert for performance reasons */
FRenderQueryRHIRef OuterOcclusionQuery;
bool bOuterOcclusionQuerySubmitted = false;
/** When a new graphics PSO is set, we discard all old constants set for the previous shader. */
bool bDiscardSharedGraphicsConstants = false;
/** When a new compute PSO is set, we discard all old constants set for the previous shader. */
bool bDiscardSharedComputeConstants = false;
/** Used by variable rate shading to cache the current state of the combiners and the constant shading rate*/
#if PLATFORM_SUPPORTS_VARIABLE_RATE_SHADING
static_assert(D3D12_RS_SET_SHADING_RATE_COMBINER_COUNT == ED3D12VRSCombinerStages::Num);
D3D12_SHADING_RATE_COMBINER VRSCombiners[D3D12_RS_SET_SHADING_RATE_COMBINER_COUNT] = { D3D12_SHADING_RATE_COMBINER_PASSTHROUGH, D3D12_SHADING_RATE_COMBINER_PASSTHROUGH };
D3D12_SHADING_RATE VRSShadingRate = D3D12_SHADING_RATE_1X1;
#endif
static D3D12_RESOURCE_STATES SkipFastClearEliminateState;
D3D12_RESOURCE_STATES ValidResourceStates;
/** Constant buffers for Set*ShaderParameter calls. */
FD3D12ConstantBuffer StageConstantBuffers[SF_NumStandardFrequencies];
#if PLATFORM_SUPPORTS_VIRTUAL_TEXTURES
bool bNeedFlushTextureCache = false;
void InvalidateTextureCache() { bNeedFlushTextureCache = true; }
inline void FlushTextureCacheIfNeeded()
{
if (bNeedFlushTextureCache)
{
FlushTextureCache();
bNeedFlushTextureCache = false;
}
}
virtual void FlushTextureCache() {};
#endif
#if RHI_RAYTRACING
// Used to deduplicate work done by the shader table on this context.
Experimental::TRobinHoodHashSet<uint64> RayTracingShaderTables;
#endif
/** needs to be called before each draw call */
void CommitNonComputeShaderConstants();
/** needs to be called before each dispatch call */
void CommitComputeShaderConstants();
template <class ShaderType> void SetResourcesFromTables(const ShaderType* RESTRICT);
void SetSRVParameter(EShaderFrequency Frequency, uint32 SRVIndex, FD3D12ShaderResourceView* SRV);
void SetUAVParameter(EShaderFrequency Frequency, uint32 UAVIndex, FD3D12UnorderedAccessView* UAV);
void SetUAVParameter(EShaderFrequency Frequency, uint32 UAVIndex, FD3D12UnorderedAccessView* UAV, uint32 InitialCount);
void CommitGraphicsResourceTables();
void CommitComputeResourceTables();
template<typename TPixelShader>
void ResolveTextureUsingShader(
FD3D12Texture* SourceTexture,
FD3D12Texture* DestTexture,
FD3D12RenderTargetView* DestSurfaceRTV,
FD3D12DepthStencilView* DestSurfaceDSV,
const D3D12_RESOURCE_DESC& ResolveTargetDesc,
const FResolveRect& SourceRect,
const FResolveRect& DestRect,
typename TPixelShader::FParameter PixelShaderParameter
);
virtual void SetDepthBounds(float MinDepth, float MaxDepth);
virtual void SetShadingRate(EVRSShadingRate ShadingRate, FD3D12Resource* ShadingRateImage, const TStaticArray<EVRSRateCombiner, ED3D12VRSCombinerStages::Num>& Combiners);
virtual void SetAsyncComputeBudgetInternal(EAsyncComputeBudget Budget) {}
virtual void RHIBeginTransitions(TArrayView<const FRHITransition*> Transitions) final override;
virtual void RHIEndTransitions(TArrayView<const FRHITransition*> Transitions) final override;
// IRHIComputeContext interface
virtual void RHISetComputePipelineState(FRHIComputePipelineState* ComputePipelineState) final override;
virtual void RHIDispatchComputeShader(uint32 ThreadGroupCountX, uint32 ThreadGroupCountY, uint32 ThreadGroupCountZ) final override;
virtual void RHIDispatchIndirectComputeShader(FRHIBuffer* ArgumentBuffer, uint32 ArgumentOffset) final override;
virtual void RHISetStaticUniformBuffers(const FUniformBufferStaticBindings& InUniformBuffers) final override;
virtual void RHISetStaticUniformBuffer(FUniformBufferStaticSlot Slot, FRHIUniformBuffer* Buffer) final override;
virtual void RHISetShaderParameters(FRHIComputeShader* Shader, TConstArrayView<uint8> InParametersData, TConstArrayView<FRHIShaderParameter> InParameters, TConstArrayView<FRHIShaderParameterResource> InResourceParameters, TConstArrayView<FRHIShaderParameterResource> InBindlessParameters) final override;
virtual void RHISetShaderUnbinds(FRHIComputeShader* Shader, TConstArrayView<FRHIShaderParameterUnbind> InUnbinds) final override;
virtual void RHISetShaderUnbinds(FRHIGraphicsShader* Shader, TConstArrayView<FRHIShaderParameterUnbind> InUnbinds) final override;
#if WITH_RHI_BREADCRUMBS
virtual void RHIBeginBreadcrumbGPU(FRHIBreadcrumbNode* Breadcrumb) final override;
virtual void RHIEndBreadcrumbGPU (FRHIBreadcrumbNode* Breadcrumb) final override;
#endif
// IRHICommandContext interface
virtual void RHISetMultipleViewports(uint32 Count, const FViewportBounds* Data) final override;
virtual void RHIClearUAVFloat(FRHIUnorderedAccessView* UnorderedAccessViewRHI, const FVector4f& Values) final override;
virtual void RHIClearUAVUint(FRHIUnorderedAccessView* UnorderedAccessViewRHI, const FUintVector4& Values) final override;
virtual void RHICopyTexture(FRHITexture* SourceTexture, FRHITexture* DestTexture, const FRHICopyTextureInfo& CopyInfo) final override;
virtual void RHICopyBufferRegion(FRHIBuffer* DestBuffer, uint64 DstOffset, FRHIBuffer* SourceBuffer, uint64 SrcOffset, uint64 NumBytes) final override;
virtual void RHICopyToStagingBuffer(FRHIBuffer* SourceBuffer, FRHIStagingBuffer* DestinationStagingBuffer, uint32 Offset, uint32 NumBytes) final override;
virtual void RHIBeginRenderQuery(FRHIRenderQuery* RenderQuery) final override;
virtual void RHIEndRenderQuery(FRHIRenderQuery* RenderQuery) final override;
#if (RHI_NEW_GPU_PROFILER == 0)
virtual void RHICalibrateTimers(FRHITimestampCalibrationQuery* CalibrationQuery) final override;
#endif
virtual void RHISetStreamSource(uint32 StreamIndex, FRHIBuffer* VertexBuffer, uint32 Offset) final override;
virtual void RHISetViewport(float MinX, float MinY, float MinZ, float MaxX, float MaxY, float MaxZ) final override;
virtual void RHISetStereoViewport(float LeftMinX, float RightMinX, float LeftMinY, float RightMinY, float MinZ, float LeftMaxX, float RightMaxX, float LeftMaxY, float RightMaxY, float MaxZ) override;
virtual void RHISetScissorRect(bool bEnable, uint32 MinX, uint32 MinY, uint32 MaxX, uint32 MaxY) final override;
virtual void RHISetGraphicsPipelineState(FRHIGraphicsPipelineState* GraphicsPipelineState, uint32 StencilRef, bool bApplyAdditionalState) final override;
virtual void RHISetShaderParameters(FRHIGraphicsShader* Shader, TConstArrayView<uint8> InParametersData, TConstArrayView<FRHIShaderParameter> InParameters, TConstArrayView<FRHIShaderParameterResource> InResourceParameters, TConstArrayView<FRHIShaderParameterResource> InBindlessParameters) final override;
virtual void RHISetStencilRef(uint32 StencilRef) final override;
virtual void RHISetBlendFactor(const FLinearColor& BlendFactor) final override;
void SetRenderTargets(uint32 NumSimultaneousRenderTargets, const FRHIRenderTargetView* NewRenderTargets, const FRHIDepthRenderTargetView* NewDepthStencilTarget);
void SetRenderTargetsAndClear(const FRHISetRenderTargetsInfo& RenderTargetsInfo);
virtual void RHISetShaderRootConstants(
const FUint32Vector4& Constants) override;
virtual void RHIDispatchComputeShaderBundle(
FRHIShaderBundle* ShaderBundle,
FRHIBuffer* RecordArgBuffer,
TConstArrayView<FRHIShaderParameterResource> SharedBindlessParameters,
TConstArrayView<FRHIShaderBundleComputeDispatch> Dispatches,
bool bEmulated) override;
virtual void RHIDispatchGraphicsShaderBundle(
FRHIShaderBundle* ShaderBundle,
FRHIBuffer* RecordArgBuffer,
const FRHIShaderBundleGraphicsState& BundleState,
TConstArrayView<FRHIShaderParameterResource> SharedBindlessParameters,
TConstArrayView<FRHIShaderBundleGraphicsDispatch> Dispatches,
bool bEmulated) override;
virtual void RHIDrawPrimitive(uint32 BaseVertexIndex, uint32 NumPrimitives, uint32 NumInstances) final override;
virtual void RHIDrawPrimitiveIndirect(FRHIBuffer* ArgumentBuffer, uint32 ArgumentOffset) final override;
virtual void RHIDrawIndexedIndirect(FRHIBuffer* IndexBufferRHI, FRHIBuffer* ArgumentsBufferRHI, int32 DrawArgumentsIndex, uint32 NumInstances) final override;
virtual void RHIDrawIndexedPrimitive(FRHIBuffer* IndexBuffer, int32 BaseVertexIndex, uint32 FirstInstance, uint32 NumVertices, uint32 StartIndex, uint32 NumPrimitives, uint32 NumInstances) final override;
virtual void RHIDrawIndexedPrimitiveIndirect(FRHIBuffer* IndexBuffer, FRHIBuffer* ArgumentBuffer, uint32 ArgumentOffset) final override;
virtual void RHIMultiDrawIndexedPrimitiveIndirect(FRHIBuffer* IndexBuffer, FRHIBuffer* ArgumentBuffer, uint32 ArgumentOffset, FRHIBuffer* CountBuffer, uint32 CountBufferOffset, uint32 MaxDrawArguments) final override;
#if PLATFORM_SUPPORTS_MESH_SHADERS
virtual void RHIDispatchMeshShader(uint32 ThreadGroupCountX, uint32 ThreadGroupCountY, uint32 ThreadGroupCountZ) final override;
virtual void RHIDispatchIndirectMeshShader(FRHIBuffer* ArgumentBuffer, uint32 ArgumentOffset) final override;
#endif
virtual void RHISetDepthBounds(float MinDepth, float MaxDepth) final override;
virtual void RHISetShadingRate(EVRSShadingRate ShadingRate, EVRSRateCombiner Combiner) final override;
virtual void RHIClearMRTImpl(bool* bClearColorArray, int32 NumClearColors, const FLinearColor* ColorArray, bool bClearDepth, float Depth, bool bClearStencil, uint32 Stencil);
virtual void RHIBeginRenderPass(const FRHIRenderPassInfo& InInfo, const TCHAR* InName)
{
FRHISetRenderTargetsInfo RTInfo;
InInfo.ConvertToRenderTargetsInfo(RTInfo);
SetRenderTargetsAndClear(RTInfo);
RenderPassInfo = InInfo;
}
virtual void RHIEndRenderPass()
{
UE::RHICore::ResolveRenderPassTargets(RenderPassInfo, [this](UE::RHICore::FResolveTextureInfo Info)
{
ResolveTexture(Info);
});
}
void ResolveTexture(UE::RHICore::FResolveTextureInfo Info);
#if D3D12_RHI_RAYTRACING
virtual void RHIBindAccelerationStructureMemory(FRHIRayTracingScene* Scene, FRHIBuffer* Buffer, uint32 BufferOffset) final override;
virtual void BuildAccelerationStructuresInternal(TConstArrayView<D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC> BuildDesc);
#if WITH_MGPU
// Should be called before RHIBuildAccelerationStructures when multiple GPU support is present (for example, from FD3D12CommandContextRedirector::RHIBuildAccelerationStructures)
static void UnregisterAccelerationStructuresInternalMGPU(TConstArrayView<FRayTracingGeometryBuildParams> Params, FRHIGPUMask GPUMask);
#endif
virtual void RHIBuildAccelerationStructures(TConstArrayView<FRayTracingGeometryBuildParams> Params, const FRHIBufferRange& ScratchBufferRange) final override;
virtual void RHIBuildAccelerationStructures(TConstArrayView<FRayTracingSceneBuildParams> Params) final override;
virtual void RHIClearShaderBindingTable(FRHIShaderBindingTable* SBT) final override;
virtual void RHICommitShaderBindingTable(FRHIShaderBindingTable* SBT, FRHIBuffer* InlineBindingDataBuffer) final override;
virtual void RHIRayTraceDispatch(FRHIRayTracingPipelineState* RayTracingPipelineState, FRHIRayTracingShader* RayGenShader,
FRHIShaderBindingTable* InSBT, const FRayTracingShaderBindings& GlobalResourceBindings,
uint32 Width, uint32 Height) final override;
virtual void RHIRayTraceDispatchIndirect(FRHIRayTracingPipelineState* RayTracingPipelineState, FRHIRayTracingShader* RayGenShader,
FRHIShaderBindingTable* InSBT, const FRayTracingShaderBindings& GlobalResourceBindings,
FRHIBuffer* ArgumentBuffer, uint32 ArgumentOffset) final override;
virtual void RHISetBindingsOnShaderBindingTable(
FRHIShaderBindingTable* InSBT, FRHIRayTracingPipelineState* Pipeline,
uint32 NumBindings, const FRayTracingLocalShaderBindings* Bindings, ERayTracingBindingType BindingType) final override;
#endif // D3D12_RHI_RAYTRACING
template<typename TRHIType, typename TReturnType = typename TD3D12ResourceTraits<TRHIType>::TConcreteType>
static FORCEINLINE TReturnType* ResourceCast(TRHIType* Resource)
{
return static_cast<TReturnType*>(Resource);
}
template<typename TRHIType, typename TReturnType = typename TD3D12ResourceTraits<TRHIType>::TConcreteType>
static FORCEINLINE_DEBUGGABLE TReturnType* ResourceCast(TRHIType* Resource, uint32 GPUIndex)
{
TReturnType* Object = ResourceCast<TRHIType, TReturnType>(Resource);
return Object ? static_cast<TReturnType*>(Object->GetLinkedObject(GPUIndex)) : nullptr;
}
template<typename ObjectType, typename RHIType>
static FORCEINLINE_DEBUGGABLE ObjectType* RetrieveObject(RHIType* RHIObject, uint32 GPUIndex)
{
return ResourceCast<RHIType, ObjectType>(RHIObject, GPUIndex);
}
template<typename ObjectType, typename RHIType>
FORCEINLINE_DEBUGGABLE ObjectType* RetrieveObject(RHIType* RHIObject)
{
return RetrieveObject<ObjectType, RHIType>(RHIObject, GetGPUIndex());
}
static inline FD3D12Texture* RetrieveTexture(FRHITexture* Texture, uint32 GPUIndex)
{
FD3D12Texture* RHITexture = GetD3D12TextureFromRHITexture(Texture);
return RHITexture ? RHITexture->GetLinkedObject(GPUIndex) : nullptr;
}
FORCEINLINE_DEBUGGABLE FD3D12Texture* RetrieveTexture(FRHITexture* Texture)
{
return RetrieveTexture(Texture, GetGPUIndex());
}
uint32 GetFrameFenceCounter() const;
uint32 GetGPUIndex() const { return GPUMask.ToIndex(); }
virtual void RHISetGPUMask(FRHIGPUMask InGPUMask) final override
{
// This is a single-GPU context so it doesn't make sense to ever change its GPU
// mask. If multiple GPUs are supported we should be using the redirector context.
ensure(InGPUMask == GPUMask);
}
inline const TArray<FRHIUniformBuffer*>& GetStaticUniformBuffers() const
{
return StaticUniformBuffers;
}
void FlushPendingDescriptorUpdates();
void SetExplicitDescriptorCache(FD3D12ExplicitDescriptorCache& ExplicitDescriptorCache);
void UnsetExplicitDescriptorCache();
virtual void Finalize(TArray<FD3D12Payload*>& OutPayloads) override;
#if PLATFORM_SUPPORTS_BINDLESS_RENDERING
FD3D12DescriptorHeap* GetBindlessResourcesHeap();
FD3D12ContextBindlessState& GetBindlessState() { return BindlessState; }
#endif
const FRHIShaderBindingLayout& GetShaderBindingLayout() const
{
static const FRHIShaderBindingLayout Default;
return ShaderBindinglayout ? *ShaderBindinglayout : Default;
}
FORCENOINLINE void CopyBufferRegionChecked(
ID3D12Resource* DestResource, const FName& DestName, uint64 DestOffset,
ID3D12Resource* SourceResource, const FName& SourceName, uint64 SourceOffset,
uint32 ByteCount
);
FORCENOINLINE void CopyTextureRegionChecked(
const D3D12_TEXTURE_COPY_LOCATION* DestCopyLocation, int DestX, int DestY, int DestZ, EPixelFormat DestPixelFormat,
const D3D12_TEXTURE_COPY_LOCATION* SourceCopyLocation, const D3D12_BOX* SourceBox, EPixelFormat SourcePixelFormat,
const FName& DebugName
);
protected:
FD3D12CommandContext* GetSingleDeviceContext(uint32 InGPUIndex) final override
{
return InGPUIndex == GetGPUIndex() ? this : nullptr;
}
private:
void SetupDispatch(uint32 ThreadGroupCountX, uint32 ThreadGroupCountY, uint32 ThreadGroupCountZ);
void SetupDraw(FRHIBuffer* IndexBufferRHI, uint32 NumPrimitives = 0, uint32 NumVertices = 0);
void SetupDispatchDraw(uint32 ThreadGroupCountX, uint32 ThreadGroupCountY, uint32 ThreadGroupCountZ);
FD3D12ResourceLocation& SetupIndirectArgument(FRHIBuffer* ArgumentBufferRHI, D3D12_RESOURCE_STATES ExtraStates = static_cast<D3D12_RESOURCE_STATES>(0));
void PostGpuEvent();
static void ClearUAV(TRHICommandList_RecursiveHazardous<FD3D12CommandContext>& RHICmdList, FD3D12UnorderedAccessView_RHI* UAV, const void* ClearValues, bool bFloat);
void DispatchWorkGraphShaderBundle(FRHIShaderBundle* ShaderBundle, FRHIBuffer* RecordArgBuffer, TConstArrayView<FRHIShaderParameterResource> SharedBindlessParameters, TConstArrayView<FRHIShaderBundleComputeDispatch> Dispatches);
void DispatchWorkGraphShaderBundle(FRHIShaderBundle* ShaderBundle, FRHIBuffer* RecordArgBuffer, const FRHIShaderBundleGraphicsState& BundleState, TConstArrayView<FRHIShaderParameterResource> SharedBindlessParameters, TConstArrayView<FRHIShaderBundleGraphicsDispatch> Dispatches);
void HandleDiscardResources (TArrayView<const FRHITransition*> Transitions, bool bIsBeginTransition);
void HandleResourceTransitions (const struct FD3D12TransitionData* TransitionData, bool& bUAVBarrier);
void HandleTransientAliasing (const struct FD3D12TransitionData* TransitionData);
void HandleResourceDiscardTransitions(const struct FD3D12TransitionData* TransitionData, TArray<struct FD3D12DiscardResource>& ResourcesToDiscard);
void HandleReservedResourceCommits (const struct FD3D12TransitionData* TransitionData);
TArray<FRHIUniformBuffer*> StaticUniformBuffers;
const FRHIShaderBindingLayout* ShaderBindinglayout = nullptr;
#if PLATFORM_SUPPORTS_BINDLESS_RENDERING
FD3D12ContextBindlessState BindlessState;
#endif
};
// Version of command context to handle multi-GPU. Because IRHICommandContext is pure virtual we can return the normal
// FD3D12CommandContext when not using mGPU, thus there is no additional overhead for the common case i.e. 1 GPU.
class FD3D12CommandContextRedirector final : public FD3D12CommandContextBase
{
public:
// The type of command lists this context records.
ED3D12QueueType const QueueType;
bool const bIsDefaultContext;
FD3D12CommandContextRedirector(class FD3D12Adapter* InParent, ED3D12QueueType QueueType, bool InIsDefaultContext);
virtual FD3D12CommandContextRedirector* AsRedirector() override { return this; }
#define ContextRedirect(Call) { for (uint32 GPUIndex : GPUMask) PhysicalContexts[GPUIndex]-> Call; }
#define ContextGPU0(Call) { PhysicalContexts[0]-> Call; }
FORCEINLINE virtual void RHISetComputePipelineState(FRHIComputePipelineState* ComputePipelineState) final override
{
ContextRedirect(RHISetComputePipelineState(ComputePipelineState));
}
FORCEINLINE virtual void RHIDispatchComputeShader(uint32 ThreadGroupCountX, uint32 ThreadGroupCountY, uint32 ThreadGroupCountZ) final override
{
ContextRedirect(RHIDispatchComputeShader(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ));
}
FORCEINLINE virtual void RHIDispatchIndirectComputeShader(FRHIBuffer* ArgumentBuffer, uint32 ArgumentOffset) final override
{
ContextRedirect(RHIDispatchIndirectComputeShader(ArgumentBuffer, ArgumentOffset));
}
FORCEINLINE virtual void RHIBeginTransitions(TArrayView<const FRHITransition*> Transitions) final override
{
ContextRedirect(RHIBeginTransitions(Transitions));
}
FORCEINLINE virtual void RHIEndTransitions(TArrayView<const FRHITransition*> Transitions) final override
{
ContextRedirect(RHIEndTransitions(Transitions));
}
#if WITH_MGPU
virtual void RHITransferResources(TConstArrayView<FTransferResourceParams> Params) final override;
virtual void RHITransferResourceSignal(TConstArrayView<FTransferResourceFenceData*> FenceDatas, FRHIGPUMask SrcGPUMask) final override;
virtual void RHITransferResourceWait(TConstArrayView<FTransferResourceFenceData*> FenceDatas) final override;
// New and improved cross GPU transfer API
virtual void RHICrossGPUTransfer(TConstArrayView<FTransferResourceParams> Params, TConstArrayView<FCrossGPUTransferFence*> PreTransfer, TConstArrayView<FCrossGPUTransferFence*> PostTransfer) final override;
virtual void RHICrossGPUTransferSignal(TConstArrayView<FTransferResourceParams> Params, TConstArrayView<FCrossGPUTransferFence*> PreTransfer) final override;
virtual void RHICrossGPUTransferWait(TConstArrayView<FCrossGPUTransferFence*> PostTransfer) final override;
#endif // WITH_MGPU
FORCEINLINE virtual void RHICopyToStagingBuffer(FRHIBuffer* SourceBuffer, FRHIStagingBuffer* DestinationStagingBuffer, uint32 Offset, uint32 NumBytes) final override
{
ContextRedirect(RHICopyToStagingBuffer(SourceBuffer, DestinationStagingBuffer, Offset, NumBytes));
}
FORCEINLINE virtual void RHISetShaderParameters(FRHIComputeShader* Shader, TConstArrayView<uint8> InParametersData, TConstArrayView<FRHIShaderParameter> InParameters, TConstArrayView<FRHIShaderParameterResource> InResourceParameters, TConstArrayView<FRHIShaderParameterResource> InBindlessParameters) final override
{
ContextRedirect(RHISetShaderParameters(Shader, InParametersData, InParameters, InResourceParameters, InBindlessParameters));
}
FORCEINLINE virtual void RHISetShaderUnbinds(FRHIComputeShader* Shader, TConstArrayView<FRHIShaderParameterUnbind> InUnbinds) final override
{
ContextRedirect(RHISetShaderUnbinds(Shader, InUnbinds));
}
#if WITH_RHI_BREADCRUMBS
FORCEINLINE virtual void RHIBeginBreadcrumbGPU(FRHIBreadcrumbNode* Breadcrumb) final override
{
// Always forward to all sub-contexts, regardless of mask
for (uint32 GPUIndex : PhysicalGPUMask)
{
PhysicalContexts[GPUIndex]->RHIBeginBreadcrumbGPU(Breadcrumb);
}
}
FORCEINLINE virtual void RHIEndBreadcrumbGPU(FRHIBreadcrumbNode* Breadcrumb) final override
{
// Always forward to all sub-contexts, regardless of mask
for (uint32 GPUIndex : PhysicalGPUMask)
{
PhysicalContexts[GPUIndex]->RHIEndBreadcrumbGPU(Breadcrumb);
}
}
#endif // WITH_RHI_BREADCRUMBS
// IRHICommandContext interface
FORCEINLINE virtual void RHISetMultipleViewports(uint32 Count, const FViewportBounds* Data) final override
{
ContextRedirect(RHISetMultipleViewports(Count, Data));
}
FORCEINLINE virtual void RHIClearUAVFloat(FRHIUnorderedAccessView* UnorderedAccessViewRHI, const FVector4f& Values) final override
{
ContextRedirect(RHIClearUAVFloat(UnorderedAccessViewRHI, Values));
}
FORCEINLINE virtual void RHIClearUAVUint(FRHIUnorderedAccessView* UnorderedAccessViewRHI, const FUintVector4& Values) final override
{
ContextRedirect(RHIClearUAVUint(UnorderedAccessViewRHI, Values));
}
FORCEINLINE virtual void RHICopyTexture(FRHITexture* SourceTextureRHI, FRHITexture* DestTextureRHI, const FRHICopyTextureInfo& CopyInfo) final override
{
ContextRedirect(RHICopyTexture(SourceTextureRHI, DestTextureRHI, CopyInfo));
}
FORCEINLINE virtual void RHICopyBufferRegion(FRHIBuffer* DestBuffer, uint64 DstOffset, FRHIBuffer* SourceBuffer, uint64 SrcOffset, uint64 NumBytes) final override
{
ContextRedirect(RHICopyBufferRegion(DestBuffer, DstOffset, SourceBuffer, SrcOffset, NumBytes));
}
FORCEINLINE virtual void RHIBeginRenderQuery(FRHIRenderQuery* RenderQuery) final override
{
ContextRedirect(RHIBeginRenderQuery(RenderQuery));
}
FORCEINLINE virtual void RHIEndRenderQuery(FRHIRenderQuery* RenderQuery) final override
{
ContextRedirect(RHIEndRenderQuery(RenderQuery));
}
#if (RHI_NEW_GPU_PROFILER == 0)
FORCEINLINE virtual void RHICalibrateTimers(FRHITimestampCalibrationQuery* CalibrationQuery) final override
{
ContextRedirect(RHICalibrateTimers(CalibrationQuery));
}
#endif
FORCEINLINE virtual void RHISetStreamSource(uint32 StreamIndex, FRHIBuffer* VertexBuffer, uint32 Offset) final override
{
ContextRedirect(RHISetStreamSource(StreamIndex, VertexBuffer, Offset));
}
FORCEINLINE virtual void RHISetViewport(float MinX, float MinY, float MinZ, float MaxX, float MaxY, float MaxZ) final override
{
ContextRedirect(RHISetViewport(MinX, MinY, MinZ, MaxX, MaxY, MaxZ));
}
FORCEINLINE virtual void RHISetStereoViewport(float LeftMinX, float RightMinX, float LeftMinY, float RightMinY, float MinZ, float LeftMaxX, float RightMaxX, float LeftMaxY, float RightMaxY, float MaxZ) override
{
ContextRedirect(RHISetStereoViewport(LeftMinX, RightMinX, LeftMinY, RightMinY, MinZ, LeftMaxX, RightMaxX, LeftMaxY, RightMaxY, MaxZ));
}
FORCEINLINE virtual void RHISetScissorRect(bool bEnable, uint32 MinX, uint32 MinY, uint32 MaxX, uint32 MaxY) final override
{
ContextRedirect(RHISetScissorRect(bEnable, MinX, MinY, MaxX, MaxY));
}
FORCEINLINE virtual void RHISetGraphicsPipelineState(FRHIGraphicsPipelineState* GraphicsPipelineState, uint32 StencilRef, bool bApplyAdditionalState) final override
{
ContextRedirect(RHISetGraphicsPipelineState(GraphicsPipelineState, StencilRef, bApplyAdditionalState));
}
FORCEINLINE virtual void RHISetStaticUniformBuffers(const FUniformBufferStaticBindings& InUniformBuffers) final override
{
ContextRedirect(RHISetStaticUniformBuffers(InUniformBuffers));
}
FORCEINLINE virtual void RHISetStaticUniformBuffer(FUniformBufferStaticSlot Slot, FRHIUniformBuffer* Buffer) final override
{
ContextRedirect(RHISetStaticUniformBuffer(Slot, Buffer));
}
FORCEINLINE virtual void RHISetShaderParameters(FRHIGraphicsShader* Shader, TConstArrayView<uint8> InParametersData, TConstArrayView<FRHIShaderParameter> InParameters, TConstArrayView<FRHIShaderParameterResource> InResourceParameters, TConstArrayView<FRHIShaderParameterResource> InBindlessParameters) final override
{
ContextRedirect(RHISetShaderParameters(Shader, InParametersData, InParameters, InResourceParameters, InBindlessParameters));
}
FORCEINLINE virtual void RHISetShaderUnbinds(FRHIGraphicsShader* Shader, TConstArrayView<FRHIShaderParameterUnbind> InUnbinds) final override
{
ContextRedirect(RHISetShaderUnbinds(Shader, InUnbinds));
}
FORCEINLINE virtual void RHISetStencilRef(uint32 StencilRef) final override
{
ContextRedirect(RHISetStencilRef(StencilRef));
}
FORCEINLINE void RHISetBlendFactor(const FLinearColor& BlendFactor) final override
{
ContextRedirect(RHISetBlendFactor(BlendFactor));
}
FORCEINLINE void RHISetShaderRootConstants(const FUint32Vector4& Constants) final override
{
ContextRedirect(RHISetShaderRootConstants(Constants));
}
FORCEINLINE virtual void RHIDrawPrimitive(uint32 BaseVertexIndex, uint32 NumPrimitives, uint32 NumInstances) final override
{
ContextRedirect(RHIDrawPrimitive(BaseVertexIndex, NumPrimitives, NumInstances));
}
FORCEINLINE virtual void RHIDrawPrimitiveIndirect(FRHIBuffer* ArgumentBuffer, uint32 ArgumentOffset) final override
{
ContextRedirect(RHIDrawPrimitiveIndirect(ArgumentBuffer, ArgumentOffset));
}
FORCEINLINE virtual void RHIDrawIndexedIndirect(FRHIBuffer* IndexBufferRHI, FRHIBuffer* ArgumentsBufferRHI, int32 DrawArgumentsIndex, uint32 NumInstances) final override
{
ContextRedirect(RHIDrawIndexedIndirect(IndexBufferRHI, ArgumentsBufferRHI, DrawArgumentsIndex, NumInstances));
}
FORCEINLINE virtual void RHIDrawIndexedPrimitive(FRHIBuffer* IndexBuffer, int32 BaseVertexIndex, uint32 FirstInstance, uint32 NumVertices, uint32 StartIndex, uint32 NumPrimitives, uint32 NumInstances) final override
{
ContextRedirect(RHIDrawIndexedPrimitive(IndexBuffer, BaseVertexIndex, FirstInstance, NumVertices, StartIndex, NumPrimitives, NumInstances));
}
FORCEINLINE virtual void RHIDrawIndexedPrimitiveIndirect(FRHIBuffer* IndexBuffer, FRHIBuffer* ArgumentBuffer, uint32 ArgumentOffset) final override
{
ContextRedirect(RHIDrawIndexedPrimitiveIndirect(IndexBuffer, ArgumentBuffer, ArgumentOffset));
}
FORCEINLINE virtual void RHIMultiDrawIndexedPrimitiveIndirect(FRHIBuffer* IndexBuffer, FRHIBuffer* ArgumentBuffer, uint32 ArgumentOffset, FRHIBuffer* CountBuffer, uint32 CountBufferOffset, uint32 MaxDrawArguments) final override
{
ContextRedirect(RHIMultiDrawIndexedPrimitiveIndirect(IndexBuffer, ArgumentBuffer, ArgumentOffset, CountBuffer, CountBufferOffset, MaxDrawArguments));
}
#if PLATFORM_SUPPORTS_MESH_SHADERS
FORCEINLINE virtual void RHIDispatchMeshShader(uint32 ThreadGroupCountX, uint32 ThreadGroupCountY, uint32 ThreadGroupCountZ) final override
{
ContextRedirect(RHIDispatchMeshShader(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ));
}
FORCEINLINE virtual void RHIDispatchIndirectMeshShader(FRHIBuffer* ArgumentBuffer, uint32 ArgumentOffset) final override
{
ContextRedirect(RHIDispatchIndirectMeshShader(ArgumentBuffer, ArgumentOffset));
}
#endif
FORCEINLINE virtual void RHISetDepthBounds(float MinDepth, float MaxDepth) final override
{
ContextRedirect(RHISetDepthBounds(MinDepth, MaxDepth));
}
FORCEINLINE virtual void RHISetShadingRate(EVRSShadingRate ShadingRate, EVRSRateCombiner Combiner) final override
{
ContextRedirect(RHISetShadingRate(ShadingRate, Combiner));
}
virtual void RHIBeginRenderPass(const FRHIRenderPassInfo& InInfo, const TCHAR* InName) final override
{
ContextRedirect(RHIBeginRenderPass(InInfo, InName));
}
virtual void RHIEndRenderPass() final override
{
ContextRedirect(RHIEndRenderPass());
}
#if D3D12_RHI_RAYTRACING
virtual void RHIBuildAccelerationStructures(TConstArrayView<FRayTracingGeometryBuildParams> Params, const FRHIBufferRange& ScratchBufferRange) final override
{
#if WITH_MGPU
FD3D12CommandContext::UnregisterAccelerationStructuresInternalMGPU(Params, GPUMask);
#endif
ContextRedirect(RHIBuildAccelerationStructures(Params, ScratchBufferRange));
}
virtual void RHIBuildAccelerationStructures(TConstArrayView<FRayTracingSceneBuildParams> Params) final override
{
ContextRedirect(RHIBuildAccelerationStructures(Params));
}
virtual void RHIRayTraceDispatch(FRHIRayTracingPipelineState* RayTracingPipelineState, FRHIRayTracingShader* RayGenShader,
FRHIShaderBindingTable* SBT, const FRayTracingShaderBindings& GlobalResourceBindings,
uint32 Width, uint32 Height) final override
{
ContextRedirect(RHIRayTraceDispatch(RayTracingPipelineState, RayGenShader, SBT, GlobalResourceBindings, Width, Height));
}
virtual void RHIRayTraceDispatchIndirect(FRHIRayTracingPipelineState* RayTracingPipelineState, FRHIRayTracingShader* RayGenShader,
FRHIShaderBindingTable* SBT, const FRayTracingShaderBindings& GlobalResourceBindings,
FRHIBuffer* ArgumentBuffer, uint32 ArgumentOffset) final override
{
ContextRedirect(RHIRayTraceDispatchIndirect(RayTracingPipelineState, RayGenShader, SBT, GlobalResourceBindings, ArgumentBuffer, ArgumentOffset));
}
virtual void RHISetBindingsOnShaderBindingTable(FRHIShaderBindingTable* SBT, FRHIRayTracingPipelineState* Pipeline, uint32 NumBindings, const FRayTracingLocalShaderBindings* Bindings, ERayTracingBindingType BindingType) final override
{
ContextRedirect(RHISetBindingsOnShaderBindingTable(SBT, Pipeline, NumBindings, Bindings, BindingType));
}
virtual void RHIClearShaderBindingTable(FRHIShaderBindingTable* SBT) final override
{
ContextRedirect(RHIClearShaderBindingTable(SBT));
}
virtual void RHIBindAccelerationStructureMemory(FRHIRayTracingScene* Scene, FRHIBuffer* Buffer, uint32 BufferOffset) final override
{
ContextRedirect(RHIBindAccelerationStructureMemory(Scene, Buffer, BufferOffset));
}
virtual void RHICommitShaderBindingTable(FRHIShaderBindingTable* SBT, FRHIBuffer* InlineBindingDataBuffer) final override
{
ContextRedirect(RHICommitShaderBindingTable(SBT, InlineBindingDataBuffer));
}
#endif // D3D12_RHI_RAYTRACING
virtual void RHISetGPUMask(FRHIGPUMask InGPUMask) final override
{
GPUMask = InGPUMask;
check(PhysicalGPUMask.ContainsAll(GPUMask));
}
virtual FRHIGPUMask RHIGetGPUMask() const final override
{
return GPUMask;
}
// Sets the mask of which GPUs can be supported, as opposed to the currently active
// set. RHISetGPUMask checks that the active mask is a subset of the physical mask.
FORCEINLINE void SetPhysicalGPUMask(FRHIGPUMask InGPUMask)
{
PhysicalGPUMask = InGPUMask;
}
FORCEINLINE void SetPhysicalContext(FD3D12CommandContext* Context)
{
check(Context);
const uint32 GPUIndex = Context->GetGPUIndex();
check(PhysicalGPUMask.Contains(GPUIndex));
PhysicalContexts[GPUIndex] = Context;
}
FORCEINLINE FD3D12CommandContext* GetSingleDeviceContext(uint32 GPUIndex) final override
{
return PhysicalContexts[GPUIndex];
}
virtual void SetExecutingCommandList(FRHICommandListBase* InCmdList) final override
{
FD3D12CommandContextBase::SetExecutingCommandList(InCmdList);
for (uint32 Index : PhysicalGPUMask)
{
PhysicalContexts[Index]->SetExecutingCommandList(InCmdList);
}
}
private:
TStaticArray<FD3D12CommandContext*, MAX_NUM_GPUS> PhysicalContexts;
};
struct FD3D12TransitionData
{
ERHIPipeline SrcPipelines, DstPipelines;
ERHITransitionCreateFlags CreateFlags = ERHITransitionCreateFlags::None;
TArray<FRHITransitionInfo, TInlineAllocator<4, FConcurrentLinearArrayAllocator>> TransitionInfos;
TArray<FRHITransientAliasingInfo, TInlineAllocator<4, FConcurrentLinearArrayAllocator>> AliasingInfos;
TArray<FRHITransientAliasingOverlap, TInlineAllocator<4, FConcurrentLinearArrayAllocator>> AliasingOverlaps;
TArray<TRHIPipelineArray<FD3D12SyncPointRef>, TInlineAllocator<MAX_NUM_GPUS>> SyncPoints;
bool bCrossPipeline = false;
bool bAsyncToAllPipelines = false;
};
class FD3D12ContextArray : public TRHIPipelineArray<FD3D12CommandContextBase*>
{
public:
FD3D12ContextArray(FRHIContextArray const& Contexts)
{
for (int32 Index = 0; Index < int32(ERHIPipeline::Num); ++Index)
{
(*this)[Index] = FD3D12CommandContextBase::Get(Contexts[Index]);
}
}
operator FRHIContextArray() const
{
FRHIContextArray Result;
for (int32 Index = 0; Index < int32(ERHIPipeline::Num); ++Index)
{
FD3D12CommandContextBase* Base = (*this)[Index];
Result[Index] = Base ? &Base->GetHighestLevelContext() : nullptr;
}
return Result;
}
};