Sign in to follow this  
amtri

how to save window bitmap

Recommended Posts

amtri    189
Hello, I have a Direct3D 9 window with a graphics image being displayed. I'm trying to capture the image from that window only onto a bitmap memory image. I did figure out how to do it, but ran into 2 problems. I'm using device->CreateOffscreenPlainSurface followed by device->GetFrontBufferData and D3DXSaveSurfaceToFileInMemory The above sequence *works*. I use a RECT area where my window is defined and capture just that area. My problems are as follows: 1) The function GetFrontBufferData takes forever. Probably more than 1 second. 2) If I have my application running and then do something on the desktop, even though my window is still there it is no longer on top, so the screen capture actually captures something other than my window, which is now in the back. Does anybody have a clean solution to this problem? Thanks.

Share this post


Link to post
Share on other sites
Lifepower    136
According to MSDN about GetFrontBufferData:
Quote:

This function is very slow, by design, and should not be used in any performance-critical path.

The reason behind this is probably because pipeline is not meant for reading front buffers. Besides GetFromBufferData, another approach wouls be using GetDC(0) to capture display's area and copy it somewhere (that is, using GDI to capture screenshot). I'm not sure it will be any faster though.

As for the other question: since you are capturing front buffer and running in windowed mode, other windows are part of front buffer as well. Sorry, I don't know any solution to this. [sad]

Share this post


Link to post
Share on other sites
Rompa    307
I did this just recently, and it works for both windowed and full screen modes. In my case, I capture the front buffer which is the entire screen even when running in windowed mode, and I exclude the rest of the crap with the window rect stuff below:

bool RenderDevice::TakeScreenShot(const char* szFilename)
{
ASSERT(this);
ASSERT(szFilename);

RECT rectWindow;
bool bSuccess = false;

if (GetWindowRect(m_hWindow, &rectWindow))
{
HRESULT hr;
D3DDISPLAYMODE displayMode;

hr = m_pDevice->GetDisplayMode(0, &displayMode);
if (TSE_SUCCEEDED(hr))
{
IDirect3DSurface9* pSurface;
hr = m_pDevice->CreateOffscreenPlainSurface(displayMode.Width, displayMode.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &pSurface, 0);
if (SUCCEEDED(hr))
{
hr = m_pDevice->GetFrontBufferData(0, pSurface);
if (SUCCEEDED(hr))
{
static u32 uScreenShotCounter = 1;
const char* szSaveFileName = TSEFmt("%s_%03u.bmp", szFilename, uScreenShotCounter);

hr = D3DXSaveSurfaceToFile(szSaveFileName, D3DXIFF_BMP, pSurface, 0, &rectWindow);
if (SUCCEEDED(hr))
{
uScreenShotCounter = (uScreenShotCounter + 1) % 1000;
bSuccess = true;
}
}
pSurface->Release();
}
}
}

return bSuccess;
}


I don't get anything like a 1 second delay, mine is perhaps 1/4 second even at 1920x1200 on my ATI XTX1950X (too many X's if you ask me!). You'd have to play with capturing the back buffer or something to not get any overlapping window, I guess. I've not been bothered to do that though :-)

Share this post


Link to post
Share on other sites
amtri    189
Rompa,

Your approach is what I tried, except that rather than saving to a file, I saved it to memory.

Guess I'll try Lifepower's approach of GetDC(0).

Thanks to both of you!

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