Merge lp:~smspillaz/compiz/compiz.experimental_buffer_age_support into lp:compiz/0.9.9

Proposed by Sam Spilsbury on 2013-01-30
Status: Superseded
Proposed branch: lp:~smspillaz/compiz/compiz.experimental_buffer_age_support
Merge into: lp:compiz/0.9.9
Diff against target: 2322 lines (+1480/-79)
27 files modified
compizconfig/CMakeLists.txt (+1/-1)
plugins/animation/src/animation.cpp (+1/-1)
plugins/composite/CMakeLists.txt (+6/-1)
plugins/composite/include/composite/agedamagequery.h (+53/-0)
plugins/composite/include/composite/composite.h (+49/-14)
plugins/composite/src/backbuffertracking/CMakeLists.txt (+31/-0)
plugins/composite/src/backbuffertracking/include/backbuffertracking.h (+125/-0)
plugins/composite/src/backbuffertracking/src/backbuffertracking.cpp (+214/-0)
plugins/composite/src/backbuffertracking/tests/CMakeLists.txt (+24/-0)
plugins/composite/src/backbuffertracking/tests/test-composite-backbuffertracking.cpp (+450/-0)
plugins/composite/src/privates.h (+18/-2)
plugins/composite/src/screen.cpp (+137/-12)
plugins/kdecompat/src/kdecompat.cpp (+2/-2)
plugins/opengl/include/opengl/opengl.h (+18/-3)
plugins/opengl/src/doublebuffer/src/double-buffer.cpp (+1/-2)
plugins/opengl/src/framebufferobject.cpp (+1/-1)
plugins/opengl/src/paint.cpp (+11/-3)
plugins/opengl/src/privates.h (+30/-1)
plugins/opengl/src/screen.cpp (+290/-30)
plugins/resize/src/resize.cpp (+1/-1)
plugins/ring/src/ring.cpp (+1/-1)
plugins/scale/src/scale.cpp (+3/-1)
plugins/staticswitcher/src/staticswitcher.cpp (+1/-1)
plugins/switcher/src/switcher.cpp (+1/-1)
plugins/td/src/3d.cpp (+1/-1)
plugins/water/src/water.cpp (+9/-0)
plugins/water/src/water.h (+1/-0)
To merge this branch: bzr merge lp:~smspillaz/compiz/compiz.experimental_buffer_age_support
Reviewer Review Type Date Requested Status
Compiz Maintainers 2013-01-30 Pending
Review via email: mp+145550@code.launchpad.net

This proposal has been superseded by a proposal from 2013-02-10.

Commit message

Add support for the GLX_EXT_buffer_age extension on hardware that supports it, which should result in a nice speed-boost due to the fact that we no longer have to abuse fillrate by retaining old frame contents, and instead asking the driver how defined the current frame is.

Note: Unity gets a bit confused by this change and will cause full-screen redraws constantly unless these branches are applied to both nux and unity respectively:

https://code.launchpad.net/~smspillaz/nux/nux.experimental_fix_1091589
https://code.launchpad.net/~smspillaz/unity/unity.fix_1089811

Description of the change

Add support for the GLX_EXT_buffer_age extension on hardware that supports it, which should result in a nice speed-boost due to the fact that we no longer have to abuse fillrate by retaining old frame contents, and instead asking the driver how defined the current frame is.

To post a comment you must log in.
3553. By Sam Spilsbury on 2013-01-30

Merge lp:compiz

3554. By Sam Spilsbury on 2013-02-10

Merge lp:compiz

3555. By Sam Spilsbury on 2013-02-10

Remove useless printf

Unmerged revisions

3555. By Sam Spilsbury on 2013-02-10

Remove useless printf

3554. By Sam Spilsbury on 2013-02-10

Merge lp:compiz

3553. By Sam Spilsbury on 2013-01-30

Merge lp:compiz

3552. By Sam Spilsbury on 2013-01-04

Fix warnings and compile errors on clang and gles

3551. By Sam Spilsbury on 2013-01-03

Merge lp:compiz

3550. By Sam Spilsbury on 2013-01-03

Add test to indicate the new behaviour of getDamageForAge when adding additional
damage regions

3549. By Sam Spilsbury on 2013-01-02

Added missing func

3548. By Sam Spilsbury on 2013-01-02

Apply other necessary changes, revert a change that didn't belong here

3547. By Sam Spilsbury on 2013-01-02

Allow plugins to have their own FrameRosters in core - have a callback
to determine whether or not a particular piece of damage should be tracked.

This is necessary for plugins that need to increase damage regions upon
incoming damage from older frames, but don't want to feedback on that
damage (such as the blur plugin).

Also fixed some potential overdraw problems with
PAINT_WINDOW_NO_CORE_INSTANCE_MASK

3546. By Sam Spilsbury on 2013-01-01

Switch to stack allocation again, make the tests pass

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'compizconfig/CMakeLists.txt'
2--- compizconfig/CMakeLists.txt 2012-09-12 08:35:51 +0000
3+++ compizconfig/CMakeLists.txt 2013-01-30 08:46:22 +0000
4@@ -7,7 +7,7 @@
5 option (USE_GCONF "Enable legacy GNOME 2.x option integration with GConf" ON)
6
7 add_subdirectory (libcompizconfig)
8-add_subdirectory (compizconfig-python)
9+#add_subdirectory (compizconfig-python)
10 add_subdirectory (integration)
11 add_subdirectory (ccsm)
12
13
14=== modified file 'plugins/animation/src/animation.cpp'
15--- plugins/animation/src/animation.cpp 2013-01-11 08:28:51 +0000
16+++ plugins/animation/src/animation.cpp 2013-01-30 08:46:22 +0000
17@@ -1617,7 +1617,7 @@
18 // Is this the first glPaint call this round
19 // without the mask PAINT_WINDOW_OCCLUSION_DETECTION_MASK?
20 if (mPAScreen->mStartingNewPaintRound &&
21- !(mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK))
22+ !(mask & PAINT_WINDOW_NO_DRAW_MASKS))
23 {
24 mPAScreen->mStartingNewPaintRound = false;
25
26
27=== modified file 'plugins/composite/CMakeLists.txt'
28--- plugins/composite/CMakeLists.txt 2012-09-25 01:15:36 +0000
29+++ plugins/composite/CMakeLists.txt 2013-01-30 08:46:22 +0000
30@@ -2,9 +2,14 @@
31
32 include (CompizPlugin)
33
34+include_directories (${CMAKE_CURRENT_SOURCE_DIR}/include)
35 include_directories (${CMAKE_CURRENT_SOURCE_DIR}/src/pixmapbinding/include)
36+include_directories (${CMAKE_CURRENT_SOURCE_DIR}/src/backbuffertracking/include)
37+
38 link_directories (${CMAKE_CURRENT_BINARY_DIR}/src/pixmapbinding)
39+link_directories (${CMAKE_CURRENT_BINARY_DIR}/src/backbuffertracking)
40
41-compiz_plugin (composite LIBRARIES compiz_composite_pixmapbinding)
42+compiz_plugin (composite LIBRARIES compiz_composite_pixmapbinding compiz_composite_backbuffertracking)
43
44 add_subdirectory (src/pixmapbinding)
45+add_subdirectory (src/backbuffertracking)
46
47=== added file 'plugins/composite/include/composite/agedamagequery.h'
48--- plugins/composite/include/composite/agedamagequery.h 1970-01-01 00:00:00 +0000
49+++ plugins/composite/include/composite/agedamagequery.h 2013-01-30 08:46:22 +0000
50@@ -0,0 +1,53 @@
51+/*
52+ * Compiz, composite plugin, GLX_EXT_buffer_age logic
53+ *
54+ * Copyright (c) 2012 Sam Spilsbury
55+ * Authors: Sam Spilsbury <smspillaz@gmail.com>
56+ *
57+ * Permission is hereby granted, free of charge, to any person obtaining a
58+ * copy of this software and associated documentation files (the "Software"),
59+ * to deal in the Software without restriction, including without limitation
60+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
61+ * and/or sell copies of the Software, and to permit persons to whom the
62+ * Software is furnished to do so, subject to the following conditions:
63+ *
64+ * The above copyright notice and this permission notice shall be included in
65+ * all copies or substantial portions of the Software.
66+ *
67+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
68+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
69+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
70+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
71+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
72+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
73+ * DEALINGS IN THE SOFTWARE.
74+ */
75+#ifndef _COMPIZ_COMPOSITE_AGEDAMAGEQUERY_H
76+#define _COMPIZ_COMPOSITE_AGEDAMAGEQUERY_H
77+
78+#include <boost/shared_ptr.hpp>
79+#include <core/region.h>
80+
81+namespace compiz
82+{
83+namespace composite
84+{
85+namespace buffertracking
86+{
87+class AgeDamageQuery
88+{
89+ public:
90+
91+ typedef boost::shared_ptr <AgeDamageQuery> Ptr;
92+ typedef boost::function <bool (const CompRegion &)> AreaShouldBeMarkedDirty;
93+
94+ virtual ~AgeDamageQuery () {}
95+ virtual CompRegion damageForFrameAge (unsigned int) = 0;
96+ virtual const CompRegion & currentFrameDamage () = 0;
97+};
98+}
99+}
100+}
101+
102+#endif
103+
104
105=== modified file 'plugins/composite/include/composite/composite.h'
106--- plugins/composite/include/composite/composite.h 2012-10-16 05:11:10 +0000
107+++ plugins/composite/include/composite/composite.h 2013-01-30 08:46:22 +0000
108@@ -30,7 +30,7 @@
109
110 #include <X11/extensions/Xcomposite.h>
111
112-#define COMPIZ_COMPOSITE_ABI 5
113+#define COMPIZ_COMPOSITE_ABI 6
114
115 #include "core/pluginclasshandler.h"
116 #include "core/timer.h"
117@@ -38,6 +38,8 @@
118 #include "core/screen.h"
119 #include "core/wrapsystem.h"
120
121+#include "composite/agedamagequery.h"
122+
123 #define COMPOSITE_SCREEN_DAMAGE_PENDING_MASK (1 << 0)
124 #define COMPOSITE_SCREEN_DAMAGE_REGION_MASK (1 << 1)
125 #define COMPOSITE_SCREEN_DAMAGE_ALL_MASK (1 << 2)
126@@ -98,18 +100,19 @@
127 namespace composite
128 {
129 class PaintHandler {
130-public:
131- virtual ~PaintHandler () {};
132-
133- virtual void paintOutputs (CompOutput::ptrList &outputs,
134- unsigned int mask,
135- const CompRegion &region) = 0;
136-
137- virtual bool hasVSync () { return false; };
138- virtual bool requiredForcedRefreshRate () { return false; };
139-
140- virtual void prepareDrawing () {};
141- virtual bool compositingActive () { return false; };
142+ public:
143+ virtual ~PaintHandler () {};
144+
145+ virtual void paintOutputs (CompOutput::ptrList &outputs,
146+ unsigned int mask,
147+ const CompRegion &region) = 0;
148+
149+ virtual bool hasVSync () { return false; };
150+ virtual bool requiredForcedRefreshRate () { return false; };
151+
152+ virtual void prepareDrawing () {};
153+ virtual bool compositingActive () { return false; };
154+ virtual unsigned int getFrameAge () { return 1; }
155 };
156 }
157 }
158@@ -173,12 +176,19 @@
159 * Hookable function to damage regions directly
160 */
161 virtual void damageRegion (const CompRegion &r);
162+
163+ /**
164+ * Hookable function to notify plugins that the last damage
165+ * event for this frame has been received, and all further damage
166+ * events will be for the next frame
167+ */
168+ virtual void damageCutoff ();
169 };
170
171 extern template class PluginClassHandler<CompositeScreen, CompScreen, COMPIZ_COMPOSITE_ABI>;
172
173 class CompositeScreen :
174- public WrapableHandler<CompositeScreenInterface, 7>,
175+ public WrapableHandler<CompositeScreenInterface, 8>,
176 public PluginClassHandler<CompositeScreen, CompScreen, COMPIZ_COMPOSITE_ABI>,
177 public CompOption::Class
178 {
179@@ -203,6 +213,24 @@
180 void damageScreen ();
181
182 void damagePending ();
183+
184+ /**
185+ * Causes the damage that was recorded on N - 1 number of
186+ * frames ago to be added to the current frame, applied
187+ * culmulatively. An age of "zero" means that the entire frame
188+ * is considered undefined and must be completely repaired,
189+ * wheras an age of 1 means that this frame is the same as the
190+ * last frame, so no damage is required.
191+ */
192+ void applyDamageForFrameAge (unsigned int);
193+ unsigned int getFrameAge ();
194+ void addOverdrawDamageRegion (const CompRegion &);
195+
196+ typedef compiz::composite::buffertracking::AgeDamageQuery DamageQuery;
197+ typedef DamageQuery::AreaShouldBeMarkedDirty AreaShouldBeMarkedDirty;
198+
199+ DamageQuery::Ptr
200+ getDamageQuery (const AreaShouldBeMarkedDirty &callback);
201
202
203 unsigned int damageMask ();
204@@ -248,6 +276,7 @@
205 * event loop
206 */
207 WRAPABLE_HND (6, CompositeScreenInterface, void, damageRegion, const CompRegion &);
208+ WRAPABLE_HND (7, CompositeScreenInterface, void, damageCutoff);
209
210 friend class PrivateCompositeDisplay;
211
212@@ -310,6 +339,12 @@
213 */
214 #define PAINT_WINDOW_BLEND_MASK (1 << 19)
215
216+/**
217+ * flags that would indicate the window is never actually drawn
218+ */
219+#define PAINT_WINDOW_NO_DRAW_MASKS (PAINT_WINDOW_OCCLUSION_DETECTION_MASK | \
220+ PAINT_WINDOW_NO_CORE_INSTANCE_MASK)
221+
222 class CompositeWindowInterface;
223 extern template class WrapableInterface<CompositeWindow, CompositeWindowInterface>;
224
225
226=== added directory 'plugins/composite/src/backbuffertracking'
227=== added file 'plugins/composite/src/backbuffertracking/CMakeLists.txt'
228--- plugins/composite/src/backbuffertracking/CMakeLists.txt 1970-01-01 00:00:00 +0000
229+++ plugins/composite/src/backbuffertracking/CMakeLists.txt 2013-01-30 08:46:22 +0000
230@@ -0,0 +1,31 @@
231+INCLUDE_DIRECTORIES (
232+ ${CMAKE_CURRENT_SOURCE_DIR}/../../include
233+ ${CMAKE_CURRENT_SOURCE_DIR}/include
234+ ${CMAKE_CURRENT_SOURCE_DIR}/src
235+
236+ ${Boost_INCLUDE_DIRS}
237+)
238+
239+LINK_DIRECTORIES (${COMPIZ_LIBRARY_DIRS})
240+
241+SET(
242+ SRCS
243+ ${CMAKE_CURRENT_SOURCE_DIR}/src/backbuffertracking.cpp
244+)
245+
246+ADD_LIBRARY(
247+ compiz_composite_backbuffertracking STATIC
248+
249+ ${SRCS}
250+)
251+
252+if (COMPIZ_BUILD_TESTING)
253+ADD_SUBDIRECTORY( ${CMAKE_CURRENT_SOURCE_DIR}/tests )
254+endif (COMPIZ_BUILD_TESTING)
255+
256+TARGET_LINK_LIBRARIES(
257+ compiz_composite_backbuffertracking
258+
259+ compiz_size
260+ compiz_core
261+)
262
263=== added directory 'plugins/composite/src/backbuffertracking/include'
264=== added file 'plugins/composite/src/backbuffertracking/include/backbuffertracking.h'
265--- plugins/composite/src/backbuffertracking/include/backbuffertracking.h 1970-01-01 00:00:00 +0000
266+++ plugins/composite/src/backbuffertracking/include/backbuffertracking.h 2013-01-30 08:46:22 +0000
267@@ -0,0 +1,125 @@
268+/*
269+ * Compiz, composite plugin, GLX_EXT_buffer_age logic
270+ *
271+ * Copyright (c) 2012 Sam Spilsbury
272+ * Authors: Sam Spilsbury <smspillaz@gmail.com>
273+ *
274+ * Permission is hereby granted, free of charge, to any person obtaining a
275+ * copy of this software and associated documentation files (the "Software"),
276+ * to deal in the Software without restriction, including without limitation
277+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
278+ * and/or sell copies of the Software, and to permit persons to whom the
279+ * Software is furnished to do so, subject to the following conditions:
280+ *
281+ * The above copyright notice and this permission notice shall be included in
282+ * all copies or substantial portions of the Software.
283+ *
284+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
285+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
286+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
287+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
288+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
289+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
290+ * DEALINGS IN THE SOFTWARE.
291+ */
292+#ifndef _COMPIZ_COMPOSITE_BACKBUFFERTRACKING_H
293+#define _COMPIZ_COMPOSITE_BACKBUFFERTRACKING_H
294+
295+#include <memory>
296+#include <boost/noncopyable.hpp>
297+#include <boost/shared_ptr.hpp>
298+#include <boost/weak_ptr.hpp>
299+#include <boost/function.hpp>
300+
301+#include <composite/agedamagequery.h>
302+
303+class CompSize;
304+class CompRegion;
305+
306+namespace compiz
307+{
308+namespace composite
309+{
310+namespace buffertracking
311+{
312+class DamageAgeTracking
313+{
314+ public:
315+
316+ virtual ~DamageAgeTracking () {};
317+ virtual void dirtyAreaOnCurrentFrame (const CompRegion &) = 0;
318+ virtual void overdrawRegionOnPaintingFrame (const CompRegion &) = 0;
319+ virtual void subtractObscuredArea (const CompRegion &) = 0;
320+ virtual void incrementFrameAges () = 0;
321+};
322+
323+class AgeingDamageBufferObserver
324+{
325+ public:
326+
327+ virtual ~AgeingDamageBufferObserver () {};
328+ virtual void observe (DamageAgeTracking &damageAgeTracker) = 0;
329+ virtual void unobserve (DamageAgeTracking &damageAgeTracker) = 0;
330+};
331+
332+class AgeingDamageBuffers :
333+ public AgeingDamageBufferObserver,
334+ boost::noncopyable
335+{
336+ public:
337+
338+ AgeingDamageBuffers ();
339+
340+ void observe (DamageAgeTracking &damageAgeTracker);
341+ void unobserve (DamageAgeTracking &damageAgeTracker);
342+ void incrementAges ();
343+ void markAreaDirty (const CompRegion &reg);
344+ void markAreaDirtyOnLastFrame (const CompRegion &reg);
345+ void subtractObscuredArea (const CompRegion &reg);
346+
347+ private:
348+
349+ class Private;
350+ std::auto_ptr <Private> priv;
351+};
352+
353+class FrameRoster :
354+ public DamageAgeTracking,
355+ public AgeDamageQuery,
356+ boost::noncopyable
357+{
358+ public:
359+
360+ typedef AgeDamageQuery::AreaShouldBeMarkedDirty AreaShouldBeMarkedDirty;
361+ typedef boost::shared_ptr <FrameRoster> Ptr;
362+
363+ FrameRoster (const CompSize &size,
364+ AgeingDamageBufferObserver &tracker,
365+ const AreaShouldBeMarkedDirty &shouldMarkDirty);
366+
367+ ~FrameRoster ();
368+
369+ void dirtyAreaOnCurrentFrame (const CompRegion &);
370+ void overdrawRegionOnPaintingFrame (const CompRegion &);
371+ void subtractObscuredArea (const CompRegion &);
372+ void incrementFrameAges ();
373+ CompRegion damageForFrameAge (unsigned int);
374+ const CompRegion & currentFrameDamage ();
375+
376+ class Private;
377+ std::auto_ptr <Private> priv;
378+
379+ static const unsigned int NUM_TRACKED_FRAMES = 10;
380+
381+ static
382+ FrameRoster::Ptr create (const CompSize &size,
383+
384+ const AreaShouldBeMarkedDirty &shouldMarkDirty);
385+
386+ private:
387+
388+};
389+} // namespace buffertracking
390+} // namespace composite
391+} // namespace compiz
392+#endif
393
394=== added directory 'plugins/composite/src/backbuffertracking/src'
395=== added file 'plugins/composite/src/backbuffertracking/src/backbuffertracking.cpp'
396--- plugins/composite/src/backbuffertracking/src/backbuffertracking.cpp 1970-01-01 00:00:00 +0000
397+++ plugins/composite/src/backbuffertracking/src/backbuffertracking.cpp 2013-01-30 08:46:22 +0000
398@@ -0,0 +1,214 @@
399+/*
400+ * Compiz, composite plugin, GLX_EXT_buffer_age logic
401+ *
402+ * Copyright (c) 2012 Sam Spilsbury
403+ * Authors: Sam Spilsbury <smspillaz@gmail.com>
404+ *
405+ * Permission is hereby granted, free of charge, to any person obtaining a
406+ * copy of this software and associated documentation files (the "Software"),
407+ * to deal in the Software without restriction, including without limitation
408+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
409+ * and/or sell copies of the Software, and to permit persons to whom the
410+ * Software is furnished to do so, subject to the following conditions:
411+ *
412+ * The above copyright notice and this permission notice shall be included in
413+ * all copies or substantial portions of the Software.
414+ *
415+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
416+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
417+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
418+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
419+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
420+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
421+ * DEALINGS IN THE SOFTWARE.
422+ */
423+#include <deque>
424+#include <core/size.h>
425+#include <core/region.h>
426+#include "backbuffertracking.h"
427+#include <cstdio>
428+
429+namespace bt = compiz::composite::buffertracking;
430+
431+class bt::FrameRoster::Private
432+{
433+ public:
434+
435+ Private (const CompSize &size,
436+ bt::AgeingDamageBufferObserver &observer,
437+ const bt::FrameRoster::AreaShouldBeMarkedDirty &shouldBeMarkedDirty) :
438+ screenSize (size),
439+ observer (observer),
440+ shouldBeMarkedDirty (shouldBeMarkedDirty),
441+ oldFrames (1)
442+ {
443+ }
444+
445+ CompSize screenSize;
446+ bt::AgeingDamageBufferObserver &observer;
447+ bt::FrameRoster::AreaShouldBeMarkedDirty shouldBeMarkedDirty;
448+ std::deque <CompRegion> oldFrames;
449+};
450+
451+bt::FrameRoster::FrameRoster (const CompSize &size,
452+ bt::AgeingDamageBufferObserver &tracker,
453+ const AreaShouldBeMarkedDirty &shouldBeMarkedDirty) :
454+ priv (new bt::FrameRoster::Private (size,
455+ tracker,
456+ shouldBeMarkedDirty))
457+{
458+ priv->observer.observe (*this);
459+}
460+
461+bt::FrameRoster::~FrameRoster ()
462+{
463+ priv->observer.unobserve (*this);
464+}
465+
466+CompRegion
467+bt::FrameRoster::damageForFrameAge (unsigned int age)
468+{
469+ if (!age)
470+ return CompRegion (0, 0,
471+ priv->screenSize.width (),
472+ priv->screenSize.height ());
473+
474+ if (age >= priv->oldFrames.size ())
475+ return CompRegion (0, 0,
476+ priv->screenSize.width (),
477+ priv->screenSize.height ());
478+
479+ CompRegion accumulatedDamage;
480+
481+ while (age--)
482+ {
483+ unsigned int frameNum = (priv->oldFrames.size () - age) - 1;
484+ accumulatedDamage += priv->oldFrames[frameNum];
485+ }
486+
487+ return accumulatedDamage;
488+}
489+
490+void
491+bt::FrameRoster::dirtyAreaOnCurrentFrame (const CompRegion &r)
492+{
493+ if (priv->shouldBeMarkedDirty (r))
494+ (*priv->oldFrames.rbegin ()) += r;
495+}
496+
497+void
498+bt::FrameRoster::subtractObscuredArea (const CompRegion &r)
499+{
500+ (*priv->oldFrames.rbegin ()) -= r;
501+}
502+
503+void
504+bt::FrameRoster::overdrawRegionOnPaintingFrame (const CompRegion &r)
505+{
506+ assert (priv->oldFrames.size () > 1);
507+ std::deque <CompRegion>::reverse_iterator it = priv->oldFrames.rbegin ();
508+ ++it;
509+ (*it) += r;
510+}
511+
512+void
513+bt::FrameRoster::incrementFrameAges ()
514+{
515+ priv->oldFrames.push_back (CompRegion ());
516+
517+ /* Get rid of old frames */
518+ if (priv->oldFrames.size () > NUM_TRACKED_FRAMES)
519+ priv->oldFrames.pop_front ();
520+}
521+
522+const CompRegion &
523+bt::FrameRoster::currentFrameDamage ()
524+{
525+ return *priv->oldFrames.rbegin ();
526+}
527+
528+class bt::AgeingDamageBuffers::Private
529+{
530+ public:
531+
532+ std::vector <bt::DamageAgeTracking *> damageAgeTrackers;
533+};
534+
535+bt::AgeingDamageBuffers::AgeingDamageBuffers () :
536+ priv (new bt::AgeingDamageBuffers::Private ())
537+{
538+}
539+
540+void
541+bt::AgeingDamageBuffers::observe (bt::DamageAgeTracking &damageAgeTracker)
542+{
543+ priv->damageAgeTrackers.push_back (&damageAgeTracker);
544+}
545+
546+void
547+bt::AgeingDamageBuffers::unobserve (bt::DamageAgeTracking &damageAgeTracker)
548+{
549+ std::vector <bt::DamageAgeTracking *>::iterator it =
550+ std::find (priv->damageAgeTrackers.begin (),
551+ priv->damageAgeTrackers.end (),
552+ &damageAgeTracker);
553+
554+ if (it != priv->damageAgeTrackers.end ())
555+ priv->damageAgeTrackers.erase (it);
556+}
557+
558+void
559+bt::AgeingDamageBuffers::incrementAges ()
560+{
561+ for (std::vector <bt::DamageAgeTracking *>::iterator it =
562+ priv->damageAgeTrackers.begin ();
563+ it != priv->damageAgeTrackers.end ();
564+ ++it)
565+ {
566+ bt::DamageAgeTracking *tracker = *it;
567+
568+ tracker->incrementFrameAges ();
569+ }
570+}
571+
572+void
573+bt::AgeingDamageBuffers::markAreaDirty (const CompRegion &reg)
574+{
575+ for (std::vector <bt::DamageAgeTracking *>::iterator it =
576+ priv->damageAgeTrackers.begin ();
577+ it != priv->damageAgeTrackers.end ();
578+ ++it)
579+ {
580+ bt::DamageAgeTracking *tracker = *it;
581+
582+ tracker->dirtyAreaOnCurrentFrame (reg);
583+ }
584+}
585+
586+void
587+bt::AgeingDamageBuffers::subtractObscuredArea (const CompRegion &reg)
588+{
589+ for (std::vector <bt::DamageAgeTracking *>::iterator it =
590+ priv->damageAgeTrackers.begin ();
591+ it != priv->damageAgeTrackers.end ();
592+ ++it)
593+ {
594+ bt::DamageAgeTracking *tracker = *it;
595+
596+ tracker->subtractObscuredArea (reg);
597+ }
598+}
599+
600+void
601+bt::AgeingDamageBuffers::markAreaDirtyOnLastFrame (const CompRegion &reg)
602+{
603+ for (std::vector <bt::DamageAgeTracking *>::iterator it =
604+ priv->damageAgeTrackers.begin ();
605+ it != priv->damageAgeTrackers.end ();
606+ ++it)
607+ {
608+ bt::DamageAgeTracking *tracker = *it;
609+
610+ tracker->overdrawRegionOnPaintingFrame (reg);
611+ }
612+}
613
614=== added directory 'plugins/composite/src/backbuffertracking/tests'
615=== added file 'plugins/composite/src/backbuffertracking/tests/CMakeLists.txt'
616--- plugins/composite/src/backbuffertracking/tests/CMakeLists.txt 1970-01-01 00:00:00 +0000
617+++ plugins/composite/src/backbuffertracking/tests/CMakeLists.txt 2013-01-30 08:46:22 +0000
618@@ -0,0 +1,24 @@
619+find_library (GMOCK_LIBRARY gmock)
620+find_library (GMOCK_MAIN_LIBRARY gmock_main)
621+
622+if (NOT GMOCK_LIBRARY OR NOT GMOCK_MAIN_LIBRARY OR NOT GTEST_FOUND)
623+ message ("Google Mock and Google Test not found - cannot build tests!")
624+ set (COMPIZ_BUILD_TESTING OFF)
625+endif (NOT GMOCK_LIBRARY OR NOT GMOCK_MAIN_LIBRARY OR NOT GTEST_FOUND)
626+
627+include_directories (${GTEST_INCLUDE_DIRS})
628+
629+link_directories (${COMPIZ_LIBRARY_DIRS})
630+
631+add_executable (compiz_test_composite_backbuffertracking
632+ ${CMAKE_CURRENT_SOURCE_DIR}/test-composite-backbuffertracking.cpp)
633+
634+target_link_libraries (compiz_test_composite_backbuffertracking
635+ compiz_composite_backbuffertracking
636+ ${GTEST_BOTH_LIBRARIES}
637+ ${GMOCK_LIBRARY}
638+ ${GMOCK_MAIN_LIBRARY}
639+ ${CMAKE_THREAD_LIBS_INIT} # Link in pthread.
640+ )
641+
642+compiz_discover_tests (compiz_test_composite_backbuffertracking COVERAGE compiz_composite_backbuffertracking)
643
644=== added file 'plugins/composite/src/backbuffertracking/tests/test-composite-backbuffertracking.cpp'
645--- plugins/composite/src/backbuffertracking/tests/test-composite-backbuffertracking.cpp 1970-01-01 00:00:00 +0000
646+++ plugins/composite/src/backbuffertracking/tests/test-composite-backbuffertracking.cpp 2013-01-30 08:46:22 +0000
647@@ -0,0 +1,450 @@
648+/*
649+ * Compiz, composite plugin, GLX_EXT_buffer_age logic
650+ *
651+ * Copyright (c) 2012 Sam Spilsbury
652+ * Authors: Sam Spilsbury <smspillaz@gmail.com>
653+ *
654+ * Permission is hereby granted, free of charge, to any person obtaining a
655+ * copy of this software and associated documentation files (the "Software"),
656+ * to deal in the Software without restriction, including without limitation
657+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
658+ * and/or sell copies of the Software, and to permit persons to whom the
659+ * Software is furnished to do so, subject to the following conditions:
660+ *
661+ * The above copyright notice and this permission notice shall be included in
662+ * all copies or substantial portions of the Software.
663+ *
664+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
665+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
666+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
667+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
668+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
669+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
670+ * DEALINGS IN THE SOFTWARE.
671+ */
672+#include <boost/bind.hpp>
673+
674+#include <gtest/gtest.h>
675+#include <gmock/gmock.h>
676+
677+#include <core/region.h>
678+#include <core/size.h>
679+
680+#include "backbuffertracking.h"
681+
682+using ::testing::NiceMock;
683+using ::testing::_;
684+using ::testing::AtLeast;
685+
686+namespace bt = compiz::composite::buffertracking;
687+
688+namespace
689+{
690+class MockAgeingDamageBufferObserver :
691+ public bt::AgeingDamageBufferObserver
692+{
693+ public:
694+
695+ MOCK_METHOD1 (observe, void (bt::DamageAgeTracking &));
696+ MOCK_METHOD1 (unobserve, void (bt::DamageAgeTracking &));
697+};
698+
699+bool alwaysTrackDamage (const CompRegion &)
700+{
701+ return true;
702+}
703+
704+
705+class BackbufferTracking :
706+ public ::testing::Test
707+{
708+ public:
709+
710+ BackbufferTracking () :
711+ screen (1000, 1000),
712+ roster ()
713+ {
714+ }
715+
716+ virtual void SetUp ()
717+ {
718+ SetupRoster ();
719+ }
720+
721+ virtual void SetupRoster ()
722+ {
723+ roster.reset (new bt::FrameRoster (screen,
724+ niceTracker,
725+ boost::bind (alwaysTrackDamage,
726+ _1)));
727+ }
728+
729+ protected:
730+
731+ CompSize screen;
732+ NiceMock <MockAgeingDamageBufferObserver> niceTracker;
733+ bt::FrameRoster::Ptr roster;
734+};
735+
736+class BackbufferTrackingCallbacks :
737+ public BackbufferTracking
738+{
739+ public:
740+
741+ BackbufferTrackingCallbacks () :
742+ shouldDamage (false)
743+ {
744+ }
745+
746+ protected:
747+
748+ void allowDamage (bool allow)
749+ {
750+ shouldDamage = allow;
751+ }
752+
753+ private:
754+
755+ virtual void SetupRoster ()
756+ {
757+ roster.reset (new bt::FrameRoster (screen,
758+ niceTracker,
759+ boost::bind (&BackbufferTrackingCallbacks::shouldDamageCallback,
760+ this, _1)));
761+ }
762+
763+ bool shouldDamageCallback (const CompRegion &)
764+ {
765+ return shouldDamage;
766+ }
767+
768+ bool shouldDamage;
769+};
770+}
771+
772+std::ostream &
773+operator<< (std::ostream &os, const CompRegion &reg)
774+{
775+ os << "Region with Bounding Rectangle : " <<
776+ reg.boundingRect ().x () << " " <<
777+ reg.boundingRect ().y () << " " <<
778+ reg.boundingRect ().width () << " " <<
779+ reg.boundingRect ().height () << std::endl;
780+ CompRect::vector rects (reg.rects ());
781+ for (CompRect::vector::iterator it = rects.begin ();
782+ it != rects.end ();
783+ it++)
784+ os << " - subrectangle: " <<
785+ (*it).x () << " " <<
786+ (*it).y () << " " <<
787+ (*it).width () << " " <<
788+ (*it).height () << " " << std::endl;
789+
790+ return os;
791+}
792+
793+TEST (BackbufferTrackingConstruction, CreateAddsToObserverList)
794+{
795+ MockAgeingDamageBufferObserver mockAgeingDamageBufferObserver;
796+
797+ /* We can't verify the argument here,
798+ * but we can verify the function call */
799+ EXPECT_CALL (mockAgeingDamageBufferObserver, observe (_));
800+ EXPECT_CALL (mockAgeingDamageBufferObserver, unobserve (_)).Times (AtLeast (0));
801+ bt::FrameRoster roster (CompSize (),
802+ mockAgeingDamageBufferObserver,
803+ boost::bind (alwaysTrackDamage, _1));
804+}
805+
806+TEST (BackbufferTrackingConstruction, DestroyRemovesFromObserverList)
807+{
808+ MockAgeingDamageBufferObserver mockAgeingDamageBufferObserver;
809+
810+ /* We can't verify the argument here,
811+ * but we can verify the function call */
812+ EXPECT_CALL (mockAgeingDamageBufferObserver, observe (_)).Times (AtLeast (0));
813+ EXPECT_CALL (mockAgeingDamageBufferObserver, unobserve (_));
814+ bt::FrameRoster roster (CompSize (),
815+ mockAgeingDamageBufferObserver,
816+ boost::bind (alwaysTrackDamage, _1));
817+}
818+
819+TEST_F (BackbufferTrackingCallbacks, TrackIntoCurrentIfCallbackTrue)
820+{
821+ allowDamage (true);
822+ CompRegion damage (100, 100, 100, 100);
823+ roster->dirtyAreaOnCurrentFrame (damage);
824+ EXPECT_EQ (damage, roster->currentFrameDamage ());
825+}
826+
827+TEST_F (BackbufferTrackingCallbacks, NoTrackIntoCurrentIfCallbackFalse)
828+{
829+ allowDamage (false);
830+ CompRegion damage (100, 100, 100, 100);
831+ roster->dirtyAreaOnCurrentFrame (damage);
832+ EXPECT_EQ (emptyRegion, roster->currentFrameDamage ());
833+}
834+
835+TEST_F (BackbufferTracking, DirtyAreaSubtraction)
836+{
837+ CompRegion dirty (100, 100, 100, 100);
838+ CompRegion obscured (150, 150, 50, 50);
839+ roster->dirtyAreaOnCurrentFrame (dirty);
840+ roster->subtractObscuredArea (obscured);
841+ EXPECT_EQ (dirty - obscured, roster->currentFrameDamage ());
842+}
843+
844+TEST_F (BackbufferTracking, DirtyAreaForAgeZeroAll)
845+{
846+ EXPECT_EQ (CompRegion (0, 0, screen.width (), screen.height ()),
847+ roster->damageForFrameAge (0));
848+}
849+
850+TEST_F (BackbufferTracking, DirtyAreaAllForOlderThanTrackedAge)
851+{
852+ EXPECT_EQ (CompRegion (0, 0, screen.width (), screen.height ()),
853+ roster->damageForFrameAge (1));
854+}
855+
856+TEST_F (BackbufferTracking, NoDirtyAreaForLastFrame)
857+{
858+ CompRegion all (0, 0, screen.width (), screen.height ());
859+ roster->dirtyAreaOnCurrentFrame (all);
860+ roster->incrementFrameAges ();
861+ EXPECT_EQ (emptyRegion, roster->damageForFrameAge (1));
862+}
863+
864+TEST_F (BackbufferTracking, DirtyAreaIfMoreSinceLastFrame)
865+{
866+ CompRegion all (0, 0, screen.width (), screen.height ());
867+ roster->dirtyAreaOnCurrentFrame (all);
868+ roster->incrementFrameAges ();
869+ roster->dirtyAreaOnCurrentFrame(all);
870+ EXPECT_EQ (all, roster->damageForFrameAge (1));
871+}
872+
873+TEST_F (BackbufferTracking, AddOverdrawRegionForLastFrame)
874+{
875+ CompRegion all (0, 0, screen.width (), screen.height ());
876+ roster->dirtyAreaOnCurrentFrame (all);
877+ roster->incrementFrameAges ();
878+ roster->incrementFrameAges ();
879+ roster->overdrawRegionOnPaintingFrame (all);
880+ EXPECT_EQ (all, roster->damageForFrameAge (2));
881+}
882+
883+TEST_F (BackbufferTracking, TwoFramesAgo)
884+{
885+ CompRegion all (0, 0, screen.width (), screen.height ());
886+ CompRegion topleft (0, 0, screen.width () / 2, screen.height () / 2);
887+
888+ roster->dirtyAreaOnCurrentFrame (all);
889+ roster->incrementFrameAges ();
890+ roster->dirtyAreaOnCurrentFrame (topleft);
891+ roster->incrementFrameAges ();
892+ EXPECT_EQ (topleft, roster->damageForFrameAge (2));
893+}
894+
895+TEST_F (BackbufferTracking, TwoFramesAgoCulmulative)
896+{
897+ CompRegion all (0, 0, screen.width (), screen.height ());
898+ CompRegion topleft (0, 0, screen.width () / 2, screen.height () / 2);
899+ CompRegion topright (0, screen.width () / 2,
900+ screen.width () / 2,
901+ screen.height () / 2);
902+
903+ roster->dirtyAreaOnCurrentFrame (all);
904+ roster->incrementFrameAges ();
905+ roster->dirtyAreaOnCurrentFrame (topleft);
906+ roster->dirtyAreaOnCurrentFrame (topright);
907+ roster->incrementFrameAges ();
908+ EXPECT_EQ (topleft + topright, roster->damageForFrameAge (2));
909+}
910+
911+TEST_F (BackbufferTracking, ThreeFramesAgo)
912+{
913+ CompRegion all (0, 0, screen.width (), screen.height ());
914+ CompRegion topleft (0, 0, screen.width () / 2, screen.height () / 2);
915+ CompRegion bottomright (screen.width () / 2,
916+ screen.height () / 2,
917+ screen.width () / 2,
918+ screen.height () / 2);
919+
920+ roster->dirtyAreaOnCurrentFrame (all);
921+ roster->incrementFrameAges ();
922+ roster->dirtyAreaOnCurrentFrame (topleft);
923+ roster->incrementFrameAges ();
924+ roster->dirtyAreaOnCurrentFrame (bottomright);
925+ roster->incrementFrameAges ();
926+
927+ EXPECT_EQ (topleft + bottomright, roster->damageForFrameAge (3));
928+}
929+
930+/* These are more or less functional tests from this point forward
931+ * just checking a number of different situations */
932+
933+TEST_F (BackbufferTracking, ThreeFramesAgoWithFourFrames)
934+{
935+ CompRegion all (0, 0, screen.width (), screen.height ());
936+ CompRegion topleft (0, 0, screen.width () / 2, screen.height () / 2);
937+ CompRegion bottomright (screen.width () / 2,
938+ screen.height () / 2,
939+ screen.width () / 2,
940+ screen.height () / 2);
941+ CompRegion topright (screen.width () / 2,
942+ 0,
943+ screen.width () / 2,
944+ screen.height () / 2);
945+
946+ roster->dirtyAreaOnCurrentFrame (all);
947+ roster->incrementFrameAges ();
948+ roster->dirtyAreaOnCurrentFrame (topleft);
949+ roster->incrementFrameAges ();
950+ roster->dirtyAreaOnCurrentFrame (bottomright);
951+ roster->incrementFrameAges ();
952+ roster->dirtyAreaOnCurrentFrame (topright);
953+ roster->incrementFrameAges ();
954+
955+ EXPECT_EQ (topright + bottomright, roster->damageForFrameAge (3));
956+}
957+
958+TEST_F (BackbufferTracking, ThreeFramesAgoWithFourFramesAndOverlap)
959+{
960+ CompRegion all (0, 0, screen.width (), screen.height ());
961+ CompRegion topleft (0, 0, screen.width () / 2, screen.height () / 2);
962+ CompRegion bottomright (screen.width () / 2,
963+ screen.height () / 2,
964+ screen.width () / 2,
965+ screen.height () / 2);
966+ CompRegion topright (screen.width () / 2,
967+ 0,
968+ screen.width () / 2,
969+ screen.height () / 2);
970+
971+ roster->dirtyAreaOnCurrentFrame (all);
972+ roster->incrementFrameAges ();
973+ roster->dirtyAreaOnCurrentFrame (topleft);
974+ roster->incrementFrameAges ();
975+ roster->dirtyAreaOnCurrentFrame (bottomright);
976+ roster->incrementFrameAges ();
977+ roster->dirtyAreaOnCurrentFrame (bottomright);
978+ roster->incrementFrameAges ();
979+
980+ EXPECT_EQ (bottomright, roster->damageForFrameAge (3));
981+}
982+
983+TEST_F (BackbufferTracking, AllDamageForExceedingMaxTrackedFrames)
984+{
985+ CompRegion all (0, 0, screen.width (), screen.height ());
986+ CompRegion damage (0, 0, 1, 1);
987+
988+ roster->dirtyAreaOnCurrentFrame (all);
989+
990+ for (unsigned int i = 0; i < bt::FrameRoster::NUM_TRACKED_FRAMES - 1; ++i)
991+ {
992+ roster->incrementFrameAges ();
993+ roster->dirtyAreaOnCurrentFrame (damage);
994+ }
995+
996+ EXPECT_EQ (all, roster->damageForFrameAge (bt::FrameRoster::NUM_TRACKED_FRAMES + 1));
997+}
998+
999+TEST_F (BackbufferTracking, DamageForMaxTrackedFrame)
1000+{
1001+ CompRegion all (0, 0, screen.width (), screen.height ());
1002+ CompRegion damage (0, 0, 1, 1);
1003+
1004+ roster->dirtyAreaOnCurrentFrame (all);
1005+
1006+ for (unsigned int i = 0; i < bt::FrameRoster::NUM_TRACKED_FRAMES + 1; ++i)
1007+ {
1008+ roster->incrementFrameAges ();
1009+ roster->dirtyAreaOnCurrentFrame (damage);
1010+ }
1011+
1012+ EXPECT_EQ (all, roster->damageForFrameAge (bt::FrameRoster::NUM_TRACKED_FRAMES));
1013+}
1014+
1015+class MockDamageAgeTracking :
1016+ public bt::DamageAgeTracking
1017+{
1018+ public:
1019+
1020+ typedef boost::shared_ptr <MockDamageAgeTracking> Ptr;
1021+
1022+ MOCK_METHOD0 (incrementFrameAges, void ());
1023+ MOCK_METHOD1 (dirtyAreaOnCurrentFrame, void (const CompRegion &));
1024+ MOCK_METHOD1 (subtractObscuredArea, void (const CompRegion &));
1025+ MOCK_METHOD1 (overdrawRegionOnPaintingFrame, void (const CompRegion &));
1026+};
1027+
1028+class AgeingDamageBuffers :
1029+ public ::testing::Test
1030+{
1031+ public:
1032+
1033+ AgeingDamageBuffers ()
1034+ {
1035+ ageing.observe (mockDamageAgeTracker);
1036+ }
1037+
1038+ MockDamageAgeTracking mockDamageAgeTracker;
1039+ bt::AgeingDamageBuffers ageing;
1040+};
1041+
1042+TEST_F (AgeingDamageBuffers, IncrementAgesOnValidRosters)
1043+{
1044+ EXPECT_CALL (mockDamageAgeTracker, incrementFrameAges ());
1045+ ageing.incrementAges ();
1046+}
1047+
1048+TEST_F (AgeingDamageBuffers, DirtyAreaOnValidRosters)
1049+{
1050+ CompRegion dirtyArea (100, 100, 100, 100);
1051+ EXPECT_CALL (mockDamageAgeTracker, dirtyAreaOnCurrentFrame (dirtyArea));
1052+ ageing.markAreaDirty (dirtyArea);
1053+}
1054+
1055+TEST_F (AgeingDamageBuffers, SubtractObscuredAreaOnValidRosters)
1056+{
1057+ CompRegion obscuredArea (100, 100, 100, 100);
1058+ EXPECT_CALL (mockDamageAgeTracker, subtractObscuredArea (obscuredArea));
1059+ ageing.subtractObscuredArea (obscuredArea);
1060+}
1061+
1062+TEST_F (AgeingDamageBuffers, AddOverdrawAreaOnValidRosters)
1063+{
1064+ CompRegion overdrawArea (100, 100, 100, 100);
1065+ EXPECT_CALL (mockDamageAgeTracker, overdrawRegionOnPaintingFrame (overdrawArea));
1066+ ageing.markAreaDirtyOnLastFrame (overdrawArea);
1067+}
1068+
1069+TEST_F (AgeingDamageBuffers, IncrementAgesOnInvalidRosters)
1070+{
1071+ EXPECT_CALL (mockDamageAgeTracker, incrementFrameAges ()).Times (0);
1072+ ageing.unobserve (mockDamageAgeTracker);
1073+ ageing.incrementAges ();
1074+}
1075+
1076+TEST_F (AgeingDamageBuffers, DirtyAreaOnInvalidRosters)
1077+{
1078+ EXPECT_CALL (mockDamageAgeTracker, dirtyAreaOnCurrentFrame (_)).Times (0);
1079+ ageing.unobserve (mockDamageAgeTracker);
1080+ ageing.markAreaDirty (emptyRegion);
1081+}
1082+
1083+TEST_F (AgeingDamageBuffers, SubtractObscuredAreaOnInvalidRosters)
1084+{
1085+ EXPECT_CALL (mockDamageAgeTracker, subtractObscuredArea (_)).Times (0);
1086+ ageing.unobserve (mockDamageAgeTracker);
1087+ ageing.subtractObscuredArea (emptyRegion);
1088+}
1089+
1090+TEST_F (AgeingDamageBuffers, AddOverdrawAreaOnInvalidRosters)
1091+{
1092+ EXPECT_CALL (mockDamageAgeTracker, overdrawRegionOnPaintingFrame (_)).Times (0);
1093+ ageing.unobserve (mockDamageAgeTracker);
1094+ ageing.markAreaDirtyOnLastFrame (emptyRegion);
1095+}
1096+
1097+
1098
1099=== modified file 'plugins/composite/src/privates.h'
1100--- plugins/composite/src/privates.h 2012-09-20 09:35:40 +0000
1101+++ plugins/composite/src/privates.h 2013-01-30 08:46:22 +0000
1102@@ -36,12 +36,20 @@
1103 #include <map>
1104
1105 #include "pixmapbinding.h"
1106+#include "backbuffertracking.h"
1107 #include "composite_options.h"
1108
1109 extern CompPlugin::VTable *compositeVTable;
1110
1111 extern CompWindow *lastDamagedWindow;
1112
1113+enum DamageTracking
1114+{
1115+ DamageForCurrentFrame = 0,
1116+ DamageForLastFrame = 1,
1117+ DamageFinalPaintRegion
1118+};
1119+
1120 class PrivateCompositeScreen :
1121 ScreenInterface,
1122 public CompositeOptions
1123@@ -66,6 +74,8 @@
1124
1125 void scheduleRepaint ();
1126
1127+ const CompRegion * damageTrackedBuffer (const CompRegion &);
1128+
1129 public:
1130
1131 CompositeScreen *cScreen;
1132@@ -80,10 +90,12 @@
1133 bool randrExtension;
1134 int randrEvent, randrError;
1135
1136- CompRegion damage;
1137+ CompRegion lastFrameDamage;
1138 unsigned long damageMask;
1139
1140- CompRegion tmpRegion;
1141+ CompRegion tmpRegion;
1142+
1143+ DamageTracking currentlyTrackingDamage;
1144
1145 Window overlay;
1146 Window output;
1147@@ -99,6 +111,7 @@
1148 int redrawTime;
1149 int optimalRedrawTime;
1150 bool scheduled, painting, reschedule;
1151+ bool damageRequiresRepaintReschedule;
1152
1153 bool slowAnimations;
1154
1155@@ -115,6 +128,9 @@
1156
1157 /* Map Damage handle to its bounding box */
1158 std::map<Damage, XRectangle> damages;
1159+
1160+ compiz::composite::buffertracking::AgeingDamageBuffers ageingBuffers;
1161+ compiz::composite::buffertracking::FrameRoster roster;
1162 };
1163
1164 class PrivateCompositeWindow :
1165
1166=== modified file 'plugins/composite/src/screen.cpp'
1167--- plugins/composite/src/screen.cpp 2012-11-18 00:22:02 +0000
1168+++ plugins/composite/src/screen.cpp 2013-01-30 08:46:22 +0000
1169@@ -47,6 +47,8 @@
1170
1171 template class WrapableInterface<CompositeScreen, CompositeScreenInterface>;
1172
1173+namespace bt = compiz::composite::buffertracking;
1174+
1175 static const int FALLBACK_REFRESH_RATE = 60; /* if all else fails */
1176
1177 CompWindow *lastDamagedWindow = 0;
1178@@ -276,6 +278,14 @@
1179 delete priv;
1180 }
1181
1182+namespace
1183+{
1184+bool alwaysMarkDirty ()
1185+{
1186+ return true;
1187+}
1188+}
1189+
1190
1191 PrivateCompositeScreen::PrivateCompositeScreen (CompositeScreen *cs) :
1192 cScreen (cs),
1193@@ -294,6 +304,7 @@
1194 randrEvent (0),
1195 randrError (0),
1196 damageMask (COMPOSITE_SCREEN_DAMAGE_ALL_MASK),
1197+ currentlyTrackingDamage (DamageForCurrentFrame),
1198 overlay (None),
1199 output (None),
1200 exposeRects (),
1201@@ -305,12 +316,16 @@
1202 scheduled (false),
1203 painting (false),
1204 reschedule (false),
1205+ damageRequiresRepaintReschedule (true),
1206 slowAnimations (false),
1207 pHnd (NULL),
1208 FPSLimiterMode (CompositeFPSLimiterModeDefault),
1209 withDestroyedWindows (),
1210 cmSnAtom (0),
1211- newCmSnOwner (None)
1212+ newCmSnOwner (None),
1213+ roster (*screen,
1214+ ageingBuffers,
1215+ boost::bind (alwaysMarkDirty))
1216 {
1217 gettimeofday (&lastRedraw, 0);
1218 // wrap outputChangeNotify
1219@@ -491,15 +506,47 @@
1220 return false;
1221 }
1222
1223+const CompRegion *
1224+PrivateCompositeScreen::damageTrackedBuffer (const CompRegion &region)
1225+{
1226+ const CompRegion *currentDamage = NULL;
1227+
1228+ switch (currentlyTrackingDamage)
1229+ {
1230+ case DamageForCurrentFrame:
1231+ currentDamage = &(roster.currentFrameDamage ());
1232+ ageingBuffers.markAreaDirty (region);
1233+ break;
1234+ case DamageForLastFrame:
1235+ currentDamage = &(lastFrameDamage);
1236+ lastFrameDamage += region;
1237+ break;
1238+ case DamageFinalPaintRegion:
1239+ currentDamage = &(tmpRegion);
1240+ tmpRegion += region;
1241+ break;
1242+ default:
1243+ compLogMessage ("composite", CompLogLevelFatal, "unreachable section");
1244+ assert (false);
1245+ abort ();
1246+ }
1247+
1248+ assert (currentDamage);
1249+ return currentDamage;
1250+}
1251+
1252 void
1253 CompositeScreen::damageScreen ()
1254 {
1255+ /* Don't tell plugins about damage events when the damage buffer is already full */
1256 bool alreadyDamaged = priv->damageMask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK;
1257+ alreadyDamaged |= ((currentDamage () & screen->region ()) == screen->region ());
1258
1259 priv->damageMask |= COMPOSITE_SCREEN_DAMAGE_ALL_MASK;
1260 priv->damageMask &= ~COMPOSITE_SCREEN_DAMAGE_REGION_MASK;
1261
1262- priv->scheduleRepaint ();
1263+ if (priv->damageRequiresRepaintReschedule)
1264+ priv->scheduleRepaint ();
1265
1266 /*
1267 * Call through damageRegion since plugins listening for incoming damage
1268@@ -507,7 +554,15 @@
1269 */
1270
1271 if (!alreadyDamaged)
1272+ {
1273 damageRegion (CompRegion (0, 0, screen->width (), screen->height ()));
1274+
1275+ /* Set the damage region as the fullscreen region, because if
1276+ * windows are unredirected we need to correctly subtract from
1277+ * it later
1278+ */
1279+ priv->damageTrackedBuffer (screen->region ());
1280+ }
1281 }
1282
1283 void
1284@@ -518,7 +573,12 @@
1285 if (priv->damageMask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK)
1286 return;
1287
1288- priv->damage += region;
1289+ /* Don't cause repaints to be scheduled for empty damage
1290+ * regions */
1291+ if (region.isEmpty ())
1292+ return;
1293+
1294+ const CompRegion *currentDamage = priv->damageTrackedBuffer (region);
1295 priv->damageMask |= COMPOSITE_SCREEN_DAMAGE_REGION_MASK;
1296
1297 /* if the number of damage rectangles grows two much between repaints,
1298@@ -526,16 +586,61 @@
1299 in order to make sure we're not having too much overhead, damage
1300 the whole screen if we have a lot of damage rects */
1301
1302- if (priv->damage.numRects () > 100)
1303- damageScreen ();
1304- priv->scheduleRepaint ();
1305+ if (currentDamage->numRects () > 100)
1306+ damageScreen ();
1307+
1308+ if (priv->damageRequiresRepaintReschedule)
1309+ priv->scheduleRepaint ();
1310+}
1311+
1312+void
1313+CompositeScreen::damageCutoff ()
1314+{
1315+ WRAPABLE_HND_FUNCTN (damageCutoff);
1316 }
1317
1318 void
1319 CompositeScreen::damagePending ()
1320 {
1321 priv->damageMask |= COMPOSITE_SCREEN_DAMAGE_PENDING_MASK;
1322- priv->scheduleRepaint ();
1323+
1324+ if (priv->damageRequiresRepaintReschedule)
1325+ priv->scheduleRepaint ();
1326+}
1327+
1328+void
1329+CompositeScreen::applyDamageForFrameAge (unsigned int age)
1330+{
1331+ /* Track into "last frame damage" */
1332+ priv->currentlyTrackingDamage = DamageForLastFrame;
1333+ damageRegion (priv->roster.damageForFrameAge (age));
1334+ priv->currentlyTrackingDamage = DamageForCurrentFrame;
1335+}
1336+
1337+unsigned int
1338+CompositeScreen::getFrameAge ()
1339+{
1340+ if (priv->pHnd)
1341+ return priv->pHnd->getFrameAge ();
1342+
1343+ return 1;
1344+}
1345+
1346+void
1347+CompositeScreen::addOverdrawDamageRegion (const CompRegion &r)
1348+{
1349+ priv->ageingBuffers.markAreaDirtyOnLastFrame (r);
1350+}
1351+
1352+typedef CompositeScreen::AreaShouldBeMarkedDirty ShouldMarkDirty;
1353+
1354+CompositeScreen::DamageQuery::Ptr
1355+CompositeScreen::getDamageQuery (const ShouldMarkDirty &callback)
1356+{
1357+ /* No initial damage */
1358+ return bt::FrameRoster::Ptr (new bt::FrameRoster (CompSize (),
1359+ priv->ageingBuffers,
1360+ callback));
1361 }
1362
1363 unsigned int
1364@@ -780,6 +885,10 @@
1365 {
1366 int timeDiff;
1367
1368+ /* Damage that accumulates here does not require a repaint reschedule
1369+ * as it will end up on this frame */
1370+ priv->damageRequiresRepaintReschedule = false;
1371+
1372 if (priv->pHnd)
1373 priv->pHnd->prepareDrawing ();
1374
1375@@ -814,7 +923,7 @@
1376 continue;
1377
1378 if (!CompositeWindow::get (w)->redirected ())
1379- priv->damage -= w->region ();
1380+ priv->ageingBuffers.subtractObscuredArea (w->region ());
1381
1382 break;
1383 }
1384@@ -826,7 +935,13 @@
1385 }
1386 }
1387
1388- priv->tmpRegion = priv->damage & screen->region ();
1389+ /* All further damage is for the next frame now, as
1390+ * priv->tmpRegion will be assigned. Notify plugins that do
1391+ * damage tracking of this */
1392+ damageCutoff ();
1393+
1394+ priv->tmpRegion = (priv->roster.currentFrameDamage () + priv->lastFrameDamage) & screen->region ();
1395+ priv->currentlyTrackingDamage = DamageFinalPaintRegion;
1396
1397 if (priv->damageMask & COMPOSITE_SCREEN_DAMAGE_REGION_MASK)
1398 {
1399@@ -848,7 +963,9 @@
1400 XSync (dpy, False);
1401 priv->damages.clear ();
1402
1403- priv->damage = CompRegion ();
1404+ /* Any more damage requires a repaint reschedule */
1405+ priv->damageRequiresRepaintReschedule = true;
1406+ priv->lastFrameDamage = CompRegion ();
1407
1408 int mask = priv->damageMask;
1409 priv->damageMask = 0;
1410@@ -864,9 +981,13 @@
1411 else
1412 outputs.push_back (&screen->fullscreenOutput ());
1413
1414+ priv->currentlyTrackingDamage = DamageForCurrentFrame;
1415+
1416+ /* All new damage goes on the next frame */
1417+ priv->ageingBuffers.incrementAges ();
1418+
1419 paint (outputs, mask);
1420
1421-
1422 donePaint ();
1423
1424 priv->outputShapeChanged = false;
1425@@ -1023,8 +1144,12 @@
1426 CompositeScreenInterface::damageRegion (const CompRegion &r)
1427 WRAPABLE_DEF (damageRegion, r);
1428
1429+void
1430+CompositeScreenInterface::damageCutoff ()
1431+ WRAPABLE_DEF (damageCutoff);
1432+
1433 const CompRegion &
1434 CompositeScreen::currentDamage () const
1435 {
1436- return priv->damage;
1437+ return priv->roster.currentFrameDamage ();
1438 }
1439
1440=== modified file 'plugins/kdecompat/src/kdecompat.cpp'
1441--- plugins/kdecompat/src/kdecompat.cpp 2012-08-14 06:33:22 +0000
1442+++ plugins/kdecompat/src/kdecompat.cpp 2013-01-30 08:46:22 +0000
1443@@ -196,7 +196,7 @@
1444 if ((!(ks->optionGetPlasmaThumbnails () || mPreviews.empty ()) &&
1445 !(mSlideData || mSlideData->remaining)) ||
1446 !window->mapNum () ||
1447- (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK))
1448+ (mask & PAINT_WINDOW_NO_DRAW_MASKS))
1449 {
1450 status = gWindow->glPaint (attrib, transform, region, mask);
1451 return status;
1452@@ -210,7 +210,7 @@
1453 CompRect clipBox (window->x (), window->y (),
1454 window->width (), window->height ());
1455
1456- if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
1457+ if (mask & PAINT_WINDOW_NO_DRAW_MASKS)
1458 return false;
1459
1460 remainder = (float) data->remaining / data->duration;
1461
1462=== modified file 'plugins/opengl/include/opengl/opengl.h'
1463--- plugins/opengl/include/opengl/opengl.h 2013-01-10 09:23:24 +0000
1464+++ plugins/opengl/include/opengl/opengl.h 2013-01-30 08:46:22 +0000
1465@@ -37,6 +37,13 @@
1466 #else
1467 #include <GL/gl.h>
1468 #include <GL/glx.h>
1469+
1470+/* Some implementations have not yet given a definition
1471+ * to GLX_BACK_BUFFER_AGE_EXT but this is the token as defined
1472+ * in the spec (https://www.opengl.org/registry/specs/EXT/glx_buffer_age.txt)
1473+ */
1474+#define GLX_BACK_BUFFER_AGE_EXT 0x20F4
1475+
1476 #endif
1477
1478 #include <core/size.h>
1479@@ -50,7 +57,7 @@
1480 #include <opengl/programcache.h>
1481 #include <opengl/shadercache.h>
1482
1483-#define COMPIZ_OPENGL_ABI 6
1484+#define COMPIZ_OPENGL_ABI 8
1485
1486 /*
1487 * Some plugins check for #ifdef USE_MODERN_COMPIZ_GL. Support it for now, but
1488@@ -525,6 +532,7 @@
1489 extern bool shaders;
1490 extern bool stencilBuffer;
1491 extern GLint maxTextureUnits;
1492+ extern bool bufferAge;
1493
1494 extern bool canDoSaturated;
1495 extern bool canDoSlightlySaturated;
1496@@ -663,6 +671,11 @@
1497 unsigned int mask);
1498
1499 /**
1500+ * Return true if glPaintCompositedOutput is required for this frame
1501+ */
1502+ virtual bool glPaintCompositedOutputRequired ();
1503+
1504+ /**
1505 * Hookable function used by plugins to determine stenciling mask
1506 */
1507 virtual void glBufferStencil (const GLMatrix &matrix,
1508@@ -674,7 +687,7 @@
1509 extern template class PluginClassHandler<GLScreen, CompScreen, COMPIZ_OPENGL_ABI>;
1510
1511 class GLScreen :
1512- public WrapableHandler<GLScreenInterface, 8>,
1513+ public WrapableHandler<GLScreenInterface, 9>,
1514 public PluginClassHandler<GLScreen, CompScreen, COMPIZ_OPENGL_ABI>,
1515 public CompOption::Class
1516 {
1517@@ -788,7 +801,9 @@
1518 WRAPABLE_HND (6, GLScreenInterface, void, glPaintCompositedOutput,
1519 const CompRegion &, GLFramebufferObject *, unsigned int);
1520
1521- WRAPABLE_HND (7, GLScreenInterface, void, glBufferStencil, const GLMatrix &,
1522+ WRAPABLE_HND (7, GLScreenInterface, bool, glPaintCompositedOutputRequired);
1523+
1524+ WRAPABLE_HND (8, GLScreenInterface, void, glBufferStencil, const GLMatrix &,
1525 GLVertexBuffer &,
1526 CompOutput *);
1527
1528
1529=== modified file 'plugins/opengl/src/doublebuffer/src/double-buffer.cpp'
1530--- plugins/opengl/src/doublebuffer/src/double-buffer.cpp 2012-11-09 06:13:00 +0000
1531+++ plugins/opengl/src/doublebuffer/src/double-buffer.cpp 2013-01-30 08:46:22 +0000
1532@@ -26,6 +26,7 @@
1533
1534 #include <cstdlib>
1535 #include <cassert>
1536+#include <cstdio>
1537 #include "opengl/doublebuffer.h"
1538
1539 using namespace compiz::opengl;
1540@@ -77,9 +78,7 @@
1541
1542 if (setting[NEED_PERSISTENT_BACK_BUFFER] &&
1543 !setting[HAVE_PERSISTENT_BACK_BUFFER])
1544- {
1545 copyFrontToBack ();
1546- }
1547 }
1548 else
1549 {
1550
1551=== modified file 'plugins/opengl/src/framebufferobject.cpp'
1552--- plugins/opengl/src/framebufferobject.cpp 2012-08-06 09:44:49 +0000
1553+++ plugins/opengl/src/framebufferobject.cpp 2013-01-30 08:46:22 +0000
1554@@ -131,7 +131,7 @@
1555
1556 (*GL::framebufferTexture2D) (GL::FRAMEBUFFER, GL::COLOR_ATTACHMENT0,
1557 priv->glTex->target (),
1558- priv->glTex->name (), 0);
1559+ priv->glTex->name (), 0);
1560
1561 priv->status = (*GL::checkFramebufferStatus) (GL::DRAW_FRAMEBUFFER);
1562
1563
1564=== modified file 'plugins/opengl/src/paint.cpp'
1565--- plugins/opengl/src/paint.cpp 2013-01-01 10:04:50 +0000
1566+++ plugins/opengl/src/paint.cpp 2013-01-30 08:46:22 +0000
1567@@ -626,8 +626,8 @@
1568 if (mask & PAINT_SCREEN_FULL_MASK)
1569 {
1570 glPaintTransformedOutput (sAttrib, sTransform,
1571- CompRegion (*output), output, mask);
1572-
1573+ CompRegionRef (output->region ()), output, mask);
1574+ priv->cScreen->addOverdrawDamageRegion (CompRegionRef (output->region ()));
1575 return true;
1576 }
1577
1578@@ -657,8 +657,9 @@
1579 }
1580 else if (mask & PAINT_SCREEN_FULL_MASK)
1581 {
1582- glPaintTransformedOutput (sAttrib, sTransform, CompRegion (*output),
1583+ glPaintTransformedOutput (sAttrib, sTransform, CompRegionRef (output->region ()),
1584 output, mask);
1585+ priv->cScreen->addOverdrawDamageRegion (CompRegionRef (output->region ()));
1586
1587 return true;
1588 }
1589@@ -668,6 +669,13 @@
1590 }
1591 }
1592
1593+bool
1594+GLScreen::glPaintCompositedOutputRequired ()
1595+{
1596+ WRAPABLE_HND_FUNCTN_RETURN (bool, glPaintCompositedOutputRequired);
1597+ return false;
1598+}
1599+
1600 void
1601 GLScreen::glPaintCompositedOutput (const CompRegion &region,
1602 GLFramebufferObject *fbo,
1603
1604=== modified file 'plugins/opengl/src/privates.h'
1605--- plugins/opengl/src/privates.h 2013-01-01 09:41:41 +0000
1606+++ plugins/opengl/src/privates.h 2013-01-30 08:46:22 +0000
1607@@ -29,6 +29,9 @@
1608 #define _OPENGL_PRIVATES_H
1609
1610 #include <memory>
1611+#include <vector>
1612+#include <tr1/tuple>
1613+#include <boost/shared_ptr.hpp>
1614
1615 #include <composite/composite.h>
1616 #include <opengl/opengl.h>
1617@@ -119,8 +122,26 @@
1618 GLTexture::List textures;
1619 };
1620
1621+class FrameProvider
1622+{
1623+ public:
1624+
1625+ typedef boost::shared_ptr <FrameProvider> Ptr;
1626+ typedef std::tr1::tuple <GLFramebufferObject *, int> Frame;
1627+
1628+ virtual ~FrameProvider () {}
1629+
1630+ virtual GLuint getCurrentFrame () = 0;
1631+ virtual void endFrame () = 0;
1632+
1633+ virtual bool providesPersistence () = 0;
1634+ virtual bool alwaysPostprocess () = 0;
1635+ virtual void invalidateAll () = 0;
1636+};
1637+
1638 class PrivateGLScreen :
1639 public ScreenInterface,
1640+ public CompositeScreenInterface,
1641 public compiz::composite::PaintHandler,
1642 public OpenglOptions
1643 {
1644@@ -141,12 +162,16 @@
1645 bool hasVSync ();
1646 bool requiredForcedRefreshRate ();
1647
1648+ unsigned int getFrameAge ();
1649+
1650 void updateRenderMode ();
1651
1652 void prepareDrawing ();
1653
1654 bool compositingActive ();
1655
1656+ void damageCutoff ();
1657+
1658 void paintBackground (const GLMatrix &transform,
1659 const CompRegion &region,
1660 bool transformed);
1661@@ -162,6 +187,8 @@
1662
1663 bool driverIsBlacklisted (const char *regex) const;
1664
1665+ bool postprocessRequiredForCurrentFrame ();
1666+
1667 public:
1668
1669 GLScreen *gScreen;
1670@@ -196,7 +223,7 @@
1671 GLXDoubleBuffer doubleBuffer;
1672 #endif
1673
1674- GLFramebufferObject *scratchFbo;
1675+ boost::shared_ptr <GLFramebufferObject> scratchFbo;
1676 CompRegion outputRegion;
1677
1678 XRectangle lastViewport;
1679@@ -221,8 +248,10 @@
1680 Pixmap rootPixmapCopy;
1681 CompSize rootPixmapSize;
1682
1683+ FrameProvider::Ptr frameProvider;
1684 const char *glVendor, *glRenderer, *glVersion;
1685
1686+ bool postprocessingRequired;
1687 mutable CompString prevRegex;
1688 mutable bool prevBlacklisted;
1689 };
1690
1691=== modified file 'plugins/opengl/src/screen.cpp'
1692--- plugins/opengl/src/screen.cpp 2013-01-09 10:57:03 +0000
1693+++ plugins/opengl/src/screen.cpp 2013-01-30 08:46:22 +0000
1694@@ -186,6 +186,7 @@
1695 bool vboEnabled = false;
1696 bool shaders = false;
1697 GLint maxTextureUnits = 1;
1698+ bool bufferAge = false;
1699
1700 bool canDoSaturated = false;
1701 bool canDoSlightlySaturated = false;
1702@@ -301,6 +302,52 @@
1703
1704 #ifndef USE_GLES
1705
1706+class BufferAgeFrameProvider :
1707+ public FrameProvider
1708+{
1709+ public:
1710+
1711+ BufferAgeFrameProvider (Display *disp,
1712+ GLXDrawable drawable) :
1713+ mDisplay (disp),
1714+ mDrawable (drawable)
1715+ {
1716+ }
1717+
1718+ unsigned int getCurrentFrame ()
1719+ {
1720+ unsigned int age = 0;
1721+ (*GL::queryDrawable) (mDisplay,
1722+ mDrawable,
1723+ GLX_BACK_BUFFER_AGE_EXT,
1724+ &age);
1725+ return age;
1726+ }
1727+
1728+ void endFrame ()
1729+ {
1730+ }
1731+
1732+ void invalidateAll ()
1733+ {
1734+ }
1735+
1736+ bool providesPersistence ()
1737+ {
1738+ return true;
1739+ }
1740+
1741+ bool alwaysPostprocess ()
1742+ {
1743+ return false;
1744+ }
1745+
1746+ private:
1747+
1748+ Display *mDisplay;
1749+ GLXDrawable mDrawable;
1750+};
1751+
1752 namespace compiz
1753 {
1754 namespace opengl
1755@@ -358,6 +405,137 @@
1756
1757 #endif
1758
1759+class UndefinedFrameProvider :
1760+ public FrameProvider
1761+{
1762+ public:
1763+
1764+ unsigned int getCurrentFrame ()
1765+ {
1766+ return 0;
1767+ }
1768+
1769+ void endFrame ()
1770+ {
1771+ }
1772+
1773+ void invalidateAll ()
1774+ {
1775+ }
1776+
1777+ bool providesPersistence ()
1778+ {
1779+ return false;
1780+ }
1781+
1782+ bool alwaysPostprocess ()
1783+ {
1784+ return false;
1785+ }
1786+};
1787+
1788+class PostprocessFrameProvider :
1789+ public FrameProvider
1790+{
1791+ public:
1792+
1793+ PostprocessFrameProvider (GLFramebufferObject *object) :
1794+ mObject (object),
1795+ mAge (0)
1796+ {
1797+ }
1798+
1799+ unsigned int getCurrentFrame ()
1800+ {
1801+ /* We are now using this buffer, reset
1802+ * age back to zero */
1803+ unsigned int lastAge = mAge;
1804+ mAge = 0;
1805+
1806+ return lastAge;
1807+ }
1808+
1809+ void endFrame ()
1810+ {
1811+ ++mAge;
1812+ }
1813+
1814+ void invalidateAll ()
1815+ {
1816+ mAge = 0;
1817+ }
1818+
1819+ bool providesPersistence ()
1820+ {
1821+ return true;
1822+ }
1823+
1824+ bool alwaysPostprocess ()
1825+ {
1826+ return true;
1827+ }
1828+
1829+ private:
1830+
1831+ GLFramebufferObject *mObject;
1832+ unsigned int mAge;
1833+};
1834+
1835+class OptionalPostprocessFrameProvider :
1836+ public FrameProvider
1837+{
1838+ public:
1839+
1840+ typedef boost::function <bool ()> PostprocessRequired;
1841+
1842+ OptionalPostprocessFrameProvider (const FrameProvider::Ptr &backbuffer,
1843+ const FrameProvider::Ptr &scratchbuffer,
1844+ const PostprocessRequired &ppRequired) :
1845+ mBackbuffer (backbuffer),
1846+ mScratchbuffer (scratchbuffer),
1847+ mPPRequired (ppRequired)
1848+ {
1849+ }
1850+
1851+ unsigned int getCurrentFrame ()
1852+ {
1853+ if (mPPRequired ())
1854+ return mScratchbuffer->getCurrentFrame ();
1855+ else
1856+ return mBackbuffer->getCurrentFrame ();
1857+ }
1858+
1859+ void endFrame ()
1860+ {
1861+ mScratchbuffer->endFrame ();
1862+ }
1863+
1864+ void invalidateAll ()
1865+ {
1866+ mScratchbuffer->invalidateAll ();
1867+ }
1868+
1869+ bool providesPersistence ()
1870+ {
1871+ /* We are only as good as the backbuffer is */
1872+ return mBackbuffer->providesPersistence ();
1873+ }
1874+
1875+ bool alwaysPostprocess ()
1876+ {
1877+ if (mPPRequired ())
1878+ return mScratchbuffer->alwaysPostprocess ();
1879+ else
1880+ return mBackbuffer->alwaysPostprocess ();
1881+ }
1882+
1883+ private:
1884+
1885+ FrameProvider::Ptr mBackbuffer;
1886+ FrameProvider::Ptr mScratchbuffer;
1887+ PostprocessRequired mPPRequired;
1888+};
1889+
1890 bool
1891 GLScreen::glInitContext (XVisualInfo *visinfo)
1892 {
1893@@ -593,6 +771,8 @@
1894
1895 priv->incorrectRefreshRate = false;
1896
1897+ priv->frameProvider.reset (new PostprocessFrameProvider ());
1898+
1899 #else
1900
1901 Display *dpy = screen->dpy ();
1902@@ -899,12 +1079,48 @@
1903
1904 if (GL::fboSupported)
1905 {
1906- priv->scratchFbo = new GLFramebufferObject;
1907+ priv->scratchFbo.reset (new GLFramebufferObject ());
1908 priv->scratchFbo->allocate (*screen, NULL, GL_BGRA);
1909 }
1910
1911 GLVertexBuffer::streamingBuffer ()->setAutoProgram (priv->autoProgram);
1912
1913+ /* We need scratchFbo to be set before doing this, and it is common
1914+ * to both the GLES and non-GLES codepaths, so using another #ifdef
1915+ */
1916+#ifndef USE_GLES
1917+ const Window outputWindow = CompositeScreen::get (screen)->output ();
1918+
1919+ if (GL::fboEnabled)
1920+ {
1921+ if (GL::bufferAge)
1922+ {
1923+ FrameProvider::Ptr back (new BufferAgeFrameProvider (screen->dpy (),
1924+ outputWindow));
1925+ FrameProvider::Ptr scratch (new PostprocessFrameProvider (priv->scratchFbo.get ()));
1926+ OptionalPostprocessFrameProvider::PostprocessRequired ppReq
1927+ (boost::bind (&PrivateGLScreen::postprocessRequiredForCurrentFrame,
1928+ priv));
1929+ priv->frameProvider.reset (new OptionalPostprocessFrameProvider (back,
1930+ scratch,
1931+ ppReq));
1932+ }
1933+ else
1934+ {
1935+ /* Prefer using FBO's instead of switching between a defined/undefined backbuffer */
1936+ priv->frameProvider.reset (new PostprocessFrameProvider (priv->scratchFbo.get ()));
1937+ }
1938+ }
1939+ else
1940+ {
1941+ if (GL::bufferAge)
1942+ priv->frameProvider.reset (new BufferAgeFrameProvider (screen->dpy (),
1943+ outputWindow));
1944+ else
1945+ priv->frameProvider.reset (new UndefinedFrameProvider ());
1946+ }
1947+#endif
1948+
1949 return true;
1950 }
1951
1952@@ -993,6 +1209,13 @@
1953 return;
1954 }
1955
1956+ if (strstr (glxExtensions, "GLX_EXT_buffer_age"))
1957+ {
1958+ compLogMessage ("opengl", CompLogLevelInfo,
1959+ "GLX_EXT_buffer_age is supported");
1960+ GL::bufferAge = true;
1961+ }
1962+
1963 priv->getProcAddress = (GL::GLXGetProcAddressProc)
1964 getProcAddress ("glXGetProcAddressARB");
1965 GL::bindTexImage = (GL::GLXBindTexImageProc)
1966@@ -1209,9 +1432,6 @@
1967 glXDestroyContext (screen->dpy (), priv->ctx);
1968 #endif
1969
1970- if (priv->scratchFbo)
1971- delete priv->scratchFbo;
1972-
1973 delete priv;
1974 }
1975
1976@@ -1233,7 +1453,7 @@
1977 ctx (EGL_NO_CONTEXT),
1978 doubleBuffer (screen->dpy (), *screen, surface),
1979 #endif
1980- scratchFbo (NULL),
1981+ scratchFbo (),
1982 outputRegion (),
1983 refreshSubBuffer (false),
1984 lastMask (0),
1985@@ -1246,13 +1466,16 @@
1986 autoProgram (new GLScreenAutoProgram(gs)),
1987 rootPixmapCopy (None),
1988 rootPixmapSize (),
1989+ frameProvider (),
1990 glVendor (NULL),
1991 glRenderer (NULL),
1992 glVersion (NULL),
1993+ postprocessingRequired (false)
1994 prevRegex (),
1995 prevBlacklisted (false)
1996 {
1997 ScreenInterface::setHandler (screen);
1998+ CompositeScreenInterface::setHandler (cScreen);
1999 }
2000
2001 PrivateGLScreen::~PrivateGLScreen ()
2002@@ -1443,8 +1666,11 @@
2003 {
2004 screen->outputChangeNotify ();
2005
2006+ frameProvider->invalidateAll ();
2007+
2008 if (scratchFbo)
2009 scratchFbo->allocate (*screen, NULL, GL_BGRA);
2010+
2011 updateView ();
2012 }
2013
2014@@ -1669,6 +1895,10 @@
2015 GLScreenInterface::projectionMatrix ()
2016 WRAPABLE_DEF (projectionMatrix)
2017
2018+bool
2019+GLScreenInterface::glPaintCompositedOutputRequired ()
2020+ WRAPABLE_DEF (glPaintCompositedOutputRequired)
2021+
2022 void
2023 GLScreenInterface::glPaintCompositedOutput (const CompRegion &region,
2024 GLFramebufferObject *fbo,
2025@@ -1977,18 +2207,6 @@
2026 glDepthMask (GL_FALSE);
2027 glStencilMask (0);
2028
2029- GLFramebufferObject *oldFbo = NULL;
2030- bool useFbo = false;
2031-
2032- /* Clear the color buffer where appropriate */
2033- if (GL::fboEnabled && scratchFbo)
2034- {
2035- oldFbo = scratchFbo->bind ();
2036- useFbo = scratchFbo->checkStatus () && scratchFbo->tex ();
2037- if (!useFbo)
2038- GLFramebufferObject::rebind (oldFbo);
2039- }
2040-
2041 #ifdef UNSAFE_ARM_SGX_FIXME
2042 refreshSubBuffer = ((lastMask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK) &&
2043 !(mask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK) &&
2044@@ -2006,8 +2224,21 @@
2045 }
2046 #endif
2047
2048- CompRegion tmpRegion = (mask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK) ?
2049- screen->region () : region;
2050+ CompRegion paintRegion ((mask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK) ?
2051+ screen->region () : region);
2052+ bool useFbo = false;
2053+ GLFramebufferObject *oldFbo = NULL;
2054+
2055+ postprocessingRequired = gScreen->glPaintCompositedOutputRequired ();
2056+ postprocessingRequired |= frameProvider->alwaysPostprocess ();
2057+
2058+ /* Clear the color buffer where appropriate */
2059+ if ((GL::fboEnabled && postprocessRequiredForCurrentFrame ()))
2060+ {
2061+ oldFbo = scratchFbo->bind ();
2062+ if (scratchFbo->checkStatus ())
2063+ useFbo = true;
2064+ }
2065
2066 foreach (CompOutput *output, outputs)
2067 {
2068@@ -2034,7 +2265,8 @@
2069
2070 gScreen->glPaintOutput (defaultScreenPaintAttrib,
2071 identity,
2072- CompRegion (*output), output,
2073+ CompRegion (*output),
2074+ output,
2075 PAINT_SCREEN_REGION_MASK |
2076 PAINT_SCREEN_FULL_MASK);
2077 }
2078@@ -2057,7 +2289,9 @@
2079 tmpRegion = CompRegion (*output);
2080 #endif
2081
2082- outputRegion = tmpRegion & CompRegion (*output);
2083+ /* Clip current paint region to output extents */
2084+ CompRegionRef wholeOutput (output->region ());
2085+ outputRegion = (paintRegion & wholeOutput);
2086
2087 if (!gScreen->glPaintOutput (defaultScreenPaintAttrib,
2088 identity,
2089@@ -2068,10 +2302,11 @@
2090
2091 gScreen->glPaintOutput (defaultScreenPaintAttrib,
2092 identity,
2093- CompRegion (*output), output,
2094+ wholeOutput, output,
2095 PAINT_SCREEN_FULL_MASK);
2096
2097- tmpRegion += *output;
2098+ paintRegion += wholeOutput;
2099+ cScreen->addOverdrawDamageRegion (wholeOutput);
2100 }
2101 }
2102 }
2103@@ -2082,13 +2317,18 @@
2104
2105 if (useFbo)
2106 {
2107- GLFramebufferObject::rebind (oldFbo);
2108-
2109 // FIXME: does not work if screen dimensions exceed max texture size
2110 // We should try to use glBlitFramebuffer instead.
2111- gScreen->glPaintCompositedOutput (screen->region (), scratchFbo, mask);
2112+ GLFramebufferObject::rebind (oldFbo);
2113+ /* If we must always postprocess, then we don't have any
2114+ * "real" backbuffer persistence, redraw the whole thing */
2115+ gScreen->glPaintCompositedOutput (frameProvider->alwaysPostprocess () ?
2116+ screen->region () :
2117+ paintRegion, scratchFbo.get (), mask);
2118 }
2119
2120+ frameProvider->endFrame ();
2121+
2122 if (cScreen->outputWindowChanged ())
2123 {
2124 /*
2125@@ -2100,20 +2340,27 @@
2126 return;
2127 }
2128
2129+ bool persistence = frameProvider->providesPersistence ();
2130 bool alwaysSwap = optionGetAlwaysSwapBuffers ();
2131- bool fullscreen = useFbo ||
2132+ bool fullscreen = persistence ||
2133 alwaysSwap ||
2134 ((mask & COMPOSITE_SCREEN_DAMAGE_ALL_MASK) &&
2135 commonFrontbuffer);
2136
2137 doubleBuffer.set (DoubleBuffer::VSYNC, optionGetSyncToVblank ());
2138- doubleBuffer.set (DoubleBuffer::HAVE_PERSISTENT_BACK_BUFFER, useFbo);
2139+ doubleBuffer.set (DoubleBuffer::HAVE_PERSISTENT_BACK_BUFFER, persistence);
2140 doubleBuffer.set (DoubleBuffer::NEED_PERSISTENT_BACK_BUFFER, alwaysSwap);
2141- doubleBuffer.render (tmpRegion, fullscreen);
2142+ doubleBuffer.render (paintRegion, fullscreen);
2143
2144 lastMask = mask;
2145 }
2146
2147+unsigned int
2148+PrivateGLScreen::getFrameAge ()
2149+{
2150+ return frameProvider->getCurrentFrame ();
2151+}
2152+
2153 bool
2154 PrivateGLScreen::hasVSync ()
2155 {
2156@@ -2138,6 +2385,13 @@
2157 }
2158
2159 void
2160+PrivateGLScreen::damageCutoff ()
2161+{
2162+ cScreen->applyDamageForFrameAge (frameProvider->getCurrentFrame ());
2163+ cScreen->damageCutoff ();
2164+}
2165+
2166+void
2167 PrivateGLScreen::updateRenderMode ()
2168 {
2169 #ifndef USE_GLES
2170@@ -2170,6 +2424,12 @@
2171 return prevBlacklisted;
2172 }
2173
2174+bool
2175+PrivateGLScreen::postprocessRequiredForCurrentFrame ()
2176+{
2177+ return postprocessingRequired;
2178+}
2179+
2180 GLTexture::BindPixmapHandle
2181 GLScreen::registerBindPixmap (GLTexture::BindPixmapProc proc)
2182 {
2183@@ -2198,7 +2458,7 @@
2184 GLFramebufferObject *
2185 GLScreen::fbo ()
2186 {
2187- return priv->scratchFbo;
2188+ return priv->scratchFbo.get ();
2189 }
2190
2191 GLTexture *
2192
2193=== modified file 'plugins/resize/src/resize.cpp'
2194--- plugins/resize/src/resize.cpp 2012-10-19 09:23:11 +0000
2195+++ plugins/resize/src/resize.cpp 2013-01-30 08:46:22 +0000
2196@@ -257,7 +257,7 @@
2197 float xScale, yScale;
2198 int x, y;
2199
2200- if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
2201+ if (mask & PAINT_WINDOW_NO_DRAW_MASKS)
2202 return false;
2203
2204 status = gWindow->glPaint (attrib, transform, region,
2205
2206=== modified file 'plugins/ring/src/ring.cpp'
2207--- plugins/ring/src/ring.cpp 2013-01-19 11:47:22 +0000
2208+++ plugins/ring/src/ring.cpp 2013-01-30 08:46:22 +0000
2209@@ -264,7 +264,7 @@
2210 GLWindowPaintAttrib wAttrib (gWindow->lastPaintAttrib ());
2211 GLMatrix wTransform = transform;
2212
2213- if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
2214+ if (mask & PAINT_WINDOW_NO_DRAW_MASKS)
2215 return false;
2216
2217 if (mSlot)
2218
2219=== modified file 'plugins/scale/src/scale.cpp'
2220--- plugins/scale/src/scale.cpp 2013-01-29 23:16:32 +0000
2221+++ plugins/scale/src/scale.cpp 2013-01-30 08:46:22 +0000
2222@@ -384,12 +384,14 @@
2223
2224 status = gWindow->glPaint (sAttrib, transform, region, mask);
2225
2226+ mask &= ~(PAINT_WINDOW_NO_CORE_INSTANCE_MASK);
2227+
2228 if (scaled)
2229 {
2230 GLWindowPaintAttrib lastAttrib (gWindow->lastPaintAttrib ());
2231 GLMatrix wTransform (transform);
2232
2233- if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
2234+ if (mask & PAINT_WINDOW_NO_DRAW_MASKS)
2235 return false;
2236
2237 if (window->alpha () || lastAttrib.opacity != OPAQUE)
2238
2239=== modified file 'plugins/staticswitcher/src/staticswitcher.cpp'
2240--- plugins/staticswitcher/src/staticswitcher.cpp 2012-12-10 03:28:47 +0000
2241+++ plugins/staticswitcher/src/staticswitcher.cpp 2013-01-30 08:46:22 +0000
2242@@ -1246,7 +1246,7 @@
2243
2244 const CompWindow::Geometry &g = window->geometry ();
2245
2246- if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK ||
2247+ if (mask & PAINT_WINDOW_NO_DRAW_MASKS ||
2248 sScreen->ignoreSwitcher)
2249 return false;
2250
2251
2252=== modified file 'plugins/switcher/src/switcher.cpp'
2253--- plugins/switcher/src/switcher.cpp 2012-12-10 03:28:47 +0000
2254+++ plugins/switcher/src/switcher.cpp 2013-01-30 08:46:22 +0000
2255@@ -971,7 +971,7 @@
2256
2257 const CompWindow::Geometry &g = window->geometry ();
2258
2259- if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK ||
2260+ if (mask & PAINT_WINDOW_NO_DRAW_MASKS ||
2261 sScreen->ignoreSwitcher)
2262 return false;
2263
2264
2265=== modified file 'plugins/td/src/3d.cpp'
2266--- plugins/td/src/3d.cpp 2013-01-11 22:35:15 +0000
2267+++ plugins/td/src/3d.cpp 2013-01-30 08:46:22 +0000
2268@@ -163,7 +163,7 @@
2269 glGetIntegerv (GL_CULL_FACE_MODE, &cull);
2270 cullInv = (cull == GL_BACK)? GL_FRONT : GL_BACK;
2271
2272- if (ww && wh && !(mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK) &&
2273+ if (ww && wh && !(mask & PAINT_WINDOW_NO_DRAW_MASKS) &&
2274 ((cs->paintOrder () == FTB && mFtb) ||
2275 (cs->paintOrder () == BTF && !mFtb)))
2276 {
2277
2278=== modified file 'plugins/water/src/water.cpp'
2279--- plugins/water/src/water.cpp 2012-12-10 03:28:47 +0000
2280+++ plugins/water/src/water.cpp 2013-01-30 08:46:22 +0000
2281@@ -183,6 +183,7 @@
2282 cScreen->preparePaintSetEnabled (this, true);
2283 gScreen->glPaintOutputSetEnabled (this, true);
2284 gScreen->glPaintCompositedOutputSetEnabled (this, true);
2285+ gScreen->glPaintCompositedOutputRequiredSetEnabled (this, true);
2286 cScreen->donePaintSetEnabled (this, true);
2287 }
2288
2289@@ -317,6 +318,13 @@
2290 }
2291 }
2292
2293+bool
2294+WaterScreen::glPaintCompositedOutputRequired ()
2295+{
2296+ printf ("call\n");
2297+ return true;
2298+}
2299+
2300 void
2301 WaterScreen::glPaintCompositedOutput (const CompRegion &region,
2302 GLFramebufferObject *fbo,
2303@@ -467,6 +475,7 @@
2304 cScreen->preparePaintSetEnabled (this, false);
2305 gScreen->glPaintOutputSetEnabled (this, false);
2306 gScreen->glPaintCompositedOutputSetEnabled (this, false);
2307+ gScreen->glPaintCompositedOutputRequiredSetEnabled (this, false);
2308 cScreen->donePaintSetEnabled (this, false);
2309 }
2310
2311
2312=== modified file 'plugins/water/src/water.h'
2313--- plugins/water/src/water.h 2012-09-07 23:56:21 +0000
2314+++ plugins/water/src/water.h 2013-01-30 08:46:22 +0000
2315@@ -64,6 +64,7 @@
2316
2317 void handleEvent (XEvent *);
2318
2319+ bool glPaintCompositedOutputRequired ();
2320 void glPaintCompositedOutput (const CompRegion &region,
2321 GLFramebufferObject *fbo,
2322 unsigned int mask);

Subscribers

People subscribed via source and target branches