// Copyright Epic Games, Inc. All Rights Reserved. /*============================================================================= D3D12RHIPrivate.h: Private D3D RHI definitions. =============================================================================*/ #pragma once #include "D3D12RHICommon.h" #include "ID3D12DynamicRHI.h" #include "CoreMinimal.h" #include "Misc/CommandLine.h" #include "Misc/App.h" #include "Misc/ConfigCacheIni.h" #include "Misc/Paths.h" #include "Misc/ScopeLock.h" #include "Misc/ScopeRWLock.h" #include "HAL/LowLevelMemTracker.h" #include "HAL/RunnableThread.h" #include "HAL/ThreadManager.h" #include "Containers/ResourceArray.h" #include "Serialization/MemoryReader.h" #include "EngineGlobals.h" #include "StaticBoundShaderState.h" // Dependencies. #include "DXGIUtilities.h" #include "GPUProfiler.h" #include "ShaderCore.h" #include "HDRHelper.h" #include "D3D12Submission.h" #include "D3D12RHIDefinitions.h" // TODO reorder includes so we just include D3D12PipelineState.h here #include COMPILED_PLATFORM_HEADER(D3D12PipelineState.h) #include "D3D12DiskCache.h" #include "D3D12NvidiaExtensions.h" #include "D3D12IntelExtensions.h" #include "D3D12Residency.h" // D3D RHI public headers. #include "D3D12Util.h" #include "D3D12State.h" #include "D3D12Resources.h" #include "D3D12RootSignature.h" #include "D3D12Shader.h" #include "D3D12View.h" #include "D3D12CommandList.h" #include "D3D12Texture.h" #include "D3D12DirectCommandListManager.h" #include "D3D12Viewport.h" #include "D3D12ConstantBuffer.h" #include "D3D12Query.h" #include "D3D12DescriptorCache.h" #include "D3D12StateCachePrivate.h" #include "D3D12Allocation.h" #include "D3D12TransientResourceAllocator.h" #include "D3D12CommandContext.h" #include "D3D12Stats.h" #include "D3D12Device.h" #include "D3D12Adapter.h" template< typename t_A, typename t_B > inline t_A RoundUpToNextMultiple(const t_A& a, const t_B& b) { return ((a - 1) / b + 1) * b; } using namespace D3D12RHI; extern TAutoConsoleVariable GD3D12DebugCvar; static bool D3D12RHI_ShouldCreateWithWarp() { // Use the warp adapter if specified on the command line. static bool bCreateWithWarp = FParse::Param(FCommandLine::Get(), TEXT("warp")); return bCreateWithWarp; } static bool D3D12RHI_AllowSoftwareFallback() { static bool bAllowSoftwareRendering = FParse::Param(FCommandLine::Get(), TEXT("AllowSoftwareRendering")); return bAllowSoftwareRendering; } static bool D3D12RHI_ShouldAllowAsyncResourceCreation() { static bool bAllowAsyncResourceCreation = !FParse::Param(FCommandLine::Get(), TEXT("nod3dasync")); return bAllowAsyncResourceCreation; } static bool D3D12RHI_ShouldForceCompatibility() { // Suppress the use of newer D3D12 features. static bool bForceCompatibility = FParse::Param(FCommandLine::Get(), TEXT("d3dcompat")) || FParse::Param(FCommandLine::Get(), TEXT("d3d12compat")); return bForceCompatibility; } static bool D3D12RHI_IsRenderDocPresent(ID3D12Device* Device) { IID RenderDocID; if (SUCCEEDED(IIDFromString(L"{A7AA6116-9C8D-4BBA-9083-B4D816B71B78}", &RenderDocID))) { TRefCountPtr RenderDoc; if (SUCCEEDED(Device->QueryInterface(RenderDocID, (void**)RenderDoc.GetInitReference()))) { return true; } } return false; } struct FD3D12UpdateTexture3DData { FD3D12ResourceLocation* UploadHeapResourceLocation; bool bComputeShaderCopy; }; /** * Structure that represents various RTPSO properties (0 if unknown). * These can be used to report performance characteristics, sort shaders by occupancy, etc. */ struct FD3D12RayTracingPipelineInfo { static constexpr uint32 MaxPerformanceGroups = 10; // Estimated RTPSO group based on occupancy or other platform-specific heuristics. // Group 0 is expected to be performing worst, 9 (MaxPerformanceGroups-1) is expected to be the best. uint32 PerformanceGroup = 0; uint32 NumVGPR = 0; uint32 NumSGPR = 0; uint32 StackSize = 0; uint32 ScratchSize = 0; }; /** * Struct used for driver work around on certain driver versions */ struct FD3D12WorkaroundFlags { }; extern FD3D12WorkaroundFlags GD3D12WorkaroundFlags; /** Forward declare the context for the AMD AGS utility library. */ struct AGSContext; struct INTCExtensionContext; /** The interface which is implemented by the dynamically bound RHI. */ class FD3D12DynamicRHI : public ID3D12PlatformDynamicRHI { friend class FD3D12CommandContext; static FD3D12DynamicRHI* SingleD3DRHI; public: static FD3D12DynamicRHI* GetD3DRHI() { return SingleD3DRHI; } void TerminateOnOutOfMemory(ID3D12Device* InDevice, HRESULT D3DResult, bool bCreatingTextures); // Dump & Log all the information we have on a GPU crash (NvAfterMath, DRED, Breadcrumbs, ...) void OutputGPUCrashReport(FTextBuilder& ErrorMessage); // Returns true if the calling thread is the interrupt thread // (or acting as the interrupt thread when D3D12_USE_INTERRUPT_THREAD is zero). bool IsInInterruptThread() const; // Main crash function for handling D3D API errors void HandleFailedD3D12Result(HRESULT D3DResult, ID3D12Device* Device, bool bCreatingTextures, const TCHAR* Message); private: // Calls OutputGpuCrashReport, and also forces a quit. void TerminateOnGPUCrash(); /** Texture pool size */ int64 RequestedTexturePoolSize; friend class FD3D12Thread; class FD3D12Thread* SubmissionThread = nullptr; class FD3D12Thread* InterruptThread = nullptr; // Used when a dedicated interrupt thread is disabled (D3D12_USE_INTERRUPT_THREAD) // Tracks the thread ID of the thread currently acting as the interrupt thread. uint32 InterruptThreadID = 0; enum class EQueueStatus { None = 0, // Work was processed through the queue. Processed = 1 << 0, // The queue has further, unprocessed work. Pending = 1 << 1 }; FRIEND_ENUM_CLASS_FLAGS(EQueueStatus); struct FProcessResult { EQueueStatus Status = EQueueStatus::None; uint32 WaitTimeout = INFINITE; }; TQueue*, EQueueMode::Mpsc> PendingPayloadsForSubmission; // Ensures all prior batched command lists have reached the driver ID3D12Queue object. void FlushBatchedPayloads(FD3D12Queue::FPayloadArray& PayloadsToHandDown); // Executes reserved resource commit operations and cross-queue sync when required void UpdateReservedResources(FD3D12Payload* Payload); FCriticalSection SubmissionCS; FCriticalSection InterruptCS; FProcessResult ProcessSubmissionQueue(); FProcessResult ProcessInterruptQueue(); FCriticalSection ObjectsToDeleteCS; TArray ObjectsToDelete; virtual void UpdateMemoryStats(); public: template void DeferredDelete(Args&&... InArgs) { FScopeLock Lock(&ObjectsToDeleteCS); ObjectsToDelete.Emplace(Forward(InArgs)...); } void SubmitCommands(TConstArrayView Commands); void SubmitPayloads(TArray&& Payloads); // Processes the interrupt queue on the calling thread, until the specified GraphEvent is signaled. // If the GraphEvent is nullptr, processes the queue until no further progress is made. void ProcessInterruptQueueUntil(FGraphEvent* GraphEvent); // Called when the GPU has crashed. This function will not return. void ProcessInterruptQueueOnGPUCrash(); struct FD3D12TimingArray : public TArray, TInlineAllocator> { FD3D12Timing* CreateNew(FD3D12Queue& Queue) { return Emplace_GetRef(MakeUnique(Queue)).Get(); } }; FD3D12TimingArray CurrentTimingPerQueue; void ProcessTimestamps(FD3D12TimingArray const& TimingPerQueue); void InitializeSubmissionPipe(); void ShutdownSubmissionPipe(); // Inserts a task graph task which is executed once all previously submitted GPU work has completed (across all queues, device and adapters). void EnqueueEndOfPipeTask(TUniqueFunction TaskFunc, TUniqueFunction ModifyPayloadCallback = {}); FGraphEventRef EopTask; // Enumerates all queues across all devices and active adapters void ForEachQueue(TFunctionRef Callback); /** Initialization constructor. */ FD3D12DynamicRHI(const TArray>& ChosenAdaptersIn, bool bInPixEventEnabled); /** Destructor */ virtual ~FD3D12DynamicRHI(); // FDynamicRHI interface. virtual void Init() override; virtual void PostInit() override; virtual void Shutdown() override; virtual const TCHAR* GetName() override { return TEXT("D3D12"); } template::TConcreteType> static FORCEINLINE TReturnType* ResourceCast(TRHIType* Resource) { return static_cast(Resource); } template::TConcreteType> static FORCEINLINE const TReturnType* ResourceCast(const 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; } virtual bool QueueSupportsTileMapping(ED3D12QueueType /*InQueueType*/) { return true; } virtual FD3D12CommandContext* CreateCommandContext(FD3D12Device* InParent, ED3D12QueueType InQueueType, bool InIsDefaultContext); virtual void CreateCommandQueue(FD3D12Device* Device, const D3D12_COMMAND_QUEUE_DESC& Desc, TRefCountPtr& OutCommandQueue); virtual bool GetHardwareGPUFrameTime(double& OutGPUFrameTime) const { OutGPUFrameTime = 0.0; return false; } virtual void RHIEndFrame_RenderThread(FRHICommandListImmediate& RHICmdList) final override; virtual void RHIEndFrame(const FRHIEndFrameArgs& Args) final override; virtual FSamplerStateRHIRef RHICreateSamplerState(const FSamplerStateInitializerRHI& Initializer) final override; virtual FRasterizerStateRHIRef RHICreateRasterizerState(const FRasterizerStateInitializerRHI& Initializer) final override; virtual FDepthStencilStateRHIRef RHICreateDepthStencilState(const FDepthStencilStateInitializerRHI& Initializer) final override; virtual FBlendStateRHIRef RHICreateBlendState(const FBlendStateInitializerRHI& Initializer) final override; virtual FVertexDeclarationRHIRef RHICreateVertexDeclaration(const FVertexDeclarationElementList& Elements) final override; virtual FPixelShaderRHIRef RHICreatePixelShader(TArrayView Code, const FSHAHash& Hash) final override; virtual FVertexShaderRHIRef RHICreateVertexShader(TArrayView Code, const FSHAHash& Hash) final override; virtual FMeshShaderRHIRef RHICreateMeshShader(TArrayView Code, const FSHAHash& Hash) final override; virtual FAmplificationShaderRHIRef RHICreateAmplificationShader(TArrayView Code, const FSHAHash& Hash) final override; virtual FGeometryShaderRHIRef RHICreateGeometryShader(TArrayView Code, const FSHAHash& Hash) final override; virtual FComputeShaderRHIRef RHICreateComputeShader(TArrayView Code, const FSHAHash& Hash) override; virtual FWorkGraphShaderRHIRef RHICreateWorkGraphShader(TArrayView Code, const FSHAHash& Hash, EShaderFrequency ShaderFrequency) override; virtual FGPUFenceRHIRef RHICreateGPUFence(const FName& Name) final override; virtual FStagingBufferRHIRef RHICreateStagingBuffer() final override; virtual void* RHILockStagingBuffer(FRHIStagingBuffer* StagingBuffer, FRHIGPUFence* Fence, uint32 Offset, uint32 SizeRHI) final override; virtual void RHIUnlockStagingBuffer(FRHIStagingBuffer* StagingBuffer) final override; virtual FBoundShaderStateRHIRef RHICreateBoundShaderState(FRHIVertexDeclaration* VertexDeclaration, FRHIVertexShader* VertexShader, FRHIPixelShader* PixelShader, FRHIGeometryShader* GeometryShader) final override; virtual FGraphicsPipelineStateRHIRef RHICreateGraphicsPipelineState(const FGraphicsPipelineStateInitializer& Initializer) final override; virtual FComputePipelineStateRHIRef RHICreateComputePipelineState(const FComputePipelineStateInitializer& Initializer) final override; virtual FWorkGraphPipelineStateRHIRef RHICreateWorkGraphPipelineState(const FWorkGraphPipelineStateInitializer& Initializer) final override; virtual void RHICreateTransition(FRHITransition* Transition, const FRHITransitionCreateInfo& CreateInfo) final override; virtual void RHIReleaseTransition(FRHITransition* Transition) final override; virtual FUniformBufferRHIRef RHICreateUniformBuffer(const void* Contents, const FRHIUniformBufferLayout* Layout, EUniformBufferUsage Usage, EUniformBufferValidation Validation) final override; virtual void RHIUpdateUniformBuffer(FRHICommandListBase& RHICmdList, FRHIUniformBuffer* UniformBufferRHI, const void* Contents) final override; [[nodiscard]] virtual FRHIBufferInitializer RHICreateBufferInitializer(FRHICommandListBase& RHICmdList, const FRHIBufferCreateDesc& CreateDesc) override; virtual void RHIReplaceResources(FRHICommandListBase& RHICmdList, TArray&& ReplaceInfos) final override; virtual void* RHILockBuffer(FRHICommandListBase& RHICmdList, FRHIBuffer* Buffer, uint32 Offset, uint32 Size, EResourceLockMode LockMode) final override; virtual void* RHILockBufferMGPU(FRHICommandListBase& RHICmdList, FRHIBuffer* Buffer, uint32 GPUIndex, uint32 Offset, uint32 Size, EResourceLockMode LockMode) final override; virtual void RHIUnlockBuffer(FRHICommandListBase& RHICmdList, FRHIBuffer* Buffer) final override; #if ENABLE_LOW_LEVEL_MEM_TRACKER || UE_MEMORY_TRACE_ENABLED virtual void RHIUpdateAllocationTags(FRHICommandListBase& RHICmdList, FRHIBuffer* Buffer) final override; #endif virtual void RHIUnlockBufferMGPU(FRHICommandListBase& RHICmdList, FRHIBuffer* Buffer, uint32 GPUIndex) final override; virtual FTextureReferenceRHIRef RHICreateTextureReference(FRHICommandListBase& RHICmdList, FRHITexture* InReferencedTexture) final override; virtual void RHIUpdateTextureReference(FRHICommandListBase& RHICmdList, FRHITextureReference* TextureRef, FRHITexture* NewTexture) final override; virtual FRHICalcTextureSizeResult RHICalcTexturePlatformSize(const FRHITextureDesc& Desc, uint32 FirstMipIndex) override; virtual void RHIGetTextureMemoryStats(FTextureMemoryStats& OutStats) final override; virtual bool RHIGetTextureMemoryVisualizeData(FColor* TextureData, int32 SizeX, int32 SizeY, int32 Pitch, int32 PixelSize) final override; virtual FTextureRHIRef RHIAsyncCreateTexture2D(uint32 SizeX, uint32 SizeY, uint8 Format, uint32 NumMips, ETextureCreateFlags Flags, ERHIAccess InResourceState, void** InitialMipData, uint32 NumInitialMips, const TCHAR* DebugName, FGraphEventRef& OutCompletionEvent) final override; [[nodiscard]] virtual FRHITextureInitializer RHICreateTextureInitializer(FRHICommandListBase& RHICmdList, const FRHITextureCreateDesc& CreateDesc) override; virtual uint32 RHIComputeMemorySize(FRHITexture* TextureRHI) final override; virtual FTextureRHIRef RHIAsyncReallocateTexture2D(FRHITexture* Texture2D, int32 NewMipCount, int32 NewSizeX, int32 NewSizeY, FThreadSafeCounter* RequestStatus) override; virtual FRHILockTextureResult RHILockTexture(FRHICommandListImmediate& RHICmdList, const FRHILockTextureArgs& Arguments) final override; virtual void RHIUnlockTexture(FRHICommandListImmediate& RHICmdList, const FRHILockTextureArgs& Arguments) final override; virtual void RHIUpdateTexture2D(FRHICommandListBase& RHICmdList, FRHITexture* Texture, uint32 MipIndex, const struct FUpdateTextureRegion2D& UpdateRegion, uint32 SourcePitch, const uint8* SourceData) final override; virtual void RHIUpdateTexture3D(FRHICommandListBase& RHICmdList, FRHITexture* Texture, uint32 MipIndex, const struct FUpdateTextureRegion3D& UpdateRegion, uint32 SourceRowPitch, uint32 SourceDepthPitch, const uint8* SourceData) final override; virtual FUpdateTexture3DData RHIBeginUpdateTexture3D(FRHICommandListBase& RHICmdList, FRHITexture* Texture, uint32 MipIndex, const struct FUpdateTextureRegion3D& UpdateRegion) final override; virtual void RHIEndUpdateTexture3D(FRHICommandListBase& RHICmdList, FUpdateTexture3DData& UpdateData) final override; virtual void RHIEndMultiUpdateTexture3D(FRHICommandListBase& RHICmdList, TArray& UpdateDataArray) final override; virtual void RHIBindDebugLabelName(FRHICommandListBase& RHICmdList, FRHITexture* Texture, const TCHAR* Name) final override; virtual void RHIBindDebugLabelName(FRHICommandListBase& RHICmdList, FRHIBuffer* Buffer, const TCHAR* Name) final override; virtual void RHIReadSurfaceData(FRHITexture* Texture, FIntRect Rect, TArray& OutData, FReadSurfaceDataFlags InFlags) final override; virtual void RHIReadSurfaceData(FRHITexture* TextureRHI, FIntRect InRect, TArray& OutData, FReadSurfaceDataFlags InFlags) final override; virtual void RHIMapStagingSurface(FRHITexture* Texture, FRHIGPUFence* Fence, void*& OutData, int32& OutWidth, int32& OutHeight, uint32 GPUIndex = 0) final override; virtual void RHIUnmapStagingSurface(FRHITexture* Texture, uint32 GPUIndex = 0) final override; virtual void RHIReadSurfaceFloatData(FRHITexture* Texture, FIntRect Rect, TArray& OutData, FReadSurfaceDataFlags InFlags) final override; virtual void RHIReadSurfaceFloatData(FRHITexture* Texture, FIntRect Rect, TArray& OutData, ECubeFace CubeFace, int32 ArrayIndex, int32 MipIndex) final override; virtual void RHIRead3DSurfaceFloatData(FRHITexture* Texture, FIntRect Rect, FIntPoint ZMinMax, TArray& OutData) final override; virtual void RHIRead3DSurfaceFloatData(FRHITexture* Texture, FIntRect Rect, FIntPoint ZMinMax, TArray& OutData, FReadSurfaceDataFlags InFlags) final override; virtual FRenderQueryRHIRef RHICreateRenderQuery(ERenderQueryType QueryType) final override; virtual void RHIBeginRenderQueryBatch_TopOfPipe(FRHICommandListBase& RHICmdList, ERenderQueryType QueryType) final override; virtual void RHIEndRenderQueryBatch_TopOfPipe(FRHICommandListBase& RHICmdList, ERenderQueryType QueryType) final override; virtual void RHIEndRenderQuery_TopOfPipe(FRHICommandListBase& RHICmdList, FRHIRenderQuery* RenderQuery) final override; virtual bool RHIGetRenderQueryResult(FRHIRenderQuery* RenderQuery, uint64& OutResult, bool bWait, uint32 GPUIndex = INDEX_NONE) final override; virtual uint32 RHIGetViewportNextPresentGPUIndex(FRHIViewport* Viewport) final override; virtual FTextureRHIRef RHIGetViewportBackBuffer(FRHIViewport* Viewport) final override; #if D3D12RHI_SUPPORTS_UAV_BACKBUFFER virtual FUnorderedAccessViewRHIRef RHIGetViewportBackBufferUAV(FRHIViewport* Viewport) final override; #endif virtual void RHIAliasTextureResources(FTextureRHIRef& DestTexture, FTextureRHIRef& SrcTexture) final override; virtual FTextureRHIRef RHICreateAliasedTexture(FTextureRHIRef& SourceTexture) final override; virtual void RHIGetDisplaysInformation(FDisplayInformationArray& OutDisplayInformation) final override; virtual uint64 RHIComputeStatePrecachePSOHash(const FGraphicsPipelineStateInitializer& Initializer) final override; virtual uint64 RHIComputePrecachePSOHash(const FGraphicsPipelineStateInitializer& Initializer) final override; virtual bool RHIMatchPrecachePSOInitializers(const FGraphicsPipelineStateInitializer& LHS, const FGraphicsPipelineStateInitializer& RHS) final override; virtual void RHIAdvanceFrameForGetViewportBackBuffer(FRHIViewport* Viewport) final override; virtual void RHIFlushResources() final override; virtual FViewportRHIRef RHICreateViewport(void* WindowHandle, uint32 SizeX, uint32 SizeY, bool bIsFullscreen, EPixelFormat PreferredPixelFormat) final override; virtual void RHIResizeViewport(FRHIViewport* Viewport, uint32 SizeX, uint32 SizeY, bool bIsFullscreen) final override; virtual void RHIResizeViewport(FRHIViewport* ViewportRHI, uint32 SizeX, uint32 SizeY, bool bIsFullscreen, EPixelFormat PreferredPixelFormat) final override; #if PLATFORM_WINDOWS virtual void RHIHandleDisplayChange() final override; #endif virtual void RHITick(float DeltaTime) final override; virtual void RHIBlockUntilGPUIdle() final override; virtual bool RHIGetAvailableResolutions(FScreenResolutionArray& Resolutions, bool bIgnoreRefreshRate) final override; virtual void RHIGetSupportedResolution(uint32& Width, uint32& Height) final override; virtual void* RHIGetNativeDevice() final override; virtual void* RHIGetNativeGraphicsQueue() final override; virtual void* RHIGetNativeComputeQueue() final override; virtual void* RHIGetNativeInstance() final override; virtual class IRHICommandContext* RHIGetDefaultContext() final override; virtual IRHIComputeContext* RHIGetCommandContext(ERHIPipeline Pipeline, FRHIGPUMask GPUMask) final override; virtual void RHIFinalizeContext(FRHIFinalizeContextArgs&& Args, TRHIPipelineArray& Output) final override; virtual void RHISubmitCommandLists(FRHISubmitCommandListsArgs&& Args) final override; virtual void RHIProcessDeleteQueue() final override; // Some RHIs can be suspended, most likely due to the HW going into suspend mode, this allows device dependent threads to wait until it's safe virtual FRWLock* RHIGetSuspendedLock() { return nullptr; } virtual void RHIRunOnQueue(ED3D12RHIRunOnQueueType QueueType, TFunction&& CodeToRun, bool bWaitForSubmission) final override; virtual void RHIFlushResourceBarriers(FRHICommandListBase& RHICmdList, uint32 InGPUIndex) final override; virtual IRHITransientResourceAllocator* RHICreateTransientResourceAllocator() override; virtual void RHIWriteGPUFence_TopOfPipe(FRHICommandListBase& RHICmdList, FRHIGPUFence* FenceRHI) final override; // SRV / UAV creation functions virtual FShaderResourceViewRHIRef RHICreateShaderResourceView (class FRHICommandListBase& RHICmdList, FRHIViewableResource* Resource, FRHIViewDesc const& ViewDesc) override; virtual FUnorderedAccessViewRHIRef RHICreateUnorderedAccessView(class FRHICommandListBase& RHICmdList, FRHIViewableResource* Resource, FRHIViewDesc const& ViewDesc) override; #if PLATFORM_SUPPORTS_BINDLESS_RENDERING virtual FRHIResourceCollectionRef RHICreateResourceCollection(FRHICommandListBase& RHICmdList, TConstArrayView InMembers) override; #endif // ID3D12DynamicRHI interface. virtual TArray RHIGetAdapterDescs() const final override; virtual bool RHIIsPixEnabled() const final override; virtual ID3D12CommandQueue* RHIGetCommandQueue() const final override; virtual ID3D12Device* RHIGetDevice(uint32 InIndex) const final override; virtual uint32 RHIGetDeviceNodeMask(uint32 InIndex) const final override; virtual ID3D12GraphicsCommandList* RHIGetGraphicsCommandList(FRHICommandListBase& ExecutingCmdList, uint32 InDeviceIndex) const final override; virtual DXGI_FORMAT RHIGetSwapChainFormat(EPixelFormat InFormat) const final override; virtual FTextureRHIRef RHICreateTexture2DFromResource(EPixelFormat Format, ETextureCreateFlags TexCreateFlags, const FClearValueBinding& ClearValueBinding, ID3D12Resource* Resource) final override; virtual FTextureRHIRef RHICreateTexture2DArrayFromResource(EPixelFormat Format, ETextureCreateFlags TexCreateFlags, const FClearValueBinding& ClearValueBinding, ID3D12Resource* Resource) final override; virtual FTextureRHIRef RHICreateTextureCubeFromResource(EPixelFormat Format, ETextureCreateFlags TexCreateFlags, const FClearValueBinding& ClearValueBinding, ID3D12Resource* Resource) final override; virtual ID3D12Resource* RHIGetResource(FRHIBuffer* InBuffer) const final override; virtual uint32 RHIGetResourceDeviceIndex(FRHIBuffer* InBuffer) const final override; virtual int64 RHIGetResourceMemorySize(FRHIBuffer* InBuffer) const final override; virtual bool RHIIsResourcePlaced(FRHIBuffer* InBuffer) const final override; virtual ID3D12Resource* RHIGetResource(FRHITexture* InTexture) const final override; virtual uint32 RHIGetResourceDeviceIndex(FRHITexture* InTexture) const final override; virtual int64 RHIGetResourceMemorySize(FRHITexture* InTexture) const final override; virtual bool RHIIsResourcePlaced(FRHITexture* InTexture) const final override; virtual D3D12_CPU_DESCRIPTOR_HANDLE RHIGetRenderTargetView(FRHITexture* InTexture, int32 InMipIndex = 0, int32 InArraySliceIndex = 0) const final override; virtual void RHIFinishExternalComputeWork(FRHICommandListBase& ExecutingCmdList, uint32 InDeviceIndex, ID3D12GraphicsCommandList* InCommandList) final override; virtual void RHITransitionResource(FRHICommandList& RHICmdList, FRHITexture* InTexture, D3D12_RESOURCE_STATES InState, uint32 InSubResource) final override; virtual void RHISignalManualFence(FRHICommandList& RHICmdList, ID3D12Fence* Fence, uint64 Value) final override; virtual void RHIWaitManualFence(FRHICommandList& RHICmdList, ID3D12Fence* Fence, uint64 Value) final override; virtual void RHIVerifyResult(ID3D12Device* Device, HRESULT Result, const ANSICHAR* Code, const ANSICHAR* Filename, uint32 Line, FString Message = FString()) const final override; // // The Following functions are the _RenderThread version of the above functions. They allow the RHI to control the thread synchronization for greater efficiency. // These will be un-commented as they are implemented. // virtual FTextureRHIRef AsyncReallocateTexture2D_RenderThread(class FRHICommandListImmediate& RHICmdList, FRHITexture* Texture2D, int32 NewMipCount, int32 NewSizeX, int32 NewSizeY, FThreadSafeCounter* RequestStatus); #if D3D12_RHI_RAYTRACING virtual FRayTracingAccelerationStructureSize RHICalcRayTracingSceneSize(const FRayTracingSceneInitializer& Initializer) final override; virtual FRayTracingAccelerationStructureSize RHICalcRayTracingGeometrySize(const FRayTracingGeometryInitializer& Initializer) final override; virtual FRayTracingAccelerationStructureOfflineMetadata RHIGetRayTracingGeometryOfflineMetadata(const FRayTracingGeometryOfflineDataHeader& OfflineDataHeader) final override; virtual FRayTracingGeometryRHIRef RHICreateRayTracingGeometry(FRHICommandListBase& RHICmdList, const FRayTracingGeometryInitializer& Initializer) final override; virtual FRayTracingSceneRHIRef RHICreateRayTracingScene(FRayTracingSceneInitializer Initializer) final override; virtual FRayTracingShaderRHIRef RHICreateRayTracingShader(TArrayView Code, const FSHAHash& Hash, EShaderFrequency ShaderFrequency) final override; virtual FRayTracingPipelineStateRHIRef RHICreateRayTracingPipelineState(const FRayTracingPipelineStateInitializer& Initializer) final override; virtual FShaderBindingTableRHIRef RHICreateShaderBindingTable(FRHICommandListBase& RHICmdList, const FRayTracingShaderBindingTableInitializer& Initializer) final override; #endif //D3D12_RHI_RAYTRACING virtual FShaderBundleRHIRef RHICreateShaderBundle(const FShaderBundleCreateInfo& CreateInfo) override; virtual void HandleGpuTimeout(FD3D12Payload* Payload, double SecondsSinceSubmission); bool IsQuadBufferStereoEnabled() const; void DisableQuadBufferStereo(); void* LockBuffer(FRHICommandListBase& RHICmdList, FD3D12Buffer* Buffer, uint32 BufferSize, EBufferUsageFlags BufferUsage, uint32 Offset, uint32 Size, EResourceLockMode LockMode); void UnlockBuffer(FRHICommandListBase& RHICmdList, FD3D12Buffer* Buffer, EBufferUsageFlags BufferUsage); virtual bool BeginUpdateTexture3D_ComputeShader(FUpdateTexture3DData& UpdateData, FD3D12UpdateTexture3DData* UpdateDataD3D12) { // Not supported on PC return false; } virtual void EndUpdateTexture3D_ComputeShader(FRHIComputeCommandList& RHICmdList, FUpdateTexture3DData& UpdateData, FD3D12UpdateTexture3DData* UpdateDataD3D12) { // Not supported on PC } FUpdateTexture3DData BeginUpdateTexture3D_Internal(FRHITexture* Texture, uint32 MipIndex, const struct FUpdateTextureRegion3D& UpdateRegion); void EndUpdateTexture3D_Internal(FRHICommandListBase& RHICmdList, FUpdateTexture3DData& UpdateData); public: #if PLATFORM_SUPPORTS_VIRTUAL_TEXTURES virtual void* CreateVirtualTexture(ETextureCreateFlags InFlags, D3D12_RESOURCE_DESC& ResourceDesc, const struct FD3D12TextureLayout& TextureLayout, FD3D12Resource** ppResource, FPlatformMemory::FPlatformVirtualMemoryBlock& RawTextureBlock, D3D12_RESOURCE_STATES InitialUsage = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) = 0; virtual void DestroyVirtualTexture(ETextureCreateFlags InFlags, void* RawTextureMemory, FPlatformMemory::FPlatformVirtualMemoryBlock& RawTextureBlock, uint64 CommittedTextureSize) = 0; #endif virtual bool HandleSpecialLock(FRHILockTextureResult& Result, FD3D12Texture* InTexture, const FRHILockTextureArgs& Arguments) { return false; } virtual bool HandleSpecialUnlock(FRHICommandListBase& RHICmdList, FD3D12Texture* InTexture, const FRHILockTextureArgs& Arguments) { return false; } FD3D12Adapter& GetAdapter(uint32_t Index = 0) { return *ChosenAdapters[Index]; } const FD3D12Adapter& GetAdapter(uint32_t Index = 0) const { return *ChosenAdapters[Index]; } uint32 GetNumAdapters() const { return ChosenAdapters.Num(); } bool IsPixEventEnabled() const { return bPixEventEnabled; } template void ForEachDevice(ID3D12Device* inDevice, const PerDeviceFunction& pfPerDeviceFunction); AGSContext* GetAmdAgsContext() { return AmdAgsContext; } void SetAmdSupportedExtensionFlags(uint32 Flags) { AmdSupportedExtensionFlags = Flags; } uint32 GetAmdSupportedExtensionFlags() const { return AmdSupportedExtensionFlags; } INTCExtensionContext* GetIntelExtensionContext() { return IntelExtensionContext; } protected: TArray> ChosenAdapters; #if D3D12RHI_SUPPORTS_WIN_PIX void* WinPixGpuCapturerHandle = nullptr; #endif /** Can pix events be used */ bool bPixEventEnabled = false; /** The feature level of the device. */ D3D_FEATURE_LEVEL FeatureLevel; /** * The context for the AMD AGS utility library. * AGSContext does not implement AddRef/Release. * Just use a bare pointer. */ AGSContext* AmdAgsContext; uint32 AmdSupportedExtensionFlags; INTCExtensionContext* IntelExtensionContext = nullptr; // See r.PSOPrecache.D3D12.DriverCacheAware. The CVar is cached // to prevent hotfixes or config dynamic layers from altering the // value at runtime, which is not supported. bool bDriverCacheAwarePSOPrecaching = false; /** A buffer in system memory containing all zeroes of the specified size. */ void* ZeroBuffer; uint32 ZeroBufferSize; #if PLATFORM_WINDOWS TRefCountPtr DXGIFactoryForDisplayList; #endif public: virtual FD3D12ResourceDesc GetResourceDesc(const FRHITextureDesc& CreateInfo) const; struct FCreateTextureInternalResult { FD3D12Texture* Texture{}; D3D12_RESOURCE_STATES CreateState{}; D3D12_RESOURCE_STATES DesiredState{}; }; // Per-platform D3D12Texture creation. virtual FCreateTextureInternalResult CreateTextureInternal(const FRHITextureCreateDesc& CreateDesc, ID3D12ResourceAllocator* ResourceAllocator = nullptr); // Create D3D12 texture with a resource allocator. Does not currently support any post-creation state or uploading of data. FD3D12Texture* CreateD3D12Texture(const FRHITextureCreateDesc& CreateDesc, ID3D12ResourceAllocator* ResourceAllocator) { check(CreateDesc.BulkData == nullptr); FCreateTextureInternalResult CreateResult = CreateTextureInternal(CreateDesc, ResourceAllocator); checkSlow(CreateResult.CreateState == CreateResult.DesiredState); return CreateResult.Texture; } virtual FD3D12Texture* CreateNewD3D12Texture(const FRHITextureCreateDesc& CreateDesc, class FD3D12Device* Device); struct FCreateBufferInternalResult { FD3D12Buffer* Buffer{}; D3D12_RESOURCE_STATES DesiredState{}; }; FCreateBufferInternalResult CreateBufferInternal(const FRHIBufferCreateDesc& CreateDesc, bool bHasInitialData, ID3D12ResourceAllocator* ResourceAllocator); FD3D12Buffer* CreateD3D12Buffer(FRHICommandListBase* RHICmdList, const FRHIBufferCreateDesc& CreateDesc, ID3D12ResourceAllocator* ResourceAllocator = nullptr) { FCreateBufferInternalResult CreateResult = CreateBufferInternal(CreateDesc, false, ResourceAllocator); return CreateResult.Buffer; } FD3D12Buffer* CreateD3D12Buffer(const FRHIBufferCreateDesc& CreateDesc, ID3D12ResourceAllocator* ResourceAllocator) { return CreateD3D12Buffer(nullptr, CreateDesc, ResourceAllocator); } bool SetupDisplayHDRMetaData(); protected: FD3D12Texture* CreateTextureFromResource(bool bTextureArray, bool bCubeTexture, EPixelFormat Format, ETextureCreateFlags TexCreateFlags, const FClearValueBinding& ClearValueBinding, ID3D12Resource* Resource); FD3D12Texture* CreateAliasedD3D12Texture2D(FD3D12Texture* SourceTexture); /** * Gets the best supported MSAA settings from the provided MSAA count to check against. * * @param PlatformFormat The format of the texture being created * @param MSAACount The MSAA count to check against. * @param OutBestMSAACount The best MSAA count that is suppored. Could be smaller than MSAACount if it is not supported * @param OutMSAAQualityLevels The number MSAA quality levels for the best msaa count supported */ void GetBestSupportedMSAASetting(DXGI_FORMAT PlatformFormat, uint32 MSAACount, uint32& OutBestMSAACount, uint32& OutMSAAQualityLevels); /** * Returns a pointer to a texture resource that can be used for CPU reads. * Note: the returned resource could be the original texture or a new temporary texture. * @param TextureRHI - Source texture to create a staging texture from. * @param InRect - rectangle to 'stage'. * @param StagingRectOUT - parameter is filled with the rectangle to read from the returned texture. * @return The CPU readable Texture object. */ TRefCountPtr GetStagingTexture(FRHITexture* TextureRHI, FIntRect InRect, FIntRect& OutRect, FReadSurfaceDataFlags InFlags, D3D12_PLACED_SUBRESOURCE_FOOTPRINT &readBackHeapDesc, uint32 GPUIndex); void ReadSurfaceDataNoMSAARaw(FRHITexture* TextureRHI, FIntRect Rect, TArray& OutData, FReadSurfaceDataFlags InFlags); void ReadSurfaceDataMSAARaw(FRHITexture* TextureRHI, FIntRect Rect, TArray& OutData, FReadSurfaceDataFlags InFlags); // This should only be called by Dynamic RHI member functions FD3D12Device* GetRHIDevice(uint32 GPUIndex) const; void SetupD3D12Debug(); HANDLE FlipEvent; FDisplayInformationArray DisplayList; void ProcessDeferredDeletionQueue_Platform(); }; ENUM_CLASS_FLAGS(FD3D12DynamicRHI::EQueueStatus); /** Implements the D3D12RHI module as a dynamic RHI providing module. */ class FD3D12DynamicRHIModule : public IDynamicRHIModule { public: FD3D12DynamicRHIModule() { } ~FD3D12DynamicRHIModule() { } // IModuleInterface virtual bool SupportsDynamicReloading() override { return false; } virtual void StartupModule() override; virtual void ShutdownModule() override; // IDynamicRHIModule virtual bool IsSupported() override { return IsSupported(ERHIFeatureLevel::SM5); } virtual bool IsSupported(ERHIFeatureLevel::Type RequestedFeatureLevel) override; virtual FDynamicRHI* CreateRHI(ERHIFeatureLevel::Type RequestedFeatureLevel = ERHIFeatureLevel::Num) override; private: #if D3D12RHI_SUPPORTS_WIN_PIX void* WindowsPixDllHandle = nullptr; void* WinPixGpuCapturerHandle = nullptr; #endif TArray> ChosenAdapters; // set MaxSupportedFeatureLevel and ChosenAdapter void FindAdapter(); }; // Helper to push/pop a desired state on a resource. Handles both tracked and untracked resources. class FScopedResourceBarrier { private: FD3D12ContextCommon& Context; FD3D12Resource* const Resource; FD3D12ResourceLocation* const ResourceLocation; D3D12_RESOURCE_STATES const DesiredState; D3D12_RESOURCE_STATES BeforeState; uint32 const Subresource; bool bRestoreState = false; public: FScopedResourceBarrier(FD3D12ContextCommon& Context, FD3D12Resource* Resource, FD3D12ResourceLocation* InResourceLocation, D3D12_RESOURCE_STATES DesiredState, uint32 Subresource, D3D12_RESOURCE_STATES BeforeState = D3D12_RESOURCE_STATE_TBD) : Context (Context) , Resource(Resource) , ResourceLocation(InResourceLocation) , DesiredState(DesiredState) , BeforeState(BeforeState) , Subresource (Subresource) { if ((!Resource->RequiresResourceStateTracking()) || (BeforeState != D3D12_RESOURCE_STATE_TBD)) { // Resources that do not require state tracking are kept in a default state, meaning the previous state for the transition is known. D3D12_RESOURCE_STATES CurrentState = (BeforeState != D3D12_RESOURCE_STATE_TBD) ? BeforeState : Resource->GetDefaultResourceState(); // Some states such as D3D12_RESOURCE_STATE_GENERIC_READ already includes D3D12_RESOURCE_STATE_COPY_SOURCE as well as other states, therefore transition isn't required. if (CurrentState != DesiredState && !EnumHasAllFlags(CurrentState, DesiredState)) { Context.AddTransitionBarrier(Resource, CurrentState, DesiredState, Subresource); // We will add a transition, we need to transition back to the default state when the scoped object dies. bRestoreState = true; } } } ~FScopedResourceBarrier() { if (bRestoreState) { Context.AddTransitionBarrier(Resource, DesiredState, (BeforeState != D3D12_RESOURCE_STATE_TBD) ? BeforeState : Resource->GetDefaultResourceState(), Subresource); } } }; // Returns the given format as a string. Unsupported formats are treated as DXGI_FORMAT_UNKNOWN. const TCHAR* LexToString(DXGI_FORMAT Format);