Merge lp:~3v1n0/unity/scale-decoration-cache into lp:unity

Proposed by Marco Trevisan (Treviño)
Status: Merged
Approved by: Brandon Schaefer
Approved revision: no longer in the source branch.
Merged at revision: 2749
Proposed branch: lp:~3v1n0/unity/scale-decoration-cache
Merge into: lp:unity
Diff against target: 517 lines (+165/-131)
2 files modified
plugins/unityshell/src/unityshell.cpp (+124/-80)
plugins/unityshell/src/unityshell.h (+41/-51)
To merge this branch: bzr merge lp:~3v1n0/unity/scale-decoration-cache
Reviewer Review Type Date Requested Status
Brandon Schaefer (community) Approve
Review via email: mp+126072@code.launchpad.net

Commit message

UnityWindow: when spreading, render once an empty decoration texture at full size and scale it via OpenGL

This saves a lot of drawing and improves the performances of the unity Spread. Also, don't redraw the decoration texture for selected windows if not needed.
Finally, cleanup the header file

Description of the change

Unity was always redrawing the decoration textures at every compiz gldraw iteration, and this lead to a slowdown especially when we had a lot of windows to decorate.

I've changed this approach completely, now:
 - All the scaled windows cache a full-size decoration with no title when the spread
   begins, then we always draw that decoration using a scaled matrix (this avoids all
   the cairo stuff at every iteration).

 - The selected scaled window decoration is redrawn everytime its geometry has changed or
   the title has changed.

To post a comment you must log in.
Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

What an improvement! Looks good, and is a lot faster! +1

No tests as all the features are already covered, this is about caching textures (which if this caused a problem the test we already have would catch it!)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/unityshell/src/unityshell.cpp'
2--- plugins/unityshell/src/unityshell.cpp 2012-09-24 15:22:57 +0000
3+++ plugins/unityshell/src/unityshell.cpp 2012-09-24 18:46:21 +0000
4@@ -87,9 +87,6 @@
5
6 UnityScreen* uScreen = 0;
7
8-const unsigned int SCALE_CLOSE_ICON_SIZE = 19;
9-const unsigned int SCALE_ITEMS_PADDING = 5;
10-
11 void reset_glib_logging();
12 void configure_logging();
13 void capture_g_log_calls(const gchar* log_domain,
14@@ -111,8 +108,8 @@
15 } // anon namespace
16
17 UnityScreen::UnityScreen(CompScreen* screen)
18- : BaseSwitchScreen (screen)
19- , PluginClassHandler <UnityScreen, CompScreen> (screen)
20+ : BaseSwitchScreen(screen)
21+ , PluginClassHandler <UnityScreen, CompScreen>(screen)
22 , screen(screen)
23 , cScreen(CompositeScreen::get(screen))
24 , gScreen(GLScreen::get(screen))
25@@ -669,7 +666,12 @@
26 UnityWindow::CleanupSharedTextures();
27
28 if (WindowManager::Default()->IsScaleActive())
29+ {
30 UnityWindow::SetupSharedTextures();
31+
32+ for (auto const& swin : ScaleScreen::get(screen)->getWindows())
33+ UnityWindow::get(swin->window)->CleanupCachedTextures();
34+ }
35 }
36
37 void UnityScreen::paintDisplay()
38@@ -3380,11 +3382,23 @@
39 GLTexture::List UnityWindow::close_prelight_tex_;
40 GLTexture::List UnityWindow::close_pressed_tex_;
41
42+namespace scale
43+{
44+namespace decoration
45+{
46+const unsigned CLOSE_SIZE = 19;
47+const unsigned ITEMS_PADDING = 5;
48+const unsigned RADIUS = 8;
49+}
50+}
51+
52 struct UnityWindow::CairoContext
53 {
54- CairoContext(int width, int height)
55- : pixmap_(XCreatePixmap(screen->dpy(), screen->root(), width, height, 32))
56- , texture_(GLTexture::bindPixmapToTexture(pixmap_, width, height, 32))
57+ CairoContext(unsigned width, unsigned height)
58+ : w_(width)
59+ , h_(height)
60+ , pixmap_(XCreatePixmap(screen->dpy(), screen->root(), w_, h_, 32))
61+ , texture_(GLTexture::bindPixmapToTexture(pixmap_, w_, h_, 32))
62 , surface_(nullptr)
63 , cr_(nullptr)
64 {
65@@ -3406,7 +3420,7 @@
66 cairo_restore(cr_);
67 }
68
69- ~CairoContext ()
70+ ~CairoContext()
71 {
72 if (cr_)
73 cairo_destroy(cr_);
74@@ -3414,12 +3428,12 @@
75 if (surface_)
76 cairo_surface_destroy(surface_);
77
78- texture_.clear();
79-
80 if (pixmap_)
81- XFreePixmap(screen->dpy (), pixmap_);
82+ XFreePixmap(screen->dpy(), pixmap_);
83 }
84
85+ unsigned w_;
86+ unsigned h_;
87 Pixmap pixmap_;
88 GLTexture::List texture_;
89 cairo_surface_t* surface_;
90@@ -3478,8 +3492,8 @@
91 }
92 }
93
94- WindowManager::Default()->initiate_spread.connect(sigc::mem_fun(this, &UnityWindow::OnInitiateSpreed));
95- WindowManager::Default()->terminate_spread.connect(sigc::mem_fun(this, &UnityWindow::OnTerminateSpreed));
96+ WindowManager::Default()->initiate_spread.connect(sigc::mem_fun(this, &UnityWindow::OnInitiateSpread));
97+ WindowManager::Default()->terminate_spread.connect(sigc::mem_fun(this, &UnityWindow::OnTerminateSpread));
98 }
99
100 void UnityWindow::AddProperties(GVariantBuilder* builder)
101@@ -3505,8 +3519,9 @@
102 return "Window";
103 }
104
105+
106 void UnityWindow::DrawTexture(GLTexture::List const& textures, GLWindowPaintAttrib const& attrib,
107- GLMatrix const& transform, unsigned int mask, int x, int y)
108+ GLMatrix const& transform, unsigned int mask, int x, int y, double scale)
109 {
110 for (auto const& texture : textures)
111 {
112@@ -3527,12 +3542,40 @@
113 {
114 GLMatrix wTransform(transform);
115 wTransform.translate(x, y, 0.0f);
116+ wTransform.scale(scale, scale, 1.0f);
117
118 gWindow->glDrawTexture(texture, wTransform, attrib, mask);
119 }
120 }
121 }
122
123+void UnityWindow::RenderDecoration(CairoContext const& context, double aspect)
124+{
125+ cairo_save(context.cr_);
126+
127+ // Draw window decoration based on gtk style
128+ cairo_push_group(context.cr_);
129+ auto& style = panel::Style::Instance();
130+ gtk_render_background(style.GetStyleContext(), context.cr_, 0, 0, context.w_, context.h_);
131+ gtk_render_frame(style.GetStyleContext(), context.cr_, 0, 0, context.w_, context.h_);
132+ cairo_pop_group_to_source(context.cr_);
133+
134+ // Round window decoration top border
135+ const double radius = scale::decoration::RADIUS * aspect;
136+
137+ cairo_new_sub_path(context.cr_);
138+ cairo_line_to(context.cr_, 0, context.h_);
139+ cairo_arc(context.cr_, radius, radius, radius, M_PI, -M_PI * 0.5f);
140+ cairo_line_to(context.cr_, context.w_ - radius, 0);
141+ cairo_arc(context.cr_, context.w_ - radius, radius, radius, M_PI * 0.5f, 0);
142+ cairo_line_to(context.cr_, context.w_, context.h_);
143+ cairo_close_path(context.cr_);
144+
145+ cairo_fill(context.cr_);
146+
147+ cairo_restore(context.cr_);
148+}
149+
150 void UnityWindow::RenderText(CairoContext const& context, int x, int y, int width, int height)
151 {
152 panel::Style& style = panel::Style::Instance();
153@@ -3552,11 +3595,11 @@
154 pango_cairo_context_set_resolution(pango_ctx, dpi / static_cast<float>(PANGO_SCALE));
155 pango_layout_context_changed(layout);
156
157- std::string const& win_title = WindowManager::Default()->GetWindowName(window->id());
158+ decoration_title_ = WindowManager::Default()->GetWindowName(window->id());
159 pango_layout_set_height(layout, height);
160 pango_layout_set_width(layout, -1); //avoid wrap lines
161 pango_layout_set_auto_dir(layout, false);
162- pango_layout_set_text(layout, win_title.c_str(), -1);
163+ pango_layout_set_text(layout, decoration_title_.c_str(), -1);
164
165 /* update the size of the pango layout */
166 pango_cairo_update_layout(context.cr_, layout);
167@@ -3578,8 +3621,8 @@
168 pango_layout_get_extents(layout, nullptr, &lRect);
169 int text_width = lRect.width / PANGO_SCALE;
170 int text_height = lRect.height / PANGO_SCALE;
171+ int text_space = width - x;
172 y += (height - text_height) / 2.0f;
173- int text_space = width - x;
174
175 if (text_width > text_space)
176 {
177@@ -3606,49 +3649,19 @@
178 gtk_style_context_restore(style_context);
179 }
180
181-void UnityWindow::DrawWindowDecoration(GLWindowPaintAttrib const& attrib,
182- GLMatrix const& transform,
183- unsigned int mask,
184- bool highlighted,
185- int x, int y, unsigned width, unsigned height)
186+void UnityWindow::BuildDecorationTexture()
187 {
188- // Paint a fake window decoration
189- CairoContext context(width, height);
190-
191- cairo_save(context.cr_);
192-
193- // Draw window decoration based on gtk style
194- cairo_push_group(context.cr_);
195- auto& style = panel::Style::Instance();
196- gtk_render_background(style.GetStyleContext(), context.cr_, 0, 0, width, height);
197- gtk_render_frame(style.GetStyleContext(), context.cr_, 0, 0, width, height);
198- cairo_pop_group_to_source(context.cr_);
199-
200- // Round window decoration top border
201- const double aspect = ScaleWindow::get(window)->getCurrentPosition().scale;
202- const double radius = 8.0 * aspect;
203-
204- cairo_new_sub_path(context.cr_);
205- cairo_line_to(context.cr_, 0, height);
206- cairo_arc(context.cr_, radius, radius, radius, M_PI, -M_PI * 0.5f);
207- cairo_line_to(context.cr_, width - radius, 0);
208- cairo_arc(context.cr_, width - radius, radius, radius, M_PI * 0.5f, 0);
209- cairo_line_to(context.cr_, width, height);
210- cairo_close_path(context.cr_);
211-
212- cairo_fill(context.cr_);
213-
214- cairo_restore(context.cr_);
215-
216- if (highlighted)
217+ if (!decoration_tex_.empty())
218+ return;
219+
220+ auto const& border_extents = window->border();
221+
222+ if (WindowManager::Default()->IsWindowDecorated(window->id()) && border_extents.top > 0)
223 {
224- // Draw windows title
225- const float xText = SCALE_ITEMS_PADDING * 2 + SCALE_CLOSE_ICON_SIZE;
226- RenderText(context, xText, 0.0, width - SCALE_ITEMS_PADDING, height);
227+ CairoContext context(window->borderRect().width(), border_extents.top);
228+ RenderDecoration(context);
229+ decoration_tex_ = context.texture_;
230 }
231-
232- mask |= PAINT_WINDOW_BLEND_MASK;
233- DrawTexture(context.texture_, attrib, transform, mask, x, y);
234 }
235
236 void UnityWindow::LoadCloseIcon(panel::WindowState state, GLTexture::List& texture)
237@@ -3663,7 +3676,7 @@
238 for (std::string const& file : files)
239 {
240 CompString file_name = file;
241- CompSize size(SCALE_CLOSE_ICON_SIZE, SCALE_CLOSE_ICON_SIZE);
242+ CompSize size(scale::decoration::CLOSE_SIZE, scale::decoration::CLOSE_SIZE);
243 texture = GLTexture::readImageToTexture(file_name, plugin, size);
244 if (!texture.empty())
245 break;
246@@ -3678,7 +3691,7 @@
247 suffix = "_pressed";
248
249 CompString file_name(PKGDATADIR"/close_dash" + suffix + ".png");
250- CompSize size(SCALE_CLOSE_ICON_SIZE, SCALE_CLOSE_ICON_SIZE);
251+ CompSize size(scale::decoration::CLOSE_SIZE, scale::decoration::CLOSE_SIZE);
252 texture = GLTexture::readImageToTexture(file_name, plugin, size);
253 }
254 }
255@@ -3697,6 +3710,13 @@
256 close_pressed_tex_.clear();
257 }
258
259+void UnityWindow::CleanupCachedTextures()
260+{
261+ decoration_tex_.clear();
262+ decoration_selected_tex_.clear();
263+ decoration_title_.clear();
264+}
265+
266 void UnityWindow::scalePaintDecoration(GLWindowPaintAttrib const& attrib,
267 GLMatrix const& transform,
268 CompRegion const& region,
269@@ -3715,27 +3735,53 @@
270 return;
271
272 auto const& scaled_geo = GetScaledGeometry();
273- auto const& decoration_extents = window->border();
274 auto const& pos = scale_win->getCurrentPosition();
275
276 const bool highlighted = (ss->getSelectedWindow() == window->id());
277- int width = scaled_geo.width;
278- int height = decoration_extents.top;
279 int x = scaled_geo.x;
280 int y = scaled_geo.y;
281
282+ mask |= PAINT_WINDOW_BLEND_MASK;
283
284- // If window is not highlighted, we draw the decoration at scaled size
285 if (!highlighted)
286- height *= pos.scale;
287-
288- DrawWindowDecoration(attrib, transform, mask, highlighted, x, y, width, height);
289-
290- if (highlighted)
291- {
292- x += SCALE_ITEMS_PADDING;
293- y += (height - SCALE_CLOSE_ICON_SIZE) / 2.0f;
294- mask |= PAINT_WINDOW_BLEND_MASK;
295+ {
296+ BuildDecorationTexture();
297+ DrawTexture(decoration_tex_, attrib, transform, mask, x, y, pos.scale);
298+ close_button_geo_.Set(0, 0, 0, 0);
299+ }
300+ else
301+ {
302+ auto const& decoration_extents = window->border();
303+ int width = scaled_geo.width;
304+ int height = decoration_extents.top;
305+ bool redraw_decoration = true;
306+
307+ if (!decoration_selected_tex_.empty())
308+ {
309+ GLTexture* texture = decoration_selected_tex_.front();
310+
311+ if (texture->width() == width && texture->height() == height)
312+ {
313+ if (decoration_title_ == WindowManager::Default()->GetWindowName(window->id()))
314+ redraw_decoration = false;
315+ }
316+ }
317+
318+ if (redraw_decoration)
319+ {
320+ CairoContext context(width, height);
321+ RenderDecoration(context, pos.scale);
322+
323+ // Draw window title
324+ int text_x = scale::decoration::ITEMS_PADDING * 2 + scale::decoration::CLOSE_SIZE;
325+ RenderText(context, text_x, 0.0, width - scale::decoration::ITEMS_PADDING, height);
326+ decoration_selected_tex_ = context.texture_;
327+ }
328+
329+ DrawTexture(decoration_selected_tex_, attrib, transform, mask, x, y);
330+
331+ x += scale::decoration::ITEMS_PADDING;
332+ y += (height - scale::decoration::CLOSE_SIZE) / 2.0f;
333
334 switch (close_icon_state_)
335 {
336@@ -3753,11 +3799,7 @@
337 break;
338 }
339
340- close_button_geo_.Set(x, y, SCALE_CLOSE_ICON_SIZE, SCALE_CLOSE_ICON_SIZE);
341- }
342- else if (!close_button_geo_.IsNull())
343- {
344- close_button_geo_.Set(0, 0, 0, 0);
345+ close_button_geo_.Set(x, y, scale::decoration::CLOSE_SIZE, scale::decoration::CLOSE_SIZE);
346 }
347 }
348
349@@ -3777,7 +3819,7 @@
350 return nux::Geometry(x, y, width, height);
351 }
352
353-void UnityWindow::OnInitiateSpreed()
354+void UnityWindow::OnInitiateSpread()
355 {
356 close_icon_state_ = panel::WindowState::NORMAL;
357 middle_clicked_ = false;
358@@ -3790,13 +3832,15 @@
359 wm->Decorate(xid);
360 }
361
362-void UnityWindow::OnTerminateSpreed()
363+void UnityWindow::OnTerminateSpread()
364 {
365 WindowManager *wm = WindowManager::Default();
366 Window xid = window->id();
367
368 if (wm->IsWindowDecorated(xid) && wm->IsWindowMaximized(xid))
369 wm->Undecorate(xid);
370+
371+ CleanupCachedTextures();
372 }
373
374 UnityWindow::~UnityWindow()
375
376=== modified file 'plugins/unityshell/src/unityshell.h'
377--- plugins/unityshell/src/unityshell.h 2012-09-24 15:22:57 +0000
378+++ plugins/unityshell/src/unityshell.h 2012-09-24 18:46:21 +0000
379@@ -359,34 +359,22 @@
380
381 nux::Geometry last_bound;
382
383- void minimize ();
384- void unminimize ();
385- bool minimized ();
386- bool focus ();
387- void activate ();
388+ void minimize();
389+ void unminimize();
390+ bool minimized();
391+ bool focus();
392+ void activate();
393
394- void updateFrameRegion (CompRegion &region);
395+ void updateFrameRegion(CompRegion &region);
396
397 /* occlusion detection
398 * and window hiding */
399- bool glPaint(const GLWindowPaintAttrib& attrib,
400- const GLMatrix& matrix,
401- const CompRegion& region,
402- unsigned int mask);
403+ bool glPaint(GLWindowPaintAttrib const&, GLMatrix const&, CompRegion const&, unsigned mask);
404
405 /* basic window draw function */
406- bool glDraw(const GLMatrix& matrix,
407- const GLWindowPaintAttrib& attrib,
408- const CompRegion& region,
409- unsigned intmask);
410-
411- void updateIconPos (int &wx,
412- int &wy,
413- int x,
414- int y,
415- float width,
416- float height);
417-
418+ bool glDraw(GLMatrix const&, GLWindowPaintAttrib const&, CompRegion const&, unsigned mask);
419+
420+ void updateIconPos (int &wx, int &wy, int x, int y, float width, float height);
421 void windowNotify(CompWindowNotify n);
422 void moveNotify(int x, int y, bool immediate);
423 void resizeNotify(int x, int y, int w, int h);
424@@ -396,32 +384,26 @@
425 CompPoint tryNotIntersectUI(CompPoint& pos);
426 nux::Geometry GetScaledGeometry();
427
428- void paintThumbnail (nux::Geometry const& bounding, float alpha);
429+ void paintThumbnail(nux::Geometry const& bounding, float alpha);
430
431- void enterShowDesktop ();
432- void leaveShowDesktop ();
433- bool HandleAnimations (unsigned int ms);
434+ void enterShowDesktop();
435+ void leaveShowDesktop();
436+ bool HandleAnimations(unsigned int ms);
437
438 bool handleEvent(XEvent *event);
439-
440+ void scalePaintDecoration(GLWindowPaintAttrib const&, GLMatrix const&, CompRegion const&, unsigned mask);
441+
442+ //! Emited when CompWindowNotifyBeforeDestroy is received
443+ sigc::signal<void> being_destroyed;
444+
445+
446+protected:
447+ std::string GetName() const;
448+ void AddProperties(GVariantBuilder* builder);
449+
450+private:
451 typedef compiz::CompizMinimizedWindowHandler<UnityScreen, UnityWindow>
452 UnityMinimizedHandler;
453- std::unique_ptr <UnityMinimizedHandler> mMinimizeHandler;
454- std::unique_ptr <ShowdesktopHandler> mShowdesktopHandler;
455-
456- //! Emited when CompWindowNotifyBeforeDestroy is received
457- sigc::signal<void> being_destroyed;
458-
459- void scalePaintDecoration(const GLWindowPaintAttrib &,
460- const GLMatrix &,
461- const CompRegion &,
462- unsigned int);
463-
464-protected:
465- std::string GetName() const;
466- void AddProperties(GVariantBuilder* builder);
467-
468-private:
469 struct CairoContext;
470
471 void DoEnableFocus ();
472@@ -443,8 +425,8 @@
473 void DoShow ();
474 void DoNotifyShown ();
475
476- void OnInitiateSpreed();
477- void OnTerminateSpreed();
478+ void OnInitiateSpread();
479+ void OnTerminateSpread();
480
481 void DoAddDamage ();
482 ShowdesktopHandlerWindowInterface::PostPaintAction DoHandleAnimations (unsigned int ms);
483@@ -457,20 +439,28 @@
484
485 compiz::WindowInputRemoverLock::Ptr GetInputRemover ();
486
487- void DrawWindowDecoration(GLWindowPaintAttrib const& attrib, GLMatrix const& transform,
488- unsigned int mask, bool highlighted,
489- int x, int y, unsigned width, unsigned height);
490- void DrawTexture(GLTexture::List const& textures, GLWindowPaintAttrib const& attrib,
491- GLMatrix const& transform, unsigned int mask, int x, int y);
492- void RenderText(CairoContext const& context, int x, int y, int width, int height);
493+ void RenderDecoration(CairoContext const&, double aspect = 1.0f);
494+ void RenderText(CairoContext const&, int x, int y, int width, int height);
495+ void DrawTexture(GLTexture::List const& textures, GLWindowPaintAttrib const&,
496+ GLMatrix const&, unsigned mask, int x, int y, double scale = 1.0f);
497
498+ void BuildDecorationTexture();
499+ void CleanupCachedTextures();
500 static void SetupSharedTextures();
501 static void CleanupSharedTextures();
502 static void LoadCloseIcon(panel::WindowState state, GLTexture::List& texture);
503
504+public:
505+ std::unique_ptr <UnityMinimizedHandler> mMinimizeHandler;
506+
507+private:
508+ std::unique_ptr <ShowdesktopHandler> mShowdesktopHandler;
509 static GLTexture::List close_normal_tex_;
510 static GLTexture::List close_prelight_tex_;
511 static GLTexture::List close_pressed_tex_;
512+ GLTexture::List decoration_tex_;
513+ GLTexture::List decoration_selected_tex_;
514+ std::string decoration_title_;
515 compiz::WindowInputRemoverLock::Weak input_remover_;
516 panel::WindowState close_icon_state_;
517 nux::Geometry close_button_geo_;