在上篇简单说明RHI的作用后, 我们在引擎中探索一下RHI的种种细节与实现. 在解决方案资源管理器中搜索RHI, 会有这些文件:

  (1)对应不同运行平台的PlatformDynamicRHI.cpp(上篇有提到, 主要进行硬件接口创建前的配置并创建不同绘图接口对应的RHI). 由于目标平台在打包时就确定了, 在打包时会选择编译这些PlatformDynamicRHI.cpp中的一个, 而其他平台的.cpp会被绕过编译.

                    

  (2)对应不同绘图接口的DynamicRHI. 可以看到有DX11, DX12, Vulkan, Metal的RHI模块.

      

  一顿找却没有找到OpenGL的DynamicRHI, 在管理器搜索发现被集成进了OpenGLDrv.h中:

  (3)RHI的具体功能实现部分:
                    

  重点探索第三部分.

  1.首先看RHI.h/RHI.cpp:

  在这部分, 引擎会定义各种RHI的公共变量, 比如当前显卡硬件的代号以及驱动版本:

/** * only set if RHI has the information (after init of the RHI and only if RHI has that information, never changes after that)* e.g. "NVIDIA GeForce GTX 670"*/
extern RHI_API FString GRHIAdapterName;
extern RHI_API FString GRHIAdapterInternalDriverVersion;
extern RHI_API FString GRHIAdapterUserDriverVersion;
extern RHI_API FString GRHIAdapterDriverDate;
extern RHI_API uint32 GRHIDeviceId;
extern RHI_API uint32 GRHIDeviceRevision;// 0 means not defined yet, use functions like IsRHIDeviceAMD() to access
extern RHI_API uint32 GRHIVendorId;// to trigger GPU specific optimizations and fallbacks
RHI_API bool IsRHIDeviceAMD();// to trigger GPU specific optimizations and fallbacks
RHI_API bool IsRHIDeviceIntel();// to trigger GPU specific optimizations and fallbacks
RHI_API bool IsRHIDeviceNVIDIA();

  以及各项着色/绘图特性, 例如在深度测试时获取深度, 体纹理, 硬件合并渲染, 对MSAA的支持, 对各种RenderTarget格式的支持程度, 乃至于光栅化等. 这些特性因硬件平台、绘图接口以及显示驱动的不同会有种种差异.

  2.DynamicRHI

  在这部分会有FDynamicRHI接口的定义以及图形渲染所需要的各种基础接口如创建Buffer, 创建Texture以及创建着色器等:

/** The interface which is implemented by the dynamically bound RHI. */
class RHI_API FDynamicRHI
{
public:....
}

  例如创建PixelShader和VertexShader这一类操作:

// FlushType: Wait RHI Threadvirtual FPixelShaderRHIRef RHICreatePixelShader(FRHIShaderLibraryParamRef Library, FSHAHash Hash){return nullptr;}// FlushType: Wait RHI Threadvirtual FVertexShaderRHIRef RHICreateVertexShader(const TArray<uint8>& Code) = 0;// FlushType: Wait RHI Threadvirtual FVertexShaderRHIRef RHICreateVertexShader(FRHIShaderLibraryParamRef Library, FSHAHash Hash){return nullptr;}

  3.FRenderResource

  这也是我们应用中实际操作RHI时较多使用的部分, 定义了许多创建渲染资源时需要的类, 以及众多选择进行实现的函数. 首先看资源类基类FRenderResource:

/*** A rendering resource which is owned by the rendering thread.*/
class RENDERCORE_API FRenderResource
{
public:/** @return The global initialized resource list. */static TLinkedList<FRenderResource*>*& GetResourceList();.../*** Initializes the RHI resources used by this resource.* Called when entering the state where both the resource and the RHI have been initialized.* This is only called by the rendering thread.*/virtual void InitRHI() {}/*** Releases the RHI resources used by this resource.* Called when leaving the state where both the resource and the RHI have been initialized.* This is only called by the rendering thread.*/virtual void ReleaseRHI() {}...
}

  会有众多纯虚函数暴露出来供我们选择重写. 具体接口功能在注释中有很完备的写出. 如果要具体地操作RHI, 这个资源类也会是我们进行了解与学习的入口, 这些接口是首先要了解的内容. 

  例如创建一个简单的IndexBuffer, 我们会在RenderResource中发现IndexBuffer的基类:

/** An index buffer resource. */
class FIndexBuffer : public FRenderResource
{
public:FIndexBufferRHIRef IndexBufferRHI;/** Destructor. */virtual ~FIndexBuffer() {}// FRenderResource interface.virtual void ReleaseRHI() override{IndexBufferRHI.SafeRelease();}virtual FString GetFriendlyName() const override { return TEXT("FIndexBuffer"); }
};

  会了解到对于这个IndexBuffer对应的Resource, 引擎为我们实现了Realease, 而Init的工作就需要我们亲力完成. 即可如此创建子类:

/* Index Buffer */
class FMyMeshIndexBuffer : public FIndexBuffer
{
public:int32 NumIndices;virtual void InitRHI() override{FRHIResourceCreateInfo CreateInfo;IndexBufferRHI = RHICreateIndexBuffer(sizeof(int32), NumIndices * sizeof(int32), BUF_Dynamic, CreateInfo);}
};

  此外会有常用接口如:

//开始创建Resource
void BeginInitResource(FRenderResource* Resource)
{ENQUEUE_RENDER_COMMAND(InitCommand)([Resource](FRHICommandListImmediate& RHICmdList){Resource->InitResource();});
}
//开始更新ResouceRHI
void BeginUpdateResourceRHI(FRenderResource* Resource)
{ENQUEUE_RENDER_COMMAND(UpdateCommand)([Resource](FRHICommandListImmediate& RHICmdList){Resource->UpdateRHI();});
}
...

  4. RHICommandList

  在看源码之前先要了解一下RHICommandList的机制: RHI的指令会压入RHICommandList中, 而这个List本身是存放在渲染线程中的. RHI的工作是管理各个RHI对象, 在不干扰渲染线程工作的情况下把这些对象的Command压入到渲染线程的CommanList中, 以及为渲染线程做各种复杂的异步操作而不干涉到渲染线程的正常工作.(皇上我把文件都给你整理好了你批就行了...)

  FRHICommandBase & FRHICommand: 初看到FRHICommandBase时会略感懵逼...

struct FRHICommandBase
{FRHICommandBase* Next = nullptr;virtual void ExecuteAndDestruct(FRHICommandListBase& CmdList, FRHICommandListDebugContext& DebugContext) = 0;
};

  其实看类名和虚函数名可以看出这样一个结构体是一条RHI指令的一个基类, 其中的CommanBase空指针就是为了构成CommanList链表而生的. 每个Command下的函数指针会携带一条指令, 而Next指针又会指向下一条Command, 渲染线程只需不停地读这个链表执行这些指令进行工作就可以了.

  而在其之下会有一个类模板子类FRHICommand:

template<typename TCmd>
struct FRHICommand : public FRHICommandBase
{void ExecuteAndDestruct(FRHICommandListBase& CmdList, FRHICommandListDebugContext& Context) override final{TCmd *ThisCmd = static_cast<TCmd*>(this);
#if RHI_COMMAND_LIST_DEBUG_TRACESThisCmd->StoreDebugInfo(Context);
#endifThisCmd->Execute(CmdList);ThisCmd->~TCmd();}virtual void StoreDebugInfo(FRHICommandListDebugContext& Context) {};
};

  需要模板TCmd实现方法Execute. 而此子类在执行ExecuteAndDestruct时会退化到参数类型TCmd, 执行TCmd下的Execute方法后自动析构, 这个过程也就实现了所谓"ExecuteAndDestruct".

  

转载于:https://www.cnblogs.com/Saeru-Hikari/p/10898909.html

UE4 RHI(2)相关推荐

  1. UE4 RHI与Render模块简解

    UE4中的RHI指的是Render hardware interface,作用像Ogre里的RenderSystem,针对Dx11,Dx12,Opengl等等平台抽象出相同的接口,我们能方便能使用相同 ...

  2. UE4 RHI与条件式编译

    RHI即RenderHardwareInterface, 即渲染硬件接口, 是UE为实现跨平台而实现的一套API. 每个RHI接口都为OpenGL, Vulkan, DX11等做了不同的实现. 在引擎 ...

  3. 2022年9月19日--9月25日(ue4热更新视频教程为主,本周10小时。合计1592小时,剩余8408小时)

    目前进行到mysql(7.1),tf1(2.3),oss(12.1),蓝图反射(1.7),ue4 pak(10.3), 从上周看,很不理想,原以为上班时间能学习下,结果会议室人来人往,不能指望这个了, ...

  4. Frame Pacing

    Frame Pacing是每个游戏都要遇到的问题,这里面有很多细节值得探讨. 为什么需要做Frame Pacing? 从我们的游戏线程渲染一帧到最终屏幕上绘制出一帧不是一个概念,这种间会经历CPU,G ...

  5. 游戏开发值得学习的项目

    热更新 C#开发加载DLL https://github.com/Ourpalm/ILRuntime xlua开发解释执行 https://github.com/Tencent/xLua slua开发 ...

  6. 基于UE4的多RHI线程实现

    1 UE4的现有多线程架构 UE的多线程渲染结构如下图, 它有几个特点 game thread 负责逻辑tick,render thread 负责culling.batching和draw api的生 ...

  7. 【UE4源代码观察】观察 RHI、D3D11RHI、RenderCore 这三个模块的依赖关系

    基本概念 RHI(Render Hardware Interface)的职责是对OpenGL.DirectX3D.Vulkan这些图形接口API进行封装,来统一上层的调用.D3D11RHI就是 RHI ...

  8. 【UE4源代码观察】观察D3D11是如何被RHI封装的

    我想了解D3D11是如何被UE4的RHI封装的.我知道这牵扯到很多复杂的内容,但通过观察一些最基础的API被谁在哪调用,可以对RHI是如何封装的有一个大致了解.在之前的博客<创建一个最小的D3D ...

  9. 2022年9月12日-9月18日(ue4热更新视频教程+rhi模块源码抄写调剂。本周20小时。合计1582小时,剩余8418小时。)

    目前进行到mysql(7.1),tf1(2.3),oss(12.1),蓝图反射(1.7),ue4 pak(8.6), 从上周最后两天可以看到,基本上调整月计划后,可以完成任务.且打游戏已经没有吸引力了 ...

最新文章

  1. BZOJ2351[BeiJing2011]Matrix——二维hash
  2. 生成转储拣配单的ABAP程序
  3. Android中build target,minSdkVersion,targetSdkVersion,maxSdkVersion概念区分
  4. Linux awk 命令
  5. C#求一元二次方程的根经典案例程序
  6. linux文件分割(将大的日志文件分割成小的)
  7. IDC 和浪潮联合发布了《2020-2021 中国人工智能计算力发展评估报告 》
  8. bzoj3192 [JLOI2013]删除物品 树状数组
  9. 【Openstack】实录手动部署Openstack Rocky 双节点(5)- Neutron
  10. MacroSAN杭州宏杉科技存储使用小节
  11. 微信支付商户平台开通流程
  12. 继电器控制实验程序c语言,继电器原理及实验程序
  13. 机器人设计之软件设计
  14. js 身份证 正则校验 大陆、香港、澳门、台湾 身份证 正则校验
  15. 罗永浩两年还债4个亿,我却被《真还传》圈粉
  16. 游戏电影——《落花辞》
  17. #457 科技乱炖:去中心化的Damus,会比Twitter更好么
  18. 三、外码、关系的完整性约束、关系代数
  19. [windows]VS2015配置Lemon图论算法库
  20. html2canvas 在ios 13.4.x 、 13.5.x 微信浏览器中失效无反应

热门文章

  1. 运放-滞回(迟滞)比较器全流程实战计算
  2. AE(爱情公寓制作自用)
  3. 高防CDN如何抵御ddos攻击?
  4. XJOI——3569-萌新关爱之-C语言的余数
  5. 更深入到非聚集索引:通往SQL Server索引级别2的阶梯
  6. 介绍一位网络爬虫工程师
  7. 解决电脑开机显示无信号且黑屏的6种解决方法
  8. 操作系统学习(三):浅析比例份额调度——彩票调度和步长调度
  9. 速卖通开店新手卖家专题 ▏速卖通新店铺运营思路分享
  10. JZOJ5945. 【NOIP2018模拟11.02】昆特牌(gwent)