I am trying to learn some DirectX API and, for now, I have just a WINAPI window and a simple render function that displays a bitmap over the entire screen. My WINMAIN function:
LPDIRECT3D9 pD3D; // the Direct3D object
LPDIRECT3DDEVICE9 pd3dDevice; // the Direct3D device
// This is winmain, the main entry point for Windows applications
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
int nCmdShow) {
hInst = hInstance;
// Initialize the window
if (!initWindow(hInstance)) return false;
// called after creating the window
if (!initDirect3D()) return false;
// main message loop:
MSG msg;
ZeroMemory( &msg, sizeof( msg ) );
while( msg.message != WM_QUIT) {
if( PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) {
TranslateMessage ( &msg );
DispatchMessage ( &msg );
} else {
render();
}
}
// Release the device and the Direct3D object
if( pd3dDevice != NULL ) pd3dDevice->Release( );
if( pD3D != NULL ) pD3D->Release( );
return (int) msg.wParam;
}
and this is my render function:
void render(void) {
IDirect3DSurface9* surface;
pd3dDevice->CreateOffscreenPlainSurface(640, // the width of the surface to create
480, // the height of the surface to create
D3DFMT_X8R8G8B8, // the surface format
D3DPOOL_DEFAULT, // the memory pool to use
&surface, // holds the resulting surface
NULL); // reserved
D3DXLoadSurfaceFromFile(surface, NULL, NULL, L"test.bmp", NULL, D3DX_DEFAULT, 0, NULL);
// This will hold the back buffer
IDirect3DSurface9* backbuffer = NULL;
// Check to make sure you have a valid Direct3D device
if( NULL == pd3dDevice ) return;// Clear the back buffer to a blue color
pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 0,0,255 ), 1.0f, 0 );
// Get the back buffer
pd3dDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer );
// Copy the offscreen surface to the back buffer
// Note the use of NULL values for the source and destination RECTs
// This ensures a copy of the entire surface to the back buffer
pd3dDevice->StretchRect(surface, NULL, backbuffer, NULL, D3DTEXF_NONE );
// Present the back buffer contents to the display
pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
So, the main problem is that when the render function is enabled (uncommented) the memory used by the application goes to 400 - 600 Mb in a second. Now, If I disabled (comment) the line from WinMain, the memory is left in 5 Mb but the processor goes crazy and the application uses about 50% of it. So, it looks like WinMain()
uses a lot of processor and render()
a lot of memory. Why? What am I forgetting?
Thanks!
pd3dDevice->CreateOffscreenPlainSurface(640, // the width of the surface to create
480, // the height of the surface to create
D3DFMT_X8R8G8B8, // the surface format
D3DPOOL_DEFAULT, // the memory pool to use
&surface, // holds the resulting surface
NULL); // reserved
D3DXLoadSurfaceFromFile(surface, NULL, NULL, L"test.bmp", NULL, D3DX_DEFAULT, 0, NULL);
You're calling this bit of code which creates resources a bazillion times, but you're not releasing it. It's in the render function which must be called at least 60 times a second (and if it lacks the sync with the vertical retrace, it can be called thousands of times a second, creating a huge problem for you). That means you change the pointer to the surface to a new block of surface memory with the same image and lose the address to the old (unreleased). Therefore, it causes a memory leak.
Shift that code into an initialization function of the application, not in the render function. (and make sure you manage it! When you stop using it, call the release function to lower the ref. count of the COM object so the memory can be claimed by the system (available to you, again))
Edit: This also needs to be moved to the init of the app, it's only needed once here
IDirect3DSurface9* backbuffer = NULL;
// Check to make sure you have a valid Direct3D device
if( NULL == pd3dDevice ) return;// Clear the back buffer to a blue color
pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 0,0,255 ), 1.0f, 0 );
// Get the back buffer
pd3dDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer );
// Copy the offscreen surface to the back buffer
// Note the use of NULL values for the source and destination RECTs
// This ensures a copy of the entire surface to the back buffer
pd3dDevice->StretchRect(surface, NULL, backbuffer, NULL, D3DTEXF_NONE );
// Present the back buffer contents to the display