ali
ali

Reputation: 11045

DirectX small application consuming resources like hell

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!

Upvotes: 0

Views: 473

Answers (2)

Vijay
Vijay

Reputation: 11

The Processor usage is 50% is mainly due to frequent calling of while loop infinity times.

ex.,

while(TRUE)
{
}

This will check frequently, as you are instruction the processor to concentrate this as the condition is true. if you are using 4 core processor, one of the processor will completely focus to this process, in my case I used 4 cores, thus my cpu usage is 25%. I think you are using 2 core processor.

while(TRUE)
{
Sleep(1);
}

This will resolve your processor problem.

Upvotes: 1

user1309389
user1309389

Reputation:

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

Upvotes: 3

Related Questions