Several Questions Regarding Rendering to Textures

Started by
4 comments, last by 21st Century Moose 13 years, 7 months ago
The subject pretty much says it all. Note that I'm trying to do this without D3DX, so please keep ID3DXRenderToSurface out of the picture :)

1) After calling device->SetRenderTarget, how can I set the render target back to the backbuffer when I'm done rendering to my texture?
2) What's the technical difference between a texture and a rendertarget (as in, device->CreateRenderTarget)? Is it necessary to create a render target or can I render straight to my texture?
3) I am aware that the depth buffer is required to be the same dimension as the RT. However, I will not always need a depth buffer. I there a way that I can disable it so that I do not have to create a new surface just for the depth buffer?

Thanks!
Advertisement
For (1) you'd use IDirect3DDevice9::GetRenderTarget to save out the original backbuffer, then IDirect3DDevice9::SetRenderTarget again to restore the original backbuffer when you're finished the RTT pass (and don't forget to Release () the backbuffer surface afterwards as otherwise D3D will retain a reference to it).

For (2) you should be able to create a texture with D3DUSAGE_RENDERTARGET, then use IDirect3DTexture9::GetSurfaceLevel to get the surface for miplevel 0, then set that as your render target (again, Release () the surface pointer when done).

In theory the steps given in (2) should give you a rendertarget without a depth buffer for (3), but - and I haven't done extensive testing here - it seems as though using this procedure will cause the renderer to just continue using the original depth buffer instead of disabling it. You could implement this and disable Z write/Z test, or alternatively have a look at IDirect3DDevice9::GetDepthStencilSurface, IDirect3DDevice9::SetDepthStencilSurface and IDirect3DDevice9::CreateDepthStencilSurface. IDirect3DDevice9::SetDepthStencilSurface can be passed a NULL to disable the depth/stencil operations.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

Thanks very much!

One final question: how can I copy the contents of a render target to a texture? I can find no method in the documentation that supports this...UpdateSurface and StretchRect both seem to forbid transfers from an RT to a texture. But in the documentation for ID3DXRenderToSurface notes that "If the surface is not a render target, a compatible render target is used, and the result is copied to the surface at the end of the scene." How is this copying accomplished?
1.) You can get call GetBackBuffer on the device to get the back buffer surface, so that you can set it again. Or if you're using additional swap chains, you call it on the swap chain instead.

2.) A render target is just a special type of surface that you can render to. There's an important distinction between surfaces and textures: surfaces are just contiguous blocks of memory with a size and format. Textures are collections of N surfaces (where N is the number of mip levels) with extra data that tells the GPU how to sample from them. So typically a surface isn't useful on its own, since you can't read from it unless you lock it or copy it to a surface that's part of a texture.

CreateRenderTarget just creates a renderable surface, without a texture. However you can create a render target texture by using CreateTexture and passing D3DUSAGE_RENDERTARGET. This creates all of the surfaces and the texture interface so that you can render to it and sample it. To render to it, you get the top mip surface by calling GetSurfaceLevel and passing 0.

The reason CreateRenderTarget is useful is because you can use it to create MSAA surfaces, which you can't do with CreateTexture. So what you do is during init, you create the MSAA surface with CreateRenderTarget and create a non-MSAA render target texture with the same format and dimensions. Then at runtime after you've finished rendering to the MSAA surface, you "resolve" it to the non-MSAA texture using StretchRect.

3. Setting NULL will work, although the debug runtimes will complain about it (which is annoying).
Thanks yet again MJP, I have everything working nicely now!
Quote:Original post by XeonXT
Thanks very much!

One final question: how can I copy the contents of a render target to a texture? I can find no method in the documentation that supports this...UpdateSurface and StretchRect both seem to forbid transfers from an RT to a texture. But in the documentation for ID3DXRenderToSurface notes that "If the surface is not a render target, a compatible render target is used, and the result is copied to the surface at the end of the scene." How is this copying accomplished?


There doesn't seem to be a straightforward way to do this, no. I'd guess LockRect on both, then memcpy, then Unlock would be the best. You would want to write your own version of memcpy that does 4 bytes at a time to optimise this because - according to the MS CRT source code - MS memcpy just copies one byte at a time. Semi-unrolling the loop in chunks of 16/8/4 is also very good here and can give very substantial perf improvements (just use src[0] = dst[0]; src[1] = dst[1]; etc instead of *src++ = *dst++ for max performance with this).

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

This topic is closed to new replies.

Advertisement