Merge lp:~smspillaz/unity/unity.fix_1080947 into lp:unity

Proposed by Sam Spilsbury
Status: Superseded
Proposed branch: lp:~smspillaz/unity/unity.fix_1080947
Merge into: lp:unity
Diff against target: 665 lines (+286/-129)
4 files modified
launcher/XdndCollectionWindowImp.cpp (+2/-1)
plugins/unityshell/src/unityshell.cpp (+264/-124)
plugins/unityshell/src/unityshell.h (+20/-2)
unity-shared/BackgroundEffectHelper.cpp (+0/-2)
To merge this branch: bzr merge lp:~smspillaz/unity/unity.fix_1080947
Reviewer Review Type Date Requested Status
Unity Team Pending
Review via email: mp+147544@code.launchpad.net

This proposal has been superseded by a proposal from 2013-03-22.

Commit message

Don't re-present all of our windows on every frame. Only do that if damage intersects it.

Use the new APIs exposed by compiz and nux to intelligently determine which windows need to be presented per-frame and only register damage for those windows. This fixes two things:

1. BaseWindows being redrawn from scratch every time damage was registered over them. That was incorrect and should only be done in the case of background blurs.
2. BaseWindows being drawn to the screen on every frame, regardless of whether or not they needed to be. Now they will only be drawn if some damage intersects beneath them. Note that unity will expand the damage region to accomadate the base window since nux does not support geometry clipping. So if there is a partial intersection of the launcher for example, the area of the screen which contains the launcher will be re-painted (but the launcher itself won't be redrawn, just its texture).

This also uses the framebuffer blitting API from compiz to quickly copy the non-blurred regions of the screen back to the backbuffer.

(LP: #1080947)

Description of the change

Don't re-present all of our windows on every frame. Only do that if damage intersects it.

Use the new APIs exposed by compiz and nux to intelligently determine which windows need to be presented per-frame and only register damage for those windows. This fixes two things:

1. BaseWindows being redrawn from scratch every time damage was registered over them. That was incorrect and should only be done in the case of background blurs.
2. BaseWindows being drawn to the screen on every frame, regardless of whether or not they needed to be. Now they will only be drawn if some damage intersects beneath them. Note that unity will expand the damage region to accomadate the base window since nux does not support geometry clipping. So if there is a partial intersection of the launcher for example, the area of the screen which contains the launcher will be re-painted (but the launcher itself won't be redrawn, just its texture).

This also uses the framebuffer blitting API from compiz to quickly copy the non-blurred regions of the screen back to the backbuffer.

(LP: #1080947)

This branch depends on two others:

1. https://code.launchpad.net/~smspillaz/nux/nux.fix_1091589/+merge/147543 (WindowThread::PresentWindowsIntersectingGeometryOnThisFrame, WindowThread::ForeignFrameCutoff, WindowThread::ForeignFrameEnded)
2. https://code.launchpad.net/~compiz-team/compiz/compiz.fix_1024304/+merge/147540 (composite::Frameroster)

Update: test results here: http://www.ucc.asn.au/~smspillaz/phoronix-test-suite/composite.xml

I was careful to modify phoronix-test-suite to run tests in windowed mode only, and those were the only three tests I was able to get to run in windowed mode. Of particular interest was the fact that the unigine demos had a 5x performance improvement, probably because the driver was spending less time filling redundant pixels from the compositor. In other areas we had a roughly 5FPS boost.

Compiz framerate graph:

http://www.ucc.asn.au/~smspillaz/compiz-perf-graph.png

You'll see that especially on the last test, it drops off quite a bit on the non buffer_age case, and is generally speaking lower across the board.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'launcher/XdndCollectionWindowImp.cpp'
2--- launcher/XdndCollectionWindowImp.cpp 2012-11-22 16:37:07 +0000
3+++ launcher/XdndCollectionWindowImp.cpp 2013-02-10 09:01:22 +0000
4@@ -38,7 +38,8 @@
5 auto uscreen = UScreen::GetDefault();
6 SetGeometry(uscreen->GetScreenGeometry());
7
8- ShowWindow(true);
9+ // We are not calling ShowWindow () as this window
10+ // isn't really visible
11 PushToBack();
12 // Hack to create the X Window as soon as possible.
13 EnableInputWindow(true, "XdndCollectionWindowImp");
14
15=== modified file 'plugins/unityshell/src/unityshell.cpp'
16--- plugins/unityshell/src/unityshell.cpp 2013-02-08 18:31:30 +0000
17+++ plugins/unityshell/src/unityshell.cpp 2013-02-10 09:01:22 +0000
18@@ -25,6 +25,8 @@
19 #include <Nux/BaseWindow.h>
20 #include <Nux/WindowCompositor.h>
21
22+#include <opengl/framebufferobject.h>
23+
24 #include <UnityCore/Variant.h>
25 #include <UnityCore/Lens.h>
26
27@@ -78,6 +80,8 @@
28 /* Set up vtable symbols */
29 COMPIZ_PLUGIN_20090315(unityshell, unity::UnityPluginVTable);
30
31+namespace cgl = compiz::opengl;
32+
33 namespace unity
34 {
35 using namespace launcher;
36@@ -150,6 +154,9 @@
37 , scale_just_activated_(false)
38 , big_tick_(0)
39 , screen_introspection_(screen)
40+ , ignore_redraw_request_(false)
41+ , previous_framebuffer_(nullptr)
42+ , directly_drawable_buffer_age_(0)
43 {
44 Timer timer;
45 #ifndef USE_GLES
46@@ -413,8 +420,17 @@
47 WindowManager& wm = WindowManager::Default();
48 wm.initiate_spread.connect(sigc::mem_fun(this, &UnityScreen::OnInitiateSpread));
49 wm.terminate_spread.connect(sigc::mem_fun(this, &UnityScreen::OnTerminateSpread));
50+ wm.initiate_expo.connect(sigc::mem_fun(this, &UnityScreen::DamagePanelShadow));
51+ wm.terminate_expo.connect(sigc::mem_fun(this, &UnityScreen::DamagePanelShadow));
52
53 AddChild(&screen_introspection_);
54+
55+ /* Setup our render target for scraping the blur texture */
56+ directly_drawable_fbo_.reset(cgl::createBlittableFramebufferObjectWithFallback(*screen,
57+ gScreen));
58+
59+ /* Track whole damage on the very first frame */
60+ cScreen->damageScreen();
61 }
62 }
63
64@@ -471,7 +487,6 @@
65 {
66 LOG_WARN(logger) << "Could not find key above tab!";
67 }
68-
69 }
70
71 void UnityScreen::OnInitiateSpread()
72@@ -490,6 +505,31 @@
73 UnityWindow::CleanupSharedTextures();
74 }
75
76+void UnityScreen::DamagePanelShadow()
77+{
78+ CompRect panelShadow;
79+
80+ for (CompOutput &output : screen->outputDevs())
81+ {
82+ FillShadowRectForOutput(panelShadow, &output);
83+ cScreen->damageRegion(CompRegion(panelShadow));
84+ }
85+}
86+
87+void UnityScreen::OnViewHidden(nux::BaseWindow *bw)
88+{
89+ /* Count this as regular damage */
90+ nux::Geometry geometry(bw->GetAbsoluteGeometry());
91+ cScreen->damageRegion(CompRegion (geometry.x,
92+ geometry.y,
93+ geometry.width,
94+ geometry.height));
95+}
96+
97+void UnityScreen::OnViewShown(nux::BaseWindow *bw)
98+{
99+}
100+
101 void UnityScreen::EnsureSuperKeybindings()
102 {
103 for (auto action : _shortcut_actions)
104@@ -581,7 +621,18 @@
105 panel_shadow_matrix_ = matrix;
106 }
107
108-void UnityScreen::paintPanelShadow(const CompRegion& clip)
109+void UnityScreen::FillShadowRectForOutput(CompRect &shadowRect,
110+ CompOutput *output)
111+{
112+ float panel_h = static_cast<float>(panel_style_.panel_height);
113+ float shadowX = output->x();
114+ float shadowY = output->y() + panel_h;
115+ float shadowWidth = output->width();
116+ float shadowHeight = _shadow_texture[0]->height();
117+ shadowRect.setGeometry(shadowX, shadowY, shadowWidth, shadowHeight);
118+}
119+
120+void UnityScreen::PaintPanelShadow(const CompRegion& clip)
121 {
122 if (panel_controller_->opacity() == 0.0f)
123 return;
124@@ -597,17 +648,13 @@
125 if (fullscreenRegion.contains(*output))
126 return;
127
128- float panel_h = static_cast<float>(panel_style_.panel_height);
129-
130 // You have no shadow texture. But how?
131 if (_shadow_texture.empty() || !_shadow_texture[0])
132 return;
133
134- float shadowX = output->x();
135- float shadowY = output->y() + panel_h;
136- float shadowWidth = output->width();
137- float shadowHeight = _shadow_texture[0]->height();
138- CompRect shadowRect(shadowX, shadowY, shadowWidth, shadowHeight);
139+ CompRect shadowRect;
140+
141+ FillShadowRectForOutput(shadowRect, output);
142
143 CompRegion redraw(clip);
144 redraw &= shadowRect;
145@@ -669,10 +716,10 @@
146 float y2 = r.y2();
147
148 // Texture coordinates of the above rectangle:
149- float tx1 = (x1 - shadowX) / shadowWidth;
150- float ty1 = (y1 - shadowY) / shadowHeight;
151- float tx2 = (x2 - shadowX) / shadowWidth;
152- float ty2 = (y2 - shadowY) / shadowHeight;
153+ float tx1 = (x1 - shadowRect.x()) / shadowRect.width();
154+ float ty1 = (y1 - shadowRect.y()) / shadowRect.height();
155+ float tx2 = (x2 - shadowRect.x()) / shadowRect.width();
156+ float ty2 = (y2 - shadowRect.y()) / shadowRect.height();
157
158 vertexData = {
159 x1, y1, 0,
160@@ -739,26 +786,59 @@
161
162 DrawTopPanelBackground();
163
164- auto gpu_device = nux::GetGraphicsDisplay()->GetGpuDevice();
165-
166- if (BackgroundEffectHelper::HasDirtyHelpers())
167+ if (previous_framebuffer_)
168 {
169- auto graphics_engine = nux::GetGraphicsDisplay()->GetGraphicsEngine();
170- nux::ObjectPtr<nux::IOpenGLTexture2D> bg_texture =
171- graphics_engine->CreateTextureFromBackBuffer(0, 0,
172- screen->width(),
173- screen->height());
174- gpu_device->backup_texture0_ = bg_texture;
175+ gScreen->bindFramebufferForDrawing(previous_framebuffer_);
176+
177+ CompRegion direct_draw_region =
178+ CompRegionRef (output->region()) & buffered_compiz_damage_last_frame_;
179+ CompRect::vector direct_draw_rects (direct_draw_region.rects());
180+
181+ /* Set viewport to fullscreen */
182+ glViewport (0, 0, screen->width(), screen->height());
183+
184+ for (const CompRect &r : direct_draw_rects)
185+ {
186+ /* For now we should invert the y co-ords */
187+ directly_drawable_fbo_->directDraw (r,
188+ r,
189+ compiz::opengl::ColorData,
190+ compiz::opengl::Fast);
191+ }
192+
193+ glViewport(output->x(),
194+ screen->height () - output->y2(),
195+ output->width(),
196+ screen->height());
197+
198+ nux::ObjectPtr<nux::IOpenGLTexture2D> bg_texture
199+ (nux::GetGraphicsDisplay()->GetGpuDevice()->CreateTexture2DFromID(directly_drawable_fbo_->tex()->name(),
200+ screen->width(), screen->height(),
201+ 0,
202+ nux::BITFMT_R8G8B8A8));
203+ nux::GetGraphicsDisplay()->GetGpuDevice()->backup_texture0_ = bg_texture;
204+ previous_framebuffer_ = nullptr;
205 }
206
207+ /* Bind the currently bound draw framebuffer to the read framebuffer binding.
208+ * The reason being that we want to use the results of nux images being
209+ * drawn to this framebuffer in glCopyTexSubImage2D operations */
210+ gScreen->bindFramebufferForReading(gScreen->drawFramebuffer());
211+
212 nux::Geometry geo(0, 0, screen->width (), screen->height ());
213 nux::Geometry outputGeo(output->x (), output->y (), output->width (), output->height ());
214 BackgroundEffectHelper::monitor_rect_ = geo;
215
216- GLint fboID;
217+ GLint dFBOID, rFBOID;
218 // Nux renders to the referenceFramebuffer when it's embedded.
219- glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fboID);
220- wt->GetWindowCompositor().SetReferenceFramebuffer(fboID, outputGeo);
221+#ifndef USE_GLES
222+ glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING_EXT, &dFBOID);
223+ glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING_EXT, &rFBOID);
224+#else
225+ glGetIntegerv(GL_FRAMEBUFFER_BINDING, &dFBOID);
226+ rFBOID = dFBOID;
227+#endif
228+ wt->GetWindowCompositor().SetReferenceFramebuffer(dFBOID, rFBOID, outputGeo);
229
230 nuxPrologue();
231 _in_paint = true;
232@@ -1260,6 +1340,7 @@
233 doShellRepaint = force ||
234 ( !region.isEmpty() &&
235 ( !wt->GetDrawList().empty() ||
236+ !wt->GetPresentationListGeometries().empty() ||
237 (mask & PAINT_SCREEN_FULL_MASK)
238 )
239 );
240@@ -1272,6 +1353,14 @@
241 fullscreenRegion = CompRegion();
242 nuxRegion = CompRegion();
243
244+ // bind the framebuffer if we plan to paint nux on this frame
245+ if (doShellRepaint && BackgroundEffectHelper::HasDirtyHelpers())
246+ {
247+ previous_framebuffer_ =
248+ gScreen->bindFramebufferForDrawing(directly_drawable_fbo_.get());
249+ directly_drawable_buffer_age_ = 0;
250+ }
251+
252 /* glPaintOutput is part of the opengl plugin, so we need the GLScreen base class. */
253 ret = gScreen->glPaintOutput(attrib, transform, region, output, mask);
254
255@@ -1294,8 +1383,86 @@
256 unsigned int mask)
257 {
258 allowWindowPaint = false;
259+
260+ /* PAINT_SCREEN_FULL_MASK means that we are ignoring the damage
261+ * region and redrawing the whole screen, so we should make all
262+ * nux windows be added to the presentation list that intersect
263+ * this output.
264+ *
265+ * However, damaging nux has a side effect of notifying compiz
266+ * through onRedrawRequested that we need to queue another frame.
267+ * In most cases that would be desirable, and in the case where
268+ * we did that in damageCutoff, it would not be a problem as compiz
269+ * does not queue up new frames for damage that can be processed
270+ * on the current frame. However, we're now past damage cutoff, but
271+ * a change in circumstances has required that we redraw all the nux
272+ * windows on this frame. As such, we need to ensure that damagePending
273+ * is not called as a result of queuing windows for redraw, as that
274+ * would effectively result in a damage feedback loop in plugins that
275+ * require screen transformations (eg, new frame -> plugin redraws full
276+ * screen -> we reach this point and request another redraw implicitly)
277+ */
278+ if (mask & PAINT_SCREEN_FULL_MASK)
279+ {
280+ ignore_redraw_request_ = true;
281+ compizDamageNux(CompRegionRef(output->region()));
282+ ignore_redraw_request_ = false;
283+
284+ std::vector<nux::Geometry> dirty = wt->GetPresentationListGeometries();
285+ }
286+
287 gScreen->glPaintTransformedOutput(attrib, transform, region, output, mask);
288- paintPanelShadow(region);
289+ PaintPanelShadow(region);
290+}
291+
292+
293+
294+void UnityScreen::damageCutoff()
295+{
296+ /* If there are enabled helpers, we want to apply damage
297+ * based on how old our tracking fbo is since we may need
298+ * to redraw some of the blur regions if there has been
299+ * damage since we last bound it
300+ *
301+ * XXX: Unfortunately there's a nasty feedback loop here, and not
302+ * a whole lot we can do about it. If part of the damage from any frame
303+ * intersects a nux window, we have to mark the entire region that the
304+ * nux window covers as damaged, because nux does not have any concept
305+ * of geometry clipping. That damage will feed back to us on the next frame.
306+ */
307+ if (BackgroundEffectHelper::HasEnabledHelpers())
308+ cScreen->applyDamageForFrameAge (directly_drawable_buffer_age_);
309+
310+ /* Determine nux region damage last */
311+ cScreen->damageCutoff();
312+
313+ CompRegion damage_buffer, last_damage_buffer;
314+
315+ do
316+ {
317+ last_damage_buffer = damage_buffer;
318+
319+ /* First apply any damage accumulated to nux to see
320+ * what windows need to be redrawn there */
321+ compizDamageNux(buffered_compiz_damage_this_frame_);
322+
323+ /* Apply the redraw regions to compiz so that we can
324+ * draw this frame with that region included */
325+ determineNuxDamage(damage_buffer);
326+
327+ /* We want to track the nux damage here as we will use it to
328+ * determine if we need to present other nux windows too */
329+ cScreen->damageRegion(damage_buffer);
330+
331+ /* If we had to put more damage into the damage buffer then
332+ * damage compiz with it and keep going */
333+ } while (last_damage_buffer != damage_buffer);
334+
335+ /* Clear damage buffer */
336+ buffered_compiz_damage_last_frame_ = buffered_compiz_damage_this_frame_;
337+ buffered_compiz_damage_this_frame_ = CompRegion();
338+
339+ wt->ForeignFrameCutoff();
340 }
341
342 void UnityScreen::preparePaint(int ms)
343@@ -1311,8 +1478,6 @@
344 didShellRepaint = false;
345 panelShadowPainted = CompRegion();
346 firstWindowAboveShell = NULL;
347-
348- compizDamageNux(cScreen->currentDamage());
349 }
350
351 void UnityScreen::donePaint()
352@@ -1326,11 +1491,20 @@
353 * I think this is a Nux bug. ClearDrawList should ideally also mark all
354 * the queued views as draw_cmd_queued_=false.
355 */
356+
357+ /* To prevent any potential overflow problems, we are assuming here
358+ * that compiz caps the maximum number of frames tracked at 10, so
359+ * don't increment the age any more than 11 */
360+ if (directly_drawable_buffer_age_ < 11)
361+ ++directly_drawable_buffer_age_;
362+
363 if (didShellRepaint)
364 wt->ClearDrawList();
365
366+ wt->ForeignFrameEnded();
367+
368 if (animation_controller_->HasRunningAnimations())
369- nuxDamageCompiz();
370+ onRedrawRequested();
371
372 std::list <ShowdesktopHandlerWindowInterface *> remove_windows;
373
374@@ -1376,103 +1550,52 @@
375 }
376 }
377
378- auto const& launchers = launcher_controller_->launchers();
379- for (auto const& launcher : launchers)
380- {
381- if (!launcher->Hidden())
382- {
383- nux::Geometry const& geo = launcher->GetAbsoluteGeometry();
384- CompRegion launcher_region(geo.x, geo.y, geo.width, geo.height);
385-
386- if (damage.intersects(launcher_region))
387- launcher->QueueDraw();
388-
389- nux::ObjectPtr<nux::View> const& tooltip = launcher->GetActiveTooltip();
390-
391- if (tooltip)
392- {
393- nux::Geometry const& g = tooltip->GetAbsoluteGeometry();
394- CompRegion tip_region(g.x, g.y, g.width, g.height);
395-
396- if (damage.intersects(tip_region))
397- tooltip->QueueDraw();
398- }
399-
400- nux::ObjectPtr<LauncherDragWindow> const& dragged_icon = launcher->GetDraggedIcon();
401-
402- if (dragged_icon)
403- {
404- nux::Geometry const& g = dragged_icon->GetAbsoluteGeometry();
405- CompRegion icon_region(g.x, g.y, g.width, g.height);
406-
407- if (damage.intersects(icon_region))
408- dragged_icon->QueueDraw();
409- }
410- }
411- }
412-
413- std::vector<nux::View*> const& panels(panel_controller_->GetPanelViews());
414- for (nux::View* view : panels)
415- {
416- nux::Geometry const& geo = view->GetAbsoluteGeometry();
417-
418- CompRegion panel_region(geo.x, geo.y, geo.width, geo.height);
419-
420- if (damage.intersects(panel_region))
421- view->QueueDraw();
422- }
423-
424- QuicklistManager* qm = QuicklistManager::Default();
425- if (qm)
426- {
427- auto const& view = qm->Current();
428-
429- if (view)
430- {
431- nux::Geometry const& geo = view->GetAbsoluteGeometry();
432- CompRegion quicklist_region(geo.x, geo.y, geo.width, geo.height);
433-
434- if (damage.intersects(quicklist_region))
435- view->QueueDraw();
436- }
437- }
438-
439- if (switcher_controller_ && switcher_controller_->Visible())
440- {
441- auto const& view = switcher_controller_->GetView();
442-
443- if (G_LIKELY(view))
444- {
445- nux::Geometry const& geo = view->GetAbsoluteGeometry();
446- CompRegion switcher_region(geo.x, geo.y, geo.width, geo.height);
447-
448- if (damage.intersects(switcher_region))
449- view->QueueDraw();
450- }
451+ /* Ask nux to present anything in our damage region
452+ *
453+ * Note: This is using a new nux API, to "present" windows
454+ * to the screen, as opposed to drawing them. The difference is
455+ * important. The former will just draw the window backing texture
456+ * directly to the screen, the latter will re-draw the entire window.
457+ *
458+ * The former is a lot faster, do not use QueueDraw unless the contents
459+ * of the window need to be re-drawn.
460+ */
461+ CompRect::vector rects (damage.rects());
462+ for (const CompRect &r : rects)
463+ {
464+ nux::Geometry g (r.x(), r.y(), r.width(), r.height());
465+ wt->PresentWindowsIntersectingGeometryOnThisFrame(g);
466 }
467 }
468
469 /* Grab changed nux regions and add damage rects for them */
470-void UnityScreen::nuxDamageCompiz()
471+void UnityScreen::determineNuxDamage(CompRegion &nux_damage)
472 {
473- /*
474- * If Nux is going to redraw anything then we have to tell Compiz to
475- * redraw everything. This is because Nux has a bad habit (bug??) of drawing
476- * more than just the regions of its DrawList. (LP: #1036519)
477- *
478- * Forunately, this does not happen on most frames. Only when the Unity
479- * Shell needs to redraw something.
480- *
481- * TODO: Try to figure out why redrawing the panel makes the launcher also
482- * redraw even though the launcher's geometry is not in DrawList, and
483- * stop it. Then maybe we can revert back to the old code below #else.
484- */
485- std::vector<nux::Geometry> const& dirty = wt->GetDrawList();
486- if (!dirty.empty() || animation_controller_->HasRunningAnimations())
487+ if (!launcher_controller_ || !dash_controller_)
488+ return;
489+
490+ std::vector<nux::Geometry> dirty = wt->GetPresentationListGeometries();
491+
492+ for (auto const& geo : dirty)
493+ nux_damage += CompRegion(geo.x, geo.y, geo.width, geo.height);
494+
495+ /* Special case, we need to redraw the panel shadow on panel updates */
496+ for (auto const& panel_geo : panel_controller_->GetGeometries())
497 {
498- cScreen->damageRegionSetEnabled(this, false);
499- cScreen->damageScreen();
500- cScreen->damageRegionSetEnabled(this, true);
501+ CompRect panel_rect (panel_geo.x,
502+ panel_geo.y,
503+ panel_geo.width,
504+ panel_geo.height);
505+
506+ if (nux_damage.intersects(panel_rect))
507+ {
508+ foreach (CompOutput &o, screen->outputDevs())
509+ {
510+ CompRect shadowRect;
511+ FillShadowRectForOutput(shadowRect, &o);
512+ nux_damage += shadowRect;
513+ }
514+ }
515 }
516 }
517
518@@ -1712,7 +1835,7 @@
519
520 void UnityScreen::damageRegion(const CompRegion &region)
521 {
522- compizDamageNux(region);
523+ buffered_compiz_damage_this_frame_ += region;
524 cScreen->damageRegion(region);
525 }
526
527@@ -2606,7 +2729,7 @@
528 window->id() == active_window &&
529 window->type() != CompWindowTypeDesktopMask)
530 {
531- uScreen->paintPanelShadow(region);
532+ uScreen->PaintPanelShadow(region);
533 }
534
535 bool ret = gWindow->glDraw(matrix, attrib, region, mask);
536@@ -2615,7 +2738,7 @@
537 (active_window == 0 || active_window == window->id()) &&
538 (window->type() == CompWindowTypeDesktopMask))
539 {
540- uScreen->paintPanelShadow(region);
541+ uScreen->PaintPanelShadow(region);
542 }
543
544 return ret;
545@@ -2938,11 +3061,15 @@
546 nux::ColorLayer background(nux::color::Transparent);
547 static_cast<nux::WindowThread*>(thread)->SetWindowBackgroundPaintLayer(&background);
548 LOG_INFO(logger) << "UnityScreen::initUnity: " << timer.ElapsedSeconds() << "s";
549+
550+ nux::GetWindowCompositor().sigHiddenViewWindow.connect (sigc::mem_fun(self, &UnityScreen::OnViewHidden));
551+ nux::GetWindowCompositor().sigVisibleViewWindow.connect (sigc::mem_fun(self, &UnityScreen::OnViewShown));
552 }
553
554 void UnityScreen::onRedrawRequested()
555 {
556- nuxDamageCompiz();
557+ if (!ignore_redraw_request_)
558+ cScreen->damagePending();
559 }
560
561 /* Handle option changes and plug that into nux windows */
562@@ -3132,6 +3259,8 @@
563 << " h=" << primary_monitor_().height;
564
565 needsRelayout = false;
566+
567+ DamagePanelShadow ();
568 }
569
570 /* Handle changes in the number of workspaces by showing the switcher
571@@ -3163,6 +3292,17 @@
572 {
573 screen->outputChangeNotify ();
574
575+ /* Unbind and reallocate the directly drawable fbo */
576+ cgl::BindableFramebuffer *old_read_buffer =
577+ gScreen->bindFramebufferForReading(gScreen->backbuffer());
578+ cgl::BindableFramebuffer *old_draw_buffer =
579+ gScreen->bindFramebufferForDrawing(gScreen->backbuffer());
580+
581+ directly_drawable_fbo_->allocate (*screen, NULL, GL_BGRA);
582+
583+ gScreen->bindFramebufferForReading(old_read_buffer);
584+ gScreen->bindFramebufferForDrawing(old_draw_buffer);
585+
586 ScheduleRelayout(500);
587 }
588
589
590=== modified file 'plugins/unityshell/src/unityshell.h'
591--- plugins/unityshell/src/unityshell.h 2013-02-06 17:30:10 +0000
592+++ plugins/unityshell/src/unityshell.h 2013-02-10 09:01:22 +0000
593@@ -96,9 +96,10 @@
594
595 /* nux draw wrapper */
596 void paintDisplay();
597- void paintPanelShadow(const CompRegion& clip);
598+ void PaintPanelShadow(const CompRegion& clip);
599 void setPanelShadowMatrix(const GLMatrix& matrix);
600
601+ void damageCutoff();
602 void preparePaint (int ms);
603 void paintFboForOutput (CompOutput *output);
604 void donePaint ();
605@@ -214,7 +215,7 @@
606 void initLauncher();
607
608 void compizDamageNux(CompRegion const& region);
609- void nuxDamageCompiz();
610+ void determineNuxDamage(CompRegion &nux_damage);
611
612 void onRedrawRequested();
613 void Relayout();
614@@ -236,6 +237,13 @@
615 void OnInitiateSpread();
616 void OnTerminateSpread();
617
618+ void DamagePanelShadow();
619+
620+ void OnViewHidden(nux::BaseWindow *bw);
621+ void OnViewShown(nux::BaseWindow *bw);
622+
623+ void RestoreWindow(GVariant* data);
624+
625 bool SaveInputThenFocus(const guint xid);
626
627 void OnPanelStyleChanged();
628@@ -246,6 +254,8 @@
629 bool TopPanelBackgroundTextureNeedsUpdate() const;
630 void UpdateTopPanelBackgroundTexture();
631
632+ void FillShadowRectForOutput(CompRect &shadowRect,
633+ CompOutput *output);
634 unsigned CompizModifiersToNux(unsigned input) const;
635 unsigned XModifiersToNux(unsigned input) const;
636
637@@ -343,6 +353,14 @@
638 UBusManager ubus_manager_;
639 glib::SourceManager sources_;
640
641+ CompRegion buffered_compiz_damage_this_frame_;
642+ CompRegion buffered_compiz_damage_last_frame_;
643+ bool ignore_redraw_request_;
644+
645+ std::unique_ptr <compiz::opengl::DirectDrawObject> directly_drawable_fbo_;
646+ compiz::opengl::BindableFramebuffer *previous_framebuffer_;
647+ unsigned int directly_drawable_buffer_age_;
648+
649 friend class UnityWindow;
650 };
651
652
653=== modified file 'unity-shared/BackgroundEffectHelper.cpp'
654--- unity-shared/BackgroundEffectHelper.cpp 2013-01-29 13:20:11 +0000
655+++ unity-shared/BackgroundEffectHelper.cpp 2013-02-10 09:01:22 +0000
656@@ -92,9 +92,7 @@
657 for (BackgroundEffectHelper * bg_effect_helper : registered_list_)
658 {
659 if (bg_effect_helper->enabled)
660- {
661 return true;
662- }
663 }
664
665 return false;