How to Solve the Flickering Issue when Refreshing a Window in FB Graphics Mode

Forum for discussion about the documentation project.
fxm
Posts: 8351
Joined: Apr 22, 2009 12:46
Location: Paris (suburb), FRANCE

How to Solve the Flickering Issue when Refreshing a Window in FB Graphics Mode

Postby fxm » May 12, 2018 18:26

Refreshing (redrawing without precaution) a window in graphics mode can result in annoying flickering (this is due to the display of unwanted intermediate images picked up during the user refreshing phase).
The phenomenon is obviously intensified if the entire window is first erased before being completely updated, and this repeatedly.

This topic presents the basic FB coding techniques to fight against this phenomenon.


If you take into account the only graphical user task (regardless of CPU resources needed for the OS), there are two main methods to avoid flickering:
  • In first priority, use of a block [Screenlock ..... Screenunlock] to encapsulate the graphical instructions for refreshing.
    But the documentation enlightens a warning to its use:
    It is strongly recommended that the lock on a page be held for as short a time as possible. Only screen drawing should occur while the screen is locked, input/output and waiting must be avoided. In Win32 and Linux the screen is locked by stopping the thread that processes also the OS' events. If the screen is kept locked for a long time the event queue could overflow and make the system unstable.
  • In a second priority, if the lock time is too long, use the principle of double video paging.
The instruction Screensync is a reminiscence of the old QuickBASIC where there was only this type of instruction (wait &h3DA, 8) to improve flickering.
It is empirical because it only allows to synchronize the drawing relating to the fixed dead time between two frames.
To be used occasionally with very little time drawing.

There is usually no interest to mix together these 2 (or 3) methods.

Then, in your loop, you must provide enough CPU resources to OS (smoothed with Sleep instruction at the end of the loop). Otherwise, it will take itself out of your control, resulting in a jerky display.
Remark: using Screensynch provides CPU resources to OS (dead time between end of your graphic drawing and end of its frame tracing), but by a non controllable way (because linked to the frame period).


A small program to enlighten (and compare the different efficiencies) the 4 following different methods (or no method) to animate a drawing/printing to a graphic screen by a loop with clearing screen:
    1. Draw/Print loop to screen with raw coding (no method)
      Algorithm:

      Code: Select all

      '    SCREEN 19, , 2 'to enable double-paging
      '    SCREENSET 0, 0 'to cancel double-paging
      '
      '  ┌─► CLS          'to clear the page
      '  │   Drawing      'to draw on the page
      '  │   Printing     'to print on the page
      '  └── Temporizing  'to avoid hogging the CPU
    2. Draw/Print loop to screen with synchronizing
      Algorithm:

      Code: Select all

      '    SCREEN 19, , 2 'to enable double-paging
      '    SCREENSET 0, 0 'to cancel double-paging
      '
      '  ┌─► SCREENSYNC   'to synchronize between two frames
      '  │   CLS          'to clear the page
      '  │   Drawing      'to draw on the page
      '  │   Printing     'to print on the page
      '  └── Temporizing  'to avoid hogging the CPU
       
    3. Draw/Print loop to screen with locking
      Algorithm:

      Code: Select all

      '    SCREEN 19, , 2 'to enable double-paging
      '    SCREENSET 0, 0 'to cancel double-paging
      '
      '  ┌─► SCREENLOCK   'to lock the page's frame buffer
      '  │   CLS          'to clear the page
      '  │   Drawing      'to draw on the page
      '  │   Printing     'to print on the page
      '  │   SCREENUNLOCK 'to unlock the page's frame buffer
      '  └── Temporizing  'to avoid hogging the CPU
       
    4. Draw/Print loop to screen with double buffering
      Algorithm:

      Code: Select all

      '    SCREEN 19, , 2 'to enable double-paging
      '    SCREENSET 1, 0 'to activate double-paging
      '
      '  ┌─► CLS          'to clear the work page
      '  │   Drawing      'to draw on the work page
      '  │   Printing     'to print on the work page
      '  │   SCREENCOPY   'to copy the work page into the visible page
      '  └── Temporizing  'to avoid hogging the CPU
       
        Double buffering and page flipping (below) are functionally equivalent (but not under the hood) if the work page is entirely refreshed at each iteration as here.
    5. Draw/Print loop to screen with page flipping
      Algorithm:

      Code: Select all

      '    SCREEN 19, , 2     'to enable double-paging
      '    SCREENSET 1, 0     'to activate double-paging
      '    p0=0 : p1=1        'to initialize flipping
      '
      '  ┌─► CLS              'to clear the work page
      '  │   Drawing          'to draw on the work page
      '  │   Printing         'to print on the work page
      '  │   SCREENSET p0, p1 'to set the work page to the p0 value, and the visible page to the p1 value
      '  │   SWAP p0, p1      'to exchange the values of p0 and p
      '  └── Temporizing      'to avoid hogging the CPU
       
        Page flipping and double buffering (above) are functionally equivalent (but not under the hood) if the work page is entirely refreshed at each iteration as here.
Complete program listing:

Code: Select all

Declare Sub Draw_circle_recursion (Byval x As Integer, Byval y As Integer, Byval r As Integer, Byval rmin As integer)

Dim I As Integer = 0
Dim Inc As Integer
Dim Key As String
Dim Code As Integer = 1
Dim Tempo As Integer = 3
Dim p0 As Integer = 0
Dim p1 As Integer = 1


Screen 19, , 2

Do
  If Code = 4 Or Code = 5 Then
    Screenset 1, 0
  Else
    Screenset 0, 0
  End If
  Do
    Select Case Code
    Case 2
      Screensync
    Case 3
      Screenlock
    End Select
    Cls
    Draw_circle_recursion(10 + I, 300, 9 + I * I / 29 / 29, 10)
    Locate 1, 1
    Select Case Code
    Case 1
      Print "1. Draw/Print loop to screen with raw coding:"
      Print
      Print "   SCREEN 19, , 2 'to enable double-paging"
      Print "   SCREENSET 0, 0 'to cancel double-paging"
      Print
      Print " " & Chr(218) & Chr(196) & Chr(16) & " CLS"
      Print " " & Chr(179) & " " & " " & " Drawing"
      Print " " & Chr(179) & " " & " " & " Printing"
      Print " " & Chr(192) & Chr(196) & Chr(196) & " Temporizing"; Tempo; " ms";
    Case 2
      Print "2. Draw/Print loop to screen with synchronizing:"
      Print
      Print "   SCREEN 19, , 2 'to enable double-paging"
      Print "   SCREENSET 0, 0 'to cancel double-paging"
      Print
      Print " " & Chr(218) & Chr(196) & Chr(16) & " SCREENSYNC"
      Print " " & Chr(179) & " " & " " & " CLS"
      Print " " & Chr(179) & " " & " " & " Drawing"
      Print " " & Chr(179) & " " & " " & " Printing"
      Print " " & Chr(192) & Chr(196) & Chr(196) & " Temporizing"; Tempo; " ms";
    Case 3
      Print "3. Draw/Print loop to screen with locking:"
      Print
      Print "   SCREEN 19, , 2 'to enable double-paging"
      Print "   SCREENSET 0, 0 'to cancel double-paging"
      Print
      Print " " & Chr(218) & Chr(196) & Chr(16) & " SCREENLOCK"
      Print " " & Chr(179) & " " & " " & " CLS"
      Print " " & Chr(179) & " " & " " & " Drawing"
      Print " " & Chr(179) & " " & " " & " Printing"
      Print " " & Chr(179) & " " & " " & " SCREENUNLOCK"
      Print " " & Chr(192) & Chr(196) & Chr(196) & " Temporizing"; Tempo; " ms";
    Case 4
      Print "4. Draw/Print loop to screen with double buffering:"
      Print
      Print "   SCREEN 19, , 2 'to enable double-paging"
      Print "   SCREENSET 1, 0 'to activate double-paging"
      Print
      Print " " & Chr(218) & Chr(196) & Chr(16) & " CLS"
      Print " " & Chr(179) & " " & " " & " Drawing"
      Print " " & Chr(179) & " " & " " & " Printing"
      Print " " & Chr(179) & " " & " " & " SCREENCOPY"
      Print " " & Chr(192) & Chr(196) & Chr(196) & " Temporizing"; Tempo; " ms";
    Case 5
      Print "5. Draw/Print loop to screen with page flipping:"
      Print
      Print "   SCREEN 19, , 2 'to enable double-paging"
      Print "   SCREENSET 1, 0 'to activate double-paging"
      Print "   p0=0 : p1=1    'to initialize flipping"
      Print
      Print " " & Chr(218) & Chr(196) & Chr(16) & " CLS"
      Print " " & Chr(179) & " " & " " & " Drawing"
      Print " " & Chr(179) & " " & " " & " Printing"
      Print " " & Chr(179) & " " & " " & " SCREENSET p0, p1"
      Print " " & Chr(179) & " " & " " & " SWAP p0, p1"
      Print " " & Chr(192) & Chr(196) & Chr(196) & " Temporizing"; Tempo; " ms";
    End Select
    Locate 30, 1
    Print "<1>: Draw/Print with raw coding"
    Print "<2>: Draw/Print with synchronizing"
    Print "<3>: Draw/Print with locking"
    Print "<4>: Draw/Print with double buffering"
    Print "<5>: Draw/Print with page flipping"
    Print "<+/->: Tempo setting (+/-)"
    Print
    Print "<Escape> or click [X]: Quit";
    Select Case Code
    Case 3
      Screenunlock
    Case 4
      Screencopy
    Case 5
      Screenset p0, p1
      Swap p0, p1
    End Select
    If I = 0 Then
      Inc = +1
    Elseif I = 480 Then
      Inc = -1
    End If
    I = I + Inc
    Key = Inkey
    If Key = "+" And Tempo < 10 Then
      Tempo = Tempo + 1
    Elseif Key = "-" And Tempo > 0 Then
      Tempo = Tempo - 1
    End If
    Static As Integer K
    K += 1
    If Tempo > 0 Then
      If K >= 25 / Tempo Then
        Sleep 25
        K = 0
      End If
    End If
  Loop While Key <> "1" And Key <> "2" And Key <> "3" And Key <> "4" And Key <> "5" And Key <> Chr(27) And Key <> Chr(255) & "k"
  Code = Val(Key)
Loop Until Key = Chr(27) Or Key = Chr(255) & "k"


Sub Draw_circle_recursion ( ByVal x As Integer, Byval y As Integer, ByVal r As Integer, Byval rmin As integer )
  Circle (x, y), r, r Shr 1
  If r > rmin Then
    Draw_circle_recursion(x + r shr 1, y, r Shr 1, rmin)
    Draw_circle_recursion(x - r Shr 1, y, r Shr 1, rmin)
    Draw_circle_recursion(x, y + r Shr 1, r Shr 1, rmin)
    Draw_circle_recursion(x, y - r Shr 1, r Shr 1, rmin)
    Draw_circle_recursion(x + r Shr 1, y + r Shr 1, r Shr 2, rmin)
    Draw_circle_recursion(x - r Shr 1, y + r Shr 1, r Shr 2, rmin)
    Draw_circle_recursion(x + r Shr 1, y - r Shr 1, r Shr 2, rmin)
    Draw_circle_recursion(x - r Shr 1, y - r Shr 1, r Shr 2, rmin)
  End If
End Sub
    Note on temporizing in the loop (for compatibility with any PC):
    The true temporizing value applied is always 25 ms ('Sleep 25'), but only for one loop on N (with 'N = 25 / tempo', and 'tempo' the wanted value in ms between 1 and 10).
Last edited by fxm on May 13, 2018 9:36, edited 5 times in total.
badidea
Posts: 975
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: How to Solve the Flickering Issue when Refreshing a Window in FB Graphics Mode

Postby badidea » May 12, 2018 19:53

A question: What are 'UC resources'?
A remark: There is no 'sleep' in your 'Complete program listing'. edit: Sorry, I missed your remark about screensync.
lizard
Posts: 406
Joined: Oct 17, 2017 11:35
Location: Germany

Re: How to Solve the Flickering Issue when Refreshing a Window in FB Graphics Mode

Postby lizard » May 12, 2018 20:13

Very impressive demo!

Thats my forum, where such cracks are working.
fxm
Posts: 8351
Joined: Apr 22, 2009 12:46
Location: Paris (suburb), FRANCE

Re: How to Solve the Flickering Issue when Refreshing a Window in FB Graphics Mode

Postby fxm » May 12, 2018 20:19

badidea wrote:A question: What are 'UC resources'?
My mistake: UC is the French acronym for CPU !

badidea wrote:A remark: There is no 'sleep' in your 'Complete program listing'.
Because it was an old program that I had developed on a very old PC, and even 'Sleep 1' was too long (I had replaced it by a temporizing procedure).
Now, less of a problem with a modern PC.
Nevertheless one can define a code using 'Sleep', but compatible of all PC.
(for example, for a target timeout of N (ms) in [1, 10], always calling 'Sleep 25', but only once on 25/N)

I will correct these two points in the first post.
grindstone
Posts: 556
Joined: May 05, 2015 5:35
Location: Germany

Re: How to Solve the Flickering Issue when Refreshing a Window in FB Graphics Mode

Postby grindstone » May 13, 2018 12:21

Correct me if I'm wrong, but IMHO "page flipping" is quite the same as "double buffering". The "page flipping" - example only shows how SCREENCOPY works under the hood.
fxm
Posts: 8351
Joined: Apr 22, 2009 12:46
Location: Paris (suburb), FRANCE

Re: How to Solve the Flickering Issue when Refreshing a Window in FB Graphics Mode

Postby fxm » May 13, 2018 14:21

A small program as a support for reflection before we discuss it if necessary :-)

Code: Select all

Dim As String s = "How to Solve the Flickering Issue when Refreshing a Window in FB Graphics Mode"

Screen 12, , 2
Screenset 1, 0
Dim As Integer p0 = 0, p1 = 1

Color 14
Locate 7, 24
Print "DOUBLE-BUFFERING METHOD (page 1)"
Locate 14, 2
For I As Integer = 1 To Len(s)
  Print Mid(s, I, 1);
  Screencopy
  Sleep 200
Next I
Locate 29, 2
Print "Any <key> to continue";
Screencopy

Sleep

Color 11
Locate 8, 24
Print "PAGE-FLIPPING METHOD (page 1)"
Screenset p0, p1
Swap p0, p1
Locate 8, 24
Print "PAGE-FLIPPING METHOD (page 0)"
Locate 15, 2
For I As Integer = 1 To Len(s)
  Print Mid(s, I, 1);
  Screenset p0, p1
  Swap p0, p1
  Sleep 200
Next I
Locate 30, 2
Print "Any <key> to exit";
Screenset p0, p1

Sleep

grindstone wrote:Correct me if I'm wrong, but IMHO "page flipping" is quite the same as "double buffering".
Maybe I could add a note on that in the first post?
MrSwiss
Posts: 2764
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: How to Solve the Flickering Issue when Refreshing a Window in FB Graphics Mode

Postby MrSwiss » May 13, 2018 16:43

fxm wrote:... for reflection before we discuss it if necessary :-)

Currently, the second code part, is NOT working *as expected*, because:
every second string-char is missed ... (unless, this is intentional).
fxm
Posts: 8351
Joined: Apr 22, 2009 12:46
Location: Paris (suburb), FRANCE

Re: How to Solve the Flickering Issue when Refreshing a Window in FB Graphics Mode

Postby fxm » May 13, 2018 16:54

Yes, it's intentional.
This is to show that the two methods produce equivalent results only if the screen is completely refreshed at each iteration:

Code: Select all

Dim As String s = "How to Solve the Flickering Issue when Refreshing a Window in FB Graphics Mode"

Screen 12, , 2
Screenset 1, 0
Dim As Integer p0 = 0, p1 = 1

Color 14
For I As Integer = 1 To Len(s)
  Cls
  Locate 7, 24
  Print "DOUBLE-BUFFERING METHOD (page 1)"
  Locate 14, 2
  Print Mid(s, 1, I);
  Screencopy
  Sleep 200
Next I
Locate 29, 2
Print "Any <key> to continue";
Screencopy

Sleep

Color 11
Locate 15, 2
For I As Integer = 1 To Len(s)
  Cls
  Locate 8, 24
  Print "PAGE-FLIPPING METHOD (page " & p0 & ")"
  Locate 15, 2
  Print Mid(s, 1, I);
  Screenset p0, p1
  Swap p0, p1
  Sleep 200
Next I
Locate 30, 2

Sleep

- double buffering: we always write on the same page
- page flipping: we write alternately on each page

[edit]
- code corrected
grindstone
Posts: 556
Joined: May 05, 2015 5:35
Location: Germany

Re: How to Solve the Flickering Issue when Refreshing a Window in FB Graphics Mode

Postby grindstone » May 14, 2018 8:21

fxm wrote:- double buffering: we always write on the same page
- page flipping: we write alternately on each page

Yes, I see the difference. Thank you. :-)
fxm
Posts: 8351
Joined: Apr 22, 2009 12:46
Location: Paris (suburb), FRANCE

Re: How to Solve the Flickering Issue when Refreshing a Window in FB Graphics Mode

Postby fxm » May 14, 2018 8:40

Obviously, double buffering and page flipping are functionally equivalent (but not under the hood) if the page is entirely refreshed at each iteration (as my example of post #1).

Note: In my first post, I updated the 5 algorithms by adding comment at each code line to explain it (and a note for the last two algorithms).
dafhi
Posts: 1197
Joined: Jun 04, 2005 9:51

Re: How to Solve the Flickering Issue when Refreshing a Window in FB Graphics Mode

Postby dafhi » Jun 03, 2018 4:10

I've used lock because no flickering issues ever, and I figured lower memory.

These examples are great!
coderJeff
Site Admin
Posts: 2693
Joined: Nov 04, 2005 14:23
Location: Ontario, Canada
Contact:

Re: How to Solve the Flickering Issue when Refreshing a Window in FB Graphics Mode

Postby coderJeff » Jun 10, 2018 21:05

fxm wrote:double buffering and page flipping are functionally equivalent (but not under the hood)

fxm, this is an excellent comparison of methods; all of them. Thank-you.

May be of some interest to the topic...

On old hardware (and not in FB):

Method 2, screensync & draw: video memory used entirely for the display, write directly to video memory.
Method 4, double buffer: video memory used entirely for the display, write to a main memory framebuffer, and copy to video memory.
Method 5, page flipping: video memory with multiple pages, write directly to video memory, then change pointer to start of video display, often with just a few instructions.

In FB:

FB never draws directly to video memory; It always draws to frame buffers (excl. opengl modes), on all platforms. The only video operation gfxlib2 knows is to copy from a frame buffer (or just the dirty parts of a frame buffer) to video memory.

So,

Method 2, screensync & draw: page (or part page depending on what rows are dirty) is copied once from the frame buffer to video memory. Needs 1 frame buffer.
Method 4, double buffering: page is copied twice, once to copy from the working frame buffer to the visible frame buffer, then from the visible frame buffer to the video memory. Needs 2 frame buffers
Method 5, page flipping: page is copied once, from the visible frame buffer to the video memory. Needs 2 frame buffers
Tourist Trap
Posts: 2383
Joined: Jun 02, 2015 16:24

Re: How to Solve the Flickering Issue when Refreshing a Window in FB Graphics Mode

Postby Tourist Trap » Jun 17, 2018 22:06

Thanks fxm, very pretty job.

Return to “Documentation”

Who is online

Users browsing this forum: No registered users and 2 guests