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

GetRenderTargetData - does it block?

Started by Omroth May 24, 2010 at 8:02 AM 12 replies 4.5k views
Original Post
Omroth
Omroth
Hey guys. I have some code I'm using here to grab the back buffer onto a surface in main memory. My question is: does this block? Ie, will the surface in main memory be ready when this has finished executing? Thanks, Ian D3DDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &bBuffer ); // Figure the size we're snagging. D3DSURFACE_DESC desc; bBuffer->GetDesc(&desc); HRESULT hr = D3DDevice->CreateOffscreenPlainSurface(desc.Width,desc.Height,desc.Format,D3DPOOL_SYSTEMMEM,&mBuffer,NULL); D3DDevice->GetRenderTargetData(bBuffer , mBuffer); bBuffer->Release(); if (lastBuffer) { lastBuffer->UnlockRect(); lastBuffer->Release(); } // TODO: Investigate alternatives to D3DLOCK_DONOTWAIT D3DLOCKED_RECT pLockedRect; hr = mBuffer->LockRect(&pLockedRect,NULL, D3DLOCK_DONOTWAIT); lastBuffer = mBuffer;
Evil Steve
Evil Steve
Quote:
Original post by Omroth
My question is: does this block? Ie, will the surface in main memory be ready when this has finished executing?
Yes, it'll block - GetRenderTargetData() will finish rendering anything queued up and then copy the contents of the backbuffer to mBuffer.
Omroth
Omroth
Thanks EvilSteve.

I've heard a lot about the inefficiencies of getRenderTargetData requiring DX to finish rendering all of the stuff "queed up". If I'm not worried about screen output, would it make sense to render to a series of buffers, and only call getRenderTargetData on each buffer once it's finished rendering? Would that have an appreciable speed increase?

Thanks,
Ian
Evil Steve
Evil Steve
You could double buffer the results, I.e. render to two render targets in turn, which could help, but would introduce a frame of lag.

Why do you need to get the render target data in the first place? There may be a better way to do things.
Omroth
Omroth
I'm able to deal with lag of up to a second really, I just need to be able to get frames from the card to main memory as close to 25 frames a second as possible. I also have no requirement for the graphics card to output anything via VGA at all.

What I'm basically doing is using DirectX/the 3d card to create a video stream, which needs to go via main memory to a separate card for further processing before being output.

Can you think of any techniques I can use to speed this all up?

Cheers,
Ian
Evil Steve
Evil Steve
I think you'll probably get the best performance out of using GetRenderTargetData() with a double-buffered system. Anything else will involve locking a default pool resource in non-readonly mode, which is usually a killer for performance.
crowley9
crowley9
DX10 has better support for ths sort of thng (staging buffers, and DO_NOT_WAIT locks), which will likely give you better performance. If using DX10 is an option for you, this is the way to go.
Omroth
Omroth
Thanks again guys.

I'm getting some weird output from this now. The frames I'm getting sent down have a tear in them, a diagonal tear where the top left "corner" seems to be from the previous frame, so I'm assuming that the backbuffer is being written to as GetRenderTargetData is doing the copy.

This goes against what I was expected - do you have any suggestions how I can diagnose this further?

Thanks,
Ian
Omroth
Omroth
Fyi, this is on a Radeon 5850 running Catalyst drivers 2009.0925.1707.28889.

I suppose I should try a driver update as well.
rubicondev
rubicondev
You can either lock and get a perfect frame, or read it "right the hell now" and you'll get something that isn't quite finished. Not sure what the 3rd option is that you're looking for tbh - this is a logical problem, not a rendering specific thing.

Best advice has been given - use a locking method and double-buffer it to keep the throughput speed up.
------------------------------Great Little War Game
Omroth
Omroth
You misunderstand - I /thought/ I was getting the finished frame, as was implied above, by my current method. What extra do I need to do to "lock" it?
Nik02
Nik02
When you use the "do not wait" flag with the lock, you say that you don't care if the rendering is finished or not - just give the data that is in the buffer this instance. Try removing the flag.

I believe that in most GPUs, the surface-to-surface copy is implemented as a simple render operation (though probably bypassing most of the geometry setup needed in "ordinary" rendering). A diagonal tear might simply be an artifact of this process.
Niko Suni
Omroth
Omroth
I've tried removing the flags but still get the tearing - am I locking the right thing at the right place? Do I need to "lock" the backbuffer as well?

Thanks for all the help guys,
Ian
JohnnyCode
JohnnyCode
Guys I googled this
Quote:

"
When I try to play Nocturne it gives me the error message:

Unable to Lock Front Buffer

File: wddvmem.cpp
Line: 838

I'm running Vista, but I've changed the GameTap compatibility properties to XP. I've tried everything that works with other games (i.e. BlloodRayne) such as Run as Administrator, Run in 256 Color, Run in 600x480 etc. If anyone has any other suggestions I'm game.
"


If front buffer is lockable , then, after call to Present(), Front buffer is lockable with delay of 0. If present() blocks of course. You should be able to access it for reading.

Topic Locked

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

Sign in to reply to this topic.