Merge lp:~compiz-team/compiz/compiz.gles2.always-swapbuffers.1 into lp:~compiz-linaro-team/compiz/gles2

Proposed by Sam Spilsbury
Status: Merged
Merged at revision: 3255
Proposed branch: lp:~compiz-team/compiz/compiz.gles2.always-swapbuffers.1
Merge into: lp:~compiz-linaro-team/compiz/gles2
Prerequisite: lp:~compiz-team/compiz/compiz.compiz_discover_tests
Diff against target: 699 lines (+439/-115)
8 files modified
plugins/opengl/CMakeLists.txt (+7/-2)
plugins/opengl/include/opengl/doublebuffer.h (+31/-0)
plugins/opengl/src/doublebuffer/CMakeLists.txt (+31/-0)
plugins/opengl/src/doublebuffer/src/double-buffer.cpp (+34/-0)
plugins/opengl/src/doublebuffer/tests/CMakeLists.txt (+24/-0)
plugins/opengl/src/doublebuffer/tests/test-opengl-double-buffer.cpp (+91/-0)
plugins/opengl/src/privates.h (+67/-0)
plugins/opengl/src/screen.cpp (+154/-113)
To merge this branch: bzr merge lp:~compiz-team/compiz/compiz.gles2.always-swapbuffers.1
Reviewer Review Type Date Requested Status
Daniel van Vugt Approve
Review via email: mp+113544@code.launchpad.net

This proposal supersedes a proposal from 2012-07-05.

Description of the change

Always use *SwapBuffers instead of using glCopyPixels. Introduces a dependency on either having EGL_NV_post_sub_buffer OR GLX_MESA_copy_sub_buffer OR OpenGL 3.0 OR GL_EXT_framebuffer_object.

More of an RFC really.

Related to bug 1013514

To post a comment you must log in.
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

It seems to work very nicely on intel. I have a couple of concerns though:

1. The glCopyPixels fallback works and is reliable. I would like to keep it unless there is a good reason not to. That way we don't raise the minimum system requirements unnecessarily.

2. We need a configuration option for people to be able to choose the old rendering method. There is a significant performance hit in (unthrottled) benchmark results with this change. So people need to have the option of going back to regional updates.

review: Needs Fixing
Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

> It seems to work very nicely on intel. I have a couple of concerns though:
>
> 1. The glCopyPixels fallback works and is reliable. I would like to keep it
> unless there is a good reason not to. That way we don't raise the minimum
> system requirements unnecessarily.

It is completely broken on NVIDIA (for reasons unknown, and for reasons that I don't think are worth looking into).

The only hardware that was going to be using this fallback path these days was hardware using the binary nvidia driver older than about 2003 (< GF FX 5xxx) and radeon hardware using the binary fglrx driver < Radeon 9xxx (2003 also). Every other driver supports supports either GLX_EXT_framebuffer_object or GL_MESA_copy_sub_buffer. The binary fglrx and nvidia drivers which support that hardware are, to the best of my knowledge, not even supported on modern distributions at all these days.

>
> 2. We need a configuration option for people to be able to choose the old
> rendering method.

I would prefer not to do this.

Back in the Beryl days we had countless configuration options for controlling how rendering worked internally and we had countless bug reports because people used the wrong configuration for their particular hardware. Configuration should only be exposed for user-facing functionality and not for core functionality. I think we can all agree that the existing configuration options which change how rendering work, like providing an option to sync to vblank is already totally insane. Adding an option to say "do you want to handle vsync in software or hardware" also makes no sense to the user.

Assuming that we might be running in the case of glCopyPixels OR glXSwapBuffers presents a significant divergence in codepath internally. It means we need to keep around and maintain a bunch of old vsync code which we know is flaky at best because its not handled internally in the driver. I would prefer to drop support for GL_MESA_copy_sub_buffer, but I at least decided that for now we should support hardware on the open drivers that is more than ten years old.

We will also be heavily depending on shaders and vertex buffer objects in the future, and these codepaths have higher requirements than GLX_EXT_framebuffer_object anyways.

Its time to move on from the past.

> There is a significant performance hit in (unthrottled)
> benchmark results with this change. So people need to have the option of going
> back to regional updates.

I'd like some information on this.

If it is that the performance hit comes from the fact that we're effectively always being vsync'd because we're using glXSwapBuffers / eglSwapBuffers, then I think the best course of action is to leave VSync on by default and use triple buffering so that you don't get the performance hit when you're really under load.

We're a compositor, not a benchmark. I don't think there's a good reason to maintain the old codepaths.

Revision history for this message
Achim (ach1m) wrote : Posted in a previous version of this proposal

Just FYI the intel driver is using triple buffering by default.

$ cat /var/log/Xorg.0.log | grep "Triple"
[ 15.316] (**) intel(0): Triple buffering? enabled

Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

Okay, after some discussions on IRC, here is I think what the best course of action should be:

1) Always use glXSwapBuffers if GLX_EXT_framebuffer_object is available
2) If GLX_EXT_framebuffer_object is not available fall back in the following order:
   a) Use glXSwapBuffers if damage is fullscreen
   b) Use GLX_MESA_copy_sub_buffer if available
   c) Use glCopyPixels

What this means is that if you hit 2(c) on NVIDIA, you're going to have a broken desktop. We should probably warn if we hit that case

I would much prefer to do this in future:

With VSync On:

1) Always use glXSwapBuffers if GLX_EXT_framebuffer_object is available
2) If GLX_EXT_framebuffer_object is not available fall back in the following order:
   a) Use glXSwapBuffers if damage is fullscreen
   b) Use GLX_MESA_copy_sub_buffer if available
   c) Use glCopyPixels

With VSync Off:

1) Only render to framebuffer object if plugins needed to do fullscreen postprocessing
2) Use glXSwapBuffers where we are either rendering to an fbo, or doing a fullscreen render
3) Use glCopySubBufferMESA where supported
4) Use glCopyPixels if glCopySubBufferMESA is not supported

The reason being that always using swapbuffers in the no vsync case will effectively slow down unthrottled rendering because we have to do the pipeline stall on binding the fbo. Because the user doesn't care about image perfection with vsync off, we can just use the slightly more glitchy methods.

I will rework the code however to go with the first methods

Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

As discussed on IRC, we will be dropping the glCopyPixels codepath as it is broken on all drivers not just nvidia

Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

Hi, resubmitted with the following changes:

1. Got the fallback logic under test, created an abstraction that we could use for both EGL and GLX, which removed some ifdef soup
2. Called SwapBuffers if fullscreen damage or painting to FBO
3. Added startup requirement on GLX_MESA_copy_sub_buffer / EGL_NV_post_sub_buffer OR GLX_EXT_framebuffer_object OR OpenGL ES 2.0
4. Removed EGL_BUFFER_PRESERVED call in eglSurfaceAttrib, we no longer need to do this as the framebuffer object is our main output device (incidentally , this should provide a small speed boost as there is no longer an implicit glReadPixels / glDrawPixels done inside of eglSwapBuffers : see http://www.khronos.org/registry/egl/specs/EGLTechNote0001.html)

Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Please use a more appropriate class name that doesn't contain a verb. So change:
   XYZBufferBlit
to
   XYZDoubleBuffer
(where Buffer is a noun in this case, not a verb ;)

Also missing file:

[ 26%] Building CXX object plugins/opengl/src/bufferblit/CMakeFiles/compiz_opengl_buffer_blit.dir/src/buffer-blit.cpp.o
/home/dan/bzr/compiz/tmp.swap/plugins/opengl/src/bufferblit/src/buffer-blit.cpp:4:31: fatal error: opengl/bufferblit.h: No such file or directory
compilation terminated.
make[2]: *** [plugins/opengl/src/bufferblit/CMakeFiles/compiz_opengl_buffer_blit.dir/src/buffer-blit.cpp.o] Error 1
make[1]: *** [plugins/opengl/src/bufferblit/CMakeFiles/compiz_opengl_buffer_blit.dir/all] Error 2
make[1]: *** Waiting for unfinished jobs....

review: Needs Fixing
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Please use a more appropriate class name that doesn't contain a verb. So change:
   XYZBufferBlit
to
   XYZDoubleBuffer
(where Buffer is a noun in this case, not a verb ;)

review: Needs Fixing
Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

Rename complete

3265. By Sam Spilsbury

 lp:~compiz-linaro-team/compiz/gles2

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Works well. Although it feels overcomplicated... I can't put my finger on any exact problems right now.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/opengl/CMakeLists.txt'
2--- plugins/opengl/CMakeLists.txt 2012-05-17 10:41:21 +0000
3+++ plugins/opengl/CMakeLists.txt 2012-07-06 10:07:22 +0000
4@@ -2,12 +2,17 @@
5
6 include (CompizPlugin)
7
8+set (INTERNAL_LIBRARIES
9+ compiz_opengl_double_buffer)
10+
11+add_subdirectory (src/doublebuffer)
12+
13 if (USE_GLES)
14- compiz_plugin(opengl PLUGINDEPS composite CFLAGSADD "-DUSE_GLES -std=c++0x" LIBRARIES ${OPENGLES2_LIBRARIES} INCDIRS ${OPENGLES2_INCLUDE_DIR})
15+ compiz_plugin(opengl PLUGINDEPS composite CFLAGSADD "-DUSE_GLES -std=c++0x" LIBRARIES ${OPENGLES2_LIBRARIES} ${INTERNAL_LIBRARIES} INCDIRS ${OPENGLES2_INCLUDE_DIR})
16 else (USE_GLES)
17 find_package (OpenGL)
18 if (OPENGL_FOUND)
19- compiz_plugin(opengl PLUGINDEPS composite CFLAGSADD -std=c++0x LIBRARIES ${OPENGL_gl_LIBRARY} INCDIRS ${OPENGL_INCLUDE_DIR})
20+ compiz_plugin(opengl PLUGINDEPS composite CFLAGSADD -std=c++0x LIBRARIES ${OPENGL_gl_LIBRARY} ${INTERNAL_LIBRARIES} INCDIRS ${OPENGL_INCLUDE_DIR})
21 endif (OPENGL_FOUND)
22 endif (USE_GLES)
23
24
25=== added file 'plugins/opengl/include/opengl/doublebuffer.h'
26--- plugins/opengl/include/opengl/doublebuffer.h 1970-01-01 00:00:00 +0000
27+++ plugins/opengl/include/opengl/doublebuffer.h 2012-07-06 10:07:22 +0000
28@@ -0,0 +1,31 @@
29+#ifndef _COMPIZ_OPENGL_BUFFERBLIT_H
30+#define _COMPIZ_OPENGL_BUFFERBLIT_H
31+
32+#include <core/region.h>
33+
34+namespace compiz
35+{
36+namespace opengl
37+{
38+
39+const unsigned int PaintedWithFramebufferObject = (1 << 0);
40+const unsigned int PaintedFullscreen = (1 << 1);
41+
42+class GLDoubleBufferInterface
43+{
44+ public:
45+
46+ virtual ~GLDoubleBufferInterface () {}
47+
48+ virtual void swapBuffers () const = 0;
49+ virtual bool subBufferBlitAvailable () const = 0;
50+ virtual void subBufferBlit (const CompRegion &region) const = 0;
51+};
52+
53+void blitBuffers (unsigned int flags,
54+ const CompRegion &blitRegion,
55+ GLDoubleBufferInterface &);
56+
57+}
58+}
59+#endif
60
61=== added directory 'plugins/opengl/src/doublebuffer'
62=== added file 'plugins/opengl/src/doublebuffer/CMakeLists.txt'
63--- plugins/opengl/src/doublebuffer/CMakeLists.txt 1970-01-01 00:00:00 +0000
64+++ plugins/opengl/src/doublebuffer/CMakeLists.txt 2012-07-06 10:07:22 +0000
65@@ -0,0 +1,31 @@
66+INCLUDE_DIRECTORIES (
67+ ${compiz_SOURCE_DIR}/src/logmessage/include
68+ ${CMAKE_CURRENT_SOURCE_DIR}/../../include
69+ ${CMAKE_CURRENT_SOURCE_DIR}/src
70+
71+ ${Boost_INCLUDE_DIRS}
72+)
73+
74+LINK_DIRECTORIES (${COMPIZ_LIBRARY_DIRS})
75+
76+SET(
77+ SRCS
78+ ${CMAKE_CURRENT_SOURCE_DIR}/src/double-buffer.cpp
79+)
80+
81+ADD_LIBRARY(
82+ compiz_opengl_double_buffer STATIC
83+
84+ ${SRCS}
85+)
86+
87+if (COMPIZ_BUILD_TESTING)
88+ADD_SUBDIRECTORY( ${CMAKE_CURRENT_SOURCE_DIR}/tests )
89+endif (COMPIZ_BUILD_TESTING)
90+
91+TARGET_LINK_LIBRARIES(
92+ compiz_opengl_double_buffer
93+
94+ compiz_region
95+ compiz_logmessage
96+)
97
98=== added directory 'plugins/opengl/src/doublebuffer/src'
99=== added file 'plugins/opengl/src/doublebuffer/src/double-buffer.cpp'
100--- plugins/opengl/src/doublebuffer/src/double-buffer.cpp 1970-01-01 00:00:00 +0000
101+++ plugins/opengl/src/doublebuffer/src/double-buffer.cpp 2012-07-06 10:07:22 +0000
102@@ -0,0 +1,34 @@
103+#include <iostream>
104+
105+#include <core/logmessage.h>
106+#include <opengl/doublebuffer.h>
107+
108+#include <cstdlib>
109+
110+using namespace compiz::opengl;
111+
112+char programName[] = "compiz_test_opengl_double_buffer";
113+bool debugOutput = false;
114+
115+void
116+compiz::opengl::blitBuffers (unsigned int flags,
117+ const CompRegion &tmpRegion,
118+ GLDoubleBufferInterface &blit)
119+{
120+ if (flags & (PaintedFullscreen |
121+ PaintedWithFramebufferObject))
122+ {
123+ blit.swapBuffers ();
124+ }
125+ else if (blit.subBufferBlitAvailable ())
126+ {
127+ blit.subBufferBlit (tmpRegion);
128+ }
129+ else
130+ {
131+ /* FIXME: We need to use compLogMessage here, but for some
132+ * reason it just crashes in the tests */
133+ std::cerr << "(compiz) - fatal: no back to front flip methods supported" << std::endl;
134+ abort ();
135+ }
136+}
137
138=== added directory 'plugins/opengl/src/doublebuffer/tests'
139=== added file 'plugins/opengl/src/doublebuffer/tests/CMakeLists.txt'
140--- plugins/opengl/src/doublebuffer/tests/CMakeLists.txt 1970-01-01 00:00:00 +0000
141+++ plugins/opengl/src/doublebuffer/tests/CMakeLists.txt 2012-07-06 10:07:22 +0000
142@@ -0,0 +1,24 @@
143+find_library (GMOCK_LIBRARY gmock)
144+find_library (GMOCK_MAIN_LIBRARY gmock_main)
145+
146+if (NOT GMOCK_LIBRARY OR NOT GMOCK_MAIN_LIBRARY OR NOT GTEST_FOUND)
147+ message ("Google Mock and Google Test not found - cannot build tests!")
148+ set (COMPIZ_BUILD_TESTING OFF)
149+endif (NOT GMOCK_LIBRARY OR NOT GMOCK_MAIN_LIBRARY OR NOT GTEST_FOUND)
150+
151+include_directories (${GTEST_INCLUDE_DIRS})
152+
153+link_directories (${COMPIZ_LIBRARY_DIRS})
154+
155+add_executable (compiz_test_opengl_double_buffer
156+ ${CMAKE_CURRENT_SOURCE_DIR}/test-opengl-double-buffer.cpp)
157+
158+target_link_libraries (compiz_test_opengl_double_buffer
159+ compiz_opengl_double_buffer
160+ ${GTEST_BOTH_LIBRARIES}
161+ ${GMOCK_LIBRARY}
162+ ${GMOCK_MAIN_LIBRARY}
163+ ${CMAKE_THREAD_LIBS_INIT} # Link in pthread.
164+ )
165+
166+compiz_discover_tests (compiz_test_opengl_double_buffer)
167
168=== added file 'plugins/opengl/src/doublebuffer/tests/test-opengl-double-buffer.cpp'
169--- plugins/opengl/src/doublebuffer/tests/test-opengl-double-buffer.cpp 1970-01-01 00:00:00 +0000
170+++ plugins/opengl/src/doublebuffer/tests/test-opengl-double-buffer.cpp 2012-07-06 10:07:22 +0000
171@@ -0,0 +1,91 @@
172+#include <gtest/gtest.h>
173+#include <gmock/gmock.h>
174+
175+#include <opengl/doublebuffer.h>
176+
177+using namespace compiz::opengl;
178+using testing::_;
179+using testing::StrictMock;
180+using testing::Return;
181+
182+class MockGLDoubleBuffer :
183+ public GLDoubleBufferInterface
184+{
185+ public:
186+
187+ MOCK_CONST_METHOD0 (swapBuffers, void ());
188+ MOCK_CONST_METHOD0 (subBufferBlitAvailable, bool ());
189+ MOCK_CONST_METHOD1 (subBufferBlit, void (const CompRegion &));
190+};
191+
192+class CompizOpenGLDoubleBufferTest :
193+ public ::testing::Test
194+{
195+ public:
196+
197+ MockGLDoubleBuffer mglbb;
198+ CompRegion blitRegion;
199+
200+};
201+
202+class CompizOpenGLDoubleBufferDeathTest :
203+ public CompizOpenGLDoubleBufferTest
204+{
205+};
206+
207+TEST_F(CompizOpenGLDoubleBufferTest, TestPaintedWithFBOAlwaysSwaps)
208+{
209+ EXPECT_CALL (mglbb, swapBuffers ());
210+
211+ blitBuffers (PaintedWithFramebufferObject, blitRegion, mglbb);
212+}
213+
214+TEST_F(CompizOpenGLDoubleBufferTest, TestPaintedFullscreenAlwaysSwaps)
215+{
216+ EXPECT_CALL (mglbb, swapBuffers ());
217+
218+ blitBuffers (PaintedFullscreen, blitRegion, mglbb);
219+}
220+
221+TEST_F(CompizOpenGLDoubleBufferTest, TestNoPaintedFullscreenOrFBOAlwaysBlitsSubBuffer)
222+{
223+ EXPECT_CALL (mglbb, subBufferBlitAvailable ()).WillOnce (Return (true));
224+ EXPECT_CALL (mglbb, subBufferBlit (_));
225+
226+ blitBuffers (0, blitRegion, mglbb);
227+}
228+
229+TEST_F(CompizOpenGLDoubleBufferTest, TestNoPaintedFullscreenOrFBODoesNotBlitIfNotSupported)
230+{
231+
232+}
233+
234+TEST_F(CompizOpenGLDoubleBufferTest, TestBlitExactlyWithRegionSpecified)
235+{
236+ CompRegion r1 (0, 0, 100, 100);
237+ CompRegion r2 (100, 100, 100, 100);
238+ CompRegion r3 (200, 200, 100, 100);
239+
240+ EXPECT_CALL (mglbb, subBufferBlitAvailable ()).WillRepeatedly (Return (true));
241+
242+ EXPECT_CALL (mglbb, subBufferBlit (r1));
243+ blitBuffers (0, r1, mglbb);
244+
245+ EXPECT_CALL (mglbb, subBufferBlit (r2));
246+ blitBuffers (0, r2, mglbb);
247+
248+ EXPECT_CALL (mglbb, subBufferBlit (r3));
249+ blitBuffers (0, r3, mglbb);
250+}
251+
252+TEST_F(CompizOpenGLDoubleBufferDeathTest, TestNoPaintedFullscreenOrFBODoesNotBlitIfNotSupportedAndDies)
253+{
254+ StrictMock <MockGLDoubleBuffer> mglbbStrict;
255+
256+ ON_CALL (mglbbStrict, subBufferBlitAvailable ()).WillByDefault (Return (false));
257+
258+ ASSERT_DEATH ({
259+ blitBuffers (0, blitRegion, mglbbStrict);
260+ },
261+ ".fatal.");
262+}
263
264=== modified file 'plugins/opengl/src/privates.h'
265--- plugins/opengl/src/privates.h 2012-05-26 12:52:04 +0000
266+++ plugins/opengl/src/privates.h 2012-07-06 10:07:22 +0000
267@@ -36,12 +36,77 @@
268 #include <opengl/framebufferobject.h>
269 #endif
270
271+#include <opengl/doublebuffer.h>
272+
273 #include "privatetexture.h"
274 #include "privatevertexbuffer.h"
275 #include "opengl_options.h"
276
277 extern CompOutput *targetOutput;
278
279+class BaseDoubleBuffer
280+{
281+ public:
282+
283+ BaseDoubleBuffer (Display *,
284+ const CompSize &,
285+ const boost::function <bool ()> &);
286+
287+ protected:
288+
289+ Display *mDpy;
290+ const CompSize &mSize;
291+ boost::function <bool ()> getSyncVblank;
292+};
293+
294+#ifndef USE_GLES
295+
296+class GLXDoubleBuffer :
297+ public compiz::opengl::GLDoubleBufferInterface,
298+ public BaseDoubleBuffer
299+{
300+ public:
301+
302+ GLXDoubleBuffer (Display *,
303+ const CompSize &,
304+ const boost::function <bool ()> &,
305+ Window,
306+ const boost::function <void ()> &);
307+
308+ void swapBuffers () const;
309+ bool subBufferBlitAvailable () const;
310+ void subBufferBlit (const CompRegion &region) const;
311+
312+ protected:
313+
314+ Window mOutput;
315+ boost::function <void ()> waitVSync;
316+};
317+
318+#else
319+
320+class EGLDoubleBuffer :
321+ public compiz::opengl::GLDoubleBufferInterface,
322+ public BaseDoubleBuffer
323+{
324+ public:
325+
326+ EGLDoubleBuffer (Display *,
327+ const CompSize &,
328+ const boost::function <bool ()> &,
329+ EGLSurface const &);
330+
331+ void swapBuffers () const;
332+ bool subBufferBlitAvailable () const;
333+ void subBufferBlit (const CompRegion &region) const;
334+
335+ private:
336+
337+ EGLSurface const & mSurface;
338+};
339+
340+#endif
341+
342 class GLIcon
343 {
344 public:
345@@ -118,10 +183,12 @@
346 #ifdef USE_GLES
347 EGLContext ctx;
348 EGLSurface surface;
349+ EGLDoubleBuffer bufferBlit;
350 #else
351 GLXContext ctx;
352
353 GL::GLXGetProcAddressProc getProcAddress;
354+ GLXDoubleBuffer bufferBlit;
355 #endif
356
357 GLFramebufferObject *scratchFbo;
358
359=== modified file 'plugins/opengl/src/screen.cpp'
360--- plugins/opengl/src/screen.cpp 2012-07-03 18:16:28 +0000
361+++ plugins/opengl/src/screen.cpp 2012-07-06 10:07:22 +0000
362@@ -341,8 +341,8 @@
363 return false;
364 }
365
366- // Currently we rely unconditionally on preserving the buffer contents.
367- eglSurfaceAttrib (dpy, priv->surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
368+ // Do not preserve buffer contents on swap
369+ eglSurfaceAttrib (dpy, priv->surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED);
370
371 priv->ctx = eglCreateContext (dpy, config, EGL_NO_CONTEXT, context_attribs);
372 if (priv->ctx == EGL_NO_CONTEXT)
373@@ -415,6 +415,15 @@
374 GL::postSubBuffer = (GL::EGLPostSubBufferNVProc)
375 eglGetProcAddress ("eglPostSubBufferNV");
376
377+ if (!GL::fbo &&
378+ !GL::postSubBuffer)
379+ {
380+ compLogMessage ("opengl", CompLogLevelFatal,
381+ "GL_EXT_framebuffer_object or EGL_NV_post_sub_buffer are required");
382+ screen->handleCompizEvent ("opengl", "fatal_fallback", o);
383+ return false;
384+ }
385+
386 GL::activeTexture = glActiveTexture;
387 GL::genFramebuffers = glGenFramebuffers;
388 GL::deleteFramebuffers = glDeleteFramebuffers;
389@@ -631,6 +640,16 @@
390 GL::fbo = true;
391 }
392
393+
394+ if (!GL::fbo &&
395+ !GL::copySubBuffer)
396+ {
397+ compLogMessage ("opengl", CompLogLevelFatal,
398+ "GL_EXT_framebuffer_object or GLX_MESA_copy_sub_buffer are required");
399+ screen->handleCompizEvent ("opengl", "fatal_fallback", o);
400+ return false;
401+ }
402+
403 if (strstr (glExtensions, "GL_ARB_vertex_buffer_object"))
404 {
405 GL::bindBuffer = (GL::GLBindBufferProc)
406@@ -1069,6 +1088,14 @@
407 lighting (false),
408 #ifndef USE_GLES
409 getProcAddress (0),
410+ bufferBlit (screen->dpy (), *screen,
411+ boost::bind (&PrivateGLScreen::optionGetSyncToVblank, this),
412+ cScreen->output (),
413+ boost::bind (&PrivateGLScreen::waitForVideoSync, this)),
414+ #else
415+ bufferBlit (screen->dpy (), *screen,
416+ boost::bind (&PrivateGLScreen::optionGetSyncToVblank, this),
417+ surface),
418 #endif
419 scratchFbo (NULL),
420 scratchFboBindFailed (false),
421@@ -1677,6 +1704,111 @@
422 GL::waitForVideoSync ();
423 }
424
425+BaseDoubleBuffer::BaseDoubleBuffer (Display *d, const CompSize &s,
426+ const boost::function <bool ()> &getSyncVblankFunc) :
427+ mDpy (d),
428+ mSize (s),
429+ getSyncVblank (getSyncVblankFunc)
430+{
431+}
432+
433+#ifndef USE_GLES
434+
435+GLXDoubleBuffer::GLXDoubleBuffer (Display *d,
436+ const CompSize &s,
437+ const boost::function <bool ()> &getSyncVblankFunc,
438+ Window output,
439+ const boost::function <void ()> &waitVSyncFunc) :
440+ BaseDoubleBuffer (d, s, getSyncVblankFunc),
441+ mOutput (output),
442+ waitVSync (waitVSyncFunc)
443+{
444+}
445+
446+void
447+GLXDoubleBuffer::swapBuffers () const
448+{
449+ GL::controlSwapVideoSync (getSyncVblank ());
450+ glXSwapBuffers (mDpy, mOutput);
451+}
452+
453+bool
454+GLXDoubleBuffer::subBufferBlitAvailable () const
455+{
456+ return GL::copySubBuffer ? true : false;
457+}
458+
459+void
460+GLXDoubleBuffer::subBufferBlit (const CompRegion &region) const
461+{
462+ CompRect::vector blitRects (region.rects ());
463+ int y = 0;
464+
465+ waitVSync ();
466+
467+ foreach (const CompRect &r, blitRects)
468+ {
469+ y = mSize.height () - r.y2 ();
470+
471+ (*GL::copySubBuffer) (screen->dpy (), mOutput,
472+ r.x1 (), y,
473+ r.width (),
474+ r.height ());
475+ }
476+}
477+
478+#else
479+
480+EGLDoubleBuffer::EGLDoubleBuffer (Display *d,
481+ const CompSize &s,
482+ const boost::function <bool ()> &getSyncVblankFunc,
483+ EGLSurface const & surface) :
484+ BaseDoubleBuffer (d, s, getSyncVblankFunc),
485+ mSurface (surface)
486+{
487+}
488+
489+void
490+EGLDoubleBuffer::swapBuffers () const
491+{
492+ GL::controlSwapVideoSync (getSyncVblank ());
493+
494+ eglSwapBuffers (eglGetDisplay (mDpy), mSurface);
495+ eglWaitGL ();
496+ XFlush (mDpy);
497+}
498+
499+bool
500+EGLDoubleBuffer::subBufferBlitAvailable () const
501+{
502+ return GL::postSubBuffer ? true : false;
503+}
504+
505+void
506+EGLDoubleBuffer::subBufferBlit (const CompRegion &region) const
507+{
508+ CompRect::vector blitRects (region.rects ());
509+ int y = 0;
510+
511+ GL::controlSwapVideoSync (getSyncVblank ());
512+
513+ foreach (const CompRect &r, blitRects)
514+ {
515+ y = mSize.height () - r.y2 ();
516+
517+ (*GL::postSubBuffer) (eglGetDisplay (screen->dpy ()),
518+ mSurface,
519+ r.x1 (), y,
520+ r.width (),
521+ r.height ());
522+ }
523+
524+ eglWaitGL ();
525+ XFlush (screen->dpy ());
526+}
527+
528+#endif
529+
530 void
531 PrivateGLScreen::paintOutputs (CompOutput::ptrList &outputs,
532 unsigned int mask,
533@@ -1691,11 +1823,21 @@
534 GLFramebufferObject *oldFbo = NULL;
535 bool useFbo = false;
536
537- if (!scratchFboBindFailed)
538+ /* Clear the color buffer where appropriate */
539+ if (!scratchFboBindFailed && GL::fbo)
540 {
541+ if (clearBuffers)
542+ glClear (GL_COLOR_BUFFER_BIT);
543+
544 oldFbo = scratchFbo->bind ();
545 useFbo = scratchFbo->checkStatus () && scratchFbo->tex ();
546 }
547+ else
548+ {
549+ if (clearBuffers)
550+ if (mask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)
551+ glClear (GL_COLOR_BUFFER_BIT);
552+ }
553
554 if (!useFbo && !scratchFboBindFailed)
555 {
556@@ -1721,12 +1863,6 @@
557 }
558 #endif
559
560- if (clearBuffers)
561- {
562- if (mask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)
563- glClear (GL_COLOR_BUFFER_BIT);
564- }
565-
566 CompRegion tmpRegion (region);
567
568 foreach (CompOutput *output, outputs)
569@@ -1747,11 +1883,7 @@
570 lastViewport = r;
571 }
572
573-#ifdef USE_GLES
574- if (mask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK || !GL::postSubBuffer)
575-#else
576 if (mask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)
577-#endif
578 {
579 GLMatrix identity;
580
581@@ -1796,109 +1928,18 @@
582 GLFramebufferObject::rebind (oldFbo);
583
584 // FIXME: does not work if screen dimensions exceed max texture size
585- gScreen->glPaintCompositedOutput (tmpRegion, scratchFbo, mask);
586+ gScreen->glPaintCompositedOutput (screen->region (), scratchFbo, mask);
587 }
588
589- glFlush ();
590-
591-#ifdef USE_GLES
592- if (mask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK || !GL::postSubBuffer)
593-#else
594+ unsigned int blitMask = 0;
595+
596+ if (useFbo)
597+ blitMask |= compiz::opengl::PaintedWithFramebufferObject;
598+
599 if (mask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)
600-#endif
601- {
602- /*
603- * controlSwapVideoSync is much faster than waitForVideoSync because
604- * it won't block the CPU. The waiting is offloaded to the GPU.
605- * Unfortunately it only works with glXSwapBuffers in most drivers.
606- */
607- #ifdef USE_GLES
608- Display *xdpy = screen->dpy ();
609- GL::controlSwapVideoSync (optionGetSyncToVblank ());
610- eglSwapBuffers (eglGetDisplay (xdpy), surface);
611- eglWaitGL ();
612- XFlush (xdpy);
613- #else
614- GL::controlSwapVideoSync (optionGetSyncToVblank ());
615- glXSwapBuffers (screen->dpy (), cScreen->output ());
616- #endif
617- }
618- else
619- {
620- BoxPtr pBox = const_cast <Region> (tmpRegion.handle ())->rects;
621- int nBox = const_cast <Region> (tmpRegion.handle ())->numRects;
622- int y;
623-
624- waitForVideoSync ();
625-
626- #ifdef USE_GLES
627- Display *xdpy = screen->dpy ();
628-
629- GL::controlSwapVideoSync (optionGetSyncToVblank ());
630-
631- while (nBox--)
632- {
633- y = screen->height () - pBox->y2;
634-
635- (*GL::postSubBuffer) (eglGetDisplay (xdpy), surface,
636- pBox->x1, y,
637- pBox->x2 - pBox->x1,
638- pBox->y2 - pBox->y1);
639- pBox++;
640- }
641-
642- eglWaitGL ();
643- XFlush (xdpy);
644-
645- #else
646- if (GL::copySubBuffer)
647- {
648- while (nBox--)
649- {
650- y = screen->height () - pBox->y2;
651-
652- (*GL::copySubBuffer) (screen->dpy (), cScreen->output (),
653- pBox->x1, y,
654- pBox->x2 - pBox->x1,
655- pBox->y2 - pBox->y1);
656-
657- pBox++;
658- }
659- }
660- else
661- {
662- glEnable (GL_SCISSOR_TEST);
663- glDrawBuffer (GL_FRONT);
664-
665- while (nBox--)
666- {
667- y = screen->height () - pBox->y2;
668-
669- glBitmap (0, 0, 0, 0,
670- pBox->x1 - rasterPos.x (),
671- y - rasterPos.y (),
672- NULL);
673-
674- rasterPos = CompPoint (pBox->x1, y);
675-
676- glScissor (pBox->x1, y,
677- pBox->x2 - pBox->x1,
678- pBox->y2 - pBox->y1);
679-
680- glCopyPixels (pBox->x1, y,
681- pBox->x2 - pBox->x1,
682- pBox->y2 - pBox->y1,
683- GL_COLOR);
684-
685- pBox++;
686- }
687-
688- glDrawBuffer (GL_BACK);
689- glDisable (GL_SCISSOR_TEST);
690- glFlush ();
691- }
692- #endif
693- }
694+ blitMask |= compiz::opengl::PaintedFullscreen;
695+
696+ compiz::opengl::blitBuffers (blitMask, tmpRegion, bufferBlit);
697
698 lastMask = mask;
699 }

Subscribers

People subscribed via source and target branches