zoukankan      html  css  js  c++  java
  • 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 

  • 相关阅读:
    Thinking in Java Reading Note(9.接口)
    Thinking in java Reading Note(8.多态)
    Thinking in Java Reading Note(7.复用类)
    SQL必知必会
    Thinking in Java Reading Note(5.初始化与清理)
    Thinking in Java Reading Note(2.一切都是对象)
    鸟哥的Linux私房菜笔记(1.基础)
    Thinking in Java Reading Note(1.对象导论)
    CoreJava2 Reading Note(2:I/O)
    CoreJava2 Reading Note(1:Stream)
  • 原文地址:https://www.cnblogs.com/kekec/p/15652661.html
Copyright © 2011-2022 走看看