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
=== modified file 'plugins/opengl/CMakeLists.txt'
--- plugins/opengl/CMakeLists.txt 2012-05-17 10:41:21 +0000
+++ plugins/opengl/CMakeLists.txt 2012-07-06 10:07:22 +0000
@@ -2,12 +2,17 @@
22
3include (CompizPlugin)3include (CompizPlugin)
44
5set (INTERNAL_LIBRARIES
6 compiz_opengl_double_buffer)
7
8add_subdirectory (src/doublebuffer)
9
5if (USE_GLES)10if (USE_GLES)
6 compiz_plugin(opengl PLUGINDEPS composite CFLAGSADD "-DUSE_GLES -std=c++0x" LIBRARIES ${OPENGLES2_LIBRARIES} INCDIRS ${OPENGLES2_INCLUDE_DIR})11 compiz_plugin(opengl PLUGINDEPS composite CFLAGSADD "-DUSE_GLES -std=c++0x" LIBRARIES ${OPENGLES2_LIBRARIES} ${INTERNAL_LIBRARIES} INCDIRS ${OPENGLES2_INCLUDE_DIR})
7else (USE_GLES)12else (USE_GLES)
8 find_package (OpenGL)13 find_package (OpenGL)
9 if (OPENGL_FOUND)14 if (OPENGL_FOUND)
10 compiz_plugin(opengl PLUGINDEPS composite CFLAGSADD -std=c++0x LIBRARIES ${OPENGL_gl_LIBRARY} INCDIRS ${OPENGL_INCLUDE_DIR})15 compiz_plugin(opengl PLUGINDEPS composite CFLAGSADD -std=c++0x LIBRARIES ${OPENGL_gl_LIBRARY} ${INTERNAL_LIBRARIES} INCDIRS ${OPENGL_INCLUDE_DIR})
11 endif (OPENGL_FOUND)16 endif (OPENGL_FOUND)
12endif (USE_GLES)17endif (USE_GLES)
1318
1419
=== added file 'plugins/opengl/include/opengl/doublebuffer.h'
--- plugins/opengl/include/opengl/doublebuffer.h 1970-01-01 00:00:00 +0000
+++ plugins/opengl/include/opengl/doublebuffer.h 2012-07-06 10:07:22 +0000
@@ -0,0 +1,31 @@
1#ifndef _COMPIZ_OPENGL_BUFFERBLIT_H
2#define _COMPIZ_OPENGL_BUFFERBLIT_H
3
4#include <core/region.h>
5
6namespace compiz
7{
8namespace opengl
9{
10
11const unsigned int PaintedWithFramebufferObject = (1 << 0);
12const unsigned int PaintedFullscreen = (1 << 1);
13
14class GLDoubleBufferInterface
15{
16 public:
17
18 virtual ~GLDoubleBufferInterface () {}
19
20 virtual void swapBuffers () const = 0;
21 virtual bool subBufferBlitAvailable () const = 0;
22 virtual void subBufferBlit (const CompRegion &region) const = 0;
23};
24
25void blitBuffers (unsigned int flags,
26 const CompRegion &blitRegion,
27 GLDoubleBufferInterface &);
28
29}
30}
31#endif
032
=== added directory 'plugins/opengl/src/doublebuffer'
=== added file 'plugins/opengl/src/doublebuffer/CMakeLists.txt'
--- plugins/opengl/src/doublebuffer/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ plugins/opengl/src/doublebuffer/CMakeLists.txt 2012-07-06 10:07:22 +0000
@@ -0,0 +1,31 @@
1INCLUDE_DIRECTORIES (
2 ${compiz_SOURCE_DIR}/src/logmessage/include
3 ${CMAKE_CURRENT_SOURCE_DIR}/../../include
4 ${CMAKE_CURRENT_SOURCE_DIR}/src
5
6 ${Boost_INCLUDE_DIRS}
7)
8
9LINK_DIRECTORIES (${COMPIZ_LIBRARY_DIRS})
10
11SET(
12 SRCS
13 ${CMAKE_CURRENT_SOURCE_DIR}/src/double-buffer.cpp
14)
15
16ADD_LIBRARY(
17 compiz_opengl_double_buffer STATIC
18
19 ${SRCS}
20)
21
22if (COMPIZ_BUILD_TESTING)
23ADD_SUBDIRECTORY( ${CMAKE_CURRENT_SOURCE_DIR}/tests )
24endif (COMPIZ_BUILD_TESTING)
25
26TARGET_LINK_LIBRARIES(
27 compiz_opengl_double_buffer
28
29 compiz_region
30 compiz_logmessage
31)
032
=== added directory 'plugins/opengl/src/doublebuffer/src'
=== added file 'plugins/opengl/src/doublebuffer/src/double-buffer.cpp'
--- plugins/opengl/src/doublebuffer/src/double-buffer.cpp 1970-01-01 00:00:00 +0000
+++ plugins/opengl/src/doublebuffer/src/double-buffer.cpp 2012-07-06 10:07:22 +0000
@@ -0,0 +1,34 @@
1#include <iostream>
2
3#include <core/logmessage.h>
4#include <opengl/doublebuffer.h>
5
6#include <cstdlib>
7
8using namespace compiz::opengl;
9
10char programName[] = "compiz_test_opengl_double_buffer";
11bool debugOutput = false;
12
13void
14compiz::opengl::blitBuffers (unsigned int flags,
15 const CompRegion &tmpRegion,
16 GLDoubleBufferInterface &blit)
17{
18 if (flags & (PaintedFullscreen |
19 PaintedWithFramebufferObject))
20 {
21 blit.swapBuffers ();
22 }
23 else if (blit.subBufferBlitAvailable ())
24 {
25 blit.subBufferBlit (tmpRegion);
26 }
27 else
28 {
29 /* FIXME: We need to use compLogMessage here, but for some
30 * reason it just crashes in the tests */
31 std::cerr << "(compiz) - fatal: no back to front flip methods supported" << std::endl;
32 abort ();
33 }
34}
035
=== added directory 'plugins/opengl/src/doublebuffer/tests'
=== added file 'plugins/opengl/src/doublebuffer/tests/CMakeLists.txt'
--- plugins/opengl/src/doublebuffer/tests/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ plugins/opengl/src/doublebuffer/tests/CMakeLists.txt 2012-07-06 10:07:22 +0000
@@ -0,0 +1,24 @@
1find_library (GMOCK_LIBRARY gmock)
2find_library (GMOCK_MAIN_LIBRARY gmock_main)
3
4if (NOT GMOCK_LIBRARY OR NOT GMOCK_MAIN_LIBRARY OR NOT GTEST_FOUND)
5 message ("Google Mock and Google Test not found - cannot build tests!")
6 set (COMPIZ_BUILD_TESTING OFF)
7endif (NOT GMOCK_LIBRARY OR NOT GMOCK_MAIN_LIBRARY OR NOT GTEST_FOUND)
8
9include_directories (${GTEST_INCLUDE_DIRS})
10
11link_directories (${COMPIZ_LIBRARY_DIRS})
12
13add_executable (compiz_test_opengl_double_buffer
14 ${CMAKE_CURRENT_SOURCE_DIR}/test-opengl-double-buffer.cpp)
15
16target_link_libraries (compiz_test_opengl_double_buffer
17 compiz_opengl_double_buffer
18 ${GTEST_BOTH_LIBRARIES}
19 ${GMOCK_LIBRARY}
20 ${GMOCK_MAIN_LIBRARY}
21 ${CMAKE_THREAD_LIBS_INIT} # Link in pthread.
22 )
23
24compiz_discover_tests (compiz_test_opengl_double_buffer)
025
=== added file 'plugins/opengl/src/doublebuffer/tests/test-opengl-double-buffer.cpp'
--- plugins/opengl/src/doublebuffer/tests/test-opengl-double-buffer.cpp 1970-01-01 00:00:00 +0000
+++ plugins/opengl/src/doublebuffer/tests/test-opengl-double-buffer.cpp 2012-07-06 10:07:22 +0000
@@ -0,0 +1,91 @@
1#include <gtest/gtest.h>
2#include <gmock/gmock.h>
3
4#include <opengl/doublebuffer.h>
5
6using namespace compiz::opengl;
7using testing::_;
8using testing::StrictMock;
9using testing::Return;
10
11class MockGLDoubleBuffer :
12 public GLDoubleBufferInterface
13{
14 public:
15
16 MOCK_CONST_METHOD0 (swapBuffers, void ());
17 MOCK_CONST_METHOD0 (subBufferBlitAvailable, bool ());
18 MOCK_CONST_METHOD1 (subBufferBlit, void (const CompRegion &));
19};
20
21class CompizOpenGLDoubleBufferTest :
22 public ::testing::Test
23{
24 public:
25
26 MockGLDoubleBuffer mglbb;
27 CompRegion blitRegion;
28
29};
30
31class CompizOpenGLDoubleBufferDeathTest :
32 public CompizOpenGLDoubleBufferTest
33{
34};
35
36TEST_F(CompizOpenGLDoubleBufferTest, TestPaintedWithFBOAlwaysSwaps)
37{
38 EXPECT_CALL (mglbb, swapBuffers ());
39
40 blitBuffers (PaintedWithFramebufferObject, blitRegion, mglbb);
41}
42
43TEST_F(CompizOpenGLDoubleBufferTest, TestPaintedFullscreenAlwaysSwaps)
44{
45 EXPECT_CALL (mglbb, swapBuffers ());
46
47 blitBuffers (PaintedFullscreen, blitRegion, mglbb);
48}
49
50TEST_F(CompizOpenGLDoubleBufferTest, TestNoPaintedFullscreenOrFBOAlwaysBlitsSubBuffer)
51{
52 EXPECT_CALL (mglbb, subBufferBlitAvailable ()).WillOnce (Return (true));
53 EXPECT_CALL (mglbb, subBufferBlit (_));
54
55 blitBuffers (0, blitRegion, mglbb);
56}
57
58TEST_F(CompizOpenGLDoubleBufferTest, TestNoPaintedFullscreenOrFBODoesNotBlitIfNotSupported)
59{
60
61}
62
63TEST_F(CompizOpenGLDoubleBufferTest, TestBlitExactlyWithRegionSpecified)
64{
65 CompRegion r1 (0, 0, 100, 100);
66 CompRegion r2 (100, 100, 100, 100);
67 CompRegion r3 (200, 200, 100, 100);
68
69 EXPECT_CALL (mglbb, subBufferBlitAvailable ()).WillRepeatedly (Return (true));
70
71 EXPECT_CALL (mglbb, subBufferBlit (r1));
72 blitBuffers (0, r1, mglbb);
73
74 EXPECT_CALL (mglbb, subBufferBlit (r2));
75 blitBuffers (0, r2, mglbb);
76
77 EXPECT_CALL (mglbb, subBufferBlit (r3));
78 blitBuffers (0, r3, mglbb);
79}
80
81TEST_F(CompizOpenGLDoubleBufferDeathTest, TestNoPaintedFullscreenOrFBODoesNotBlitIfNotSupportedAndDies)
82{
83 StrictMock <MockGLDoubleBuffer> mglbbStrict;
84
85 ON_CALL (mglbbStrict, subBufferBlitAvailable ()).WillByDefault (Return (false));
86
87 ASSERT_DEATH ({
88 blitBuffers (0, blitRegion, mglbbStrict);
89 },
90 ".fatal.");
91}
092
=== modified file 'plugins/opengl/src/privates.h'
--- plugins/opengl/src/privates.h 2012-05-26 12:52:04 +0000
+++ plugins/opengl/src/privates.h 2012-07-06 10:07:22 +0000
@@ -36,12 +36,77 @@
36#include <opengl/framebufferobject.h>36#include <opengl/framebufferobject.h>
37#endif37#endif
3838
39#include <opengl/doublebuffer.h>
40
39#include "privatetexture.h"41#include "privatetexture.h"
40#include "privatevertexbuffer.h"42#include "privatevertexbuffer.h"
41#include "opengl_options.h"43#include "opengl_options.h"
4244
43extern CompOutput *targetOutput;45extern CompOutput *targetOutput;
4446
47class BaseDoubleBuffer
48{
49 public:
50
51 BaseDoubleBuffer (Display *,
52 const CompSize &,
53 const boost::function <bool ()> &);
54
55 protected:
56
57 Display *mDpy;
58 const CompSize &mSize;
59 boost::function <bool ()> getSyncVblank;
60};
61
62#ifndef USE_GLES
63
64class GLXDoubleBuffer :
65 public compiz::opengl::GLDoubleBufferInterface,
66 public BaseDoubleBuffer
67{
68 public:
69
70 GLXDoubleBuffer (Display *,
71 const CompSize &,
72 const boost::function <bool ()> &,
73 Window,
74 const boost::function <void ()> &);
75
76 void swapBuffers () const;
77 bool subBufferBlitAvailable () const;
78 void subBufferBlit (const CompRegion &region) const;
79
80 protected:
81
82 Window mOutput;
83 boost::function <void ()> waitVSync;
84};
85
86#else
87
88class EGLDoubleBuffer :
89 public compiz::opengl::GLDoubleBufferInterface,
90 public BaseDoubleBuffer
91{
92 public:
93
94 EGLDoubleBuffer (Display *,
95 const CompSize &,
96 const boost::function <bool ()> &,
97 EGLSurface const &);
98
99 void swapBuffers () const;
100 bool subBufferBlitAvailable () const;
101 void subBufferBlit (const CompRegion &region) const;
102
103 private:
104
105 EGLSurface const & mSurface;
106};
107
108#endif
109
45class GLIcon110class GLIcon
46{111{
47 public:112 public:
@@ -118,10 +183,12 @@
118 #ifdef USE_GLES183 #ifdef USE_GLES
119 EGLContext ctx;184 EGLContext ctx;
120 EGLSurface surface;185 EGLSurface surface;
186 EGLDoubleBuffer bufferBlit;
121 #else187 #else
122 GLXContext ctx;188 GLXContext ctx;
123189
124 GL::GLXGetProcAddressProc getProcAddress;190 GL::GLXGetProcAddressProc getProcAddress;
191 GLXDoubleBuffer bufferBlit;
125 #endif192 #endif
126193
127 GLFramebufferObject *scratchFbo;194 GLFramebufferObject *scratchFbo;
128195
=== modified file 'plugins/opengl/src/screen.cpp'
--- plugins/opengl/src/screen.cpp 2012-07-03 18:16:28 +0000
+++ plugins/opengl/src/screen.cpp 2012-07-06 10:07:22 +0000
@@ -341,8 +341,8 @@
341 return false;341 return false;
342 }342 }
343343
344 // Currently we rely unconditionally on preserving the buffer contents.344 // Do not preserve buffer contents on swap
345 eglSurfaceAttrib (dpy, priv->surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);345 eglSurfaceAttrib (dpy, priv->surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED);
346346
347 priv->ctx = eglCreateContext (dpy, config, EGL_NO_CONTEXT, context_attribs);347 priv->ctx = eglCreateContext (dpy, config, EGL_NO_CONTEXT, context_attribs);
348 if (priv->ctx == EGL_NO_CONTEXT)348 if (priv->ctx == EGL_NO_CONTEXT)
@@ -415,6 +415,15 @@
415 GL::postSubBuffer = (GL::EGLPostSubBufferNVProc)415 GL::postSubBuffer = (GL::EGLPostSubBufferNVProc)
416 eglGetProcAddress ("eglPostSubBufferNV");416 eglGetProcAddress ("eglPostSubBufferNV");
417417
418 if (!GL::fbo &&
419 !GL::postSubBuffer)
420 {
421 compLogMessage ("opengl", CompLogLevelFatal,
422 "GL_EXT_framebuffer_object or EGL_NV_post_sub_buffer are required");
423 screen->handleCompizEvent ("opengl", "fatal_fallback", o);
424 return false;
425 }
426
418 GL::activeTexture = glActiveTexture;427 GL::activeTexture = glActiveTexture;
419 GL::genFramebuffers = glGenFramebuffers;428 GL::genFramebuffers = glGenFramebuffers;
420 GL::deleteFramebuffers = glDeleteFramebuffers;429 GL::deleteFramebuffers = glDeleteFramebuffers;
@@ -631,6 +640,16 @@
631 GL::fbo = true;640 GL::fbo = true;
632 }641 }
633642
643
644 if (!GL::fbo &&
645 !GL::copySubBuffer)
646 {
647 compLogMessage ("opengl", CompLogLevelFatal,
648 "GL_EXT_framebuffer_object or GLX_MESA_copy_sub_buffer are required");
649 screen->handleCompizEvent ("opengl", "fatal_fallback", o);
650 return false;
651 }
652
634 if (strstr (glExtensions, "GL_ARB_vertex_buffer_object"))653 if (strstr (glExtensions, "GL_ARB_vertex_buffer_object"))
635 {654 {
636 GL::bindBuffer = (GL::GLBindBufferProc)655 GL::bindBuffer = (GL::GLBindBufferProc)
@@ -1069,6 +1088,14 @@
1069 lighting (false),1088 lighting (false),
1070 #ifndef USE_GLES1089 #ifndef USE_GLES
1071 getProcAddress (0),1090 getProcAddress (0),
1091 bufferBlit (screen->dpy (), *screen,
1092 boost::bind (&PrivateGLScreen::optionGetSyncToVblank, this),
1093 cScreen->output (),
1094 boost::bind (&PrivateGLScreen::waitForVideoSync, this)),
1095 #else
1096 bufferBlit (screen->dpy (), *screen,
1097 boost::bind (&PrivateGLScreen::optionGetSyncToVblank, this),
1098 surface),
1072 #endif1099 #endif
1073 scratchFbo (NULL),1100 scratchFbo (NULL),
1074 scratchFboBindFailed (false),1101 scratchFboBindFailed (false),
@@ -1677,6 +1704,111 @@
1677 GL::waitForVideoSync ();1704 GL::waitForVideoSync ();
1678}1705}
16791706
1707BaseDoubleBuffer::BaseDoubleBuffer (Display *d, const CompSize &s,
1708 const boost::function <bool ()> &getSyncVblankFunc) :
1709 mDpy (d),
1710 mSize (s),
1711 getSyncVblank (getSyncVblankFunc)
1712{
1713}
1714
1715#ifndef USE_GLES
1716
1717GLXDoubleBuffer::GLXDoubleBuffer (Display *d,
1718 const CompSize &s,
1719 const boost::function <bool ()> &getSyncVblankFunc,
1720 Window output,
1721 const boost::function <void ()> &waitVSyncFunc) :
1722 BaseDoubleBuffer (d, s, getSyncVblankFunc),
1723 mOutput (output),
1724 waitVSync (waitVSyncFunc)
1725{
1726}
1727
1728void
1729GLXDoubleBuffer::swapBuffers () const
1730{
1731 GL::controlSwapVideoSync (getSyncVblank ());
1732 glXSwapBuffers (mDpy, mOutput);
1733}
1734
1735bool
1736GLXDoubleBuffer::subBufferBlitAvailable () const
1737{
1738 return GL::copySubBuffer ? true : false;
1739}
1740
1741void
1742GLXDoubleBuffer::subBufferBlit (const CompRegion &region) const
1743{
1744 CompRect::vector blitRects (region.rects ());
1745 int y = 0;
1746
1747 waitVSync ();
1748
1749 foreach (const CompRect &r, blitRects)
1750 {
1751 y = mSize.height () - r.y2 ();
1752
1753 (*GL::copySubBuffer) (screen->dpy (), mOutput,
1754 r.x1 (), y,
1755 r.width (),
1756 r.height ());
1757 }
1758}
1759
1760#else
1761
1762EGLDoubleBuffer::EGLDoubleBuffer (Display *d,
1763 const CompSize &s,
1764 const boost::function <bool ()> &getSyncVblankFunc,
1765 EGLSurface const & surface) :
1766 BaseDoubleBuffer (d, s, getSyncVblankFunc),
1767 mSurface (surface)
1768{
1769}
1770
1771void
1772EGLDoubleBuffer::swapBuffers () const
1773{
1774 GL::controlSwapVideoSync (getSyncVblank ());
1775
1776 eglSwapBuffers (eglGetDisplay (mDpy), mSurface);
1777 eglWaitGL ();
1778 XFlush (mDpy);
1779}
1780
1781bool
1782EGLDoubleBuffer::subBufferBlitAvailable () const
1783{
1784 return GL::postSubBuffer ? true : false;
1785}
1786
1787void
1788EGLDoubleBuffer::subBufferBlit (const CompRegion &region) const
1789{
1790 CompRect::vector blitRects (region.rects ());
1791 int y = 0;
1792
1793 GL::controlSwapVideoSync (getSyncVblank ());
1794
1795 foreach (const CompRect &r, blitRects)
1796 {
1797 y = mSize.height () - r.y2 ();
1798
1799 (*GL::postSubBuffer) (eglGetDisplay (screen->dpy ()),
1800 mSurface,
1801 r.x1 (), y,
1802 r.width (),
1803 r.height ());
1804 }
1805
1806 eglWaitGL ();
1807 XFlush (screen->dpy ());
1808}
1809
1810#endif
1811
1680void1812void
1681PrivateGLScreen::paintOutputs (CompOutput::ptrList &outputs,1813PrivateGLScreen::paintOutputs (CompOutput::ptrList &outputs,
1682 unsigned int mask,1814 unsigned int mask,
@@ -1691,11 +1823,21 @@
1691 GLFramebufferObject *oldFbo = NULL;1823 GLFramebufferObject *oldFbo = NULL;
1692 bool useFbo = false;1824 bool useFbo = false;
16931825
1694 if (!scratchFboBindFailed)1826 /* Clear the color buffer where appropriate */
1827 if (!scratchFboBindFailed && GL::fbo)
1695 {1828 {
1829 if (clearBuffers)
1830 glClear (GL_COLOR_BUFFER_BIT);
1831
1696 oldFbo = scratchFbo->bind ();1832 oldFbo = scratchFbo->bind ();
1697 useFbo = scratchFbo->checkStatus () && scratchFbo->tex ();1833 useFbo = scratchFbo->checkStatus () && scratchFbo->tex ();
1698 }1834 }
1835 else
1836 {
1837 if (clearBuffers)
1838 if (mask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)
1839 glClear (GL_COLOR_BUFFER_BIT);
1840 }
16991841
1700 if (!useFbo && !scratchFboBindFailed)1842 if (!useFbo && !scratchFboBindFailed)
1701 {1843 {
@@ -1721,12 +1863,6 @@
1721 }1863 }
1722#endif1864#endif
17231865
1724 if (clearBuffers)
1725 {
1726 if (mask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)
1727 glClear (GL_COLOR_BUFFER_BIT);
1728 }
1729
1730 CompRegion tmpRegion (region);1866 CompRegion tmpRegion (region);
17311867
1732 foreach (CompOutput *output, outputs)1868 foreach (CompOutput *output, outputs)
@@ -1747,11 +1883,7 @@
1747 lastViewport = r;1883 lastViewport = r;
1748 }1884 }
17491885
1750#ifdef USE_GLES
1751 if (mask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK || !GL::postSubBuffer)
1752#else
1753 if (mask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)1886 if (mask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)
1754#endif
1755 {1887 {
1756 GLMatrix identity;1888 GLMatrix identity;
17571889
@@ -1796,109 +1928,18 @@
1796 GLFramebufferObject::rebind (oldFbo);1928 GLFramebufferObject::rebind (oldFbo);
17971929
1798 // FIXME: does not work if screen dimensions exceed max texture size1930 // FIXME: does not work if screen dimensions exceed max texture size
1799 gScreen->glPaintCompositedOutput (tmpRegion, scratchFbo, mask);1931 gScreen->glPaintCompositedOutput (screen->region (), scratchFbo, mask);
1800 }1932 }
18011933
1802 glFlush ();1934 unsigned int blitMask = 0;
18031935
1804#ifdef USE_GLES1936 if (useFbo)
1805 if (mask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK || !GL::postSubBuffer)1937 blitMask |= compiz::opengl::PaintedWithFramebufferObject;
1806#else1938
1807 if (mask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)1939 if (mask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)
1808#endif1940 blitMask |= compiz::opengl::PaintedFullscreen;
1809 {1941
1810 /*1942 compiz::opengl::blitBuffers (blitMask, tmpRegion, bufferBlit);
1811 * controlSwapVideoSync is much faster than waitForVideoSync because
1812 * it won't block the CPU. The waiting is offloaded to the GPU.
1813 * Unfortunately it only works with glXSwapBuffers in most drivers.
1814 */
1815 #ifdef USE_GLES
1816 Display *xdpy = screen->dpy ();
1817 GL::controlSwapVideoSync (optionGetSyncToVblank ());
1818 eglSwapBuffers (eglGetDisplay (xdpy), surface);
1819 eglWaitGL ();
1820 XFlush (xdpy);
1821 #else
1822 GL::controlSwapVideoSync (optionGetSyncToVblank ());
1823 glXSwapBuffers (screen->dpy (), cScreen->output ());
1824 #endif
1825 }
1826 else
1827 {
1828 BoxPtr pBox = const_cast <Region> (tmpRegion.handle ())->rects;
1829 int nBox = const_cast <Region> (tmpRegion.handle ())->numRects;
1830 int y;
1831
1832 waitForVideoSync ();
1833
1834 #ifdef USE_GLES
1835 Display *xdpy = screen->dpy ();
1836
1837 GL::controlSwapVideoSync (optionGetSyncToVblank ());
1838
1839 while (nBox--)
1840 {
1841 y = screen->height () - pBox->y2;
1842
1843 (*GL::postSubBuffer) (eglGetDisplay (xdpy), surface,
1844 pBox->x1, y,
1845 pBox->x2 - pBox->x1,
1846 pBox->y2 - pBox->y1);
1847 pBox++;
1848 }
1849
1850 eglWaitGL ();
1851 XFlush (xdpy);
1852
1853 #else
1854 if (GL::copySubBuffer)
1855 {
1856 while (nBox--)
1857 {
1858 y = screen->height () - pBox->y2;
1859
1860 (*GL::copySubBuffer) (screen->dpy (), cScreen->output (),
1861 pBox->x1, y,
1862 pBox->x2 - pBox->x1,
1863 pBox->y2 - pBox->y1);
1864
1865 pBox++;
1866 }
1867 }
1868 else
1869 {
1870 glEnable (GL_SCISSOR_TEST);
1871 glDrawBuffer (GL_FRONT);
1872
1873 while (nBox--)
1874 {
1875 y = screen->height () - pBox->y2;
1876
1877 glBitmap (0, 0, 0, 0,
1878 pBox->x1 - rasterPos.x (),
1879 y - rasterPos.y (),
1880 NULL);
1881
1882 rasterPos = CompPoint (pBox->x1, y);
1883
1884 glScissor (pBox->x1, y,
1885 pBox->x2 - pBox->x1,
1886 pBox->y2 - pBox->y1);
1887
1888 glCopyPixels (pBox->x1, y,
1889 pBox->x2 - pBox->x1,
1890 pBox->y2 - pBox->y1,
1891 GL_COLOR);
1892
1893 pBox++;
1894 }
1895
1896 glDrawBuffer (GL_BACK);
1897 glDisable (GL_SCISSOR_TEST);
1898 glFlush ();
1899 }
1900 #endif
1901 }
19021943
1903 lastMask = mask;1944 lastMask = mask;
1904}1945}

Subscribers

People subscribed via source and target branches