Multiple OpenGL contexts, multiple windows, multithreading and Vsync

I am using OpenGL to create a graphical user interface application that can have any number of windows - the "multi document interface" style

If there is a window, the main loop may be as follows:

>Handle events > draw() > swap buffer (Vsync causes blocking until the vertical monitor flushes)

However, when there are 3 windows, consider the main loop:

>Each window handles events > each window draw() > window 1 swap buffer (block until Vsync) > (after a period of time) window 2 swap buffer (block until Vsync) > (after a period of time) window 3 swap buffer (block until Vsync)

Bad... Now the application that renders a frame occurs at 1 / 3 of the correct frame rate

Workaround: utility window

One solution is that only one of the windows is open with Vsync and the rest is closed with Vsync First call swapbuffers () on the Vsync window, then draw one, and then draw the remaining windows and swapbuffers () on each window

This solution may look good, but it's not without a problem:

A window is special, which is inappropriate > a game may lead to screen tearing > some platforms ignore the Vsync setting and force it to turn on > I read that the switching of OpenGL context is an expensive operation and should be avoided

Solution: one thread per window

Because each thread can have an OpenGL context binding, perhaps the answer is that each window has a thread

I still want the GUI to be single threaded, but the main loop in the 3 window case is as follows:

(each window)

>Lock global mutex > handle events > draw() > unlock global mutex > swapbuffers()

This other question means no:

To investigate this statement, I created a simple test program The program creates n windows and N threads. Each thread binds a window, requests each window to enable Vsync, and then reports the frame rate So far, the results are as follows:

> Linux,X11,4.4. 0 NVIDIA 346.47(2015-04-13)

>The frame rate is 60 FPS, no matter how many windows are open

> OSX 10.9. 5(2015-04-13)

There is no upper limit on the frame rate; The swap buffer is not blocked

Solution: there is only one context and a large frame buffer

Another idea that came to my mind is that there is only one OpenGL context, a large framebuffer, and the sizes of all windows are put together

Each frame and window calls glviewport to set their respective framebuffer rectangle before drawing

After all drawings are completed, swapbuffers() is in a unique OpenGL context

I am going to investigate whether this solution is feasible I have some questions:

>Is there such a large frame buffer? > Can I call glviewport multiple times per frame? > Does the window library API I'm using allow me to create OpenGL contexts independently of windows? > If the windows are of different sizes, waste space in the frame buffer?

Camilla Berglund, glfw's maintainer, said:

Solution: there is only one context

This question indicates that the algorithm may work:

Activate OpenGL context on window 1  
Draw scene in to window 1

Activate OpenGL context on window 2  
Draw scene in to window 2

Activate OpenGL context on window 3  
Draw scene in to window 3

For all Windows
SwapBuffers

According to the questioner,

It seems that they have only tested on Microsoft Windows, and this solution will be everywhere

Many other sources tell me that makecontextcurrent () is too slow in the draw () routine

It also does not appear to comply with the EGL specification In order to allow another thread eglswapbuffers (), you must eglmakecurrent (null), which means that your eglswapbuffers should now return EGL_ BAD_ CONTEXT.

problem

So my question is: what is the best way to open a multi window application using Vsync? This seems to be a common problem, but I haven't seen a satisfactory solution yet

Similar problems

Similar to this problem: synchronizing multiple OpenGL windows to Vsync, but I want a platform independent solution - at least for each platform

And this question: using swapbuffers() with multiple OpenGL canvas and vertical sync? But really, this problem has nothing to do with Python

Solution

No, it doesn't stop Buffer swap calls return immediately without blocking However, it inserts a synchronization point so that any command to change the background buffer is delayed until a buffer swap occurs The length of OpenGL command queue is limited, which makes program blocks possible

Buffer swapping is also not an OpenGL operation It is a graphics / window system level operation, independent of OpenGL context Just look at the buffer swap function: their only parameter is the handle to drawable (= window) In fact, even if you have multiple OpenGL contexts running on a drawable, you only need to swap the buffers once; You can use drawable without OpenGL context

So the usual approach is:

' first do all the drawing operations
foreach w in windows:
    foreach ctx in w.contexts:
        ctx.make_current(w)
        do_opengl_stuff()
        glFlush()

' with all the drawing commands issued
' loop over all the windows and issue
' the buffer swaps.
foreach w in windows:
    w.swap_buffers()

Since buffer swapping is not blocked, you can issue all buffer swapping for all windows without being delayed by V-sync However, the next OpenGL drawing command that addresses the background buffer for swapping may stop

The solution is to use the FBO that occurs in the actual drawing and combine it with the FBO BLIT loop to the background buffer before the swap buffer loop:

' first do all the drawing operations
foreach w in windows:
    foreach ctx in w.contexts:
        ctx.make_current(w)
        glBindFramebuffer(GL_DRAW_BUFFER,ctx.master_fbo)
        do_opengl_stuff()
        glFlush()

' blit the FBOs' renderbuffers to the main back buffer
foreach w in windows:
    foreach ctx in w.contexts:
        ctx.make_current(w)
        glBindFramebuffer(GL_DRAW_BUFFER,0)
        blit_renderbuffer_to_backbuffer(ctx.master_renderbuffer)
        glFlush()

' with all the drawing commands issued
' loop over all the windows and issue
' the buffer swaps.
foreach w in windows:
    w.swap_buffers()
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>