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

我想了解D3D11是如何被UE4的RHI封装的。我知道这牵扯到很多复杂的内容,但通过观察一些最基础的API被谁在哪调用,可以对RHI是如何封装的有一个大致了解。在之前的博客《创建一个最小的D3D11实例》中,有一些最基础的D3D11的API调用,我选他们作为观察的对象。

ID3D11Device 是怎么被创建的?

首先,FD3D11Device 被定义为了 ID3D11Device,这在 D3D11RHIBasePrivate.h可找到:

typedef ID3D11Device FD3D11Device;

FD3D11DynamicRHI中有一个成员:

/** The global D3D device's immediate context */
TRefCountPtr<FD3D11Device> Direct3DDevice;

FD3D11DynamicRHI 是一个继承FDynamicRHIIRHICommandContext的类:

class D3D11RHI_API FD3D11DynamicRHI : public FDynamicRHI, public IRHICommandContextPSOFallback

它有个全局的指针:

extern FD3D11DynamicRHI*	GD3D11RHI;

最终,通过调用D3D11的APID3D11CreateDevice完成创建。
堆栈如下(主线程中):

RHIInit
FD3D11DynamicRHI::Init
FD3D11DynamicRHI::InitD3DDevice
D3D11CreateDevice

ID3D11DeviceContext 是怎么得到的?

与前者很类似。
FD3D11DeviceContext 被定义为了 ID3D11DeviceContext

typedef ID3D11DeviceContext FD3D11DeviceContext;

FD3D11DynamicRHI中有一个成员:

/** The global D3D device's immediate context */
TRefCountPtr<FD3D11DeviceContext> Direct3DDeviceIMContext;

在前者ID3D11DeviceD3D11CreateDevice函数创建时得到。

IDXGISwapChain 是怎么创建的?

首先,FD3D11Viewport中有一个成员:

TRefCountPtr<IDXGISwapChain> SwapChain;

FD3D11Viewport的构造函数中调用IDXGIFactory2::CreateSwapChainForHwnd函数来创建:

IDXGISwapChain1* SwapChain1 = nullptr;
IDXGIFactory2* Factory2 = (IDXGIFactory2*)D3DRHI->GetFactory();

if(!FAILED(Factory2->CreateSwapChainForHwnd(D3DRHI->GetDevice(), WindowHandle, &SwapChainDesc, &FSSwapChainDesc, nullptr, &SwapChain1)))
{
	SwapChain1->QueryInterface(__uuidof(IDXGISwapChain1), (void**)SwapChain.GetInitReference());

	// See if we are running on a HDR monitor 
	CheckHDRMonitorStatus();
}

堆栈如下(主线程中):

FD3D11DynamicRHI::RHICreateViewport
FD3D11Viewport::FD3D11Viewport
IDXGIFactory2::CreateSwapChainForHwnd
RHICreateViewport

值得一提的是,创建SwapChain是需要一个窗口的Handle,我感兴趣它是怎么得到的。
这里我调试时是调到了FSlateRHIRenderer来调用RHICreateViewport

NewInfo->ViewportRHI = RHICreateViewport( NewInfo->OSWindow, Width, Height, bFullscreen, NewInfo->PixelFormat );

其中NewInfo->OSWindow获得方式是:

TSharedRef<FGenericWindow> NativeWindow = Window->GetNativeWindow().ToSharedRef();
NewInfo->OSWindow = NativeWindow->GetOSWindowHandle();

SwapChain 的 BackBuffer 的 RenderTargetView如何被创建

堆栈如下(主线程):

RHICreateViewport
FD3D11DynamicRHI::RHICreateViewport
FD3D11Viewport::FD3D11Viewport
FD3D11Viewport::GetSwapChainSurface
ID3D11Device::CreateRenderTargetView

值得一提的是,GetSwapChainSurface最后会返回一个FD3D11Texture2D*对象,他将作为FD3D11Viewport的成员BackBuffer的值。

ImmediateContext->ClearRenderTargetView 在哪调用

调用堆栈如下(渲染线程

FD3D11DynamicRHI::RHIBeginRenderPass
IRHICommandContext::RHIBeginRenderPass
FD3D11DynamicRHI::RHISetRenderTargetsAndClear
FD3D11DynamicRHI::RHIClearMRTImpl
ID3D11DeviceContext::ClearRenderTargetView

SwapChain->Present(0, 0) 在哪调用

调用堆栈如下(渲染线程

FRHICommandEndDrawingViewport::Execute
FD3D11DynamicRHI::RHIEndDrawingViewport
FD3D11Viewport::Present
FD3D11Viewport::PresentChecked
IDXGISwapChain::Present

如何设置Viewport

调用堆栈如下(渲染线程

FD3D11DynamicRHI::RHIBeginRenderPass
IRHICommandContext::RHIBeginRenderPass
FD3D11DynamicRHI::RHISetRenderTargetsAndClear
FD3D11DynamicRHI::RHISetRenderTargets
FD3D11DynamicRHI::RHISetViewport
FD3D11StateCacheBase::SetViewport
ID3D11DeviceContext::RSSetViewports

着色器

在引擎的\Engine\Shaders\目录中有大量的 .ush.usf,他们如何被编译成各个图形接口对应的着色器文件,相信UE4有复杂的系统,讨论它们应该需要另开篇章了。
这里对一些基础API打上断点简单看下,ID3D11Device::CreateVertexShader
在这里插入图片描述
看起来和RenderCore模块有很大关系。
而设置顶点着色器的堆栈如下(渲染线程):

FRHICommandSetGraphicsPipelineState::Execute
FD3D11DynamicRHI::RHISetGraphicsPipelineState
RHICommandContextPSOFallback::RHISetGraphicsPipelineState
FD3D11DynamicRHI::RHISetBoundShaderState
FD3D11StateCacheBase::SetVertexShader
ID3D11DeviceContext::VSSetShader

输入布局如何设置

和前者一样,输入布局也在FD3D11DynamicRHI::RHISetBoundShaderState中:

void FD3D11DynamicRHI::RHISetBoundShaderState(FRHIBoundShaderState* BoundShaderStateRHI)
{
	FD3D11BoundShaderState* BoundShaderState = ResourceCast(BoundShaderStateRHI);

	StateCache.SetStreamStrides(BoundShaderState->StreamStrides);
	StateCache.SetInputLayout(BoundShaderState->InputLayout);
	StateCache.SetVertexShader(BoundShaderState->VertexShader);
	StateCache.SetPixelShader(BoundShaderState->PixelShader);

	StateCache.SetHullShader(BoundShaderState->HullShader);
	StateCache.SetDomainShader(BoundShaderState->DomainShader);
	StateCache.SetGeometryShader(BoundShaderState->GeometryShader);

SetInputLayout函数中调用了IASetInputLayout

D3D11_STATE_CACHE_INLINE void SetInputLayout(ID3D11InputLayout* InputLayout)
{
#if D3D11_ALLOW_STATE_CACHE
	D3D11_STATE_CACHE_VERIFY_PRE();
	if ((CurrentInputLayout != InputLayout) || GD3D11SkipStateCaching)
	{
		CurrentInputLayout = InputLayout;
		Direct3DDeviceIMContext->IASetInputLayout(InputLayout);
	}
	D3D11_STATE_CACHE_VERIFY_POST();
#else
	Direct3DDeviceIMContext->IASetInputLayout(InputLayout);
#endif
}

顶点缓冲如何被设置

而设置顶点着色器的堆栈如下(渲染线程):

FD3D11DynamicRHI::RHISetStreamSource
FD3D11StateCacheBase::SetStreamSource
FD3D11StateCacheBase::InternalSetStreamSource
ID3D11DeviceContext::IASetVertexBuffers

Draw调用

Draw调用的堆栈如下(渲染线程):

FRHICommandDrawIndexedPrimitive::Execute
FD3D11DynamicRHI::RHIDrawIndexedPrimitive
ID3D11DeviceContext::DrawIndexed
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值