Jump to content
  • Advertisement
Sign in to follow this  
kiniport

Copying the frame buffer

This topic is 4816 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm trying to sum the brightnesses of all the pixels on the screen, but reading the frame buffer is incredibly slow. My scene renders at about 2500 fps without copying the frame buffer, and about 45 fps with the copy. The surface is only 256x256, so at 45fps thats only 12 MB/s of bandwidth. It seems like my computer should be able to copy a little faster than that(P4 3.0ghz, radeon 9600). I'm using dx9 and simply locking the back buffer. Is there a faster way? Is rendering to a texture and then locking it faster? Is there a way to do this using a pixel shader? I would somehow need to write data someplace other than the screen inside the shader, like writing to a register and hoping the value stays from pixel to pixel. Thanks in advance.

Share this post


Link to post
Share on other sites
Advertisement
I beleive if you declare a global variable in your pixel shader and keep adding the brightness to it, and at the end of the rendering you could get the data back by calling GetVertexShaderConstantX or get the data by using one of the ConstantTable functions (assuming you're using Dx9 and HLSL).

Hope this helps.

Share this post


Link to post
Share on other sites
Pixel shaders 'constants' are just that, constant... you can't modify them in your shader, so that approach wouldn't work.

You can downsample your rendertarget, so there's less to send back, and effectively do the sumation on the GPU.

You could also lookup into the resulting downsampled texture for retrieving the value in subsequent passes, eliminating the need for transfering it back to the CPU.

-- EDIT --
I've never done anything like this myself, however, I would assume you could do something like:
Let the bilinear filtering take care of averaging 2x2 texels (by sampling in the middle of them), then doing 2x2 or 4x4 of those samples per pass in your pixel shader, effectively downsampling by 4x4 or 8x8 every pass.

I noticed your original question was "sum the brightness".
Averaging would do the same, just multiply with the number of pixels in your original render target (if that's indeed what you want).

Share this post


Link to post
Share on other sites
Thanks for the suggestions.

So is it safe to say that there is no way to send info from a pixel shader back to dx?

c2_0, If I understand you correctly, your suggesting I render my scene to a texture, and then repeatedly render it to smaller buffers. Which begs the question of wheather or not auto-mipmaps are generated on the video card, in which case I could just call GenerateMipSubLevels, and then read the last mipmap level back. I think I'll give it a try.

Share this post


Link to post
Share on other sites
Quote:
Original post by kiniport
Thanks for the suggestions.

So is it safe to say that there is no way to send info from a pixel shader back to dx?


The only way is to render the pixel shader result into a rendertarget, and read the rendertarget back to the system memory. Shaders cannot modify the input data (in current architectures) in any way.

Quote:


c2_0, If I understand you correctly, your suggesting I render my scene to a texture, and then repeatedly render it to smaller buffers. Which begs the question of wheather or not auto-mipmaps are generated on the video card, in which case I could just call GenerateMipSubLevels, and then read the last mipmap level back. I think I'll give it a try.


The only problem here is that D3D doesn't allow automatic mip chains to be locked, since they invariably reside in memory allocated for the video card [smile]

The best way is to calculate as much as possible on the card, and only transfer the final result back to the system memory if and only if absolutely needed.

Share this post


Link to post
Share on other sites
Quote:
Original post by kiniport
Thanks for the suggestions.

So is it safe to say that there is no way to send info from a pixel shader back to dx?

c2_0, If I understand you correctly, your suggesting I render my scene to a texture, and then repeatedly render it to smaller buffers. Which begs the question of wheather or not auto-mipmaps are generated on the video card, in which case I could just call GenerateMipSubLevels, and then read the last mipmap level back. I think I'll give it a try.

No problem.

Auto-miplevels would not be generated on the GPU. The driver would normally take care of this.

May I ask what you're trying to achieve with this, and why you need the value back on the CPU?

Share this post


Link to post
Share on other sites
Quote:

The only problem here is that D3D doesn't allow automatic mip chains to be locked, since they invariably reside in memory allocated for the video card


I was afraid of that.

Quote:

May I ask what you're trying to achieve with this, and why you need the value back on the CPU?


I wrote a simple radiosity renderer for generating lightmaps. I'm rendereing what every texel "sees", and then summing the pixels to get the brightness for that texel. It works fine, but copying the frame buffer takes about 98% of the rendering time.

Now I understand why reading the frame buffer would be slow, but 12MB/s of bandwidth seems pathetic to me.

Share this post


Link to post
Share on other sites
Are you trying to sum or average the luminance that each pixel sees? If you are averaging, then you can use the StretchRect(...) api to downsample by 1/2 the render target size each pass using linear filtering.

If you are summing, then this approach won't work. You would need to use a pixel shader that point samples each of the pixels in your texture (most likely over several passes) and adds their values. The rendertarget for these passes would ideally be 1 pixel, but I don't know if that is possible. Even so, if you take it down to a 2x2 or 4x4 you can do the small amount of addition on the CPU after reading back.

So, to recap:

- Set a 16x16 render texture as the render target.
- Render a full target size quad.
- In the pixel shader, sample the input render texture 16 times in a grid that represents the target pixel in the input texture. The output will be the sum of these samples.
- Repeat to get to a smaller target if necesary. Remember to use additive alpha blending on subsequent passes so you don't overwrite the previous result.

Also, as a side note, what parameters are you using on your create render target call? If you use the wrong memory pool it could kill your performance. I am actually accessing a similar sized texture without that much of a performance hit (on a FX Go5200 nonetheless!!!). Good luck!

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!