×
INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Contact US

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Students Click Here

Device Context memory leaks and poor frame rate
2

Device Context memory leaks and poor frame rate

Device Context memory leaks and poor frame rate

(OP)
I have recently used basic API functions to load a bitmap and make it 'bounce' around the screen. The program implements a wrapper class which does all the loading, blitting, drawing, and creating of the bitmap being used.

I am currently having problems with the "draw" function of my program, which takes as parameters the Device Context of the window to blit to, and the (x, y) location of the window to draw to, then performs the BitBlt function using these parameters as a basis and uses default values for every other argument in the API function. Originally, before learning of the GetDC(), ReleaseDC() system, I simply called the function like this:

myBitmap.draw(x, y, GetDC(hWnd));

This method got me fantastic frame rates and relatively good results, except for the fact that it had a memory leak, responsible for making BitBlt fail ever 9978th time.

After realizing this, I quickly embedded the new ReleaseDC() function into the program after placing the HDC into a variable and passing it into the function. The code then looked something like this:

HDC windowDC;

.
.
.

<start main loop>

windowDC = GetDC(hWnd);
myBitmap.draw(x, y, windowDC);
ReleaseDC(hWnd, windowDC);
UpdateWindow(hWnd);

<end main loop>

.
.
.

DeleteDC(windowDC);

This still compiles, runs, and responds. However, even though the frame rate has technically increased (quite dramatically as a matter of fact), the refresh rate seems to have dropped to a crawl. What at one point was a smooth bouncing action has now become a choppy slide show with the image not behaving with the same physical activity as before. I have posted the code in completion below. If anyone has any comments or possible solutions, they would be greatly appreciated. Thank You.

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdlib.h>
#include <String.h>
#include "Bitmap.h"
#include "Input.h"

LRESULT CALLBACK WndProc( HWND hWnd, UINT messg,
                                WPARAM wParam, LPARAM lParam );

bool running = true;

const int RESWIDTH = 1280;
const int RESHEIGHT = 1024;
const double XMAXVELOCITY = 750.0;
const double YACC = 1500.0;
const double XACC = 2000.0;
const LPTSTR PATH = "C:/Bounce.bmp";

int WINAPI WinMain(HINSTANCE hInst,     /*Win32 entry-point routine */
                    HINSTANCE hPreInst,
                    LPSTR lpszCmdLine,
                    int nCmdShow)
{
    #pragma unused(lpszCmdLine)
    HWND hWnd;
    MSG lpMsg;
    WNDCLASS wc;
    clsBitmap testBitmap;
    clsKeyboard keyboard;
    DEVMODE dm;
    HDC windowHDC;
    double currentTick = 0;
    double x = 0;
    double y = 0;
    long numFrames = 0;
    double totalTime = 0;
    double averageFR = 0;
    double currentTime = 0;
    bool forward = true;
    bool up = false;
    double yVelocity = 0;
    double xVelocity = 0;
    bool acc;

    if(!hPreInst)            /*set up window class and register it */
    {
        wc.lpszClassName     = szProgName;
        wc.hInstance         = hInst;
        wc.lpfnWndProc        = WndProc;
        wc.hCursor            = LoadCursor(NULL, IDC_ARROW);
        wc.hIcon            = LoadIcon(NULL, IDI_APPLICATION);
        wc.lpszMenuName        = NULL;
        wc.hbrBackground    = (HBRUSH)GetStockObject(WHITE_BRUSH);
        wc.style            = 0;
        wc.cbClsExtra        = 0;
        wc.cbWndExtra        = 0;

        if(!RegisterClass(&wc))
            return false;
    }

    hWnd = CreateWindow(szProgName,                            /* now create the window */
                        "CodeWarrior Win32 stationery",
                        WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
                        0,
                        0,
                        RESWIDTH,
                        RESHEIGHT,
                        (HWND)NULL,
                        (HMENU)NULL,
                        hInst,
                        (LPSTR)NULL);

    ShowWindow(hWnd, nCmdShow );
    UpdateWindow( hWnd );
    
    memset(&dm,0,sizeof(dm));
    if(!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm))
    {
        MessageBox(NULL, "Could Not Enum Display Settings", "Error", MB_OK);
    }
    dm.dmPelsWidth    = RESWIDTH;                    
    dm.dmPelsHeight    = RESHEIGHT;                    
    dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;    
    int result = ChangeDisplaySettings(&dm,CDS_FULLSCREEN);
    
    RECT windowRect;
    GetWindowRect(hWnd, &windowRect);
        
    testBitmap.load(PATH);
    
    ShowCursor(false);
    
    windowHDC = GetDC(hWnd);
    
    totalTime = GetTickCount();
    currentTick = GetTickCount();
    while(running)                    /* begin the message loop */
    {
        if(keyboard.keyIsDown(VK_ESCAPE))
            running = false;
        currentTime = GetTickCount() - currentTick;
        currentTick = GetTickCount();
        
        if((keyboard.keyIsDown(VK_RIGHT) && !keyboard.keyIsDown(VK_LEFT)))
        {
            xVelocity += XACC * (currentTime / 1000);
            if(xVelocity > XMAXVELOCITY)
                xVelocity = XMAXVELOCITY;
        }
        else if(xVelocity > 0)
        {
            xVelocity -= XACC * (currentTime / 1000);
            if(xVelocity < 0)
                xVelocity = 0;
        }
        
        if(keyboard.keyIsDown(VK_LEFT) && !keyboard.keyIsDown(VK_RIGHT))
        {
            xVelocity -= XACC * (currentTime / 1000);
            if(xVelocity < -XMAXVELOCITY)
                xVelocity = -XMAXVELOCITY;
        }
        else if(xVelocity < 0)
        {
            xVelocity += XACC * (currentTime / 1000);
            if(xVelocity > 0)
                xVelocity = 0;
        }
        
        if(x < windowRect.left)
        {
            xVelocity = 0;
            x = windowRect.left;
        }
        else if(x > (windowRect.right - windowRect.left) - testBitmap.getWidth())
        {
            xVelocity = 0;
            x = (windowRect.right - windowRect.left) - testBitmap.getWidth();
        }
        
        x += xVelocity * (currentTime / 1000);
        if(acc)
            yVelocity += YACC * (currentTime / 1000);
        else
        {
            yVelocity -= YACC * (currentTime / 1000);
            if(yVelocity <= 0)
            {
                yVelocity = -yVelocity;
                acc = !acc;
                up = !up;
            }
        }
        if(up)
            y -= yVelocity * (currentTime / 1000);
        else
            y += yVelocity * (currentTime / 1000);
        if((!up && y >= (windowRect.bottom - windowRect.top) - testBitmap.getHeight()))
        {
            acc = !acc;
            up = !up;
            y = 2 * (windowRect.bottom - windowRect.top - testBitmap.getHeight()) - y;
        }
        windowDC = GetDC(hWnd);
        if(!testBitmap.draw(x, y, windowHDC))
        {
            running = false;
            ReleaseDC(hWnd, windowDC);
        }
        else
        {
            if(GetMessage(&lpMsg, NULL, 0, 0))
            {
                TranslateMessage(&lpMsg);
                DispatchMessage(&lpMsg);
            }
            UpdateWindow(hWnd);
            numFrames++;
        }
        
    }
    DeleteDC(hWnd, windowHDC);
    totalTime = GetTickCount() - totalTime;
    ShowCursor(true);
    ChangeDisplaySettings(NULL, 0);
    averageFR = numFrames / (totalTime / 1000);
    return(lpMsg.wParam);
}

LRESULT CALLBACK WndProc( HWND hWnd, UINT messg,                /*callback procedure */
                                WPARAM wParam, LPARAM lParam )
{
    switch(messg)
    {
        case WM_PAINT:
        break;
        
        case WM_DESTROY:
            PostQuitMessage(0);
            running = false;
        break;
        
        default:
            return( DefWindowProc( hWnd, messg, wParam, lParam ) );
    }

    return(0L);
}

RE: Device Context memory leaks and poor frame rate

(OP)
First of all, I would like to thank you for the link to that article. It was an interesting read, and will do me nothing but good in getting things to animate.

With that said, I finally found out that the real problem with my program (and the reason I could never figure out what was wrong with my device context) had nothing to do with the Device Context at all!!! It was a time related issue!!

The function I was using to calculate how much time had passed (GetTickCount()) is only accurate down to the millisecond. My frame rate was astronomical, somewhere around 35,000 frames per second. This means that over 90% of the time, the amount of time that had passed since the last frame was zero!!! Zero time means zero movement.

As for that 10% of the time when it was not zero, the bitmap seemed to do a "leap" to catch up to where it should be. These occational leaps the bitmap made gave the illusion of a slow refresh rate!! I was able to fix the problem by putting a restriction on the frame rate.

RE: Device Context memory leaks and poor frame rate

>aGetTickCount ... accurate down to the millisecond

Might be worth pointing out that it isn't...it has a tick rate equal to that of the system timer, which is approx 55ms on  W95/98/Me, 10ms on NT/2000/2003, and generally 15ms on XP

RE: Device Context memory leaks and poor frame rate

This is a nice 'stopwatch' class for timing out things with high precision.
Does nice for an animation.

filename: sw.h



#ifndef SW_H
#define SW_H

#define WIN32_LEAN_AND_MEAN

#include    <windows.h>


/*
=================================================
class SW

    Measures time intervals with best precision
    available under windows.

    Returns time values in seconds with fractions
    e.g.: 0.00000012345 and 1.20001752 seconds

=================================================
*/
class SW
{
private:
    LARGE_INTEGER        liFreq;
    LARGE_INTEGER        liStart;
    LARGE_INTEGER        liStop;

public:
    BOOL    bAvailable;

public:
    SW()
    {
        liStart.QuadPart = liStop.QuadPart = 0;
        bAvailable = QueryPerformanceFrequency(&liFreq);
    }

    void    Start()
    {
        QueryPerformanceCounter(&liStart);
    }

    void    Stop(double& dSeconds)
    {
        QueryPerformanceCounter(&liStop);
        dSeconds = (((double)liStop.QuadPart - (double)liStart.QuadPart) / (double)liFreq.QuadPart);
    }

    void    Reset()
    {
        liStart.QuadPart = liStop.QuadPart = 0;
    }
};


#endif //SW_H



Here some pseudo code sample in how to use it:



BYTE    bContinue = 1;
double    dElapsed, dInterval = 0.04;    //== (1/25) seconds means 25 fps.
SW        sw;

sw.Start();

while(bContinue){

    sw.Stop(dElapsed);

    if(dElapsed < dInterval) continue;


    BitBlt(...);

    sw.Start();
}



I also use it a lot for measuring performance of a piece of code :)

Red Flag This Post

Please let us know here why this post is inappropriate. Reasons such as off-topic, duplicates, flames, illegal, vulgar, or students posting their homework.

Red Flag Submitted

Thank you for helping keep Tek-Tips Forums free from inappropriate posts.
The Tek-Tips staff will check this out and take appropriate action.

Reply To This Thread

Posting in the Tek-Tips forums is a member-only feature.

Click Here to join Tek-Tips and talk with other members! Already a Member? Login

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close