0

EDIT: D24S8 textures cannot be copied. Period. Sometimes, however, it is possible to change the depth buffer format to INTZ, a special FOURCC format, which has the same layout, but can be set as input for texture samplers.

Finally my approach was to use a proxy dll to intercept all texture creation calls to be able to change the format wherever D24S8 was given. Afterwards I could then bind this texture to a texture sampler of the pixel shader, set a R32F render target and write the sampled values (DrawPrimitive on a triangle strip of two primitives) to this target.

Often the developers already used an R32F texture with D3D9 to store the depth values there and circumvent the D3D9 depth/stencil problem. In this case it is possible to straightly copy this texture to system memory if you need access.


The original post:

I am developing a Lidar sensor plugin used with a simulation environment called VBS which gets called after a new frame has been rendered to the back buffer. It has two input parameters of type IDirect3DSurface9*, one to the render target (with format X8R8G8B8) and one to the depth buffer (with format D24S8).

Currently I am trying to somehow extract the position of each pixel relative to the camera. Because I need to use the game API to retrieve the frustum values that are necessary to calculate the projection matrix, I first thought about copying the depth buffer values from GPU to system memory. I already tried GetRenderTargetData and DXLoadSurfaceFromSurface to copy the depth buffer values to a texture created in system memory, but neither of those methods succeeded.

In [1] @ozeanix suggests to use a pixel shader and add an additional render pass to copy the depth values to a texture with a format that is not a depth/stencil format and afterwards "LockRect" this texture.

Trying to implement that approach I realized that I don't know how to pass the depth buffer values to the pixel shader. The only way that I came up with was to copy the depth buffer surface to a newly created 1-level texture of the same format (and afterwards pass that texture to a ps shader), but neither GetRenderTargetData nor DXLoadSurfaceFromSurface nor UpdateSurface succeeded.

Just to make sure that the restrictions are clear: I cannot repeat the render calls (as I said, my plugin gets called only after the whole frame has been rendered), I cannot change the existing shaders (so I think I cannot enable MRT) and I also cannot redirect the depth/stencil output to a different texture (render target) first and copy this texture to the final depth buffer afterwards.

  1. Is there any way how I can pass the depth buffer to the pixel shader?

  2. In case my shader has access to the buffer how am I supposed to execute this pixel shader? Do I have to use "DrawPrimitive" or something similar (in which case I don't know which vertices I have to set as parameters)?

  3. Writing this post I thought about calculating the relative position inside the pixel shader (so setting the projection matrix in my callback, then outputting the positions directly) - is that perhaps a better approach?

Thanks in advance!

[1] Copy depth buffer with non-lockable format (D24S8) to system memory with Direct3D9, Win 8.1

Apollo13
  • 119
  • 1
  • 1
  • 11
  • I can't be of too much help unfortunately. The issue you have (which I didn't really think all the way through) is you don't have a texture for the D24S8 surface, and to the best of my limited knowledge, you cannot attach a surface as a texture object for use in a pixel shader. In other words, you need an `IDirect3DTexture9*` rather than an `IDirect3DSurface9*`. The problem is, to get a texture you'd need to create a new texture of the same size, and then possibly use `StretchRectangle` to draw the surface into level 0 of the texture. – ozeanix Jun 20 '17 at 23:00
  • Try to see if you can use [`IDirect3DSurface9::GetContainer`](https://msdn.microsoft.com/en-us/library/windows/desktop/bb205893(v=vs.85).aspx) to get the `IDirect3DTexture9*` that owns the D24S8 surface you're being passed. If you can successfully get that texture, you can *possibly* use it in a call to [`ID3DXBaseEffect::SetTexture`](https://msdn.microsoft.com/en-us/library/windows/desktop/bb205727(v=vs.85).aspx) which would bind the texture to a name. [See here](https://stackoverflow.com/questions/18740545/how-to-pass-textures-to-directx-9-pixel-shader) for an example. – ozeanix Jun 20 '17 at 23:09
  • If you can get that far, then you have to figure out how to actually sample that texture inside the pixel shader, and that's way too far outside my realm of understanding - I've never tried to sample from a D24S8 and I'm not sure how you would address it. Perhaps the R, G, and B channels could be interpreted as 8 bits each out of the total 24 depth bits, and the alpha channel would bind to the stencil buffer's 8 bits? – ozeanix Jun 20 '17 at 23:11
  • Unfortunately the GetContainer approach does not work. In the meantime I also read multiple times that it is not possible to bind a D24S8 surface to a texture... – Apollo13 Aug 10 '17 at 15:17

0 Answers0