Discussion:
multiple calls to invalidateRect not combined into a single update rect
(too old to reply)
Eric Johnson
2007-09-17 17:43:04 UTC
Permalink
Hi,
I have an audio processing "plugin" dll that works with several
different host applications. I'm seeing a problem when the plugin dll
is used with one particular host application.
Our plugin app creates its own window and needs to redraw certain
rects within this window at a regular interval. We create a timer to
trigger this animation cycle. When the timer callback is called we
use invalidateRect to invalidate the individual rects that need to be
drawn. Usually, by the time that we see a WM_PAINT message, these
small rects have been combined by Windows into a smaller set of update
rects. For example if we invalidate 8 small rects during the
animation, we'll see 2 WM_PAINT messages generated. Sometimes though,
we see a bunch of WM_PAINT messages with all of the individual small
rects needing to be redrawn. Handling all of the these WM_PAINT
messages results in worse performance for our app. Can anyone explain
what would cause the update rect to be calculated differently in some
situations than others?

Thanks,
Eric
Joseph M. Newcomer
2007-09-17 18:14:48 UTC
Permalink
First, are multiple threads involved? IF so, you are seeing the kind of behavior that
would happen if one thread is invalidating a window owned by another thread.

If there is any intervening update opportunity, you will see WM_PAINT messages coming in.
If all of the updates happen in the owner thread of the window, and the scenario is of the
form

OnTimer:
Invalidate
Invalidate
Invalidate
Invalidate
Invalidate
return

then you should see only a single WM_PAINT message. But if between the invalidations
there is an UpdateWindow, or the invalidates happen as the result of discrete message
calls, you will see potentially multiple updates. You would have to show some code schema
(such as the one above) before we could assess why this is happening.
joe
Post by Eric Johnson
Hi,
I have an audio processing "plugin" dll that works with several
different host applications. I'm seeing a problem when the plugin dll
is used with one particular host application.
Our plugin app creates its own window and needs to redraw certain
rects within this window at a regular interval. We create a timer to
trigger this animation cycle. When the timer callback is called we
use invalidateRect to invalidate the individual rects that need to be
drawn. Usually, by the time that we see a WM_PAINT message, these
small rects have been combined by Windows into a smaller set of update
rects. For example if we invalidate 8 small rects during the
animation, we'll see 2 WM_PAINT messages generated. Sometimes though,
we see a bunch of WM_PAINT messages with all of the individual small
rects needing to be redrawn. Handling all of the these WM_PAINT
messages results in worse performance for our app. Can anyone explain
what would cause the update rect to be calculated differently in some
situations than others?
Thanks,
Eric
Joseph M. Newcomer [MVP]
email: ***@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
Eric Johnson
2007-09-17 21:22:37 UTC
Permalink
Hi Joe,
Your intuition was correct. As it turns out, the code was more
complicated than I realized. To make a long story short, yes in some
cases there are 2 threads running. So, now the question is: in the
situation where thread 1 owns the window and thread 2 invalidates
parts of the window, is there any simple way to force a series of
invalidateRect calls to be coalesced into a single invalidate rect?

Thanks,
Eric
Joseph M. Newcomer
2007-09-18 13:42:27 UTC
Permalink
Thread 2 should not be touching the window. A window really needs to be managed by a
single thread (yes, there is a multithreaded drawing example in the MSDN, but life becomes
a lot simpler when all the management is done from a single thread). And no, once you
start doing this from another thread, there is no way to combine them. In fact, it is
fundamental to the definition of Windows that they cannot be combined. Once a thread
invalidates an area, the owner thread is free to send a WM_PAINT. The only way I know to
prevent this is to have the thread create a list of invalidated rectangles, and when it
reaches a clean point where all the invalidations have already happened, PostMessage a
pointer to that array of rects and let the receiving thread handle them.

Example:

typedef CArray<CRect> InvRects;

thread 2 (secondary thread):
InvRects * Inv = new InvRects;

Inv->Add(r1);
...
Inv->Add(r2);
...
etc.
wnd->PostMessage(UWM_INVALIDATE_RECTS, (WPARAM)Inv);

thread 1 (main GUI thread):

LRESULT CMyWnd::OnInvalidateRects(WPARAM wParam, LPARAM)
{
InvRects * Inv = (InvRects *)wParam;
for(int i = 0; i < Inv->GetSize(); i++)
InvalidateRect(&Inv[i]);
delete Inv;
return 0;
}

Note now that you are constrained to do all explicit invalidation in your secondary
thread.
joe
Post by Eric Johnson
Hi Joe,
Your intuition was correct. As it turns out, the code was more
complicated than I realized. To make a long story short, yes in some
cases there are 2 threads running. So, now the question is: in the
situation where thread 1 owns the window and thread 2 invalidates
parts of the window, is there any simple way to force a series of
invalidateRect calls to be coalesced into a single invalidate rect?
Thanks,
Eric
Joseph M. Newcomer [MVP]
email: ***@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
Eric Johnson
2007-09-18 16:10:44 UTC
Permalink
Okay. Thank you for your help, Joe. Looks like I've got some work to
do!

Loading...