Mir

Merge lp:~alan-griffiths/mir/only-visible-surfaces-change-scene into lp:mir

Proposed by Alan Griffiths
Status: Merged
Approved by: Alan Griffiths
Approved revision: no longer in the source branch.
Merged at revision: 2614
Proposed branch: lp:~alan-griffiths/mir/only-visible-surfaces-change-scene
Merge into: lp:mir
Diff against target: 154 lines (+26/-13)
4 files modified
src/server/scene/legacy_scene_change_notification.cpp (+11/-3)
tests/integration-tests/test_surface_stack_with_compositor.cpp (+2/-2)
tests/unit-tests/scene/test_basic_surface.cpp (+5/-0)
tests/unit-tests/scene/test_legacy_scene_change_notification.cpp (+8/-8)
To merge this branch: bzr merge lp:~alan-griffiths/mir/only-visible-surfaces-change-scene
Reviewer Review Type Date Requested Status
Daniel van Vugt Approve
Alexandros Frantzis (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+260746@code.launchpad.net

Commit message

scene: surfaces that are not (and were not recently) visible shouldn't trigger compositing

Description of the change

scene: surfaces that are not (and were not recently) visible shouldn't trigger compositing

This is a significant part of the resolution to the discussion on the mir-devel mailing list "When should a nested server first post a buffer?"

We still need a test case for the nested server behaviour but this fixes the root cause (spurious "damage" triggering compositing).

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

This proposal makes sense for improved efficiency at least, but I'm not sure if it improves correctness at all...

Theoretically the compositor should be treated as something that may sample the scene at any time, at any frequency. So briefly drawing a frame when there's not really any new changes to show shouldn't be an error. Unless the shell is broken and fails to draw itself on start-up when there are no active clients(?).

Feels like we're missing the mark on addressing the root cause. But also feels like a worthy change to have...

review: Needs Information
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

> This proposal makes sense for improved efficiency at least, but I'm not sure
> if it improves correctness at all...
>
> Theoretically the compositor should be treated as something that may sample
> the scene at any time, at any frequency. So briefly drawing a frame when
> there's not really any new changes to show shouldn't be an error. Unless the
> shell is broken and fails to draw itself on start-up when there are no active
> clients(?).

Sure the compositor is permitted to sample the scene "when it wants". But it needs to decide how to respond to scene changes. The LegacySceneChangeNotification class is part of this decision mechanism. (It is called "Legacy" because the mechanism is knowingly unsophisticated - this MP makes it a little more sophisticated.)

> Feels like we're missing the mark on addressing the root cause. But also feels
> like a worthy change to have...

The "root cause" depends on what you think the problem is.

From the POV of USC the problem is that U8 posts a frame before it has drawn anything.

The reason U8 posts before it has drawn anything is that nested Mir posts a frame when the surface is created, not when it is drawn.

And that is fixed as a side-effect of the optimization proposed here.

Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

Looks good.

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

Sounds OK, I think...

In the "already running" case you have to consider that there's possibly another client running that could cause you to get composited on-screen slightly sooner than you expect (or are ready for). Like in bug 1447896.

In Compiz I solved this by giving 1ms of grace time to the scene change notification so that temporally near-by changes in other windows make it into the same frame. Although the latency penalty is sub-optimal then, and my predictive-bypass branch will solve the problem completely.

Even on start-up though, if your shell is comprised of multiple surfaces there's no guarantee that the first visible frame will contain all of them. Because they race each other. But our logic does ensure in that case at least a second frame will replace it soon enough.

So we're potentially re-introducing the problem of having an incomplete shell visible on the first frame. But that's non-trivial to fix without the "wait for second frame" hack. Surfaces are asynchronous with each other and that's a very good thing, most of the time.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/server/scene/legacy_scene_change_notification.cpp'
--- src/server/scene/legacy_scene_change_notification.cpp 2015-05-12 06:58:52 +0000
+++ src/server/scene/legacy_scene_change_notification.cpp 2015-06-01 16:35:23 +0000
@@ -41,8 +41,15 @@
4141
42void ms::LegacySceneChangeNotification::add_surface_observer(ms::Surface* surface)42void ms::LegacySceneChangeNotification::add_surface_observer(ms::Surface* surface)
43{43{
44 auto notifier = [surface, this, was_visible = false] () mutable
45 {
46 if (surface->visible() || was_visible)
47 scene_notify_change();
48 was_visible = surface->visible();
49 };
50
44 auto observer = std::make_shared<ms::LegacySurfaceChangeNotification>(51 auto observer = std::make_shared<ms::LegacySurfaceChangeNotification>(
45 scene_notify_change, buffer_notify_change);52 notifier, buffer_notify_change);
46 surface->add_observer(observer);53 surface->add_observer(observer);
47 54
48 {55 {
@@ -54,7 +61,6 @@
54void ms::LegacySceneChangeNotification::surface_added(ms::Surface* surface)61void ms::LegacySceneChangeNotification::surface_added(ms::Surface* surface)
55{62{
56 add_surface_observer(surface);63 add_surface_observer(surface);
57 scene_notify_change();
58}64}
5965
60void ms::LegacySceneChangeNotification::surface_exists(ms::Surface* surface)66void ms::LegacySceneChangeNotification::surface_exists(ms::Surface* surface)
@@ -73,7 +79,9 @@
73 surface_observers.erase(it);79 surface_observers.erase(it);
74 }80 }
75 }81 }
76 scene_notify_change();82
83 if (surface->visible())
84 scene_notify_change();
77}85}
7886
79void ms::LegacySceneChangeNotification::surfaces_reordered()87void ms::LegacySceneChangeNotification::surfaces_reordered()
8088
=== modified file 'tests/integration-tests/test_surface_stack_with_compositor.cpp'
--- tests/integration-tests/test_surface_stack_with_compositor.cpp 2015-05-19 21:34:34 +0000
+++ tests/integration-tests/test_surface_stack_with_compositor.cpp 2015-06-01 16:35:23 +0000
@@ -183,7 +183,7 @@
183 EXPECT_TRUE(stub_secondary_db.has_posted_at_least(0, timeout));183 EXPECT_TRUE(stub_secondary_db.has_posted_at_least(0, timeout));
184}184}
185185
186TEST_F(SurfaceStackCompositor, adding_a_surface_that_has_been_swapped_triggers_a_composition)186TEST_F(SurfaceStackCompositor, swapping_a_surface_that_has_been_added_triggers_a_composition)
187{187{
188 mc::MultiThreadedCompositor mt_compositor(188 mc::MultiThreadedCompositor mt_compositor(
189 mt::fake_shared(stub_display),189 mt::fake_shared(stub_display),
@@ -193,8 +193,8 @@
193 null_comp_report, false);193 null_comp_report, false);
194 mt_compositor.start();194 mt_compositor.start();
195195
196 stack.add_surface(stub_surface, default_params.depth, default_params.input_mode);
196 stub_surface->primary_buffer_stream()->swap_buffers(&stubbuf, [](mg::Buffer*){});197 stub_surface->primary_buffer_stream()->swap_buffers(&stubbuf, [](mg::Buffer*){});
197 stack.add_surface(stub_surface, default_params.depth, default_params.input_mode);
198198
199 EXPECT_TRUE(stub_primary_db.has_posted_at_least(1, timeout));199 EXPECT_TRUE(stub_primary_db.has_posted_at_least(1, timeout));
200 EXPECT_TRUE(stub_secondary_db.has_posted_at_least(1, timeout));200 EXPECT_TRUE(stub_secondary_db.has_posted_at_least(1, timeout));
201201
=== modified file 'tests/unit-tests/scene/test_basic_surface.cpp'
--- tests/unit-tests/scene/test_basic_surface.cpp 2015-05-19 21:34:34 +0000
+++ tests/unit-tests/scene/test_basic_surface.cpp 2015-06-01 16:35:23 +0000
@@ -171,6 +171,7 @@
171 .Times(1);171 .Times(1);
172172
173 surface.add_observer(observer);173 surface.add_observer(observer);
174 post_a_frame(surface);
174175
175 EXPECT_EQ(rect.top_left, surface.top_left());176 EXPECT_EQ(rect.top_left, surface.top_left());
176177
@@ -187,6 +188,7 @@
187 .Times(1);188 .Times(1);
188189
189 surface.add_observer(observer);190 surface.add_observer(observer);
191 post_a_frame(surface);
190192
191 EXPECT_EQ(rect.size, surface.size());193 EXPECT_EQ(rect.size, surface.size());
192 EXPECT_NE(new_size, surface.size());194 EXPECT_NE(new_size, surface.size());
@@ -223,6 +225,7 @@
223 .Times(1);225 .Times(1);
224226
225 surface.add_observer(observer);227 surface.add_observer(observer);
228 post_a_frame(surface);
226229
227 auto original_transformation = surface.compositor_snapshot(compositor_id)->transformation();230 auto original_transformation = surface.compositor_snapshot(compositor_id)->transformation();
228 glm::mat4 trans{0.1f, 0.5f, 0.9f, 1.3f,231 glm::mat4 trans{0.1f, 0.5f, 0.9f, 1.3f,
@@ -243,6 +246,7 @@
243 .Times(1);246 .Times(1);
244247
245 surface.add_observer(observer);248 surface.add_observer(observer);
249 post_a_frame(surface);
246250
247 float alpha = 0.5f;251 float alpha = 0.5f;
248 surface.set_alpha(0.5f);252 surface.set_alpha(0.5f);
@@ -301,6 +305,7 @@
301 .Times(1);305 .Times(1);
302306
303 surface.add_observer(observer);307 surface.add_observer(observer);
308 post_a_frame(surface);
304309
305 surface.set_hidden(true);310 surface.set_hidden(true);
306}311}
307312
=== modified file 'tests/unit-tests/scene/test_legacy_scene_change_notification.cpp'
--- tests/unit-tests/scene/test_legacy_scene_change_notification.cpp 2015-04-09 08:57:24 +0000
+++ tests/unit-tests/scene/test_legacy_scene_change_notification.cpp 2015-06-01 16:35:23 +0000
@@ -42,6 +42,10 @@
4242
43struct LegacySceneChangeNotificationTest : public testing::Test43struct LegacySceneChangeNotificationTest : public testing::Test
44{44{
45 void SetUp() override
46 {
47 ON_CALL(surface,visible()).WillByDefault(testing::Return(true));
48 }
45 testing::NiceMock<MockSceneCallback> scene_callback;49 testing::NiceMock<MockSceneCallback> scene_callback;
46 testing::NiceMock<MockBufferCallback> buffer_callback;50 testing::NiceMock<MockBufferCallback> buffer_callback;
47 std::function<void(int)> buffer_change_callback{[this](int arg){buffer_callback.invoke(arg);}};51 std::function<void(int)> buffer_change_callback{[this](int arg){buffer_callback.invoke(arg);}};
@@ -52,8 +56,7 @@
5256
53TEST_F(LegacySceneChangeNotificationTest, fowards_all_observations_to_callback)57TEST_F(LegacySceneChangeNotificationTest, fowards_all_observations_to_callback)
54{58{
55 EXPECT_CALL(scene_callback, invoke())59 EXPECT_CALL(scene_callback, invoke()).Times(2);
56 .Times(3);
5760
58 ms::LegacySceneChangeNotification observer(scene_change_callback, buffer_change_callback);61 ms::LegacySceneChangeNotification observer(scene_change_callback, buffer_change_callback);
59 observer.surface_added(&surface);62 observer.surface_added(&surface);
@@ -87,10 +90,8 @@
87 .WillOnce(SaveArg<0>(&surface_observer));90 .WillOnce(SaveArg<0>(&surface_observer));
88 91
89 int buffer_num{3}; 92 int buffer_num{3};
90 EXPECT_CALL(scene_callback, invoke())93 EXPECT_CALL(scene_callback, invoke()).Times(0);
91 .Times(1);94 EXPECT_CALL(buffer_callback, invoke(buffer_num)).Times(1);
92 EXPECT_CALL(buffer_callback, invoke(buffer_num))
93 .Times(1);
9495
95 ms::LegacySceneChangeNotification observer(scene_change_callback, buffer_change_callback);96 ms::LegacySceneChangeNotification observer(scene_change_callback, buffer_change_callback);
96 observer.surface_added(&surface);97 observer.surface_added(&surface);
@@ -105,8 +106,7 @@
105106
106 EXPECT_CALL(surface, add_observer(_)).Times(1)107 EXPECT_CALL(surface, add_observer(_)).Times(1)
107 .WillOnce(SaveArg<0>(&surface_observer));108 .WillOnce(SaveArg<0>(&surface_observer));
108 EXPECT_CALL(scene_callback, invoke())109 EXPECT_CALL(scene_callback, invoke()).Times(1);
109 .Times(2);
110110
111 ms::LegacySceneChangeNotification observer(scene_change_callback,111 ms::LegacySceneChangeNotification observer(scene_change_callback,
112 buffer_change_callback);112 buffer_change_callback);

Subscribers

People subscribed via source and target branches