问题
EDIT: As ozeanix points out in the comments it is not possible to copy a D24S8 surface to system memory. Unfortunately you also cannot bind the surface (or rather its containing texture) to a pixel shader.
I ended up going the reimplementation way, intercepting all D3D9 calls. If the graphics card supports it - all cards with DX10+ should do - it is sometimes possible to exchange the D24S8 format with FOURCC INTZ, which has the same memory layout, but can be bound to a pixel shader's texture sampler and thus copied to a different texture in video memory. This texture's content can then be copied to a system memory texture with GetRenderTargetData.
Original post:
I am developing a plugin which should calculate the world position of each pixel contained in a Direct3D surface. The plugin gets called via callback when there is a newly rendered image waiting in the back buffer.
Given are two pointers (IDirect3DSurface9*) to the render target surface (D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE) and the depth buffer surface (D3DFMT_D24S8, D3DMULTISAMPLE_NONMASKABLE). The linked device's display mode is also set to "D3DFMT_X8R8G8B8"
The settings above cannot be changed!
To be able to calculate the world position I also need access to the depth buffer values. So my first attempt was to create an offscreen plain surface with format "D24S8" in system memory, use "GetRenderTargetData" to copy the data and then lock this offscreen surface (with LockRect). Unfortunately, the very first command failed already - apparently this format is not allowed in system memory (there is no problem creating such an offscreen surface in the default pool). So I used the DirectX Caps Viewer ...
D3D Device Type "HAL" and Adapter Format "D3DFMT_X8R8G8B8":
Depth/Stencil Formats:
"D3DFMT_D24S8", "D3DFMT_D24X8", "D3DFMT_D16", "D3DFMT_D32F_LOCKABLE"
Texture Formats (only mentioning the depth/stencil & depth formats):
"D3DFMT_D24S8", "D3DFMT_D24X8", "D3DFMT_D16", "D3DFMT_D32F_LOCKABLE",
"DXT1" through "DXT5"
- but all are only supported in conjunction with usage type "0 (Plain)".
Plain Surface Formats: No depth stencil formats at all are listed.
What I also tried:
Create a texture with only one level and format set to D3DFMT_D24S8, placed in D3DPOOL_SYSTEMMEM (also failed)
Create a surface of type D32F_LOCKABLE in D3DPOOL_DEFAULT (successful) and use D3DXLoadSurfaceFromSurface to convert and copy the data so that a subsequent call to LockRect would provide a handle to the data (failed)
Create depth/stencil surface with disabled multisampling (successful) and use StretchRect to copy from source to destination (failed) and check if multisampling is part of the problem
My questions
According to DirectX Caps Viewer D24S8 should be supported on textures. Are those lists only applicable for ressources in default memory pool?
Is there any way I can copy the depth values to system memory at all?
Is there any possibility to enable extended error reporting for DirectX calls on Windows 8.1? I know that beginning with Win8.1 the OS itself uses the same API and thus the DirectX runtime cannot be set to debug mode, but perhaps I have missed an appropriate option
By the way, with D3DDevice Type "REF" there are a few depth and stencil formats listed for Plain Surfaces (D16_LOCKABLE, D16, D32F_LOCKABLE, D32_LOCKABLE, S8_LOCKABLE) and no depth/stencil entries available in the list of texture formats, but I need to use hardware acceleration, otherwise my application renders way too slow.
来源:https://stackoverflow.com/questions/44501884/copy-depth-buffer-with-non-lockable-format-d24s8-to-system-memory-with-direct3