Skip to main content
GameDev.net gamedev.net
🔒 Locked

Many passes

Started by 51mon Jan 4, 2007 at 5:25 AM 3 replies 550+ views
Original Post
51mon
51mon
I have a technique with many passes. The output from every pass is the input to the next one, i.e. I render to a texture in the first pass then I use that texture when rendering to a second texture in the next pass and so on. My question is, do I have to change render target between every pass or can I make it automatic, since I have such a pipelined architecture?
TheAdmiral
TheAdmiral
Well there's no way to get it done for you, as the API would have no idea when one pass is ending and the next beginning. However, you can make things pretty simple for yourself by encapsulating the process into a set of functions, or a class, if you're that way inclined.

I use a similar method in a couple of my projects for modular post-processing. At device-creation-time, two render-textures are created, matching the viewport's dimensions. I maintain two pointers (IDirect3DTexture9*) pRTSource and pRTDest, initially pointing at these two render-textures, which are used to ping-pong render:

After rendering all the geometry that needs post-processing, a PostProcessBegin() function is called to copy the screen-buffer to the pRTSource texture.
The first post-process is performed, rendering from pRTSource to pRTDest.
The texture pointers are switched with a call to PostProcessFlip().
The second post-process is performed, rendering from pRTSource to pRTDest.
The texture pointers are switched with a call to PostProcessFlip().
...
The final result is copied to the screen-buffer by PostProcessEnd(), and we finally Present() as normal.

In this way, the post-process chain allows for insertion, deletion and permutation without the necessity to mess about with implementation details.

I believe that this method, while not entirely optimal, is fairly standard. I'm sure you could use a similar technique under your circumstances.

Admiral
Ring3 Circus - Diary of a programmer, journal of a hacker.
51mon
51mon
Quote:
Original post by TheAdmiral
Well there's no way to get it done for you, as the API would have no idea when one pass is ending and the next beginning. However, you can make things pretty simple for yourself by encapsulating the process into a set of functions, or a class, if you're that way inclined.

I use a similar method in a couple of my projects for modular post-processing. At device-creation-time, two render-textures are created, matching the viewport's dimensions. I maintain two pointers (IDirect3DTexture9*) pRTSource and pRTDest, initially pointing at these two render-textures, which are used to ping-pong render:

After rendering all the geometry that needs post-processing, a PostProcessBegin() function is called to copy the screen-buffer to the pRTSource texture.
The first post-process is performed, rendering from pRTSource to pRTDest.
The texture pointers are switched with a call to PostProcessFlip().
The second post-process is performed, rendering from pRTSource to pRTDest.
The texture pointers are switched with a call to PostProcessFlip().
...
The final result is copied to the screen-buffer by PostProcessEnd(), and we finally Present() as normal.

In this way, the post-process chain allows for insertion, deletion and permutation without the necessity to mess about with implementation details.

I believe that this method, while not entirely optimal, is fairly standard. I'm sure you could use a similar technique under your circumstances.

Admiral


Thanks for the advice. In the PostProcessFlip() function do you lock the textures and exchange the pointers? I have different sizes of all my textures (I'm working with downsampling) so I might do it best with just standard procedure? I was just checking if there was some method of saving CPU-GPU calls when the architecture is static and the GPU have all work laid out (through the technique).
AndyTX
AndyTX
Quote:
Original post by 51mon
Thanks for the advice. In the PostProcessFlip() function do you lock the textures and exchange the pointers?

Definitely don't lock the textures! All you want to do is swap them... the one that's the texture is the new render target and vice versa.

Quote:
Original post by 51mon
I was just checking if there was some method of saving CPU-GPU calls when the architecture is static and the GPU have all work laid out (through the technique).

No, there is no such way right now (other than resorting to lower-level interfaces like AMD's CTM or NVIDIA's CUDA). DX10 makes these "small batches" more efficient though.
TheAdmiral
TheAdmiral
Quote:
Original post by AndyTX
Definitely don't lock the textures! All you want to do is swap them...

That is, swap the pointers you use to reference them. Observe that you never instantiate a IDirect3DTexture9 object (in fact, it causes an error to do so), but you only create pointers to them. It costs you virtually nothing to swap these two pointers (say, using std::swap), but as far as your implementation is concerned, the textures themselves have been swapped by doing so.

Of course, you could lock both textures and swap the buffers, but this would be insanity [rolleyes].

Admiral
Ring3 Circus - Diary of a programmer, journal of a hacker.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.