Mir

Merge lp:~kdub/mir/share-occlusion-with-examples into lp:mir

Proposed by Kevin DuBois
Status: Merged
Merged at revision: 1813
Proposed branch: lp:~kdub/mir/share-occlusion-with-examples
Merge into: lp:mir
Diff against target: 213 lines (+36/-22)
5 files modified
examples/CMakeLists.txt (+4/-0)
src/server/compositor/default_display_buffer_compositor.cpp (+1/-1)
src/server/compositor/occlusion.cpp (+15/-9)
src/server/compositor/occlusion.h (+5/-1)
tests/unit-tests/compositor/test_occlusion.cpp (+11/-11)
To merge this branch: bzr merge lp:~kdub/mir/share-occlusion-with-examples
Reviewer Review Type Date Requested Status
Alberto Aguirre (community) Disapprove
Alexandros Frantzis (community) Disapprove
Alan Griffiths Disapprove
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+222577@code.launchpad.net

Commit message

share occlusion detection logic with the examples/, and allow for different screen coverage areas to be computed based on a renderable.

Description of the change

share occlusion detection logic with the examples/, and allow for different screen coverage areas to be computed based on a renderable.

note:
I'm aiming for this MP to be preparation for fixing lp: #1299977. It raises a sticky question of how to share useful src/ code with examples/ though, so I'd like to tackle that question in this MP.

I've been trying to read the team's temperature on the question 'how to share production code with examples', and the way this MP shares the code seems the most agreeable. Here are the options I considered for how to do this:

1) place the header file in the public folders (as was done with gl_renderer.h). This has the big disadvantage that these privately-intended classes become public API, so I'd like to shy away from this.

2) have the example code duplicate functionality where it needs to. This is actually what I prefer the most. If my intention is to use the mir API to rewrite the compositor, I should expect to write an occlusion algorithm and a renderer from scratch. This does have the downside of we'd have to maintain one algorithm in the examples/ and one in src/, but the upside that the demos only depend on the major version number and are not locked into the specific mirserver version.

3) allow the examples to access the src/ headers, which is what this MP implements. This keeps the private stuff (like occlusion and renderer) private, but has the downside that examples/ is tied to the specific version of libmirserver.

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
Cemil Azizoglu (cemil-azizoglu) wrote :

Perhaps whatever shared code examples need could be factored out of the private area and put under a util dir. Both the private headers and the examples can then include what they need from util.

Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

My cents on this topic:

If it is a useful utility that mir users are likely to use then we should provide it as an official API. Maybe it is so self contained that it is possible to provide that as a header only solutions to avoid having a larger ABI? So if that is the case 1) might be a possibility.

But I share your preference here: If it is a case of the examples should show how things are done properly or in a specific way based on shell decisions or should show how to do it efficiently, we should duplicate the code inside the examples and have a version with elaborate inline comments or unit tests that tell a good story.

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

If I were an end user looking for an example of how to "filter occlusions" and saw this use of a private API then I'd be unimpressed. And rightly so.

The examples show end-users how to write code that works with Mir. That means they must only access facilities that are are available to users (and should use them correctly).

If there is a conflict between "it should be private" and "it is useful for the examples" then there is a design issue to be resolved about what the requirement is and how to support it.

In other words, find a way to publish the facility that's needed so end users can access it too. I can believe that you want to offer a different (more restricted or more stable) interface than the internal one, but this MP is wrong.

Even duplicating code is better than telling the user "don't do what the example shows you how to do".

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

I agree that its strange to let the examples access internals in src/ that other users don't have access to. So this leaves us with:

1) reimplement common graphics algorithms (drawing, occlusion scanning) in the examples. This has the downside that we'd have somewhat-duplicated code in examples/ and src/
2) provide an API for common composition (and really, common GL operations) for the future compositor writers. This has the downside that its a pretty sizable undertaking (nux/qml/etc)
3) provide a utility class that's private, but contains only common GL operations. (eg, things anyone drawing with opengl would be expected to know how to write)

Our current two users (USC, unity8) have elected to use the default implementation (usc) or rewrite everything (unity8). I'd expect a future compositor writer to not want to use a mir-made drawing utility class (mir-nux).

The middle route seems to be 3). The utility folder would only have common graphics utilities in it. It wouldn't be a public API. In the current code, this is occlusion.h and Renderer/GLRenderer. I'd expect it to grow to include an animation framework and other stuff like that. If any of these become really awesome interfaces every user wants to use, we can make it a public API at that point. Now we just need a good name for that folder...

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

> 3) provide a utility class that's private, but contains only common GL
clarification: "utility classes in a utility folder" is a clearer

Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote :

> > 3) provide a utility class that's private, but contains only common GL
> clarification: "utility classes in a utility folder" is a clearer

+1 if you mean "utility classes in a utility folder that both Mir proper and examples make use of".

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

> > > 3) provide a utility class that's private, but contains only common GL
> > clarification: "utility classes in a utility folder" is a clearer
>
> +1 if you mean "utility classes in a utility folder that both Mir proper and
> examples make use of".

I have two concerns:

1. "Utility" is a terrible name - are other folders non-utility (= useless)
2. We need to make this folder available to people trying to reproduce the examples.

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

> > > > 3) provide a utility class that's private, but contains only common GL
> > > clarification: "utility classes in a utility folder" is a clearer
> >
> > +1 if you mean "utility classes in a utility folder that both Mir proper and
> > examples make use of".
>
> I have two concerns:
>
> 1. "Utility" is a terrible name - are other folders non-utility (= useless)
agree

> 2. We need to make this folder available to people trying to reproduce the
> examples.

I disagree here, as this introduces an API to support, and the goal is to only have only well-known GL stuff in this folder. Someone who wants to replace an OpenGL compositor object can reasonably be expected to develop their own vertex/shader/etc OpenGL stuff. I'll grant that this is a moderate chunk of code (100 lines maybe), but people are used to writing it.

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

> > 2. We need to make this folder available to people trying to reproduce the
> > examples.
>
> I disagree here, as this introduces an API to support, and the goal is to only
> have only well-known GL stuff in this folder. Someone who wants to replace an
> OpenGL compositor object can reasonably be expected to develop their own
> vertex/shader/etc OpenGL stuff. I'll grant that this is a moderate chunk of
> code (100 lines maybe), but people are used to writing it.

The point of providing examples is that our users can take them, *build* them and experiment with changing them.

I don't understand why you are so averse to either duplicating or sharing a bit of "well-known GL stuff" that you want to make things difficult for users to use the example code.

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

My preference would also be to duplicate the code. The examples (an example shell in this case) and the core code will likely have different needs that change for different reasons. We ideally don't want the internal needs of the examples affecting core internal code. The change proposed in this MP is an example of this happening: our core code doesn't currently need the "coverage_of" parameter; it's introduced only for the benefit of the examples (if understood things correctly).

review: Disapprove
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

I concur that a "private" api/util library is not what the examples should use.

Given that we lack test coverage on compositor/rendering output howerver, I hesitate on duplicating code. If we can make a version of the demo shell with all the current features (except I guess decorations) so that the default mir renderer/compositor is used then I would be ok. Basically a shell that we can use to manual test for rendering artifacts - at least until we have proper test coverage for that.

review: Disapprove

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'examples/CMakeLists.txt'
2--- examples/CMakeLists.txt 2014-06-02 17:07:02 +0000
3+++ examples/CMakeLists.txt 2014-06-09 22:29:32 +0000
4@@ -100,6 +100,10 @@
5 ${PROJECT_SOURCE_DIR}/include/client
6 ${PROJECT_SOURCE_DIR}/include/platform
7 ${GLESv2_INCLUDE_DIRS}
8+ #mir has some useful private code that we don't want to duplicate in our examples.
9+ #it is not part of our public api, but useful nonetheless. Users of the api will
10+ #have to write their own implementations
11+ ${PROJECT_SOURCE_DIR}/src/server/compositor
12 )
13
14 add_executable(mir_demo_standalone_render_to_fb
15
16=== modified file 'src/server/compositor/default_display_buffer_compositor.cpp'
17--- src/server/compositor/default_display_buffer_compositor.cpp 2014-06-05 20:35:46 +0000
18+++ src/server/compositor/default_display_buffer_compositor.cpp 2014-06-09 22:29:32 +0000
19@@ -52,7 +52,7 @@
20
21 auto const& view_area = display_buffer.view_area();
22 auto renderable_list = scene->renderable_list_for(this);
23- mc::filter_occlusions_from(renderable_list, view_area);
24+ mc::filter_occlusions_from(renderable_list, view_area, simple_renderable_rect);
25
26 //TODO: the DisplayBufferCompositor should not have to figure out if it has to force
27 // a subsequent compositon. The MultiThreadedCompositor should be smart enough to
28
29=== modified file 'src/server/compositor/occlusion.cpp'
30--- src/server/compositor/occlusion.cpp 2014-04-17 01:34:35 +0000
31+++ src/server/compositor/occlusion.cpp 2014-06-09 22:29:32 +0000
32@@ -27,8 +27,9 @@
33 {
34 bool renderable_is_occluded(
35 Renderable const& renderable,
36- Rectangle const& area,
37- std::vector<Rectangle>& coverage)
38+ Rectangle const& display_area,
39+ Rectangle const& coverage_area,
40+ std::vector<Rectangle>& coverage_list)
41 {
42 static const glm::mat4 identity;
43 if (renderable.transformation() != identity)
44@@ -41,14 +42,13 @@
45 return true; //invisible; definitely occluded.
46
47 // Not weirdly transformed but also not on this monitor? Don't care...
48- if (!area.overlaps(renderable.screen_position()))
49+ if (!display_area.overlaps(coverage_area))
50 return true; // Not on the display; definitely occluded.
51
52 bool occluded = false;
53- Rectangle const& window = renderable.screen_position();
54- for (const auto &r : coverage)
55+ for (const auto &r : coverage_list)
56 {
57- if (r.contains(window))
58+ if (r.contains(coverage_area))
59 {
60 occluded = true;
61 break;
62@@ -56,21 +56,27 @@
63 }
64
65 if (!occluded && renderable.alpha() == 1.0f && !renderable.shaped())
66- coverage.push_back(window);
67+ coverage_list.push_back(coverage_area);
68
69 return occluded;
70 }
71 }
72
73+Rectangle mir::compositor::simple_renderable_rect(Renderable const& renderable)
74+{
75+ return renderable.screen_position();
76+}
77+
78 void mir::compositor::filter_occlusions_from(
79 RenderableList& list,
80- Rectangle const& area)
81+ geometry::Rectangle const& area,
82+ std::function<Rectangle(Renderable const&)> coverage_of)
83 {
84 std::vector<Rectangle> coverage;
85 auto it = list.rbegin();
86 while (it != list.rend())
87 {
88- if (renderable_is_occluded(**it, area, coverage))
89+ if (renderable_is_occluded(**it, area, coverage_of(**it), coverage))
90 list.erase(std::prev(it.base()));
91 else
92 it++;
93
94=== modified file 'src/server/compositor/occlusion.h'
95--- src/server/compositor/occlusion.h 2014-03-26 16:59:32 +0000
96+++ src/server/compositor/occlusion.h 2014-06-09 22:29:32 +0000
97@@ -29,8 +29,12 @@
98 namespace compositor
99 {
100
101-void filter_occlusions_from(graphics::RenderableList& list, geometry::Rectangle const& area);
102+geometry::Rectangle simple_renderable_rect(graphics::Renderable const& renderable);
103
104+void filter_occlusions_from(
105+ graphics::RenderableList& list,
106+ geometry::Rectangle const& area,
107+ std::function<geometry::Rectangle(graphics::Renderable const&)> filter_fn);
108 } // namespace compositor
109 } // namespace mir
110
111
112=== modified file 'tests/unit-tests/compositor/test_occlusion.cpp'
113--- tests/unit-tests/compositor/test_occlusion.cpp 2014-06-03 19:16:54 +0000
114+++ tests/unit-tests/compositor/test_occlusion.cpp 2014-06-09 22:29:32 +0000
115@@ -45,7 +45,7 @@
116 auto window = std::make_shared<mtd::FakeRenderable>(12, 34, 56, 78);
117 mg::RenderableList list{window};
118
119- filter_occlusions_from(list, monitor_rect);
120+ filter_occlusions_from(list, monitor_rect, simple_renderable_rect);
121 ASSERT_EQ(1u, list.size());
122 EXPECT_EQ(window, list.front());
123 }
124@@ -58,7 +58,7 @@
125 auto bottom = std::make_shared<mtd::FakeRenderable>(200, 1000, 100, 1000);
126 mg::RenderableList list{left, right, top, bottom};
127
128- filter_occlusions_from(list, monitor_rect);
129+ filter_occlusions_from(list, monitor_rect, simple_renderable_rect);
130 EXPECT_EQ(4u, list.size());
131 }
132
133@@ -68,7 +68,7 @@
134 auto bottom = std::make_shared<mtd::FakeRenderable>(12, 12, 5, 5);
135 mg::RenderableList list{bottom, top};
136
137- filter_occlusions_from(list, monitor_rect);
138+ filter_occlusions_from(list, monitor_rect, simple_renderable_rect);
139
140 ASSERT_EQ(1u, list.size());
141 EXPECT_EQ(top, list.front());
142@@ -80,7 +80,7 @@
143 auto bottom = std::make_shared<mtd::FakeRenderable>(Rectangle{{12, 12}, {5, 5}}, 1.0f);
144 mg::RenderableList list{bottom, top};
145
146- filter_occlusions_from(list, monitor_rect);
147+ filter_occlusions_from(list, monitor_rect, simple_renderable_rect);
148
149 ASSERT_EQ(2u, list.size());
150 EXPECT_EQ(bottom, list.front());
151@@ -92,7 +92,7 @@
152 auto window = std::make_shared<mtd::FakeRenderable>(Rectangle{{10, 10}, {10, 10}}, 1.0f, true, false);
153 mg::RenderableList list{window};
154
155- filter_occlusions_from(list, monitor_rect);
156+ filter_occlusions_from(list, monitor_rect, simple_renderable_rect);
157
158 EXPECT_EQ(0u, list.size());
159 }
160@@ -103,7 +103,7 @@
161 auto bottom = std::make_shared<mtd::FakeRenderable>(12, 12, 5, 5);
162 mg::RenderableList list{bottom, top};
163
164- filter_occlusions_from(list, monitor_rect);
165+ filter_occlusions_from(list, monitor_rect, simple_renderable_rect);
166
167 ASSERT_EQ(1u, list.size());
168 EXPECT_EQ(bottom, list.front());
169@@ -115,7 +115,7 @@
170 auto bottom = std::make_shared<mtd::FakeRenderable>(12, 12, 5, 5);
171 mg::RenderableList list{bottom, top};
172
173- filter_occlusions_from(list, monitor_rect);
174+ filter_occlusions_from(list, monitor_rect, simple_renderable_rect);
175
176 ASSERT_EQ(2u, list.size());
177 EXPECT_EQ(bottom, list.front());
178@@ -128,7 +128,7 @@
179 auto bottom = std::make_shared<mtd::FakeRenderable>(10, 10, 10, 10);
180 mg::RenderableList list{bottom, top};
181
182- filter_occlusions_from(list, monitor_rect);
183+ filter_occlusions_from(list, monitor_rect, simple_renderable_rect);
184
185 ASSERT_EQ(1u, list.size());
186 EXPECT_EQ(top, list.front());
187@@ -140,7 +140,7 @@
188 auto bottom = std::make_shared<mtd::FakeRenderable>(9, 9, 12, 12);
189 mg::RenderableList list{bottom, top};
190
191- filter_occlusions_from(list, monitor_rect);
192+ filter_occlusions_from(list, monitor_rect, simple_renderable_rect);
193
194 ASSERT_EQ(2u, list.size());
195 EXPECT_EQ(bottom, list.front());
196@@ -154,7 +154,7 @@
197 for (auto x = 0u; x < num_windows; x++)
198 list.push_back(std::make_shared<mtd::FakeRenderable>(x, x, 200, 100));
199
200- filter_occlusions_from(list, monitor_rect);
201+ filter_occlusions_from(list, monitor_rect, simple_renderable_rect);
202 EXPECT_EQ(num_windows, list.size());
203 }
204
205@@ -175,7 +175,7 @@
206 window0 //not occluded
207 };
208
209- filter_occlusions_from(list, monitor_rect);
210+ filter_occlusions_from(list, monitor_rect, simple_renderable_rect);
211
212 auto expected_size = 3u;
213 ASSERT_EQ(expected_size, list.size());

Subscribers

People subscribed via source and target branches