Merge lp:~compiz-team/compiz/compiz.fix_1016366 into lp:compiz/0.9.8

Proposed by Sam Spilsbury
Status: Merged
Merged at revision: 3274
Proposed branch: lp:~compiz-team/compiz/compiz.fix_1016366
Merge into: lp:compiz/0.9.8
Diff against target: 590 lines (+215/-101)
8 files modified
plugins/composite/include/composite/composite.h (+5/-0)
plugins/composite/src/pixmapbinding/include/pixmapbinding.h (+11/-0)
plugins/composite/src/pixmapbinding/src/pixmapbinding.cpp (+4/-1)
plugins/composite/src/pixmapbinding/tests/test-composite-pixmapbinding.cpp (+128/-48)
plugins/composite/src/privates.h (+4/-1)
plugins/composite/src/window.cpp (+23/-13)
plugins/opengl/src/window.cpp (+37/-33)
src/window.cpp (+3/-5)
To merge this branch: bzr merge lp:~compiz-team/compiz/compiz.fix_1016366
Reviewer Review Type Date Requested Status
Daniel van Vugt Approve
Review via email: mp+111541@code.launchpad.net

Description of the change

== Problem ==
There are a few cases where textures can become invalid because a pixmap went away and a plugin is keeping the texture around for animations (eg, unmapRefCnt).

This is anywhere where CompositeWindow::release () can be called from, which includes frame updates, map, unmap, resize etc. In those cases, some drivers may not report a failure to bind the texture and we will have an invalid texture.

== Solution ==
Don't allow unbinds of textures kept around for animations in
any case, not just resizing.

== Test ==
Covered by existing unit tests.

To post a comment you must log in.
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Works nicely on intel. I'll retest with NVIDIA later.

I would suggest making frozen() const. But it looks like that might not be possible because it uses CompWindow which is not const-friendly.

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

Also OK on NVIDIA.

For future reference, I would suggest not using names like:
   class PixmapFreezerInterface
And instead use something like:
   class FreezablePixmap

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/composite/include/composite/composite.h'
2--- plugins/composite/include/composite/composite.h 2012-06-06 05:12:28 +0000
3+++ plugins/composite/include/composite/composite.h 2012-06-22 05:29:36 +0000
4@@ -371,6 +371,11 @@
5 bool redirected ();
6 bool overlayWindow ();
7
8+ /**
9+ * Returns true if pixmap updates are frozen
10+ */
11+ bool frozen ();
12+
13 void damageTransformedRect (float xScale,
14 float yScale,
15 float xTranslate,
16
17=== modified file 'plugins/composite/src/pixmapbinding/include/pixmapbinding.h'
18--- plugins/composite/src/pixmapbinding/include/pixmapbinding.h 2012-05-31 07:15:37 +0000
19+++ plugins/composite/src/pixmapbinding/include/pixmapbinding.h 2012-06-22 05:29:36 +0000
20@@ -61,6 +61,15 @@
21 virtual void allowFurtherRebindAttempts () = 0;
22 };
23
24+class PixmapFreezerInterface
25+{
26+ public:
27+
28+ virtual ~PixmapFreezerInterface () {}
29+
30+ virtual bool frozen () = 0;
31+};
32+
33 class WindowAttributesGetInterface
34 {
35 public:
36@@ -163,6 +172,7 @@
37 PixmapBinding (const NewPixmapReadyCallback &,
38 WindowPixmapGetInterface *,
39 WindowAttributesGetInterface *,
40+ PixmapFreezerInterface *,
41 ServerGrabInterface *);
42
43 ~PixmapBinding ();
44@@ -184,6 +194,7 @@
45
46 WindowPixmapGetInterface *windowPixmapRetreiver;
47 WindowAttributesGetInterface *windowAttributesRetreiver;
48+ PixmapFreezerInterface *pixmapFreezer;
49 ServerGrabInterface *serverGrab;
50
51 };
52
53=== modified file 'plugins/composite/src/pixmapbinding/src/pixmapbinding.cpp'
54--- plugins/composite/src/pixmapbinding/src/pixmapbinding.cpp 2012-05-31 07:15:37 +0000
55+++ plugins/composite/src/pixmapbinding/src/pixmapbinding.cpp 2012-06-22 05:29:36 +0000
56@@ -33,6 +33,7 @@
57 PixmapBinding::PixmapBinding (const NewPixmapReadyCallback &cb,
58 WindowPixmapGetInterface *pmg,
59 WindowAttributesGetInterface *wag,
60+ PixmapFreezerInterface *pf,
61 ServerGrabInterface *sg) :
62 mPixmap (),
63 mSize (),
64@@ -41,6 +42,7 @@
65 newPixmapReadyCallback (cb),
66 windowPixmapRetreiver (pmg),
67 windowAttributesRetreiver (wag),
68+ pixmapFreezer (pf),
69 serverGrab (sg)
70 {
71 }
72@@ -124,7 +126,8 @@
73 void
74 PixmapBinding::release ()
75 {
76- needsRebind = true;
77+ if (!pixmapFreezer->frozen ())
78+ needsRebind = true;
79 }
80
81 void
82
83=== modified file 'plugins/composite/src/pixmapbinding/tests/test-composite-pixmapbinding.cpp'
84--- plugins/composite/src/pixmapbinding/tests/test-composite-pixmapbinding.cpp 2012-06-01 07:49:55 +0000
85+++ plugins/composite/src/pixmapbinding/tests/test-composite-pixmapbinding.cpp 2012-06-22 05:29:36 +0000
86@@ -41,6 +41,14 @@
87 {
88 };
89
90+class MockPixmapFreezer :
91+ public PixmapFreezerInterface
92+{
93+ public:
94+
95+ MOCK_METHOD0 (frozen, bool ());
96+};
97+
98 class MockWindowPixmapGet :
99 public WindowPixmapGetInterface
100 {
101@@ -136,6 +144,7 @@
102 MockWindowPixmapGet mwpg;
103 MockWindowAttributesGet mwag;
104 MockServerGrab msg;
105+ MockPixmapFreezer mpf;
106 XWindowAttributes xwa;
107
108 xwa.width = 100;
109@@ -152,6 +161,7 @@
110 PixmapBinding pr (readyCb,
111 &mwpg,
112 &mwag,
113+ &mpf,
114 &msg);
115
116 EXPECT_CALL (msg, grabServer ());
117@@ -181,6 +191,7 @@
118 MockWindowPixmapGet mwpg;
119 MockWindowAttributesGet mwag;
120 MockServerGrab msg;
121+ MockPixmapFreezer mpf;
122 XWindowAttributes xwa;
123
124 xwa.width = 100;
125@@ -197,6 +208,7 @@
126 PixmapBinding pr (readyCb,
127 &mwpg,
128 &mwag,
129+ &mpf,
130 &msg);
131
132 EXPECT_CALL (msg, grabServer ());
133@@ -227,54 +239,114 @@
134 MockWindowPixmapGet mwpg;
135 MockWindowAttributesGet mwag;
136 MockServerGrab msg;
137- XWindowAttributes xwa;
138-
139- xwa.width = 100;
140- xwa.height = 200;
141- xwa.map_state = IsViewable;
142- xwa.border_width = 1;
143-
144- FakeWindowAttributesGet fwag (xwa);
145-
146- MockPixmapReady ready;
147-
148- boost::function <void ()> readyCb (boost::bind (&PixmapReadyInterface::ready, &ready));
149-
150- PixmapBinding pr (readyCb,
151- &mwpg,
152- &mwag,
153- &msg);
154-
155- EXPECT_CALL (msg, grabServer ());
156- EXPECT_CALL (msg, syncServer ()).Times (2);
157- EXPECT_CALL (mwag, getAttributes (_)).WillOnce (Invoke (&fwag, &FakeWindowAttributesGet::getAttributes));
158- EXPECT_CALL (mwpg, getPixmap ()).WillOnce (Return (boost::shared_static_cast <WindowPixmapInterface> (wp)));
159-
160- EXPECT_CALL (*wp, pixmap ()).WillOnce (Return (1));
161-
162- EXPECT_CALL (ready, ready ());
163- EXPECT_CALL (msg, ungrabServer ());
164-
165- EXPECT_TRUE (pr.bind ());
166-
167- EXPECT_CALL (*wp, pixmap ()).WillOnce (Return (1));
168-
169- EXPECT_EQ (pr.pixmap (), 1);
170- EXPECT_EQ (pr.size (), CompSize (102, 202));
171-
172- EXPECT_CALL (*wp, releasePixmap ());
173-
174- pr.release ();
175-
176- EXPECT_CALL (msg, grabServer ());
177- EXPECT_CALL (msg, syncServer ()).Times (2);
178- EXPECT_CALL (mwag, getAttributes (_)).WillOnce (Invoke (&fwag, &FakeWindowAttributesGet::getAttributes));
179- EXPECT_CALL (mwpg, getPixmap ()).WillOnce (Return (boost::shared_static_cast <WindowPixmapInterface> (wp)));
180-
181- EXPECT_CALL (*wp, pixmap ()).WillOnce (Return (1));
182-
183- EXPECT_CALL (ready, ready ());
184- EXPECT_CALL (msg, ungrabServer ());
185+ MockPixmapFreezer mpf;
186+ XWindowAttributes xwa;
187+
188+ xwa.width = 100;
189+ xwa.height = 200;
190+ xwa.map_state = IsViewable;
191+ xwa.border_width = 1;
192+
193+ FakeWindowAttributesGet fwag (xwa);
194+
195+ MockPixmapReady ready;
196+
197+ boost::function <void ()> readyCb (boost::bind (&PixmapReadyInterface::ready, &ready));
198+
199+ PixmapBinding pr (readyCb,
200+ &mwpg,
201+ &mwag,
202+ &mpf,
203+ &msg);
204+
205+ EXPECT_CALL (msg, grabServer ());
206+ EXPECT_CALL (msg, syncServer ()).Times (2);
207+ EXPECT_CALL (mwag, getAttributes (_)).WillOnce (Invoke (&fwag, &FakeWindowAttributesGet::getAttributes));
208+ EXPECT_CALL (mwpg, getPixmap ()).WillOnce (Return (boost::shared_static_cast <WindowPixmapInterface> (wp)));
209+
210+ EXPECT_CALL (*wp, pixmap ()).WillOnce (Return (1));
211+
212+ EXPECT_CALL (ready, ready ());
213+ EXPECT_CALL (msg, ungrabServer ());
214+
215+ EXPECT_TRUE (pr.bind ());
216+
217+ EXPECT_CALL (mpf, frozen ()).WillOnce (Return (false));
218+ EXPECT_CALL (*wp, pixmap ()).WillOnce (Return (1));
219+
220+ EXPECT_EQ (pr.pixmap (), 1);
221+ EXPECT_EQ (pr.size (), CompSize (102, 202));
222+
223+ EXPECT_CALL (*wp, releasePixmap ());
224+
225+ pr.release ();
226+
227+ EXPECT_CALL (msg, grabServer ());
228+ EXPECT_CALL (msg, syncServer ()).Times (2);
229+ EXPECT_CALL (mwag, getAttributes (_)).WillOnce (Invoke (&fwag, &FakeWindowAttributesGet::getAttributes));
230+ EXPECT_CALL (mwpg, getPixmap ()).WillOnce (Return (boost::shared_static_cast <WindowPixmapInterface> (wp)));
231+
232+ EXPECT_CALL (*wp, pixmap ()).WillOnce (Return (1));
233+
234+ EXPECT_CALL (ready, ready ());
235+ EXPECT_CALL (msg, ungrabServer ());
236+
237+ EXPECT_TRUE (pr.bind ());
238+
239+ EXPECT_CALL (*wp, pixmap ()).WillOnce (Return (1));
240+
241+ EXPECT_EQ (pr.pixmap (), 1);
242+ EXPECT_EQ (pr.size (), CompSize (102, 202));
243+
244+ EXPECT_CALL (*wp, releasePixmap ());
245+}
246+
247+TEST(CompositePixmapBinderTest, TestNoRebindAfterReleaseWhenFrozen)
248+{
249+ MockPixmap::Ptr wp (boost::make_shared <MockPixmap> ());
250+
251+ MockWindowPixmapGet mwpg;
252+ MockWindowAttributesGet mwag;
253+ MockServerGrab msg;
254+ MockPixmapFreezer mpf;
255+ XWindowAttributes xwa;
256+
257+ xwa.width = 100;
258+ xwa.height = 200;
259+ xwa.map_state = IsViewable;
260+ xwa.border_width = 1;
261+
262+ FakeWindowAttributesGet fwag (xwa);
263+
264+ MockPixmapReady ready;
265+
266+ boost::function <void ()> readyCb (boost::bind (&PixmapReadyInterface::ready, &ready));
267+
268+ PixmapBinding pr (readyCb,
269+ &mwpg,
270+ &mwag,
271+ &mpf,
272+ &msg);
273+
274+ EXPECT_CALL (msg, grabServer ());
275+ EXPECT_CALL (msg, syncServer ()).Times (2);
276+ EXPECT_CALL (mwag, getAttributes (_)).WillOnce (Invoke (&fwag, &FakeWindowAttributesGet::getAttributes));
277+ EXPECT_CALL (mwpg, getPixmap ()).WillOnce (Return (boost::shared_static_cast <WindowPixmapInterface> (wp)));
278+
279+ EXPECT_CALL (*wp, pixmap ()).WillOnce (Return (1));
280+
281+ EXPECT_CALL (ready, ready ());
282+ EXPECT_CALL (msg, ungrabServer ());
283+
284+ EXPECT_TRUE (pr.bind ());
285+
286+ EXPECT_CALL (mpf, frozen ()).WillOnce (Return (true));
287+ EXPECT_CALL (*wp, pixmap ()).WillOnce (Return (1));
288+
289+ EXPECT_EQ (pr.pixmap (), 1);
290+ EXPECT_EQ (pr.size (), CompSize (102, 202));
291+
292+ pr.release ();
293
294 EXPECT_TRUE (pr.bind ());
295
296@@ -291,6 +363,7 @@
297 MockWindowPixmapGet mwpg;
298 MockWindowAttributesGet mwag;
299 MockServerGrab msg;
300+ MockPixmapFreezer mpf;
301 XWindowAttributes xwa;
302
303 xwa.width = 100;
304@@ -303,6 +376,7 @@
305 PixmapBinding pr (boost::function <void ()> (),
306 &mwpg,
307 &mwag,
308+ &mpf,
309 &msg);
310
311 EXPECT_CALL (msg, grabServer ());
312@@ -322,6 +396,7 @@
313 MockWindowPixmapGet mwpg;
314 MockWindowAttributesGet mwag;
315 MockServerGrab msg;
316+ MockPixmapFreezer mpf;
317 XWindowAttributes xwa;
318
319 xwa.width = 0;
320@@ -334,6 +409,7 @@
321 PixmapBinding pr (boost::function <void ()> (),
322 &mwpg,
323 &mwag,
324+ &mpf,
325 &msg);
326
327 EXPECT_CALL (msg, grabServer ());
328@@ -355,6 +431,7 @@
329 MockWindowPixmapGet mwpg;
330 MockWindowAttributesGet mwag;
331 MockServerGrab msg;
332+ MockPixmapFreezer mpf;
333 XWindowAttributes xwa;
334
335 xwa.width = 100;
336@@ -367,6 +444,7 @@
337 PixmapBinding pr (boost::function <void ()> (),
338 &mwpg,
339 &mwag,
340+ &mpf,
341 &msg);
342
343 EXPECT_CALL (msg, grabServer ());
344@@ -391,6 +469,7 @@
345 MockWindowPixmapGet mwpg;
346 MockWindowAttributesGet mwag;
347 MockServerGrab msg;
348+ MockPixmapFreezer mpf;
349 XWindowAttributes xwa;
350
351 xwa.width = 100;
352@@ -403,6 +482,7 @@
353 PixmapBinding pr (boost::function <void ()> (),
354 &mwpg,
355 &mwag,
356+ &mpf,
357 &msg);
358
359 EXPECT_CALL (msg, grabServer ());
360
361=== modified file 'plugins/composite/src/privates.h'
362--- plugins/composite/src/privates.h 2012-06-06 05:12:28 +0000
363+++ plugins/composite/src/privates.h 2012-06-22 05:29:36 +0000
364@@ -116,7 +116,8 @@
365 public WindowInterface,
366 public CompositePixmapRebindInterface,
367 public WindowPixmapGetInterface,
368- public WindowAttributesGetInterface
369+ public WindowAttributesGetInterface,
370+ public PixmapFreezerInterface
371 {
372 public:
373 PrivateCompositeWindow (CompWindow *w, CompositeWindow *cw);
374@@ -132,6 +133,7 @@
375 void release ();
376 void setNewPixmapReadyCallback (const boost::function <void ()> &);
377 void allowFurtherRebindAttempts ();
378+ bool frozen ();
379
380 static void handleDamageRect (CompositeWindow *w,
381 int x,
382@@ -159,6 +161,7 @@
383 XRectangle *damageRects;
384 int sizeDamage;
385 int nDamage;
386+
387 private:
388
389 bool getAttributes (XWindowAttributes &);
390
391=== modified file 'plugins/composite/src/window.cpp'
392--- plugins/composite/src/window.cpp 2012-06-06 05:12:28 +0000
393+++ plugins/composite/src/window.cpp 2012-06-22 05:29:36 +0000
394@@ -108,6 +108,7 @@
395 mPixmapBinding (boost::function <void ()> (),
396 this,
397 this,
398+ this,
399 screen->serverGrabInterface ()),
400 damage (None),
401 damaged (false),
402@@ -184,6 +185,21 @@
403 return false;
404 }
405
406+bool
407+PrivateCompositeWindow::frozen ()
408+{
409+ /* keep old pixmap for windows that are unmapped on the client side,
410+ * but not yet on our side as it's pretty likely that plugins are
411+ * currently using it for animations
412+ */
413+
414+ bool pendingUnmap = !window->mapNum () && window->isViewable ();
415+ bool hidden = window->state () & CompWindowStateHiddenMask;
416+ bool animated = window->hasUnmapReference ();
417+
418+ return (pendingUnmap || hidden) && animated;
419+}
420+
421 Pixmap
422 CompositeWindow::pixmap ()
423 {
424@@ -260,6 +276,12 @@
425 return priv->overlayWindow;
426 }
427
428+bool
429+CompositeWindow::frozen ()
430+{
431+ return priv->frozen ();
432+}
433+
434 void
435 CompositeWindow::damageTransformedRect (float xScale,
436 float yScale,
437@@ -605,19 +627,7 @@
438 cScreen->damageRegion (CompRegion (CompRect (x1, y1, x2 - x1, y2 - y1)));
439 }
440
441- if (((!window->mapNum () && window->isViewable ()) ||
442- window->state () & CompWindowStateHiddenMask) && window->hasUnmapReference ())
443- {
444- /* keep old pixmap for windows that are unmapped on the client side,
445- * but not yet on our side as it's pretty likely that plugins are
446- * currently using it for animations
447- */
448- }
449- else
450- {
451- cWindow->release ();
452- }
453-
454+ cWindow->release ();
455 cWindow->addDamage ();
456 }
457
458
459=== modified file 'plugins/opengl/src/window.cpp'
460--- plugins/opengl/src/window.cpp 2012-05-26 02:48:05 +0000
461+++ plugins/opengl/src/window.cpp 2012-06-22 05:29:36 +0000
462@@ -104,37 +104,42 @@
463 bool
464 GLWindow::bind ()
465 {
466- if ((priv->needsRebind && !priv->cWindow->bind ()))
467+ if (priv->needsRebind)
468 {
469- if (!priv->textures.empty ())
470- {
471- /* Getting a new pixmap failed, recycle the old texture */
472+ if (!priv->cWindow->bind ())
473+ {
474+ if (!priv->textures.empty ())
475+ {
476+ /* Getting a new pixmap failed, recycle the old texture */
477+ priv->needsRebind = false;
478+ return true;
479+ }
480+ else
481+ return false;
482+ }
483+
484+ GLTexture::List textures =
485+ GLTexture::bindPixmapToTexture (priv->cWindow->pixmap (),
486+ priv->cWindow->size ().width (),
487+ priv->cWindow->size ().height (),
488+ priv->window->depth ());
489+ if (textures.empty ())
490+ {
491+ compLogMessage ("opengl", CompLogLevelInfo,
492+ "Couldn't bind redirected window 0x%x to "
493+ "texture\n", (int) priv->window->id ());
494+ return false;
495+ }
496+ else
497+ {
498+ priv->textures = textures;
499 priv->needsRebind = false;
500- return true;
501 }
502- else
503- return false;
504- }
505-
506- GLTexture::List textures =
507- GLTexture::bindPixmapToTexture (priv->cWindow->pixmap (),
508- priv->cWindow->size ().width (),
509- priv->cWindow->size ().height (),
510- priv->window->depth ());
511- if (textures.empty ())
512- {
513- compLogMessage ("opengl", CompLogLevelInfo,
514- "Couldn't bind redirected window 0x%x to "
515- "texture\n", (int) priv->window->id ());
516- return false;
517- }
518- else
519- {
520- priv->textures = textures;
521- priv->needsRebind = false;
522- }
523-
524- priv->updateState |= PrivateGLWindow::UpdateRegion | PrivateGLWindow::UpdateMatrix;
525+
526+ priv->updateState |= PrivateGLWindow::UpdateRegion | PrivateGLWindow::UpdateMatrix;
527+
528+ return true;
529+ }
530
531 return true;
532 }
533@@ -142,7 +147,8 @@
534 void
535 GLWindow::release ()
536 {
537- priv->needsRebind = true;
538+ if (!priv->cWindow->frozen ())
539+ priv->needsRebind = true;
540 }
541
542 bool
543@@ -202,8 +208,7 @@
544 {
545 window->resizeNotify (dx, dy, dwidth, dheight);
546 updateState |= PrivateGLWindow::UpdateMatrix | PrivateGLWindow::UpdateRegion;
547- if (!window->hasUnmapReference ())
548- gWindow->release ();
549+ gWindow->release ();
550 }
551
552 void
553@@ -225,8 +230,7 @@
554 case CompWindowNotifyReparent:
555 case CompWindowNotifyUnreparent:
556 case CompWindowNotifyFrameUpdate:
557- if (!window->hasUnmapReference ())
558- gWindow->release ();
559+ gWindow->release ();
560 break;
561 default:
562 break;
563
564=== modified file 'src/window.cpp'
565--- src/window.cpp 2012-05-27 04:32:55 +0000
566+++ src/window.cpp 2012-06-22 05:29:36 +0000
567@@ -1403,11 +1403,11 @@
568 void
569 CompWindow::unmap ()
570 {
571+ if (priv->mapNum)
572+ priv->mapNum = 0;
573+
574 windowNotify (CompWindowNotifyBeforeUnmap);
575
576- if (priv->mapNum)
577- priv->mapNum = 0;
578-
579 /* Even though we're still keeping the backing
580 * pixmap of the window around, it's safe to
581 * unmap the frame window since there's no use
582@@ -1461,9 +1461,7 @@
583 priv->invisible = true;
584
585 if (priv->shaded)
586- {
587 priv->updateFrameWindow ();
588- }
589
590 screen->updateClientList ();
591

Subscribers

People subscribed via source and target branches