UE4 RHI浅析

RHI: Render hardware interface 渲染硬件层接口, 本人理解RHI是一套硬件无关,平台无关的图形渲染API.  

它是如何做到与平台无关,与硬件无关的呢?

每个RHI接口都对应着多个图形API的实现版本. 对于每个RHI接口,其实都有针对DX11,DX12,OpenGL等版本的实现。对于不同平台,引擎初始化的时候就已经确定要用哪一套图形API了。  之后,调用的RHI其实就是对应初始化时候确定用的那套图形API实现的版本.

比如RHIDrawIndexedPrimitive接口,对于DX,OPENGL,其实都实现了RHIDrawIndexedPrimitive接口。
当引擎初始化的时候,判断是在windows平台上的,并决定使用DX11。之后,当调用RHIDrawIndexedPrimitive接口时,其实调用的是DX11版本的RHIDrawIndexedPrimitive。

对于RHI使用者而已,不需要关心是调用了哪套图形API,反正能正确运行,从而造成跨平台的假象;而从开发角度而言,RHI并不是平台无关的,它需要开发人员呕心沥血地开发和维护,以保证RHI在不同平台下运行结果都一样

DynamicRHI.h里 FDynamicRHI, IRHIComputeContext两个虚基类里定义了所有的RHI接口。
实现RHI接口的子类有:
1. class D3D11RHI_API FD3D11DynamicRHI : public FDynamicRHI, public IRHICommandContext
2. class FD3D12DynamicRHI : public FDynamicRHI
3. class OPENGLDRV_API FOpenGLDynamicRHI : public FDynamicRHI, public IRHICommandContext

Vulkan: 新一代跨平台,充分利用多核多线程的图形API
4. class FVulkanDynamicRHI : public FDynamicRHI

Metal:苹果系统的图形API             
5. class FMetalDynamicRHI : public FDynamicRHI, public FMetalRHICommandContext

RHI初始化接口
void RHIInit(bool bHasEditorToken)
{
        GDynamicRHI = PlatformCreateDynamicRHI();
}


PlatformCreateDynamicRHI是一个全局函数,负责创建一个RHI全局变量,每个平台下都有一个实现版本.   但是它的实现方式很奇怪,在Runtime/RHI/Private下,每个平台的xxx.cpp文件都实现了该函数,C++在多个文件里实现同一个全局函数,这样难道不会报错吗?
另外,笔者也没有找到   GDynamicRHI = PlatformCreateDynamicRHI(); 这句代码是如何决定调用哪个平台的PlatformCreateDynamicRHI.

win32版本的PlatformCreateDynamicRHI
FDynamicRHI* PlatformCreateDynamicRHI()
{
    FDynamicRHI* DynamicRHI = nullptr;

    //win32下支持多套图形API,则由用户通过命令行指定.
    const bool bForceSM5  = FParse::Param(FCommandLine::Get(),TEXT("sm5"));
    const bool bForceSM4  = FParse::Param(FCommandLine::Get(), TEXT("sm4"));
    const bool bForceVulkan = FParse::Param(FCommandLine::Get(), TEXT("vulkan"));
    const bool bForceD3D10 = FParse::Param(FCommandLine::Get(),TEXT("d3d10")) || FParse::Param(FCommandLine::Get(),TEXT("dx10")) || (bForceSM4 && !bForceVulkan);
    const bool bForceD3D11 = FParse::Param(FCommandLine::Get(),TEXT("d3d11")) || FParse::Param(FCommandLine::Get(),TEXT("dx11")) || (bForceSM5 && !bForceVulkan);
    const bool bForceD3D12 = FParse::Param(FCommandLine::Get(), TEXT("d3d12")) || FParse::Param(FCommandLine::Get(), TEXT("dx12"));
    const bool bForceOpenGL = (WINVER < 0x0600) || FParse::Param(FCommandLine::Get(), TEXT("opengl")) || FParse::Param(FCommandLine::Get(), TEXT("opengl3")) || FParse::Param(FCommandLine::Get(),          TEXT("opengl4"));



    // Load the dynamic RHI module.
    IDynamicRHIModule* DynamicRHIModule = NULL;
    if(bForceOpenGL)
    {
        DynamicRHIModule = &FModuleManager::LoadModuleChecked(TEXT("OpenGLDrv"));
    }
    else if (bForceVulkan)
    {
        DynamicRHIModule = &FModuleManager::LoadModuleChecked(TEXT("VulkanRHI"))   
    }
    else if (bForceD3D12)
    {
        DynamicRHIModule = &FModuleManager::LoadModuleChecked(TEXT("D3D12RHI"));
    }
    else
    {
        DynamicRHIModule = &FModuleManager::LoadModuleChecked(TEXT("D3D11RHI"));
    }

    if (DynamicRHIModule)
        DynamicRHI = DynamicRHIModule->CreateRHI();
    

    return DynamicRHI;
}

FDynamicRHI* FD3D11DynamicRHIModule::CreateRHI()
{
        return new FD3D11DynamicRHI(DXGIFactory1,ChosenAdapter.MaxSupportedFeatureLevel,ChosenAdapter.AdapterIndex,ChosenDescription);
}




           

你可能感兴趣的:(Unreal,Engine,4)