• UE4之RHI图形API封装


    RHI全称是Render Hardware Interface(渲染硬件接口),封装了众多图形API(DirectX、OpenGL、Vulkan、Metal)之间的差异

    基于D3D11 API设计而成,包含了资源管理(Shader、Texture、VertexBuffer等)和图形API封装(DrawIndexedPrimitive、Clear、SetTexture等)。

    对Game和Renderer模块提供了简便且一致的概念、数据、资源和接口,实现一份渲染代码跑在多个平台的目标。

    RHI相关的测试代码:UnrealEngine\Engine\Plugins\Tests\RHITests\Source\RHITests

    资源管理部分详见:UE4之RHI资源管理。本文重点讲 图形API封装

    IRHICommandContext

    IRHICommandContext是RHI的命令上下文接口类,定义了一组图形API相关的操作。在可以并行处理命令列表的平台上,它是一个单独的对象。它和相关继承类型定义如下:

    // Engine\Source\Runtime\RHI\Public\RHIContext.h
    
    // 能够执行计算工作的上下文。可以在gfx管道上执行异步或计算.
    class IRHIComputeContext
    {
    public:
        virtual ~IRHIComputeContext();
    
        // 设置/派发计算着色器.
        virtual void RHISetComputeShader(FRHIComputeShader* ComputeShader) = 0;
        virtual void RHISetComputePipelineState(FRHIComputePipelineState* ComputePipelineState);
        virtual void RHIDispatchComputeShader(uint32 ThreadGroupCountX, uint32 ThreadGroupCountY, uint32 ThreadGroupCountZ) = 0;
        virtual void RHIDispatchIndirectComputeShader(FRHIVertexBuffer* ArgumentBuffer, uint32 ArgumentOffset) = 0;
        virtual void RHISetAsyncComputeBudget(EAsyncComputeBudget Budget) {}
        
        // 转换资源.
        virtual void RHIBeginTransitions(TArrayView<const FRHITransition*> Transitions) = 0;
        virtual void RHIEndTransitions(TArrayView<const FRHITransition*> Transitions) = 0;
    
        // UAV
        virtual void RHIClearUAVFloat(FRHIUnorderedAccessView* UnorderedAccessViewRHI, const FVector4& Values) = 0;
        virtual void RHIClearUAVUint(FRHIUnorderedAccessView* UnorderedAccessViewRHI, const FUintVector4& Values) = 0;
        virtual void RHIBeginUAVOverlap() {}
        virtual void RHIEndUAVOverlap() {}
        virtual void RHIBeginUAVOverlap(TArrayView<FRHIUnorderedAccessView* const> UAVs) {}
        virtual void RHIEndUAVOverlap(TArrayView<FRHIUnorderedAccessView* const> UAVs) {}
    
        // 着色器参数.
        virtual void RHISetShaderTexture(FRHIComputeShader* PixelShader, uint32 TextureIndex, FRHITexture* NewTexture) = 0;
        virtual void RHISetShaderSampler(FRHIComputeShader* ComputeShader, uint32 SamplerIndex, FRHISamplerState* NewState) = 0;
        virtual void RHISetUAVParameter(FRHIComputeShader* ComputeShader, uint32 UAVIndex, FRHIUnorderedAccessView* UAV) = 0;
        virtual void RHISetUAVParameter(FRHIComputeShader* ComputeShader, uint32 UAVIndex, FRHIUnorderedAccessView* UAV, uint32 InitialCount) = 0;
        virtual void RHISetShaderResourceViewParameter(FRHIComputeShader* ComputeShader, uint32 SamplerIndex, FRHIShaderResourceView* SRV) = 0;
        virtual void RHISetShaderUniformBuffer(FRHIComputeShader* ComputeShader, uint32 BufferIndex, FRHIUniformBuffer* Buffer) = 0;
        virtual void RHISetShaderParameter(FRHIComputeShader* ComputeShader, uint32 BufferIndex, uint32 BaseIndex, uint32 NumBytes, const void* NewValue) = 0;
        virtual void RHISetGlobalUniformBuffers(const FUniformBufferStaticBindings& InUniformBuffers);
        
        // 压入/弹出事件.
        virtual void RHIPushEvent(const TCHAR* Name, FColor Color) = 0;
        virtual void RHIPopEvent() = 0;
    
        // 其它接口.
        virtual void RHISubmitCommandsHint() = 0;
        virtual void RHIInvalidateCachedState() {}
        virtual void RHICopyToStagingBuffer(FRHIVertexBuffer* SourceBufferRHI, FRHIStagingBuffer* DestinationStagingBufferRHI, uint32 InOffset, uint32 InNumBytes);
        virtual void RHIWriteGPUFence(FRHIGPUFence* FenceRHI);
        virtual void RHISetGPUMask(FRHIGPUMask GPUMask);
    
        // 加速结构.
        virtual void RHIBuildAccelerationStructure(FRHIRayTracingGeometry* Geometry);
        virtual void RHIBuildAccelerationStructures(const TArrayView<const FAccelerationStructureBuildParams> Params);
        virtual void RHIBuildAccelerationStructure(FRHIRayTracingScene* Scene);
    
        // 获取计算上下文.
        inline IRHIComputeContext& GetLowestLevelContext() { return *this; }
        inline IRHIComputeContext& GetHighestLevelContext() { return *this; }
    };
    
    // 命令上下文.
    class IRHICommandContext : public IRHIComputeContext
    {
    public:
        virtual ~IRHICommandContext();
    
        // 派发计算.
        virtual void RHIDispatchComputeShader(uint32 ThreadGroupCountX, uint32 ThreadGroupCountY, uint32 ThreadGroupCountZ) = 0;
        virtual void RHIDispatchIndirectComputeShader(FRHIVertexBuffer* ArgumentBuffer, uint32 ArgumentOffset) = 0;
        
        // 渲染查询.
        virtual void RHIBeginRenderQuery(FRHIRenderQuery* RenderQuery) = 0;
        virtual void RHIEndRenderQuery(FRHIRenderQuery* RenderQuery) = 0;
        virtual void RHIPollOcclusionQueries();
    
        // 开启/结束接口.
        virtual void RHIBeginDrawingViewport(FRHIViewport* Viewport, FRHITexture* RenderTargetRHI) = 0;
        virtual void RHIEndDrawingViewport(FRHIViewport* Viewport, bool bPresent, bool bLockToVsync) = 0;
        virtual void RHIBeginFrame() = 0;
        virtual void RHIEndFrame() = 0;
        virtual void RHIBeginScene() = 0;
        virtual void RHIEndScene() = 0;
        virtual void RHIBeginUpdateMultiFrameResource(FRHITexture* Texture);
        virtual void RHIEndUpdateMultiFrameResource(FRHITexture* Texture);
        virtual void RHIBeginUpdateMultiFrameResource(FRHIUnorderedAccessView* UAV);
        virtual void RHIEndUpdateMultiFrameResource(FRHIUnorderedAccessView* UAV);
            
        // 设置数据.
        virtual void RHISetStreamSource(uint32 StreamIndex, FRHIVertexBuffer* VertexBuffer, uint32 Offset) = 0;
        virtual void RHISetViewport(float MinX, float MinY, float MinZ, float MaxX, float MaxY, float MaxZ) = 0;
        virtual void RHISetStereoViewport(...);
        virtual void RHISetScissorRect(bool bEnable, uint32 MinX, uint32 MinY, uint32 MaxX, uint32 MaxY) = 0;
        virtual void RHISetGraphicsPipelineState(FRHIGraphicsPipelineState* GraphicsState, bool bApplyAdditionalState) = 0;
    
        // 设置着色器参数.
        virtual void RHISetShaderTexture(FRHIGraphicsShader* Shader, uint32 TextureIndex, FRHITexture* NewTexture) = 0;
        virtual void RHISetShaderTexture(FRHIComputeShader* PixelShader, uint32 TextureIndex, FRHITexture* NewTexture) = 0;
        virtual void RHISetShaderSampler(FRHIComputeShader* ComputeShader, uint32 SamplerIndex, FRHISamplerState* NewState) = 0;
        virtual void RHISetShaderSampler(FRHIGraphicsShader* Shader, uint32 SamplerIndex, FRHISamplerState* NewState) = 0;
        virtual void RHISetUAVParameter(FRHIPixelShader* PixelShader, uint32 UAVIndex, FRHIUnorderedAccessView* UAV) = 0;
        virtual void RHISetUAVParameter(FRHIComputeShader* ComputeShader, uint32 UAVIndex, FRHIUnorderedAccessView* UAV) = 0;
        virtual void RHISetUAVParameter(FRHIComputeShader* ComputeShader, uint32 UAVIndex, FRHIUnorderedAccessView* UAV, uint32 InitialCount) = 0;
        virtual void RHISetShaderResourceViewParameter(FRHIComputeShader* ComputeShader, uint32 SamplerIndex, FRHIShaderResourceView* SRV) = 0;
        virtual void RHISetShaderResourceViewParameter(FRHIGraphicsShader* Shader, uint32 SamplerIndex, FRHIShaderResourceView* SRV) = 0;
        virtual void RHISetShaderUniformBuffer(FRHIGraphicsShader* Shader, uint32 BufferIndex, FRHIUniformBuffer* Buffer) = 0;
        virtual void RHISetShaderUniformBuffer(FRHIComputeShader* ComputeShader, uint32 BufferIndex, FRHIUniformBuffer* Buffer) = 0;
        virtual void RHISetShaderParameter(FRHIGraphicsShader* Shader, uint32 BufferIndex, uint32 BaseIndex, uint32 NumBytes, const void* NewValue) = 0;
        virtual void RHISetShaderParameter(FRHIComputeShader* ComputeShader, uint32 BufferIndex, uint32 BaseIndex, uint32 NumBytes, const void* NewValue) = 0;
        virtual void RHISetStencilRef(uint32 StencilRef) {}
        virtual void RHISetBlendFactor(const FLinearColor& BlendFactor) {}
        
        // 绘制图元.
        virtual void RHIDrawPrimitive(uint32 BaseVertexIndex, uint32 NumPrimitives, uint32 NumInstances) = 0;
        virtual void RHIDrawPrimitiveIndirect(FRHIVertexBuffer* ArgumentBuffer, uint32 ArgumentOffset) = 0;
        virtual void RHIDrawIndexedIndirect(FRHIIndexBuffer* IndexBufferRHI, FRHIStructuredBuffer* ArgumentsBufferRHI, int32 DrawArgumentsIndex, uint32 NumInstances) = 0;
        virtual void RHIDrawIndexedPrimitive(FRHIIndexBuffer* IndexBuffer, int32 BaseVertexIndex, uint32 FirstInstance, uint32 NumVertices, uint32 StartIndex, uint32 NumPrimitives, uint32 NumInstances) = 0;
        virtual void RHIDrawIndexedPrimitiveIndirect(FRHIIndexBuffer* IndexBuffer, FRHIVertexBuffer* ArgumentBuffer, uint32 ArgumentOffset) = 0;
    
        // 其它接口
        virtual void RHISetDepthBounds(float MinDepth, float MaxDepth) = 0;
        virtual void RHISetShadingRate(EVRSShadingRate ShadingRate, EVRSRateCombiner Combiner);
        virtual void RHISetShadingRateImage(FRHITexture* RateImageTexture, EVRSRateCombiner Combiner);
        virtual void RHISetMultipleViewports(uint32 Count, const FViewportBounds* Data) = 0;
        virtual void RHICopyToResolveTarget(FRHITexture* SourceTexture, FRHITexture* DestTexture, const FResolveParams& ResolveParams) = 0;
        virtual void RHIResummarizeHTile(FRHITexture2D* DepthTexture);
        virtual void RHICalibrateTimers();
        virtual void RHICalibrateTimers(FRHITimestampCalibrationQuery* CalibrationQuery);
        virtual void RHIDiscardRenderTargets(bool Depth, bool Stencil, uint32 ColorBitMask) {}
        
        // 纹理
        virtual void RHIUpdateTextureReference(FRHITextureReference* TextureRef, FRHITexture* NewTexture) = 0;
        virtual void RHICopyTexture(FRHITexture* SourceTexture, FRHITexture* DestTexture, const FRHICopyTextureInfo& CopyInfo);
        virtual void RHICopyBufferRegion(FRHIVertexBuffer* DestBuffer, ...);
        
        // Pass相关.
        virtual void RHIBeginRenderPass(const FRHIRenderPassInfo& InInfo, const TCHAR* InName) = 0;
        virtual void RHIEndRenderPass() = 0;
        virtual void RHINextSubpass();
    
        // 光线追踪.
        virtual void RHIClearRayTracingBindings(FRHIRayTracingScene* Scene);
        virtual void RHIBuildAccelerationStructures(const TArrayView<const FAccelerationStructureBuildParams> Params);
        virtual void RHIBuildAccelerationStructure(FRHIRayTracingGeometry* Geometry) final override;
        virtual void RHIBuildAccelerationStructure(FRHIRayTracingScene* Scene);
        virtual void RHIRayTraceOcclusion(FRHIRayTracingScene* Scene, ...);
        virtual void RHIRayTraceIntersection(FRHIRayTracingScene* Scene, ...);
        virtual void RHIRayTraceDispatch(FRHIRayTracingPipelineState* RayTracingPipelineState, ...);
        virtual void RHISetRayTracingHitGroups(FRHIRayTracingScene* Scene, ...);
        virtual void RHISetRayTracingHitGroup(FRHIRayTracingScene* Scene, ...);
        virtual void RHISetRayTracingCallableShader(FRHIRayTracingScene* Scene, ...);
        virtual void RHISetRayTracingMissShader(FRHIRayTracingScene* Scene, ...);
        
        (......)
    
    protected:
        // 渲染Pass信息.
        FRHIRenderPassInfo RenderPassInfo;
    };

    IRHICommandContext还有许多子类:

    • IRHICommandContextPSOFallback:不支持真正的图形管道的RHI命令上下文。

      • FNullDynamicRHI:空实现的动态绑定RHI。
      • FOpenGLDynamicRHI:OpenGL的动态RHI。
      • FD3D11DynamicRHI:D3D11的动态RHI。
    • FMetalRHICommandContext:Metal平台的命令上下文。

    • FD3D12CommandContextBase:D3D12的命令上下文。

    • FVulkanCommandListContext:Vulkan平台的命令队列上下文。

    • FEmptyDynamicRHI:动态绑定的RHI实现的接口。

    • FValidationContext:校验上下文。

    上述的子类中,平台相关的部分子类还继承了FDynamicRHI。

    IRHICommandContextPSOFallback比较特殊,它的子类都是不支持并行绘制的图形API(如:OpenGL、D3D11)。

    IRHICommandContextPSOFallback定义如下:

    class IRHICommandContextPSOFallback : public IRHICommandContext
    {
    public:
        // 设置渲染状态.
        virtual void RHISetBoundShaderState(FRHIBoundShaderState* BoundShaderState) = 0;
        virtual void RHISetDepthStencilState(FRHIDepthStencilState* NewState, uint32 StencilRef) = 0;
        virtual void RHISetRasterizerState(FRHIRasterizerState* NewState) = 0;
        virtual void RHISetBlendState(FRHIBlendState* NewState, const FLinearColor& BlendFactor) = 0;
        virtual void RHIEnableDepthBoundsTest(bool bEnable) = 0;
        // 管线状态.
        virtual void RHISetGraphicsPipelineState(FRHIGraphicsPipelineState* GraphicsState, bool bApplyAdditionalState) override;
    };

    IRHICommandContext的核心继承UML图如下:

    IRHICommandContextContainer

    IRHICommandContextContainer就是包含了IRHICommandContext对象的类型,它和核心继承子类的定义如下:

    // Engine\Source\Runtime\RHI\Public\RHICommandList.h
    
    class IRHICommandContextContainer
    {
    public:
        virtual ~IRHICommandContextContainer();
    
        // 获取IRHICommandContext实例.
        virtual IRHICommandContext* GetContext();
        virtual void SubmitAndFreeContextContainer(int32 Index, int32 Num);
        virtual void FinishContext();
    };
    
    // Engine\Source\Runtime\Apple\MetalRHI\Private\MetalContext.cpp
    
    class FMetalCommandContextContainer : public IRHICommandContextContainer
    {
        // FMetalRHICommandContext列表的下一个.
        FMetalRHICommandContext* CmdContext;
        int32 Index;
        int32 Num;
        
    public:
        void* operator new(size_t Size);
        void operator delete(void *RawMemory);
        
        FMetalCommandContextContainer(int32 InIndex, int32 InNum);
        virtual ~FMetalCommandContextContainer() override final;
        
        virtual IRHICommandContext* GetContext() override final;
        virtual void FinishContext() override final;
        // 提交并释放自己.
        virtual void SubmitAndFreeContextContainer(int32 NewIndex, int32 NewNum) override final;
    };
    
    // FMetalCommandContextContainer分配器.
    static TLockFreeFixedSizeAllocator<sizeof(FMetalCommandContextContainer), PLATFORM_CACHE_LINE_SIZE, FThreadSafeCounter> FMetalCommandContextContainerAllocator;
    
    // Engine\Source\Runtime\D3D12RHI\Private\D3D12CommandContext.cpp
    
    class FD3D12CommandContextContainer : public IRHICommandContextContainer
    {
        // 适配器.
        FD3D12Adapter* Adapter;
        // 命令上下文.
        FD3D12CommandContext* CmdContext;
        // 上下文重定向器.
        FD3D12CommandContextRedirector* CmdContextRedirector;
        FRHIGPUMask GPUMask;
    
        // 命令队列列表.
        TArray<FD3D12CommandListHandle> CommandLists;
    
    public:
        void* operator new(size_t Size);
        void operator delete(void* RawMemory);
    
        FD3D12CommandContextContainer(FD3D12Adapter* InAdapter, FRHIGPUMask InGPUMask);
        virtual ~FD3D12CommandContextContainer() override
    
        virtual IRHICommandContext* GetContext() override;
        virtual void FinishContext() override;
        virtual void SubmitAndFreeContextContainer(int32 Index, int32 Num) override;
    };
    
    // Engine\Source\Runtime\VulkanRHI\Private\VulkanContext.h
    
    struct FVulkanCommandContextContainer : public IRHICommandContextContainer, public VulkanRHI::FDeviceChild
    {
        // 命令队列上下文.
        FVulkanCommandListContext* CmdContext;
    
        FVulkanCommandContextContainer(FVulkanDevice* InDevice);
    
        virtual IRHICommandContext* GetContext() override final;
        virtual void FinishContext() override final;
        virtual void SubmitAndFreeContextContainer(int32 Index, int32 Num) override final;
    
        void* operator new(size_t Size);
        void operator delete(void* RawMemory);
    };

    IRHICommandContextContainer相当于存储了一个或一组命令上下文的容器,以支持并行化地提交命令队列,只在D3D12、Metal、Vulkan等现代图形API中有实现。

    完整继承UML图如下:

    FDynamicRHI

    FDynamicRHI是由动态绑定的RHI实现的接口,它定义的接口和CommandContext比较相似,部分如下:

    class RHI_API FDynamicRHI
    {
    public:
        virtual ~FDynamicRHI() {}
    
        virtual void Init() = 0;
        virtual void PostInit() {}
        virtual void Shutdown() = 0;
    
        void InitPixelFormatInfo(const TArray<uint32>& PixelFormatBlockBytesIn);
    
        // ---- RHI接口 ----
    
        // 下列接口要求FlushType: Thread safe
        virtual FSamplerStateRHIRef RHICreateSamplerState(const FSamplerStateInitializerRHI& Initializer) = 0;
        virtual FRasterizerStateRHIRef RHICreateRasterizerState(const FRasterizerStateInitializerRHI& Initializer) = 0;
        virtual FDepthStencilStateRHIRef RHICreateDepthStencilState(const FDepthStencilStateInitializerRHI& Initializer) = 0;
        virtual FBlendStateRHIRef RHICreateBlendState(const FBlendStateInitializerRHI& Initializer) = 0;
    
        // 下列接口要求FlushType: Wait RHI Thread
        virtual FVertexDeclarationRHIRef RHICreateVertexDeclaration(const FVertexDeclarationElementList& Elements) = 0;
        virtual FPixelShaderRHIRef RHICreatePixelShader(TArrayView<const uint8> Code, const FSHAHash& Hash) = 0;
        virtual FVertexShaderRHIRef RHICreateVertexShader(TArrayView<const uint8> Code, const FSHAHash& Hash) = 0;
        virtual FHullShaderRHIRef RHICreateHullShader(TArrayView<const uint8> Code, const FSHAHash& Hash) = 0;
        virtual FDomainShaderRHIRef RHICreateDomainShader(TArrayView<const uint8> Code, const FSHAHash& Hash) = 0;
        virtual FGeometryShaderRHIRef RHICreateGeometryShader(TArrayView<const uint8> Code, const FSHAHash& Hash) = 0;
        virtual FComputeShaderRHIRef RHICreateComputeShader(TArrayView<const uint8> Code, const FSHAHash& Hash) = 0;
    
         // FlushType: Must be Thread-Safe.
        virtual FRenderQueryPoolRHIRef RHICreateRenderQueryPool(ERenderQueryType QueryType, uint32 NumQueries = UINT32_MAX);
        inline FComputeFenceRHIRef RHICreateComputeFence(const FName& Name);
        
        virtual FGPUFenceRHIRef RHICreateGPUFence(const FName &Name);
        virtual void RHICreateTransition(FRHITransition* Transition, ERHIPipeline SrcPipelines, ERHIPipeline DstPipelines, ERHICreateTransitionFlags CreateFlags, TArrayView<const FRHITransitionInfo> Infos);
        virtual void RHIReleaseTransition(FRHITransition* Transition);
    
        // FlushType: Thread safe.    
        virtual FStagingBufferRHIRef RHICreateStagingBuffer();
        virtual void* RHILockStagingBuffer(FRHIStagingBuffer* StagingBuffer, FRHIGPUFence* Fence, uint32 Offset, uint32 SizeRHI);
        virtual void RHIUnlockStagingBuffer(FRHIStagingBuffer* StagingBuffer);
        
        // FlushType: Thread safe, but varies depending on the RHI
        virtual FBoundShaderStateRHIRef RHICreateBoundShaderState(FRHIVertexDeclaration* VertexDeclaration, FRHIVertexShader* VertexShader, FRHIHullShader* HullShader, FRHIDomainShader* DomainShader, FRHIPixelShader* PixelShader, FRHIGeometryShader* GeometryShader) = 0;
        // FlushType: Thread safe
        virtual FGraphicsPipelineStateRHIRef RHICreateGraphicsPipelineState(const FGraphicsPipelineStateInitializer& Initializer);
        
        // FlushType: Thread safe, but varies depending on the RHI
        virtual FUniformBufferRHIRef RHICreateUniformBuffer(const void* Contents, const FRHIUniformBufferLayout& Layout, EUniformBufferUsage Usage, EUniformBufferValidation Validation) = 0;
        virtual void RHIUpdateUniformBuffer(FRHIUniformBuffer* UniformBufferRHI, const void* Contents) = 0;
        
        // FlushType: Wait RHI Thread
        virtual FIndexBufferRHIRef RHICreateIndexBuffer(uint32 Stride, uint32 Size, uint32 InUsage, ERHIAccess InResourceState, FRHIResourceCreateInfo& CreateInfo) = 0;
        virtual void* RHILockIndexBuffer(FRHICommandListImmediate& RHICmdList, FRHIIndexBuffer* IndexBuffer, uint32 Offset, uint32 Size, EResourceLockMode LockMode);
        virtual void RHIUnlockIndexBuffer(FRHICommandListImmediate& RHICmdList, FRHIIndexBuffer* IndexBuffer);
        virtual void RHITransferIndexBufferUnderlyingResource(FRHIIndexBuffer* DestIndexBuffer, FRHIIndexBuffer* SrcIndexBuffer);
    
        // FlushType: Wait RHI Thread
        virtual FVertexBufferRHIRef RHICreateVertexBuffer(uint32 Size, uint32 InUsage, ERHIAccess InResourceState, FRHIResourceCreateInfo& CreateInfo) = 0;
        // FlushType: Flush RHI Thread
        virtual void* RHILockVertexBuffer(FRHICommandListImmediate& RHICmdList, FRHIVertexBuffer* VertexBuffer, uint32 Offset, uint32 SizeRHI, EResourceLockMode LockMode);
        virtual void RHIUnlockVertexBuffer(FRHICommandListImmediate& RHICmdList, FRHIVertexBuffer* VertexBuffer);
        // FlushType: Flush Immediate (seems dangerous)
        virtual void RHICopyVertexBuffer(FRHIVertexBuffer* SourceBuffer, FRHIVertexBuffer* DestBuffer) = 0;
        virtual void RHITransferVertexBufferUnderlyingResource(FRHIVertexBuffer* DestVertexBuffer, FRHIVertexBuffer* SrcVertexBuffer);
    
        // FlushType: Wait RHI Thread
        virtual FStructuredBufferRHIRef RHICreateStructuredBuffer(uint32 Stride, uint32 Size, uint32 InUsage, ERHIAccess InResourceState, FRHIResourceCreateInfo& CreateInfo) = 0;
        // FlushType: Flush RHI Thread
        virtual void* RHILockStructuredBuffer(FRHICommandListImmediate& RHICmdList, FRHIStructuredBuffer* StructuredBuffer, uint32 Offset, uint32 SizeRHI, EResourceLockMode LockMode);
        virtual void RHIUnlockStructuredBuffer(FRHICommandListImmediate& RHICmdList, FRHIStructuredBuffer* StructuredBuffer);
    
        // FlushType: Wait RHI Thread
        virtual FUnorderedAccessViewRHIRef RHICreateUnorderedAccessView(FRHIStructuredBuffer* StructuredBuffer, bool bUseUAVCounter, bool bAppendBuffer) = 0;
        // FlushType: Wait RHI Thread
        virtual FUnorderedAccessViewRHIRef RHICreateUnorderedAccessView(FRHITexture* Texture, uint32 MipLevel) = 0;
        // FlushType: Wait RHI Thread
        virtual FUnorderedAccessViewRHIRef RHICreateUnorderedAccessView(FRHITexture* Texture, uint32 MipLevel, uint8 Format);
    
        (......)
    
        // RHI帧更新,须从主线程调用,FlushType: Thread safe
        virtual void RHITick(float DeltaTime) = 0;
        // 阻塞CPU直到GPU执行完成变成空闲. FlushType: Flush Immediate (seems wrong)
        virtual void RHIBlockUntilGPUIdle() = 0;
        // 开始当前帧,并确保GPU正在积极地工作 FlushType: Flush Immediate (copied from RHIBlockUntilGPUIdle)
        virtual void RHISubmitCommandsAndFlushGPU() {};
    
        // 通知RHI准备暂停它.
        virtual void RHIBeginSuspendRendering() {};
        // 暂停RHI渲染并将控制权交给系统的操作, FlushType: Thread safe
        virtual void RHISuspendRendering() {};
        // 继续RHI渲染, FlushType: Thread safe
        virtual void RHIResumeRendering() {};
        // FlushType: Flush Immediate
        virtual bool RHIIsRenderingSuspended() { return false; };
    
        // FlushType: called from render thread when RHI thread is flushed 
        // 仅在FRHIResource::FlushPendingDeletes内的延迟删除之前每帧调用.
        virtual void RHIPerFrameRHIFlushComplete();
    
        // 执行命令队列, FlushType: Wait RHI Thread
        virtual void RHIExecuteCommandList(FRHICommandList* CmdList) = 0;
    
        // FlushType: Flush RHI Thread
        virtual void* RHIGetNativeDevice() = 0;
        // FlushType: Flush RHI Thread
        virtual void* RHIGetNativeInstance() = 0;
    
        // 获取命令上下文. FlushType: Thread safe
        virtual IRHICommandContext* RHIGetDefaultContext() = 0;
        // 获取计算上下文. FlushType: Thread safe
        virtual IRHIComputeContext* RHIGetDefaultAsyncComputeContext();
    
        // FlushType: Thread safe
        virtual class IRHICommandContextContainer* RHIGetCommandContextContainer(int32 Index, int32 Num) = 0;
    
        // 直接由渲染线程调用的接口, 以优化RHI调用.
        virtual FVertexBufferRHIRef CreateAndLockVertexBuffer_RenderThread(class FRHICommandListImmediate& RHICmdList, uint32 Size, uint32 InUsage, ERHIAccess InResourceState, FRHIResourceCreateInfo& CreateInfo, void*& OutDataBuffer);
        virtual FIndexBufferRHIRef CreateAndLockIndexBuffer_RenderThread(class FRHICommandListImmediate& RHICmdList, uint32 Stride, uint32 Size, uint32 InUsage, ERHIAccess InResourceState, FRHIResourceCreateInfo& CreateInfo, void*& OutDataBuffer);
        
        (......)
    
        // Buffer Lock/Unlock
        virtual void* LockVertexBuffer_BottomOfPipe(class FRHICommandListImmediate& RHICmdList, ...);
        virtual void* LockIndexBuffer_BottomOfPipe(class FRHICommandListImmediate& RHICmdList, ...);
        
        (......)
    };

    以上只显示了部分接口,其中部分接口要求从渲染线程调用,部分须从游戏线程调用。大多数接口在被调用前需刷新指定类型的命令,比如:

    class RHI_API FDynamicRHI
    {
        // FlushType: Wait RHI Thread
        void RHIExecuteCommandList(FRHICommandList* CmdList);
    
        // FlushType: Flush Immediate
        void RHIBlockUntilGPUIdle();
    
        // FlushType: Thread safe 
        void RHITick(float DeltaTime);
    };

    那么调用以上接口的代码如下:

    class RHI_API FRHICommandListImmediate : public FRHICommandList
    {
        void ExecuteCommandList(FRHICommandList* CmdList)
        {
            // 等待RHI线程.
            FScopedRHIThreadStaller StallRHIThread(*this);
            GDynamicRHI->RHIExecuteCommandList(CmdList);
        }
        
        void BlockUntilGPUIdle()
        {
            // 调用FDynamicRHI::RHIBlockUntilGPUIdle须刷新RHI.
            ImmediateFlush(EImmediateFlushType::FlushRHIThread);  
            GDynamicRHI->RHIBlockUntilGPUIdle();
        }
        
        void Tick(float DeltaTime)
        {
            // 由于FDynamicRHI::RHITick是Thread Safe(线程安全), 所以不需要调用ImmediateFlush或等待事件.
            GDynamicRHI->RHITick(DeltaTime);
        }
    };

    我们继续看FDynamicRHI的子类定义:

    // Engine\Source\Runtime\Apple\MetalRHI\Private\MetalDynamicRHI.h
    
    class FMetalDynamicRHI : public FDynamicRHI
    {
    public:
        FMetalDynamicRHI(ERHIFeatureLevel::Type RequestedFeatureLevel);
        ~FMetalDynamicRHI();
        
        // 设置必要的内部资源
        void SetupRecursiveResources();
    
        // FDynamicRHI interface.
        virtual void Init();
        virtual void Shutdown() {}
        virtual const TCHAR* GetName() override { return TEXT("Metal"); }
        
        virtual FSamplerStateRHIRef RHICreateSamplerState(const FSamplerStateInitializerRHI& Initializer) final override;
        virtual FRasterizerStateRHIRef RHICreateRasterizerState(const FRasterizerStateInitializerRHI& Initializer) final override;
        virtual FDepthStencilStateRHIRef RHICreateDepthStencilState(...) final override;
        
        (......)
        
    private:
        // 立即模式上下文.
        FMetalRHIImmediateCommandContext ImmediateContext;
        // 异步计算上下文.
        FMetalRHICommandContext* AsyncComputeContext;
        // 顶点声明缓存.
        TMap<uint32, FVertexDeclarationRHIRef> VertexDeclarationCache;
    };
    
    // Engine\Source\Runtime\D3D12RHI\Private\D3D12RHIPrivate.h
    
    class FD3D12DynamicRHI : public FDynamicRHI
    {
        static FD3D12DynamicRHI* SingleD3DRHI;
    
    public:
        static D3D12RHI_API FD3D12DynamicRHI* GetD3DRHI() { return SingleD3DRHI; }
    
        FD3D12DynamicRHI(const TArray<TSharedPtr<FD3D12Adapter>>& ChosenAdaptersIn, bool bInPixEventEnabled);
        virtual ~FD3D12DynamicRHI();
    
        // FDynamicRHI interface.
        virtual void Init() override;
        virtual void PostInit() override;
        virtual void Shutdown() override;
        virtual const TCHAR* GetName() override { return TEXT("D3D12"); }
    
        virtual FSamplerStateRHIRef RHICreateSamplerState(const FSamplerStateInitializerRHI& Initializer) final override;
        virtual FRasterizerStateRHIRef RHICreateRasterizerState(const FRasterizerStateInitializerRHI& Initializer) final override;
        virtual FDepthStencilStateRHIRef RHICreateDepthStencilState(const FDepthStencilStateInitializerRHI& Initializer) final override;
        
        (......)
        
    protected:
        // 已选择的适配器.
        TArray<TSharedPtr<FD3D12Adapter>> ChosenAdapters;
        // AMD AGS工具库上下文.
        AGSContext* AmdAgsContext;
    
        // D3D12设备.
        inline FD3D12Device* GetRHIDevice(uint32 GPUIndex)
        {
            return GetAdapter().GetDevice(GPUIndex);
        }
        
        (......)
    };
    
    // Engine\Source\Runtime\EmptyRHI\Public\EmptyRHI.h
    
    class FEmptyDynamicRHI : public FDynamicRHI, public IRHICommandContext
    {
        (......)
    };
    
    // Engine\Source\Runtime\NullDrv\Public\NullRHI.h
    
    class FNullDynamicRHI : public FDynamicRHI , public IRHICommandContextPSOFallback
    {
        (......)
    };
    
    
    class OPENGLDRV_API FOpenGLDynamicRHI  final : public FDynamicRHI, public IRHICommandContextPSOFallback
    {
    public:
        FOpenGLDynamicRHI();
        ~FOpenGLDynamicRHI();
    
        // FDynamicRHI interface.
        virtual void Init();
        virtual void PostInit();
    
        virtual void Shutdown();
        virtual const TCHAR* GetName() override { return TEXT("OpenGL"); }
        
        virtual FRasterizerStateRHIRef RHICreateRasterizerState(const FRasterizerStateInitializerRHI& Initializer) final override;
        virtual FDepthStencilStateRHIRef RHICreateDepthStencilState(const FDepthStencilStateInitializerRHI& Initializer) final override;
        virtual FBlendStateRHIRef RHICreateBlendState(const FBlendStateInitializerRHI& Initializer) final override;
        
        (......)
        
    private:
        // 计数器.
        uint32 SceneFrameCounter;
        uint32 ResourceTableFrameCounter;
    
        // RHI设备状态, 独立于使用的底层OpenGL上下文.
        FOpenGLRHIState                        PendingState;
        FOpenGLStreamedVertexBufferArray    DynamicVertexBuffers;
        FOpenGLStreamedIndexBufferArray        DynamicIndexBuffers;
        FSamplerStateRHIRef                    PointSamplerState;
    
        // 已创建的视口.
        TArray<FOpenGLViewport*> Viewports;
        TRefCountPtr<FOpenGLViewport>        DrawingViewport;
        bool                                bRevertToSharedContextAfterDrawingViewport;
    
        // 已绑定的着色器状态历史.
        TGlobalResource< TBoundShaderStateHistory<10000> > BoundShaderStateHistory;
    
        // 逐上下文状态缓存.
        FOpenGLContextState InvalidContextState;
        FOpenGLContextState    SharedContextState;
        FOpenGLContextState    RenderingContextState;
    
        // 统一缓冲区.
        TArray<FRHIUniformBuffer*> GlobalUniformBuffers;
        TMap<GLuint, TPair<GLenum, GLenum>> TextureMipLimits;
    
        // 底层平台相关的数据.
        FPlatformOpenGLDevice* PlatformDevice;
    
        // 查询相关.
        TArray<FOpenGLRenderQuery*> Queries;
        FCriticalSection QueriesListCriticalSection;
        
        // 配置和呈现数据.
        FOpenGLGPUProfiler GPUProfilingData;
        FCriticalSection CustomPresentSection;
        TRefCountPtr<class FRHICustomPresent> CustomPresent;
        
        (......)
    };
    
    // Engine\Source\Runtime\RHI\Public\RHIValidation.h
    
    class FValidationRHI : public FDynamicRHI
    {
    public:
        RHI_API FValidationRHI(FDynamicRHI* InRHI);
        RHI_API virtual ~FValidationRHI();
    
        virtual FSamplerStateRHIRef RHICreateSamplerState(const FSamplerStateInitializerRHI& Initializer) override final;
        virtual FRasterizerStateRHIRef RHICreateRasterizerState(const FRasterizerStateInitializerRHI& Initializer) override final;
        virtual FDepthStencilStateRHIRef RHICreateDepthStencilState(const FDepthStencilStateInitializerRHI& Initializer) override final;
        
        (......)
        
        // RHI实例.
        FDynamicRHI*    RHI;
        // 所属的上下文.
        TIndirectArray<IRHIComputeContext> OwnedContexts;
        // 深度模板状态列表.
        TMap<FRHIDepthStencilState*, FDepthStencilStateInitializerRHI> DepthStencilStates;
    };
    
    // Engine\Source\Runtime\VulkanRHI\Public\VulkanDynamicRHI.h
    
    class FVulkanDynamicRHI : public FDynamicRHI
    {
    public:
        FVulkanDynamicRHI();
        ~FVulkanDynamicRHI();
    
        // FDynamicRHI interface.
        virtual void Init() final override;
        virtual void PostInit() final override;
        virtual void Shutdown() final override;;
        virtual const TCHAR* GetName() final override { return TEXT("Vulkan"); }
    
        void InitInstance();
    
        virtual FSamplerStateRHIRef RHICreateSamplerState(const FSamplerStateInitializerRHI& Initializer) final override;
        virtual FRasterizerStateRHIRef RHICreateRasterizerState(const FRasterizerStateInitializerRHI& Initializer) final override;
        virtual FDepthStencilStateRHIRef RHICreateDepthStencilState(const FDepthStencilStateInitializerRHI& Initializer) final override;
        
        (......)
        
    protected:
        // 实例.
        VkInstance Instance;
        TArray<const ANSICHAR*> InstanceExtensions;
        TArray<const ANSICHAR*> InstanceLayers;
    
        // 设备.
        TArray<FVulkanDevice*> Devices;
        FVulkanDevice* Device;
    
        // 视口.
        TArray<FVulkanViewport*> Viewports;
        TRefCountPtr<FVulkanViewport> DrawingViewport;
    
        // 缓存.
        IConsoleObject* SavePipelineCacheCmd = nullptr;
        IConsoleObject* RebuildPipelineCacheCmd = nullptr;
    
        // 临界区.
        FCriticalSection LockBufferCS;
    
        // 内部接口.
        void CreateInstance();
        void SelectAndInitDevice();
        void InitGPU(FVulkanDevice* Device);
        void InitDevice(FVulkanDevice* Device);
        
        (......)
    };
    
    // Engine\Source\Runtime\Windows\D3D11RHI\Private\D3D11RHIPrivate.h
    
    class D3D11RHI_API FD3D11DynamicRHI : public FDynamicRHI, public IRHICommandContextPSOFallback
    {
    public:
        FD3D11DynamicRHI(IDXGIFactory1* InDXGIFactory1,D3D_FEATURE_LEVEL InFeatureLevel,int32 InChosenAdapter, const DXGI_ADAPTER_DESC& ChosenDescription);
        virtual ~FD3D11DynamicRHI();
    
        virtual void InitD3DDevice();
    
        // FDynamicRHI interface.
        virtual void Init() override;
        virtual void PostInit() override;
        virtual void Shutdown() override;
        virtual const TCHAR* GetName() override { return TEXT("D3D11"); }
    
        // HDR display output
        virtual void EnableHDR();
        virtual void ShutdownHDR();
    
        virtual FSamplerStateRHIRef RHICreateSamplerState(const FSamplerStateInitializerRHI& Initializer) final override;
        virtual FRasterizerStateRHIRef RHICreateRasterizerState(const FRasterizerStateInitializerRHI& Initializer) final override;
        virtual FDepthStencilStateRHIRef RHICreateDepthStencilState(const FDepthStencilStateInitializerRHI& Initializer) final override;
        
        (......)
    
        ID3D11Device* GetDevice() const
        {
            return Direct3DDevice;
        }
        FD3D11DeviceContext* GetDeviceContext() const
        {
            return Direct3DDeviceIMContext;
        }
        IDXGIFactory1* GetFactory() const
        {
            return DXGIFactory1;
        }
        
    protected:
        // D3D工厂(接口).
        TRefCountPtr<IDXGIFactory1> DXGIFactory1;
         // D3D设备.
        TRefCountPtr<FD3D11Device> Direct3DDevice;
        // D3D设备的立即上下文.
        TRefCountPtr<FD3D11DeviceContext> Direct3DDeviceIMContext;
    
        // 线程锁.
        FD3D11LockTracker LockTracker;
        FCriticalSection LockTrackerCS;
    
        // 视口.
        TArray<FD3D11Viewport*> Viewports;
        TRefCountPtr<FD3D11Viewport> DrawingViewport;
    
        // AMD AGS工具库上下文.
        AGSContext* AmdAgsContext;
    
        // RT, UAV, 着色器等资源.
        TRefCountPtr<ID3D11RenderTargetView> CurrentRenderTargets[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT];
        TRefCountPtr<FD3D11UnorderedAccessView> CurrentUAVs[D3D11_PS_CS_UAV_REGISTER_COUNT];
        ID3D11UnorderedAccessView* UAVBound[D3D11_PS_CS_UAV_REGISTER_COUNT];
        TRefCountPtr<ID3D11DepthStencilView> CurrentDepthStencilTarget;
        TRefCountPtr<FD3D11TextureBase> CurrentDepthTexture;
        FD3D11BaseShaderResource* CurrentResourcesBoundAsSRVs[SF_NumStandardFrequencies][D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT];
        FD3D11BaseShaderResource* CurrentResourcesBoundAsVBs[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
        FD3D11BaseShaderResource* CurrentResourceBoundAsIB;
        int32 MaxBoundShaderResourcesIndex[SF_NumStandardFrequencies];
        FUniformBufferRHIRef BoundUniformBuffers[SF_NumStandardFrequencies][MAX_UNIFORM_BUFFERS_PER_SHADER_STAGE];
        uint16 DirtyUniformBuffers[SF_NumStandardFrequencies];
        TArray<FRHIUniformBuffer*> GlobalUniformBuffers;
    
        // 已创建的常量缓冲区.
        TArray<TRefCountPtr<FD3D11ConstantBuffer> > VSConstantBuffers;
        TArray<TRefCountPtr<FD3D11ConstantBuffer> > HSConstantBuffers;
        TArray<TRefCountPtr<FD3D11ConstantBuffer> > DSConstantBuffers;
        TArray<TRefCountPtr<FD3D11ConstantBuffer> > PSConstantBuffers;
        TArray<TRefCountPtr<FD3D11ConstantBuffer> > GSConstantBuffers;
        TArray<TRefCountPtr<FD3D11ConstantBuffer> > CSConstantBuffers;
    
        // 已绑定的着色器状态历史.
        TGlobalResource< TBoundShaderStateHistory<10000> > BoundShaderStateHistory;
        FComputeShaderRHIRef CurrentComputeShader;
    
        (......)
    };

    它们的核心继承UML图如下:

    需要注意的是,传统图形API(D3D11、OpenGL)除了继承FDynamicRHI,还需要继承IRHICommandContextPSOFallback,因为需要借助后者的接口处理PSO的数据和行为,以保证传统和现代API对PSO的一致处理行为。

    也正因为此,现代图形API(D3D12、Vulkan、Metal)不需要继承IRHICommandContext的任何继承体系的类型,单单直接继承FDynamicRHI就可以处理RHI层的所有数据和操作。

    既然现代图形API(D3D12、Vulkan、Metal)的DynamicRHI没有继承IRHICommandContext的任何继承体系的类型,那么它们是如何实现FDynamicRHI::RHIGetDefaultContext的接口?

    下面以FD3D12DynamicRHI为例:

    IRHICommandContext* FD3D12DynamicRHI::RHIGetDefaultContext()
    {
        FD3D12Adapter& Adapter = GetAdapter();
    
        IRHICommandContext* DefaultCommandContext = nullptr;    
        if (GNumExplicitGPUsForRendering > 1) // 多GPU
        {
            DefaultCommandContext = static_cast<IRHICommandContext*>(&Adapter.GetDefaultContextRedirector());
        }
        else // 单GPU
        {
            FD3D12Device* Device = Adapter.GetDevice(0);
            DefaultCommandContext = static_cast<IRHICommandContext*>(&Device->GetDefaultCommandContext());
        }
    
        return DefaultCommandContext;
    }

    无论是单GPU还是多GPU,都是从FD3D12CommandContext强制转换而来,而FD3D12CommandContext又是IRHICommandContext的子子子类,因此静态类型转换完全没问题。

    FD3D11DynamicRHI

    FD3D11DynamicRHI包含或引用了若干D3D11平台相关的核心类型,它们的定义如下所示:

    // Engine\Source\Runtime\Windows\D3D11RHI\Private\D3D11RHIPrivate.h
    
    class D3D11RHI_API FD3D11DynamicRHI : public FDynamicRHI, public IRHICommandContextPSOFallback
    {
        (......)
    
    protected:
        // D3D工厂(接口).
        TRefCountPtr<IDXGIFactory1> DXGIFactory1;
         // D3D设备.
        TRefCountPtr<FD3D11Device> Direct3DDevice;
        // D3D设备的立即上下文.
        TRefCountPtr<FD3D11DeviceContext> Direct3DDeviceIMContext;
    
        // 视口.
        TArray<FD3D11Viewport*> Viewports;
        TRefCountPtr<FD3D11Viewport> DrawingViewport;
    
        // AMD AGS工具库上下文.
        AGSContext* AmdAgsContext;
    
        (......)
    };
    
    // Engine\Source\Runtime\Windows\D3D11RHI\Private\Windows\D3D11RHIBasePrivate.h
    
    typedef ID3D11DeviceContext FD3D11DeviceContext;
    typedef ID3D11Device FD3D11Device;
    
    // Engine\Source\Runtime\Windows\D3D11RHI\Public\D3D11Viewport.h
    
    class FD3D11Viewport : public FRHIViewport
    {
    public:
        FD3D11Viewport(class FD3D11DynamicRHI* InD3DRHI) : D3DRHI(InD3DRHI), PresentFailCount(0), ValidState (0), FrameSyncEvent(InD3DRHI);
        FD3D11Viewport(class FD3D11DynamicRHI* InD3DRHI, HWND InWindowHandle, uint32 InSizeX, uint32 InSizeY, bool bInIsFullscreen, EPixelFormat InPreferredPixelFormat);
        ~FD3D11Viewport();
    
        virtual void Resize(uint32 InSizeX, uint32 InSizeY, bool bInIsFullscreen, EPixelFormat PreferredPixelFormat);
        void ConditionalResetSwapChain(bool bIgnoreFocus);
        void CheckHDRMonitorStatus();
    
        // 呈现交换链.
        bool Present(bool bLockToVsync);
    
        // Accessors.
        FIntPoint GetSizeXY() const;
        FD3D11Texture2D* GetBackBuffer() const;
        EColorSpaceAndEOTF GetPixelColorSpace() const;
    
        void WaitForFrameEventCompletion();
        void IssueFrameEvent()
    
        IDXGISwapChain* GetSwapChain() const;
        virtual void* GetNativeSwapChain() const override;
        virtual void* GetNativeBackBufferTexture() const override;
        virtual void* GetNativeBackBufferRT() const overrid;
    
        virtual void SetCustomPresent(FRHICustomPresent* InCustomPresent) override
        virtual FRHICustomPresent* GetCustomPresent() const;
    
        virtual void* GetNativeWindow(void** AddParam = nullptr) const override;
        static FD3D11Texture2D* GetSwapChainSurface(FD3D11DynamicRHI* D3DRHI, EPixelFormat PixelFormat, uint32 SizeX, uint32 SizeY, IDXGISwapChain* SwapChain);
    
    protected:
        // 动态RHI.
        FD3D11DynamicRHI* D3DRHI;
        // 交换链.
        TRefCountPtr<IDXGISwapChain> SwapChain;
        // 后渲染缓冲.
        TRefCountPtr<FD3D11Texture2D> BackBuffer;
    
        FD3D11EventQuery FrameSyncEvent;
        FCustomPresentRHIRef CustomPresent;
    
        (......)
    };

    FD3D11DynamicRHI绘制成UML图之后如下所示:

    FOpenGLDynamicRHI

    FOpenGLDynamicRHI相关的核心类型定义如下:

    class OPENGLDRV_API FOpenGLDynamicRHI  final : public FDynamicRHI, public IRHICommandContextPSOFallback
    {
        (......)
        
    private:
        // 已创建的视口.
        TArray<FOpenGLViewport*> Viewports;
        // 底层平台相关的数据.
        FPlatformOpenGLDevice* PlatformDevice;
    };
    
    // Engine\Source\Runtime\OpenGLDrv\Public\OpenGLResources.h
    
    class FOpenGLViewport : public FRHIViewport
    {
    public:
        FOpenGLViewport(class FOpenGLDynamicRHI* InOpenGLRHI,void* InWindowHandle,uint32 InSizeX,uint32 InSizeY,bool bInIsFullscreen,EPixelFormat PreferredPixelFormat);
        ~FOpenGLViewport();
    
        void Resize(uint32 InSizeX,uint32 InSizeY,bool bInIsFullscreen);
    
        // Accessors.
        FIntPoint GetSizeXY() const;
        FOpenGLTexture2D *GetBackBuffer() const;
        bool IsFullscreen( void ) const;
    
        void WaitForFrameEventCompletion();
        void IssueFrameEvent();
        virtual void* GetNativeWindow(void** AddParam) const override;
    
        struct FPlatformOpenGLContext* GetGLContext() const;
        FOpenGLDynamicRHI* GetOpenGLRHI() const;
    
        virtual void SetCustomPresent(FRHICustomPresent* InCustomPresent) override;
        FRHICustomPresent* GetCustomPresent() const;
        
    private:
        FOpenGLDynamicRHI* OpenGLRHI;
        struct FPlatformOpenGLContext* OpenGLContext;
        uint32 SizeX;
        uint32 SizeY;
        bool bIsFullscreen;
        EPixelFormat PixelFormat;
        bool bIsValid;
        TRefCountPtr<FOpenGLTexture2D> BackBuffer;
        FOpenGLEventQuery FrameSyncEvent;
        FCustomPresentRHIRef CustomPresent;
    };
    
    // Engine\Source\Runtime\OpenGLDrv\Private\Android\AndroidOpenGL.cpp
    
    // 安卓系统的OpenGL设备.
    struct FPlatformOpenGLDevice
    {
        bool TargetDirty;
    
        void SetCurrentSharedContext();
        void SetCurrentRenderingContext();
        void SetupCurrentContext();
        void SetCurrentNULLContext();
    
        FPlatformOpenGLDevice();
        ~FPlatformOpenGLDevice();
        
        void Init();
        void LoadEXT();
        void Terminate();
        void ReInit();
    };
    
    // Engine\Source\Runtime\OpenGLDrv\Private\Windows\OpenGLWindows.cpp
    
    // Windows系统的OpenGL设备.
    struct FPlatformOpenGLDevice
    {
        FPlatformOpenGLContext    SharedContext;
        FPlatformOpenGLContext    RenderingContext;
        TArray<FPlatformOpenGLContext*>    ViewportContexts;
        bool                    TargetDirty;
    
        /** Guards against operating on viewport contexts from more than one thread at the same time. */
        FCriticalSection*        ContextUsageGuard;
    };
    
    // Engine\Source\Runtime\OpenGLDrv\Private\Lumin\LuminOpenGL.cpp
    
    // Lumin系统的OpenGL设备.
    struct FPlatformOpenGLDevice
    {
        void SetCurrentSharedContext();
        void SetCurrentRenderingContext();
        void SetCurrentNULLContext();
    
        FPlatformOpenGLDevice();
        ~FPlatformOpenGLDevice();
        
        void Init();
        void LoadEXT();
        void Terminate();
        void ReInit();
    };
    
    // Engine\Source\Runtime\OpenGLDrv\Private\Linux\OpenGLLinux.cpp
    
    // Linux系统的OpenGL设备.
    struct FPlatformOpenGLDevice
    {
        FPlatformOpenGLContext    SharedContext;
        FPlatformOpenGLContext    RenderingContext;
        int32                    NumUsedContexts;
        FCriticalSection*        ContextUsageGuard;
    };
    
    // Engine\Source\Runtime\OpenGLDrv\Private\Lumin\LuminGL4.cpp
    
    // Lumin系统的OpenGL设备.
    struct FPlatformOpenGLDevice
    {
        FPlatformOpenGLContext    SharedContext;
        FPlatformOpenGLContext    RenderingContext;
        TArray<FPlatformOpenGLContext*>    ViewportContexts;
        bool                    TargetDirty;
        FCriticalSection*        ContextUsageGuard;
    };
    以上显示不同操作系统,OpenGL设备对象的定义有所不同。实际上,OpenGL上下文也因操作系统而异,下面以Windows为例:
    
    // Engine\Source\Runtime\OpenGLDrv\Private\Windows\OpenGLWindows.cpp
    
    struct FPlatformOpenGLContext
    {
        // 窗口句柄
        HWND WindowHandle;
        // 设备上下文.
        HDC DeviceContext;
        // OpenGL上下文.
        HGLRC OpenGLContext;
        
        // 其它实际.
        bool bReleaseWindowOnDestroy;
        int32 SyncInterval;
        GLuint    ViewportFramebuffer;
        GLuint    VertexArrayObject;    // one has to be generated and set for each context (OpenGL 3.2 Core requirements)
        GLuint    BackBufferResource;
        GLenum    BackBufferTarget;
    };

    FOpenGLDynamicRHI绘制成的UML图如下所示:

    FD3D12DynamicRHI

    FD3D12DynamicRHI的核心类型定义如下:

    // Engine\Source\Runtime\D3D12RHI\Private\D3D12RHIPrivate.h
    
    class FD3D12DynamicRHI : public FDynamicRHI
    {
        (......)
        
    protected:
        // 已选择的适配器.
        TArray<TSharedPtr<FD3D12Adapter>> ChosenAdapters;
    
        // D3D12设备.
        inline FD3D12Device* GetRHIDevice(uint32 GPUIndex)
        {
            return GetAdapter().GetDevice(GPUIndex);
        }
        
        (......)
    };
    
    // Engine\Source\Runtime\D3D12RHI\Private\D3D12Adapter.h
    
    class FD3D12Adapter : public FNoncopyable
    {
    public:
        void Initialize(FD3D12DynamicRHI* RHI);
        void InitializeDevices();
        void InitializeRayTracing();
        
        // 资源创建.
        HRESULT CreateCommittedResource(...)
        HRESULT CreateBuffer(...);
        template <typename BufferType> 
        BufferType* CreateRHIBuffer(...);
    
        inline FD3D12CommandContextRedirector& GetDefaultContextRedirector();
        inline FD3D12CommandContextRedirector& GetDefaultAsyncComputeContextRedirector();
        FD3D12FastConstantAllocator& GetTransientUniformBufferAllocator();
    
        void BlockUntilIdle();
        
        (......)
    
    protected:
        virtual void CreateRootDevice(bool bWithDebug);
    
        FD3D12DynamicRHI* OwningRHI;
    
        // LDA设置拥有一个ID3D12Device
        TRefCountPtr<ID3D12Device> RootDevice;
        TRefCountPtr<ID3D12Device1> RootDevice1;
        
        TRefCountPtr<IDXGIAdapter> DxgiAdapter;
        
        TRefCountPtr<IDXGIFactory> DxgiFactory;
        TRefCountPtr<IDXGIFactory2> DxgiFactory2;
        
        // 每个设备代表一个物理GPU“节点”.
        FD3D12Device* Devices[MAX_NUM_GPUS];
        
        FD3D12CommandContextRedirector DefaultContextRedirector;
        FD3D12CommandContextRedirector DefaultAsyncComputeContextRedirector;
        
        TArray<FD3D12Viewport*> Viewports;
        TRefCountPtr<FD3D12Viewport> DrawingViewport;
    
        (......)
    };
    
    // Engine\Source\Runtime\D3D12RHI\Private\D3D12RHICommon.h
    
    class FD3D12AdapterChild
    {
    protected:
        FD3D12Adapter* ParentAdapter;
    
        (......)
    };
    
    class FD3D12DeviceChild
    {
    protected:
        FD3D12Device* Parent;
        
        (......)
    };
    
    // Engine\Source\Runtime\D3D12RHI\Private\D3D12Device.h
    
    class FD3D12Device : public FD3D12SingleNodeGPUObject, public FNoncopyable, public FD3D12AdapterChild
    {
    public:
        TArray<FD3D12CommandListHandle> PendingCommandLists;
        
        void Initialize();
        void CreateCommandContexts();
        void InitPlatformSpecific();
        virtual void Cleanup();
        bool GetQueryData(FD3D12RenderQuery& Query, bool bWait);
    
        ID3D12Device* GetDevice();
    
        void BlockUntilIdle();
        bool IsGPUIdle();
    
        FD3D12SamplerState* CreateSampler(const FSamplerStateInitializerRHI& Initializer);
    
        (......)
        
    protected:
        // CommandListManager
        FD3D12CommandListManager* CommandListManager;
        FD3D12CommandListManager* CopyCommandListManager;
        FD3D12CommandListManager* AsyncCommandListManager;
        FD3D12CommandAllocatorManager TextureStreamingCommandAllocatorManager;
    
        // Allocator
        FD3D12OfflineDescriptorManager RTVAllocator;
        FD3D12OfflineDescriptorManager DSVAllocator;
        FD3D12OfflineDescriptorManager SRVAllocator;
        FD3D12OfflineDescriptorManager UAVAllocator;
        FD3D12DefaultBufferAllocator DefaultBufferAllocator;
    
        // FD3D12CommandContext
        TArray<FD3D12CommandContext*> CommandContextArray;
        TArray<FD3D12CommandContext*> FreeCommandContexts;
        TArray<FD3D12CommandContext*> AsyncComputeContextArray;
    
        (......)
    };
    
    // Engine\Source\Runtime\D3D12RHI\Public\D3D12Viewport.h
    
    class FD3D12Viewport : public FRHIViewport, public FD3D12AdapterChild
    {
    public:
        void Init();
        void Resize(uint32 InSizeX, uint32 InSizeY, bool bInIsFullscreen, EPixelFormat PreferredPixelFormat);
    
        void ConditionalResetSwapChain(bool bIgnoreFocus);
        bool Present(bool bLockToVsync);
    
        void WaitForFrameEventCompletion();
        bool CurrentOutputSupportsHDR() const;
    
        (......)
        
    private:
        HWND WindowHandle;
    
    #if D3D12_VIEWPORT_EXPOSES_SWAP_CHAIN
        TRefCountPtr<IDXGISwapChain1> SwapChain1;
        TRefCountPtr<IDXGISwapChain4> SwapChain4;
    #endif
    
        TArray<TRefCountPtr<FD3D12Texture2D>> BackBuffers;
        TRefCountPtr<FD3D12Texture2D> DummyBackBuffer_RenderThread;
        uint32 CurrentBackBufferIndex_RHIThread;
        FD3D12Texture2D* BackBuffer_RHIThread;
        TArray<TRefCountPtr<FD3D12Texture2D>> SDRBackBuffers;
        TRefCountPtr<FD3D12Texture2D> SDRDummyBackBuffer_RenderThread;
        FD3D12Texture2D* SDRBackBuffer_RHIThread;
    
        bool CheckHDRSupport();
        void EnableHDR();
        void ShutdownHDR();
        
        (......)
    };
    
    // Engine\Source\Runtime\D3D12RHI\Private\D3D12CommandContext.h
    
    class FD3D12CommandContextBase : public IRHICommandContext, public FD3D12AdapterChild
    {
    public:
        FD3D12CommandContextBase(class FD3D12Adapter* InParent, FRHIGPUMask InGPUMask, bool InIsDefaultContext, bool InIsAsyncComputeContext);
    
        void RHIBeginDrawingViewport(FRHIViewport* Viewport, FRHITexture* RenderTargetRHI) final override;
        void RHIEndDrawingViewport(FRHIViewport* Viewport, bool bPresent, bool bLockToVsync) final override;
        void RHIBeginFrame() final override;
        void RHIEndFrame() final override;
    
        (......)
    
    protected:
        virtual FD3D12CommandContext* GetContext(uint32 InGPUIndex) = 0;
    
        FRHIGPUMask GPUMask;
        
        (......)
    };
    
    class FD3D12CommandContext : public FD3D12CommandContextBase, public FD3D12DeviceChild
    {
    public:
        FD3D12CommandContext(class FD3D12Device* InParent, bool InIsDefaultContext, bool InIsAsyncComputeContext);
        virtual ~FD3D12CommandContext();
    
        void EndFrame();
        void ConditionalObtainCommandAllocator();
        void ReleaseCommandAllocator();
    
        FD3D12CommandListManager& GetCommandListManager();
        void OpenCommandList();
        void CloseCommandList();
    
        FD3D12CommandListHandle FlushCommands(bool WaitForCompletion = false, EFlushCommandsExtraAction ExtraAction = FCEA_None);
        void Finish(TArray<FD3D12CommandListHandle>& CommandLists);
    
        FD3D12FastConstantAllocator ConstantsAllocator;
        FD3D12CommandListHandle CommandListHandle;
        FD3D12CommandAllocator* CommandAllocator;
        FD3D12CommandAllocatorManager CommandAllocatorManager;
    
        FD3D12DynamicRHI& OwningRHI;
    
        // State Block.
        FD3D12RenderTargetView* CurrentRenderTargets[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT];
        FD3D12DepthStencilView* CurrentDepthStencilTarget;
        FD3D12TextureBase* CurrentDepthTexture;
        uint32 NumSimultaneousRenderTargets;
    
        // Uniform Buffer.
        FD3D12UniformBuffer* BoundUniformBuffers[SF_NumStandardFrequencies][MAX_CBS];
        FUniformBufferRHIRef BoundUniformBufferRefs[SF_NumStandardFrequencies][MAX_CBS];
        uint16 DirtyUniformBuffers[SF_NumStandardFrequencies];
    
        // 常量缓冲区.
        FD3D12ConstantBuffer VSConstantBuffer;
        FD3D12ConstantBuffer HSConstantBuffer;
        FD3D12ConstantBuffer DSConstantBuffer;
        FD3D12ConstantBuffer PSConstantBuffer;
        FD3D12ConstantBuffer GSConstantBuffer;
        FD3D12ConstantBuffer CSConstantBuffer;
    
        template <class ShaderType> void SetResourcesFromTables(const ShaderType* RESTRICT);
        template <class ShaderType> uint32 SetUAVPSResourcesFromTables(const ShaderType* RESTRICT Shader);
        void CommitGraphicsResourceTables();
        void CommitComputeResourceTables(FD3D12ComputeShader* ComputeShader);
        void ValidateExclusiveDepthStencilAccess(FExclusiveDepthStencil Src) const;
        void CommitRenderTargetsAndUAVs();
    
        virtual void SetDepthBounds(float MinDepth, float MaxDepth);
        virtual void SetShadingRate(EVRSShadingRate ShadingRate, EVRSRateCombiner Combiner);
    
        (......)
    
    protected:
        FD3D12CommandContext* GetContext(uint32 InGPUIndex) final override;
        TArray<FRHIUniformBuffer*> GlobalUniformBuffers;
    };
    
    class FD3D12CommandContextRedirector final : public FD3D12CommandContextBase
    {
    public:
        FD3D12CommandContextRedirector(class FD3D12Adapter* InParent, bool InIsDefaultContext, bool InIsAsyncComputeContext);
    
        virtual void RHISetComputeShader(FRHIComputeShader* ComputeShader) final override;
        virtual void RHISetComputePipelineState(FRHIComputePipelineState* ComputePipelineState) final override;
        virtual void RHIDispatchComputeShader(uint32 ThreadGroupCountX, uint32 ThreadGroupCountY, uint32 ThreadGroupCountZ) final override;
        
        (......)
        
    private:
        FRHIGPUMask PhysicalGPUMask;
        FD3D12CommandContext* PhysicalContexts[MAX_NUM_GPUS];
    };
    
    // Engine\Source\Runtime\D3D12RHI\Private\D3D12CommandContext.cpp
    
    class FD3D12CommandContextContainer : public IRHICommandContextContainer
    {
        FD3D12Adapter* Adapter;
        FD3D12CommandContext* CmdContext;
        FD3D12CommandContextRedirector* CmdContextRedirector;
        FRHIGPUMask GPUMask;
        TArray<FD3D12CommandListHandle> CommandLists;
    
        (......)
    };

    以上可知,D3D12涉及的核心类型非常多,涉及多层级的复杂的数据结构链,其内存布局如下所示:

    [Engine]--
            |
            |-[RHI]--
                    |
                    |-[Adapter]-- (LDA)
                    |            |
                    |            |- [Device]
                    |            |
                    |            |- [Device]
                    |
                    |-[Adapter]--
                                |
                                |- [Device]--
                                            |
                                            |-[CommandContext]
                                            |
                                            |-[CommandContext]---
                                                                |
                                                                |-[StateCache]

    在这种方案下,FD3D12Device表示1个节点,属于1个物理适配器。这种结构允许一个RHI控制几个不同类型的硬件设置,例如:

    • 单GPU系统(常规案例)。
    • 多GPU系统,如LDA(Crossfire/SLI)。
    • 非对称多GPU系统,如分离、集成GPU协作系统。

    将D3D12的核心类抽象成UML图之后,如下所示:

    FVulkanDynamicRHI

    FVulkanDynamicRHI涉及的核心类如下:

    // Engine\Source\Runtime\VulkanRHI\Public\VulkanDynamicRHI.h
    
    class FVulkanDynamicRHI : public FDynamicRHI
    {
    public:
        // FDynamicRHI interface.
        virtual void Init() final override;
        virtual void PostInit() final override;
        virtual void Shutdown() final override;;
        void InitInstance();
    
        (......)
        
    protected:
        // 实例.
        VkInstance Instance;
        
        // 设备.
        TArray<FVulkanDevice*> Devices;
        FVulkanDevice* Device;
    
        // 视口.
        TArray<FVulkanViewport*> Viewports;
        
        (......)
    };
    
    // Engine\Source\Runtime\VulkanRHI\Private\VulkanDevice.h
    
    class FVulkanDevice
    {
    public:
        FVulkanDevice(FVulkanDynamicRHI* InRHI, VkPhysicalDevice Gpu);
        ~FVulkanDevice();
    
        bool QueryGPU(int32 DeviceIndex);
        void InitGPU(int32 DeviceIndex);
        void CreateDevice();
        void PrepareForDestroy();
        void Destroy();
    
        void WaitUntilIdle();
        void PrepareForCPURead();
        void SubmitCommandsAndFlushGPU();
    
        (......)
        
    private:
        void SubmitCommands(FVulkanCommandListContext* Context);
    
        // vk设备.
        VkDevice Device;
        // vk物理设备.
        VkPhysicalDevice Gpu;
        
        VkPhysicalDeviceProperties GpuProps;
        VkPhysicalDeviceFeatures PhysicalFeatures;
    
        // 管理器.
        VulkanRHI::FDeviceMemoryManager DeviceMemoryManager;
        VulkanRHI::FMemoryManager MemoryManager;
        VulkanRHI::FDeferredDeletionQueue2 DeferredDeletionQueue;
        VulkanRHI::FStagingManager StagingManager;
        VulkanRHI::FFenceManager FenceManager;
        FVulkanDescriptorPoolsManager* DescriptorPoolsManager = nullptr;
        
        FVulkanDescriptorSetCache* DescriptorSetCache = nullptr;
        FVulkanShaderFactory ShaderFactory;
    
        // 队列.
        FVulkanQueue* GfxQueue;
        FVulkanQueue* ComputeQueue;
        FVulkanQueue* TransferQueue;
        FVulkanQueue* PresentQueue;
    
        // GPU品牌.
        EGpuVendorId VendorId = EGpuVendorId::NotQueried;
    
        // 命令队列上下文.
        FVulkanCommandListContextImmediate* ImmediateContext;
        FVulkanCommandListContext* ComputeContext;
        TArray<FVulkanCommandListContext*> CommandContexts;
    
        FVulkanDynamicRHI* RHI = nullptr;
        class FVulkanPipelineStateCacheManager* PipelineStateCache;
        
        (......)
    };
    
    // Engine\Source\Runtime\VulkanRHI\Private\VulkanQueue.h
    
    class FVulkanQueue
    {
    public:
        FVulkanQueue(FVulkanDevice* InDevice, uint32 InFamilyIndex);
        ~FVulkanQueue();
    
        void Submit(FVulkanCmdBuffer* CmdBuffer, uint32 NumSignalSemaphores = 0, VkSemaphore* SignalSemaphores = nullptr);
        void Submit(FVulkanCmdBuffer* CmdBuffer, VkSemaphore SignalSemaphore);
    
        void GetLastSubmittedInfo(FVulkanCmdBuffer*& OutCmdBuffer, uint64& OutFenceCounter) const;
    
        (......)
        
    private:
        // vk队列
        VkQueue Queue;
        // 家族索引.
        uint32 FamilyIndex;
        // 队列索引.
        uint32 QueueIndex;
        FVulkanDevice* Device;
    
        // vk命令缓冲.
        FVulkanCmdBuffer* LastSubmittedCmdBuffer;
        uint64 LastSubmittedCmdBufferFenceCounter;
        uint64 SubmitCounter;
        mutable FCriticalSection CS;
    
        void UpdateLastSubmittedCommandBuffer(FVulkanCmdBuffer* CmdBuffer);
    };
    
    // Engine\Source\Runtime\VulkanRHI\Public\VulkanMemory.h
    
    // 设备子节点.
    class FDeviceChild
    {
    public:
        FDeviceChild(FVulkanDevice* InDevice = nullptr);
        
        (......)
        
     protected:
        FVulkanDevice* Device;
    };
    
    // Engine\Source\Runtime\VulkanRHI\Private\VulkanContext.h
    
    class FVulkanCommandListContext : public IRHICommandContext
    {
    public:
        FVulkanCommandListContext(FVulkanDynamicRHI* InRHI, FVulkanDevice* InDevice, FVulkanQueue* InQueue, FVulkanCommandListContext* InImmediate);
        virtual ~FVulkanCommandListContext();
    
        static inline FVulkanCommandListContext& GetVulkanContext(IRHICommandContext& CmdContext);
    
        inline bool IsImmediate() const;
    
        virtual void RHISetStreamSource(uint32 StreamIndex, FRHIVertexBuffer* VertexBuffer, uint32 Offset) final override;
        virtual void RHISetViewport(float MinX, float MinY, float MinZ, float MaxX, float MaxY, float MaxZ) final override;
        virtual void RHISetScissorRect(bool bEnable, uint32 MinX, uint32 MinY, uint32 MaxX, uint32 MaxY) final override;
        
        (......)
    
        inline FVulkanDevice* GetDevice() const;
        void PrepareParallelFromBase(const FVulkanCommandListContext& BaseContext);
    
    protected:
        FVulkanDynamicRHI* RHI;
        FVulkanCommandListContext* Immediate;
        FVulkanDevice* Device;
        FVulkanQueue* Queue;
        
        FVulkanUniformBufferUploader* UniformBufferUploader;
        FVulkanCommandBufferManager* CommandBufferManager;
        static FVulkanLayoutManager LayoutManager;
    
    private:
        FVulkanGPUProfiler GpuProfiler;
        TArray<FRHIUniformBuffer*> GlobalUniformBuffers;
        
        (......)
    };
    
    // 立即模式的命令队列上下文.
    class FVulkanCommandListContextImmediate : public FVulkanCommandListContext
    {
    public:
        FVulkanCommandListContextImmediate(FVulkanDynamicRHI* InRHI, FVulkanDevice* InDevice, FVulkanQueue* InQueue);
    };
    
    // 命令上下文容器.
    struct FVulkanCommandContextContainer : public IRHICommandContextContainer, public VulkanRHI::FDeviceChild
    {
        FVulkanCommandListContext* CmdContext;
    
        FVulkanCommandContextContainer(FVulkanDevice* InDevice);
    
        virtual IRHICommandContext* GetContext() override final;
        virtual void FinishContext() override final;
        virtual void SubmitAndFreeContextContainer(int32 Index, int32 Num) override final;
        
        void* operator new(size_t Size);
        void operator delete(void* RawMemory);
        
        (......)
    };
    
    // Engine\Source\Runtime\VulkanRHI\Private\VulkanViewport.h
    
    class FVulkanViewport : public FRHIViewport, public VulkanRHI::FDeviceChild
    {
    public:
        FVulkanViewport(FVulkanDynamicRHI* InRHI, FVulkanDevice* InDevice, void* InWindowHandle, uint32 InSizeX,uint32 InSizeY,bool bInIsFullscreen, EPixelFormat InPreferredPixelFormat);
        ~FVulkanViewport();
    
        void AdvanceBackBufferFrame(FRHICommandListImmediate& RHICmdList);
        void WaitForFrameEventCompletion();
    
        virtual void SetCustomPresent(FRHICustomPresent* InCustomPresent) override final;
        virtual FRHICustomPresent* GetCustomPresent() const override final;
        virtual void Tick(float DeltaTime) override final;
        bool Present(FVulkanCommandListContext* Context, FVulkanCmdBuffer* CmdBuffer, FVulkanQueue* Queue, FVulkanQueue* PresentQueue, bool bLockToVsync);
    
        (......)
        
    protected:
        TArray<VkImage, TInlineAllocator<NUM_BUFFERS*2>> BackBufferImages;
        TArray<VulkanRHI::FSemaphore*, TInlineAllocator<NUM_BUFFERS*2>> RenderingDoneSemaphores;
        TArray<FVulkanTextureView, TInlineAllocator<NUM_BUFFERS*2>> TextureViews;
        TRefCountPtr<FVulkanBackBuffer> RHIBackBuffer;
        TRefCountPtr<FVulkanTexture2D>    RenderingBackBuffer;
        
        /** narrow-scoped section that locks access to back buffer during its recreation*/
        FCriticalSection RecreatingSwapchain;
    
        FVulkanDynamicRHI* RHI;
        FVulkanSwapChain* SwapChain;
        void* WindowHandle;
        VulkanRHI::FSemaphore* AcquiredSemaphore;
        FCustomPresentRHIRef CustomPresent;
        FVulkanCmdBuffer* LastFrameCommandBuffer = nullptr;
        
        (......)
    };

    若将Vulkan RHI的核心类型绘制成UML图,则是如下图所示:

    FMetalDynamicRHI

    FMetalDynamicRHI的核心类型定义如下:

    // Engine\Source\Runtime\Apple\MetalRHI\Private\MetalDynamicRHI.h
    
    class FMetalDynamicRHI : public FDynamicRHI
    {
    public:
        // FDynamicRHI interface.
        virtual void Init();
        virtual void Shutdown() {}
        
        (......)
        
    private:
        // 立即模式上下文.
        FMetalRHIImmediateCommandContext ImmediateContext;
        // 异步计算上下文.
        FMetalRHICommandContext* AsyncComputeContext;
        
        (......)
    };
    
    // Engine\Source\Runtime\Apple\MetalRHI\Public\MetalRHIContext.h
    
    class FMetalRHICommandContext : public IRHICommandContext
    {
    public:
        FMetalRHICommandContext(class FMetalProfiler* InProfiler, FMetalContext* WrapContext);
        virtual ~FMetalRHICommandContext();
    
        virtual void RHISetComputeShader(FRHIComputeShader* ComputeShader) override;
        virtual void RHISetComputePipelineState(FRHIComputePipelineState* ComputePipelineState) override;
        virtual void RHIDispatchComputeShader(uint32 ThreadGroupCountX, uint32 ThreadGroupCountY, uint32 ThreadGroupCountZ) final override;
        
        (......)
    
    protected:
        // Metal上下文.
        FMetalContext* Context;
        
        TSharedPtr<FMetalCommandBufferFence, ESPMode::ThreadSafe> CommandBufferFence;
        class FMetalProfiler* Profiler;
        FMetalBuffer PendingVertexBuffer;
    
        TArray<FRHIUniformBuffer*> GlobalUniformBuffers;
    
        (......)
    };
    
    class FMetalRHIComputeContext : public FMetalRHICommandContext
    {
    public:
        FMetalRHIComputeContext(class FMetalProfiler* InProfiler, FMetalContext* WrapContext);
        virtual ~FMetalRHIComputeContext();
        
        virtual void RHISetAsyncComputeBudget(EAsyncComputeBudget Budget) final override;
        virtual void RHISetComputeShader(FRHIComputeShader* ComputeShader) final override;
        virtual void RHISetComputePipelineState(FRHIComputePipelineState* ComputePipelineState) final override;
        virtual void RHISubmitCommandsHint() final override;
    };
    
    class FMetalRHIImmediateCommandContext : public FMetalRHICommandContext
    {
    public:
        FMetalRHIImmediateCommandContext(class FMetalProfiler* InProfiler, FMetalContext* WrapContext);
    
        // FRHICommandContext API accessible only on the immediate device context
        virtual void RHIBeginDrawingViewport(FRHIViewport* Viewport, FRHITexture* RenderTargetRHI) final override;
        virtual void RHIEndDrawingViewport(FRHIViewport* Viewport, bool bPresent, bool bLockToVsync) final override;
        
        (......)
    };
    
    // Engine\Source\Runtime\Apple\MetalRHI\Private\MetalContext.h
    
    // 上下文.
    class FMetalContext
    {
    public:
        FMetalContext(mtlpp::Device InDevice, FMetalCommandQueue& Queue, bool const bIsImmediate);
        virtual ~FMetalContext();
        
        mtlpp::Device& GetDevice();
        
        bool PrepareToDraw(uint32 PrimitiveType, EMetalIndexType IndexType = EMetalIndexType_None);
        void SetRenderPassInfo(const FRHIRenderPassInfo& RenderTargetsInfo, bool const bRestart = false);
    
        void SubmitCommandsHint(uint32 const bFlags = EMetalSubmitFlagsCreateCommandBuffer);
        void SubmitCommandBufferAndWait();
        void ResetRenderCommandEncoder();
        
        void DrawPrimitive(uint32 PrimitiveType, uint32 BaseVertexIndex, uint32 NumPrimitives, uint32 NumInstances);
        void DrawPrimitiveIndirect(uint32 PrimitiveType, FMetalVertexBuffer* VertexBuffer, uint32 ArgumentOffset);
        void DrawIndexedPrimitive(FMetalBuffer const& IndexBuffer, ...);
        void DrawIndexedIndirect(FMetalIndexBuffer* IndexBufferRHI, ...);
        void DrawIndexedPrimitiveIndirect(uint32 PrimitiveType, ...);
        void DrawPatches(uint32 PrimitiveType, ...);
        
        (......)
    
    protected:
        // Metal底层设备.
        mtlpp::Device Device;
        
        FMetalCommandQueue& CommandQueue;
        FMetalCommandList CommandList;
        
        FMetalStateCache StateCache;
        FMetalRenderPass RenderPass;
        
        dispatch_semaphore_t CommandBufferSemaphore;
        TSharedPtr<FMetalQueryBufferPool, ESPMode::ThreadSafe> QueryBuffer;
        TRefCountPtr<FMetalFence> StartFence;
        TRefCountPtr<FMetalFence> EndFence;
        
        int32 NumParallelContextsInPass;
        
        (......)
    };
    
    // Engine\Source\Runtime\Apple\MetalRHI\Private\MetalCommandQueue.h
    
    class FMetalCommandQueue
    {
    public:
        FMetalCommandQueue(mtlpp::Device Device, uint32 const MaxNumCommandBuffers = 0);
        ~FMetalCommandQueue(void);
        
        mtlpp::CommandBuffer CreateCommandBuffer(void);
        void CommitCommandBuffer(mtlpp::CommandBuffer& CommandBuffer);
        void SubmitCommandBuffers(TArray<mtlpp::CommandBuffer> BufferList, uint32 Index, uint32 Count);
        FMetalFence* CreateFence(ns::String const& Label) const;
        void GetCommittedCommandBufferFences(TArray<mtlpp::CommandBufferFence>& Fences);
        
        mtlpp::Device& GetDevice(void);
        
        static mtlpp::ResourceOptions GetCompatibleResourceOptions(mtlpp::ResourceOptions Options);
        static inline bool SupportsFeature(EMetalFeatures InFeature);
        static inline bool SupportsSeparateMSAAAndResolveTarget();
        
        (......)
    
    private:
        // 设备.
        mtlpp::Device Device;
        // 命令队列.
        mtlpp::CommandQueue CommandQueue;
        // 命令缓存区列表.(注意是数组的数组)
        TArray<TArray<mtlpp::CommandBuffer>> CommandBuffers;
        
        TLockFreePointerListLIFO<mtlpp::CommandBufferFence> CommandBufferFences;
        uint64 ParallelCommandLists;
    };
    
    // Engine\Source\Runtime\Apple\MetalRHI\Private\MetalCommandList.h
    
    class FMetalCommandList
    {
    public:
        FMetalCommandList(FMetalCommandQueue& InCommandQueue, bool const bInImmediate);
        ~FMetalCommandList(void);
        
        void Commit(mtlpp::CommandBuffer& Buffer, TArray<ns::Object<mtlpp::CommandBufferHandler>> CompletionHandlers, bool const bWait, bool const bIsLastCommandBuffer);
        void Submit(uint32 Index, uint32 Count);
        
        bool IsImmediate(void) const;
        bool IsParallel(void) const;
        void SetParallelIndex(uint32 Index, uint32 Num);
        uint32 GetParallelIndex(void) const;
        uint32 GetParallelNum(void) const;
    
        (......)
        
    private:
        // 所属的FMetalCommandQueue.
        FMetalCommandQueue& CommandQueue;
        // 已提交的命令缓冲列表.
        TArray<mtlpp::CommandBuffer> SubmittedBuffers;
    };

    相比其它现代图形API而言,FMetalDynamicRHI的概念和接口都简介多了。其UML图如下:

    不同平台加载FDynamicRHI流程

    IDynamicRHIModule
    IDynamicRHIModule从IModuleInterface派生,可通过FModuleManager::LoadModule()等函数动态地加载,是各个DynamicRHIModule的公共接口类。
    FNullDynamicRHIModule、FOpenGLDynamicRHIModule、FD3D11DynamicRHIModule、FD3D12DynamicRHIModule、FVulkanDynamicRHIModule、FMetalDynamicRHIModule、FEmptyDynamicRHIModule通过重写CreateRHI函数,
    创建并返回对应的FDynamicRHI类型,相关的代码如下:
    // FNullDynamicRHIModule模块
    class FNullDynamicRHIModule
        : public IDynamicRHIModule
    {
    public:
    
        // IDynamicRHIModule
    
        virtual bool SupportsDynamicReloading() override { return false; }
        virtual bool IsSupported() override { return true; }
    
        virtual FDynamicRHI* CreateRHI(ERHIFeatureLevel::Type RequestedFeatureLevel = ERHIFeatureLevel::Num) override
        {
            return new FNullDynamicRHI();
        }
    };
    
    // FOpenGLDynamicRHIModule模块
    class FOpenGLDynamicRHIModule : public IDynamicRHIModule
    {
    public:
        
        // IModuleInterface
        virtual bool SupportsDynamicReloading() override { return false; }
    
        // IDynamicRHIModule
        virtual bool IsSupported() override { return true; }
    
        virtual FDynamicRHI* CreateRHI(ERHIFeatureLevel::Type RequestedFeatureLevel = ERHIFeatureLevel::Num) override
        {
            GRequestedFeatureLevel = InRequestedFeatureLevel;
            return new FOpenGLDynamicRHI();
        }
    };
    
    // FD3D11DynamicRHIModule模块
    class FD3D11DynamicRHIModule : public IDynamicRHIModule
    {
    public:
        // IModuleInterface    
        virtual bool SupportsDynamicReloading() override { return false; }
        virtual void StartupModule() override;
    
        // IDynamicRHIModule
        virtual bool IsSupported() override
        {
            // if not computed yet
            if(!ChosenAdapter.IsValid())
            {
                FindAdapter();
            }
    
            // The hardware must support at least 10.0 (usually 11_0, 10_0 or 10_1).
            return ChosenAdapter.IsValid()
                && ChosenAdapter.MaxSupportedFeatureLevel != D3D_FEATURE_LEVEL_9_1
                && ChosenAdapter.MaxSupportedFeatureLevel != D3D_FEATURE_LEVEL_9_2
                && ChosenAdapter.MaxSupportedFeatureLevel != D3D_FEATURE_LEVEL_9_3;
        }
        
        virtual FDynamicRHI* CreateRHI(ERHIFeatureLevel::Type RequestedFeatureLevel = ERHIFeatureLevel::Num) override
        {
            {
    #if PLATFORM_HOLOLENS
            GMaxRHIFeatureLevel = ERHIFeatureLevel::ES3_1;
            GMaxRHIShaderPlatform = SP_PCD3D_ES3_1;
    #endif
    
            TRefCountPtr<IDXGIFactory1> DXGIFactory1;
            SafeCreateDXGIFactory(DXGIFactory1.GetInitReference());
            check(DXGIFactory1);
    
            GD3D11RHI = new FD3D11DynamicRHI(DXGIFactory1,ChosenAdapter.MaxSupportedFeatureLevel,ChosenAdapter.AdapterIndex,ChosenDescription);
            FDynamicRHI* FinalRHI = GD3D11RHI;
    
    #if ENABLE_RHI_VALIDATION
            if (FParse::Param(FCommandLine::Get(), TEXT("RHIValidation")))
            {
                FinalRHI = new FValidationRHI(FinalRHI);
            }
    #endif
    
            return FinalRHI;
    }
        }
    
    private:
        FD3D11Adapter ChosenAdapter;
        // we don't use GetDesc().Description as there is a bug with Optimus where it can report the wrong name
        DXGI_ADAPTER_DESC ChosenDescription;
    
        // set MaxSupportedFeatureLevel and ChosenAdapter
        void FindAdapter();
    };
    
    // FD3D12DynamicRHIModule模块
    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
        {
        #if !PLATFORM_HOLOLENS
            if (!FPlatformMisc::VerifyWindowsVersion(10, 0))
            {
                return false;
            }
        #endif
    
            // If not computed yet
            if (ChosenAdapters.Num() == 0)
            {
                FindAdapter();
            }
    
            // The hardware must support at least 11.0.
            return ChosenAdapters.Num() > 0
                && ChosenAdapters[0]->GetDesc().IsValid()
                && ChosenAdapters[0]->GetDesc().MaxSupportedFeatureLevel >= D3D_FEATURE_LEVEL_11_0;
        }
        
        virtual FDynamicRHI* CreateRHI(ERHIFeatureLevel::Type RequestedFeatureLevel = ERHIFeatureLevel::Num) override
        {
            ERHIFeatureLevel::Type PreviewFeatureLevel;
            if (!GIsEditor && RHIGetPreviewFeatureLevel(PreviewFeatureLevel))
            {
                check(PreviewFeatureLevel == ERHIFeatureLevel::ES3_1);
    
                // ES3.1 feature level emulation in D3D
                GMaxRHIFeatureLevel = PreviewFeatureLevel;
                if (GMaxRHIFeatureLevel == ERHIFeatureLevel::ES3_1)
                {
                    GMaxRHIShaderPlatform = SP_PCD3D_ES3_1;
                }
            }
            else
            {
                GMaxRHIFeatureLevel = ERHIFeatureLevel::SM5;
                GMaxRHIShaderPlatform = SP_PCD3D_SM5;
            }
    
        #if USE_PIX
            bool bPixEventEnabled = (WindowsPixDllHandle != nullptr);
        #else
            bool bPixEventEnabled = false;
        #endif // USE_PIX
    
            GD3D12RHI = new FD3D12DynamicRHI(ChosenAdapters, bPixEventEnabled);
        #if ENABLE_RHI_VALIDATION
            if (FParse::Param(FCommandLine::Get(), TEXT("RHIValidation")))
            {
                return new FValidationRHI(GD3D12RHI);
            }
        #endif
            return GD3D12RHI;
        }
    
    private:
    
    #if USE_PIX && (PLATFORM_WINDOWS || PLATFORM_HOLOLENS)
        void* WindowsPixDllHandle = nullptr;
    #endif // USE_PIX && (PLATFORM_WINDOWS || PLATFORM_HOLOLENS)
    
        TArray<TSharedPtr<FD3D12Adapter>> ChosenAdapters;
    
        // set MaxSupportedFeatureLevel and ChosenAdapter
        void FindAdapter();
    };
    
    // FVulkanDynamicRHIModule模块
    class FVulkanDynamicRHIModule : public IDynamicRHIModule
    {
    public:
        // IDynamicRHIModule
        virtual bool IsSupported() override
        {
            return FVulkanPlatform::IsSupported();
        }
    
        virtual FDynamicRHI* CreateRHI(ERHIFeatureLevel::Type RequestedFeatureLevel = ERHIFeatureLevel::Num) override
        {
            FVulkanPlatform::SetupMaxRHIFeatureLevelAndShaderPlatform(InRequestedFeatureLevel);
            check(GMaxRHIFeatureLevel != ERHIFeatureLevel::Num);
    
            GVulkanRHI = new FVulkanDynamicRHI();
            FDynamicRHI* FinalRHI = GVulkanRHI;
    
        #if ENABLE_RHI_VALIDATION
            if (FParse::Param(FCommandLine::Get(), TEXT("RHIValidation")))
            {
                FinalRHI = new FValidationRHI(FinalRHI);
            }
        #endif
    
            return FinalRHI;
        }
    };
    
    
    // FMetalDynamicRHIModule模块
    class FMetalDynamicRHIModule : public IDynamicRHIModule
    {
    public:
        virtual bool IsSupported() override final { return true; }
    
        virtual FDynamicRHI* CreateRHI(ERHIFeatureLevel::Type RequestedFeatureLevel = ERHIFeatureLevel::Num) override final
        {
            LLM(MetalLLM::Initialise());
            return new FMetalDynamicRHI(RequestedFeatureLevel);
        }
    };
    
    // FEmptyDynamicRHIModule模块
    class FEmptyDynamicRHIModule : public IDynamicRHIModule
    {
    public:
        // IDynamicRHIModule
        virtual bool IsSupported() override { return true; }
    
        virtual FDynamicRHI* CreateRHI(ERHIFeatureLevel::Type RequestedFeatureLevel = ERHIFeatureLevel::Num) override
        {
            return new FEmptyDynamicRHI();
        }
    };
    DynamicRHIModule的继承关系如下:

    不同平台实现了各自FDynamicRHI* PlatformCreateDynamicRHI全局函数版本,依据命令行参数或ini配置文件来确定当前应该加载的IDynamicRHIModule,最后调用CreateRHI函数创建出最终使用的FDynamicRHI实例。

    并将该实例保存到全局变量extern RHI_API FDynamicRHI* GDynamicRHI中  // UnrealEngine\Engine\Source\Runtime\RHI\Public\DynamicRHI.h

    /* UnrealEngine\Engine\Source\Runtime\RHI\Private\Windows\WindowsDynamicRHI.cpp */
    // windows平台
    FDynamicRHI* PlatformCreateDynamicRHI()
    {
        FDynamicRHI* DynamicRHI = nullptr;
    
    #if UE_BUILD_DEBUG || UE_BUILD_DEVELOPMENT
        if (!FPlatformMisc::IsDebuggerPresent())
        {
            if (FParse::Param(FCommandLine::Get(), TEXT("AttachDebugger")))
            {
                // Wait to attach debugger
                do
                {
                    FPlatformProcess::Sleep(0);
                }
                while (!FPlatformMisc::IsDebuggerPresent());
            }
        }
    #endif
    
        ERHIFeatureLevel::Type RequestedFeatureLevel;
        const TCHAR* LoadedRHIModuleName;
        IDynamicRHIModule* DynamicRHIModule = LoadDynamicRHIModule(RequestedFeatureLevel, LoadedRHIModuleName);
    
        if (DynamicRHIModule)
        {
            // Create the dynamic RHI.
            DynamicRHI = DynamicRHIModule->CreateRHI(RequestedFeatureLevel);
            GLoadedRHIModuleName = LoadedRHIModuleName;
        }
    
        return DynamicRHI;
    }
    
    
    /* UnrealEngine\Engine\Source\Runtime\RHI\Private\Android\AndroidDynamicRHI.cpp */
    // Android平台
    FDynamicRHI* PlatformCreateDynamicRHI()
    {
        FDynamicRHI* DynamicRHI = NULL;
    
        // Load the dynamic RHI module.
        IDynamicRHIModule* DynamicRHIModule = NULL;
        ERHIFeatureLevel::Type RequestedFeatureLevel = ERHIFeatureLevel::Num;
        FString GraphicsRHI;
    
        if (FPlatformMisc::ShouldUseVulkan() || FPlatformMisc::ShouldUseDesktopVulkan())
        {
            // Vulkan is required, release the EGL created by FAndroidAppEntry::PlatformInit.
            FAndroidAppEntry::ReleaseEGL();
    
            DynamicRHIModule = &FModuleManager::LoadModuleChecked<IDynamicRHIModule>(TEXT("VulkanRHI"));
            if (!DynamicRHIModule->IsSupported())
            {
                DynamicRHIModule = &FModuleManager::LoadModuleChecked<IDynamicRHIModule>(TEXT("OpenGLDrv"));
                GraphicsRHI = TEXT("OpenGL");
            }
            else
            {
                RequestedFeatureLevel = FPlatformMisc::ShouldUseDesktopVulkan() ? ERHIFeatureLevel::SM5 : ERHIFeatureLevel::ES3_1;
                GraphicsRHI = TEXT("Vulkan");
            }
        }
        else
        {
            DynamicRHIModule = &FModuleManager::LoadModuleChecked<IDynamicRHIModule>(TEXT("OpenGLDrv"));
            GraphicsRHI = TEXT("OpenGL");
        }
    
        if (!DynamicRHIModule->IsSupported()) 
        {
    
        //    FMessageDialog::Open(EAppMsgType::Ok, TEXT("OpenGL 3.2 is required to run the engine."));
            FPlatformMisc::RequestExit(1);
            DynamicRHIModule = NULL;
        }
    
        if (DynamicRHIModule)
        {
            FApp::SetGraphicsRHI(GraphicsRHI);
            // Create the dynamic RHI.
            DynamicRHI = DynamicRHIModule->CreateRHI(RequestedFeatureLevel);
        }
    
    #if !PLATFORM_LUMIN
        FPlatformMisc::UnlockAndroidWindow();
    #endif
    
        return DynamicRHI;
    }
    
    /* UnrealEngine\Engine\Source\Runtime\RHI\Private\Apple\AppleDynamicRHI.cpp */
    // macOS、iOS平台
    FDynamicRHI* PlatformCreateDynamicRHI()
    {
        SCOPED_AUTORELEASE_POOL;
    
        FDynamicRHI* DynamicRHI = NULL;
        IDynamicRHIModule* DynamicRHIModule = NULL;
    
        bool const bIsMetalSupported = FPlatformMisc::HasPlatformFeature(TEXT("Metal"));
        
        // Must be Metal!
        if(!bIsMetalSupported)
        {
            FText Title = NSLOCTEXT("AppleDynamicRHI", "OpenGLNotSupportedTitle","Metal Not Supported");
    #if PLATFORM_MAC
            FMessageDialog::Open(EAppMsgType::Ok, NSLOCTEXT("MacPlatformCreateDynamicRHI", "OpenGLNotSupported.", "You must have a Metal compatible graphics card and be running Mac OS X 10.11.6 or later to launch this process."), &Title);
    #else
            FMessageDialog::Open(EAppMsgType::Ok, NSLOCTEXT("AppleDynamicRHI", "OpenGLNotSupported.", "You must have a Metal compatible iOS or tvOS device with iOS 8 or later to launch this app."), &Title);
    #endif
            FPlatformMisc::RequestExit(true);
        }
        
        if (FParse::Param(FCommandLine::Get(),TEXT("opengl")))
        {
            UE_LOG(LogRHI, Log, TEXT("OpenGL command line option ignored; Apple platforms only support Metal."));
        }
    
        ERHIFeatureLevel::Type RequestedFeatureLevel = ERHIFeatureLevel::Num;
        {
            // Check the list of targeted shader platforms and decide an RHI based off them
            TArray<FString> TargetedShaderFormats;
    #if PLATFORM_MAC
            GConfig->GetArray(TEXT("/Script/MacTargetPlatform.MacTargetSettings"), TEXT("TargetedRHIs"), TargetedShaderFormats, GEngineIni);
    #else
            bool bSupportsMetalMRT = false;
            GConfig->GetBool(TEXT("/Script/IOSRuntimeSettings.IOSRuntimeSettings"), TEXT("bSupportsMetalMRT"), bSupportsMetalMRT, GEngineIni);
            if (bSupportsMetalMRT)
            {
    #if PLATFORM_TVOS
                TargetedShaderFormats.Add(LegacyShaderPlatformToShaderFormat(SP_METAL_MRT_TVOS).ToString());
    #else
                TargetedShaderFormats.Add(LegacyShaderPlatformToShaderFormat(SP_METAL_MRT).ToString());
    #endif
            }
            
    #if PLATFORM_TVOS
            TargetedShaderFormats.Add(LegacyShaderPlatformToShaderFormat(SP_METAL_TVOS).ToString());
    #else
            TargetedShaderFormats.Add(LegacyShaderPlatformToShaderFormat(SP_METAL).ToString());
    #endif
            
    #endif // else branch of PLATFORM_MAC
            
            // Metal is not always available, so don't assume that we can use the first platform
            for (FString Name : TargetedShaderFormats)
            {
                FName ShaderFormatName(*Name);
                EShaderPlatform TargetedPlatform = ShaderFormatToLegacyShaderPlatform(ShaderFormatName);
                
                // Instead use the first platform that *could* work
                if (IsMetalPlatform(TargetedPlatform))
                {
                    RequestedFeatureLevel = GetMaxSupportedFeatureLevel(TargetedPlatform);
                    break;
                }
            }
        }
    
        // Load the dynamic RHI module.
        {
            DynamicRHIModule = &FModuleManager::LoadModuleChecked<IDynamicRHIModule>(TEXT("MetalRHI"));
            
            {
    #if PLATFORM_MAC
                if (FParse::Param(FCommandLine::Get(),TEXT("metal")))
                {
                    RequestedFeatureLevel = ERHIFeatureLevel::SM5;
                }
                else if (FParse::Param(FCommandLine::Get(),TEXT("metalsm5")) || FParse::Param(FCommandLine::Get(),TEXT("metalmrt")))
                {
                    RequestedFeatureLevel = ERHIFeatureLevel::SM5;
                }
    #else
                if (FParse::Param(FCommandLine::Get(),TEXT("metal")))
                {
                    RequestedFeatureLevel = ERHIFeatureLevel::ES3_1;
                }
                else if (FParse::Param(FCommandLine::Get(),TEXT("metalmrt")))
                {
                    RequestedFeatureLevel = ERHIFeatureLevel::SM5;
                }
    #endif
            }
            FApp::SetGraphicsRHI(TEXT("Metal"));
        }
        
        // Create the dynamic RHI.
        DynamicRHI = DynamicRHIModule->CreateRHI(RequestedFeatureLevel);
        return DynamicRHI;
    }

    在windows平台上,调用堆栈如下:

    参考

    剖析虚幻渲染体系(10)- RHI 

  • 相关阅读:
    A02 React+Antdesign 创建新项目
    B02 Vue+Element 创建新项目
    B01 Vue+Element 开发环境搭建
    A01 React+Antdesign 开发环境准备
    批量处理TXT转csv
    pyinstall python文件打包成二进制exe文件
    vue前端与django后端数据交互
    页面自适应
    ETL-kettle通过java代码传递参数,调用job调用转换
    ETL-kettle基本操作,表的输入输出
  • 原文地址:https://www.cnblogs.com/kekec/p/15652661.html
Copyright © 2020-2023  润新知