Index: unity-5.12/plugins/unityshell/src/unityshell.h =================================================================== --- unity-5.12.orig/plugins/unityshell/src/unityshell.h 2012-07-13 04:31:24.985819836 +0800 +++ unity-5.12/plugins/unityshell/src/unityshell.h 2012-07-13 04:50:59.132903966 +0800 @@ -111,6 +111,7 @@ const char *eventName, CompOption::Vector &o); + void damageRegion(const CompRegion ®ion); /* paint on top of all windows if we could not find a window * to paint underneath */ @@ -132,9 +133,6 @@ CompOutput*, unsigned int); - /* Pop our InputOutput windows from the paint list */ - const CompWindowList& getWindowPaintList(); - /* handle X11 events */ void handleEvent(XEvent*); @@ -211,7 +209,10 @@ static gboolean initPluginActions(gpointer data); void initLauncher(); - void damageNuxRegions(); + + void compizDamageNux(CompRegion const& region); + void nuxDamageCompiz(); + void onRedrawRequested(); void Relayout(); @@ -256,7 +257,6 @@ bool enable_shortcut_overlay_; std::unique_ptr gesture_engine_; - nux::Geometry lastTooltipArea; bool needsRelayout; bool _in_paint; guint32 relayoutSourceId; @@ -275,11 +275,17 @@ /* handle paint order */ bool doShellRepaint; + bool didShellRepaint; bool allowWindowPaint; bool damaged; bool _key_nav_mode_requested; CompOutput* _last_output; - CompWindowList _withRemovedNuxWindows; + + CompRegion nuxRegion; + CompRegion fullscreenRegion; + CompWindow* firstWindowAboveShell; + + CompRegion aboveShell; nux::Property primary_monitor_; Index: unity-5.12/plugins/unityshell/src/unityshell.cpp =================================================================== --- unity-5.12.orig/plugins/unityshell/src/unityshell.cpp 2012-07-13 04:31:24.893821801 +0800 +++ unity-5.12/plugins/unityshell/src/unityshell.cpp 2012-07-13 04:32:27.156492251 +0800 @@ -115,6 +115,7 @@ , _redraw_handle(0) , newFocusedWindow(nullptr) , doShellRepaint(false) + , didShellRepaint(false) , allowWindowPaint(false) , damaged(false) , _key_nav_mode_requested(false) @@ -904,6 +905,7 @@ } doShellRepaint = false; + didShellRepaint = true; damaged = false; } @@ -1206,7 +1208,15 @@ { bool ret; - doShellRepaint = true; + /* + * Very important! + * Don't waste GPU and CPU rendering the shell on every frame if you don't + * need to. Doing so on every frame causes Nux to hog the GPU and slow down + * ALL rendering. (LP: #988079) + */ + bool force = forcePaintOnTop() || PluginAdapter::Default()->IsExpoActive(); + doShellRepaint = force || !(region.isEmpty() || wt->GetDrawList().empty()); + allowWindowPaint = true; _last_output = output; paint_panel_ = false; @@ -1222,13 +1232,21 @@ * attempts to bind it will only increment * its bind reference so make sure that * you always unbind as much as you bind */ - _fbo->bind (nux::Geometry (output->x (), output->y (), output->width (), output->height ())); + if (doShellRepaint) + _fbo->bind (nux::Geometry (output->x (), output->y (), output->width (), output->height ())); #endif + // CompRegion has no clear() method. So this is the fastest alternative. + aboveShell = CompRegion(); + nuxRegion = CompRegion(); + /* glPaintOutput is part of the opengl plugin, so we need the GLScreen base class. */ ret = gScreen->glPaintOutput(attrib, transform, region, output, mask); #ifndef USE_GLES + if (doShellRepaint && !force && aboveShell.contains(*output)) + doShellRepaint = false; + if (doShellRepaint) paintDisplay(region, transform, mask); #endif @@ -1281,16 +1299,31 @@ for (ShowdesktopHandlerWindowInterface *wi : ShowdesktopHandler::animating_windows) wi->HandleAnimations (ms); + // Workaround Nux bug LP: #1014610: if (damaged) { damaged = false; - damageNuxRegions(); + nuxDamageCompiz(); } + compizDamageNux(cScreen->currentDamage()); + didShellRepaint = false; } void UnityScreen::donePaint() { + /* + * It's only safe to clear the draw list if drawing actually occurred + * (i.e. the shell was not obscured behind a fullscreen window). + * If you clear the draw list and drawing has not occured then you'd be + * left with all your views thinking they're queued for drawing still and + * would refuse to redraw when you return from fullscreen. + * I think this is a Nux bug. ClearDrawList should ideally also mark all + * the queued views as draw_cmd_queued_=false. + */ + if (didShellRepaint) + wt->ClearDrawList(); + std::list remove_windows; for (ShowdesktopHandlerWindowInterface *wi : ShowdesktopHandler::animating_windows) @@ -1311,35 +1344,116 @@ cScreen->donePaint (); } +void UnityScreen::compizDamageNux(CompRegion const& damage) +{ + if (!launcher_controller_) + return; + + /* + * Prioritise user interaction over active blur updates. So the general + * slowness of the active blur doesn't affect the UI interaction performance. + * + * Also, BackgroundEffectHelper::ProcessDamage() is causing a feedback loop + * while the dash is open. Calling it results in the NEXT frame (and the + * current one?) to get some damage. This GetDrawList().empty() check avoids + * that feedback loop and allows us to idle correctly. + */ + if (wt->GetDrawList().empty()) + { + CompRect::vector const& rects(damage.rects()); + for (CompRect const& r : rects) + { + nux::Geometry geo(r.x(), r.y(), r.width(), r.height()); + BackgroundEffectHelper::ProcessDamage(geo); + } + } + + auto launchers = launcher_controller_->launchers(); + for (auto launcher : launchers) + { + if (!launcher->Hidden()) + { + nux::Geometry geo = launcher->GetAbsoluteGeometry(); + CompRegion launcher_region(geo.x, geo.y, geo.width, geo.height); + if (damage.intersects(launcher_region)) + launcher->QueueDraw(); + nux::ObjectPtr tooltip = launcher->GetActiveTooltip(); + if (!tooltip.IsNull()) + { + nux::Geometry tip = tooltip->GetAbsoluteGeometry(); + CompRegion tip_region(tip.x, tip.y, tip.width, tip.height); + if (damage.intersects(tip_region)) + tooltip->QueueDraw(); + } + } + } + + std::vector const& panels(panel_controller_->GetPanelViews()); + for (nux::View* view : panels) + { + nux::Geometry geo = view->GetAbsoluteGeometry(); + CompRegion panel_region(geo.x, geo.y, geo.width, geo.height); + if (damage.intersects(panel_region)) + view->QueueDraw(); + } + + QuicklistManager* qm = QuicklistManager::Default(); + if (qm) + { + QuicklistView* view = qm->Current(); + if (view) + { + nux::Geometry geo = view->GetAbsoluteGeometry(); + CompRegion quicklist_region(geo.x, geo.y, geo.width, geo.height); + if (damage.intersects(quicklist_region)) + view->QueueDraw(); + } + } +} + /* Grab changed nux regions and add damage rects for them */ -void UnityScreen::damageNuxRegions() +void UnityScreen::nuxDamageCompiz() { - CompRegion nux_damage; + /* + * WARNING: Nux bug LP: #1014610 (unbounded DrawList growth) will cause + * this code to be called far too often in some cases and + * Unity will appear to freeze for a while. Please ensure you + * have Nux 3.0+ with the fix for LP: #1014610. + */ - if (damaged) + if (!launcher_controller_ || !dash_controller_) return; - std::vector dirty = wt->GetDrawList(); - damaged = true; + CompRegion nux_damage; + + std::vector const& dirty = wt->GetDrawList(); + for (auto geo : dirty) + nux_damage += CompRegion(geo.x, geo.y, geo.width, geo.height); - for (std::vector::iterator it = dirty.begin(), end = dirty.end(); - it != end; ++it) + if (launcher_controller_->IsOverlayOpen()) { - nux::Geometry const& geo = *it; + nux::BaseWindow* dash_window = dash_controller_->window(); + nux::Geometry const& geo = dash_window->GetAbsoluteGeometry(); nux_damage += CompRegion(geo.x, geo.y, geo.width, geo.height); } - nux::Geometry geo = wt->GetWindowCompositor().GetTooltipMainWindowGeometry(); - nux_damage += CompRegion(geo.x, geo.y, geo.width, geo.height); + auto launchers = launcher_controller_->launchers(); + for (auto launcher : launchers) + { + if (!launcher->Hidden()) + { + nux::ObjectPtr tooltip = launcher->GetActiveTooltip(); + if (!tooltip.IsNull()) + { + nux::Geometry const& g = tooltip->GetAbsoluteGeometry(); + nux_damage += CompRegion(g.x, g.y, g.width, g.height); + } + } + } - geo = lastTooltipArea; - nux_damage += CompRegion(lastTooltipArea.x, lastTooltipArea.y, - lastTooltipArea.width, lastTooltipArea.height); + cScreen->damageRegionSetEnabled(this, false); cScreen->damageRegion(nux_damage); - - wt->ClearDrawList(); - - lastTooltipArea = geo; + cScreen->damageRegionSetEnabled(this, true); } /* handle X Events */ @@ -1536,6 +1650,12 @@ } } +void UnityScreen::damageRegion(const CompRegion ®ion) +{ + compizDamageNux(region); + cScreen->damageRegion(region); +} + void UnityScreen::handleCompizEvent(const char* plugin, const char* event, CompOption::Vector& option) @@ -2144,13 +2264,14 @@ return false; } +/* const CompWindowList& UnityScreen::getWindowPaintList() { CompWindowList& pl = _withRemovedNuxWindows = cScreen->getWindowPaintList(); pl.remove_if(isNuxWindow); return pl; -} +} */ void UnityScreen::RaiseInputWindows() { @@ -2176,6 +2297,42 @@ const CompRegion& region, unsigned int mask) { + /* + * The occlusion pass tests windows from TOP to BOTTOM. That's opposite to + * the actual painting loop. + * + * Detect uScreen->fullscreenRegion here. That represents the region which + * fully covers the shell on its output. It does not include regular windows + * stacked above the shell like DnD icons or Onboard etc. + */ + if (isNuxWindow(window)) + { + if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK) + { + uScreen->nuxRegion += window->geometry(); + uScreen->nuxRegion -= uScreen->fullscreenRegion; + } + return false; // Ensure nux windows are never painted by compiz + } + else if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK) + { + static const unsigned int nonOcclusionBits = + PAINT_WINDOW_TRANSLUCENT_MASK | + PAINT_WINDOW_TRANSFORMED_MASK | + PAINT_WINDOW_NO_CORE_INSTANCE_MASK; + if (!(mask & nonOcclusionBits) && + (window->state() & CompWindowStateFullscreenMask)) + // And I've been advised to test other things, but they don't work: + // && (attrib.opacity == OPAQUE)) <-- Doesn't work; Only set in glDraw + // && !window->alpha() <-- Doesn't work; Opaque windows often have alpha + { + uScreen->fullscreenRegion += window->geometry(); + uScreen->fullscreenRegion -= uScreen->nuxRegion; + } + if (uScreen->nuxRegion.isEmpty()) + uScreen->firstWindowAboveShell = window; + } + GLWindowPaintAttrib wAttrib = attrib; if (mMinimizeHandler) @@ -2210,7 +2367,7 @@ * and if so paint nux and stop us from painting * other windows or on top of the whole screen */ bool UnityWindow::glDraw(const GLMatrix& matrix, -#ifndef USE_GLES +#ifndef USE_MODERN_COMPIZ_GL GLFragment::Attrib& attrib, #else const GLWindowPaintAttrib& attrib, @@ -2234,28 +2391,17 @@ } } - if (uScreen->doShellRepaint && !uScreen->forcePaintOnTop ()) + if (uScreen->doShellRepaint && + !uScreen->forcePaintOnTop () && + window == uScreen->firstWindowAboveShell && + !uScreen->fullscreenRegion.contains(window->geometry()) + ) { - std::vector const& xwns = nux::XInputWindow::NativeHandleList(); - unsigned int size = xwns.size(); - - for (CompWindow* w = window; w && uScreen->doShellRepaint; w = w->prev) - { - auto id = w->id(); - - for (unsigned int i = 0; i < size; ++i) - { - if (xwns[i] == id) - { -#ifdef USE_GLES - uScreen->paintDisplay(); +#ifdef USE_MODERN_COMPIZ_GL + uScreen->paintDisplay(); #else - uScreen->paintDisplay(region, matrix, mask); + uScreen->paintDisplay(region, matrix, mask); #endif - break; - } - } - } } if (window->type() == CompWindowTypeDesktopMask) @@ -2560,17 +2706,7 @@ void UnityScreen::onRedrawRequested() { - // disable blur updates so we dont waste perf. This can stall the blur during animations - // but ensures a smooth animation. - if (_in_paint) - { - if (!_redraw_handle) - _redraw_handle = g_idle_add_full (G_PRIORITY_DEFAULT, &UnityScreen::OnRedrawTimeout, this, NULL); - } - else - { - damageNuxRegions(); - } + nuxDamageCompiz(); } /* Handle option changes and plug that into nux windows */ Index: unity-5.12/plugins/unityshell/src/AbstractLauncherIcon.h =================================================================== --- unity-5.12.orig/plugins/unityshell/src/AbstractLauncherIcon.h 2012-07-13 04:31:24.961820349 +0800 +++ unity-5.12/plugins/unityshell/src/AbstractLauncherIcon.h 2012-07-13 04:32:27.156492251 +0800 @@ -218,6 +218,7 @@ sigc::signal needs_redraw; sigc::signal remove; + sigc::signal> tooltip_visible; sigc::signal visibility_changed; sigc::connection needs_redraw_connection; Index: unity-5.12/plugins/unityshell/src/Launcher.cpp =================================================================== --- unity-5.12.orig/plugins/unityshell/src/Launcher.cpp 2012-07-13 04:31:24.937820862 +0800 +++ unity-5.12/plugins/unityshell/src/Launcher.cpp 2012-07-13 04:32:27.160492165 +0800 @@ -1650,6 +1650,11 @@ } } +nux::ObjectPtr Launcher::GetActiveTooltip() const +{ + return _active_tooltip; +} + void Launcher::SetActionState(LauncherActionState actionstate) { @@ -1810,6 +1815,7 @@ EnsureAnimation(); icon->needs_redraw.connect(sigc::mem_fun(this, &Launcher::OnIconNeedsRedraw)); + icon->tooltip_visible.connect(sigc::mem_fun(this, &Launcher::OnTooltipVisible)); } void Launcher::OnIconRemoved(AbstractLauncherIcon::Ptr icon) @@ -1886,6 +1892,11 @@ EnsureAnimation(); } +void Launcher::OnTooltipVisible(nux::ObjectPtr view) +{ + _active_tooltip = view; +} + void Launcher::Draw(nux::GraphicsEngine& GfxContext, bool force_draw) { Index: unity-5.12/plugins/unityshell/src/Launcher.h =================================================================== --- unity-5.12.orig/plugins/unityshell/src/Launcher.h 2012-07-13 04:31:25.017819153 +0800 +++ unity-5.12/plugins/unityshell/src/Launcher.h 2012-07-13 04:32:27.160492165 +0800 @@ -99,6 +99,8 @@ return _parent; }; + nux::ObjectPtr GetActiveTooltip() const; // nullptr = no tooltip + virtual void RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); virtual void RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); virtual void RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); @@ -276,6 +278,7 @@ void OnOrderChanged(); void OnIconNeedsRedraw(AbstractLauncherIcon::Ptr icon); + void OnTooltipVisible(nux::ObjectPtr view); void OnOverlayHidden(GVariant* data); void OnOverlayShown(GVariant* data); @@ -369,6 +372,7 @@ nux::Point2 _mouse_position; nux::BaseWindow* _parent; + nux::ObjectPtr _active_tooltip; LauncherModel* _model; LauncherDragWindow* _drag_window; LauncherHideMachine* _hide_machine; Index: unity-5.12/plugins/unityshell/src/LauncherIcon.cpp =================================================================== --- unity-5.12.orig/plugins/unityshell/src/LauncherIcon.cpp 2012-07-13 04:31:24.917821290 +0800 +++ unity-5.12/plugins/unityshell/src/LauncherIcon.cpp 2012-07-13 04:32:27.160492165 +0800 @@ -524,6 +524,7 @@ LoadTooltip(); _tooltip->ShowTooltipWithTipAt(tip_x, tip_y); _tooltip->ShowWindow(!tooltip_text().empty()); + tooltip_visible.emit(_tooltip); } void @@ -545,6 +546,7 @@ if (_tooltip) _tooltip->ShowWindow(false); + tooltip_visible.emit(nux::ObjectPtr(nullptr)); } bool LauncherIcon::OpenQuicklist(bool select_first_item, int monitor) @@ -660,6 +662,7 @@ { if (_tooltip) _tooltip->ShowWindow(false); + tooltip_visible.emit(nux::ObjectPtr(nullptr)); } gboolean Index: unity-5.12/plugins/unityshell/src/PanelController.cpp =================================================================== --- unity-5.12.orig/plugins/unityshell/src/PanelController.cpp 2012-07-13 04:31:24.849822741 +0800 +++ unity-5.12/plugins/unityshell/src/PanelController.cpp 2012-07-13 04:32:27.160492165 +0800 @@ -48,6 +48,7 @@ void QueueRedraw(); std::vector GetTrayXids() const; + std::vector GetPanelViews() const; std::vector GetGeometries() const; // NOTE: nux::Property maybe? @@ -111,6 +112,15 @@ return xids; } +std::vector Controller::Impl::GetPanelViews() const +{ + std::vector views; + views.reserve(windows_.size()); + for (auto window: windows_) + views.push_back(ViewForWindow(window)); + return views; +} + std::vector Controller::Impl::GetGeometries() const { std::vector geometries; @@ -337,6 +347,11 @@ return pimpl->GetTrayXids(); } +std::vector Controller::GetPanelViews() const +{ + return pimpl->GetPanelViews(); +} + std::vector Controller::GetGeometries() const { return pimpl->GetGeometries(); Index: unity-5.12/plugins/unityshell/src/PanelController.h =================================================================== --- unity-5.12.orig/plugins/unityshell/src/PanelController.h 2012-07-13 04:31:24.873822229 +0800 +++ unity-5.12/plugins/unityshell/src/PanelController.h 2012-07-13 04:32:27.164492079 +0800 @@ -41,6 +41,7 @@ void QueueRedraw(); std::vector GetTrayXids() const; + std::vector GetPanelViews() const; std::vector GetGeometries() const; // NOTE: nux::Property maybe?