Mir

Merge lp:~vanvugt/mir/reverse-scene-traversal into lp:mir

Proposed by Daniel van Vugt
Status: Merged
Approved by: Alexandros Frantzis
Approved revision: no longer in the source branch.
Merged at revision: 1138
Proposed branch: lp:~vanvugt/mir/reverse-scene-traversal
Merge into: lp:mir
Diff against target: 187 lines (+113/-0)
6 files modified
include/server/mir/compositor/scene.h (+5/-0)
include/server/mir/surfaces/surface_stack.h (+2/-0)
src/server/surfaces/surface_stack.cpp (+18/-0)
tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp (+4/-0)
tests/unit-tests/compositor/test_multi_threaded_compositor.cpp (+2/-0)
tests/unit-tests/surfaces/test_surface_stack.cpp (+82/-0)
To merge this branch: bzr merge lp:~vanvugt/mir/reverse-scene-traversal
Reviewer Review Type Date Requested Status
Alexandros Frantzis (community) Approve
Alan Griffiths Abstain
Kevin DuBois (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+190315@code.launchpad.net

Commit message

Add support for traversing the Scene from front surface to back.
This is required for occlusion detection at least (coming soon).

Description of the change

Prerequisite for fixing bug 1227739.

To post a comment you must log in.
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

43 + for ( auto layer = layers_by_depth.rbegin()
44 + ; layer != layers_by_depth.rend()
45 + ; ++layer
46 + )

Although I don't find anything in our coding standard about this, we tend to break lines after punctuation marks.

Use std::for_each() instead?

49 + for (auto it = surfaces.rbegin(); it != surfaces.rend(); ++it)
50 + {

Use std::for_each() instead?

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

Fixed semicolons.

I disagree with for_each() here because it would force me to either add more functions or use lambdas. Both would reduce readability (and efficiency) a bit.

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

*Needs discussion*

I think we need a serious rethink of the interface Scene provides. It is evolving into a bad case of coupling.

lock()/unlock() are a problem because they imply locking the whole of the data model, not just the part relevant to the current operation.

Locking the whole data model is problematic if, for example, you want to composit different screens on different threads (which we attempt).

This MP adding forward and reverse traversals and expecting the results to make sense requires maintaining a lock across connected traversals. That will make it difficult to reduce the scope of locking to affected parts of the data.

I know at present there's no way to lock just a subset of the current model - but this interface makes that hard to change. The lock()/unlock() were originally a hack around the lack of a post-traversal call on OperatorForScene.

I think we want something like:

  auto surfaces = scene->select(filter);

  for (auto x : subscene) ...

and/or

  for (auto it = surfaces.rbegin(); it != surfaces.rend(); ++it)

With "~surfaces" releasing the lock.

review: Needs Information
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
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 :

Alan,

As it happens, I too decided just this week I would like to see:
    auto surfaces = scene->select(filter);
or
    auto surfaces = scene->snapshot();

However I am sticking with the current design at present, in an effort to make small incremental steps that are still potentially saucy-compatible. My immediate goal is to resolve bug 1227739 in or soon-after saucy is released. That means using existing interfaces.

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

Although "filtering" can be complex, requiring multiple passes in varying directions. So I don't endorse:
    auto surfaces = scene->select(filter);
That would break down for what I have planned. I would however endorse something like:
    auto renderables = scene->snapshot();
The locking is now atomic, non-blocking, and allows for arbitrary filtering algorithms including culling of non-visible renderables before the list is sent to the renderer.

Revision history for this message
Kevin DuBois (kdub) wrote :

so we always traverse layers forward, and then have a forward/reverse for surfaces? I agree with Alan's "need information", if we have enough time. If this needs to get in before ffe, though, I guess my review is an approve. Hope we can reinvent the scenegraph soon though

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

OK we all seem to agree that this adds to the technical debt we'll need to sort out (and have some tentative agreement on the right approach to doing that).

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

> If this needs to get in before ffe, though, I guess my review is an approve.
> Hope we can reinvent the scenegraph soon though.

+1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'include/server/mir/compositor/scene.h'
--- include/server/mir/compositor/scene.h 2013-08-28 03:41:48 +0000
+++ include/server/mir/compositor/scene.h 2013-10-10 09:44:21 +0000
@@ -66,8 +66,13 @@
66public:66public:
67 virtual ~Scene() {}67 virtual ~Scene() {}
6868
69 // Back to front; normal rendering order
69 virtual void for_each_if(FilterForScene& filter, OperatorForScene& op) = 0;70 virtual void for_each_if(FilterForScene& filter, OperatorForScene& op) = 0;
7071
72 // Front to back; as used when scanning for occlusions
73 virtual void reverse_for_each_if(FilterForScene& filter,
74 OperatorForScene& op) = 0;
75
71 /**76 /**
72 * Sets a callback to be called whenever the state of the77 * Sets a callback to be called whenever the state of the
73 * Scene changes.78 * Scene changes.
7479
=== modified file 'include/server/mir/surfaces/surface_stack.h'
--- include/server/mir/surfaces/surface_stack.h 2013-08-28 03:41:48 +0000
+++ include/server/mir/surfaces/surface_stack.h 2013-10-10 09:44:21 +0000
@@ -67,6 +67,8 @@
6767
68 // From Scene68 // From Scene
69 virtual void for_each_if(compositor::FilterForScene &filter, compositor::OperatorForScene &op);69 virtual void for_each_if(compositor::FilterForScene &filter, compositor::OperatorForScene &op);
70 virtual void reverse_for_each_if(compositor::FilterForScene& filter,
71 compositor::OperatorForScene& op);
70 virtual void set_change_callback(std::function<void()> const& f);72 virtual void set_change_callback(std::function<void()> const& f);
71 73
72 // From InputTargets74 // From InputTargets
7375
=== modified file 'src/server/surfaces/surface_stack.cpp'
--- src/server/surfaces/surface_stack.cpp 2013-10-03 06:01:11 +0000
+++ src/server/surfaces/surface_stack.cpp 2013-10-10 09:44:21 +0000
@@ -66,6 +66,24 @@
66 }66 }
67}67}
6868
69void ms::SurfaceStack::reverse_for_each_if(mc::FilterForScene& filter,
70 mc::OperatorForScene& op)
71{
72 std::lock_guard<std::recursive_mutex> lg(guard);
73 for (auto layer = layers_by_depth.rbegin();
74 layer != layers_by_depth.rend();
75 ++layer)
76 {
77 auto surfaces = layer->second;
78 for (auto it = surfaces.rbegin(); it != surfaces.rend(); ++it)
79 {
80 mc::CompositingCriteria& info = *((*it)->compositing_criteria());
81 ms::BufferStream& stream = *((*it)->buffer_stream());
82 if (filter(info)) op(info, stream);
83 }
84 }
85}
86
69void ms::SurfaceStack::set_change_callback(std::function<void()> const& f)87void ms::SurfaceStack::set_change_callback(std::function<void()> const& f)
70{88{
71 std::lock_guard<std::mutex> lg{notify_change_mutex};89 std::lock_guard<std::mutex> lg{notify_change_mutex};
7290
=== modified file 'tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp'
--- tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp 2013-08-28 03:41:48 +0000
+++ tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp 2013-10-10 09:44:21 +0000
@@ -47,6 +47,8 @@
47struct MockScene : mc::Scene47struct MockScene : mc::Scene
48{48{
49 MOCK_METHOD2(for_each_if, void(mc::FilterForScene&, mc::OperatorForScene&));49 MOCK_METHOD2(for_each_if, void(mc::FilterForScene&, mc::OperatorForScene&));
50 MOCK_METHOD2(reverse_for_each_if, void(mc::FilterForScene&,
51 mc::OperatorForScene&));
50 MOCK_METHOD1(set_change_callback, void(std::function<void()> const&));52 MOCK_METHOD1(set_change_callback, void(std::function<void()> const&));
51 MOCK_METHOD0(lock, void());53 MOCK_METHOD0(lock, void());
52 MOCK_METHOD0(unlock, void());54 MOCK_METHOD0(unlock, void());
@@ -76,6 +78,8 @@
76 }78 }
77 }79 }
7880
81 void reverse_for_each_if(mc::FilterForScene&, mc::OperatorForScene&) {}
82
79 void set_change_callback(std::function<void()> const&) {}83 void set_change_callback(std::function<void()> const&) {}
8084
81 void change(const std::vector<mc::CompositingCriteria*> &surfs)85 void change(const std::vector<mc::CompositingCriteria*> &surfs)
8286
=== modified file 'tests/unit-tests/compositor/test_multi_threaded_compositor.cpp'
--- tests/unit-tests/compositor/test_multi_threaded_compositor.cpp 2013-08-28 03:41:48 +0000
+++ tests/unit-tests/compositor/test_multi_threaded_compositor.cpp 2013-10-10 09:44:21 +0000
@@ -86,6 +86,8 @@
86 {86 {
87 }87 }
8888
89 void reverse_for_each_if(mc::FilterForScene&, mc::OperatorForScene&) {}
90
89 void set_change_callback(std::function<void()> const& f)91 void set_change_callback(std::function<void()> const& f)
90 {92 {
91 std::lock_guard<std::mutex> lock{callback_mutex};93 std::lock_guard<std::mutex> lock{callback_mutex};
9294
=== modified file 'tests/unit-tests/surfaces/test_surface_stack.cpp'
--- tests/unit-tests/surfaces/test_surface_stack.cpp 2013-08-28 03:41:48 +0000
+++ tests/unit-tests/surfaces/test_surface_stack.cpp 2013-10-10 09:44:21 +0000
@@ -256,6 +256,88 @@
256 stack.for_each_if(filter, renderable_operator);256 stack.for_each_if(filter, renderable_operator);
257}257}
258258
259TEST_F(SurfaceStack, skips_surface_that_is_filtered_out_reverse)
260{
261 using namespace ::testing;
262
263 EXPECT_CALL(mock_surface_allocator, create_surface(_,_))
264 .WillOnce(Return(stub_surface1))
265 .WillOnce(Return(stub_surface2))
266 .WillOnce(Return(stub_surface3));
267
268 ms::SurfaceStack stack(mt::fake_shared(mock_surface_allocator),
269 mt::fake_shared(input_registrar));
270 auto s1 = stack.create_surface(default_params);
271 auto criteria1 = s1.lock()->compositing_criteria();
272 auto stream1 = s1.lock()->buffer_stream();
273 auto s2 = stack.create_surface(default_params);
274 auto criteria2 = s2.lock()->compositing_criteria();
275 auto stream2 = s2.lock()->buffer_stream();
276 auto s3 = stack.create_surface(default_params);
277 auto criteria3 = s3.lock()->compositing_criteria();
278 auto stream3 = s3.lock()->buffer_stream();
279
280 MockFilterForScene filter;
281 MockOperatorForScene renderable_operator;
282
283 Sequence seq1, seq2;
284 EXPECT_CALL(filter, filter(Ref(*criteria3)))
285 .InSequence(seq1)
286 .WillOnce(Return(true));
287 EXPECT_CALL(filter, filter(Ref(*criteria2)))
288 .InSequence(seq1)
289 .WillOnce(Return(false));
290 EXPECT_CALL(filter, filter(Ref(*criteria1)))
291 .InSequence(seq1)
292 .WillOnce(Return(true));
293 EXPECT_CALL(renderable_operator,
294 renderable_operator(Ref(*criteria3), Ref(*stream3)))
295 .InSequence(seq2);
296 EXPECT_CALL(renderable_operator,
297 renderable_operator(Ref(*criteria1), Ref(*stream1)))
298 .InSequence(seq2);
299
300 stack.reverse_for_each_if(filter, renderable_operator);
301}
302
303TEST_F(SurfaceStack, stacking_order_reverse)
304{
305 using namespace ::testing;
306
307 EXPECT_CALL(mock_surface_allocator, create_surface(_,_))
308 .WillOnce(Return(stub_surface1))
309 .WillOnce(Return(stub_surface2))
310 .WillOnce(Return(stub_surface3));
311
312 ms::SurfaceStack stack(mt::fake_shared(mock_surface_allocator),
313 mt::fake_shared(input_registrar));
314
315 auto s1 = stack.create_surface(default_params);
316 auto criteria1 = s1.lock()->compositing_criteria();
317 auto stream1 = s1.lock()->buffer_stream();
318 auto s2 = stack.create_surface(default_params);
319 auto criteria2 = s2.lock()->compositing_criteria();
320 auto stream2 = s2.lock()->buffer_stream();
321 auto s3 = stack.create_surface(default_params);
322 auto criteria3 = s3.lock()->compositing_criteria();
323 auto stream3 = s3.lock()->buffer_stream();
324
325 StubFilterForScene filter;
326 MockOperatorForScene renderable_operator;
327 Sequence seq;
328 EXPECT_CALL(renderable_operator,
329 renderable_operator(Ref(*criteria3), Ref(*stream3)))
330 .InSequence(seq);
331 EXPECT_CALL(renderable_operator,
332 renderable_operator(Ref(*criteria2), Ref(*stream2)))
333 .InSequence(seq);
334 EXPECT_CALL(renderable_operator,
335 renderable_operator(Ref(*criteria1), Ref(*stream1)))
336 .InSequence(seq);
337
338 stack.reverse_for_each_if(filter, renderable_operator);
339}
340
259TEST_F(SurfaceStack, stacking_order)341TEST_F(SurfaceStack, stacking_order)
260{342{
261 using namespace ::testing;343 using namespace ::testing;

Subscribers

People subscribed via source and target branches