How to enable triple buffering?
BlitzMax Forums/OpenGL Module/How to enable triple buffering?
| ||
Title says it all. I stumbled on this article: http://www.anandtech.com/video/showdoc.aspx?i=3591&p=1 Which explains very clearly the differences between single, double and triple buffering. I am assuming there is a way to to s call for the video driver to set it to the wished buffering mode. While we are at it, is it possible to probe for vertical sync speed and set it to the highest possible too? |
| ||
I read part of the article. To my knowledge triple buffering is where you start processing the next frame as soon as you finished the current one, even if you haven't flipped the current one yet. Particularly useful when you are locked into the vertical blank but you don't want to just sit there spinning your wheels waiting for it to be time to flip. It can be useful when your game isn't using 100% of the CPU time and has some time left to start the next frame. Also as the article mentions, if your frame takes just over 1 frame to draw and would thus miss the vertical blank, it can start drawing the next frame in the hope that it will finish before it has to flip, so that you can see `current time` rather than 1 frame old. However, what that means is if your game is not CPU intensive, *whats the point in starting the next frame early*? It helps perhaps when you have lots of work to do or highly fluctuating workloads. To achieve it you'd need some other `buffer`. In OpenGL for example you'd need to perhaps use a Frame Buffer Object/Render Buffer to make a second backbuffer. You'd also need to be able to ideally flip the display and do calculations separately, ie you'd need something like threading, or going and checking how much time is left in the current frame and possibly going off to do a little bit of work before checking if it's time to flip. I don't know that this is really supported in the driver as such. GL for example does not typically have triple buffering. Not sure what happens when you change the write buffer to point to a different buffer, though, like a stereo buffer or auxiliary buffer (if supported). Otherwise I'm thinking you'd need to use renderbuffers or copy the whole extra buffer into the backbuffer before flipping? I don't know if render buffers can be used to flip. I think if you just use threading and have your main thread deal with flipping the display with Flip 1 (vsync), and some other thread doing all your logic calculations, combined with one extra buffer, you could do triple buffering. Here's a thought though... There is a difference nowadays between rendering graphics and calculating logic. Logic is typically decoupled from graphics so that you can do things like delta timing or fixed rate logic, to support physics stability etc. Calculating logic does not necessarily have to be tied into creating a visual representation of that logic. You could technically calculate many frames of logic for only one frame of graphics. And in fact in a high-frequency fixed-rate system you could be doing 3 or more logic loops for every graphics frame. The graphics would only need to `lock` a `logic buffer` when it's time to draw a frame of graphics, say once every 60th of a second. When it's `locked` the logic state for that logic pass, the cpu can still go off and calculate more logic frames - either after the graphics are done rendering or at the same time using threads. This still only requires a double buffered display. Even if you're still only doing 1 frame of logic every 1 graphics frame, you can still go off an start doing the next frame's logic at the same time as the graphics are being rendered for the locked `logic buffer`, in its own thread. After all there isn't much point updating graphics more often than 60fps or so. So if there is some cpu time spare in this frame, we can start calculating the next frame. Since logic and rendering are separate, now, we don't need 3 graphics buffers, only 2. You can have as many logic `buffers` as you like - ie sets of game state, but I don't see why you'd need more than 2 or 3 - one to be locked for drawing graphics, and one to be updated for the next frame/logic step. When a logic step is finished, if the graphics finished using the locked buffer you can now use that buffer to store the next logic frame. So I think these days triple buffer is defunct. It's an old-school technique based on the days when nobody was doing delta/fixed rate logic. They even did this back on the Amiga sometimes to squeeze out a little extra performance during the wait for the vertical blank - the vblank was often triggered by a hardware interrupt which called a piece of code to render the display and flip it at the right time. So when that was done, the `normal program` could start on the next frame. In the old days you only had 3 buffers because people weren't doing decoupled logic, had no clue about logic buffers, or threading, and the hardware was a preditcable standard spec - which means you didn't have to worry about lots of different CPU speeds or graphics cards. You had one cpu speed, one graphics performance level, and so you didn't have to worry about flexible framerates - you could finetune everything to always perform at 50/25 or 60/30 hz. So these days I think triple buffering has been replaced by threaded engines and multiple logic passes which really removes the need to have another backbuffer. That said, I suppose if you just got done drawing a frame and you're going off to start more logic, you could possible start drawing another frame as well. So maybe it would still have some benefit, but I think in terms of engine design people these days just go with threading to take advantage of the available cpu time, or at least a fixed-rate-like logic system to update graphics only as often as needed. |
| ||
So the way to go is to have two textures on a FBO and render one frame to each alternating the display from the first to the second every frame. While one is rendered to, the other is being displayed. I am thinking of having a game logic thread running at constant steps, producing a 'game state frame' , and a rendering thread which would pick up the latest complete 'game state' and render it. I am thinking about having the game logic thread running at either the best frame rate available to the user or to just have it run at 200Hz. While it may be overkill for user input granularity, there are already 200Hz monitors out there. Only a single complete game state would be available at any time. if the renderer thread does not pick one game state up, and the logic thread starts calculating a third one, the oldest game state is deleted, leaving only the newest complete game state available. Now, how do I read the available video modes/refresh rates? |
| ||
Okay, however, like I said, if you have separate logic, you only need double-buffering. So long as you make it so that you can have more than one set of logic data you only need to double-buffer the graphics. ie you are double-buffering your logic updates, which takes the place of needing to have a third graphics buffer. When the logic update is done, you mark that `logic buffer` as complete and then when the graphics are ready it can start using it to draw. Then you go and start doing another logic update in a second logic buffer. If that one gets done by the time the graphics need to update again, it'll use that one. If it doesn't, it'll use the old one, and if this one gets done with and locked but the graphics are still updating with the second buffer, then go to a third logic buffer, etc. Look at the help files in the IDE to find the display mode commands. |