Detect Vertical Blank
BlitzMax Forums/OpenGL Module/Detect Vertical Blank
| ||
Could anyone point me to a method for detecting an imminent hardware refresh? For some reason, I can't get FlipHook to work. Do you need a Max2d context? I'm using OGL in a MaxGUI Canvas. In case you're wondering why I need it, I plan on doing the following: Detect Vertical Blank Flip current buffer Draw updated graphics (to backbuffer) While drawing, set "IS_DRAWING" = True DO NOT FLIP once done drawing. Set "IS_DRAWING" = False Upon next Vertical Blank, check status of "IS_DRAWING" If False, flip and repeat the whole process If True, DO NOT FLIP. Allow the draw function to continue drawing Wait for the next Vertical Blank and check again. The idea is that, with a 60hz refresh rate, the system will attempt to draw once every 1/60th of a second. A buffer will already be 'ready' as soon as the system detects a vertical blank, and thus will be able to dump that completed buffer to the screen with no tearing. If the draw function hasn't finished drawing the buffer, it skips the flip until the next 1/60th of a second cycle. In this case of just one flip 'skip', the true flip rate would be 30 flips per second for that short period of time. This is probably how "Flip 1" works, but for whatever reason Flip 1 locks up my app and hogs CPU. Thanks for your assistance in advance. |
| ||
Flip 1 detects the vertical blank and then flips the backbuffer. |
| ||
Yes, but as I said in my post... This is probably how "Flip 1" works, but for whatever reason Flip 1 locks up my app and hogs CPU. Besides, I would like more precise control over my buffer flips. There has to be a way to detect the vertical blank. What about fliphook? I couldn't get that to work but perhaps was doing it wrong. Has anyone used it? |
| ||
It would be nice to have a WaitVBL command that just waits for the blank and then returns, but alas we don't got one. At the moment you have to flip at the same time as the vblank wait, and like you say it wastes cpu time. You could use a timer to estimate when the vblank is about to occur and trigger a flip? |
| ||
Unfortunately that still causes tearing. Sure, I can flip 60 or 30 or 15 times per second (assuming 60 hz), but there is no guarantee that my custom 'flip timer' will fire in sync with the VBL. The phase shift between the two leads to tearing. |
| ||
Unless every several frames you do a Flip 1 and resynchronize the flips with your timed flips. Not ideal I know. It would be really nice to have a WaitVBL command - maybe we can rip some code out from Flip()? or does it access the o/s to do it? |
| ||
Well, the flip() code is stored in BRL.mod -> graphics.mod, under line 341. The code is as follows: Function Flip( sync=-1 ) RunHooks FlipHook,Null If sync<>-1 _driver.Flip sync Return EndIf If _graphics<>_exGraphics Or Not _softSync Local sync=False If _gDepth sync=True _driver.Flip sync Return EndIf _syncTime:+_syncPeriod _syncAccum:+_syncFrac If _syncAccum>=_syncRate _syncAccum:-_syncRate _syncTime:+1 EndIf Local dt=_syncTime-MilliSecs() If dt>0 Delay dt Else _syncTime:-dt EndIf _driver.Flip False End Function I'll take a closer look and try to figure out what's going on here. |
| ||
I think that the line: _driver.Flip syncis the one which is calling a routine in the driver, which is probably platform specific, to do a Flip 0 or a Flip 1. The rest of the code seems to handle the Flip -1 condition. We'd have to look at the driver's Flip routine to see which parts of it are coded in BlitzMax and whether there is something there we can pull out to do just a vbl wait without flipping, otherwise it might involve dipping into C code or something. |
| ||
Are you sure about that? _driver is a TGraphicsObject, whose method "Flip" is the one we're looking at above. It seems like there are several recursive calls to the Flip function from within itself. My guess is that the various globals, namely: Global _softSync,_syncRate,_syncPeriod,_syncFrac,_syncAccum,_syncTime Are somewhere registered with the platform-specific drivers, and an internal buffer swap is called by those drivers when conditions pertaining to the globals are met. Perhaps when _syncFrac = 0. Gah, where's Mark when you need him? |
| ||
See this below code, for example, in Objective C format from the .m Mac file, as part of the GLGraphics module (part of the GL driver): And this was referenced in the GLGraphics.bmx file, so I'm sure the DX driver has its own code for flipping too. That's why I said you probably have to dip into C code to handle the verticle blank issue. I don't entirely follow what the above code is doing, either. It seems like it's using a GL graphics context and setting Sync to be a field within that type, either 1 or 0, and presumably the flushBuffer is actually doing the flip - presumably the vertical blank part of it is built into the o/s's implementation of OpenGL. You'd probably end up having to look at the o/s API itself to see if it provides a vblank wait that isn't tied to a flip. |
| ||
I saw this on an Apple page: "OpenGL blocks drawing to the display while waiting for the next vertical retrace. Applications that attempt to draw to the screen during this waiting period waste time that could be spent performing other drawing operations or saving battery life and minimizing fan operation." "The swap interval can be set only to 0 or 1. If the swap interval is set to 1, the buffers are swapped only during the vertical retrace. After you set up synchronization, call the function CGLFlushDrawable to copy the back buffer to the front buffer during the vertical retrace of the display." which says to me that with GL you don't really get to detect the vblank yourself, it's part of the call to flip the display because when you're using OpenGL you have to use the GL flip function provided by the o/s. I don't quite get what you plan to do. Lets say you spend half a frame rendering the next frame and you have several milliseconds of time spare, what else do you plan to do in that time? Further processing while somehow the hook just magically occurs when the flip is ready? You still have to poll for events to trigger the hook function. Are you hoping for a `test if the vertical blank happened yet` poll command, which returns with a true/false rather than waiting? How about you use Flip 1 to sync to vbl, then you know that you have about 15 milliseconds until the next vbl, so after you finish preparing the next frame you check the time and if the time hasn't arrive to do the next flip (approximately just before) you keep doing processing. Then you do a Flip 1 - it'll waste a little bit of time but not all of it. |
| ||
My program is entirely hook-based. As a result, I need a logical way of calling the screen's redraw function, since I do not want to draw 'whenever possible,' as this would interrupt the other timed functions. The ideal case is to be able to hook into the VBL so I can call my redraw function exactly once per refresh. I'm going to put this one on the back-burner and simply call my redraw function less frequently. If anyone has used the "fliphook" function with success, I'd love to hear about it. |
| ||
The flip hook is supposed to work. If it's not working, is it bugged? |
| ||
Perhaps I'm doing it wrong.. my assumption was that I simply Addhook(Fliphook,MyFlipHookFunc) like I would with any EmitEventHook, and then it will simply call MyFlipHookFunc once every flip. hmf |
| ||
It would help to have a small example which shows the problem. |