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

319 lines
18 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
MetalRHI.h: Public Metal RHI definitions..
=============================================================================*/
#pragma once
#include "CoreMinimal.h"
#include "RHI.h"
// Metal RHI public headers.
#include "MetalThirdParty.h"
#include "MetalState.h"
#include "MetalResources.h"
#include "MetalRHIContext.h"
#include "MetalViewport.h"
#include "MetalSubmission.h"
class FMetalDevice;
#if METAL_RHI_RAYTRACING
class FMetalRayTracingCompactionRequestHandler;
#endif // METAL_RHI_RAYTRACING
struct FMetalDeferredDeleteObject
{
typedef TVariant<FMetalBufferPtr,
MTLTexturePtr,
NS::Object*,
#if PLATFORM_SUPPORTS_BINDLESS_RENDERING
FRHIDescriptorHandle,
#endif
FMetalFence*,
TUniqueFunction<void()>*> TObjectStorage;
TObjectStorage Storage;
explicit FMetalDeferredDeleteObject(FMetalBufferPtr InBuffer) : Storage(TInPlaceType<FMetalBufferPtr>(), InBuffer)
{}
explicit FMetalDeferredDeleteObject(MTLTexturePtr InTexture) : Storage(TInPlaceType<MTLTexturePtr>(), InTexture)
{}
explicit FMetalDeferredDeleteObject(NS::Object* InObject) : Storage(TInPlaceType<NS::Object*>(), InObject)
{}
#if PLATFORM_SUPPORTS_BINDLESS_RENDERING
explicit FMetalDeferredDeleteObject(FRHIDescriptorHandle InHandle) : Storage(TInPlaceType<FRHIDescriptorHandle>(), InHandle)
{}
#endif
explicit FMetalDeferredDeleteObject(FMetalFence* InFence) : Storage(TInPlaceType<FMetalFence*>(), InFence)
{}
explicit FMetalDeferredDeleteObject(TUniqueFunction<void()>&& Func) :
Storage(TInPlaceType<TUniqueFunction<void()>*>(), new TUniqueFunction<void()>(MoveTemp(Func)))
{}
};
struct FMetalFinalizedCommands final : public IRHIPlatformCommandList, public TArray<FMetalPayload*>
{};
/** The interface which is implemented by the dynamically bound RHI. */
class FMetalDynamicRHI : public FDynamicRHI
{
static inline FMetalDynamicRHI* Singleton = nullptr;
public:
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;
};
static inline FMetalDynamicRHI& Get() { return *Singleton; }
/** Initialization constructor. */
FMetalDynamicRHI(ERHIFeatureLevel::Type RequestedFeatureLevel);
/** Destructor */
~FMetalDynamicRHI();
// FDynamicRHI interface.
virtual void Init();
virtual void Shutdown() {}
virtual const TCHAR* GetName() override { return TEXT("Metal"); }
virtual ERHIInterfaceType GetInterfaceType() const override { return ERHIInterfaceType::Metal; }
virtual void RHIEndFrame_RenderThread(FRHICommandListImmediate& RHICmdList) final override;
virtual void RHIEndFrame(const FRHIEndFrameArgs& Args) final override;
virtual FRHIShaderLibraryRef RHICreateShaderLibrary(EShaderPlatform Platform, FString const& FilePath, FString const& Name) 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<const uint8> Code, const FSHAHash& Hash) final override;
virtual FVertexShaderRHIRef RHICreateVertexShader(TArrayView<const uint8> Code, const FSHAHash& Hash) final override;
virtual FGeometryShaderRHIRef RHICreateGeometryShader(TArrayView<const uint8> Code, const FSHAHash& Hash) final override;
virtual FComputeShaderRHIRef RHICreateComputeShader(TArrayView<const uint8> Code, const FSHAHash& Hash) final override;
#if PLATFORM_SUPPORTS_MESH_SHADERS
virtual FMeshShaderRHIRef RHICreateMeshShader(TArrayView<const uint8> Code, const FSHAHash& Hash) final override;
virtual FAmplificationShaderRHIRef RHICreateAmplificationShader(TArrayView<const uint8> Code, const FSHAHash& Hash) final override;
#endif
virtual FBoundShaderStateRHIRef RHICreateBoundShaderState(FRHIVertexDeclaration* VertexDeclaration, FRHIVertexShader* VertexShader, FRHIPixelShader* PixelShader, FRHIGeometryShader* GeometryShader) final override;
virtual FGraphicsPipelineStateRHIRef RHICreateGraphicsPipelineState(const FGraphicsPipelineStateInitializer& Initializer) final override;
virtual TRefCountPtr<FRHIComputePipelineState> RHICreateComputePipelineState(const FComputePipelineStateInitializer& Initializer) final override;
virtual FUniformBufferRHIRef RHICreateUniformBuffer(const void* Contents, const FRHIUniformBufferLayout* Layout, EUniformBufferUsage Usage, EUniformBufferValidation Validation) final override;
[[nodiscard]] virtual FRHIBufferInitializer RHICreateBufferInitializer(FRHICommandListBase& RHICmdList, const FRHIBufferCreateDesc& CreateDesc) final override;
virtual void RHIReplaceResources(FRHICommandListBase& RHICmdList, TArray<FRHIResourceReplaceInfo>&& ReplaceInfos) final override;
virtual void * RHILockBuffer(class FRHICommandListBase& RHICmdList, FRHIBuffer* Buffer, uint32 Offset, uint32 SizeRHI, EResourceLockMode LockMode) final override;
virtual void RHIUnlockBuffer(class FRHICommandListBase& RHICmdList, FRHIBuffer* Buffer) final override;
virtual void* LockBuffer_BottomOfPipe(FRHICommandListBase& RHICmdList, FRHIBuffer* Buffer, uint32 Offset, uint32 SizeRHI, EResourceLockMode LockMode) final override;
virtual void UnlockBuffer_BottomOfPipe(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
// SRV / UAV creation functions
virtual FShaderResourceViewRHIRef RHICreateShaderResourceView (class FRHICommandListBase& RHICmdList, FRHIViewableResource* Resource, FRHIViewDesc const& ViewDesc) final override;
virtual FUnorderedAccessViewRHIRef RHICreateUnorderedAccessView(class FRHICommandListBase& RHICmdList, FRHIViewableResource* Resource, FRHIViewDesc const& ViewDesc) final override;
#if PLATFORM_SUPPORTS_BINDLESS_RENDERING
virtual FRHIResourceCollectionRef RHICreateResourceCollection(FRHICommandListBase& RHICmdList, TConstArrayView<FRHIResourceCollectionMember> InMembers) final override;
#endif
virtual FRHICalcTextureSizeResult RHICalcTexturePlatformSize(FRHITextureDesc const& Desc, uint32 FirstMipIndex) final override;
virtual uint64 RHIGetMinimumAlignmentForBufferBackedSRV(EPixelFormat Format) final override;
virtual void RHIGetTextureMemoryStats(FTextureMemoryStats& OutStats) final override;
virtual bool RHIGetTextureMemoryVisualizeData(FColor* TextureData,int32 SizeX,int32 SizeY,int32 Pitch,int32 PixelSize) final override;
[[nodiscard]] virtual FRHITextureInitializer RHICreateTextureInitializer(FRHICommandListBase& RHICmdList, const FRHITextureCreateDesc& CreateDesc) 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;
virtual uint32 RHIComputeMemorySize(FRHITexture* TextureRHI) final override;
virtual FTextureRHIRef RHIAsyncReallocateTexture2D(FRHITexture* Texture2D, int32 NewMipCount, int32 NewSizeX, int32 NewSizeY, FThreadSafeCounter* RequestStatus) final 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 void RHIBindDebugLabelName(FRHICommandListBase& RHICmdList, FRHITexture* Texture, const TCHAR* Name) final override;
virtual void RHIReadSurfaceData(FRHITexture* Texture,FIntRect Rect,TArray<FColor>& OutData,FReadSurfaceDataFlags InFlags) final override;
virtual void RHIReadSurfaceData(FRHITexture* TextureRHI, FIntRect InRect, TArray<FLinearColor>& OutData, FReadSurfaceDataFlags InFlags) final override;
#if PLATFORM_IOS
virtual void RHIReadSurfaceDataDirect(FRHITexture* TextureRHI, FIntRect Rect, TArray<FColor>& OutData) final override;
#endif // PLATFORM_IOS
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<FFloat16Color>& OutData,ECubeFace CubeFace,int32 ArrayIndex,int32 MipIndex) final override;
virtual void RHIRead3DSurfaceFloatData(FRHITexture* Texture,FIntRect Rect,FIntPoint ZMinMax,TArray<FFloat16Color>& OutData) final override;
virtual FRenderQueryRHIRef RHICreateRenderQuery(ERenderQueryType QueryType) final override;
virtual bool RHIGetRenderQueryResult(FRHIRenderQuery* RenderQuery, uint64& OutResult, bool bWait, uint32 GPUIndex = INDEX_NONE) final override;
virtual FTextureRHIRef RHIGetViewportBackBuffer(FRHIViewport* Viewport) 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* Viewport, uint32 SizeX, uint32 SizeY, bool bIsFullscreen, EPixelFormat PreferredPixelFormat) final override;
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* METALRHI_API RHIGetNativeDevice() final override;
virtual void* METALRHI_API RHIGetNativeGraphicsQueue() final override;
virtual void* METALRHI_API RHIGetNativeComputeQueue() final override;
virtual void* METALRHI_API RHIGetNativeInstance() final override;
virtual class IRHICommandContext* METALRHI_API RHIGetDefaultContext() final override;
virtual IRHIUploadContext* RHIGetUploadContext() final override;
virtual IRHIComputeContext* RHIGetCommandContext(ERHIPipeline Pipeline, FRHIGPUMask GPUMask) final override;
virtual IRHIComputeContext* RHIGetParallelCommandContext(FRHIParallelRenderPassInfo const& ParallelRenderPass, FRHIGPUMask GPUMask) final override;
virtual void RHIProcessDeleteQueue() final override;
virtual void RHIFinalizeContext(FRHIFinalizeContextArgs&& Args, TRHIPipelineArray<IRHIPlatformCommandList*>& Output) final override;
virtual IRHIPlatformCommandList* RHIFinalizeParallelContext(IRHIComputeContext* Context) final override;
virtual void RHISubmitCommandLists(FRHISubmitCommandListsArgs&& Args) final override;
virtual FTextureRHIRef AsyncReallocateTexture2D_RenderThread(class FRHICommandListImmediate& RHICmdList, FRHITexture* Texture2D, int32 NewMipCount, int32 NewSizeX, int32 NewSizeY, FThreadSafeCounter* RequestStatus) 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 RHICreateTransition(FRHITransition* Transition, const FRHITransitionCreateInfo& CreateInfo) final override;
virtual void RHIReleaseTransition(FRHITransition* Transition) final override;
virtual FGPUFenceRHIRef RHICreateGPUFence(const FName &Name) final override;
virtual void RHIWriteGPUFence_TopOfPipe(FRHICommandListBase& RHICmdList, FRHIGPUFence* FenceRHI) 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 FRHIShaderLibraryRef RHICreateShaderLibrary_RenderThread(class FRHICommandListImmediate& RHICmdList, EShaderPlatform Platform, FString FilePath, FString Name) final override;
virtual void RHIUpdateUniformBuffer(FRHICommandListBase& RHICmdList, FRHIUniformBuffer* UniformBufferRHI, const void* Contents) final override;
virtual uint16 RHIGetPlatformTextureMaxSampleCount() override;
#if METAL_RHI_RAYTRACING
virtual FRayTracingAccelerationStructureSize RHICalcRayTracingSceneSize(const FRayTracingSceneInitializer& Initializer) final override;
virtual FRayTracingAccelerationStructureSize RHICalcRayTracingGeometrySize(const FRayTracingGeometryInitializer& Initializer) final override;
virtual FRayTracingGeometryRHIRef RHICreateRayTracingGeometry(FRHICommandListBase& RHICmdList, const FRayTracingGeometryInitializer& Initializer) final override;
virtual FRayTracingSceneRHIRef RHICreateRayTracingScene(FRayTracingSceneInitializer Initializer) final override;
virtual FRayTracingShaderRHIRef RHICreateRayTracingShader(TArrayView<const uint8> 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 // METAL_RHI_RAYTRACING
virtual FTextureReferenceRHIRef RHICreateTextureReference(FRHICommandListBase& RHICmdList, FRHITexture* InReferencedTexture) final override;
virtual void RHIUpdateTextureReference(FRHICommandListBase& RHICmdList, FRHITextureReference* TextureRef, FRHITexture* NewTexture) final override;
virtual uint64 RHIComputePrecachePSOHash(const FGraphicsPipelineStateInitializer& Initializer) final override;
virtual bool RHIMatchPrecachePSOInitializers(const FGraphicsPipelineStateInitializer& LHS, const FGraphicsPipelineStateInitializer& RHS) final override;
virtual void RHIBeginRenderQuery_TopOfPipe(FRHICommandListBase& RHICmdList, FRHIRenderQuery* RenderQuery) override;
virtual void RHIEndRenderQuery_TopOfPipe (FRHICommandListBase& RHICmdList, FRHIRenderQuery* RenderQuery) override;
virtual void RHIBeginRenderQueryBatch_TopOfPipe(FRHICommandListBase& RHICmdList, ERenderQueryType QueryType) final override;
virtual void RHIEndRenderQueryBatch_TopOfPipe(FRHICommandListBase& RHICmdList, ERenderQueryType QueryType) final override;
void RHIRunOnQueue(TFunction<void(FMetalCommandQueue&)>&& CodeToRun, bool bWaitForSubmission);
template <typename ...Args>
void DeferredDelete(Args&&... InArgs)
{
check(!IsInGameThread() || !IsRunningRHIInSeparateThread());
FScopeLock Lock(&ObjectsToDeleteCS);
ObjectsToDelete.Emplace(Forward<Args>(InArgs)...);
}
void SubmitCommands(TConstArrayView<struct FMetalFinalizedCommands*> Commands);
void SubmitPayloads(TArray<FMetalPayload*>&& Payloads);
// Ensures all prior batched command lists have reached the MetalQueue
void FlushBatchedPayloads(FMetalCommandQueue::FPayloadArray& PayloadsToHandDown);
// 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);
void ProcessPendingCommandBuffers();
// Called when the GPU has crashed. This function will not return.
void ProcessInterruptQueueOnGPUCrash();
#if RHI_NEW_GPU_PROFILER
struct FMetalTimingArray : public TArray<TUniquePtr<FMetalTiming>, TInlineAllocator<GMetalMaxNumQueues>>
{
FMetalTiming* CreateNew(FMetalCommandQueue& Queue)
{
return Emplace_GetRef(MakeUnique<FMetalTiming>(Queue)).Get();
}
};
FMetalTimingArray CurrentTimingPerQueue;
#endif
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<void()> TaskFunc, TUniqueFunction<void(FMetalPayload&)> ModifyPayloadCallback = {});
FGraphEventRef EopTask;
FCriticalSection SubmissionCS;
FCriticalSection InterruptCS;
FProcessResult ProcessSubmissionQueue();
FProcessResult ProcessInterruptQueue();
// Enumerates all queues across all devices and active adapters
void ForEachQueue(TFunctionRef<void(FMetalCommandQueue&)> Callback);
private:
FMetalDevice* Device;
FTextureMemoryStats MemoryStats;
FMetalRHICommandContext ImmediateContext;
TMap<uint32, FVertexDeclarationRHIRef> VertexDeclarationCache;
TLockFreePointerListUnordered<FMetalRHICommandContext, PLATFORM_CACHE_LINE_SIZE> MetalCommandContextPool;
FCriticalSection ObjectsToDeleteCS;
TArray<FMetalDeferredDeleteObject> ObjectsToDelete;
TArray<FMetalCommandBuffer*> CmdBuffersPendingCompletion;
#if METAL_USE_METAL_SHADER_CONVERTER
struct IRCompiler* CompilerInstance;
#endif
friend class FMetalThread;
class FMetalThread* SubmissionThread = nullptr;
class FMetalThread* InterruptThread = nullptr;
TQueue<TArray<FMetalPayload*>*, EQueueMode::Mpsc> PendingPayloadsForSubmission;
};
ENUM_CLASS_FLAGS(FMetalDynamicRHI::EQueueStatus);