VSync and FlipBuffers(), and Questions

Share your advanced PureBasic knowledge/code with the community.
chris319
Enthusiast
Enthusiast
Posts: 782
Joined: Mon Oct 24, 2005 1:05 pm

VSync and FlipBuffers(), and Questions

Post by chris319 »

I was wondering if FlipBuffers() blocks program execution while waiting for VSync, so I wrote this little program to find out. The answer is yes, it does block program execution while waiting for VSync. By opening the screen in either mode you can see this for yourself.

Two questions: I noticed that it takes a couple of buffer flips for things to synchronize with the display frequency (on my system the display frequency is around 60 Hz). Does anyone know why this is?

By what mechanism does FlipBuffers() know that VSync has arrived?

If anyone has any suggestions for improvements, please feel free to suggest.

Code: Select all

DisableDebugger

Dim duration.f(20)

OpenConsole()

QueryPerformanceFrequency_(@maxFreq): maxFreq / 1000

InitSprite()
;OpenScreen(1024, 768, 32, "", #PB_Screen_NoSynchronization)
OpenScreen(1024, 768, 32, "", #PB_Screen_WaitSynchronization)

;IT MAY TAKE A FEW BUFFER FLIPS TO GET SYNCHRONIZED
 For ct = 1 To 20
   FlipBuffers()
 Next

For ct = 1 To 20
  QueryPerformanceCounter_(@then.q)

  FlipBuffers()

  QueryPerformanceCounter_(@now.q)

  duration(ct) = (now - then) / maxFreq
Next

CloseScreen()

For ct = 1 To 20
PrintN(StrF(duration(ct),2) + " ms" + Chr(9) + StrF(1/duration(ct)*1000,2) + " frames per second")
Next

PrintN(Chr(10) + "Press any key to exit."): While Inkey() = "": Delay(5): Wend: CloseConsole()

End
Last edited by chris319 on Tue Oct 02, 2012 1:32 am, edited 1 time in total.
User avatar
Demivec
Addict
Addict
Posts: 4270
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: VSync and FlipBuffers(), and Questions

Post by Demivec »

I don't see any patterns.

What do you see in these results?

Code: Select all

15.00 ms        66.66 frames per second
17.88 ms        55.92 frames per second
16.52 ms        60.52 frames per second
17.10 ms        58.47 frames per second
15.49 ms        64.56 frames per second
40.49 ms        24.70 frames per second
12.37 ms        80.83 frames per second
84.72 ms        11.80 frames per second
0.36 ms 2793.91 frames per second
0.02 ms 61706.89 frames per second
15.09 ms        66.28 frames per second
14.51 ms        68.92 frames per second
15.31 ms        65.32 frames per second
16.59 ms        60.29 frames per second
16.68 ms        59.94 frames per second
16.64 ms        60.10 frames per second
16.83 ms        59.41 frames per second
27.94 ms        35.80 frames per second
9.71 ms 102.98 frames per second
12.36 ms        80.88 frames per second
chris319
Enthusiast
Enthusiast
Posts: 782
Joined: Mon Oct 24, 2005 1:05 pm

Re: VSync and FlipBuffers(), and Questions

Post by chris319 »

On my laptop I sometimes get weird values as well. On my desktop with an Nvidia AGP graphics card, after a few warm-up flips it gives 59.xx frames per second consistently. So something is goofy with FlipBuffers (it is not always waiting for VBlank it would seem).

Used to be that you could read the VBlank bit on port $3DA, but if you try to peek that address with PB it causes a crash.
User avatar
Demivec
Addict
Addict
Posts: 4270
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: VSync and FlipBuffers(), and Questions

Post by Demivec »

Even though the screen is setup to wait for the Vsync, I think you would still need to use SetFrameRate().

Alternatively you can open the screen with smart-synchronization to avoid the program hogging the cpu while it's simply waiting. In this way I think you would be able to take advantage of other threads being able to do something productive during the delay.
chris319
Enthusiast
Enthusiast
Posts: 782
Joined: Mon Oct 24, 2005 1:05 pm

Re: VSync and FlipBuffers(), and Questions

Post by chris319 »

Demivec wrote:Even though the screen is setup to wait for the Vsync, I think you would still need to use SetFrameRate().
Try it!
User avatar
Demivec
Addict
Addict
Posts: 4270
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: VSync and FlipBuffers(), and Questions

Post by Demivec »

chris319 wrote:
Demivec wrote:Even though the screen is setup to wait for the Vsync, I think you would still need to use SetFrameRate().
Try it!
Well, here's the results (information overload :wink: ):

Code: Select all

Smart, SetFrameRate(60)     Smart, no SetFrameRate
16.40 ms    60.99 fps       56.38 ms      17.74 fps    
16.39 ms    61.00 fps        0.05 ms   19037.23 fps 
16.40 ms    60.99 fps        9.42 ms     106.15 fps   
16.39 ms    61.00 fps       17.84 ms      56.06 fps    
16.40 ms    60.99 fps       15.50 ms      64.51 fps    
16.39 ms    60.99 fps       17.10 ms      58.46 fps    
16.39 ms    61.00 fps       25.63 ms      39.01 fps    
16.39 ms    61.00 fps       17.49 ms      57.17 fps    
16.40 ms    60.99 fps        7.00 ms     142.85 fps   
16.40 ms    60.99 fps       16.65 ms      60.05 fps    
18.62 ms    53.72 fps       30.97 ms      32.29 fps    
16.39 ms    61.00 fps       15.39 ms      64.99 fps    
16.39 ms    60.99 fps        3.32 ms     301.01 fps   
16.39 ms    60.99 fps       19.88 ms      50.30 fps    
16.39 ms    61.00 fps       13.85 ms      72.21 fps    
16.40 ms    60.99 fps       15.15 ms      66.01 fps    
16.40 ms    60.99 fps       16.65 ms      60.05 fps    
16.39 ms    61.00 fps       17.63 ms      56.71 fps    
16.39 ms    61.00 fps       16.95 ms      59.00 fps    
16.40 ms    60.99 fps       15.59 ms      64.13 fps    

Vsync, SetFrameRate(60)     Vsync, no SetFrameRate
16.40 ms    60.99 fps        2.12 ms     471.79 fps 
16.39 ms    61.00 fps       15.38 ms      65.02 fps  
16.39 ms    60.99 fps       17.95 ms      55.72 fps  
16.39 ms    60.99 fps       41.20 ms      24.27 fps  
16.39 ms    60.99 fps        9.57 ms     104.54 fps 
17.50 ms    57.16 fps       19.04 ms      52.52 fps  
16.39 ms    60.99 fps       12.15 ms      82.28 fps  
16.39 ms    60.99 fps       17.39 ms      57.50 fps  
16.39 ms    61.00 fps       15.91 ms      62.86 fps  
16.40 ms    60.99 fps       16.67 ms      59.97 fps  
16.40 ms    60.99 fps       16.67 ms      60.00 fps  
16.39 ms    61.00 fps       16.69 ms      59.91 fps  
16.39 ms    60.99 fps       26.73 ms      37.42 fps  
16.39 ms    61.00 fps       11.95 ms      83.68 fps  
16.39 ms    60.99 fps       11.39 ms      87.81 fps  
16.40 ms    60.99 fps       16.66 ms      60.04 fps  
16.40 ms    60.99 fps       16.71 ms      59.84 fps  
16.40 ms    60.99 fps       16.61 ms      60.22 fps  
16.39 ms    61.00 fps       16.69 ms      59.91 fps  
16.40 ms    60.99 fps       16.64 ms      60.09 fps  

No Vsync, SetFrameRate(60)   No Vsync, no SetFrameRate
16.40 ms    60.99 fps        0.08 ms   12341.38 fps 
16.40 ms    60.99 fps        0.08 ms   12384.08 fps 
16.39 ms    61.00 fps        0.08 ms   12341.38 fps 
16.40 ms    60.99 fps        0.08 ms   12384.08 fps 
16.39 ms    61.00 fps        0.08 ms   12384.08 fps 
16.40 ms    60.99 fps        0.08 ms   12384.08 fps 
19.11 ms    52.33 fps        0.08 ms   12384.08 fps 
16.39 ms    61.00 fps        0.08 ms   12384.08 fps 
16.40 ms    60.99 fps        0.08 ms   12341.38 fps 
16.39 ms    60.99 fps        0.08 ms   12384.08 fps 
16.40 ms    60.99 fps        0.09 ms   11325.95 fps 
16.39 ms    60.99 fps        0.08 ms   12298.97 fps 
16.40 ms    60.99 fps        0.08 ms   12384.08 fps 
16.39 ms    60.99 fps        0.08 ms   12384.08 fps 
16.40 ms    60.99 fps        0.08 ms   12384.08 fps 
16.39 ms    60.99 fps        0.08 ms   12384.08 fps 
16.40 ms    60.99 fps        0.08 ms   12384.08 fps 
16.39 ms    61.00 fps        0.08 ms   12384.08 fps 
16.40 ms    60.99 fps        0.08 ms   12384.08 fps 
16.39 ms    61.00 fps        0.08 ms   12384.08 fps 
chris319
Enthusiast
Enthusiast
Posts: 782
Joined: Mon Oct 24, 2005 1:05 pm

Re: VSync and FlipBuffers(), and Questions

Post by chris319 »

Here's what I get. Clearly the frame rate must be set regardless.

I am concerned about FlipBuffers() exiting early -- it shouldn't. I can understand why it might exit late if a higher-priority task has the machine tied up.

Code: Select all

Frame rate not set, #PB_Screen_NoSynchronization

0.06 ms 16076.191 frames per second
49.17 ms 20.339 frames per second
0.16 ms 6418.250 frames per second
0.07 ms 14938.052 frames per second
0.06 ms 17583.334 frames per second
0.74 ms 1355.823 frames per second
0.08 ms 12787.879 frames per second
0.07 ms 14938.052 frames per second
0.06 ms 17768.422 frames per second
1.63 ms 614.042 frames per second
0.09 ms 11405.405 frames per second
0.06 ms 15924.529 frames per second
0.10 ms 9590.909 frames per second
0.06 ms 15924.529 frames per second
2.08 ms 481.735 frames per second
0.08 ms 11804.195 frames per second
0.12 ms 8154.589 frames per second
0.06 ms 16880.002 frames per second
0.06 ms 17402.061 frames per second
0.49 ms 2041.112 frames per second
0.07 ms 14184.874 frames per second
0.06 ms 15775.701 frames per second
0.06 ms 17583.334 frames per second
0.35 ms 2846.543 frames per second
0.11 ms 9483.146 frames per second
0.06 ms 17402.061 frames per second
0.30 ms 3296.875 frames per second
0.06 ms 15629.630 frames per second
0.06 ms 17224.488 frames per second
0.68 ms 1466.551 frames per second

Frame rate @60 Hz, #PB_Screen_NoSynchronization

16.40 ms        60.978 frames per second
16.40 ms        60.980 frames per second
16.40 ms        60.989 frames per second
16.40 ms        60.989 frames per second
16.40 ms        60.994 frames per second
16.40 ms        60.994 frames per second
16.40 ms        60.980 frames per second
91.66 ms        10.910 frames per second
16.39 ms        60.998 frames per second
16.39 ms        60.996 frames per second
16.40 ms        60.987 frames per second
16.40 ms        60.991 frames per second
16.40 ms        60.987 frames per second
16.40 ms        60.983 frames per second
16.40 ms        60.989 frames per second
16.40 ms        60.985 frames per second
16.40 ms        60.989 frames per second
16.40 ms        60.989 frames per second
16.40 ms        60.987 frames per second
16.40 ms        60.983 frames per second
16.39 ms        60.996 frames per second
16.40 ms        60.980 frames per second
16.40 ms        60.985 frames per second
16.40 ms        60.989 frames per second
16.40 ms        60.994 frames per second
16.40 ms        60.983 frames per second
16.40 ms        60.985 frames per second
16.40 ms        60.989 frames per second
16.40 ms        60.991 frames per second
16.40 ms        60.991 frames per second

Frame rate not set, #PB_Screen_WaitSynchronization

16.20 ms        61.716 frames per second
19.17 ms        52.163 frames per second
54.01 ms        18.515 frames per second
0.10 ms 9645.714 frames per second
0.05 ms 21641.025 frames per second
6.44 ms 155.190 frames per second
15.96 ms        62.662 frames per second
15.93 ms        62.763 frames per second
16.03 ms        62.382 frames per second
15.99 ms        62.523 frames per second
15.99 ms        62.553 frames per second
15.98 ms        62.565 frames per second
16.01 ms        62.475 frames per second
15.98 ms        62.593 frames per second
16.00 ms        62.500 frames per second
15.99 ms        62.544 frames per second
16.01 ms        62.479 frames per second
15.98 ms        62.590 frames per second
16.00 ms        62.500 frames per second
15.98 ms        62.567 frames per second
16.01 ms        62.465 frames per second
15.98 ms        62.579 frames per second
16.01 ms        62.475 frames per second
15.99 ms        62.556 frames per second
16.01 ms        62.463 frames per second
15.97 ms        62.602 frames per second
16.01 ms        62.475 frames per second
15.98 ms        62.572 frames per second
16.00 ms        62.509 frames per second
16.00 ms        62.493 frames per second

Frame rate @60 Hz, #PB_Screen_WaitSynchronization

16.40 ms        60.978 frames per second
16.40 ms        60.994 frames per second
16.40 ms        60.989 frames per second
16.40 ms        60.989 frames per second
16.44 ms        60.840 frames per second
16.39 ms        60.996 frames per second
16.39 ms        60.996 frames per second
16.40 ms        60.989 frames per second
16.40 ms        60.994 frames per second
16.40 ms        60.994 frames per second
16.40 ms        60.994 frames per second
16.40 ms        60.994 frames per second
16.40 ms        60.987 frames per second
16.40 ms        60.991 frames per second
16.41 ms        60.954 frames per second
20.55 ms        48.671 frames per second
16.39 ms        61.011 frames per second
16.40 ms        60.994 frames per second
18.18 ms        55.011 frames per second
16.40 ms        60.994 frames per second
16.40 ms        60.994 frames per second
16.39 ms        60.996 frames per second
16.40 ms        60.991 frames per second
16.40 ms        60.989 frames per second
16.40 ms        60.991 frames per second
16.40 ms        60.989 frames per second
16.40 ms        60.987 frames per second
16.40 ms        60.987 frames per second
16.40 ms        60.989 frames per second
16.40 ms        60.991 frames per second

Frame rate not set, #PB_Screen_SmartSynchronization

35.14 ms        28.454 frames per second
0.09 ms 10820.513 frames per second
12.74 ms        78.519 frames per second
15.94 ms        62.751 frames per second
19.76 ms        50.616 frames per second
12.35 ms        80.963 frames per second
15.92 ms        62.823 frames per second
15.99 ms        62.544 frames per second
16.02 ms        62.419 frames per second
15.97 ms        62.609 frames per second
15.96 ms        62.672 frames per second
16.03 ms        62.401 frames per second
15.99 ms        62.542 frames per second
15.94 ms        62.735 frames per second
15.97 ms        62.600 frames per second
16.01 ms        62.477 frames per second
15.99 ms        62.558 frames per second
15.99 ms        62.544 frames per second
16.01 ms        62.472 frames per second
15.98 ms        62.590 frames per second
16.00 ms        62.486 frames per second
15.99 ms        62.542 frames per second
16.00 ms        62.493 frames per second
15.98 ms        62.560 frames per second
16.01 ms        62.449 frames per second
15.98 ms        62.576 frames per second
15.99 ms        62.551 frames per second
16.00 ms        62.486 frames per second
15.99 ms        62.535 frames per second
16.00 ms        62.505 frames per second

Frame rate @60 Hz, #PB_Screen_SmartSynchronization

16.40 ms        60.980 frames per second
16.40 ms        60.989 frames per second
16.40 ms        60.989 frames per second
16.40 ms        60.991 frames per second
16.40 ms        60.991 frames per second
16.40 ms        60.991 frames per second
16.40 ms        60.991 frames per second
16.40 ms        60.994 frames per second
16.40 ms        60.989 frames per second
16.53 ms        60.500 frames per second
162.39 ms       6.158 frames per second
16.39 ms        60.996 frames per second
16.40 ms        60.989 frames per second
16.40 ms        60.991 frames per second
16.40 ms        60.994 frames per second
16.40 ms        60.987 frames per second
16.40 ms        60.991 frames per second
16.40 ms        60.994 frames per second
16.40 ms        60.989 frames per second
16.40 ms        60.994 frames per second
16.40 ms        60.989 frames per second
16.40 ms        60.991 frames per second
81.80 ms        12.225 frames per second
16.39 ms        61.005 frames per second
16.40 ms        60.994 frames per second
16.40 ms        60.989 frames per second
16.40 ms        60.987 frames per second
16.39 ms        60.996 frames per second
16.40 ms        60.991 frames per second
16.39 ms        60.996 frames per second
chris319
Enthusiast
Enthusiast
Posts: 782
Joined: Mon Oct 24, 2005 1:05 pm

Re: VSync and FlipBuffers(), and Questions

Post by chris319 »

It gets worse. I created a procedure which draws a box on the screen and it messes up the timing beyond belief. If the StartDrawing() function is moved to line 27 (outside the loop) and disabled inside the procedure, the box is not drawn at all.

Code: Select all

Procedure DrawScreen(null)

  StartDrawing(ScreenOutput())
  Box(0,0,400,400, $00ffff)
  StopDrawing()

EndProcedure

DisableDebugger

Dim duration.f(100)

OpenConsole()

QueryPerformanceFrequency_(@maxFreq): maxFreq / 1000

InitSprite()
OpenScreen(1024, 768, 32, "", #PB_Screen_WaitSynchronization)
;OpenScreen(1024, 768, 32, "", #PB_Screen_SmartSynchronization)
SetFrameRate(60) ;MUST BE SET

;IT MAY TAKE A FEW BUFFER FLIPS TO GET SYNCHRONIZED
 For ct = 1 To 20
   FlipBuffers()
 Next

;StartDrawing(ScreenOutput())

For ct = 1 To 30
  DrawScreen(null)
  QueryPerformanceCounter_(@then.q)
  FlipBuffers()
  QueryPerformanceCounter_(@now.q)
  duration(ct) = (now - then) / maxFreq
Next

;StopDrawing()
CloseScreen()

For ct = 1 To 30
PrintN(StrF(duration(ct),2) + " ms" + Chr(9) + StrF(1/duration(ct)*1000,3) + " frames per second")
Next

;PrintN(Str(PeekA($3DA))) ;, 8

PrintN(Chr(10) + "Press any key to exit."): While Inkey() = "": Delay(5): Wend: CloseConsole()

End
User avatar
Demivec
Addict
Addict
Posts: 4270
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: VSync and FlipBuffers(), and Questions

Post by Demivec »

chris319 wrote:It gets worse. I created a procedure which draws a box on the screen and it messes up the timing beyond belief. If the StartDrawing() function is moved to line 27 (outside the loop) and disabled inside the procedure, the box is not drawn at all.
That is because the FlipBuffers would then be inside the StartDrawing()/StopDrawing() block! You can't flip a screen that is still being drawn (and see it).
chris319
Enthusiast
Enthusiast
Posts: 782
Joined: Mon Oct 24, 2005 1:05 pm

Re: VSync and FlipBuffers(), and Questions

Post by chris319 »

The timing is better behaved using a windowed screen. The flip mode used when opening the windowed screen seems to have no meaning. The program relies instead on SetFrameRate().

A fly in the ointment is that FlipBuffers() doesn't work inside a procedure. I have left in my Flip() procedure to demonstrate this. My idea was to flip buffers in a separate thread. In pseudo code it would work thus:

1. Draw graphics
2. Signal external thread to flip buffers
3. External thread sets a shared "busy" flag
4. While external thread is waiting for the next VBlank, main thread begins drawing next frame
5. When finished drawing graphics, main thread waits for "busy" flag to be cleared and signals external thread for next frame. This is to make sure the main (drawing) thread does not get ahead of the screen flipping. This scheme should buy the main thread extra time to draw while the external thread is waiting for VBlank. For this to work, the graphics MUST finish rendering within a period of one frame (about 16.6 ms at 60 fps). In my real application I am doing image processing so the graphics routine is the same for each frame; I am basically reading and rewriting pixels.

Thoughts? How can I flip buffers within a procedure?

Code: Select all

Global now.q, then.q, maxFreq.q, ct, null = 0: Global Dim duration.f(100)

Procedure Flip(null)
  QueryPerformanceCounter_(@then.q)
  FlipBuffers()
  QueryPerformanceCounter_(@now.q)
  duration(ct) = (now - then) / maxFreq
EndProcedure

DisableDebugger
OpenConsole()
QueryPerformanceFrequency_(@maxFreq): maxFreq / 1000

InitSprite()
OpenWindow(0, 0, 0, 1024, 768, "", #PB_Window_BorderLess | #PB_Window_ScreenCentered)
;OpenWindowedScreen(0,0,0,1024, 768, #False, 0, 0,#PB_Screen_WaitSynchronization)
OpenWindowedScreen(0,0,0,1024, 768, #False, 0, 0,#PB_Screen_NoSynchronization)
;OpenWindowedScreen(0,0,0,1024, 768, #False, 0, 0,#PB_Screen_SmartSynchronization)
SetFrameRate(60) ;MUST BE SET

;GET SYNCHRONIZED
FlipBuffers()

For ct = 1 To 20
  StartDrawing(WindowOutput(0))
  Box(0,0,400,400, $00ffff)
  StopDrawing()

  ;Flip(null)
  QueryPerformanceCounter_(@then.q)
  FlipBuffers()
  QueryPerformanceCounter_(@now.q)
  duration(ct) = (now - then) / maxFreq
Next

Delay(2000)
CloseWindow(0)

For ct = 1 To 20
PrintN(StrF(duration(ct),2) + " ms" + Chr(9) + StrF(1/duration(ct)*1000,2) + " frames per second")
Next

;PrintN(Str(PeekA($3DA))) ;, 8

PrintN(Chr(10) + "Press any key to exit."): While Inkey() = "": Delay(5): Wend: CloseConsole()

End
chris319
Enthusiast
Enthusiast
Posts: 782
Joined: Mon Oct 24, 2005 1:05 pm

Re: VSync and FlipBuffers(), and Questions

Post by chris319 »

Back to regular screens. The following incorporates some of djes' excellent code found here:

http://www.purebasic.fr/english/viewtop ... ers+thread

Note that the thread containing FlipBuffers() has a higher priority than the main thread. Note also how the timing has been implemented in the Flip() procedure to help prevent early returns.

Code: Select all

Global now.q, then.q, maxFreq.q, ct, null = 0, threadID1, semaphore1, readyFlag
Global Dim duration.f(100)

Global frameDur.f = (1/(60 / 1)) * 1000

Structure D3DRaster_STATUS
  InVBlank.l
  ScanLine.l
EndStructure

Define.D3DRaster_STATUS Raster
Define.IDirect3DDevice9 D3DDeviceInterface

Procedure Flip(null)
Shared D3DDeviceInterface, Raster

Repeat
WaitSemaphore(semaphore1)

D3DDeviceInterface\GetRasterStatus(0, @Raster)
If Raster\InVBlank = #True
Repeat
  D3DDeviceInterface\GetRasterStatus(0, @Raster)
Until Raster\InVBlank = #False
EndIf

Repeat
  D3DDeviceInterface\GetRasterStatus(0, @Raster)
Until Raster\InVBlank = #True

FlipBuffers()

Repeat
  QueryPerformanceCounter_(@n.q)
  dur.f = (n.q - then.q) / maxFreq
Until dur.f >= frameDur

readyFlag = #True

ForEver
EndProcedure

OpenConsole()
QueryPerformanceFrequency_(@maxFreq): maxFreq / 1000
InitSprite()
OpenScreen(1024, 768, 32, "", #PB_Screen_NoSynchronization) ;, 60)
;SetFrameRate(60)

!extrn _PB_Screen_Direct3DDevice
!MOV dword EAX, [_PB_Screen_Direct3DDevice]
!MOV dword [v_D3DDeviceInterface],EAX

semaphore1 = CreateSemaphore()
threadID1 = CreateThread(@Flip(), null)

SetPriorityClass_(GetCurrentProcess_(), #HIGH_PRIORITY_CLASS)
SetThreadPriority_(GetCurrentThread_(), #THREAD_PRIORITY_ABOVE_NORMAL)
SetThreadPriority_(ThreadID(threadID1), #THREAD_PRIORITY_HIGHEST)

For ct = 1 To 30
  QueryPerformanceCounter_(@then.q)
  readyFlag = #False
  SignalSemaphore(semaphore1)

  StartDrawing(ScreenOutput())
  Box(0,0,400,400, $00ffff)
  StopDrawing()

  While readyFlag = #False: Wend

  QueryPerformanceCounter_(@now.q)
  duration(ct) = (now - then) / maxFreq
Next

SetPriorityClass_(GetCurrentProcess_(), #NORMAL_PRIORITY_CLASS)
SetThreadPriority_(GetCurrentThread_(), #THREAD_PRIORITY_NORMAL)
SetThreadPriority_(ThreadID(threadID1), #THREAD_PRIORITY_NORMAL)

KillThread(threadID1)
CloseScreen()

For ct = 1 To 30
  PrintN(StrF(duration(ct),2) + " ms" + Chr(9) + StrF(1/duration(ct)*1000,2) + " frames per second")
Next

;PrintN(Str(PeekA($3DA))) ;, 8

PrintN(Chr(10) + "Press any key to exit."): While Inkey() = "": Delay(5): Wend: CloseConsole()

End
chris319
Enthusiast
Enthusiast
Posts: 782
Joined: Mon Oct 24, 2005 1:05 pm

Re: VSync and FlipBuffers(), and Questions

Post by chris319 »

This gets us a little closer to perfection.

Code: Select all

Global now.q, then.q, maxFreq.q, ct, null = 0, threadID1, readyFlag
Global Dim duration.f(100)

Structure D3DRaster_STATUS
  InVBlank.l
  ScanLine.l
EndStructure

Define.D3DRaster_STATUS Raster
Define.IDirect3DDevice9 D3DDeviceInterface

Procedure Flip(null)
Shared D3DDeviceInterface, Raster, readyFlag

ct = 0

Repeat
QueryPerformanceCounter_(@then.q)

D3DDeviceInterface\GetRasterStatus(0, @Raster)
If Raster\InVBlank = #True ;IN CASE WE COME PARTWAY INTO A VBLANKING INTERVAL
Repeat
  D3DDeviceInterface\GetRasterStatus(0, @Raster)
Until Raster\InVBlank = #False
EndIf

Repeat
  Delay(2) ;SAVE THE CPU
  D3DDeviceInterface\GetRasterStatus(0, @Raster)
Until Raster\InVBlank = #True

FlipBuffers()

; D3DDeviceInterface\GetRasterStatus(0, @Raster)
; If Raster\InVBlank = #True
; Repeat
;   D3DDeviceInterface\GetRasterStatus(0, @Raster)
; Until Raster\InVBlank = #False
; EndIf

QueryPerformanceCounter_(@n.q)
dur.f = (n.q - then.q) / maxFreq

If ct < 30 And readyFlag = #True
  duration(ct) = dur ;(n - then) / maxFreq
  ct + 1
Else
  SetPriorityClass_(GetCurrentProcess_(), #NORMAL_PRIORITY_CLASS)
  SetThreadPriority_(ThreadID(threadID1), #THREAD_PRIORITY_NORMAL)
EndIf

ForEver

EndProcedure

readyFlag = #False
OpenConsole()
QueryPerformanceFrequency_(@maxFreq): maxFreq / 1000
InitSprite()
OpenScreen(1024, 768, 32, "", #PB_Screen_NoSynchronization) ;, 60)
;SetFrameRate(60)

StartDrawing(ScreenOutput())
Box(0,0,400,400, $00ffff)
StopDrawing()
FlipBuffers()  
StartDrawing(ScreenOutput())
Box(0,0,400,400, $00ffff)
StopDrawing()

!extrn _PB_Screen_Direct3DDevice
!MOV dword EAX, [_PB_Screen_Direct3DDevice]
!MOV dword [v_D3DDeviceInterface],EAX

threadID1 = CreateThread(@Flip(), null)

SetPriorityClass_(GetCurrentProcess_(), #REALTIME_PRIORITY_CLASS)
SetThreadPriority_(ThreadID(threadID1), #THREAD_PRIORITY_TIME_CRITICAL)

Delay(500)
readyFlag = #True

While ct < 30: Wend

SetThreadPriority_(GetCurrentThread_(), #THREAD_PRIORITY_NORMAL)
KillThread(threadID1)
SetPriorityClass_(GetCurrentProcess_(), #NORMAL_PRIORITY_CLASS)
CloseScreen()

For ct = 1 To 30
If duration(ct) <> 0  
  PrintN(StrF(duration(ct),2) + " ms" + Chr(9) + StrF(1/duration(ct)*1000,2) + " fps")
EndIf  
Next

PrintN(Chr(10) + "Press any key to exit."): While Inkey() = "": Delay(5): Wend: CloseConsole()

End
PMV
Enthusiast
Enthusiast
Posts: 727
Joined: Sat Feb 24, 2007 3:15 pm
Location: Germany

Re: VSync and FlipBuffers(), and Questions

Post by PMV »

PureBasic Help - Threads wrote:Note: Don't use DirectX inside threads (MS Windows limitation)! If you need to display graphics in threads use Images and 2DDrawing instead.
PureBasic Help - KillThread() wrote:Imediately kills the specified thread, which had previously been created with CreateThread(). This is a very dangerous function, and should only be used rarely. The problem is that the thread is killed immediately and has no chance to perform any cleanup code (for example, freeing memory, releasing items, de-allocating its own stack).

If possible, a flag like a global variable should be used to tell the thread to quit itself (which does the needed cleanup) and this function should only be used if this is not possible for some reason.
I have not any problems in my game or any other game. Maybe Flipbuffers() is able to
see, that there is nothing changed and returns immediately. What i know is, that you
doesn't need to worry about Flipbuffers()! Just make your game. :wink:
It will need enough time to do that. :)

And of course Flipbuffer() blocks if VSync is activated, that is what VSync is for. It is
just DX on windows behind all the Sprite and Screen functions ... so there is no special
behind that functions. Because i have PB i don't know what the DX-Function name is called.
:mrgreen:

MFG PMV
chris319
Enthusiast
Enthusiast
Posts: 782
Joined: Mon Oct 24, 2005 1:05 pm

Re: VSync and FlipBuffers(), and Questions

Post by chris319 »

Just make your game. :wink:
Where do you get the idea that it's a game? It's an image-processing program for video which must process an entire frame within 1/60 second.
Note: Don't use DirectX inside threads (MS Windows limitation)! If you need to display graphics in threads use Images and 2DDrawing instead.
So far no problem reading the vertical blanking information and calling FlipBuffers(). As you can see from earlier posts in this thread, the synchronization bits used with open screen aren't dependable.
Maybe Flipbuffers() is able to
see, that there is nothing changed and returns immediately.
That's making quite a big assumption about FlipBuffers().
Imediately kills the specified thread, which had previously been created with CreateThread(). This is a very dangerous function, and should only be used rarely. The problem is that the thread is killed immediately and has no chance to perform any cleanup code (for example, freeing memory, releasing items, de-allocating its own stack).

If possible, a flag like a global variable should be used to tell the thread to quit itself (which does the needed cleanup) and this function should only be used if this is not possible for some reason.
Good point and easily changed.
PMV
Enthusiast
Enthusiast
Posts: 727
Joined: Sat Feb 24, 2007 3:15 pm
Location: Germany

Re: VSync and FlipBuffers(), and Questions

Post by PMV »

Ah sorry, had read that you want to make image-processing program
just forgotted :oops: .
I have read your post a little bit more carfully and now i got what
you want to get with your little Flip()-Procedure. To be direct, that
will have no effect, i still don't think that Flipbuffers() is allowed in
a thread ... but additional, Flipbuffers() doesn't do that much. You
do the same thing (and more) as Flipbuffers() will do alone. Waits
until the next possible time to swap and get back to work for the
next frame.

And if you write to the Screen before it is flipped, you will write
to the false buffer. So you need to wait until the flip is finished.
It can be just possible, that you could write onto a sprite while
waiting for the flip and until the sprite is finished and the flip is
done, write the sprite to the screen, start waiting for the next
flip and draw the next frame onto the sprite. That would be
something like a dripple buffer. By the way, OpenGL has such an
Option ... maybe you could use OpenGL directly instead of
DX and PB. Could be, that OpenGL is more Threadsafe, too :)

MFG PMV
Post Reply