Mir

Merge lp:~afrantzis/mir/consume-only-not-rendered-buffers into lp:mir

Proposed by Alexandros Frantzis
Status: Rejected
Rejected by: Alexandros Frantzis
Proposed branch: lp:~afrantzis/mir/consume-only-not-rendered-buffers
Merge into: lp:mir
Diff against target: 365 lines (+82/-31)
11 files modified
examples/render_overlays.cpp (+11/-1)
include/platform/mir/graphics/renderable.h (+2/-0)
include/test/mir_test_doubles/fake_renderable.h (+10/-1)
include/test/mir_test_doubles/mock_renderable.h (+1/-0)
include/test/mir_test_doubles/stub_renderable.h (+13/-0)
src/server/compositor/multi_threaded_compositor.cpp (+23/-27)
src/server/scene/basic_surface.cpp (+8/-0)
src/server/scene/basic_surface.h (+3/-0)
src/server/scene/surface_stack.cpp (+3/-0)
tests/unit-tests/compositor/test_multi_threaded_compositor.cpp (+2/-2)
tests/unit-tests/graphics/android/test_hwc_device.cpp (+6/-0)
To merge this branch: bzr merge lp:~afrantzis/mir/consume-only-not-rendered-buffers
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Daniel van Vugt Needs Fixing
Kevin DuBois (community) Needs Fixing
Alan Griffiths Needs Information
Review via email: mp+216725@code.launchpad.net

Commit message

compositor: Only consume buffers that have not been rendered recently to unblock client eglSwapBuffers

Also resolves regressions - LP: #1308843 and LP: #1308844.

Description of the change

compositor: Only consume buffers that have not been rendered recently to unblock client eglSwapBuffers

Mix the best aspects of our various approaches to provide non-blocking swap buffers.

This MP uses the buffer consuming thread at the MultiThreadedCompositor level that's already present in mir/devel, but changes it so that it only consumes buffers that are not otherwise consumed by the real compositor, like https://code.launchpad.net/~raof/mir/1hz-rendering-always/+merge/216246 does. This avoids "beating" effects that are inherent in our handling of multiple compositors (i.e. multiple monitors).

Like 1hz-rendering-always, the selective buffer rendering is based on knowning when buffers are not used for some amount of time, so our consumption rate needs to be smaller than the least real compositor consumption rate (i.e. vsync). I have used 10Hz in this MP but we can change it to whatever value we want; we can even set it dynamically depending on the vsync rates of the connected screens.

To post a comment you must log in.
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

I've nothing specifically against this MP but we seem to have a flurry of MPs trying to balance incompatible requirements. Vis:

1. The compositor can always get a buffer for a surface
2. A client can always swap buffers without blocking
3. We don't drop frames
4. There's a finite limit to how many buffers we allocate

As it is logically impossible to do all of these things some requirement has to be relaxed. Which is it?

review: Needs Information
Revision history for this message
Robert Carr (robertcarr) wrote :

>> As it is logically impossible to do all of these things some requirement has to be relaxed. Which is it?

The way I have been modeling it in my head is when the screen is off or a client is occluded we may "drop frames"

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

+ virtual std::chrono::steady_clock::time_point time_last_buffer_acquired() const = 0;

this makes Renderable leak the buffer stream abstraction even worse than it has before (I expound on this in my mp review: https://code.launchpad.net/~kdub/mir/produce-renderlist-for-particular-compositor/+merge/215052/comments/514979)

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

> + virtual std::chrono::steady_clock::time_point time_last_buffer_acquired()
> const = 0;
>
> this makes Renderable leak the buffer stream abstraction even worse than it
> has before (I expound on this in my mp review:
> https://code.launchpad.net/~kdub/mir/produce-renderlist-for-particular-
> compositor/+merge/215052/comments/514979)

Note that the "buffer_acquired" in time_last_buffer_acquired() doesn't refer to the underlying buffer stream, but to Renderable::buffer(). That is, it returns the time point when someone last called Renderable::buffer(), regardless of the underlying implementation.

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

I think this is a slightly awkward way to express what I proposed (without using time measurement):
https://code.launchpad.net/~vanvugt/mir/judder/+merge/216694

I'd prefer all future work avoided the unreliability of time measurement. Because with some careful planning you can avoid it.

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

> I think this is a slightly awkward way to express what I proposed (without
> using time measurement):
> https://code.launchpad.net/~vanvugt/mir/judder/+merge/216694
>
> I'd prefer all future work avoided the unreliability of time measurement.
> Because with some careful planning you can avoid it.

The two proposal are not equivalent. As noted in https://code.launchpad.net/~vanvugt/mir/judder/+merge/216694, the judder branch "reintroduces eglSwapBuffers() blocking for buffers that are not rendered by the real compositors (i.e. for surfaces that are either occluded or off screen). That is, it only keeps eglSwapBuffers() running when all monitors are off."

This proposal keeps eglSwapBuffers() running in all cases (monitors off, surface occluded, surface off-screen).

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

Yes, that's what the unocclude branch solves.

I'm not rejecting this one, but I think it needs to be better (avoid time measurement), particularly since I've already proved doing so is possible.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1569. By Alexandros Frantzis

tests: Fix android build

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

The team has decided to go with an approach that handles non blocking inside the SwitchingBundle (for after 0.1.9).
That approach will also solve the "judder" issue, so since the "judder" issue is not critical (or even noticeable in many cases) we will probably ignore it for 0.1.9. Rejecting this MP.

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

Unmerged revisions

1569. By Alexandros Frantzis

tests: Fix android build

1568. By Alexandros Frantzis

compositor: Only consume buffers that have not been rendered recently to unblock client eglSwapBuffers

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'examples/render_overlays.cpp'
2--- examples/render_overlays.cpp 2014-04-15 05:31:19 +0000
3+++ examples/render_overlays.cpp 2014-04-23 14:10:27 +0000
4@@ -31,6 +31,7 @@
5 #include <chrono>
6 #include <csignal>
7 #include <iostream>
8+#include <atomic>
9
10 namespace mg=mir::graphics;
11 namespace ml=mir::logging;
12@@ -101,7 +102,8 @@
13 public:
14 DemoRenderable(std::shared_ptr<DemoOverlayClient> const& client, geom::Rectangle rect)
15 : client(client),
16- position(rect)
17+ position(rect),
18+ duration_last_buffer_acquired{std::chrono::steady_clock::duration{0}}
19 {
20 }
21
22@@ -112,6 +114,8 @@
23
24 std::shared_ptr<mg::Buffer> buffer(void const*) const override
25 {
26+ duration_last_buffer_acquired =
27+ std::chrono::steady_clock::now().time_since_epoch();
28 return client->last_rendered();
29 }
30
31@@ -150,10 +154,16 @@
32 return 1;
33 }
34
35+ std::chrono::steady_clock::time_point time_last_buffer_acquired() const
36+ {
37+ return std::chrono::steady_clock::time_point{duration_last_buffer_acquired};
38+ }
39+
40 private:
41 std::shared_ptr<DemoOverlayClient> const client;
42 geom::Rectangle const position;
43 glm::mat4 const trans;
44+ mutable std::atomic<std::chrono::steady_clock::duration> duration_last_buffer_acquired;
45 };
46 }
47
48
49=== modified file 'include/platform/mir/graphics/renderable.h'
50--- include/platform/mir/graphics/renderable.h 2014-04-15 05:31:19 +0000
51+++ include/platform/mir/graphics/renderable.h 2014-04-23 14:10:27 +0000
52@@ -23,6 +23,7 @@
53 #include <glm/glm.hpp>
54 #include <memory>
55 #include <list>
56+#include <chrono>
57
58 namespace mir
59 {
60@@ -84,6 +85,7 @@
61
62 virtual bool shaped() const = 0; // meaning the pixel format has alpha
63 virtual int buffers_ready_for_compositor() const = 0;
64+ virtual std::chrono::steady_clock::time_point time_last_buffer_acquired() const = 0;
65
66 protected:
67 Renderable() = default;
68
69=== modified file 'include/test/mir_test_doubles/fake_renderable.h'
70--- include/test/mir_test_doubles/fake_renderable.h 2014-04-15 05:31:19 +0000
71+++ include/test/mir_test_doubles/fake_renderable.h 2014-04-23 14:10:27 +0000
72@@ -23,6 +23,7 @@
73 #define GLM_FORCE_RADIANS
74 #include <glm/gtc/matrix_transform.hpp>
75 #include <gmock/gmock.h>
76+#include <atomic>
77
78 namespace mir
79 {
80@@ -43,7 +44,8 @@
81 opacity(opacity),
82 rectangular(rectangular),
83 visible_(visible),
84- posted(posted)
85+ posted(posted),
86+ duration_last_buffer_acquired{std::chrono::steady_clock::duration{0}}
87 {
88 }
89
90@@ -79,6 +81,7 @@
91
92 std::shared_ptr<graphics::Buffer> buffer(void const*) const override
93 {
94+ duration_last_buffer_acquired = std::chrono::steady_clock::now().time_since_epoch();
95 return buf;
96 }
97
98@@ -97,6 +100,11 @@
99 return 1;
100 }
101
102+ std::chrono::steady_clock::time_point time_last_buffer_acquired() const override
103+ {
104+ return std::chrono::steady_clock::time_point{duration_last_buffer_acquired};
105+ }
106+
107 private:
108 std::shared_ptr<graphics::Buffer> buf;
109 mir::geometry::Rectangle rect;
110@@ -104,6 +112,7 @@
111 bool rectangular;
112 bool visible_;
113 bool posted;
114+ mutable std::atomic<std::chrono::steady_clock::duration> duration_last_buffer_acquired;
115 };
116
117 } // namespace doubles
118
119=== modified file 'include/test/mir_test_doubles/mock_renderable.h'
120--- include/test/mir_test_doubles/mock_renderable.h 2014-04-15 05:31:19 +0000
121+++ include/test/mir_test_doubles/mock_renderable.h 2014-04-23 14:10:27 +0000
122@@ -56,6 +56,7 @@
123 MOCK_CONST_METHOD0(visible, bool());
124 MOCK_CONST_METHOD0(shaped, bool());
125 MOCK_CONST_METHOD0(buffers_ready_for_compositor, int());
126+ MOCK_CONST_METHOD0(time_last_buffer_acquired, std::chrono::steady_clock::time_point());
127 };
128 }
129 }
130
131=== modified file 'include/test/mir_test_doubles/stub_renderable.h'
132--- include/test/mir_test_doubles/stub_renderable.h 2014-04-15 05:31:19 +0000
133+++ include/test/mir_test_doubles/stub_renderable.h 2014-04-23 14:10:27 +0000
134@@ -22,6 +22,7 @@
135 #include "mir_test_doubles/stub_buffer.h"
136 #include <mir/graphics/renderable.h>
137 #include <memory>
138+#include <atomic>
139
140 namespace mir
141 {
142@@ -33,12 +34,18 @@
143 class StubRenderable : public graphics::Renderable
144 {
145 public:
146+ StubRenderable() :
147+ duration_last_buffer_acquired{std::chrono::steady_clock::duration{0}}
148+ {
149+ }
150+
151 ID id() const override
152 {
153 return this;
154 }
155 std::shared_ptr<graphics::Buffer> buffer(void const*) const override
156 {
157+ duration_last_buffer_acquired = std::chrono::steady_clock::now().time_since_epoch();
158 return std::make_shared<StubBuffer>();
159 }
160 bool alpha_enabled() const
161@@ -71,8 +78,14 @@
162 return 1;
163 }
164
165+ std::chrono::steady_clock::time_point time_last_buffer_acquired() const override
166+ {
167+ return std::chrono::steady_clock::time_point{duration_last_buffer_acquired};
168+ }
169+
170 private:
171 glm::mat4 trans;
172+ mutable std::atomic<std::chrono::steady_clock::duration> duration_last_buffer_acquired;
173 };
174
175 }
176
177=== modified file 'src/server/compositor/multi_threaded_compositor.cpp'
178--- src/server/compositor/multi_threaded_compositor.cpp 2014-04-17 01:34:35 +0000
179+++ src/server/compositor/multi_threaded_compositor.cpp 2014-04-23 14:10:27 +0000
180@@ -183,11 +183,20 @@
181 std::shared_ptr<CompositorReport> const report;
182 };
183
184+/*
185+ * Consumes buffers that haven't been consumed by the real compositors
186+ * for more than "buffer_consumption_period" time, forcing clients to
187+ * render at 1/sec(buffer_consumption_period) Hz even when the respective
188+ * surfaces are not rendered in any display. Note that for this to work
189+ * properly the buffer consumption period needs to be smaller than the
190+ * least real compositor period.
191+ */
192 class BufferConsumingFunctor : public CompositingFunctor
193 {
194 public:
195 BufferConsumingFunctor(std::shared_ptr<mc::Scene> const& scene)
196- : scene{scene}
197+ : scene{scene},
198+ buffer_consumption_period{std::chrono::milliseconds{100}}
199 {
200 }
201
202@@ -196,41 +205,28 @@
203 run_compositing_loop(
204 [this]
205 {
206- std::vector<std::shared_ptr<mg::Buffer>> saved_resources;
207-
208- auto const& renderables = scene->generate_renderable_list();
209-
210- for (auto const& r : renderables)
211+ auto const one_buffer_consumption_period_ago =
212+ std::chrono::steady_clock::now();
213+
214+ std::this_thread::sleep_for(buffer_consumption_period);
215+
216+ auto const& all = scene->generate_renderable_list();
217+ for (auto const& r : all)
218 {
219- if (r->visible())
220- saved_resources.push_back(r->buffer(this));
221+ if (r->buffers_ready_for_compositor() &&
222+ r->time_last_buffer_acquired() <= one_buffer_consumption_period_ago)
223+ {
224+ static_cast<void>(r->buffer(this));
225+ }
226 }
227
228- wait_until_next_fake_vsync();
229-
230 return false;
231 });
232 }
233
234 private:
235- void wait_until_next_fake_vsync()
236- {
237- using namespace std::chrono;
238- typedef duration<int64_t, std::ratio<1, 60>> vsync_periods;
239-
240- /* Truncate to vsync periods */
241- auto const previous_vsync =
242- duration_cast<vsync_periods>(steady_clock::now().time_since_epoch());
243- /* Convert back to a timepoint */
244- auto const previous_vsync_tp =
245- time_point<steady_clock, vsync_periods>{previous_vsync};
246- /* Next vsync time point */
247- auto const next_vsync = previous_vsync_tp + vsync_periods(1);
248-
249- std::this_thread::sleep_until(next_vsync);
250- }
251-
252 std::shared_ptr<mc::Scene> const scene;
253+ std::chrono::milliseconds const buffer_consumption_period;
254 };
255
256 }
257
258=== modified file 'src/server/scene/basic_surface.cpp'
259--- src/server/scene/basic_surface.cpp 2014-04-15 05:31:19 +0000
260+++ src/server/scene/basic_surface.cpp 2014-04-23 14:10:27 +0000
261@@ -124,6 +124,7 @@
262 surface_alpha(1.0f),
263 first_frame_posted(false),
264 hidden(false),
265+ duration_last_buffer_acquired(std::chrono::steady_clock::duration{0}),
266 nonrectangular(nonrectangular),
267 input_rectangles{surface_rect},
268 surface_buffer_stream(buffer_stream),
269@@ -332,6 +333,7 @@
270
271 std::shared_ptr<mg::Buffer> ms::BasicSurface::buffer(void const* user_id) const
272 {
273+ duration_last_buffer_acquired = std::chrono::steady_clock::now().time_since_epoch();
274 return buffer_stream()->lock_compositor_buffer(user_id);
275 }
276
277@@ -350,6 +352,12 @@
278 return surface_buffer_stream->buffers_ready_for_compositor();
279 }
280
281+std::chrono::steady_clock::time_point
282+ms::BasicSurface::time_last_buffer_acquired() const
283+{
284+ return std::chrono::steady_clock::time_point{duration_last_buffer_acquired};
285+}
286+
287 void ms::BasicSurface::with_most_recent_buffer_do(
288 std::function<void(mg::Buffer&)> const& exec)
289 {
290
291=== modified file 'src/server/scene/basic_surface.h'
292--- src/server/scene/basic_surface.h 2014-04-15 05:31:19 +0000
293+++ src/server/scene/basic_surface.h 2014-04-23 14:10:27 +0000
294@@ -31,6 +31,7 @@
295 #include <memory>
296 #include <mutex>
297 #include <string>
298+#include <atomic>
299
300 namespace mir
301 {
302@@ -127,6 +128,7 @@
303 bool alpha_enabled() const override;
304 geometry::Rectangle screen_position() const override;
305 int buffers_ready_for_compositor() const override;
306+ std::chrono::steady_clock::time_point time_last_buffer_acquired() const override;
307
308 void with_most_recent_buffer_do(
309 std::function<void(graphics::Buffer&)> const& exec) override;
310@@ -153,6 +155,7 @@
311 float surface_alpha;
312 bool first_frame_posted;
313 bool hidden;
314+ mutable std::atomic<std::chrono::steady_clock::duration> duration_last_buffer_acquired;
315 const bool nonrectangular;
316 std::vector<geometry::Rectangle> input_rectangles;
317 std::shared_ptr<compositor::BufferStream> const surface_buffer_stream;
318
319=== modified file 'src/server/scene/surface_stack.cpp'
320--- src/server/scene/surface_stack.cpp 2014-04-17 01:34:35 +0000
321+++ src/server/scene/surface_stack.cpp 2014-04-23 14:10:27 +0000
322@@ -82,6 +82,9 @@
323 int buffers_ready_for_compositor() const override
324 { return underlying_renderable->buffers_ready_for_compositor(); }
325
326+ std::chrono::steady_clock::time_point time_last_buffer_acquired() const override
327+ { return underlying_renderable->time_last_buffer_acquired(); }
328+
329 bool visible() const override
330 { return visible_; }
331
332
333=== modified file 'tests/unit-tests/compositor/test_multi_threaded_compositor.cpp'
334--- tests/unit-tests/compositor/test_multi_threaded_compositor.cpp 2014-04-16 14:49:54 +0000
335+++ tests/unit-tests/compositor/test_multi_threaded_compositor.cpp 2014-04-23 14:10:27 +0000
336@@ -308,10 +308,10 @@
337 public:
338 BufferCountingRenderable() : buffers_requested_{0} {}
339
340- std::shared_ptr<mg::Buffer> buffer(void const*) const override
341+ std::shared_ptr<mg::Buffer> buffer(void const* id) const override
342 {
343 ++buffers_requested_;
344- return std::make_shared<mtd::StubBuffer>();
345+ return mtd::StubRenderable::buffer(id);
346 }
347
348 int buffers_requested() const
349
350=== modified file 'tests/unit-tests/graphics/android/test_hwc_device.cpp'
351--- tests/unit-tests/graphics/android/test_hwc_device.cpp 2014-04-15 05:31:19 +0000
352+++ tests/unit-tests/graphics/android/test_hwc_device.cpp 2014-04-23 14:10:27 +0000
353@@ -101,6 +101,12 @@
354 {
355 return 1;
356 }
357+
358+ std::chrono::steady_clock::time_point time_last_buffer_acquired() const override
359+ {
360+ return std::chrono::steady_clock::time_point{};
361+ }
362+
363 private:
364 std::shared_ptr<mg::Buffer> buf;
365 geom::Rectangle screen_pos;

Subscribers

People subscribed via source and target branches