Sign in to follow this  
goodie

[C++] BeginPaint takes too much CPU time - any alternative?

Recommended Posts

My app has two areas, inside the main window there is one child-window OpenGL with one object and the other is child-window DataPanel where i would like to display the coordinates object in OpenGL window. Since these coordinates are changing constantly, i set a timer of 20ms which triggers InvalidateRect for DataPanel, and consequently updates all the coordinates. All works well, but i am extremely surprised that it takes so much CPU time. For example, even if between BeginPaint() and EndPaint() i put no code at all, it will take 25% of my processor time (i have 1.83Ghz dual core). Isnt this too much for merely refreshing some data? If i comment out InvalidateRect, it takes from 0-1%. case WM_TIMER: { InvalidateRect(hwnd, NULL, 1); break; } case WM_PAINT: { hdc = BeginPaint(hwnd, &ps); // code EndPaint(hwnd, &ps); break; } Any comments, suggestion, alternative solutions are very much appreciated, Boris

Share this post


Link to post
Share on other sites
How are you computing this "25% processor time"? Hopefully you are not trying to use the values reported in the Windows Task Manager for benchmarking. These numbers only indicate how much of the available CPU time as reported by the process scheduler is being consumed by each process. It has nothing to do with the performance of the process. The only thing it is telling you is that when you process your paint event, your application is consuming more of the available CPU time than when you don't process your paint event, which should be a big "duh" moment.

Share this post


Link to post
Share on other sites
What if you comment out the BeginPaint() and EndPaint() calls?

And anyway, you're rendering at about 50FPS (WM_TIMER is a low priority message and isn't always going to be sent at the speed you request, so you shouldn't be using it if you need precise timing), what's wrong with using up 25% of the CPU?

And what is in your "// code" section?

Share this post


Link to post
Share on other sites
If I comment out BeginPaint() and EndPaint() calls, but leave InvalidateRect() uncommented, it still takes around 25%. I agree that 50FPS is a lot and if i reduce that to 10FPS, CPU usage for this process drops to about 7-10%. I would like this redrawing to take as less CPU time as possible, so it would have more time for computing other functions, which will be quite demanding for CPU.

As for code section, for now it is only this:

case WM_TIMER:
{
InvalidateRect(hwnd, NULL, 1);
break;
}
case WM_PAINT:
{
hdc = BeginPaint(hwnd, &ps);
color = GetSysColor(COLOR_BTNFACE);
SetBkColor(hdc, color);
TextOut(hdc, 20, 20, positionr, lstrlen(positionr));
TextOut(hdc, 20, 40, rotationr, lstrlen(rotationr));
TextOut(hdc, 20, 135, positionv, lstrlen(positionv));
TextOut(hdc, 20, 155, rotationv, lstrlen(rotationv));
EndPaint(hwnd, &ps);
break;
}

Share this post


Link to post
Share on other sites
Rather than render text manually, could you use standard Windows GUI controls such as labels and edit boxes to display the values? This will be many times faster than TextOut() and you won't need a WM_PAINT event at all.

Share this post


Link to post
Share on other sites
When you call InvalidateRect with TRUE for the last parameter that means you are saying that you want BeginPaint to send a WM_ERASEBKGND notification (and possibly others) before returning. That's likely where your time is being spent.

Share this post


Link to post
Share on other sites
Quote:
Original post by Anon Mike
When you call InvalidateRect with TRUE for the last parameter that means you are saying that you want BeginPaint to send a WM_ERASEBKGND notification (and possibly others) before returning. That's likely where your time is being spent.
Yes, that seems likely.

I would not expect the code that is currently in the WM_PAINT handler to cause CPU usage of more than say 1% when run at 50fps. You must be doing something wrong.

Share this post


Link to post
Share on other sites
Thanks everyone for answers - I changed InvalidateRect TRUE to FALSE, but there was no change, so i guess i had a tight main loop, because when i put Sleep(5) in the loop the time taken decreases to 0-1%, which seems normal to me. Is the problem of tight loops usually solved with Sleep() or is there another approach?

// main loop
while(!done)
{
Sleep(5);
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
if (msg.message==WM_QUIT)
{
done=TRUE;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else
{
DrawGLScene();
SwapBuffers(hDCgl);
}
}

Share this post


Link to post
Share on other sites
Quote:
Original post by goodie
Thanks everyone for answers - I changed InvalidateRect TRUE to FALSE, but there was no change, so i guess i had a tight main loop, because when i put Sleep(5) in the loop the time taken decreases to 0-1%, which seems normal to me. Is the problem of tight loops usually solved with Sleep() or is there another approach?
Ah, you didn't say CPU usage was up to 100%.
You had what is called a "busy loop". Some form of yielding is required to reduce the CPU usage back to something sensible. Sleep(1) will do that just fine..

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