DX9中如何模拟DX10/11里的ConstantBuffer

今天,我的引擎的DX9 RenderApi插件终于可以跑起来了。虽然问题还很多。不过总算看到图像了。立碑纪念一下。

一开始基于DX10的API来构造整个渲染系统的。DX10的API带来很多新的概念设计。比如Constant Buffer的概念,能统一Shader Constant的管理,当然在DX10/DX11里能有效的提高参数传递的效率。

比如:我做了个TransformBuffer。这个Buffer绑定掉了所有的Matrix上。当Camera变化,或者Matrix变化得时候,我只需要加个标记。下次使用这个Buffer的时候,我检查这个Dirty标记。如果Dirty了。那就下载数据到GPU Constant Buffer中。这样的好处就不会所有的Shader都需要download一遍相同的数据到GPU中了。严重节省了GPU-CPU数据交换的时间。

但是杯具的是,DX9中没这个东西。

不过虽然没有。我至少在行为上可以模拟的像一点。顶多不需要那严重节省下来的时间而已。

DX9的ConstantTable里。可以检查一个Constant是不是Struct。 如果是一个Struct,那么它的数据都是连续的。我们可以用Struct来模拟Constant Buffer。

比如:

struct cTransformBuffer
{
matrix matWorld;
matrix matView;
matrix matProject;
float4 cameraUp;
float4 cameraPos;
float4 cameraDir;
float4 cameraArg;//[Near , Far , Fov , Aspect]
};
cTransformBuffer TransformBuffer;

我就有了一个名字为TransformBuffer的Struct。而且这个Struct的大小,和总的D3DXHANDLE在ConstantTable里是都可以拿的到得。

在我们需要数据的时候,用pConstantTable->SetValue()函数,把整块数据扔给ShaderConstantTable就Ok了。

虽然这样没有节省任何CPU-GPU时间。不过代码变的真是干净彻底啊。

PS: 同理把渲染状态进行管理。按照DX11/DX10的分类。然后成组的设置。管理渲染状态也变得更加方便了。

代码如下,自带渲染状态重复判断。不会多设置一个不需要设置的多余的渲染状态。

void xD3D9ZStencilState::Install(xD3D9ZStencilState* pOldStencil)
{
IDirect3DDevice9* pDevice = m_pD3D9RenderApi->getDevice();
if(pOldStencil)
{
GUID_VALUE(m_Stencil.m_Enable ) pDevice->SetRenderState(D3DRS_STENCILENABLE , m_Stencil.m_Enable );
GUID_VALUE(m_Stencil.m_Ref ) pDevice->SetRenderState(D3DRS_STENCILREF , m_Stencil.m_Ref );
GUID_VALUE(m_Stencil.m_Mask ) pDevice->SetRenderState(D3DRS_STENCILMASK , m_Stencil.m_Mask );
GUID_VALUE(m_Stencil.m_WriteMask) pDevice->SetRenderState(D3DRS_STENCILWRITEMASK , m_Stencil.m_WriteMask);

GUID_VALUE(m_Stencil.m_OpCW.m_Fail ) pDevice->SetRenderState(D3DRS_STENCILFAIL , m_Stencil.m_OpCW.m_Fail );
GUID_VALUE(m_Stencil.m_OpCW.m_zFail) pDevice->SetRenderState(D3DRS_STENCILZFAIL , m_Stencil.m_OpCW.m_zFail);
GUID_VALUE(m_Stencil.m_OpCW.m_Pass ) pDevice->SetRenderState(D3DRS_STENCILPASS , m_Stencil.m_OpCW.m_Pass );
GUID_VALUE(m_Stencil.m_OpCW.m_Func ) pDevice->SetRenderState(D3DRS_STENCILFUNC , m_Stencil.m_OpCW.m_Func );

GUID_VALUE(m_Stencil.m_OpCCW.m_Fail ) pDevice->SetRenderState(D3DRS_CCW_STENCILFAIL , m_Stencil.m_OpCCW.m_Fail );
GUID_VALUE(m_Stencil.m_OpCCW.m_zFail) pDevice->SetRenderState(D3DRS_CCW_STENCILZFAIL , m_Stencil.m_OpCCW.m_zFail);
GUID_VALUE(m_Stencil.m_OpCCW.m_Pass ) pDevice->SetRenderState(D3DRS_CCW_STENCILPASS , m_Stencil.m_OpCCW.m_Pass );
GUID_VALUE(m_Stencil.m_OpCCW.m_Func ) pDevice->SetRenderState(D3DRS_CCW_STENCILFUNC , m_Stencil.m_OpCCW.m_Func );
}
else
{
pDevice->SetRenderState(D3DRS_STENCILENABLE , m_Stencil.m_Enable );
pDevice->SetRenderState(D3DRS_STENCILREF , m_Stencil.m_Ref );
pDevice->SetRenderState(D3DRS_STENCILMASK , m_Stencil.m_Mask );
pDevice->SetRenderState(D3DRS_STENCILWRITEMASK , m_Stencil.m_WriteMask);

pDevice->SetRenderState(D3DRS_STENCILFAIL , m_Stencil.m_OpCW.m_Fail );
pDevice->SetRenderState(D3DRS_STENCILZFAIL , m_Stencil.m_OpCW.m_zFail);
pDevice->SetRenderState(D3DRS_STENCILPASS , m_Stencil.m_OpCW.m_Pass );
pDevice->SetRenderState(D3DRS_STENCILFUNC , m_Stencil.m_OpCW.m_Func );

pDevice->SetRenderState(D3DRS_CCW_STENCILFAIL , m_Stencil.m_OpCCW.m_Fail );
pDevice->SetRenderState(D3DRS_CCW_STENCILZFAIL , m_Stencil.m_OpCCW.m_zFail);
pDevice->SetRenderState(D3DRS_CCW_STENCILPASS , m_Stencil.m_OpCCW.m_Pass );
pDevice->SetRenderState(D3DRS_CCW_STENCILFUNC , m_Stencil.m_OpCCW.m_Func );
}
}

你可能感兴趣的:(buffer)