About Graphic buffer Flipping

Started by wookie22, March 17, 2019, 11:41:54

Previous topic - Next topic

wookie22

Bmx help states that "Flip swap the front and back buffers of the current graphics objects".

So if I have some movement in program logic achieved by drawing new object position to back buffer and then flipping buffers and then I do this:

if KeyDown(KEY_SPACE)
   While 1
      Flip 1
   Wend
Endif

So when I press space I should see my movement going back and forward in a loop right? So why I just see still frame?
Hidden Deep - 2D Action & Exploration Sci-Fi Thriller for PC/Mac/Linux
http://www.hiddendeepgame.com

Derron

Nope.

Flip: bring to the screen what you drew before

DrawImage XYZ 'not yet on screen
DrawImage XYZ2 'not yet on screen
DrawText bla 'not on screen
flip 'now xyz, xyz2 and bla are on screen

flip 'whatever is on the backbuffer is shovled to the screen - garbage or the same stuff as above, no guarantee

Your while loop is running forever - so you only put your drawn stuff on the screen during the first "flip" and all follow up flips are... sending "whatever is there" to the screen.
You cannot guarantee that this is your drawn stuff - might as well be some "random memory". Just do some "alt-tab" while it runs, open some applications - you will see how parts of your screen wander into your application canvas/screen.


bye
Ron

Matty

Flip actually copies the back buffer to the front buffer so they are identical after flipping.  Yes the word swap does indeed sound like they are exchanged not copied.  Bad wording. 

Yellownakji

#3
Quote from: wookie22 on March 17, 2019, 11:41:54
Bmx help states that "Flip swap the front and back buffers of the current graphics objects".

So if I have some movement in program logic achieved by drawing new object position to back buffer and then flipping buffers and then I do this:

if KeyDown(KEY_SPACE)
   While 1
      Flip 1
   Wend
Endif

So when I press space I should see my movement going back and forward in a loop right? So why I just see still frame?


You only use flip at the end of your application loop.


graphics(640,460,60,GRAPHICS_BACKBUFFER) 'Set graphics; using backbuffer is recommended.  60 = hertz.   writing 60 fixes to 60 so it's better to detect.

While not app_terminate() 'App_terminate can be a user variable too; whatever you use to keep the game running
     cls 'clear the screen
          '---------------------------------
          'do your app crap here
          '---------------------------------
     flip 'see flip document for vsync support
wend

TomToad

Quote from: Matty on March 17, 2019, 18:34:31
Flip actually copies the back buffer to the front buffer so they are identical after flipping.  Yes the word swap does indeed sound like they are exchanged not copied.  Bad wording.

This is not quite true.  When the graphics context is in window mode, then the back buffer is copied to the front buffer, but when in fullscreen mode, the buffers are actually swapped.  Try this example program.  Comment and uncomment the various lines to see the effect.  The program first draws a square, flips, then draws a circle without clearing the screen.  If the back buffer is copied, then you should see both square and circle on the screen (which it does when windowed).  When full screen, only the circle appears.  You can press SPACE to flip again without drawing or clearing the buffers, what happens depends on the video card and graphics driver used.  On my computer, DX7 and OpenGL flips between the square and the circle.  On DX9, the square gets cleared by the driver for some reason, so it flips between the circle and a blank screen.
SuperStrict
SetGraphicsDriver GLMax2DDriver()
'SetGraphicsDriver D3D9Max2DDriver()
'SetGraphicsDriver D3D7Max2DDriver()

'Graphics 800,600 'Windowed mode
Graphics 800,600,32 'Fullscreen mode

Cls
DrawRect 10,10,100,100
Flip
DrawOval 120,10,100,100
Flip

While Not KeyHit(KEY_ESCAPE) And Not AppTerminate()
If KeyHit(KEY_SPACE) Then Flip
Wend

------------------------------------------------
8 rabbits equals 1 rabbyte.

wookie22

TomToad - yes, that is what I was expecting and didn't happened - I've just forgot to try it on fullscreen :)

My game logic is 60Hz and Graphics mode is 120Hz. So I want just wait two v-syncs instead of one so. How do I wait for another V-sync without buffer flipping?
Hidden Deep - 2D Action & Exploration Sci-Fi Thriller for PC/Mac/Linux
http://www.hiddendeepgame.com

Derron

#6
Just do nothing every second frame on 120hz - no cls, no drawimage, no flip.
or just delay properly.


But who cares what hz that screen has?
run your logic with X hertz
render when the screen refresh desires (vsync).

loop
updateIfNeeded 'fixed rate logic
renderAndFlipIfNeeded
delay(time left to still satisfy update and render needs)
endloop


Have a look at this:
https://github.com/GWRon/Dig/blob/master/base.util.deltatimer.bmx
-> Method Loop

To see it in action:
https://github.com/GWRon/Dig/blob/master/samples/graphicalapp/graphicalapp.bmx

basically you connect some update and render function (in which you do your stuff) and it takes care of the stuff you need.


bye
Ron

wookie22

About that Delay - is it precise enough for that? It measures time in whole milliseconds while single refresh has also fraction part (like 16.667 @60Hz)
Hidden Deep - 2D Action & Exploration Sci-Fi Thriller for PC/Mac/Linux
http://www.hiddendeepgame.com

TomToad

Here is one method for fixing the logic rate.  By changing the Flip to Flip False, you can show that the logic runs the same speed even when the machine is running much faster.
Code (blitzmax) Select
'Fixed logic rate demo
'by TomToad
'March 18,2019
'
'This program works by creating a timer to run at 60 htz
'  TimerTicks() will return the number of ticks since the
'  timer was created.  By subtracting the last count from
'  the curent, we can find out how many ticks have occured
'  and therefor the number of times the logic loop needs
'  to run.
'  on a system running at exactly 60 htz, TimerCount will
'  always equal 1.  If the system is runnung faster than
'  60 htz, then sometimes TimerCount will equal 1 and
'  sometimes 0, causing the last frame to be duplicated.
'  if the system is running slower, then TimerCount will
'  sometimes be larger than 1, causing the logic to be
'  run more than once, some frames will be skipped, but
'  overall speed and physics simulation will still be the
'  same.
SuperStrict

Graphics 800,600,32
Local Timer:TTimer = CreateTimer(60)
Local TimerLast:Int = 0
Local TimerCount:Int, TimerCurrent:Int
Local x:Float = 0.0
Local y:Float = 300.0

'some stuff for calculating frames per second
Local LogicFPS:Int, LogicFrameCount:Int, RenderFPS:Int, RenderFrameCount:Int, NextTime:Int
NextTime = MilliSecs() + 1000


While Not KeyHit(KEY_ESCAPE) And Not AppTerminate()

'logic portion of the game runs 60 times a second
TimerCurrent = TimerTicks(Timer)
TimerCount = TimerCurrent-TimerLast
TimerLast = TimerCurrent

For Local t:Int = 1 To TimerCount
x :+ 1.0
If x > 800.0 Then x = 0.0
LogicFrameCount :+ 1
Next

'render part of the game
Cls
DrawOval x-10,y-10,20,20
DrawText "Render speed = "+RenderFPS+" FPS",10,10
DrawText "Logic speed = "+LogicFPS+" FPS",10,30
Flip 'Change to Flip False to have the demo run as fast as possible
RenderFrameCount :+ 1

If MilliSecs() >= NextTime
NextTime :+ 1000
LogicFPS = LogicFrameCount
LogicFrameCount = 0
RenderFPS = RenderFrameCount
RenderFrameCount = 0
EndIf
Wend
------------------------------------------------
8 rabbits equals 1 rabbyte.

wookie22

I think that when you get rid of waiting for V-Sync then there is tearing risk. I need to test it
Hidden Deep - 2D Action & Exploration Sci-Fi Thriller for PC/Mac/Linux
http://www.hiddendeepgame.com

Derron

Of course you can wait for vsync - and if you calculate that time you can at least have a slight "delay" (if you want) as this releases some stress of the cpu (if possible).


bye
Ron

imaginaryhuman

You'd think that it would be better to render to texture and then, when done, render that texture to the front buffer. ie replace the flip with a render-texture output to the visible screen. The you also get the benefit of being able to run  shader on the rendering of the render-texture to the screen (to do warping, coloring and effects etc).

Steve Elliott

Quote
Here is one method for fixing the logic rate...

Thanks for sharing that Tom.
Win11 64Gb 12th Gen Intel i9 12900K 3.2Ghz Nvidia RTX 3070Ti 8Gb
Win11 16Gb 12th Gen Intel i5 12450H 2Ghz Nvidia RTX 2050 8Gb
Win11  Pro 8Gb Celeron Intel UHD Graphics 600
Win10/Linux Mint 16Gb 4th Gen Intel i5 4570 3.2GHz, Nvidia GeForce GTX 1050 2Gb
macOS 32Gb Apple M2Max
pi5 8Gb
Spectrum Next 2Mb

Derron

#13
My deltatimer-type allows to limit FPS too - sometimes you do not need 60fps. So in some "calm games" you might come along with 30fps - no need to stress Old Aunt Lizzys AMD duron with 60 fps ;-)


@ imaginaryhuman
Feel free to post some samples. So we might merge that stuff with Col's Render2Texture (DX+GL
https://github.com/davecamp/Render2Texture

Or does this - compared to Col's work with NG's SDL.mod already?


bye
Ron