Merge lp:~vanvugt/unity/regionalDamage into lp:unity

Proposed by Daniel van Vugt
Status: Merged
Approved by: Tim Penhey
Approved revision: no longer in the source branch.
Merged at revision: 2470
Proposed branch: lp:~vanvugt/unity/regionalDamage
Merge into: lp:unity
Diff against target: 549 lines (+209/-74)
8 files modified
launcher/AbstractLauncherIcon.h (+1/-0)
launcher/Launcher.cpp (+11/-0)
launcher/Launcher.h (+4/-0)
launcher/LauncherIcon.cpp (+3/-0)
panel/PanelController.cpp (+15/-0)
panel/PanelController.h (+1/-0)
plugins/unityshell/src/unityshell.cpp (+166/-68)
plugins/unityshell/src/unityshell.h (+8/-6)
To merge this branch: bzr merge lp:~vanvugt/unity/regionalDamage
Reviewer Review Type Date Requested Status
Daniel d'Andrada (community) Needs Information
Tim Penhey (community) Approve
Sam Spilsbury (community) Approve
jenkins (community) continuous-integration Approve
Daniel van Vugt Abstain
Review via email: mp+112283@code.launchpad.net

This proposal supersedes a proposal from 2012-06-26.

Commit message

Stop Unity from redrawing the shell on every frame (ie. when it doesn't need
to). It had a severe impact on graphics performance. (LP: #988079)

This especially improves OpenGL application performance and multi-monitor
desktop performance. Because unity was previously slowing down compiz
rendering by 20-40% for each monitor added to the system. This slowdown no
longer occurs as only damaged areas of the unity shell are repainted. Now
unity will not have any impact on compiz rendering performance for most
video frames.

Coincidentally, this fixes a number of other bugs (linked).

Description of the change

For me, this branch eliminates the 25-30% slowdown (compared to regular compiz) when unity is running with a single monitor. With 2 monitors, this branch eliminates the 75%(!) slowdown experienced when unity is running. Extrapolate and hypothesize as you like.

Even simple things like scrolling in a web browser are nicer with this branch. Scrolling is smoother and faster when you don't have to render the shell on every frame.

In multi-monitor tests, unity was slowing down my system to the point of only rendering 30 FPS with two monitors. That's half what it should be. With this branch, I get 60 FPS like I should.

WARNING: This fix can only work if no window is redrawing _under_ a panel or launcher. If you have something drawing under the panel, launcher, tooltip or quicklist, then the shell will need to redraw and you won't get any performance benefit. Fixing that is a much bigger job and should be considered separate.

To post a comment you must log in.
Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal

227 + /*
228 + * The shell is hidden if there exists any window that fully covers
229 + * the output and is in front of all Nux windows on that output.
230 + * We could also check CompositeWindow::opacity() but that would be slower
231 + * and almost always pointless.
232 + */
233 + if (w->isMapped() &&
234 + w->isViewable() &&
235 + !w->inShowDesktopMode() && // Why must this != isViewable?
236 + w->geometry().contains(output))

What might be faster here is using the occlusion detection passes from core. That will take into account whether or not the window is truly occluded. Usually you can get this by checking gw->clip () in GLWindow.

This code won't work for windows that are semitransparent or have an alpha channel, which will work a little weird.

Revision history for this message
Andrea Azzarone (azzar1) wrote : Posted in a previous version of this proposal

Does it fix bug 977984 too?

Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote : Posted in a previous version of this proposal

I guess you can even remove this now

const std::string REDRAW_IDLE = "redraw-idle";

in: if (launcher_controller_.get()) no need for .get().

Overall looks good...

PS: pay attention to style, i.e.:
 bool UnityScreen::shellIsHidden(const CompOutput &output) -> bool UnityScreen::ShellIsHidden(CompOutput const& output)
 const std::vector<Window> &nuxwins(nux::XInputWindow::NativeHandleList()); -> std::vector<Window> const& nuxwins(nux::XInputWindow::NativeHandleList());

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

Marco, I think your style is wrong :)
In C and C++, & and * are part of the variable, not part of the type:
    A b, *c, d, &e(b);
That is why they usually go next to the variable and not the type.

Also, the Google C++ style guide that Unity is meant to use agrees:
    http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Reference_Arguments
but then it allows both styles :)
    http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Pointer_and_Reference_Expressions

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

Andrea, no I don't think this will fix bug 977984.

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

Sam, gw->priv->clip only seems to get updated after glPaintOutputs which looks too late. How does one use clip() normally?

shellIsHidden is designed to be fast. And it is AFAIK. Yes, I did already add a comment about transparent windows. But we're only talking about fullscreen windows here. And I don't think the case of transparent or alpha fullscreen windows is one that we should need to waste time handling. If you make a fullscreen window transparent then you won't see the shell behind it. Does that matter?

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

Actually, it does matter. The whole point of this proposal is to avoid rendering the shell because it hogs so much GPU. So I think we should not be rendering the shell if it is stacked below a transparent fullscreen window.

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

Just noticed a bug with NVIDIA:
Un-fullscreening a window does not damage the screen (!?) so the shell doesn't repaint until something changes or you use it. Not sure about the most elegant fix. It looks like a compiz bug, but I haven't yet proven it.

Revision history for this message
Daniel van Vugt (vanvugt) : Posted in a previous version of this proposal
review: Needs Fixing
Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote : Posted in a previous version of this proposal

> Marco, I think your style is wrong :)
> In C and C++, & and * are part of the variable, not part of the type:
> A b, *c, d, &e(b);
> That is why they usually go next to the variable and not the type.

I know, and that's how I used to do before, but the Unity style guide is different, see:
http://bazaar.launchpad.net/~unity-team/unity/trunk/view/head:/guides/cppguide.xml
(recently updated by Tim) http://bazaar.launchpad.net/~unity-team/unity/trunk/revision/2378

So here we use:
PointerType* ptr;
Object const& obj = ...;

Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal
Download full text (4.2 KiB)

> Sam, gw->priv->clip only seems to get updated after glPaintOutputs which looks
> too late. How does one use clip() normally?

The clip region is updated after the occlusion pass. You are right, this happens within paintOutputRegion and not paintOutputs like I thought.

I feel like there are two options here:

1. Framebuffer object rebinds are not condition on whether or not the shell is repainting, but just as it is now with BackgroundEffectHelper::HasDirtyHelpers (). That leaves the problem of windows on top of the shell. At the moment, the damage collection code examines all damage events, but we don't care about stuff underneath the shell. As such, you could probably ignore any damage events coming in between PaintDisplay and glPaintOutput (damageRegionSetEnabled (false)). I don't think this will handle the case of fullscreen windows on top of the shell very well however. In compiz at least, we'd need a concept of layered damage, which is not trivial as it requires all damage to be tied to a particular object.

At this point, you can determine whether or not to paint the shell when you actually hit a nux window. This again, depends on being able to see nux windows in the paint stack (see lp:~smspillaz/unity/unity.less-paint-insanity). I guess at the moment, you could use the heuristic, and then Window -> CompWindow the nux window and check the clip region there to see if it is empty.

2. Second option is a bit trickier, but might also work. You'll need to effectively make unity do the occlusion pass. What you would do here is loop all the windows and do something like:

class UnityWindow :
....
{
....
private:

    CompRegion clip_;
};

void DetectOcclusionsOnUnityWindows (const GLMatrix &matrix,
                                     CompOutput *output)
{
GLWindowPaintAttrib a;
CompRegion tmpRegion (*output);

/* Top to bottom */
for (CompWindow *w : screen->reverseWindows ())
{
    UnityWindow *uw = UnityWindow::get (w);

    /* We only care about windows we actually clipped */
    clip = infiniteRegion;

    if (window->alpha ())
        continue;

    if (!window->isViewable ())
        continue;

    /* GLWindow::glPaint will return true if this window should be regarded
     * as occluding other windows. PAINT_WINDOW_OCCLUSION_DETECTION_MASK will
     * not actually paint the window, but will allow plugins to modify the state
     * of the window as if it was being painted, so we will know whether it should
     * occlude other windows */
    if (gw->glPaint (a, matrix, tmpRegion, PAINT_WINDOW_OCCLUSION_DETECTION_MASK))
        tmpRegion -= w->region (); // Not inputRect () or outputRect (): Decorations are ARGB windows

    uw->clip_ = tmpRegion;
}
}

Now, you can loop the list of nux windows (probably safe to store that internally, a nux window is a nux window for life, just detect it on the UnityWindow ctor) and see if they all have empty clip regions. If so, don't paint the shell.

You can also use the region detection to determine what parts of the shell to "damage" as well.

iirc, this is something similar to what the blur plugin does. Have a look at that for other ideas. This will also fix problems to do with ...

Read more...

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

I am keeping shellIsHidden because it is fast and simple. It doesn't re-enter compiz and doesn't require any CompRegion logic. It just uses rectangles.

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

> I am keeping shellIsHidden because it is fast and simple. It doesn't re-enter
> compiz and doesn't require any CompRegion logic. It just uses rectangles.

My gripe with shellIsHidden is that it is inaccurate and will run into lots of edge cases. It doesn't make visual sense when you have windows with alpha regions, transparency or transformations preventing the shell from painting if the bounding area occludes the shell. Its pretty much defeats the purpose of having alpha regions, shape regions and transformations in the first place. You can easily run into cases where the shell won't paint even when it should, and I think that's bad. Unless you have a way to handle those cases, or a very strong argument as to why we shouldn't handle those cases, I honestly think its a blocking factor here.

The OpenGL plugin already uses similar looking logic to do its occlusion detection, and there is very little (if any) performance penalty for it. There is hardly any CompRegion allocation at all, because the variables are stored locally. In fact, every time I've callgrinded compiz, paintOutputRegion has not appeared as a hotspot anywhere. The re-entrancy into compiz is also very inexpensive because most plugins will have glPaint disabled if they are not running any animations.

I would suggest at least trying to make it work.

Other bits of review:

121 +std::vector<nux::View*> Controller::Impl::GetPanelViews() const
122 +{
123 + std::vector<nux::View*> views;
124 + views.reserve(windows_.size());
125 + for (auto window: windows_)
126 + views.push_back(ViewForWindow(window));
127 + return views;
128 +}
129 +

I think it probably makes more sense to have the panel controller keep track of the views in its own vector so that you can just return a const ref to the vector. Since we're going to be calling this function every time we call compizDamageNux, the cost of doing the initial tracking for outweighs the cost of the query here.

270 + w->isViewable() &&
271 + !w->inShowDesktopMode() && // Why must this != isViewable?

You probably wanted

w->state () & CompWindowStateHiddenMask

260 + // Loop through windows from back to front
261 + for (CompWindow* w : screen->windows ())
262 + {

If you still want to use this, it would be easier to go front to back, I had to read the code like 8 times to figure out how it worked.

// front to back
for (CompWindow *w : screen->reverseWindows ())
{
 if (w->isMapped() &&
  w->isViewable() &&
  !w->inShowDesktopMode() && // Why must this != isViewable?
  w->geometry().contains(output))
    return true; // a window that covers the whole output discovered at top first
 else
   for (Window id : nuxwins)
     if (w->id () == id && output->intersects (w->geometry ())
       return false; // a nux windows discovered first
}

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

Sam, if you want people to pay attention, use fewer words. I'll get to this later.

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

> Sam, if you want people to pay attention, use fewer words. I'll get to this
> later.

I apologize for my verbosity. Some things are complicated. This is.

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

ALPHA AND TRANSPARENCY
I can only find one edge case so far. Using the obs plugin make a fullscreen window translucent. I would like to be able to detect this using CompositeWindow opacity() and alpha(), but there are four problems with that:
  1. opacity() returns OPAQUE even after updateOpacity and even when the window is translucent. Bug?
  2. updateOpacity() triggers window damage. Not a good idea. Bug?
  3. updateOpacity() requires a round trip.
  4. alpha() is not implemented. Does it have a use?
Actually, obs doesn't use composite opacity at all. It stores opacity privately and I don't want to create a dependency of unityshell on obs. I know you've said the occlusion code is designed for all this, but I don't yet understand it. And I'm not going to use it until I understand what it's meant to do.

PANEL CONTROLLER
I would prefer to not modify the panel code at all. Also, I think the current design does the best at information hiding. I think it's only creating a vector that is typically size 1 or 2 anyway. So performance should not be an issue.

HIDDEN WINDOW DETECTION
Fixed as smspillaz suggested.

SHELLISHIDDEN
Fixed (simplified) as smspillaz suggested.

Revision history for this message
Sam Spilsbury (smspillaz) wrote : Posted in a previous version of this proposal
Download full text (3.9 KiB)

Looks pretty good now :)

427 + if (isNuxWindow(window))
428 + {
429 + if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
430 + {
431 + uScreen->nuxRegion += window->geometry();
432 + uScreen->nuxRegion -= uScreen->overShell;
433 + }
434 + return false;
435 + }
436 + else if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK &&
437 + !(mask & PAINT_WINDOW_TRANSLUCENT_MASK) &&
438 + window->state() & CompWindowStateFullscreenMask)
439 + // && !window->alpha() <-- doesn't work. False positives.
440 + {
441 + uScreen->overShell += window->geometry();
442 + uScreen->overShell -= uScreen->nuxRegion;
443 + }

I can't quite tell based on the context of the diff, but its probably safer to put this after the glPaint call, eg

bool retval = gWindow->glPaint (attrib, transform, region, mask);

And then something like:

bool nux_window = isNuxWindow (window);

if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
{
  if (nux_window)
  {
    uScreen->nuxRegion += window->geometry();
    uScreen->nuxRegion -= uScreen->overShell;
  }
  else
  {
    if (window->alpha () && attrib.opacity != opaque)
      mask |= PAINT_WINDOW_TRANSLUCENT_MASK;

    unsigned int noOcclusionMask = PAINT_WINDOW_TRANSLUCENT_MASK | PAINT_WINDOW_TRANSFORMED_MASK | PAINT_WINDOW_NO_CORE_INSTANCE_MASK;

    if (!(mask & noOcclusionMask == noOcclusionMask))
    {
      uScreen->overShell += window->geometry();
      uScreen->overShell -= uScreen->nuxRegion;
    }
  }
}

if (nux_window)
  return false;

return retval;

In that sample, I didn't check to see if the window was a fullscreen window before adding it to the occlusion region. Reason being that it is possible that a nonfullscreen window can be validly stacked above the shell (think override redirect windows, onboard, some other corner cases involving fullscreen windows and nonfullscreen windows). Note also the flags for NO_CORE_INSTANCE_MASK and TRANSFORMED_MASK.

I think the code here for determining whether or not something is over the shell using the occlusion detection is the wrong way around. The occlusion pass happens from bottom to top, so what seems to happen is that for windows stacked top to bottom as such (nux windows prefixed with N)

N1 > N2 > N3 > 4 > 5 > 6

You'll end up with:

overShell = (6 + 5 + 4)
nuxRegion = ((N3 - overShell) + (N2 - overShell) + (N1 - overShell))

Since when we hit the isNuxWindow case at N3, we add N3 to nuxRegion, and then subtract overShell from it (even though those windows aren't actually over the shell).

If you have no windows underneath the shell and a fullscreen window on top like this:

F1 > N2 > N3 > N4 > 5 > 6 > 7

You'll end up with:

nuxRegion = N4 + N3 + N2
overShell = (7 + 6 + 5 + F1) - nuxRegion

So in that case, you'll have a fullscreen window over the shell, and the shell will paint. If you don't have a fullscreen window over the shell, then the parts underneath it will obscure the shell.

The solution in this case is probably to only start to collect the shell region, and clear the "overShell" region when you hit the first nux window in PAINT_WINDOW_OCCLUSION_DETECTION_MASK. Then once you hit another window, you can s...

Read more...

Revision history for this message
jenkins (martin-mrazik+qa) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:2463
http://s-jenkins:8080/job/unity-ci/21/

review: Approve (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) :
review: Abstain
Revision history for this message
jenkins (martin-mrazik+qa) wrote :

PASSED: Continuous integration, rev:2469
http://s-jenkins:8080/job/unity-ci/29/

review: Approve (continuous-integration)
Revision history for this message
Sam Spilsbury (smspillaz) wrote :

Okay, looks good.

I would suggest getting some of the more complicated parts of this code under test, but I'm happy with it as is.

review: Approve
Revision history for this message
Tim Penhey (thumper) wrote :

> std::vector<nux::View*> const& panels(panel_controller_->GetPanelViews());

This is very bad. You are taking a reference to a temporary.
Remove the const& and the standard library move semantics will make
sure that this is efficient.

Also there isn't really a need to get the list outside the range based for loop.

You could just say:

for (nux::View* view : panel_controller_->GetPanelViews())

Similarly for the other for loops.

> std::vector<nux::Geometry> const& dirty = wt->GetDrawList();

Again here you are taking a reference to a temporary.

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

Those temporaries exist for the lifetime of the block they're created in, so it is safe.

Revision history for this message
Tim Penhey (thumper) wrote :

You are half right.

Temporaries exist for the duration of the expression they were created in.

Except if they are bound to a reference, in which case they live for the duration of the life of the reference, except in certain situation covered in section 12.2.5 of the standard.

I learned something today.

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

Yes, I was only half right. I learned something too.

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

It seems that this patch has caused a regression.

Use case:
 1 - have number of windows open
 2 - hold alt key
 3 - press tab key [switcher comes up]
 4 - click on some unselected icon

Expected outcome:
 Selected icon is instantly redrawn

Actual outcome:
 It frequently take several seconds for the switcher to be redrawn after SwitcherView calls QueueDraw()

Branches:
  lp:~dandrader/unity/switcher_click_test
  This this patch and the issue appears.

  lp:~dandrader/unity/switcher_click_test_older_trunk
  Does not have this patch and things work nice and dandy.

Background info:
I'm working on new gestures to switch between windows and interact with the window switcher (the alt-tab guy). The branches above have a snippet of my WIP code that enables a user to select a window by directly tapping/clicking over its icon on the switcher.

So is my code snipped doing something dumb or have this patch indeed caused a regresssion?

review: Needs Information
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

Things came back to normal again with revision 2475.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'launcher/AbstractLauncherIcon.h'
--- launcher/AbstractLauncherIcon.h 2012-06-06 15:40:19 +0000
+++ launcher/AbstractLauncherIcon.h 2012-06-27 07:28:39 +0000
@@ -218,6 +218,7 @@
218218
219 sigc::signal<void, AbstractLauncherIcon::Ptr> needs_redraw;219 sigc::signal<void, AbstractLauncherIcon::Ptr> needs_redraw;
220 sigc::signal<void, AbstractLauncherIcon::Ptr> remove;220 sigc::signal<void, AbstractLauncherIcon::Ptr> remove;
221 sigc::signal<void, nux::ObjectPtr<nux::View>> tooltip_visible;
221 sigc::signal<void> visibility_changed;222 sigc::signal<void> visibility_changed;
222223
223 sigc::connection needs_redraw_connection;224 sigc::connection needs_redraw_connection;
224225
=== modified file 'launcher/Launcher.cpp'
--- launcher/Launcher.cpp 2012-06-20 18:51:16 +0000
+++ launcher/Launcher.cpp 2012-06-27 07:28:39 +0000
@@ -1520,6 +1520,11 @@
1520 }1520 }
1521}1521}
15221522
1523nux::ObjectPtr<nux::View> Launcher::GetActiveTooltip() const
1524{
1525 return _active_tooltip;
1526}
1527
1523void Launcher::SetActionState(LauncherActionState actionstate)1528void Launcher::SetActionState(LauncherActionState actionstate)
1524{1529{
1525 if (_launcher_action_state == actionstate)1530 if (_launcher_action_state == actionstate)
@@ -1681,6 +1686,7 @@
1681 EnsureAnimation();1686 EnsureAnimation();
16821687
1683 icon->needs_redraw.connect(sigc::mem_fun(this, &Launcher::OnIconNeedsRedraw));1688 icon->needs_redraw.connect(sigc::mem_fun(this, &Launcher::OnIconNeedsRedraw));
1689 icon->tooltip_visible.connect(sigc::mem_fun(this, &Launcher::OnTooltipVisible));
1684}1690}
16851691
1686void Launcher::OnIconRemoved(AbstractLauncherIcon::Ptr icon)1692void Launcher::OnIconRemoved(AbstractLauncherIcon::Ptr icon)
@@ -1757,6 +1763,11 @@
1757 EnsureAnimation();1763 EnsureAnimation();
1758}1764}
17591765
1766void Launcher::OnTooltipVisible(nux::ObjectPtr<nux::View> view)
1767{
1768 _active_tooltip = view;
1769}
1770
1760void Launcher::Draw(nux::GraphicsEngine& GfxContext, bool force_draw)1771void Launcher::Draw(nux::GraphicsEngine& GfxContext, bool force_draw)
1761{1772{
17621773
17631774
=== modified file 'launcher/Launcher.h'
--- launcher/Launcher.h 2012-06-15 02:03:31 +0000
+++ launcher/Launcher.h 2012-06-27 07:28:39 +0000
@@ -96,6 +96,8 @@
96 return _parent;96 return _parent;
97 };97 };
9898
99 nux::ObjectPtr<nux::View> GetActiveTooltip() const; // nullptr = no tooltip
100
99 virtual void RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags);101 virtual void RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags);
100 virtual void RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags);102 virtual void RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags);
101 virtual void RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags);103 virtual void RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags);
@@ -269,6 +271,7 @@
269 void OnOrderChanged();271 void OnOrderChanged();
270272
271 void OnIconNeedsRedraw(AbstractLauncherIcon::Ptr icon);273 void OnIconNeedsRedraw(AbstractLauncherIcon::Ptr icon);
274 void OnTooltipVisible(nux::ObjectPtr<nux::View> view);
272275
273 void OnOverlayHidden(GVariant* data);276 void OnOverlayHidden(GVariant* data);
274 void OnOverlayShown(GVariant* data);277 void OnOverlayShown(GVariant* data);
@@ -311,6 +314,7 @@
311314
312 LauncherModel::Ptr _model;315 LauncherModel::Ptr _model;
313 nux::BaseWindow* _parent;316 nux::BaseWindow* _parent;
317 nux::ObjectPtr<nux::View> _active_tooltip;
314 QuicklistView* _active_quicklist;318 QuicklistView* _active_quicklist;
315319
316 nux::HLayout* m_Layout;320 nux::HLayout* m_Layout;
317321
=== modified file 'launcher/LauncherIcon.cpp'
--- launcher/LauncherIcon.cpp 2012-06-19 01:00:36 +0000
+++ launcher/LauncherIcon.cpp 2012-06-27 07:28:39 +0000
@@ -513,6 +513,7 @@
513 LoadTooltip();513 LoadTooltip();
514 _tooltip->ShowTooltipWithTipAt(tip_x, tip_y);514 _tooltip->ShowTooltipWithTipAt(tip_x, tip_y);
515 _tooltip->ShowWindow(!tooltip_text().empty());515 _tooltip->ShowWindow(!tooltip_text().empty());
516 tooltip_visible.emit(_tooltip);
516}517}
517518
518void519void
@@ -534,6 +535,7 @@
534535
535 if (_tooltip)536 if (_tooltip)
536 _tooltip->ShowWindow(false);537 _tooltip->ShowWindow(false);
538 tooltip_visible.emit(nux::ObjectPtr<nux::View>(nullptr));
537}539}
538540
539bool LauncherIcon::OpenQuicklist(bool select_first_item, int monitor)541bool LauncherIcon::OpenQuicklist(bool select_first_item, int monitor)
@@ -653,6 +655,7 @@
653{655{
654 if (_tooltip)656 if (_tooltip)
655 _tooltip->ShowWindow(false);657 _tooltip->ShowWindow(false);
658 tooltip_visible.emit(nux::ObjectPtr<nux::View>(nullptr));
656}659}
657660
658bool661bool
659662
=== modified file 'panel/PanelController.cpp'
--- panel/PanelController.cpp 2012-06-15 02:03:31 +0000
+++ panel/PanelController.cpp 2012-06-27 07:28:39 +0000
@@ -49,6 +49,7 @@
49 void QueueRedraw();49 void QueueRedraw();
5050
51 std::vector<Window> GetTrayXids() const;51 std::vector<Window> GetTrayXids() const;
52 std::vector<nux::View*> GetPanelViews() const;
52 std::vector<nux::Geometry> GetGeometries() const;53 std::vector<nux::Geometry> GetGeometries() const;
5354
54 // NOTE: nux::Property maybe?55 // NOTE: nux::Property maybe?
@@ -106,6 +107,15 @@
106 return xids;107 return xids;
107}108}
108109
110std::vector<nux::View*> Controller::Impl::GetPanelViews() const
111{
112 std::vector<nux::View*> views;
113 views.reserve(windows_.size());
114 for (auto window: windows_)
115 views.push_back(ViewForWindow(window));
116 return views;
117}
118
109std::vector<nux::Geometry> Controller::Impl::GetGeometries() const119std::vector<nux::Geometry> Controller::Impl::GetGeometries() const
110{120{
111 std::vector<nux::Geometry> geometries;121 std::vector<nux::Geometry> geometries;
@@ -325,6 +335,11 @@
325 return pimpl->GetTrayXids();335 return pimpl->GetTrayXids();
326}336}
327337
338std::vector<nux::View*> Controller::GetPanelViews() const
339{
340 return pimpl->GetPanelViews();
341}
342
328std::vector<nux::Geometry> Controller::GetGeometries() const343std::vector<nux::Geometry> Controller::GetGeometries() const
329{344{
330 return pimpl->GetGeometries();345 return pimpl->GetGeometries();
331346
=== modified file 'panel/PanelController.h'
--- panel/PanelController.h 2012-05-06 23:48:38 +0000
+++ panel/PanelController.h 2012-06-27 07:28:39 +0000
@@ -41,6 +41,7 @@
41 void QueueRedraw();41 void QueueRedraw();
4242
43 std::vector<Window> GetTrayXids() const;43 std::vector<Window> GetTrayXids() const;
44 std::vector<nux::View*> GetPanelViews() const;
44 std::vector<nux::Geometry> GetGeometries() const;45 std::vector<nux::Geometry> GetGeometries() const;
4546
46 // NOTE: nux::Property maybe?47 // NOTE: nux::Property maybe?
4748
=== modified file 'plugins/unityshell/src/unityshell.cpp'
--- plugins/unityshell/src/unityshell.cpp 2012-06-26 18:34:03 +0000
+++ plugins/unityshell/src/unityshell.cpp 2012-06-27 07:28:39 +0000
@@ -100,7 +100,6 @@
100const unsigned int SCROLL_UP_BUTTON = 7;100const unsigned int SCROLL_UP_BUTTON = 7;
101101
102const std::string RELAYOUT_TIMEOUT = "relayout-timeout";102const std::string RELAYOUT_TIMEOUT = "relayout-timeout";
103const std::string REDRAW_IDLE = "redraw-idle";
104} // namespace local103} // namespace local
105} // anon namespace104} // anon namespace
106105
@@ -118,6 +117,7 @@
118 , super_keypressed_(false)117 , super_keypressed_(false)
119 , newFocusedWindow(nullptr)118 , newFocusedWindow(nullptr)
120 , doShellRepaint(false)119 , doShellRepaint(false)
120 , didShellRepaint(false)
121 , allowWindowPaint(false)121 , allowWindowPaint(false)
122 , damaged(false)122 , damaged(false)
123 , _key_nav_mode_requested(false)123 , _key_nav_mode_requested(false)
@@ -909,6 +909,7 @@
909 }909 }
910910
911 doShellRepaint = false;911 doShellRepaint = false;
912 didShellRepaint = true;
912 damaged = false;913 damaged = false;
913}914}
914915
@@ -1211,7 +1212,15 @@
1211{1212{
1212 bool ret;1213 bool ret;
12131214
1214 doShellRepaint = true;1215 /*
1216 * Very important!
1217 * Don't waste GPU and CPU rendering the shell on every frame if you don't
1218 * need to. Doing so on every frame causes Nux to hog the GPU and slow down
1219 * ALL rendering. (LP: #988079)
1220 */
1221 bool force = forcePaintOnTop() || PluginAdapter::Default()->IsExpoActive();
1222 doShellRepaint = force || !(region.isEmpty() || wt->GetDrawList().empty());
1223
1215 allowWindowPaint = true;1224 allowWindowPaint = true;
1216 _last_output = output;1225 _last_output = output;
1217 paint_panel_ = false;1226 paint_panel_ = false;
@@ -1227,13 +1236,21 @@
1227 * attempts to bind it will only increment1236 * attempts to bind it will only increment
1228 * its bind reference so make sure that1237 * its bind reference so make sure that
1229 * you always unbind as much as you bind */1238 * you always unbind as much as you bind */
1230 _fbo->bind (nux::Geometry (output->x (), output->y (), output->width (), output->height ()));1239 if (doShellRepaint)
1240 _fbo->bind (nux::Geometry (output->x (), output->y (), output->width (), output->height ()));
1231#endif1241#endif
12321242
1243 // CompRegion has no clear() method. So this is the fastest alternative.
1244 aboveShell = CompRegion();
1245 nuxRegion = CompRegion();
1246
1233 /* glPaintOutput is part of the opengl plugin, so we need the GLScreen base class. */1247 /* glPaintOutput is part of the opengl plugin, so we need the GLScreen base class. */
1234 ret = gScreen->glPaintOutput(attrib, transform, region, output, mask);1248 ret = gScreen->glPaintOutput(attrib, transform, region, output, mask);
12351249
1236#ifndef USE_MODERN_COMPIZ_GL1250#ifndef USE_MODERN_COMPIZ_GL
1251 if (doShellRepaint && !force && aboveShell.contains(*output))
1252 doShellRepaint = false;
1253
1237 if (doShellRepaint)1254 if (doShellRepaint)
1238 paintDisplay(region, transform, mask);1255 paintDisplay(region, transform, mask);
1239#endif1256#endif
@@ -1286,16 +1303,32 @@
1286 for (ShowdesktopHandlerWindowInterface *wi : ShowdesktopHandler::animating_windows)1303 for (ShowdesktopHandlerWindowInterface *wi : ShowdesktopHandler::animating_windows)
1287 wi->HandleAnimations (ms);1304 wi->HandleAnimations (ms);
12881305
1306 // Workaround Nux bug LP: #1014610:
1289 if (damaged)1307 if (damaged)
1290 {1308 {
1291 damaged = false;1309 damaged = false;
1292 damageNuxRegions();1310 nuxDamageCompiz();
1293 }1311 }
12941312
1313 compizDamageNux(cScreen->currentDamage());
1314
1315 didShellRepaint = false;
1295}1316}
12961317
1297void UnityScreen::donePaint()1318void UnityScreen::donePaint()
1298{1319{
1320 /*
1321 * It's only safe to clear the draw list if drawing actually occurred
1322 * (i.e. the shell was not obscured behind a fullscreen window).
1323 * If you clear the draw list and drawing has not occured then you'd be
1324 * left with all your views thinking they're queued for drawing still and
1325 * would refuse to redraw when you return from fullscreen.
1326 * I think this is a Nux bug. ClearDrawList should ideally also mark all
1327 * the queued views as draw_cmd_queued_=false.
1328 */
1329 if (didShellRepaint)
1330 wt->ClearDrawList();
1331
1299 std::list <ShowdesktopHandlerWindowInterface *> remove_windows;1332 std::list <ShowdesktopHandlerWindowInterface *> remove_windows;
13001333
1301 for (ShowdesktopHandlerWindowInterface *wi : ShowdesktopHandler::animating_windows)1334 for (ShowdesktopHandlerWindowInterface *wi : ShowdesktopHandler::animating_windows)
@@ -1316,42 +1349,100 @@
1316 cScreen->donePaint ();1349 cScreen->donePaint ();
1317}1350}
13181351
1352void UnityScreen::compizDamageNux(CompRegion const& damage)
1353{
1354 if (!launcher_controller_)
1355 return;
1356
1357 CompRect::vector const& rects(damage.rects());
1358 for (const CompRect &r : rects)
1359 {
1360 nux::Geometry geo(r.x(), r.y(), r.width(), r.height());
1361 BackgroundEffectHelper::ProcessDamage(geo);
1362 }
1363
1364 auto launchers = launcher_controller_->launchers();
1365 for (auto launcher : launchers)
1366 {
1367 if (!launcher->Hidden())
1368 {
1369 nux::Geometry geo = launcher->GetAbsoluteGeometry();
1370 CompRegion launcher_region(geo.x, geo.y, geo.width, geo.height);
1371 if (damage.intersects(launcher_region))
1372 launcher->QueueDraw();
1373 nux::ObjectPtr<nux::View> tooltip = launcher->GetActiveTooltip();
1374 if (!tooltip.IsNull())
1375 {
1376 nux::Geometry tip = tooltip->GetAbsoluteGeometry();
1377 CompRegion tip_region(tip.x, tip.y, tip.width, tip.height);
1378 if (damage.intersects(tip_region))
1379 tooltip->QueueDraw();
1380 }
1381 }
1382 }
1383
1384 std::vector<nux::View*> const& panels(panel_controller_->GetPanelViews());
1385 for (nux::View* view : panels)
1386 {
1387 nux::Geometry geo = view->GetAbsoluteGeometry();
1388 CompRegion panel_region(geo.x, geo.y, geo.width, geo.height);
1389 if (damage.intersects(panel_region))
1390 view->QueueDraw();
1391 }
1392
1393 QuicklistManager* qm = QuicklistManager::Default();
1394 if (qm)
1395 {
1396 QuicklistView* view = qm->Current();
1397 if (view)
1398 {
1399 nux::Geometry geo = view->GetAbsoluteGeometry();
1400 CompRegion quicklist_region(geo.x, geo.y, geo.width, geo.height);
1401 if (damage.intersects(quicklist_region))
1402 view->QueueDraw();
1403 }
1404 }
1405}
1406
1319/* Grab changed nux regions and add damage rects for them */1407/* Grab changed nux regions and add damage rects for them */
1320void UnityScreen::damageNuxRegions()1408void UnityScreen::nuxDamageCompiz()
1321{1409{
1410 // Workaround Nux bug LP: #1014610 (unbounded DrawList growth)
1411 // Also, ensure we don't dereference null *controller_ on startup.
1412 if (damaged || !launcher_controller_ || !dash_controller_)
1413 return;
1414 damaged = true;
1415
1322 CompRegion nux_damage;1416 CompRegion nux_damage;
13231417
1324 if (damaged)1418 std::vector<nux::Geometry> const& dirty = wt->GetDrawList();
1325 return;1419 for (auto geo : dirty)
13261420 nux_damage += CompRegion(geo.x, geo.y, geo.width, geo.height);
1327 std::vector<nux::Geometry> dirty = wt->GetDrawList();1421
1328 damaged = true;1422 if (launcher_controller_->IsOverlayOpen())
13291423 {
1330 for (std::vector<nux::Geometry>::iterator it = dirty.begin(), end = dirty.end();1424 nux::BaseWindow* dash_window = dash_controller_->window();
1331 it != end; ++it)1425 nux::Geometry const& geo = dash_window->GetAbsoluteGeometry();
1332 {1426 nux_damage += CompRegion(geo.x, geo.y, geo.width, geo.height);
1333 nux::Geometry const& geo = *it;1427 }
1334 nux_damage += CompRegion(geo.x, geo.y, geo.width, geo.height);1428
1335 }1429 auto launchers = launcher_controller_->launchers();
13361430 for (auto launcher : launchers)
1337 nux::Geometry geo = wt->GetWindowCompositor().GetTooltipMainWindowGeometry();1431 {
1338 nux_damage += CompRegion(geo.x, geo.y, geo.width, geo.height);1432 if (!launcher->Hidden())
13391433 {
1340 geo = lastTooltipArea;1434 nux::ObjectPtr<nux::View> tooltip = launcher->GetActiveTooltip();
1341 nux_damage += CompRegion(lastTooltipArea.x, lastTooltipArea.y,1435 if (!tooltip.IsNull())
1342 lastTooltipArea.width, lastTooltipArea.height);1436 {
13431437 nux::Geometry const& g = tooltip->GetAbsoluteGeometry();
1344 /*1438 nux_damage += CompRegion(g.x, g.y, g.width, g.height);
1345 * Avoid Nux damaging Nux as recommended by smspillaz. Though I don't1439 }
1346 * believe it would be harmful or significantly expensive right now.1440 }
1347 */1441 }
1442
1348 cScreen->damageRegionSetEnabled(this, false);1443 cScreen->damageRegionSetEnabled(this, false);
1349 cScreen->damageRegion(nux_damage);1444 cScreen->damageRegion(nux_damage);
1350 cScreen->damageRegionSetEnabled(this, true);1445 cScreen->damageRegionSetEnabled(this, true);
1351
1352 wt->ClearDrawList();
1353
1354 lastTooltipArea = geo;
1355}1446}
13561447
1357/* handle X Events */1448/* handle X Events */
@@ -1511,13 +1602,7 @@
15111602
1512void UnityScreen::damageRegion(const CompRegion &region)1603void UnityScreen::damageRegion(const CompRegion &region)
1513{1604{
1514 const CompRect::vector &rects(region.rects());1605 compizDamageNux(region);
1515 for (const CompRect &r : rects)
1516 {
1517 nux::Geometry geo(r.x(), r.y(), r.width(), r.height());
1518 BackgroundEffectHelper::ProcessDamage(geo);
1519 }
1520
1521 cScreen->damageRegion(region);1606 cScreen->damageRegion(region);
1522}1607}
15231608
@@ -2173,14 +2258,6 @@
2173 return false;2258 return false;
2174}2259}
21752260
2176const CompWindowList& UnityScreen::getWindowPaintList()
2177{
2178 CompWindowList& pl = _withRemovedNuxWindows = cScreen->getWindowPaintList();
2179 pl.remove_if(isNuxWindow);
2180
2181 return pl;
2182}
2183
2184void UnityScreen::RaiseInputWindows()2261void UnityScreen::RaiseInputWindows()
2185{2262{
2186 std::vector<Window> const& xwns = nux::XInputWindow::NativeHandleList();2263 std::vector<Window> const& xwns = nux::XInputWindow::NativeHandleList();
@@ -2205,6 +2282,35 @@
2205 const CompRegion& region,2282 const CompRegion& region,
2206 unsigned int mask)2283 unsigned int mask)
2207{2284{
2285 /*
2286 * The occlusion pass tests windows from TOP to BOTTOM. That's opposite to
2287 * the actual painting loop.
2288 */
2289 if (isNuxWindow(window))
2290 {
2291 if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
2292 {
2293 uScreen->nuxRegion += window->geometry();
2294 uScreen->nuxRegion -= uScreen->aboveShell;
2295 }
2296 return false; // Ensure nux windows are never painted by compiz
2297 }
2298 else if (mask & PAINT_WINDOW_OCCLUSION_DETECTION_MASK)
2299 {
2300 static const unsigned int nonOcclusionBits =
2301 PAINT_WINDOW_TRANSLUCENT_MASK |
2302 PAINT_WINDOW_TRANSFORMED_MASK |
2303 PAINT_WINDOW_NO_CORE_INSTANCE_MASK;
2304 if (!(mask & nonOcclusionBits))
2305 // And I've been advised to test other things, but they don't work:
2306 // && (attrib.opacity == OPAQUE)) <-- Doesn't work; Only set in glDraw
2307 // && !window->alpha() <-- Doesn't work; Opaque windows often have alpha
2308 {
2309 uScreen->aboveShell += window->geometry();
2310 uScreen->aboveShell -= uScreen->nuxRegion;
2311 }
2312 }
2313
2208 GLWindowPaintAttrib wAttrib = attrib;2314 GLWindowPaintAttrib wAttrib = attrib;
22092315
2210 if (mMinimizeHandler)2316 if (mMinimizeHandler)
@@ -2263,7 +2369,17 @@
2263 }2369 }
2264 }2370 }
22652371
2266 if (uScreen->doShellRepaint && !uScreen->forcePaintOnTop ())2372 /*
2373 * Paint the shell in *roughly* the compiz stacking order. This is only
2374 * approximate because we're painting all the nux windows as soon as we find
2375 * the bottom-most nux window (from bottom to top).
2376 * But remember to avoid painting the shell if it's within the aboveShell
2377 * region.
2378 */
2379 if (uScreen->doShellRepaint &&
2380 !uScreen->forcePaintOnTop () &&
2381 !uScreen->aboveShell.contains(window->geometry())
2382 )
2267 {2383 {
2268 std::vector<Window> const& xwns = nux::XInputWindow::NativeHandleList();2384 std::vector<Window> const& xwns = nux::XInputWindow::NativeHandleList();
2269 unsigned int size = xwns.size();2385 unsigned int size = xwns.size();
@@ -2578,25 +2694,7 @@
25782694
2579void UnityScreen::onRedrawRequested()2695void UnityScreen::onRedrawRequested()
2580{2696{
2581 // disable blur updates so we dont waste perf. This can stall the blur during animations2697 nuxDamageCompiz();
2582 // but ensures a smooth animation.
2583 if (_in_paint)
2584 {
2585 if (!sources_.GetSource(local::REDRAW_IDLE))
2586 {
2587 auto redraw_idle(std::make_shared<glib::Idle>(glib::Source::Priority::DEFAULT));
2588 sources_.Add(redraw_idle, local::REDRAW_IDLE);
2589
2590 redraw_idle->Run([&]() {
2591 onRedrawRequested();
2592 return false;
2593 });
2594 }
2595 }
2596 else
2597 {
2598 damageNuxRegions();
2599 }
2600}2698}
26012699
2602/* Handle option changes and plug that into nux windows */2700/* Handle option changes and plug that into nux windows */
26032701
=== modified file 'plugins/unityshell/src/unityshell.h'
--- plugins/unityshell/src/unityshell.h 2012-06-26 17:34:31 +0000
+++ plugins/unityshell/src/unityshell.h 2012-06-27 07:28:39 +0000
@@ -133,9 +133,6 @@
133 CompOutput*,133 CompOutput*,
134 unsigned int);134 unsigned int);
135135
136 /* Pop our InputOutput windows from the paint list */
137 const CompWindowList& getWindowPaintList();
138
139 /* handle X11 events */136 /* handle X11 events */
140 void handleEvent(XEvent*);137 void handleEvent(XEvent*);
141138
@@ -212,7 +209,10 @@
212209
213 bool initPluginActions();210 bool initPluginActions();
214 void initLauncher();211 void initLauncher();
215 void damageNuxRegions();212
213 void compizDamageNux(CompRegion const& region);
214 void nuxDamageCompiz();
215
216 void onRedrawRequested();216 void onRedrawRequested();
217 void Relayout();217 void Relayout();
218218
@@ -260,7 +260,6 @@
260 bool enable_shortcut_overlay_;260 bool enable_shortcut_overlay_;
261261
262 GestureEngine gesture_engine_;262 GestureEngine gesture_engine_;
263 nux::Geometry lastTooltipArea;
264 bool needsRelayout;263 bool needsRelayout;
265 bool _in_paint;264 bool _in_paint;
266 bool super_keypressed_;265 bool super_keypressed_;
@@ -277,11 +276,14 @@
277276
278 /* handle paint order */277 /* handle paint order */
279 bool doShellRepaint;278 bool doShellRepaint;
279 bool didShellRepaint;
280 bool allowWindowPaint;280 bool allowWindowPaint;
281 bool damaged;281 bool damaged;
282 bool _key_nav_mode_requested;282 bool _key_nav_mode_requested;
283 CompOutput* _last_output;283 CompOutput* _last_output;
284 CompWindowList _withRemovedNuxWindows;284
285 CompRegion nuxRegion;
286 CompRegion aboveShell;
285287
286 nux::Property<nux::Geometry> primary_monitor_;288 nux::Property<nux::Geometry> primary_monitor_;
287289