Page 1 of 2 12 LastLast
Results 1 to 10 of 13

Thread: understanding the opengl main loop / swapbuffers

  1. #1
    Newbie Newbie
    Join Date
    Mar 2017
    Location
    La Sude
    Posts
    4

    understanding the opengl main loop / swapbuffers

    I'm trying to learn opengl through a tutorial and there is typically a main loop like this:

    Code :
    do {
      glClear(...);
      render_scene_with_lots_of_opengl_commands();
      glfwSwapBuffers(...);
    } while(true);

    As I understand it, there are two buffers - one currently shown and one you draw on. The buffers cannot be swapped at any time because that would cause tearing so swapbuffers() will wait for vertical blanking, a short time time interval that occurs once every 1/60 seconds (if that's your screens refreshrate) during which the swap can take place without tearing.
    Now, let's say I also want to add a somewhat timeconsuming calculation to be done for every drawn frame that does not involve drawing into the current draw-buffer. I'd expect the code to look like so:

    Code :
    do {
      glClear(...);
      render_scene_with_lots_of_opengl_commands();
      glReadyToSwapBuffers();
      doCalculations();
      glfwSwapBuffers(...);
    } while(true);

    The extra gl-call I added, glReadyToSwapBuffers(), may not exist or be called something else. It is supposed to tell the opengl framework that I'm finished drawing the scene and that I want it to be displayed at the next moment when that can be done (vertical blanking). The difference between this and glfwSwapBuffers() is supposed to be that glReadyToSwapBuffers() should simply schedule the switch (perhaps to be completed in an interrupt) and return immediately. The point is that I could then doCalculations() in parallel with waiting for vblank instead of doing these two serially, i.e. if the entire loop takes a little more than 1/60 second I could get, say, 50 fps instead of 30.

    My question: is there a call like my suggested glReadyToSwapBuffers() and if not - why not?

  2. #2
    Newbie OpenGL Pro
    Join Date
    Jan 2007
    Posts
    1,789
    The nearest thing to such a call is glFlush which tells the driver to start issuing buffered-up commands, but can return immediately so that you can do other work in parallel.

    You will have noticed that OpenGL itself does not actually have a SwapBuffers call. This is because OpenGL delegates this responsibility to the underlying windowing system, or a framework built on top of the underlying windowing system - in your example GLFW. GLFW is not part of OpenGL, nor are other frameworks such as GLUT or SDL.

    If you have useful work to do which you wish to run in parallel with a buffer swap, why not just run it in another thread?

  3. #3
    Senior Member Regular Contributor
    Join Date
    May 2016
    Posts
    477
    Quote Originally Posted by drhexgl View Post
    My question: is there a call like my suggested glReadyToSwapBuffers() and if not - why not?
    why should there be such a function ? what should it do / return ?

    should it wait until opengl has finished rendering the frame ?
    not necessary, because thats what "glfwSwapBuffers()" does

    should it return a bool just to check if opengl has finished rendering the frame ?
    you can do that by using a "query object", but how would you check that?
    Code :
    while ( openglstildoessomework() )
    {
    ... do other stuff ...
    }
    the problem with that would be that "..do other stuff" could take more than 1/60 seconds which would slow down the entire main loop

    the best way (imho) is to do everything non-graphics-related work in another thread(s), the main loop only does graphics

  4. #4
    Senior Member Regular Contributor
    Join Date
    Jul 2012
    Posts
    459
    For people who don't care about VSync (ie if it's disabled in the graphic card control panel, or if equivalent OpenGL codes have been honoured by the hardware), then swapBuffers or subsequent GL calls will not wait. The reasoning is almost the same if the monitor vsync rate is different (50, 60, 100 Hz), or if, for some reasons you get bounded, then the vsync get divided by 2 (or even more). Then you cannot know what amount of work you can achieve.

    Doing it in another thread, is something you can check. However, if what is sent to GL depends on what is calculated in this other thread, synchronization might become an issue. For example, if you have to wait for the whole calculation to be done in order to have something 'showable' (for example complete, or coherent...) on the screen, you'll loose one frame. You might still render at 60 fps (if this is your monitor settings), but you might only really put new contents to the display only half...

    Finally, since you told you are learning OpenGL, I would suggest you to stick in a single thread. If your computations start to slow the rendering, just like john_connor said, then try to disable vsync. You might then have a decent framerate without cutting it by half or more.

  5. #5
    Newbie Newbie
    Join Date
    Mar 2017
    Location
    La Sude
    Posts
    4
    I expect glReadyToSwapBuffers() to return immediately, with no value, after having scheduled an extra command to be run when all the gpu's drawing commands currently queued for the drawing-buffer are completed, which would:
    * check if we are in the vblank region right now, and if so swap buffers immediately
    * otherwise set a flag to inform an interrupt that runs every time the vblank starts that it is supposed to swap buffers
    * Ensure that a flag is set if the buffers are swapped by any of the two means above, which will tell the ordinary glfwSwapBuffers() that it doesn't need to do anything as the job is already done.

    Of course I can let other threads do calculations as well, I just wanted the first thread to be able to work while waiting for vblank.

  6. #6
    Senior Member OpenGL Guru
    Join Date
    Oct 2004
    Posts
    4,649
    Quote Originally Posted by drhexgl View Post
    As I understand it, there are two buffers - one currently shown and one you draw on.
    Yes, two if double-buffering is enabled. 3 or more if triple/multi-buffering is enabled. (It sounds like you may want to read up on that by the way: Triple buffering).

    The buffers cannot be swapped at any time because that would cause tearing so swapbuffers() will wait for vertical blanking, a short time time interval that occurs once every 1/60 seconds (if that's your screens refreshrate) during which the swap can take place without tearing.
    Now, let's say I also want to add a somewhat timeconsuming calculation to be done for every drawn frame that does not involve drawing into the current draw-buffer.
    As mhagain said, you can run it in another thread, possibly pipelined with the draw thread. Or you can run it synchronously on your draw thread, but that means you'll have less time to submit draw commands to the GPU (assuming you don't break a frame; i.e. drop to < 60 Hz), cutting into the max complexity of content you can render.

    The extra gl-call I added, glReadyToSwapBuffers(), may not exist or be called something else. It is supposed to tell the opengl framework that I'm finished drawing the scene and that I want it to be displayed at the next moment when that can be done (vertical blanking). The difference between this and glfwSwapBuffers() is supposed to be that glReadyToSwapBuffers() should simply schedule the switch (perhaps to be completed in an interrupt) and return immediately.
    That's what SwapBuffers pretty much does. On drivers I'm familiar with, it merely queues a "I'm done; you can swap when ready" event on the command queue. If the command queue isn't full (by driver-internal criteria), then you get the CPU back and can do what you want -- before the Swap has occurred. Some driver's will buffer up as much as another frame or two of commands before they block the draw thread in a GL call because their "queue full" criteria is met.

    To force the driver "not" to do that (on a desktop discrete GPU only; i.e. sort-last architecture) and instead wait for the swap, you put a glFinish() right after SwapBuffers. When that returns, you know that the SwapBuffers has occurred, which means you've synchronized your draw thread with the VSync clock.

    Re driver queuing, if you use triple buffering, that allows you and the driver to get further ahead on drawing the next frame before VSync even when VSync is on. This even allows the driver to start rasterizing the next frame before the Swap actually occurs when the buffer pipeline would otherwise be full.

    The point is that I could then doCalculations() in parallel with waiting for vblank instead of doing these two serially, i.e. if the entire loop takes a little more than 1/60 second I could get, say, 50 fps instead of 30.
    You can still do this, even in the same thread if you're careful. But again it's going to eat into how much time how can submit draw work. Keep in mind that instead of doing these calculations on the draw thread, you could be submitting draw work for the next frame.

  7. #7
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    3,100
    Quote Originally Posted by drhexgl View Post
    I expect glReadyToSwapBuffers() to return immediately, with no value, after having scheduled an extra command to be run when all the gpu's drawing commands currently queued for the drawing-buffer are completed,
    That's what the underlying function (glXSwapBuffers() on X11, SwapBuffers() on Windows) does.

    However, it necessarily first issues an implicit glFlush(), and if there isn't enough space to flush pending commands from CPU memory to GPU memory, it may have to block until there is. Performing an explicit glFlush() first reduces the chances of the buffer-swap function blocking.

    Furthermore, there's a limit to how many frames can be enqueued. If you render frames faster than the monitor's refresh rate (and triple buffering isn't enabled), eventually OpenGL commands will start blocking. Specifically, attempts to flush pending commands will block until there's a draw buffer available on which those commands can be executed. Almost any command can cause a flush if the command buffer is full, but the buffer swap command always flushes.

    It isn't possible to poll the state of the command pipeline. If you want to interleave rendering with other operations, use threads.

  8. #8
    Newbie OpenGL Pro
    Join Date
    Jan 2007
    Posts
    1,789
    It's worth adding to this discussion that Direct3D has a D3DPRESENT_DONOTWAIT option on it's equivalent call, which will cause it to return immediately (setting the appropriate return value) if the hardware is either busy processing or waiting for a vsync interval. The theory is that you can then do some other useful work and try again later. In practice however, it's difficult to know how much later to try again or how much other work to do, and the option is not well supported by hardware or drivers.

  9. #9
    Newbie Newbie
    Join Date
    Mar 2017
    Location
    La Sude
    Posts
    4
    Quote Originally Posted by GClements View Post
    That's what the underlying function (glXSwapBuffers() on X11, SwapBuffers() on Windows) does.

    eventually OpenGL commands will start blocking..
    Aha! I thought glfwSwapBuffers() would always block waiting for vblank as neither of the two buffers can be drawn to. But of course it doesn't need to block unless I start issuing more drawing commands before the switch has happened.

    In the Wikipedia page about the current "Geforce 10 series" graphics cards from Nvidia, it says that one of its features is that it has "Triple buffering implemented in the driver level". As my card is much older (500-series), I thought it therefore wouldn't have triple buffering.

  10. #10
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    3,100
    Quote Originally Posted by drhexgl View Post
    In the Wikipedia page about the current "Geforce 10 series" graphics cards from Nvidia, it says that one of its features is that it has "Triple buffering implemented in the driver level". As my card is much older (500-series), I thought it therefore wouldn't have triple buffering.
    Triple buffering can be implemented on practically anything; the only exception is ancient hardware where framebuffer memory and texture memory are distinct and there simply isn't enough framebuffer memory for more than two framebuffers.

    But the driver may still limit triple buffering to the refresh rate, in which case buffer swaps can still block.

Page 1 of 2 12 LastLast

Similar Threads

  1. OpenGL Control within main Visual Studio project
    By JCF120 in forum OpenGL: Windows
    Replies: 3
    Last Post: 06-13-2013, 07:05 AM
  2. Exit Main Loop
    By SamK in forum OpenGL: Basic Coding
    Replies: 4
    Last Post: 06-16-2006, 07:47 PM
  3. Can I set up OpenGL Env without creating main window?
    By xiao in forum OpenGL: Basic Coding
    Replies: 5
    Last Post: 06-18-2002, 06:52 AM
  4. OpenGL and Windows main menu
    By warlordQ in forum OpenGL: Advanced Coding
    Replies: 2
    Last Post: 08-03-2000, 09:16 AM
  5. Could opengl render to main memory directly?
    By chiwei in forum OpenGL: Advanced Coding
    Replies: 6
    Last Post: 07-30-2000, 11:26 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Proudly hosted by Digital Ocean