Merge lp:~kdub/mir/multiple-bufferstream-api into lp:mir
- multiple-bufferstream-api
- Merge into development-branch
Status: | Merged |
---|---|
Approved by: | Kevin DuBois |
Approved revision: | no longer in the source branch. |
Merged at revision: | 2670 |
Proposed branch: | lp:~kdub/mir/multiple-bufferstream-api |
Merge into: | lp:mir |
Prerequisite: | lp:~kdub/mir/add-streams-to-surface |
Diff against target: |
644 lines (+402/-15) 18 files modified
include/client/mir_toolkit/client_types.h (+10/-0) include/client/mir_toolkit/mir_surface.h (+22/-0) include/server/mir/scene/session.h (+3/-0) src/client/mir_surface.cpp (+13/-0) src/client/mir_surface.h (+1/-0) src/client/mir_surface_api.cpp (+20/-0) src/client/symbols.map (+1/-0) src/server/frontend/session_mediator.cpp (+10/-7) src/server/scene/application_session.cpp (+9/-0) src/server/scene/application_session.h (+1/-0) src/server/scene/basic_surface.cpp (+10/-7) src/server/shell/canonical_window_manager.cpp (+8/-1) tests/acceptance-tests/CMakeLists.txt (+1/-0) tests/acceptance-tests/test_buffer_stream_arrangement.cpp (+239/-0) tests/include/mir_test_doubles/mock_scene_session.h (+2/-0) tests/include/mir_test_doubles/mock_surface.h (+1/-0) tests/include/mir_test_doubles/stub_scene_session.h (+4/-0) tests/unit-tests/scene/test_application_session.cpp (+47/-0) |
To merge this branch: | bzr merge lp:~kdub/mir/multiple-bufferstream-api |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alberto Aguirre (community) | Approve | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Alexandros Frantzis (community) | Approve | ||
Review via email: mp+261123@code.launchpad.net |
Commit message
Add the client api to associate multiple streams together. Connect bits throughout the system to get the acceptance test for this feature to pass.
Description of the change
Add the client api to associate multiple streams together. Connect bits throughout the system to get the acceptance test for this feature to pass.
notes:
The acceptance test here is about the same as the one from the forerunner mp:
https:/
The only difference is that it only adds one spec-modifying function though... the other client api functions there don't seem useful.
This is the multibufferstream with-async-streams plumbed all the way through. It gets the other bufferstreams onscreen. Currently working on renovating scroll.cpp to have a demo.
PS Jenkins bot (ps-jenkins) wrote : | # |
Alexandros Frantzis (afrantzis) wrote : | # |
10+ MirBufferStream * stream;
'*' with type
26+/** Set the streams associated with the spec.
27+ * streams[0] is the bottom-most stream, and streams[size-1] is the topmost.
Space before this line.
28+ * On application of the spec, A stream that is present in the surface,
Space before this line (different topic started).
'a stream'
30+ * On application of the spec, A stream that is not present in the surface,
31+ * but is in the list will be associated with the surface.
'<some other connecting phrase>, a stream that is not present' ...
32+ * Streams set a displacement from the top-left corner of the surface.
Space before this line (change of topic), or perhaps move this information to the documentation of the MirBufferStreamInfo structure?
57+#include <list>
69+ virtual void configure_
Somewhat pre-existing: Is a vector<> not sufficient for this use case? I see that Surface:
91+ for(auto
110+ for(auto
... and elsewhere
'for ('
517+ primary_stream = std::unique_
525+ streams.
make_unique
517+ primary_stream = std::unique_
549+ infos[i++] = MirBufferStream
I doesn't seem that we need to treat the primary stream specially. Treating it as yet another stream simplifies the code.
553+ for(auto &stream
'auto const&'
442+ bool ensure_
444+ {
... return arrangment == displacement;
Or even better, change:
574+ EXPECT_
to EXPECT_
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2461
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Kevin DuBois (kdub) wrote : | # |
Issues should be fixed.
With:
'for(' vs 'for ('
I obviously don't find this to affect readability... maybe will suggest a change to style.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2467
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2467
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alberto Aguirre (albaguirre) wrote : | # |
===
45 + * \param [in] size The size of streams.
49 + unsigned int size);
===
Maybe change size to num_elements?
"The number of elements in the streams array" to avoid confusion?
===
148 +void mir_surface_
===
The implementation should validate its preconditions with mir::require(
===
172 +MIR_CLIENT_9.1 { # New in Mir 0.14
173 + global:
174 + mir_surface_
175 +} MIR_CLIENT_9;
===
No need for a 9.1 stanza as we haven't released anything with MIR_CLIENT_9 yet.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2469
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alberto Aguirre (albaguirre) wrote : | # |
===
45 + * \param [in] size The number of elements in the streams array.
===
doxygen comment still refers to size instead of num_streams.
"[0;32m[ RUN ] [mBufferStream
/tmp/buildd/
Value of: ordering-
Actual: false
Expected: true
timed out waiting for another post"
===
561 + EXPECT_
===
I guess running with Valgrind in CI needs more than 1s.
Looks good otherwise.
Alexandros Frantzis (afrantzis) wrote : | # |
Looks good (besides what others have already mentioned, of course)
Typo:
34+ * On application of the spec, A stream that is not present in the surface,
'a stream'
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2472
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Kevin DuBois (kdub) wrote : | # |
gl2mark error?
Kevin DuBois (kdub) wrote : | # |
I wonder if this is https:/
Kevin DuBois (kdub) wrote : | # |
If you take the 'artifacts' zip and install it on the device (along with the glmark debian package, like the script does), the glmark error is reproducible. It seems that there was some abi-incompatible mixing and matching of (mirclient8, mirclient9) and libmirprotobuf0. Seems appropriate to bump the protobuf versioning so that the right libraries get picked up.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2472
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2473
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2474
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2475
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2475
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Kevin DuBois (kdub) wrote : | # |
side-stepped protobuf problem by not adding new field. The SurfaceParameter changes broke it, but the test in this MP only needed already existing protobuf fields.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2479
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alberto Aguirre (albaguirre) : | # |
Preview Diff
1 | === modified file 'include/client/mir_toolkit/client_types.h' |
2 | --- include/client/mir_toolkit/client_types.h 2015-05-29 04:23:56 +0000 |
3 | +++ include/client/mir_toolkit/client_types.h 2015-06-16 12:28:06 +0000 |
4 | @@ -283,6 +283,16 @@ |
5 | MirDisplayCard *cards; |
6 | } MirDisplayConfiguration; |
7 | |
8 | +/** |
9 | + * The displacement from the top-left corner of the surface. |
10 | + */ |
11 | +typedef struct MirBufferStreamInfo |
12 | +{ |
13 | + MirBufferStream* stream; |
14 | + int displacement_x; |
15 | + int displacement_y; |
16 | +} MirBufferStreamInfo; |
17 | + |
18 | typedef struct MirRectangle |
19 | { |
20 | int left; |
21 | |
22 | === modified file 'include/client/mir_toolkit/mir_surface.h' |
23 | --- include/client/mir_toolkit/mir_surface.h 2015-06-10 09:00:22 +0000 |
24 | +++ include/client/mir_toolkit/mir_surface.h 2015-06-16 12:28:06 +0000 |
25 | @@ -433,6 +433,28 @@ |
26 | void mir_surface_spec_release(MirSurfaceSpec* spec); |
27 | |
28 | /** |
29 | + * Set the streams associated with the spec. |
30 | + * streams[0] is the bottom-most stream, and streams[size-1] is the topmost. |
31 | + * On application of the spec, a stream that is present in the surface, |
32 | + * but is not in the list will be disassociated from the surface. |
33 | + * On application of the spec, a stream that is not present in the surface, |
34 | + * but is in the list will be associated with the surface. |
35 | + * Streams set a displacement from the top-left corner of the surface. |
36 | + * |
37 | + * \warning disassociating streams from the surface will not release() them. |
38 | + * \warning It is wiser to arrange the streams within the bounds of the |
39 | + * surface the spec is applied to. Shells can define their own |
40 | + * behavior as to what happens to an out-of-bound stream. |
41 | + * |
42 | + * \param [in] spec The spec to accumulate the request in. |
43 | + * \param [in] streams The an array of non-null streams info. |
44 | + * \param [in] num_streams The number of elements in the streams array. |
45 | + */ |
46 | +void mir_surface_spec_set_streams(MirSurfaceSpec* spec, |
47 | + MirBufferStreamInfo* streams, |
48 | + unsigned int num_streams); |
49 | + |
50 | +/** |
51 | * Set the event handler to be called when events arrive for a surface. |
52 | * \warning event_handler could be called from another thread. You must do |
53 | * any locking appropriate to protect your data accessed in the |
54 | |
55 | === modified file 'include/server/mir/scene/session.h' |
56 | --- include/server/mir/scene/session.h 2015-05-19 21:34:34 +0000 |
57 | +++ include/server/mir/scene/session.h 2015-06-16 12:28:06 +0000 |
58 | @@ -22,10 +22,12 @@ |
59 | #include "mir/frontend/session.h" |
60 | #include "mir/scene/snapshot.h" |
61 | |
62 | +#include <vector> |
63 | #include <sys/types.h> |
64 | |
65 | namespace mir |
66 | { |
67 | +namespace shell { struct StreamSpecification; } |
68 | namespace scene |
69 | { |
70 | class Surface; |
71 | @@ -60,6 +62,7 @@ |
72 | |
73 | virtual frontend::BufferStreamId create_buffer_stream(graphics::BufferProperties const& props) = 0; |
74 | virtual void destroy_buffer_stream(frontend::BufferStreamId stream) = 0; |
75 | + virtual void configure_streams(Surface& surface, std::vector<shell::StreamSpecification> const& config) = 0; |
76 | }; |
77 | } |
78 | } |
79 | |
80 | === modified file 'src/client/mir_surface.cpp' |
81 | --- src/client/mir_surface.cpp 2015-06-10 11:13:15 +0000 |
82 | +++ src/client/mir_surface.cpp 2015-06-16 12:28:06 +0000 |
83 | @@ -23,6 +23,7 @@ |
84 | #include "cursor_configuration.h" |
85 | #include "client_buffer_stream_factory.h" |
86 | #include "mir_connection.h" |
87 | +#include "client_buffer_stream.h" |
88 | #include "mir/dispatch/threaded_dispatcher.h" |
89 | #include "mir/input/input_platform.h" |
90 | #include "mir/input/xkb_mapper.h" |
91 | @@ -664,6 +665,18 @@ |
92 | aspect->set_height(spec.max_aspect.value().height); |
93 | } |
94 | |
95 | + if (spec.streams.is_set()) |
96 | + { |
97 | + for(auto const& stream : spec.streams.value()) |
98 | + { |
99 | + auto const new_stream = surface_specification->add_stream(); |
100 | + new_stream->set_displacement_x(stream.displacement_x); |
101 | + new_stream->set_displacement_y(stream.displacement_y); |
102 | + new_stream->mutable_id()->set_value( |
103 | + reinterpret_cast<mcl::ClientBufferStream*>(stream.stream)->rpc_id().as_value()); |
104 | + } |
105 | + } |
106 | + |
107 | modify_wait_handle.expect_result(); |
108 | server->modify_surface(0, &mods, &modify_result, |
109 | google::protobuf::NewCallback(this, &MirSurface::on_modified)); |
110 | |
111 | === modified file 'src/client/mir_surface.h' |
112 | --- src/client/mir_surface.h 2015-05-29 04:23:56 +0000 |
113 | +++ src/client/mir_surface.h 2015-06-16 12:28:06 +0000 |
114 | @@ -97,6 +97,7 @@ |
115 | mir::optional_value<int> height_inc; |
116 | mir::optional_value<AspectRatio> min_aspect; |
117 | mir::optional_value<AspectRatio> max_aspect; |
118 | + mir::optional_value<std::vector<MirBufferStreamInfo>> streams; |
119 | }; |
120 | |
121 | struct MirPersistentId |
122 | |
123 | === modified file 'src/client/mir_surface_api.cpp' |
124 | --- src/client/mir_surface_api.cpp 2015-06-10 09:00:22 +0000 |
125 | +++ src/client/mir_surface_api.cpp 2015-06-16 12:28:06 +0000 |
126 | @@ -516,9 +516,29 @@ |
127 | // Keep calm and carry on |
128 | } |
129 | |
130 | +void mir_surface_spec_set_streams(MirSurfaceSpec* spec, MirBufferStreamInfo* streams, unsigned int size) |
131 | +try |
132 | +{ |
133 | + mir::require(spec); |
134 | + |
135 | + std::vector<MirBufferStreamInfo> copy; |
136 | + for (auto i = 0u; i < size; i++) |
137 | + { |
138 | + mir::require(mir_buffer_stream_is_valid(streams[i].stream)); |
139 | + copy.emplace_back(streams[i]); |
140 | + } |
141 | + spec->streams = copy; |
142 | +} |
143 | +catch (std::exception const& ex) |
144 | +{ |
145 | + MIR_LOG_UNCAUGHT_EXCEPTION(ex); |
146 | +} |
147 | + |
148 | + |
149 | void mir_surface_spec_set_parent(MirSurfaceSpec* spec, MirSurface* parent) |
150 | try |
151 | { |
152 | + mir::require(spec); |
153 | spec->parent = parent; |
154 | } |
155 | catch (std::exception const& ex) |
156 | |
157 | === modified file 'src/client/symbols.map' |
158 | --- src/client/symbols.map 2015-06-10 23:37:28 +0000 |
159 | +++ src/client/symbols.map 2015-06-16 12:28:06 +0000 |
160 | @@ -142,6 +142,7 @@ |
161 | mir_surface_spec_set_parent; |
162 | mir_surface_spec_set_pixel_format; |
163 | mir_surface_spec_set_preferred_orientation; |
164 | + mir_surface_spec_set_streams; |
165 | mir_surface_spec_set_type; |
166 | mir_surface_spec_set_width; |
167 | mir_surface_spec_set_width_increment; |
168 | |
169 | === modified file 'src/server/frontend/session_mediator.cpp' |
170 | --- src/server/frontend/session_mediator.cpp 2015-06-09 07:20:56 +0000 |
171 | +++ src/server/frontend/session_mediator.cpp 2015-06-16 12:28:06 +0000 |
172 | @@ -451,15 +451,18 @@ |
173 | // max_aspect is a special case (below) |
174 | |
175 | #undef COPY_IF_SET |
176 | - std::vector<msh::StreamSpecification> stream_spec; |
177 | - for(auto& stream : surface_specification.stream()) |
178 | + if (surface_specification.stream_size() > 0) |
179 | { |
180 | - stream_spec.emplace_back( |
181 | - msh::StreamSpecification{ |
182 | - mf::BufferStreamId{stream.id().value()}, |
183 | - geom::Displacement{stream.displacement_x(), stream.displacement_y()}}); |
184 | + std::vector<msh::StreamSpecification> stream_spec; |
185 | + for (auto& stream : surface_specification.stream()) |
186 | + { |
187 | + stream_spec.emplace_back( |
188 | + msh::StreamSpecification{ |
189 | + mf::BufferStreamId{stream.id().value()}, |
190 | + geom::Displacement{stream.displacement_x(), stream.displacement_y()}}); |
191 | + } |
192 | + mods.streams = std::move(stream_spec); |
193 | } |
194 | - mods.streams = std::move(stream_spec); |
195 | |
196 | if (surface_specification.has_aux_rect()) |
197 | { |
198 | |
199 | === modified file 'src/server/scene/application_session.cpp' |
200 | --- src/server/scene/application_session.cpp 2015-06-02 13:41:40 +0000 |
201 | +++ src/server/scene/application_session.cpp 2015-06-16 12:28:06 +0000 |
202 | @@ -322,3 +322,12 @@ |
203 | std::unique_lock<std::mutex> lock(surfaces_and_streams_mutex); |
204 | streams.erase(checked_find(id)); |
205 | } |
206 | + |
207 | +void ms::ApplicationSession::configure_streams( |
208 | + ms::Surface& surface, std::vector<shell::StreamSpecification> const& streams) |
209 | +{ |
210 | + std::list<ms::StreamInfo> list; |
211 | + for (auto& stream : streams) |
212 | + list.emplace_back(ms::StreamInfo{checked_find(stream.stream_id)->second, stream.displacement}); |
213 | + surface.set_streams(list); |
214 | +} |
215 | |
216 | === modified file 'src/server/scene/application_session.h' |
217 | --- src/server/scene/application_session.h 2015-05-19 21:34:34 +0000 |
218 | +++ src/server/scene/application_session.h 2015-06-16 12:28:06 +0000 |
219 | @@ -85,6 +85,7 @@ |
220 | std::shared_ptr<frontend::BufferStream> get_buffer_stream(frontend::BufferStreamId stream) const override; |
221 | frontend::BufferStreamId create_buffer_stream(graphics::BufferProperties const& params) override; |
222 | void destroy_buffer_stream(frontend::BufferStreamId stream) override; |
223 | + void configure_streams(Surface& surface, std::vector<shell::StreamSpecification> const& config) override; |
224 | |
225 | protected: |
226 | ApplicationSession(ApplicationSession const&) = delete; |
227 | |
228 | === modified file 'src/server/scene/basic_surface.cpp' |
229 | --- src/server/scene/basic_surface.cpp 2015-06-08 17:22:32 +0000 |
230 | +++ src/server/scene/basic_surface.cpp 2015-06-16 12:28:06 +0000 |
231 | @@ -844,15 +844,18 @@ |
232 | |
233 | void ms::BasicSurface::set_streams(std::list<scene::StreamInfo> const& s) |
234 | { |
235 | - std::unique_lock<std::mutex> lk(guard); |
236 | - |
237 | - if (s.end() == std::find_if(s.begin(), s.end(), |
238 | - [this] (ms::StreamInfo const& info) { return info.stream == surface_buffer_stream; })) |
239 | { |
240 | - BOOST_THROW_EXCEPTION(std::logic_error("cannot remove the created-with buffer stream yet")); |
241 | + std::unique_lock<std::mutex> lk(guard); |
242 | + |
243 | + if (s.end() == std::find_if(s.begin(), s.end(), |
244 | + [this] (ms::StreamInfo const& info) { return info.stream == surface_buffer_stream; })) |
245 | + { |
246 | + BOOST_THROW_EXCEPTION(std::logic_error("cannot remove the created-with buffer stream yet")); |
247 | + } |
248 | + |
249 | + layers = s; |
250 | } |
251 | - |
252 | - layers = s; |
253 | + observers.moved_to(surface_rect.top_left); |
254 | } |
255 | |
256 | mg::RenderableList ms::BasicSurface::generate_renderables(mc::CompositorID id) const |
257 | |
258 | === modified file 'src/server/shell/canonical_window_manager.cpp' |
259 | --- src/server/shell/canonical_window_manager.cpp 2015-06-11 09:41:30 +0000 |
260 | +++ src/server/shell/canonical_window_manager.cpp 2015-06-16 12:28:06 +0000 |
261 | @@ -274,7 +274,7 @@ |
262 | } |
263 | |
264 | void msh::CanonicalWindowManagerPolicy::handle_modify_surface( |
265 | - std::shared_ptr<scene::Session> const& /*session*/, |
266 | + std::shared_ptr<scene::Session> const& session, |
267 | std::shared_ptr<scene::Surface> const& surface, |
268 | SurfaceSpecification const& modifications) |
269 | { |
270 | @@ -369,6 +369,13 @@ |
271 | if (modifications.name.is_set()) |
272 | surface->rename(modifications.name.value()); |
273 | |
274 | + if (modifications.streams.is_set()) |
275 | + { |
276 | + auto v = modifications.streams.value(); |
277 | + std::vector<shell::StreamSpecification> l (v.begin(), v.end()); |
278 | + session->configure_streams(*surface, l); |
279 | + } |
280 | + |
281 | if (modifications.width.is_set() || modifications.height.is_set()) |
282 | { |
283 | auto new_size = surface->size(); |
284 | |
285 | === modified file 'tests/acceptance-tests/CMakeLists.txt' |
286 | --- tests/acceptance-tests/CMakeLists.txt 2015-06-11 09:41:30 +0000 |
287 | +++ tests/acceptance-tests/CMakeLists.txt 2015-06-16 12:28:06 +0000 |
288 | @@ -32,6 +32,7 @@ |
289 | test_prompt_session_client_api.cpp |
290 | test_client_screencast.cpp |
291 | test_client_surface_visibility.cpp |
292 | + test_buffer_stream_arrangement.cpp |
293 | test_client_with_custom_display_config_deadlock.cpp |
294 | test_server_without_active_outputs.cpp |
295 | test_server_startup.cpp |
296 | |
297 | === added file 'tests/acceptance-tests/test_buffer_stream_arrangement.cpp' |
298 | --- tests/acceptance-tests/test_buffer_stream_arrangement.cpp 1970-01-01 00:00:00 +0000 |
299 | +++ tests/acceptance-tests/test_buffer_stream_arrangement.cpp 2015-06-16 12:28:06 +0000 |
300 | @@ -0,0 +1,239 @@ |
301 | +/* |
302 | + * Copyright © 2015 Canonical Ltd. |
303 | + * |
304 | + * This program is free software: you can redistribute it and/or modify it |
305 | + * under the terms of the GNU General Public License version 3, |
306 | + * as published by the Free Software Foundation. |
307 | + * |
308 | + * This program is distributed in the hope that it will be useful, |
309 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
310 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
311 | + * GNU General Public License for more details. |
312 | + * |
313 | + * You should have received a copy of the GNU General Public License |
314 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
315 | + * |
316 | + * Authored by: Kevin DuBois <kevin.dubois@canonical.com> |
317 | + */ |
318 | + |
319 | +#include "mir_toolkit/mir_client_library.h" |
320 | +#include "mir_test_framework/connected_client_with_a_surface.h" |
321 | +#include "mir/compositor/display_buffer_compositor.h" |
322 | +#include "mir/compositor/display_buffer_compositor_factory.h" |
323 | +#include "mir/compositor/scene_element.h" |
324 | +#include "mir/graphics/renderable.h" |
325 | +#include "mir/graphics/cursor.h" |
326 | +#include "mir/geometry/displacement.h" |
327 | + |
328 | +#include <mutex> |
329 | +#include <condition_variable> |
330 | +#include <stdexcept> |
331 | +#include <gtest/gtest.h> |
332 | +#include <gmock/gmock.h> |
333 | + |
334 | +namespace mtf = mir_test_framework; |
335 | +namespace geom = mir::geometry; |
336 | +namespace mc = mir::compositor; |
337 | +namespace mg = mir::graphics; |
338 | +namespace |
339 | +{ |
340 | + |
341 | +MirPixelFormat an_available_format(MirConnection* connection) |
342 | +{ |
343 | + using namespace testing; |
344 | + MirPixelFormat format{mir_pixel_format_invalid}; |
345 | + unsigned int valid_formats{0}; |
346 | + mir_connection_get_available_surface_formats(connection, &format, 1, &valid_formats); |
347 | + return format; |
348 | +} |
349 | + |
350 | +struct Stream |
351 | +{ |
352 | + Stream(MirBufferStream* stream, geom::Point pt) : |
353 | + stream(stream), |
354 | + pos{pt}, |
355 | + needs_release{false} |
356 | + { |
357 | + mir_buffer_stream_swap_buffers_sync(stream); |
358 | + } |
359 | + |
360 | + Stream(MirConnection* connection, geom::Rectangle rect) : |
361 | + stream(mir_connection_create_buffer_stream_sync( |
362 | + connection, |
363 | + rect.size.width.as_int(), |
364 | + rect.size.height.as_int(), |
365 | + an_available_format(connection), |
366 | + mir_buffer_usage_hardware)), |
367 | + pos{rect.top_left}, |
368 | + needs_release{true} |
369 | + { |
370 | + mir_buffer_stream_swap_buffers_sync(stream); |
371 | + } |
372 | + |
373 | + ~Stream() |
374 | + { |
375 | + if (needs_release) |
376 | + mir_buffer_stream_release_sync(stream); |
377 | + } |
378 | + |
379 | + MirBufferStream* handle() const |
380 | + { |
381 | + return stream; |
382 | + } |
383 | + |
384 | + geom::Point position() |
385 | + { |
386 | + return pos; |
387 | + } |
388 | + |
389 | + Stream(Stream const&) = delete; |
390 | + Stream& operator=(Stream const&) = delete; |
391 | +private: |
392 | + MirBufferStream* stream; |
393 | + geom::Point const pos; |
394 | + bool const needs_release; |
395 | +}; |
396 | + |
397 | +struct Ordering |
398 | +{ |
399 | + void note_scene_element_sequence(mc::SceneElementSequence& sequence) |
400 | + { |
401 | + if (sequence.empty()) |
402 | + return; |
403 | + |
404 | + std::unique_lock<decltype(mutex)> lk(mutex); |
405 | + displacements.clear(); |
406 | + |
407 | + auto first_position = (*sequence.begin())->renderable()->screen_position().top_left; |
408 | + for (auto const& element : sequence) |
409 | + displacements.emplace_back(element->renderable()->screen_position().top_left - first_position); |
410 | + post_count++; |
411 | + |
412 | + cv.notify_all(); |
413 | + } |
414 | + |
415 | + template<typename T, typename S> |
416 | + bool wait_for_another_post_within(std::chrono::duration<T,S> duration) |
417 | + { |
418 | + std::unique_lock<decltype(mutex)> lk(mutex); |
419 | + auto count = post_count + 1; |
420 | + return cv.wait_for(lk, duration, [this, count]{return (post_count >= count);}); |
421 | + } |
422 | + |
423 | + std::vector<geom::Displacement> last_ordering() |
424 | + { |
425 | + return displacements; |
426 | + } |
427 | +private: |
428 | + std::mutex mutex; |
429 | + std::condition_variable cv; |
430 | + unsigned int post_count{0}; |
431 | + std::vector<geom::Displacement> displacements; |
432 | +}; |
433 | + |
434 | +struct OrderTrackingDBC : mc::DisplayBufferCompositor |
435 | +{ |
436 | + OrderTrackingDBC( |
437 | + std::shared_ptr<mc::DisplayBufferCompositor> const& wrapped, |
438 | + std::shared_ptr<Ordering> const& ordering) : |
439 | + wrapped(wrapped), |
440 | + ordering(ordering) |
441 | + { |
442 | + } |
443 | + |
444 | + void composite(mc::SceneElementSequence&& scene_sequence) override |
445 | + { |
446 | + ordering->note_scene_element_sequence(scene_sequence); |
447 | + wrapped->composite(std::move(scene_sequence)); |
448 | + } |
449 | + |
450 | + std::shared_ptr<mc::DisplayBufferCompositor> const wrapped; |
451 | + std::shared_ptr<Ordering> const ordering; |
452 | +}; |
453 | + |
454 | +struct OrderTrackingDBCFactory : mc::DisplayBufferCompositorFactory |
455 | +{ |
456 | + OrderTrackingDBCFactory( |
457 | + std::shared_ptr<mc::DisplayBufferCompositorFactory> const& wrapped, |
458 | + std::shared_ptr<Ordering> const& ordering) : |
459 | + wrapped(wrapped), |
460 | + ordering(ordering) |
461 | + { |
462 | + } |
463 | + |
464 | + std::unique_ptr<mc::DisplayBufferCompositor> create_compositor_for(mg::DisplayBuffer& db) override |
465 | + { |
466 | + return std::make_unique<OrderTrackingDBC>(wrapped->create_compositor_for(db), ordering); |
467 | + } |
468 | + |
469 | + std::shared_ptr<OrderTrackingDBC> last_dbc{nullptr}; |
470 | + std::shared_ptr<mc::DisplayBufferCompositorFactory> const wrapped; |
471 | + std::shared_ptr<Ordering> const ordering; |
472 | +}; |
473 | + |
474 | +struct BufferStreamArrangement : mtf::ConnectedClientWithASurface |
475 | +{ |
476 | + void SetUp() override |
477 | + { |
478 | + ordering = std::make_shared<Ordering>(); |
479 | + server.wrap_display_buffer_compositor_factory( |
480 | + [this](std::shared_ptr<mc::DisplayBufferCompositorFactory> const& wrapped) |
481 | + { |
482 | + order_tracker = std::make_shared<OrderTrackingDBCFactory>(wrapped, ordering); |
483 | + return order_tracker; |
484 | + }); |
485 | + |
486 | + ConnectedClientWithASurface::SetUp(); |
487 | + server.the_cursor()->hide(); |
488 | + |
489 | + streams.emplace_back( |
490 | + std::make_unique<Stream>(mir_surface_get_buffer_stream(surface), geom::Point{0,0})); |
491 | + int const additional_streams{3}; |
492 | + for (auto i = 0; i < additional_streams; i++) |
493 | + { |
494 | + geom::Size size{30 * i + 1, 40* i + 1}; |
495 | + geom::Point position{i * 2, i * 3}; |
496 | + streams.emplace_back(std::make_unique<Stream>(connection, geom::Rectangle{position, size})); |
497 | + } |
498 | + } |
499 | + |
500 | + void TearDown() override |
501 | + { |
502 | + streams.clear(); |
503 | + ConnectedClientWithASurface::TearDown(); |
504 | + } |
505 | + |
506 | + std::shared_ptr<Ordering> ordering; |
507 | + std::shared_ptr<OrderTrackingDBCFactory> order_tracker{nullptr}; |
508 | + std::vector<std::unique_ptr<Stream>> streams; |
509 | +}; |
510 | +} |
511 | + |
512 | +TEST_F(BufferStreamArrangement, arrangements_are_applied) |
513 | +{ |
514 | + using namespace testing; |
515 | + std::vector<MirBufferStreamInfo> infos(streams.size()); |
516 | + auto i = 0u; |
517 | + for (auto const& stream : streams) |
518 | + { |
519 | + infos[i++] = MirBufferStreamInfo{ |
520 | + stream->handle(), |
521 | + stream->position().x.as_int(), |
522 | + stream->position().y.as_int()}; |
523 | + } |
524 | + |
525 | + auto change_spec = mir_connection_create_spec_for_changes(connection); |
526 | + mir_surface_spec_set_streams(change_spec, infos.data(), infos.size()); |
527 | + mir_surface_apply_spec(surface, change_spec); |
528 | + mir_surface_spec_release(change_spec); |
529 | + |
530 | + std::vector<geom::Displacement> displacements; |
531 | + for (auto& info : infos) |
532 | + displacements.emplace_back(geom::Displacement{info.displacement_x, info.displacement_y}); |
533 | + |
534 | + //check that the compositor rendered correctly |
535 | + using namespace std::literals::chrono_literals; |
536 | + EXPECT_TRUE(ordering->wait_for_another_post_within(5s)) |
537 | + << "timed out waiting for another post"; |
538 | + EXPECT_THAT(ordering->last_ordering(), ContainerEq(displacements)); |
539 | +} |
540 | |
541 | === modified file 'tests/include/mir_test_doubles/mock_scene_session.h' |
542 | --- tests/include/mir_test_doubles/mock_scene_session.h 2015-05-19 21:34:34 +0000 |
543 | +++ tests/include/mir_test_doubles/mock_scene_session.h 2015-06-16 12:28:06 +0000 |
544 | @@ -20,6 +20,7 @@ |
545 | #define MIR_TEST_DOUBLES_MOCK_SCENE_SESSION_H_ |
546 | |
547 | #include "mir/scene/session.h" |
548 | +#include "mir/scene/surface.h" |
549 | #include "mir/scene/surface_creation_parameters.h" |
550 | #include "mir/graphics/display_configuration.h" |
551 | |
552 | @@ -64,6 +65,7 @@ |
553 | MOCK_METHOD1(destroy_buffer_stream, void(frontend::BufferStreamId)); |
554 | MOCK_METHOD1(create_buffer_stream, frontend::BufferStreamId(graphics::BufferProperties const&)); |
555 | |
556 | + MOCK_METHOD2(configure_streams, void(scene::Surface&, std::vector<shell::StreamSpecification> const&)); |
557 | }; |
558 | |
559 | } |
560 | |
561 | === modified file 'tests/include/mir_test_doubles/mock_surface.h' |
562 | --- tests/include/mir_test_doubles/mock_surface.h 2015-06-08 17:28:38 +0000 |
563 | +++ tests/include/mir_test_doubles/mock_surface.h 2015-06-16 12:28:06 +0000 |
564 | @@ -74,6 +74,7 @@ |
565 | MOCK_METHOD1(consume, void(MirEvent const&)); |
566 | |
567 | MOCK_CONST_METHOD0(primary_buffer_stream, std::shared_ptr<frontend::BufferStream>()); |
568 | + MOCK_METHOD1(set_streams, void(std::list<scene::StreamInfo> const&)); |
569 | |
570 | }; |
571 | |
572 | |
573 | === modified file 'tests/include/mir_test_doubles/stub_scene_session.h' |
574 | --- tests/include/mir_test_doubles/stub_scene_session.h 2015-05-19 21:34:34 +0000 |
575 | +++ tests/include/mir_test_doubles/stub_scene_session.h 2015-06-16 12:28:06 +0000 |
576 | @@ -117,6 +117,10 @@ |
577 | return frontend::BufferStreamId(); |
578 | } |
579 | |
580 | + void configure_streams(scene::Surface&, std::vector<shell::StreamSpecification> const&) |
581 | + { |
582 | + } |
583 | + |
584 | pid_t const pid; |
585 | }; |
586 | |
587 | |
588 | === modified file 'tests/unit-tests/scene/test_application_session.cpp' |
589 | --- tests/unit-tests/scene/test_application_session.cpp 2015-05-29 17:36:46 +0000 |
590 | +++ tests/unit-tests/scene/test_application_session.cpp 2015-06-16 12:28:06 +0000 |
591 | @@ -515,6 +515,53 @@ |
592 | session->destroy_surface(id); |
593 | } |
594 | |
595 | +MATCHER(StreamEq, "") |
596 | +{ |
597 | + return (std::get<0>(arg).stream == std::get<1>(arg).stream) && |
598 | + (std::get<0>(arg).displacement == std::get<1>(arg).displacement); |
599 | +} |
600 | + |
601 | +TEST_F(ApplicationSession, sets_and_looks_up_surface_streams) |
602 | +{ |
603 | + using namespace testing; |
604 | + NiceMock<MockBufferStreamFactory> mock_bufferstream_factory; |
605 | + NiceMock<MockSurfaceFactory> mock_surface_factory; |
606 | + |
607 | + auto mock_surface = make_mock_surface(); |
608 | + EXPECT_CALL(mock_surface_factory, create_surface(_,_)) |
609 | + .WillOnce(Return(mock_surface)); |
610 | + |
611 | + std::array<std::shared_ptr<mc::BufferStream>,3> streams {{ |
612 | + std::make_shared<mtd::StubBufferStream>(), |
613 | + std::make_shared<mtd::StubBufferStream>(), |
614 | + std::make_shared<mtd::StubBufferStream>() |
615 | + }}; |
616 | + EXPECT_CALL(mock_bufferstream_factory, create_buffer_stream(_)) |
617 | + .WillOnce(Return(streams[0])) |
618 | + .WillOnce(Return(streams[1])) |
619 | + .WillOnce(Return(streams[2])); |
620 | + |
621 | + auto stream_properties = mg::BufferProperties{{8,8}, mir_pixel_format_argb_8888, mg::BufferUsage::hardware}; |
622 | + auto session = make_application_session( |
623 | + mt::fake_shared(mock_bufferstream_factory), |
624 | + mt::fake_shared(mock_surface_factory)); |
625 | + auto stream_id0 = mf::BufferStreamId(session->create_surface(ms::a_surface().of_position({1,1})).as_value()); |
626 | + auto stream_id1 = session->create_buffer_stream(stream_properties); |
627 | + auto stream_id2 = session->create_buffer_stream(stream_properties); |
628 | + |
629 | + std::list<ms::StreamInfo> info { |
630 | + {streams[2], geom::Displacement{0,3}}, |
631 | + {streams[0], geom::Displacement{-1,1}}, |
632 | + {streams[1], geom::Displacement{0,2}} |
633 | + }; |
634 | + EXPECT_CALL(*mock_surface, set_streams(Pointwise(StreamEq(), info))); |
635 | + session->configure_streams(*mock_surface, { |
636 | + {stream_id2, geom::Displacement{0,3}}, |
637 | + {stream_id0, geom::Displacement{-1,1}}, |
638 | + {stream_id1, geom::Displacement{0,2}} |
639 | + }); |
640 | +} |
641 | + |
642 | TEST_F(ApplicationSession, buffer_stream_constructed_with_requested_parameters) |
643 | { |
644 | using namespace ::testing; |
FAILED: Continuous integration, rev:2459 jenkins. qa.ubuntu. com/job/ mir-ci/ 4016/ jenkins. qa.ubuntu. com/job/ mir-android- vivid-i386- build/2723 jenkins. qa.ubuntu. com/job/ mir-clang- wily-amd64- build/236/ console jenkins. qa.ubuntu. com/job/ mir-mediumtests -vivid- touch/2671/ console jenkins. qa.ubuntu. com/job/ mir-wily- amd64-ci/ 172 jenkins. qa.ubuntu. com/job/ mir-wily- amd64-ci/ 172/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ mir-mediumtests -builder- vivid-armhf/ 2671 jenkins. qa.ubuntu. com/job/ mir-mediumtests -builder- vivid-armhf/ 2671/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ mir-mediumtests -runner- mako/5515/ console s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 20976
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/mir- ci/4016/ rebuild
http://