News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Flicker, DirectDraw, WaitForVerticalBlank

Started by Jimg, October 26, 2005, 04:16:54 PM

Previous topic - Next topic

u

Uhm... simply make your dialog/window have the WS_CLIPCHILDREN flag.

No acrobatics (like DDraw scanlines, or using bad funcs like LockWindowUpdate) are necessary.
Please use a smaller graphic in your signature.

BogdanOntanu

The solution is diferent for standard GUI or for Games/Directdraw.

For games / directdraw just use a back buffer and this will eliminate any kind of flicker

For GUI with lots of controls the solution si more complicated. Check this:
http://win32assembly.online.fr/source0.html

Search for ESF (Eliminate Screen Flicker) program sample. But for many controls it will be a lot of work :D
Ambition is a lame excuse for the ones not brave enough to be lazy.
http://www.oby.ro

u

I strongly oppose against doing a lot of work just because you've added more controls to your window. [I'm lazy...] . So, let's dissect flickering:
Your window has a hbrBackground - a brush.
When your window's client area has to be updated, Windows sends a WM_ERASEBKGND message. If you let DefWindowProc handle it, DefWindowProc  gets that brush, gets the window clipper (region)for the client area, and fills-in that whole area.
Then, Windows posts a WM_PAINT message. Note that it posts it, not sends. So... it's not rare for Windows to make your app wait 30-60ms before it actually starts processing the WM_PAINT msg. Meanwhile, the videocard redraws everything onscreen - and so for those 30-60ms it shows your window completely in one color.
So now, finally you start drawing on the window: the result of any intermediate operation that you complete (a large BitBlt for background, or a FillRect..) - is accessible by the videocard. If you're making long drawing operations, again you get flicker (showing of intermediate, non-final results).

Then finally after the window is drawn, its children get redrawn. If you had drawn just under a button, it'll flicker.  So, why not actually make GDI avoid drawing where children are!? It's as simple as that WS_CLIPCHILDREN flag.

If you're going to draw the whole background of your window at WM_PAINT, then make your window-class' hbrBackground be NULL, or simply don't let DefWindowProc handle WM_ERASEBKGND.
If you're going to draw a big bitmap, and then many more things on top of it - you _must_ use double-buffering. And it's way simpler than that ESF example. And it's completely disregarding how many child-windows (buttons and stuff) you have - as long as you use the WS_CLIPCHILDREN.

The only problem would be if the child-windows are semi-transparent (where the final output is an alphablend of the background window and the child window). But there you should use custom-drawn, custom-handled virtual-windows, with double-buffering anyway.
Please use a smaller graphic in your signature.

ramguru

Just because Raymond Chen said something bad about LockWindowUpdate I won't reject that API, he just talks, I haven't seen any program written by him.
Style WS_CLIPCHILDREN will make trouble if there are any BS_GROUPBOX style windows in main program (though I have cure)
You can avoid sometimes double-buffer, but not when dealing with images, icons, the trick in flicker-free drawing is that there are no trick
  you just draw everything once, the main words here are everything & once: everything means whole update region ps.rcPaint
  and use InvalidateRect with bErase flag set to false...also it's worth to keep in mind that with this API you're defining update region (ps.rcPaint), so in WM_PAINT routine one should be sure to paint no bigger area than one is invalidating

Jimg

Thanks guys.

First, I'm talking about making a normal GUI dialog behave.  Full graphics programs are pretty simple with back-buffering.  No problem.  Windows controls on a dialog, however are another matter, and that's what I would really like to cover here.

BogdanOntanu-  The "gui" solution looks like a full graphics solution to me.  He fully drawing everything from scratch.  It pretty much totally defeats the reason for using standard controls and yes, as you said, it is a LOT of work.  Not an appropriate solution for your everyday dialog with flicker problems.

Ultrano-  You had me real excited there for a moment.  Attach is the exe only of the earlier program with the dialog changed to WS_CLIPCHILDREN.  Even ignoring the problem with the group boxes for now,  the buttons don't get redrawn, and the outlines for the edits don't get redrawn, and fragments of the edit window itself gets left behind when resizing.   But I believe what you say about the timing.  I don't know how to set hbrBackground be NULL for a simple dialog control but I'll work on it, and try to redraw/clear the background in the WM_PAINT event.  The real solution seems to me to be a combination of the two methods.  Get windows to paint on a back-buffer, and when it is done, blit the whole thing to the real dc.  I have no idea how to get windows to do this however.

ramguru - I'm still digesting what you said, but I don't see how most of it applies to a standard GUI dialogs and controls.

[attachment deleted by admin]

hutch--

Jim,

You can get it to redraw with the following code but the flicker is very bad.


        invoke SetClassLong,hWnd,GCL_STYLE,CS_VREDRAW or CS_HREDRAW


I have just had a look at your source in the earlier zip file and uses WinAsm Studio for its dialog styles which are set in hex rather than readable styles but I would try the two WNDCLASSEX styles "CS_BYTEALIGNWINDOW or CS_BYTEALIGNCLIENT" without the two REDRAW styles even if you have to set them with SetClassLong.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

ramguru

Your application is doomed to flicker, it's crappy EDIT controls and BS_GROUPBOX who are untreatable espeacially when resizing 20 windows at once.

Jimg

Hutch-

Ok, I tried this in the WM_INITDIALOG section

  inv GetClassLong,hWnd,GCL_STYLE
  or eax,CS_BYTEALIGNWINDOW or CS_BYTEALIGNCLIENT
  invoke SetClassLong,hWnd,GCL_STYLE,eax

I didn't seen any effect on the program I tried it on.

is it too late at this point to apply the style?
do I have to apply this style to every control in the dialog?

Sorry for the dumb questions, I've never bothered with this stuff before.




Jimg

#23
Allright you gurus, you were flirting with the answer, just not quit all the way there.  I asked over on the WinAsm Studio forum, and Antonis Kyprianou, the creater of WinAsm Studio showed me how.  Yes, you need to set WS_CLIPCHILDREN on the dialog, but you also have to set WS_CLIPSIBLINGS on all the controls.  Then, don't try to fake out windows by doing the MoveWindow with bRepaint set to FALSE and InvalidateRect and trapping WM_ERASEBKGND or any of the other things people suggested, just do the MoveWindow with bRepaint set to TRUE, and that's it.  Simple and effective.  Here's the results.  It needs a little cleanup up on placement and zorder, but there is NO flickering on my computer.  Hooray!  :cheekygreen:

edit:  fixed static label problem just so it wouldn't distract from fixing the flickering problem.

[attachment deleted by admin]

u

Still, fix up those labels - they are prone to getting dirty.
Please use a smaller graphic in your signature.

Jimg

absolutely.  I was so stoked I couldn't wait that long to post the answer!

Jimg

Ok, I fixed static label problem just so it wouldn't distract from fixing the flickering problem.  I'm surprised that a static doesn't recenter the text when its size changes.  I'm also surprised that I couldn't find an API to tell the static to update itself, I had to do a gettext and a settext to get it to update.  But that has nothing to do with fixing the flickering problem.