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

Re: VSync and FlipBuffers(), and Questions

Post by chris319 »

If you read the earlier posts in this thread carefully, you see that I tried several schemes for achieving a consistent frame rate and that the synchronization flags in OpenScreen() didn't work very well. I don't know what the exact problem is with using DirectX to monitor the scan lines and flip buffers inside a thread but this works OK so far (it's not perfect) considering that I'm trying to get Windows to do what should really be done with a hard-real-time OS.

Now there is a further hangup. Try changing the line count in line 22 of the program to 768 and see tearing at the top of the frame (at least I do). So I made an educated guess and subtracted 16 from the line count and the tearing went away, so maybe there is a bug in DirectX?
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.
All true. There will have to be synchronization between drawing and buffer flipping.

Code: Select all

Global now.q, then.q, maxFreq.q, ct, null = 0, threadID1, readyFlag, threadKillFlag = #False
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)

Delay(15) ;GIVE THE CPU A REST FOR APPROXIMATELY 700 SCAN LINES AT 60 Hz REFRESH RATE
Repeat
  D3DDeviceInterface\GetRasterStatus(0, @Raster)
Until Raster\ScanLine = 768 - 16 ;CHANGE THIS VALUE TO 768 TO SEE TEARING AT THE TOP
;Until Raster\ScanLine = 768

FlipBuffers()

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

If ct < 30 And readyFlag = #True
  duration(ct) = dur ;(n - then) / maxFreq
  ct + 1
EndIf

If threadKillFlag = #True: KillThread(threadID1): EndIf
ForEver

EndProcedure

MessageRequester("", "When you see two colored boxes, quit by pressing any key.")
readyFlag = #False
QueryPerformanceFrequency_(@maxFreq): maxFreq / 1000
InitSprite()
InitKeyboard()
OpenScreen(1024, 768, 32, "", #PB_Screen_NoSynchronization) ;, 60)
;SetFrameRate(60)

StartDrawing(ScreenOutput())
Box(0,0,200,768, $ff0000)
StopDrawing()
FlipBuffers()  
StartDrawing(ScreenOutput())
;Box(0,0,200,768, $ff0000)
Box(200,0,200,768, $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

Repeat
  ExamineKeyboard()
Until KeyboardPushed(#PB_Key_All)

threadKillFlag = #True
SetThreadPriority_(GetCurrentThread_(), #THREAD_PRIORITY_NORMAL)
SetPriorityClass_(GetCurrentProcess_(), #NORMAL_PRIORITY_CLASS)
CloseScreen()

OpenConsole()
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 »

I had really a big laugh after i have seen that code.
please get fully rid of KillThread()! Just replace it with
a "break" ... you doesn't have understand my quote
that sayes ... "don't use KillThread()!"? :lol:
It is just for the worst case scenario!

chris319 wrote:If you read the earlier posts in this thread carefully, you see that I tried several schemes for achieving a consistent frame rate and that the synchronization flags in OpenScreen() didn't work very well. I don't know what the exact problem is with using DirectX to monitor the scan lines and flip buffers inside a thread but this works OK so far (it's not perfect) considering that I'm trying to get Windows to do what should really be done with a hard-real-time OS.

Now there is a further hangup. Try changing the line count in line 22 of the program to 768 and see tearing at the top of the frame (at least I do). So I made an educated guess and subtracted 16 from the line count and the tearing went away, so maybe there is a bug in DirectX?
I know your code with your test for vsync, and the results really make no sense.
But your timing calculation gets horrible wrong. :) If you want to calculate
timings faster as the normal timer resolution of ~16ms, you need more then
calling QueryPerformanceCounter. You have to call timeBeginPeriod_(1) and
before program end timeEndPeriod_(1), where the parameter defines the
resolution in ms.
http://msdn.microsoft.com/en-us/library ... s.85).aspx
A Delay(1) is then mostly really 1 ms long.

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

Re: VSync and FlipBuffers(), and Questions

Post by chris319 »

a flag like a global variable should be used to tell the thread to quit itself (which does the needed cleanup)
Setting a higher resolution can improve the accuracy of time-out intervals in wait functions. However, it can also reduce overall system performance, because the thread scheduler switches tasks more often. High resolutions can also prevent the CPU power management system from entering power-saving modes. Setting a higher resolution does not improve the accuracy of the high-resolution performance counter.
I suggest you do some reading on the high-resolution performance counter and work through the numbers.

In the most recent version of my code there is a huge mistake unrelated to timers and KillThread(). See if you can find it.
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 year, the timeBeginPeriod is just for the normal time-stuff, like a
Delay(), sorry.

But as i understand the killthread-help. It means that if the thread itself
terminates, then it will do the needed cleanup. That means by reaching
the end of the procedure ... if you call Killthread() it will immediately
stop it without cleanup, regardless if the call is inside the thread itself
or not. Otherwise the help inside of Killthread() should mention, that it
is safe to call it inside of the thread itself, but i don't think so. :)

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

Re: VSync and FlipBuffers(), and Questions

Post by chris319 »

You really need to read the docs and these posts more carefully.
If possible, a flag like a global variable should be used to tell the thread to quit itself (which does the needed cleanup)
That's twice that I've quoted the same part of the help file. Do you understand what it means?
Post Reply