Merge lp:~raof/mir/nested-preserve-display-buffer into lp:mir
- nested-preserve-display-buffer
- Merge into development-branch
Status: | Merged |
---|---|
Approved by: | Alan Griffiths |
Approved revision: | no longer in the source branch. |
Merged at revision: | 3844 |
Proposed branch: | lp:~raof/mir/nested-preserve-display-buffer |
Merge into: | lp:mir |
Diff against target: |
453 lines (+272/-72) 4 files modified
src/server/graphics/nested/display.cpp (+127/-67) src/server/graphics/nested/display.h (+1/-1) tests/acceptance-tests/test_nested_mir.cpp (+12/-4) tests/unit-tests/platforms/nested/test_nested_display.cpp (+132/-0) |
To merge this branch: | bzr merge lp:~raof/mir/nested-preserve-display-buffer |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alan Griffiths | Approve | ||
Andreas Pokorny (community) | Approve | ||
Mir CI Bot | continuous-integration | Approve | |
Review via email: mp+310395@code.launchpad.net |
Commit message
Implement Display:
Final¹ part of the fix for bug #1556142.
¹: For now - mesa-x11 support is missing, as is eglstream support. X11 is purely for the ease of testing, and eglstream isn't ready for primetime.
Description of the change
Mir CI Bot (mir-ci-bot) wrote : | # |
Chris Halse Rogers (raof) wrote : | # |
Hm, I've got a guess as to what's wrong here; I just need to work out how to test it...
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:3814
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:3814
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Chris Halse Rogers (raof) wrote : | # |
07:28:38 9: [ FAILED ] TestClientInput
REALTIME!
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:3814
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:3815
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Alan Griffiths (alan-griffiths) wrote : | # |
+ /* We need to attach a painted client before attempting to set the display mode,
+ * otherwise the nested server will not have rendered anything, so won't be focused,
+ * so the host server won't apply any set configuration
+ */
I don't see why we need to attach a painted client *before* attempting to set the display mode. AIUI the session display configuration gets set with or without focus - and will be (re)applied whenever the session (re)gains focus.
I.e. does this change in the test work around bug in this branch? Or am I missing something?
Chris Halse Rogers (raof) wrote : | # |
This works around a (deliberate) change in behaviour in this branch.
Previously, the nearby call to
nested_
would stop and resume the compositor around the display-
The goal of this branch is to eliminate the stop()/start() cycle. This means the nested server doesn't (unnecessarily) post an empty buffer on set_base_
So, the thing that you're missing is that while the session display configuration *will* get set without focus, the test is waiting for the display configuration to be applied, which only happens with focus.
Alan Griffiths (alan-griffiths) wrote : | # |
OK, thanks.
Preview Diff
1 | === modified file 'src/server/graphics/nested/display.cpp' |
2 | --- src/server/graphics/nested/display.cpp 2016-11-11 07:56:09 +0000 |
3 | +++ src/server/graphics/nested/display.cpp 2016-11-17 00:14:50 +0000 |
4 | @@ -36,6 +36,7 @@ |
5 | |
6 | #include <boost/throw_exception.hpp> |
7 | #include <stdexcept> |
8 | +#include <algorithm> |
9 | |
10 | namespace mg = mir::graphics; |
11 | namespace mgn = mir::graphics::nested; |
12 | @@ -175,6 +176,44 @@ |
13 | return output->view_area(); |
14 | } |
15 | |
16 | +namespace |
17 | +{ |
18 | +long area_of(geom::Rectangle const& rect) |
19 | +{ |
20 | + return static_cast<long>(rect.size.width.as_int())*rect.size.height.as_int(); |
21 | +} |
22 | + |
23 | +std::vector<mg::DisplayConfigurationOutput> calculate_best_outputs( |
24 | + mg::DisplayConfiguration const& conf) |
25 | +{ |
26 | + std::vector<mg::DisplayConfigurationOutput> result; |
27 | + |
28 | + mg::OverlappingOutputGrouping unique_outputs{conf}; |
29 | + |
30 | + unique_outputs.for_each_group( |
31 | + [&](mg::OverlappingOutputGroup const& group) |
32 | + { |
33 | + geom::Rectangle const area = group.bounding_rectangle(); |
34 | + |
35 | + long max_overlap_area = 0; |
36 | + mg::DisplayConfigurationOutput best_output; |
37 | + |
38 | + group.for_each_output( |
39 | + [&](mg::DisplayConfigurationOutput const& output) |
40 | + { |
41 | + if (area_of(area.intersection_with(output.extents())) > max_overlap_area) |
42 | + { |
43 | + max_overlap_area = area_of(area.intersection_with(output.extents())); |
44 | + best_output = output; |
45 | + } |
46 | + }); |
47 | + result.push_back(best_output); |
48 | + }); |
49 | + |
50 | + return result; |
51 | +} |
52 | +} |
53 | + |
54 | mgn::Display::Display( |
55 | std::shared_ptr<mg::Platform> const& platform, |
56 | std::shared_ptr<HostConnection> const& connection, |
57 | @@ -200,7 +239,7 @@ |
58 | swap(current_configuration, conf); |
59 | } |
60 | |
61 | - create_surfaces(*current_configuration); |
62 | + create_surfaces(calculate_best_outputs(*current_configuration)); |
63 | } |
64 | |
65 | mgn::Display::~Display() noexcept |
66 | @@ -233,82 +272,57 @@ |
67 | |
68 | void mgn::Display::configure(mg::DisplayConfiguration const& configuration) |
69 | { |
70 | + if (!configuration.valid()) |
71 | + { |
72 | + BOOST_THROW_EXCEPTION(std::logic_error("Invalid or inconsistent display configuration")); |
73 | + } |
74 | + |
75 | decltype(current_configuration) new_config{dynamic_cast<NestedDisplayConfiguration*>(configuration.clone().release())}; |
76 | |
77 | { |
78 | std::lock_guard<std::mutex> lock(configuration_mutex); |
79 | |
80 | swap(current_configuration, new_config); |
81 | - create_surfaces(*current_configuration); |
82 | + create_surfaces(calculate_best_outputs(*current_configuration)); |
83 | } |
84 | |
85 | connection->apply_display_config(**current_configuration); |
86 | } |
87 | |
88 | -namespace |
89 | -{ |
90 | -long area_of(geom::Rectangle const& rect) |
91 | -{ |
92 | - return static_cast<long>(rect.size.width.as_int())*rect.size.height.as_int(); |
93 | -} |
94 | -} |
95 | - |
96 | -void mgn::Display::create_surfaces(mg::DisplayConfiguration const& configuration) |
97 | -{ |
98 | - if (!configuration.valid()) |
99 | - { |
100 | - BOOST_THROW_EXCEPTION(std::logic_error("Invalid or inconsistent display configuration")); |
101 | - } |
102 | - |
103 | +void mgn::Display::create_surfaces(std::vector<mg::DisplayConfigurationOutput> const& output_list) |
104 | +{ |
105 | decltype(outputs) result; |
106 | - OverlappingOutputGrouping unique_outputs{configuration}; |
107 | - |
108 | - unique_outputs.for_each_group( |
109 | - [&](mg::OverlappingOutputGroup const& group) |
110 | - { |
111 | - geometry::Rectangle const area = group.bounding_rectangle(); |
112 | - |
113 | - long max_overlap_area = 0; |
114 | - mg::DisplayConfigurationOutput best_output; |
115 | - |
116 | - group.for_each_output([&](mg::DisplayConfigurationOutput const& output) |
117 | - { |
118 | - if (area_of(area.intersection_with(output.extents())) > max_overlap_area) |
119 | - { |
120 | - max_overlap_area = area_of(area.intersection_with(output.extents())); |
121 | - best_output = output; |
122 | - } |
123 | - }); |
124 | - |
125 | - auto const& egl_config_format = best_output.current_format; |
126 | - geometry::Rectangle const& extents = best_output.extents(); |
127 | - |
128 | - auto& display_buffer = result[best_output.id]; |
129 | - |
130 | - { |
131 | - std::unique_lock<std::mutex> lock(outputs_mutex); |
132 | - display_buffer = outputs[best_output.id]; |
133 | - } |
134 | - |
135 | - if (display_buffer) |
136 | - { |
137 | - if (display_buffer->view_area() != extents) |
138 | - display_buffer.reset(); |
139 | - } |
140 | - |
141 | - if (!display_buffer) |
142 | - { |
143 | - complete_display_initialization(egl_config_format); |
144 | - |
145 | - eglBindAPI(MIR_SERVER_EGL_OPENGL_API); |
146 | - display_buffer = std::make_shared<mgn::detail::DisplaySyncGroup>( |
147 | - std::make_shared<mgn::detail::DisplayBuffer>( |
148 | - egl_display, |
149 | - best_output, |
150 | - connection, |
151 | - passthrough_option)); |
152 | - } |
153 | - }); |
154 | + for (auto const& output : output_list) |
155 | + { |
156 | + auto const& egl_config_format = output.current_format; |
157 | + geometry::Rectangle const& extents = output.extents(); |
158 | + |
159 | + auto& display_buffer = result[output.id]; |
160 | + |
161 | + { |
162 | + std::unique_lock<std::mutex> lock(outputs_mutex); |
163 | + display_buffer = outputs[output.id]; |
164 | + } |
165 | + |
166 | + if (display_buffer) |
167 | + { |
168 | + if (display_buffer->view_area() != extents) |
169 | + display_buffer.reset(); |
170 | + } |
171 | + |
172 | + if (!display_buffer) |
173 | + { |
174 | + complete_display_initialization(egl_config_format); |
175 | + |
176 | + eglBindAPI(MIR_SERVER_EGL_OPENGL_API); |
177 | + display_buffer = std::make_shared<mgn::detail::DisplaySyncGroup>( |
178 | + std::make_shared<mgn::detail::DisplayBuffer>( |
179 | + egl_display, |
180 | + output, |
181 | + connection, |
182 | + passthrough_option)); |
183 | + } |
184 | + } |
185 | |
186 | { |
187 | std::unique_lock<std::mutex> lock(outputs_mutex); |
188 | @@ -371,9 +385,55 @@ |
189 | } |
190 | |
191 | bool mgn::Display::apply_if_configuration_preserves_display_buffers( |
192 | - mg::DisplayConfiguration const& /*conf*/) |
193 | + mg::DisplayConfiguration const& conf) |
194 | { |
195 | - return false; |
196 | + auto new_outputs = calculate_best_outputs(conf); |
197 | + { |
198 | + std::lock_guard<decltype(configuration_mutex)> lock{configuration_mutex}; |
199 | + |
200 | + { |
201 | + std::lock_guard<decltype(outputs_mutex)> outputs_lock{outputs_mutex}; |
202 | + for (auto const existing_output : outputs) |
203 | + { |
204 | + // O(n²) here, but n < 10 and this is isn't a hot path. |
205 | + if (!std::any_of( |
206 | + new_outputs.begin(), |
207 | + new_outputs.end(), |
208 | + [id = existing_output.first](auto const&output) { return output.id == id; })) |
209 | + { |
210 | + // At least one of the existing outputs isn't used in the ne |
211 | + return false; |
212 | + } |
213 | + } |
214 | + |
215 | + for (auto const& output : new_outputs) |
216 | + { |
217 | + auto existing_output = outputs.find(output.id); |
218 | + |
219 | + /* |
220 | + * If there's no existing output associated with this ID then we can't be |
221 | + * invalidating its DisplayBuffer. |
222 | + * |
223 | + * If there *is* an existing output associated with this ID then |
224 | + * create_surfaces() will invalidate its DisplayBuffer if and only if |
225 | + * the viewport doesn't exactly match. |
226 | + */ |
227 | + if (existing_output != outputs.end() && |
228 | + existing_output->second->view_area() != output.extents()) |
229 | + { |
230 | + return false; |
231 | + } |
232 | + } |
233 | + } |
234 | + |
235 | + current_configuration = |
236 | + decltype(current_configuration){dynamic_cast<NestedDisplayConfiguration*>(conf.clone().release())}; |
237 | + |
238 | + create_surfaces(new_outputs); |
239 | + } |
240 | + connection->apply_display_config(**current_configuration); |
241 | + |
242 | + return true; |
243 | } |
244 | |
245 | mg::Frame mgn::Display::last_frame_on(unsigned) const |
246 | |
247 | === modified file 'src/server/graphics/nested/display.h' |
248 | --- src/server/graphics/nested/display.h 2016-11-09 02:30:14 +0000 |
249 | +++ src/server/graphics/nested/display.h 2016-11-17 00:14:50 +0000 |
250 | @@ -167,7 +167,7 @@ |
251 | std::mutex mutable configuration_mutex; |
252 | std::unique_ptr<NestedDisplayConfiguration> current_configuration; |
253 | |
254 | - void create_surfaces(mir::graphics::DisplayConfiguration const& configuration); |
255 | + void create_surfaces(std::vector<graphics::DisplayConfigurationOutput> const& output_list); |
256 | void complete_display_initialization(MirPixelFormat format); |
257 | }; |
258 | |
259 | |
260 | === modified file 'tests/acceptance-tests/test_nested_mir.cpp' |
261 | --- tests/acceptance-tests/test_nested_mir.cpp 2016-11-15 23:48:01 +0000 |
262 | +++ tests/acceptance-tests/test_nested_mir.cpp 2016-11-17 00:14:50 +0000 |
263 | @@ -1270,6 +1270,12 @@ |
264 | NestedMirRunner nested_mir{new_connection()}; |
265 | ignore_rebuild_of_egl_context(); |
266 | |
267 | + /* We need to attach a painted client before attempting to set the display mode, |
268 | + * otherwise the nested server will not have rendered anything, so won't be focused, |
269 | + * so the host server won't apply any set configuration |
270 | + */ |
271 | + ClientWithAPaintedSurface client(nested_mir); |
272 | + |
273 | { |
274 | std::shared_ptr<mg::DisplayConfiguration> const initial_config{nested_mir.server.the_display()->configuration()}; |
275 | initial_config->for_each_output([](mg::UserDisplayConfigurationOutput& output) |
276 | @@ -1288,8 +1294,6 @@ |
277 | ASSERT_TRUE(initial_condition.raised()); |
278 | } |
279 | |
280 | - ClientWithAPaintedSurface client(nested_mir); |
281 | - |
282 | auto const expect_config = hw_display_config_for_unplug(); |
283 | |
284 | mt::Signal condition; |
285 | @@ -1371,6 +1375,12 @@ |
286 | NestedMirRunner nested_mir{new_connection()}; |
287 | ignore_rebuild_of_egl_context(); |
288 | |
289 | + /* We need to attach a painted client before attempting to set the display mode, |
290 | + * otherwise the nested server will not have rendered anything, so won't be focused, |
291 | + * so the host server won't apply any set configuration |
292 | + */ |
293 | + ClientWithAPaintedSurface client(nested_mir); |
294 | + |
295 | { |
296 | std::shared_ptr<mg::DisplayConfiguration> const initial_config{nested_mir.server.the_display()->configuration()}; |
297 | initial_config->for_each_output([](mg::UserDisplayConfigurationOutput& output) |
298 | @@ -1389,8 +1399,6 @@ |
299 | ASSERT_TRUE(initial_condition.raised()); |
300 | } |
301 | |
302 | - ClientWithAPaintedSurface client(nested_mir); |
303 | - |
304 | auto const new_config = hw_display_config_for_plugin(); |
305 | |
306 | // The default layout policy (for cloned displays) will be applied by the MediatingDisplayChanger. |
307 | |
308 | === modified file 'tests/unit-tests/platforms/nested/test_nested_display.cpp' |
309 | --- tests/unit-tests/platforms/nested/test_nested_display.cpp 2016-08-24 14:03:18 +0000 |
310 | +++ tests/unit-tests/platforms/nested/test_nested_display.cpp 2016-11-17 00:14:50 +0000 |
311 | @@ -31,6 +31,7 @@ |
312 | #include "mir/test/doubles/stub_cursor_listener.h" |
313 | #include "mir/test/doubles/null_platform.h" |
314 | #include "mir/test/fake_shared.h" |
315 | +#include "mir/test/display_config_matchers.h" |
316 | |
317 | #include <gtest/gtest.h> |
318 | #include <gmock/gmock.h> |
319 | @@ -244,3 +245,134 @@ |
320 | |
321 | auto dummy_context = nested_display->create_gl_context(); |
322 | } |
323 | + |
324 | +TEST_F(NestedDisplay, preserves_framebuffers_for_metadata_changes) |
325 | +{ |
326 | + using namespace testing; |
327 | + |
328 | + auto display = create_nested_display( |
329 | + null_platform, |
330 | + mt::fake_shared(stub_gl_config)); |
331 | + |
332 | + auto conf = display->configuration(); |
333 | + |
334 | + std::vector<mg::DisplayBuffer*> initial_dbs; |
335 | + |
336 | + display->for_each_display_sync_group( |
337 | + [&initial_dbs](auto& sync_group) |
338 | + { |
339 | + sync_group.for_each_display_buffer( |
340 | + [&initial_dbs](auto& display_buffer) |
341 | + { |
342 | + initial_dbs.push_back(&display_buffer); |
343 | + }); |
344 | + }); |
345 | + |
346 | + ASSERT_THAT(initial_dbs, Not(IsEmpty())); |
347 | + |
348 | + conf->for_each_output( |
349 | + [](mg::UserDisplayConfigurationOutput& output) |
350 | + { |
351 | + output.scale *= 3.1415f; |
352 | + output.form_factor = |
353 | + output.form_factor == mir_form_factor_monitor ? |
354 | + mir_form_factor_phone : |
355 | + mir_form_factor_monitor; |
356 | + output.subpixel_arrangement = |
357 | + output.subpixel_arrangement == mir_subpixel_arrangement_horizontal_bgr ? |
358 | + mir_subpixel_arrangement_vertical_bgr : |
359 | + mir_subpixel_arrangement_horizontal_bgr; |
360 | + output.orientation = |
361 | + output.orientation == mir_orientation_normal ? |
362 | + mir_orientation_inverted : |
363 | + mir_orientation_normal; |
364 | + }); |
365 | + |
366 | + EXPECT_THAT(*conf, Not(mt::DisplayConfigMatches(std::cref(*display->configuration())))); |
367 | + |
368 | + EXPECT_TRUE(display->apply_if_configuration_preserves_display_buffers(* conf)); |
369 | + |
370 | + // Touch each of the saved DisplayBuffers, so valgrind will complain if we've invalidated them |
371 | + for (auto db : initial_dbs) |
372 | + { |
373 | + EXPECT_THAT(db->native_display_buffer(), NotNull()); |
374 | + } |
375 | +} |
376 | + |
377 | +TEST_F(NestedDisplay, changing_output_does_not_preserve_framebuffers) |
378 | +{ |
379 | + using namespace testing; |
380 | + |
381 | + class MultiDisplayHostConnection : public mtd::StubHostConnection |
382 | + { |
383 | + public: |
384 | + std::shared_ptr<MirDisplayConfiguration> create_display_config() override |
385 | + { |
386 | + // This builds a 3-monitor configuration... |
387 | + return mt::build_non_trivial_configuration(); |
388 | + } |
389 | + }; |
390 | + |
391 | + |
392 | + auto display = std::make_unique<mgn::Display>( |
393 | + null_platform, |
394 | + std::make_shared<MultiDisplayHostConnection>(), |
395 | + mt::fake_shared(null_display_report), |
396 | + mt::fake_shared(default_conf_policy), |
397 | + mt::fake_shared(stub_gl_config), |
398 | + mgn::PassthroughOption::disabled); |
399 | + |
400 | + auto conf = display->configuration(); |
401 | + |
402 | + // Enable the first and second displays, have the third disabled. |
403 | + conf->for_each_output( |
404 | + [counter = 0](mg::UserDisplayConfigurationOutput& output) mutable |
405 | + { |
406 | + switch (counter) |
407 | + { |
408 | + case 0: |
409 | + output.used = true; |
410 | + output.top_left = {0, 0}; |
411 | + break; |
412 | + case 1: |
413 | + output.used = true; |
414 | + output.top_left = {2000, 2000}; |
415 | + break; |
416 | + case 2: |
417 | + output.used = false; |
418 | + break; |
419 | + } |
420 | + ++counter; |
421 | + }); |
422 | + |
423 | + display->configure(*conf); |
424 | + |
425 | + conf = display->configuration(); |
426 | + |
427 | + // Enable the first and third displays, have the second disabled. |
428 | + conf->for_each_output( |
429 | + [counter = 0](mg::UserDisplayConfigurationOutput& output) mutable |
430 | + { |
431 | + switch (counter) |
432 | + { |
433 | + case 0: |
434 | + output.used = true; |
435 | + output.top_left = {0, 0}; |
436 | + break; |
437 | + case 1: |
438 | + output.used = false; |
439 | + break; |
440 | + case 2: |
441 | + output.used = true; |
442 | + output.top_left = {2000, 2000}; |
443 | + break; |
444 | + } |
445 | + ++counter; |
446 | + }); |
447 | + |
448 | + /* |
449 | + * This tests an implementation detail; it should be perfectly possible to preserve |
450 | + * display buffers in this case, but we don't, so we shouldn't pretend to. |
451 | + */ |
452 | + EXPECT_FALSE(display->apply_if_configuration_preserves_display_buffers(*conf)); |
453 | +} |
FAILED: Continuous integration, rev:3813 /mir-jenkins. ubuntu. com/job/ mir-ci/ 2134/ /mir-jenkins. ubuntu. com/job/ build-mir/ 2762/console /mir-jenkins. ubuntu. com/job/ build-0- fetch/2825 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= vivid+overlay/ 2817 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= xenial+ overlay/ 2817 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= yakkety/ 2817 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= yakkety/ 2791/console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= xenial+ overlay/ 2791/console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= yakkety/ 2791/console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= android, release= vivid+overlay/ 2791/console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= android, release= vivid+overlay/ 2791/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= android, release= vivid+overlay/ 2791 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= android, release= vivid+overlay/ 2791/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= mesa,release= xenial+ overlay/ 2791/console
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild: /mir-jenkins. ubuntu. com/job/ mir-ci/ 2134/rebuild
https:/