Sign in to follow this  
tweduk

Retrieving a region of render target

Recommended Posts

In Direct3D9, one can easily obtain a copy of an entire render target surface using IDirect3DDevice9::GetRenderTargetData, so that it can be locked and inspected by the application. For performance reasons, I want to obtain a copy of a region of a render target surface (as opposed to the entirety). To do this, it seems one has to: 1. Use the render target of interest as a texture and draw a textured quad into a second render target (that happens to be the same size as the region of interest). 2. Call IDirect3DDevice9::GetRenderTargetData on the second render target. Is this how people typically do this, or am I missing a more direct way?

Share this post


Link to post
Share on other sites
MJP,

I did notice StretchRect but I didn't like the look of it for a couple of reasons: (a) the comment that "driver support varies" makes it sound like it might not be something that can be relied on, (b) it doesn't say whether or not it's guaranteed to be hardware-accelerated assuming one is using a pure HAL device (although it most likely is) and (c) it seems to have a lot of restrictions, although most don't matter for what I'm doing.

I guess I'll try both techniques and see which one works best. Thanks.

Share this post


Link to post
Share on other sites
AFAIK StretchRect is hardware-accelerated, since it operates on surfaces in the DEFAULT pool (I'd imagine pulling the surface into system memory and then writing it back to AGP or device memory would be painfully slow). But yeah, the driver restrictions are a problem. Unfortunately there's just not a whole lot of options when it comes to reading back render-targets, by nature it's an expensive operation that most tend to avoid.

Share this post


Link to post
Share on other sites
Thanks for the comments, MJP.

I'm implementing an editor for 3D geometry, and for getting picking to work intuitively and accurately, a hybrid approach might be the way to go. Having tried a purely geometric method using raycasting, it seems that there are some corner cases that are problematic, resulting in picking that doesn't behave intuitively. These problems might be solved by combining geometric and framebuffer-based techniques.

All I need is a small region of pixels around the cursor (actually, they are "IDels" - ID values for the geometric objects in the scene that get drawn into a separate render target). I might also want to read a region of the depth buffer, but I haven't yet looked into how to verify that the hardware supports it.

Thus, it's a semi-realtime app and as far as performance goes, any algorithm that provides feedback to the user about what they just picked at an interactive rate should be fine.

Share this post


Link to post
Share on other sites
If you want to accelerate picking, you could render to a 1x1 render target and give each object a unique ID (ID could be something as simple as the object index in your master array). That ID is what is rendered out by the pixel shader to the target. Then you could use GetRenderTargetData and read back that one pixel to see which object is getting picked.

I did this a few years ago in a research project and it worked pretty well. The drawback is that it adds another render pass. However, the main expense here is transforming the vertices; the pixel shader will run on just one pixel per object. Since most applications are fill-rate bound, the transformation of extra vertices probably won't affect performance much. If you want to avoid processing the vertices twice, you could look at using ProcessVertices to save the results of the transformations so you can reuse it.

neneboricua

Share this post


Link to post
Share on other sites
neneboricua19,

That's pretty much what I was planning on doing, except that I'm going to write out IDs for the entire viewport into a render target, for a few reasons:

1. It should enable me to do nice effects like a "line-art" shader, which identifies the boundaries between regions of different IDs.

2. I can avoid re-rendering the scene whenever the user picks another, different point while the scene is static.

3. On hardware that can use multiple render targets, I should be able to render the scene normally and as IDs at the same time fairly cheaply, using multiple render targets. Even low-end cards support this nowadays.

I plan on examining a small region of pixels around the cursor, rather than just the one under the cursor, because if the user wants to pick a line of width 1 pixel, it will be a bit fiddly if they have to click exactly on the line.

Nice to know I'm on the right track, thanks!

[Edited by - tweduk on April 22, 2008 2:50:20 PM]

Share this post


Link to post
Share on other sites
Sounds like a good plan. The only "gotcha" might be that if you want to use multiple render targets, all of the targets have to be the same dimensions and format.

Keep in mind that if you write out the ID's for the entire buffer and call GetRenderTargetData on it every frame, you will take a pretty large performance hit. If at all possible, you should at least double, if not tripple buffer this data. In a particular frame, you should access the results of the GetRenderTargetData call you issued 2 or 3 frames before. This is to avoid stalling the pipeline. Hopefully by the time you actually try to look at ID's, the copy will be done and you won't incur such a large performance cost.

neneboricua

Share this post


Link to post
Share on other sites
Quote:
Original post by neneboricua19
Sounds like a good plan. The only "gotcha" might be that if you want to use multiple render targets, all of the targets have to be the same dimensions and format.


They don't have to be the same format, only the same number of bits per pixel. And only Nvidia 6 & 7 series have this restriction, IIRC.

Share this post


Link to post
Share on other sites
neneboricua19,

Yeah, performance might be pretty bad if I grabbed the whole of the ID buffer, so each time I want to pick, I will blit (well, StretchRect or draw a textured quad) a small region of the ID buffer around the cursor position into another render target (say 7x7 or 5x5), and GetRenderTargetData on that.

Pipeline stalls don't really matter too much for this app, as long as the app responds at interactive rates to what the user is doing.

Share this post


Link to post
Share on other sites
You shouldn't have problems with StretchRect. The driver comments are quite old, and there shouldn't be any problem with current drivers of any card made in the last several years (5 at least, I'd say).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this