// 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 #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* 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)) uint8 LockedResourceStorage[sizeof(TUniquePtr)]; 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&& Func) : Type(EType::Func) , Func(new TUniqueFunction(MoveTemp(Func))) {} explicit FD3D12DeferredDeleteObject(FD3D12Texture* InTexture, TUniquePtr&& 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* LockedResource = new (TextureStagingBufferData.LockedResourceStorage) TUniquePtr(); *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& 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 ToWait; TArray 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 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(RHICmdList.GetComputeContext().GetLowestLevelContext()); } static FD3D12CommandContextBase* Get(IRHIComputeContext* RHIContext) { return RHIContext ? static_cast(&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(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() = StatEvent; StatEvent = {}; } } #endif FD3D12FastConstantAllocator ConstantsAllocator; // Current GPU event stack TArray 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 RayTracingShaderTables; #endif /** needs to be called before each draw call */ void CommitNonComputeShaderConstants(); /** needs to be called before each dispatch call */ void CommitComputeShaderConstants(); template 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 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& Combiners); virtual void SetAsyncComputeBudgetInternal(EAsyncComputeBudget Budget) {} virtual void RHIBeginTransitions(TArrayView Transitions) final override; virtual void RHIEndTransitions(TArrayView 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 InParametersData, TConstArrayView InParameters, TConstArrayView InResourceParameters, TConstArrayView InBindlessParameters) final override; virtual void RHISetShaderUnbinds(FRHIComputeShader* Shader, TConstArrayView InUnbinds) final override; virtual void RHISetShaderUnbinds(FRHIGraphicsShader* Shader, TConstArrayView 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 InParametersData, TConstArrayView InParameters, TConstArrayView InResourceParameters, TConstArrayView 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 SharedBindlessParameters, TConstArrayView Dispatches, bool bEmulated) override; virtual void RHIDispatchGraphicsShaderBundle( FRHIShaderBundle* ShaderBundle, FRHIBuffer* RecordArgBuffer, const FRHIShaderBundleGraphicsState& BundleState, TConstArrayView SharedBindlessParameters, TConstArrayView 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 BuildDesc); #if WITH_MGPU // Should be called before RHIBuildAccelerationStructures when multiple GPU support is present (for example, from FD3D12CommandContextRedirector::RHIBuildAccelerationStructures) static void UnregisterAccelerationStructuresInternalMGPU(TConstArrayView Params, FRHIGPUMask GPUMask); #endif virtual void RHIBuildAccelerationStructures(TConstArrayView Params, const FRHIBufferRange& ScratchBufferRange) final override; virtual void RHIBuildAccelerationStructures(TConstArrayView 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::TConcreteType> static FORCEINLINE TReturnType* ResourceCast(TRHIType* Resource) { return static_cast(Resource); } template::TConcreteType> static FORCEINLINE_DEBUGGABLE TReturnType* ResourceCast(TRHIType* Resource, uint32 GPUIndex) { TReturnType* Object = ResourceCast(Resource); return Object ? static_cast(Object->GetLinkedObject(GPUIndex)) : nullptr; } template static FORCEINLINE_DEBUGGABLE ObjectType* RetrieveObject(RHIType* RHIObject, uint32 GPUIndex) { return ResourceCast(RHIObject, GPUIndex); } template FORCEINLINE_DEBUGGABLE ObjectType* RetrieveObject(RHIType* RHIObject) { return RetrieveObject(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& GetStaticUniformBuffers() const { return StaticUniformBuffers; } void FlushPendingDescriptorUpdates(); void SetExplicitDescriptorCache(FD3D12ExplicitDescriptorCache& ExplicitDescriptorCache); void UnsetExplicitDescriptorCache(); virtual void Finalize(TArray& 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(0)); void PostGpuEvent(); static void ClearUAV(TRHICommandList_RecursiveHazardous& RHICmdList, FD3D12UnorderedAccessView_RHI* UAV, const void* ClearValues, bool bFloat); void DispatchWorkGraphShaderBundle(FRHIShaderBundle* ShaderBundle, FRHIBuffer* RecordArgBuffer, TConstArrayView SharedBindlessParameters, TConstArrayView Dispatches); void DispatchWorkGraphShaderBundle(FRHIShaderBundle* ShaderBundle, FRHIBuffer* RecordArgBuffer, const FRHIShaderBundleGraphicsState& BundleState, TConstArrayView SharedBindlessParameters, TConstArrayView Dispatches); void HandleDiscardResources (TArrayView Transitions, bool bIsBeginTransition); void HandleResourceTransitions (const struct FD3D12TransitionData* TransitionData, bool& bUAVBarrier); void HandleTransientAliasing (const struct FD3D12TransitionData* TransitionData); void HandleResourceDiscardTransitions(const struct FD3D12TransitionData* TransitionData, TArray& ResourcesToDiscard); void HandleReservedResourceCommits (const struct FD3D12TransitionData* TransitionData); TArray 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 Transitions) final override { ContextRedirect(RHIBeginTransitions(Transitions)); } FORCEINLINE virtual void RHIEndTransitions(TArrayView Transitions) final override { ContextRedirect(RHIEndTransitions(Transitions)); } #if WITH_MGPU virtual void RHITransferResources(TConstArrayView Params) final override; virtual void RHITransferResourceSignal(TConstArrayView FenceDatas, FRHIGPUMask SrcGPUMask) final override; virtual void RHITransferResourceWait(TConstArrayView FenceDatas) final override; // New and improved cross GPU transfer API virtual void RHICrossGPUTransfer(TConstArrayView Params, TConstArrayView PreTransfer, TConstArrayView PostTransfer) final override; virtual void RHICrossGPUTransferSignal(TConstArrayView Params, TConstArrayView PreTransfer) final override; virtual void RHICrossGPUTransferWait(TConstArrayView 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 InParametersData, TConstArrayView InParameters, TConstArrayView InResourceParameters, TConstArrayView InBindlessParameters) final override { ContextRedirect(RHISetShaderParameters(Shader, InParametersData, InParameters, InResourceParameters, InBindlessParameters)); } FORCEINLINE virtual void RHISetShaderUnbinds(FRHIComputeShader* Shader, TConstArrayView 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 InParametersData, TConstArrayView InParameters, TConstArrayView InResourceParameters, TConstArrayView InBindlessParameters) final override { ContextRedirect(RHISetShaderParameters(Shader, InParametersData, InParameters, InResourceParameters, InBindlessParameters)); } FORCEINLINE virtual void RHISetShaderUnbinds(FRHIGraphicsShader* Shader, TConstArrayView 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 Params, const FRHIBufferRange& ScratchBufferRange) final override { #if WITH_MGPU FD3D12CommandContext::UnregisterAccelerationStructuresInternalMGPU(Params, GPUMask); #endif ContextRedirect(RHIBuildAccelerationStructures(Params, ScratchBufferRange)); } virtual void RHIBuildAccelerationStructures(TConstArrayView 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 PhysicalContexts; }; struct FD3D12TransitionData { ERHIPipeline SrcPipelines, DstPipelines; ERHITransitionCreateFlags CreateFlags = ERHITransitionCreateFlags::None; TArray> TransitionInfos; TArray> AliasingInfos; TArray> AliasingOverlaps; TArray, TInlineAllocator> SyncPoints; bool bCrossPipeline = false; bool bAsyncToAllPipelines = false; }; class FD3D12ContextArray : public TRHIPipelineArray { 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; } };