The MASM Forum

Projects => ObjAsm => Topic started by: Biterider on May 25, 2021, 04:02:46 AM

Title: Flicker reduction drawing strategy
Post by: Biterider on May 25, 2021, 04:02:46 AM
Hi
I want to share the result of a flicker reduction strategy for normal windows.
When experimenting with dynamic layouts, I've found that dialogs flicker a lot less when they are resized than regular windows. It seems that dialogs have a smarter implementation to redraw the background. Unfortunately, this feature doesn't seem to be available for regular windows. That said, if you want better flicker behaviour, you'll have to write your own code.  :badgrin:

A common painting strategy in coding examples is to paint the entire background first, and then paint any remaining child windows. This is fine for immutable windows, but when they have to be changed and redrawn frequently, such as resizing, the poor design quickly becomes apparent.

In this situation, the goal is to paint the background only where it is needed and avoid painting over the areas covered by child windows. This requires the creation of a dynamic array of rectangular areas, starting with the client window and excluding all areas of the child windows.  :biggrin:

I wrote the code in the form of a WndBackground object (derived from DataCollection) to do this job. The result is impressive; the window practically no longer flickers!

Regions were candidates for the implementation, but they lack the ability to exclude other regions, so I went with a collection of RECT structures. Maybe a linked list of RECTs would be a better performance choice, but for the moment, I use a DataCollection, that is easier to handle.

Attached the source code and a demo binary from a project I'm working on.

To see the impact of the implementation, run one of the binaries and create an MDI child by pressing Ctrl+N. Now change the size by dragging the border.
Compare the visual result with the other binary.

Have fun!  :cool:

Biterider
Title: Re: Flicker reduction drawing strategy
Post by: HSE on May 25, 2021, 04:56:24 AM
Hi Biterider!

Fantastic  :thumbsup:

Now that MDI child is not flickering we can clearly  see that, dragging superior border, statusbar jump like crazy  :biggrin: :biggrin: :biggrin:

Have fun!

HSE.
Title: Re: Flicker reduction drawing strategy
Post by: Biterider on May 25, 2021, 05:31:42 AM
Hi HSE
You mean that dragging the upper border of the MDI child, its Statusbar is jumping?
I can not see that here (Win10). What OS do you have? Both binaries are doing the same thing?


Biterider
Title: Re: Flicker reduction drawing strategy
Post by: HSE on May 25, 2021, 06:11:49 AM
Biterider:

Quote from: Biterider on May 25, 2021, 05:31:42 AM
You mean that dragging the upper border of the MDI child, its Statusbar is jumping?
Yes. Resizing using upper border, status bar is moved upward or downward (I think) and redraw again in his position, that look like increasing and decreasing height.

Quote from: Biterider on May 25, 2021, 05:31:42 AM
What OS do you have? Both binaries are doing the same thing?
Same thing in 7-32 and 7-64, both files. Child flickering attract a little more attention, removing flickering you note better this behaviour.
HSE
Title: Re: Flicker reduction drawing strategy
Post by: Biterider on May 25, 2021, 06:32:51 AM
Hi HSE
There are 2 Statusbars. One in the frame Window (below the client window) and another in the MDI child. I think you mean the first. Right?

Biterider
Title: Re: Flicker reduction drawing strategy
Post by: HSE on May 25, 2021, 07:00:39 AM
 :thumbsup:
Title: Re: Flicker reduction drawing strategy
Post by: jj2007 on May 25, 2021, 07:16:42 AM
I'm afraid the demo flickers a lot here on my Win7-64 machine. Virtually everything flickers when resizing, even the menu!

For comparison I attach a small editor demo (some functions don't work yet). On my machine, it remains pretty calm, with the exception of the three controls (2x edit, one static) embedded into the toolbar in the upper right corner.
Title: Re: Flicker reduction drawing strategy
Post by: HSE on May 25, 2021, 08:23:00 AM
Quote from: jj2007 on May 25, 2021, 07:16:42 AM
On my machine, it remains pretty calm
There is a problem here, the background is greenish!!  :biggrin:

Very interesting the resizing problem with upper border is similar, but also with lower border. I addition you can see a green band at right when enlarging from left or right.
Title: Re: Flicker reduction drawing strategy
Post by: jj2007 on May 25, 2021, 08:52:47 AM
Quote from: HSE on May 25, 2021, 08:23:00 AM
There is a problem here, the background is greenish!!  :biggrin:
:tongue:

QuoteVery interesting the resizing problem with upper border is similar, but also with lower border. I addition you can see a green band at right when enlarging from left or right.

On my machine I have no flicker at all when resizing vertically. In contrast, horizontal resizing makes the three embedded controls in the upper right corner flicker a bit.

The menu remains always calm. In contrast, biterider's demo shows flicker in the menu, which is quite odd :cool:
Title: Re: Flicker reduction drawing strategy
Post by: HSE on May 25, 2021, 09:09:47 AM
Quote from: jj2007 on May 25, 2021, 08:52:47 AM
horizontal resizing makes
The scroll box is oscillating between two different sizes and positions when horizontal resizing   :rolleyes:
Title: Re: Flicker reduction drawing strategy
Post by: jj2007 on May 25, 2021, 09:14:38 AM
You are right :thumbsup:

Very weird, it really jumps up and down. With vertical resizing it remains very smooth. I don't have control over this behaviour, it's a standard RichEdit "feature", apparently. Toggling word wrap has no effect (this was my suspicion) :sad:

@Biterider: Your demo really flickers. The menu, the toolbar, the tree control - everything. I suppose it's really the background erasing that goes haywire. But why the menu??? That is NC background.
Title: Re: Flicker reduction drawing strategy
Post by: HSE on May 25, 2021, 09:43:36 AM
Quote from: jj2007 on May 25, 2021, 09:14:38 AM
it's a standard RichEdit "feature"

Usually I use MoveWindow, but help say:
QuoteTo resize the control, you can use the SetWindowPos function.

Title: Re: Flicker reduction drawing strategy
Post by: jj2007 on May 25, 2021, 10:08:28 AM
Tested, no effect. I bet that SetWindowPos uses MoveWindow under the hood :cool:
Title: Re: Flicker reduction drawing strategy
Post by: jj2007 on May 25, 2021, 07:39:20 PM
P.S.: The "jumping scrollbar" in my demo does not appear in my WinXP VM. It behaves normally, although there is generally much more flicker than on Win7.

If I take away the vertical scrollbar by omitting WS_VSCROLL from the style during CreateWindowEx, and then enable it afterwards with SetWindowLong, I get a smooth scrollbar - no jumps, see attachment!

  gcStyleEdit= WS_BORDER or ES_LEFT or ES_AUTOVSCROLL or ES_MULTILINE or 0*WS_VSCROLL
  GuiControl MyEdit, "richedit", bcol RgbCol(222, 255, 240)
 
  invoke GetWindowLong, hMyEdit, GWL_STYLE
  or eax, WS_VSCROLL
  invoke SetWindowLong, hMyEdit, GWL_STYLE, eax


So it seems the built-in RichEdit scrollbar has a little problem - I've added it to the RichEd20.dll bugs thread (http://masm32.com/board/index.php?topic=6563.msg102917#msg102917) :sad:
Title: Re: Flicker reduction drawing strategy
Post by: LiaoMi on May 25, 2021, 07:59:06 PM
Hi Biterider,

on my machine, I didn't notice any difference  :undecided: I think the best way would be to measure the performance metric and display it as data.

The Linux perf GUI for performance analysis - https://github.com/KDAB/hotspot and https://github.com/KDAB/hotspot#screenshots
Library of ImGui controls for displaying performance metrics - https://github.com/GameTechDev/MetricsGui
Performance counter monitoring GUI - https://github.com/numascale/perf-gui

By synchronizing data objects in each test, you can determine where the problem area is. You can create a set of tests for both cases, and then measure the timings that affect the desynchronization of rendering to the screen.
Title: Re: Flicker reduction drawing strategy
Post by: LiaoMi on May 25, 2021, 08:08:37 PM
Hi jj2007,

when scrolling the text has at least 3 additional frames, the text is displayed with a soapy effect. The top border causes flickering at the bottom region of the window when resized. With general resizing, there is a green flicker in the background of the program  :rolleyes:
Title: Re: Flicker reduction drawing strategy
Post by: LiaoMi on May 25, 2021, 08:58:56 PM

We can visually see the flicker, if we use the program screentogif, in this program, you can change the recording rate and view the rendering by frame. By combining this data with the obtained measurements, then we can draw conclusions about the performance.
https://www.screentogif.com/
https://github.com/NickeManarin/ScreenToGif/releases/download/2.30/ScreenToGif.2.30.Portable.zip

@jj2007
Flickering of the text while scrolling could not be confirmed. This is probably an optical illusion - https://en.wikipedia.org/wiki/Optical_illusion
The rest of the flickering was confirmed, you can look at the picture.
Title: Re: Flicker reduction drawing strategy
Post by: LiaoMi on May 25, 2021, 10:17:47 PM
Hi Biterider,

here is the test ...
Title: Re: Flicker reduction drawing strategy
Post by: LiaoMi on May 25, 2021, 10:37:48 PM
If you compare both results, you can see that there are the same patterns. The sequence of drawing is visible, areas that were processed separately are visible. The new concept shows black artifacts and more shifts in the transform window. In the regular form, this effect appears less often and the transformation of the window is more often limited to one drawing, if we consider this event to be atomic. Visually, I did not see any difference with my own eyes.

The only technique that can remove flicker is double buffering  :tongue:
Title: Re: Flicker reduction drawing strategy
Post by: jj2007 on May 25, 2021, 10:47:13 PM
Quote from: LiaoMi on May 25, 2021, 08:58:56 PMhttps://github.com/NickeManarin/ScreenToGif/releases/download/2.30/ScreenToGif.2.30.Portable.zip
That one asks for dotnot 4.8 :sad:

QuoteFlickering of the text while scrolling could not be confirmed. This is probably an optical illusion - https://en.wikipedia.org/wiki/Optical_illusion
The rest of the flickering was confirmed, you can look at the picture.

I didn't say the text flickers. The RichEdit control is quite good at that, actually. The embedded simple edit control does flicker a bit, and this is normal for edit controls.
Title: Re: Flicker reduction drawing strategy
Post by: daydreamer on May 25, 2021, 11:29:02 PM
Quote from: LiaoMi on May 25, 2021, 10:37:48 PM
If you compare both results, you can see that there are the same patterns. The sequence of drawing is visible, areas that were processed separately are visible. The new concept shows black artifacts and more shifts in the transform window. In the regular form, this effect appears less often and the transformation of the window is more often limited to one drawing, if we consider this event to be atomic. Visually, I did not see any difference with my own eyes.

The only technique that can remove flicker is double buffering  :tongue:
there are some more advanced api's that let you wait for vertical retrace,disadvantage to draw in order opposite direction than screen output to monitor
Title: Re: Flicker reduction drawing strategy
Post by: HSE on May 25, 2021, 11:47:41 PM
Quote from: jj2007 on May 25, 2021, 10:08:28 AM
Tested, no effect. I bet that SetWindowPos uses MoveWindow under the hood :cool:
SetWindowPos allow a lot of flags, but apparently nothing for this problem.

Quote from: jj2007 on May 25, 2021, 07:39:20 PM
If I take away the vertical scrollbar by omitting WS_VSCROLL from the style during CreateWindowEx, and then enable it afterwards with SetWindowLong
:thumbsup:
Title: Re: Flicker reduction drawing strategy
Post by: HSE on May 26, 2021, 01:25:20 AM
Perhaps is for here?:
QuoteThe DeferWindowPos function updates the specified multiple-window - position structure for the specified window. The function then returns the handle to the updated structure. The EndDeferWindowPos function uses the information in this structure to change the position and size of a number of windows simultaneously. The BeginDeferWindowPos function creates the structure.
Title: Re: Flicker reduction drawing strategy
Post by: Biterider on May 26, 2021, 01:52:13 AM
Hi HSE
Dynamic layouts use DeferWindowPos to reposition all controls at once.

Biterider
Title: Re: Flicker reduction drawing strategy
Post by: LiaoMi on May 26, 2021, 01:56:31 AM
Quote from: HSE on May 26, 2021, 01:25:20 AM
Perhaps is for here?:
QuoteThe DeferWindowPos function updates the specified multiple-window - position structure for the specified window. The function then returns the handle to the updated structure. The EndDeferWindowPos function uses the information in this structure to change the position and size of a number of windows simultaneously. The BeginDeferWindowPos function creates the structure.

Hi HSE,

Wm_size Edit flicker - http://masm32.com/board/index.php?topic=7668.msg83761#msg83761 and http://masm32.com/board/index.php?topic=7668.msg83780#msg83780

case WM_ENTERSIZEMOVE:
SendMessage(hEdit, WM_SETREDRAW, 0, 0);
return TRUE;
case WM_EXITSIZEMOVE: {
SendMessage(hEdit, WM_SETREDRAW, 1, 0);
RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE | RDW_ERASE);
}
return TRUE;
Title: Re: Flicker reduction drawing strategy
Post by: HSE on May 26, 2021, 06:07:25 AM
Quote from: Biterider on May 26, 2021, 01:52:13 AM
Dynamic layouts use DeferWindowPos to reposition all controls at once.
Ok. Then that don't solve very much.

Quote from: LiaoMi on May 26, 2021, 01:56:31 AM
Wm_size Edit flicker
That could be usefull  :thumbsup:, just I don't know how  :cool:
Title: Re: Flicker reduction drawing strategy
Post by: jj2007 on May 26, 2021, 07:48:50 AM
Quote from: Biterider on May 26, 2021, 01:52:13 AM
Dynamic layouts use DeferWindowPos to reposition all controls at once.

That's an interesting option. I use MoveWindow, ..., 1 to reposition all controls in a loop. Perhaps DeferWindowPos is faster or less flickery, I'll have to look into that - thanks for the hint :thup:

Attached a debug version of my demo, demonstrating why the richedit's vertical scrollbar is jumping up and down - btw only for horizontal sizing. The cause is found (it's a bug in the control) but so far no therapy in sight :sad:

Btw invoke SendMessage, hMyEdit, WM_SETREDRAW, 0, 0 is not a valid option, it just looks ugly :sad:

Event Message
  .if uMsg_==WM_ENTERSIZEMOVE
invoke GetScrollInfo, hMyEdit, SB_VERT, addr sinf
fdeb 4, "start sizing", sinf.nMin, sinf.nMax, sinf.nPage, sinf.nPos, sinf.nTrackPos
  .elseif uMsg_==WM_SIZING
invoke GetScrollInfo, hMyEdit, SB_VERT, addr sinf
fdeb 4, "GetScrollInfo", sinf.nMax
  .elseif uMsg_==WM_EXITSIZEMOVE
invoke GetScrollInfo, hMyEdit, SB_VERT, addr sinf
fdeb 4, "end sizing", sinf.nMin, sinf.nMax, sinf.nPage, sinf.nPos, sinf.nTrackPos
  .endif
Title: Re: Flicker reduction drawing strategy
Post by: hutch-- on May 26, 2021, 12:02:26 PM
There is a magic rule, do not layer windows that independently update their client area. A bare window with the background colour set in the WNDCLASSEX does not flicker. If you put another window over it, then set the base window to 0 or a transparent background. If you need to have multiple windows, ensure that what is under them has the update turned off. It makes the layout a bit more complicated but done right, you will have no flicker at all.
Title: Re: Flicker reduction drawing strategy
Post by: jj2007 on May 26, 2021, 08:04:49 PM
Hutch,

That is all correct, but the WS_CLIPCHILDREN style should take care of that. My experience is that certain controls behave worse than others. The RichEdit control, for example, remains pretty smooth, except that there is that jumping vertical scrollbar. Edit and static controls, otoh, do flicker when you resize them. Not much, but it's clearly visible.

GuiParas equ xr0, y0, w880, h-1, b Red ; right-aligned, on top, 88% width, red background
GuiMenu equ @File, &Open, &Save, -, E&xit, @Edit, Undo, Copy, Paste
include \masm32\MasmBasic\Res\MbGui.asm
  GuiControl MyEdit, "richedit", FileRead$(98), bcol LiteBlueGreen, x100, w800, y50, h250, wrap
  GuiControl MyRich, "edit", FileRead$(99), bcol White, x100, w800, y350, h250
  GuiControl MyStatic, "static", FileRead$(99), bcol LiteYellow, x100, w800, y650, h250
GuiEnd


The attached executables are built once with the WS_CLIPCHILDREN style, once without. The difference is obvious. Still, even with WS_CLIPCHILDREN set, the ordinary edit and static controls do flicker a little bit, only the RichEdit control stays smooth.