Mir

Merge lp:~kdub/mir/rendering-operator-even-simpler into lp:mir

Proposed by Kevin DuBois
Status: Merged
Approved by: Alan Griffiths
Approved revision: no longer in the source branch.
Merged at revision: 1521
Proposed branch: lp:~kdub/mir/rendering-operator-even-simpler
Merge into: lp:mir
Prerequisite: lp:~kdub/mir/occlusion-filter-renderable-list
Diff against target: 174 lines (+61/-26)
5 files modified
include/test/mir_test_doubles/mock_renderable.h (+10/-1)
src/server/compositor/default_display_buffer_compositor.cpp (+6/-6)
src/server/compositor/rendering_operator.cpp (+1/-13)
src/server/compositor/rendering_operator.h (+0/-3)
tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp (+44/-3)
To merge this branch: bzr merge lp:~kdub/mir/rendering-operator-even-simpler
Reviewer Review Type Date Requested Status
Alexandros Frantzis (community) Approve
Alan Griffiths Approve
PS Jenkins bot (community) continuous-integration Approve
Daniel van Vugt Approve
Review via email: mp+212966@code.launchpad.net

Commit message

compositor: now that we have a filtered list of renderables we want to draw, directly access the information needed to implement a frig instead of burdening the RenderingOperator to provide it

Description of the change

compositor: now that we have a filtered list of renderables we want to draw, directly access the information needed to implement a frig instead of burdening the RenderingOperator to provide it

I'm taking aim at eliminating RenderingOperator altogether in favor of just rendering the list from generate_renderables_list. The code eliminated from RenderingOperator in this MP moves frig information gathering to a more appropriate place.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Kevin DuBois (kdub) wrote :

^^cancelled in-flight test run because there was a merge conflict

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 :

(1) You could optimize and break this loop early when the answer becomes true:
9 + for(auto const& renderable : renderable_list)
10 + uncomposited_buffers |= (renderable->buffers_ready_for_compositor() > 1);

(2) In the coming step(s) please remember to pass the Renderer the whole list and let it do the iteration. This is necessary for non-linear and multi-pass effects like 3D shadow grouping (see how your Unity panel shadow merges with window shadows). Another example is multi-pass rendering like reflections and live previews in workspace switchers. Both involve painting the same surfaces multiple times (transformed differently) per frame. So the renderer needs the whole list to work with.

I don't understand the "frig" in this code but it seems enough of the team does :)

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

9 + for(auto const& renderable : renderable_list)
10 + uncomposited_buffers |= (renderable->buffers_ready_for_compositor() > 1);

We are essentially moving the "uncomposited_buffers |= ..." operation after mc::RenderingOperator::operator(). This was the cause of various issues and was fixed by https://code.launchpad.net/~albaguirre/mir/fix-not-compositing-client-last-posted-buffer-trunk/+merge/211601 . Has this problem been dealt with in another way?

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

> 9 + for(auto const& renderable : renderable_list)
> 10 + uncomposited_buffers |= (renderable->buffers_ready_for_compositor()
> > 1);
>
> We are essentially moving the "uncomposited_buffers |= ..." operation after
> mc::RenderingOperator::operator(). This was the cause of various issues and
> was fixed by https://code.launchpad.net/~albaguirre/mir/fix-not-compositing-
> client-last-posted-buffer-trunk/+merge/211601 . Has this problem been dealt
> with in another way?

good catch, will correct.

Its concerning that we don't have a test for this (especially because its not obvious what this is doing)

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

> Its concerning that we don't have a test for this (especially because its not
> obvious what this is doing)

Agreed. This was panic fixed during last push to trunk and a test is missing.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

+ TEST_F(DefaultDisplayBufferCompositor, decides_whether_to_recomposite_before_rendering)

I'd rather go with pure state verification vs behavior verification for this. The reason is that the current ordering of operations is an implementation detail of the current solution, which is one of possible solutions. For example, if we change the condition to renderable->buffers_ready_for_compositor() >= 1 we will need to change the ordering.

I think a test like "informs_when_recomposition_is_needed", that only checks whether composite() returns correct values would be more appropriate. Granted that the current test does that, but its overall focus, as stated in the name too, is on checking the implementation rather than the functionality.

A weak "needs fixing".

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

> + TEST_F(DefaultDisplayBufferCompositor,
> decides_whether_to_recomposite_before_rendering)
>
> I'd rather go with pure state verification vs behavior verification for this.
> The reason is that the current ordering of operations is an implementation
> detail of the current solution, which is one of possible solutions. For
> example, if we change the condition to
> renderable->buffers_ready_for_compositor() >= 1 we will need to change the
> ordering.
>
> I think a test like "informs_when_recomposition_is_needed", that only checks
> whether composite() returns correct values would be more appropriate. Granted
> that the current test does that, but its overall focus, as stated in the name
> too, is on checking the implementation rather than the functionality.
>
> A weak "needs fixing".

This test isn't entirely satisfactory and nor is the solution it validated. However, it is hard to design something better and I think this is a reasonable solution.

While you say the ordering is a detail, it is a detail required by the implicit guarantees offered by SwitchingBundle: it is indeterminate (for the compositor) whether a recently composited buffer is included in buffers_ready_for_compositor(). Asking before compositing the buffer might result in an spurious composite, but doesn't skip a required one.

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

> While you say the ordering is a detail, it is a detail required by the implicit guarantees offered by SwitchingBundle:

I am trying to wrap my head around this but I still haven't able to do so, lost in all the intricate interactions of SwitchingBundle, not convinced one way or the other.

If we indeed depend on such fragile interactions, it's all the more reason to have a test that provides a scenario that fails when internally we don't follow the strict ordering imposed on us, instead of a test that only validates that we do follow an ordering without "proving" that if we don't follow it there is going to be trouble. For example, changing the condition to >= 1 and moving the snippet after post_update() in composite() still works after amending the order of mock_renderable expectations.

Anyway, the test is just tangential to this MP, and is good to have one, so OK. However, I am puzzled by some of what I have seen and I want to look deeper.

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

I agree that the way we determine whether to recomposite is pretty fragile. We have a signal which tells compositing us to composite, and then we tell a function to composite, while at the same time asking that function if it thinks that we should recomposite again. I'd like to mop that up when we improve the scene/compositor composition signal.

At any rate, at least we have a test that will catch us when we move this bug-fixing nugget of code around unknowningly.

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

oops, topapproved, but forgot this was dependent on another branch. switching back to 'needs review'

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

> oops, topapproved, but forgot this was dependent on another branch. switching
> back to 'needs review'

Prerequisite has landed - top-approving

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/test/mir_test_doubles/mock_renderable.h'
2--- include/test/mir_test_doubles/mock_renderable.h 2014-03-26 05:48:59 +0000
3+++ include/test/mir_test_doubles/mock_renderable.h 2014-03-27 17:30:53 +0000
4@@ -37,7 +37,16 @@
5 .WillByDefault(testing::Return(geometry::Rectangle{{},{}}));
6 ON_CALL(*this, buffer(testing::_))
7 .WillByDefault(testing::Return(std::make_shared<StubBuffer>()));
8+ ON_CALL(*this, buffers_ready_for_compositor())
9+ .WillByDefault(testing::Return(1));
10+ ON_CALL(*this, alpha())
11+ .WillByDefault(testing::Return(1.0f));
12+ ON_CALL(*this, transformation())
13+ .WillByDefault(testing::Return(glm::mat4{}));
14+ ON_CALL(*this, should_be_rendered_in(testing::_))
15+ .WillByDefault(testing::Return(true));
16 }
17+
18 MOCK_CONST_METHOD1(buffer, std::shared_ptr<graphics::Buffer>(void const*));
19 MOCK_CONST_METHOD0(alpha_enabled, bool());
20 MOCK_CONST_METHOD0(screen_position, geometry::Rectangle());
21@@ -45,7 +54,7 @@
22 MOCK_CONST_METHOD0(transformation, glm::mat4());
23 MOCK_CONST_METHOD1(should_be_rendered_in, bool(geometry::Rectangle const& rect));
24 MOCK_CONST_METHOD0(shaped, bool());
25- int buffers_ready_for_compositor() const override { return 1; }
26+ MOCK_CONST_METHOD0(buffers_ready_for_compositor, int());
27 };
28 }
29 }
30
31=== modified file 'src/server/compositor/default_display_buffer_compositor.cpp'
32--- src/server/compositor/default_display_buffer_compositor.cpp 2014-03-27 17:30:53 +0000
33+++ src/server/compositor/default_display_buffer_compositor.cpp 2014-03-27 17:30:53 +0000
34@@ -129,6 +129,10 @@
35 auto const& view_area = display_buffer.view_area();
36 auto renderable_list = scene->generate_renderable_list();
37 mc::filter_occlusions_from(renderable_list, view_area);
38+
39+ for(auto const& renderable : renderable_list)
40+ uncomposited_buffers |= (renderable->buffers_ready_for_compositor() > 1);
41+
42 renderer->set_rotation(display_buffer.orientation());
43 renderer->begin();
44 mc::RenderingOperator applicator(*renderer);
45@@ -138,15 +142,11 @@
46
47 display_buffer.post_update();
48
49- uncomposited_buffers |= applicator.uncomposited_buffers();
50-
51 // This is a frig to avoid lp:1286190
52- if (last_pass_rendered_anything && !applicator.anything_was_rendered())
53- {
54+ if (last_pass_rendered_anything && renderable_list.empty())
55 uncomposited_buffers = true;
56- }
57
58- last_pass_rendered_anything = applicator.anything_was_rendered();
59+ last_pass_rendered_anything = !renderable_list.empty();
60 // End of frig
61 }
62
63
64=== modified file 'src/server/compositor/rendering_operator.cpp'
65--- src/server/compositor/rendering_operator.cpp 2014-03-26 05:48:59 +0000
66+++ src/server/compositor/rendering_operator.cpp 2014-03-27 17:30:53 +0000
67@@ -24,26 +24,14 @@
68
69 mc::RenderingOperator::RenderingOperator(
70 Renderer& renderer)
71- : renderer(renderer),
72- uncomposited_buffers_{false}
73+ : renderer(renderer)
74 {
75 }
76
77 void mc::RenderingOperator::operator()(graphics::Renderable const& renderable)
78 {
79- uncomposited_buffers_ |= renderable.buffers_ready_for_compositor() > 1;
80 auto compositor_buffer = renderable.buffer(&renderer);
81 // preserves buffers used in rendering until after post_update()
82 saved_resources.push_back(compositor_buffer);
83 renderer.render(renderable, *compositor_buffer);
84 }
85-
86-bool mc::RenderingOperator::uncomposited_buffers() const
87-{
88- return uncomposited_buffers_;
89-}
90-
91-bool mc::RenderingOperator::anything_was_rendered() const
92-{
93- return !saved_resources.empty();
94-}
95
96=== modified file 'src/server/compositor/rendering_operator.h'
97--- src/server/compositor/rendering_operator.h 2014-03-26 05:48:59 +0000
98+++ src/server/compositor/rendering_operator.h 2014-03-27 17:30:53 +0000
99@@ -38,13 +38,10 @@
100 ~RenderingOperator() = default;
101
102 void operator()(graphics::Renderable const&);
103- bool uncomposited_buffers() const;
104- bool anything_was_rendered() const;
105
106 private:
107 Renderer& renderer;
108 std::vector<std::shared_ptr<void>> saved_resources;
109- bool uncomposited_buffers_;
110 };
111
112 }
113
114=== modified file 'tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp'
115--- tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp 2014-03-27 17:30:53 +0000
116+++ tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp 2014-03-27 17:30:53 +0000
117@@ -136,9 +136,9 @@
118 {
119 using namespace testing;
120 mtd::NullDisplayBuffer display_buffer;
121- auto mock_renderable1 = std::make_shared<mtd::MockRenderable>();
122- auto mock_renderable2 = std::make_shared<mtd::MockRenderable>();
123- auto mock_renderable3 = std::make_shared<mtd::MockRenderable>();
124+ auto mock_renderable1 = std::make_shared<NiceMock<mtd::MockRenderable>>();
125+ auto mock_renderable2 = std::make_shared<NiceMock<mtd::MockRenderable>>();
126+ auto mock_renderable3 = std::make_shared<NiceMock<mtd::MockRenderable>>();
127
128 auto buf = std::make_shared<mtd::StubBuffer>();
129 EXPECT_CALL(*mock_renderable1, buffer(_))
130@@ -513,3 +513,44 @@
131 mr::null_compositor_report());
132 compositor.composite();
133 }
134+
135+//test associated with lp:1290306, 1293896, 1294048, 1294051, 1294053
136+TEST_F(DefaultDisplayBufferCompositor, decides_whether_to_recomposite_before_rendering)
137+{
138+ using namespace testing;
139+ ON_CALL(display_buffer, view_area())
140+ .WillByDefault(Return(screen));
141+ ON_CALL(display_buffer, orientation())
142+ .WillByDefault(Return(mir_orientation_normal));
143+ ON_CALL(display_buffer, can_bypass())
144+ .WillByDefault(Return(false));
145+
146+ auto mock_renderable = std::make_shared<NiceMock<mtd::MockRenderable>>();
147+ ON_CALL(*mock_renderable, screen_position())
148+ .WillByDefault(Return(geom::Rectangle{{0,0},{200,200}}));
149+
150+ //check for how many buffers should come before accessing the buffers.
151+ Sequence seq;
152+ EXPECT_CALL(*mock_renderable, buffers_ready_for_compositor())
153+ .InSequence(seq)
154+ .WillOnce(Return(2));
155+ EXPECT_CALL(*mock_renderable, buffer(_))
156+ .InSequence(seq);
157+ EXPECT_CALL(*mock_renderable, buffers_ready_for_compositor())
158+ .InSequence(seq)
159+ .WillOnce(Return(1));
160+ EXPECT_CALL(*mock_renderable, buffer(_))
161+ .InSequence(seq);
162+
163+ mg::RenderableList list({mock_renderable});
164+ FakeScene scene(list);
165+
166+ mc::DefaultDisplayBufferCompositor compositor(
167+ display_buffer,
168+ mt::fake_shared(scene),
169+ mt::fake_shared(mock_renderer),
170+ mr::null_compositor_report());
171+
172+ EXPECT_TRUE(compositor.composite());
173+ EXPECT_FALSE(compositor.composite());
174+}

Subscribers

People subscribed via source and target branches