代码改变世界

D3D9 优化小技巧

2015-04-16 21:12  风恋残雪  阅读(1399)  评论(0编辑  收藏  举报

此篇文章主要讲一些小技巧,针对前面转载的D3D9 GPU Hacks,我们可以做的一些优化。

在做延迟渲染或者其它需要深度的地方使用INTZ格式的纹理,这样可以直接对纹理进行操作,节省了显存和带宽,这样即使在前向渲染的时候也可以获取深度,有了深度信息我们就可以做很多效果,如水的柔边,水边泡沫,景深等效果。

注:以下示例代码均摘自http://developer.amd.com/wordpress/media/2012/10/Advanced-DX9-Capabilities-for-ATI-Radeon-Cards_v2.pdf

INTZ 纹理示例代码:

Depth Texture Format: INTZ
Description: An additional texture format called INTZ is exposed that allows a 24-bit depth
buffer previously used for rendering to be bound as a texture. Any fetches from this texture
will return the depth values stored. Shadow mapping applications relying on PercentageCloser
Filtering should prefer the use of DX9 Depth Stencil Textures instead. INTZ
additionally exposes an 8-bit stencil buffer when used for depth buffering, allowing stencil
operation to be carried out when an INTZ surface is bound as the active depth stencil buffer.
However the contents of the stencil buffer will not be available as texture data when binding
the surface as a texture.
Note that an INTZ depth buffer may be used as a texture concurrently to the same INTZ
surface being used for depth buffering, as long as depth writes are disabled.
Supported hardware: ATI Radeon 4000 series and above.
Implementation details
A FourCC depth texture format is exposed:
#define FOURCC_INTZ ((D3DFORMAT)(MAKEFOURCC(‘I’,’N’,’T’,’Z’)))
To check support for this feature:
// Determine if INTZ is supported
HRESULT hr;
hr =pd3d->CheckDeviceFormat(AdapterOrdinal, DeviceType, AdapterFormat,
D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE,
FOURCC_INTZ);
BOOL bINTZDepthStencilTexturesSupported = (hr == D3D_OK);
To create an INTZ depth stencil texture:
// Create an INTZ depth stencil texture
IDirect3DTexture9 *pINTZDST;
pd3dDevice->CreateTexture(dwWidth, dwHeight, 1,
D3DUSAGE_DEPTHSTENCIL, FOURCC_INTZ,
D3DPOOL_DEFAULT, &pINTZDST,
NULL);
To bind the depth stencil texture as an active depth buffer:
// Retrieve depth buffer surface from texture interface
IDirect3DSurface9 *pINTZDSTSurface;
pINTZDST->GetSurfaceLevel(0, &pINTZDSTSurface);
// Bind depth buffer
pd3dDevice->SetDepthStencilSurface(pINTZDSTSurface);
Note that calling GetSurfaceLevel() increases the reference count of pINTZDST so you will
need to Release() it when no longer needed.
To bind an INTZ depth buffer texture as a texture:
// Bind depth buffer texture
pd3dDevice->SetTexture(0, pINTZDST);

注意:此处千万不能使用 D3DXCreateTexture 来创建这样的纹理,因为D3DX并没有对此提供支持,创建的返回的纹理类型并不是你需要的INTZ等格式,下面所讲也同等适用。

在渲染阴影的时候我们一般使用D16或者D32,使用tex2dproj函数来利用硬件特性来采样纹理,这样直接返回的是一个阴影系数。渲染阴影的时候我们并不需要一张颜色纹理,但是D3D9必须要绑定一张颜色纹理。我们可以通过上面提到的NULL纹理来达到节省显存的目的,当然使用之前也需要查询当前硬件是否支持NULL纹理。

示例代码如下:

Render Target Format: NULL
Description: A render target format called NULL is exposed. Render targets created with
this format will not have any memory allocated internally, but will satisfy validation
requirements imposed by the DX9 runtime. This functionality is useful when performing
rendering onto a depth buffer without wishing to update an actual color render target since
the DX9 runtime enforces the use of a valid color render target for all rendering operations.
Therefore common depth-only rendering applications like shadow mapping or depth pre-pass
can benefit from using this “dummy” format to save memory that would otherwise be
required to bind a valid color render target for this operation.
Supported hardware: ATI Radeon 4000 series and above.
Implementation details
A FourCC color render target format is exposed:
#define FOURCC_NULL ((D3DFORMAT)(MAKEFOURCC(‘N’,’U’,’L’,’L’)))
To check support for this feature:
// Determine if NULL is supported
HRESULT hr;
hr = pd3d->CheckDeviceFormat(AdapterOrdinal, DeviceType, AdapterFormat,
D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE,
FOURCC_NULL);
BOOL bNULLRenderTargetSupported = (hr == D3D_OK);
To create a NULL render target surface:
// Create a NULL render target with 4x multisampling
IDirect3DSurface9* pDummyRenderTarget;
pd3dDevice->CreateRenderTarget(dwWidth, dwHeight, FOURCC_NULL,
D3DMULTISAMPLE_4_SAMPLES, 0,
FALSE, &pDummyRenderTarget, NULL);
To bind a NULL render target surface:
// Bind a NULL render target at slot 0 so that we don’t have to bind
// a real color buffer; this allows memory savings
pd3dDevice->SetRenderTarget(0, pDummyRenderTarget);

这样我们可以通过这些小技巧来达到节省显存、带宽等目的。还有一些小的技巧,比如Alpha to coverage, depth bound test等,我也会陆续把它们添加进来。

参考文章:

1. D3D9 GPU Hacks

2. Advanced DX9 Capabilities for ATI Radeon Cards