Mir

Merge lp:~kdub/mir/nested-db-link-to-streams into lp:mir

Proposed by Kevin DuBois
Status: Work in progress
Proposed branch: lp:~kdub/mir/nested-db-link-to-streams
Merge into: lp:mir
Diff against target: 310 lines (+197/-11)
5 files modified
src/server/graphics/nested/display_buffer.cpp (+52/-3)
src/server/graphics/nested/display_buffer.h (+9/-0)
src/server/graphics/nested/host_stream.h (+47/-0)
tests/include/mir_test_doubles/mock_host_stream.h (+43/-0)
tests/unit-tests/graphics/nested/test_nested_display_buffer.cpp (+46/-8)
To merge this branch: bzr merge lp:~kdub/mir/nested-db-link-to-streams
Reviewer Review Type Date Requested Status
Alan Griffiths Needs Fixing
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+256181@code.launchpad.net

Commit message

nested: add a currently-unused way to link the nested MirBufferStream abstraction to a mgn::DisplayBuffer, and have the buffer associate incoming renderables with linked streams to see if an optimized render is possible.

Description of the change

nested: add a currently-unused way to link the nested MirBufferStream abstraction to a mgn::DisplayBuffer, and have the buffer associate incoming renderables with linked streams to see if an optimized render is possible.

note: mgn::HostStream will have to expand a bit, depending on how that RFC branch shapes up. mgn::DisplayBuffer::post_renderables_if_optimizable() will then use those positioning functions to arrange and commit the scene to the host in sync.

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
Alan Griffiths (alan-griffiths) wrote :

281+TEST_F(NestedDisplayBufferTest, post_optimized_success)

"post_optimized_success" is not a very clear test name. It is worth considering the "given/when/then" rule. (E.g. http://martinfowler.com/bliki/GivenWhenThen.html)

given_an_optimizable_stream_when_post_if_optimizable_then_result_is_success

Or more succinctly:

given_an_optimizable_stream_post_if_optimizable_succeeds

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

Actually, I misunderstood the test:

when_linked_with_a_stream_post_if_optimizable_succeeds

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

39+ //validate that we have a host-allocated stream for every renderable we're given
40+ for(auto const& renderable : renderables)
41+ {
42+ auto buffer = renderable->buffer();
43+ auto stream_it = std::find_if(streams.begin(), streams.end(),
44+ [&buffer](HostStream* stream){ return buffer_is_current_in_stream(*buffer, stream); });
45+ //if we have any stream that needs to be rendered but we don't have a stream associated
46+ //we can't passthrough the render
47+ if (stream_it == streams.end())
48+ return false;
49+ }
50+
51+ //TODO: work out how to submit changes synchronously to the client API
52+ for(auto const& renderable : renderables)
53+ {
54+ //TODO: arrange the surfaces via the api according to how RenderableList is structured
55+ auto buffer = renderable->buffer();
56+ auto stream_it = std::find_if(streams.begin(), streams.end(),
57+ [&buffer](HostStream* stream){ return buffer_is_current_in_stream(*buffer, stream); });
58+ (*stream_it)->swap();59+ }

I've not thought it through, but this code has the ugliness I associate with choosing the wrong data structure (or algorithm).

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

> I've not thought it through, but this code has the ugliness I associate with
> choosing the wrong data structure (or algorithm).

Fair enough. At a high level though, the linkage between the BufferQueue and the DisplayBuffer is needed. The BufferQueue has to get its buffers from MirBufferStream, and the DisplayBuffer has to sort and arrange those streams to paint the desired picture.

It does become nicer if the client isn't so locked into its choices of buffers to use (currently the client has 1 buffer it can use). If the client could allocate more than one buffer, it could simply use those as the buffers in BufferQueue, and mgn::DisplayBuffer could figure out which which buffer to set as the 'active one' when it goes to post, as well as arrange appropriately.

Maybe I'll explore that route a bit more.

Unmerged revisions

2484. By Kevin DuBois

merge mir

2483. By Kevin DuBois

cleanups

2482. By Kevin DuBois

missing files

2481. By Kevin DuBois

test to pass

2480. By Kevin DuBois

another test

2479. By Kevin DuBois

test to compile

2478. By Kevin DuBois

add tests for nested posting for nested db

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/server/graphics/nested/display_buffer.cpp'
2--- src/server/graphics/nested/display_buffer.cpp 2015-04-10 01:59:08 +0000
3+++ src/server/graphics/nested/display_buffer.cpp 2015-04-14 17:12:08 +0000
4@@ -19,12 +19,15 @@
5 #include "display_buffer.h"
6
7 #include "host_connection.h"
8+#include "host_stream.h"
9 #include "mir/input/input_dispatcher.h"
10 #include "mir/graphics/pixel_format_utils.h"
11+#include "mir/graphics/buffer.h"
12 #include "mir/events/event_private.h"
13
14 #include <boost/throw_exception.hpp>
15 #include <stdexcept>
16+#include <algorithm>
17
18 namespace mg = mir::graphics;
19 namespace mgn = mir::graphics::nested;
20@@ -69,9 +72,41 @@
21 eglSwapBuffers(egl_display, egl_surface);
22 }
23
24-bool mgn::detail::DisplayBuffer::post_renderables_if_optimizable(RenderableList const&)
25-{
26- return false;
27+namespace
28+{
29+bool buffer_is_current_in_stream(mg::Buffer& buffer, mgn::HostStream* stream)
30+{
31+ return buffer.id() == stream->current_buffer().lock()->id();
32+}
33+}
34+
35+bool mgn::detail::DisplayBuffer::post_renderables_if_optimizable(RenderableList const& renderables)
36+{
37+ std::unique_lock<decltype(stream_mutex)> lk(stream_mutex);
38+
39+ //validate that we have a host-allocated stream for every renderable we're given
40+ for(auto const& renderable : renderables)
41+ {
42+ auto buffer = renderable->buffer();
43+ auto stream_it = std::find_if(streams.begin(), streams.end(),
44+ [&buffer](HostStream* stream){ return buffer_is_current_in_stream(*buffer, stream); });
45+ //if we have any stream that needs to be rendered but we don't have a stream associated
46+ //we can't passthrough the render
47+ if (stream_it == streams.end())
48+ return false;
49+ }
50+
51+ //TODO: work out how to submit changes synchronously to the client API
52+ for(auto const& renderable : renderables)
53+ {
54+ //TODO: arrange the surfaces via the api according to how RenderableList is structured
55+ auto buffer = renderable->buffer();
56+ auto stream_it = std::find_if(streams.begin(), streams.end(),
57+ [&buffer](HostStream* stream){ return buffer_is_current_in_stream(*buffer, stream); });
58+ (*stream_it)->swap();
59+ }
60+
61+ return true;
62 }
63
64 MirOrientation mgn::detail::DisplayBuffer::orientation() const
65@@ -119,3 +154,17 @@
66 dispatcher->dispatch(event);
67 }
68 }
69+
70+void mgn::detail::DisplayBuffer::link_with_stream(HostStream* stream)
71+{
72+ std::unique_lock<decltype(stream_mutex)> lk(stream_mutex);
73+ streams.insert(stream);
74+}
75+
76+void mgn::detail::DisplayBuffer::unlink_from_stream(HostStream* stream)
77+{
78+ std::unique_lock<decltype(stream_mutex)> lk(stream_mutex);
79+ auto it = streams.find(stream);
80+ if (it != streams.end())
81+ streams.erase(it);
82+}
83
84=== modified file 'src/server/graphics/nested/display_buffer.h'
85--- src/server/graphics/nested/display_buffer.h 2015-04-08 03:02:37 +0000
86+++ src/server/graphics/nested/display_buffer.h 2015-04-14 17:12:08 +0000
87@@ -24,6 +24,8 @@
88 #include "host_surface.h"
89
90 #include <EGL/egl.h>
91+#include <mutex>
92+#include <set>
93
94 namespace mir
95 {
96@@ -32,6 +34,7 @@
97 namespace nested
98 {
99 class HostSurface;
100+class HostStream;
101
102 namespace detail
103 {
104@@ -57,6 +60,9 @@
105
106 bool post_renderables_if_optimizable(RenderableList const& renderlist) override;
107
108+ void link_with_stream(HostStream*);
109+ void unlink_from_stream(HostStream*);
110+
111 DisplayBuffer(DisplayBuffer const&) = delete;
112 DisplayBuffer operator=(DisplayBuffer const&) = delete;
113 private:
114@@ -69,6 +75,9 @@
115 std::shared_ptr<input::InputDispatcher> const dispatcher;
116 EGLSurfaceHandle const egl_surface;
117
118+ std::mutex stream_mutex;
119+ std::set<HostStream*> streams;
120+
121 static void event_thunk(MirSurface* surface, MirEvent const* event, void* context);
122 void mir_event(MirEvent const& event);
123 };
124
125=== added file 'src/server/graphics/nested/host_stream.h'
126--- src/server/graphics/nested/host_stream.h 1970-01-01 00:00:00 +0000
127+++ src/server/graphics/nested/host_stream.h 2015-04-14 17:12:08 +0000
128@@ -0,0 +1,47 @@
129+/*
130+ * Copyright © 2015 Canonical Ltd.
131+ *
132+ * This program is free software: you can redistribute it and/or modify it
133+ * under the terms of the GNU General Public License version 3,
134+ * as published by the Free Software Foundation.
135+ *
136+ * This program is distributed in the hope that it will be useful,
137+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
138+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
139+ * GNU General Public License for more details.
140+ *
141+ * You should have received a copy of the GNU General Public License
142+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
143+ *
144+ * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
145+ */
146+
147+#ifndef MIR_GRAPHICS_NESTED_HOST_STREAM_H_
148+#define MIR_GRAPHICS_NESTED_HOST_STREAM_H_
149+
150+#include <memory>
151+
152+namespace mir
153+{
154+namespace graphics
155+{
156+class Buffer;
157+namespace nested
158+{
159+
160+class HostStream
161+{
162+public:
163+ virtual ~HostStream() = default;
164+ virtual std::weak_ptr<Buffer> current_buffer() const = 0;
165+ virtual void swap() = 0;
166+protected:
167+ HostStream() = default;
168+ HostStream(HostStream const&) = delete;
169+ HostStream& operator=(HostStream const&) = delete;
170+};
171+
172+}
173+}
174+}
175+#endif // MIR_GRAPHICS_NESTED_HOST_STREAM_H_
176
177=== added file 'tests/include/mir_test_doubles/mock_host_stream.h'
178--- tests/include/mir_test_doubles/mock_host_stream.h 1970-01-01 00:00:00 +0000
179+++ tests/include/mir_test_doubles/mock_host_stream.h 2015-04-14 17:12:08 +0000
180@@ -0,0 +1,43 @@
181+/*
182+ * Copyright © 2015 Canonical Ltd.
183+ *
184+ * This program is free software: you can redistribute it and/or modify it
185+ * under the terms of the GNU General Public License version 3,
186+ * as published by the Free Software Foundation.
187+ *
188+ * This program is distributed in the hope that it will be useful,
189+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
190+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
191+ * GNU General Public License for more details.
192+ *
193+ * You should have received a copy of the GNU General Public License
194+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
195+ *
196+ * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
197+ */
198+
199+#ifndef MIR_TEST_DOUBLES_MOCK_HOST_STREAM_H_
200+#define MIR_TEST_DOUBLES_MOCK_HOST_STREAM_H_
201+
202+#include "src/server/graphics/nested/host_stream.h"
203+
204+#include <gmock/gmock.h>
205+#include <gtest/gtest.h>
206+
207+namespace mir
208+{
209+namespace test
210+{
211+namespace doubles
212+{
213+
214+struct MockHostStream : graphics::nested::HostStream
215+{
216+ MOCK_CONST_METHOD0(current_buffer, std::weak_ptr<graphics::Buffer>());
217+ MOCK_METHOD0(swap, void());
218+};
219+
220+}
221+}
222+}
223+#endif /* MIR_TEST_DOUBLES_MOCK_HOST_STREAM_H_ */
224
225=== modified file 'tests/unit-tests/graphics/nested/test_nested_display_buffer.cpp'
226--- tests/unit-tests/graphics/nested/test_nested_display_buffer.cpp 2015-04-08 03:02:37 +0000
227+++ tests/unit-tests/graphics/nested/test_nested_display_buffer.cpp 2015-04-14 17:12:08 +0000
228@@ -21,7 +21,10 @@
229 #include "src/server/input/null_input_dispatcher.h"
230
231 #include "mir_test_doubles/mock_egl.h"
232+#include "mir_test_doubles/mock_host_stream.h"
233 #include "mir_test_doubles/stub_gl_config.h"
234+#include "mir_test_doubles/stub_buffer.h"
235+#include "mir_test_doubles/stub_renderable.h"
236 #include "mir_test/fake_shared.h"
237
238 #include <gtest/gtest.h>
239@@ -47,24 +50,28 @@
240 : egl_disp_handle{mock_egl.fake_egl_display,
241 mt::fake_shared(stub_gl_config)},
242 default_rect{{100,100}, {800,600}}
243- {}
244+ {
245+ ON_CALL(mock_stream, current_buffer())
246+ .WillByDefault(testing::Return(stub_buffer));
247+ }
248 testing::NiceMock<mtd::MockEGL> mock_egl;
249 mtd::StubGLConfig stub_gl_config;
250 NullHostSurface null_host_surface;
251 mi::NullInputDispatcher null_input_dispatcher;
252 mgnd::EGLDisplayHandle egl_disp_handle;
253 geom::Rectangle const default_rect;
254+ mgnd::DisplayBuffer db{
255+ egl_disp_handle,
256+ mt::fake_shared(null_host_surface),
257+ default_rect,
258+ mt::fake_shared(null_input_dispatcher),
259+ mir_pixel_format_abgr_8888};
260+ testing::NiceMock<mtd::MockHostStream> mock_stream;
261+ std::shared_ptr<mtd::StubBuffer> stub_buffer{std::make_shared<mtd::StubBuffer>()};
262 };
263
264 TEST_F(NestedDisplayBufferTest, alpha_enabled_pixel_format_enables_destination_alpha)
265 {
266- mgnd::DisplayBuffer db{
267- egl_disp_handle,
268- mt::fake_shared(null_host_surface),
269- default_rect,
270- mt::fake_shared(null_input_dispatcher),
271- mir_pixel_format_abgr_8888};
272-
273 EXPECT_TRUE(db.uses_alpha());
274 }
275
276@@ -79,3 +86,34 @@
277
278 EXPECT_FALSE(db.uses_alpha());
279 }
280+
281+TEST_F(NestedDisplayBufferTest, post_optimized_success)
282+{
283+ EXPECT_CALL(mock_stream, swap());
284+ db.link_with_stream(&mock_stream);
285+
286+ auto renderable_from_stream = std::make_shared<mtd::StubRenderable>(stub_buffer);
287+ EXPECT_TRUE(db.post_renderables_if_optimizable({renderable_from_stream}));
288+ db.unlink_from_stream(&mock_stream);
289+}
290+
291+TEST_F(NestedDisplayBufferTest, unlinking_causes_rejections)
292+{
293+ db.link_with_stream(&mock_stream);
294+
295+ auto renderable_from_stream = std::make_shared<mtd::StubRenderable>(
296+ stub_buffer);
297+ db.post_renderables_if_optimizable({renderable_from_stream});
298+ db.unlink_from_stream(&mock_stream);
299+
300+ EXPECT_FALSE(db.post_renderables_if_optimizable({renderable_from_stream}));
301+}
302+
303+TEST_F(NestedDisplayBufferTest, post_optimized_rejection_because_of_unknown_buffer)
304+{
305+ db.link_with_stream(&mock_stream);
306+
307+ auto nonstream_renderable = std::make_shared<mtd::StubRenderable>();
308+ EXPECT_FALSE(db.post_renderables_if_optimizable({nonstream_renderable}));
309+ db.unlink_from_stream(&mock_stream);
310+}

Subscribers

People subscribed via source and target branches