Mir

Merge lp:~kdub/mir/multiple-bufferstream-api into lp:mir

Proposed by Kevin DuBois
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
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://code.launchpad.net/~kdub/mir/RFC-surface-arrangements/+merge/256186
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.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
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_streams(Surface& surface, std::list<shell::StreamSpecification> const& config) = 0;

Somewhat pre-existing: Is a vector<> not sufficient for this use case? I see that Surface::set_streams() uses a list<> which I don't think offers any advantages over vector<> for our usage patterns and is a probably a pessimization ("use vector<> by default").

91+ for(auto
110+ for(auto
... and elsewhere

'for ('

517+ primary_stream = std::unique_ptr<Stream>(
525+ streams.emplace_back(std::unique_ptr<Stream>(

make_unique

517+ primary_stream = std::unique_ptr<Stream>(
549+ infos[i++] = MirBufferStreamInfo{

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_last_ordering_is_consistent_with(443+ std::vector<geom::Displacement> const& arrangement)
444+ {

... return arrangment == displacement;

Or even better, change:

574+ EXPECT_TRUE(ordering->ensure_last_ordering_is_consistent_with(displacements))

to EXPECT_THAT(ordering->last_arrangement(), ContainerEq(displacements)) to get more detailed information in case of failure.

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
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_spec_set_streams(MirSurfaceSpec* spec, MirBufferStreamInfo* streams, unsigned int size)
===

The implementation should validate its preconditions with mir::require(mir_buffer_stream_is_valid(...)) for all buffer streams.

===
172 +MIR_CLIENT_9.1 { # New in Mir 0.14
173 + global:
174 + mir_surface_spec_set_streams;
175 +} MIR_CLIENT_9;
===

No need for a 9.1 stanza as we haven't released anything with MIR_CLIENT_9 yet.

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
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 ] BufferStreamArrangement.arrangements_are_applied
/tmp/buildd/mir-0.14.0bzr2469pkg0wily2729+autopilot0/tests/acceptance-tests/test_buffer_stream_arrangement.cpp:236: Failure
Value of: ordering->wait_for_another_post_within(1s)
Actual: false
Expected: true
timed out waiting for another post"

===
561 + EXPECT_TRUE(ordering->wait_for_another_post_within(1s))
===
I guess running with Valgrind in CI needs more than 1s.

Looks good otherwise.

review: Needs Fixing
Revision history for this message
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'

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

LGTM.

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

gl2mark error?

Revision history for this message
Kevin DuBois (kdub) wrote :
Revision history for this message
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
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.

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'include/client/mir_toolkit/client_types.h'
--- include/client/mir_toolkit/client_types.h 2015-05-29 04:23:56 +0000
+++ include/client/mir_toolkit/client_types.h 2015-06-16 12:28:06 +0000
@@ -283,6 +283,16 @@
283 MirDisplayCard *cards;283 MirDisplayCard *cards;
284} MirDisplayConfiguration;284} MirDisplayConfiguration;
285285
286/**
287 * The displacement from the top-left corner of the surface.
288 */
289typedef struct MirBufferStreamInfo
290{
291 MirBufferStream* stream;
292 int displacement_x;
293 int displacement_y;
294} MirBufferStreamInfo;
295
286typedef struct MirRectangle296typedef struct MirRectangle
287{297{
288 int left;298 int left;
289299
=== modified file 'include/client/mir_toolkit/mir_surface.h'
--- include/client/mir_toolkit/mir_surface.h 2015-06-10 09:00:22 +0000
+++ include/client/mir_toolkit/mir_surface.h 2015-06-16 12:28:06 +0000
@@ -433,6 +433,28 @@
433void mir_surface_spec_release(MirSurfaceSpec* spec);433void mir_surface_spec_release(MirSurfaceSpec* spec);
434434
435/**435/**
436 * Set the streams associated with the spec.
437 * streams[0] is the bottom-most stream, and streams[size-1] is the topmost.
438 * On application of the spec, a stream that is present in the surface,
439 * but is not in the list will be disassociated from the surface.
440 * On application of the spec, a stream that is not present in the surface,
441 * but is in the list will be associated with the surface.
442 * Streams set a displacement from the top-left corner of the surface.
443 *
444 * \warning disassociating streams from the surface will not release() them.
445 * \warning It is wiser to arrange the streams within the bounds of the
446 * surface the spec is applied to. Shells can define their own
447 * behavior as to what happens to an out-of-bound stream.
448 *
449 * \param [in] spec The spec to accumulate the request in.
450 * \param [in] streams The an array of non-null streams info.
451 * \param [in] num_streams The number of elements in the streams array.
452 */
453void mir_surface_spec_set_streams(MirSurfaceSpec* spec,
454 MirBufferStreamInfo* streams,
455 unsigned int num_streams);
456
457/**
436 * Set the event handler to be called when events arrive for a surface.458 * Set the event handler to be called when events arrive for a surface.
437 * \warning event_handler could be called from another thread. You must do459 * \warning event_handler could be called from another thread. You must do
438 * any locking appropriate to protect your data accessed in the460 * any locking appropriate to protect your data accessed in the
439461
=== modified file 'include/server/mir/scene/session.h'
--- include/server/mir/scene/session.h 2015-05-19 21:34:34 +0000
+++ include/server/mir/scene/session.h 2015-06-16 12:28:06 +0000
@@ -22,10 +22,12 @@
22#include "mir/frontend/session.h"22#include "mir/frontend/session.h"
23#include "mir/scene/snapshot.h"23#include "mir/scene/snapshot.h"
2424
25#include <vector>
25#include <sys/types.h>26#include <sys/types.h>
2627
27namespace mir28namespace mir
28{29{
30namespace shell { struct StreamSpecification; }
29namespace scene31namespace scene
30{32{
31class Surface;33class Surface;
@@ -60,6 +62,7 @@
6062
61 virtual frontend::BufferStreamId create_buffer_stream(graphics::BufferProperties const& props) = 0;63 virtual frontend::BufferStreamId create_buffer_stream(graphics::BufferProperties const& props) = 0;
62 virtual void destroy_buffer_stream(frontend::BufferStreamId stream) = 0;64 virtual void destroy_buffer_stream(frontend::BufferStreamId stream) = 0;
65 virtual void configure_streams(Surface& surface, std::vector<shell::StreamSpecification> const& config) = 0;
63};66};
64}67}
65}68}
6669
=== modified file 'src/client/mir_surface.cpp'
--- src/client/mir_surface.cpp 2015-06-10 11:13:15 +0000
+++ src/client/mir_surface.cpp 2015-06-16 12:28:06 +0000
@@ -23,6 +23,7 @@
23#include "cursor_configuration.h"23#include "cursor_configuration.h"
24#include "client_buffer_stream_factory.h"24#include "client_buffer_stream_factory.h"
25#include "mir_connection.h"25#include "mir_connection.h"
26#include "client_buffer_stream.h"
26#include "mir/dispatch/threaded_dispatcher.h"27#include "mir/dispatch/threaded_dispatcher.h"
27#include "mir/input/input_platform.h"28#include "mir/input/input_platform.h"
28#include "mir/input/xkb_mapper.h"29#include "mir/input/xkb_mapper.h"
@@ -664,6 +665,18 @@
664 aspect->set_height(spec.max_aspect.value().height);665 aspect->set_height(spec.max_aspect.value().height);
665 }666 }
666667
668 if (spec.streams.is_set())
669 {
670 for(auto const& stream : spec.streams.value())
671 {
672 auto const new_stream = surface_specification->add_stream();
673 new_stream->set_displacement_x(stream.displacement_x);
674 new_stream->set_displacement_y(stream.displacement_y);
675 new_stream->mutable_id()->set_value(
676 reinterpret_cast<mcl::ClientBufferStream*>(stream.stream)->rpc_id().as_value());
677 }
678 }
679
667 modify_wait_handle.expect_result();680 modify_wait_handle.expect_result();
668 server->modify_surface(0, &mods, &modify_result,681 server->modify_surface(0, &mods, &modify_result,
669 google::protobuf::NewCallback(this, &MirSurface::on_modified));682 google::protobuf::NewCallback(this, &MirSurface::on_modified));
670683
=== modified file 'src/client/mir_surface.h'
--- src/client/mir_surface.h 2015-05-29 04:23:56 +0000
+++ src/client/mir_surface.h 2015-06-16 12:28:06 +0000
@@ -97,6 +97,7 @@
97 mir::optional_value<int> height_inc;97 mir::optional_value<int> height_inc;
98 mir::optional_value<AspectRatio> min_aspect;98 mir::optional_value<AspectRatio> min_aspect;
99 mir::optional_value<AspectRatio> max_aspect;99 mir::optional_value<AspectRatio> max_aspect;
100 mir::optional_value<std::vector<MirBufferStreamInfo>> streams;
100};101};
101102
102struct MirPersistentId103struct MirPersistentId
103104
=== modified file 'src/client/mir_surface_api.cpp'
--- src/client/mir_surface_api.cpp 2015-06-10 09:00:22 +0000
+++ src/client/mir_surface_api.cpp 2015-06-16 12:28:06 +0000
@@ -516,9 +516,29 @@
516 // Keep calm and carry on516 // Keep calm and carry on
517}517}
518518
519void mir_surface_spec_set_streams(MirSurfaceSpec* spec, MirBufferStreamInfo* streams, unsigned int size)
520try
521{
522 mir::require(spec);
523
524 std::vector<MirBufferStreamInfo> copy;
525 for (auto i = 0u; i < size; i++)
526 {
527 mir::require(mir_buffer_stream_is_valid(streams[i].stream));
528 copy.emplace_back(streams[i]);
529 }
530 spec->streams = copy;
531}
532catch (std::exception const& ex)
533{
534 MIR_LOG_UNCAUGHT_EXCEPTION(ex);
535}
536
537
519void mir_surface_spec_set_parent(MirSurfaceSpec* spec, MirSurface* parent)538void mir_surface_spec_set_parent(MirSurfaceSpec* spec, MirSurface* parent)
520try539try
521{540{
541 mir::require(spec);
522 spec->parent = parent;542 spec->parent = parent;
523}543}
524catch (std::exception const& ex)544catch (std::exception const& ex)
525545
=== modified file 'src/client/symbols.map'
--- src/client/symbols.map 2015-06-10 23:37:28 +0000
+++ src/client/symbols.map 2015-06-16 12:28:06 +0000
@@ -142,6 +142,7 @@
142 mir_surface_spec_set_parent;142 mir_surface_spec_set_parent;
143 mir_surface_spec_set_pixel_format;143 mir_surface_spec_set_pixel_format;
144 mir_surface_spec_set_preferred_orientation;144 mir_surface_spec_set_preferred_orientation;
145 mir_surface_spec_set_streams;
145 mir_surface_spec_set_type;146 mir_surface_spec_set_type;
146 mir_surface_spec_set_width;147 mir_surface_spec_set_width;
147 mir_surface_spec_set_width_increment;148 mir_surface_spec_set_width_increment;
148149
=== modified file 'src/server/frontend/session_mediator.cpp'
--- src/server/frontend/session_mediator.cpp 2015-06-09 07:20:56 +0000
+++ src/server/frontend/session_mediator.cpp 2015-06-16 12:28:06 +0000
@@ -451,15 +451,18 @@
451 // max_aspect is a special case (below)451 // max_aspect is a special case (below)
452452
453#undef COPY_IF_SET453#undef COPY_IF_SET
454 std::vector<msh::StreamSpecification> stream_spec;454 if (surface_specification.stream_size() > 0)
455 for(auto& stream : surface_specification.stream())
456 {455 {
457 stream_spec.emplace_back(456 std::vector<msh::StreamSpecification> stream_spec;
458 msh::StreamSpecification{457 for (auto& stream : surface_specification.stream())
459 mf::BufferStreamId{stream.id().value()},458 {
460 geom::Displacement{stream.displacement_x(), stream.displacement_y()}});459 stream_spec.emplace_back(
460 msh::StreamSpecification{
461 mf::BufferStreamId{stream.id().value()},
462 geom::Displacement{stream.displacement_x(), stream.displacement_y()}});
463 }
464 mods.streams = std::move(stream_spec);
461 }465 }
462 mods.streams = std::move(stream_spec);
463466
464 if (surface_specification.has_aux_rect())467 if (surface_specification.has_aux_rect())
465 {468 {
466469
=== modified file 'src/server/scene/application_session.cpp'
--- src/server/scene/application_session.cpp 2015-06-02 13:41:40 +0000
+++ src/server/scene/application_session.cpp 2015-06-16 12:28:06 +0000
@@ -322,3 +322,12 @@
322 std::unique_lock<std::mutex> lock(surfaces_and_streams_mutex);322 std::unique_lock<std::mutex> lock(surfaces_and_streams_mutex);
323 streams.erase(checked_find(id));323 streams.erase(checked_find(id));
324}324}
325
326void ms::ApplicationSession::configure_streams(
327 ms::Surface& surface, std::vector<shell::StreamSpecification> const& streams)
328{
329 std::list<ms::StreamInfo> list;
330 for (auto& stream : streams)
331 list.emplace_back(ms::StreamInfo{checked_find(stream.stream_id)->second, stream.displacement});
332 surface.set_streams(list);
333}
325334
=== modified file 'src/server/scene/application_session.h'
--- src/server/scene/application_session.h 2015-05-19 21:34:34 +0000
+++ src/server/scene/application_session.h 2015-06-16 12:28:06 +0000
@@ -85,6 +85,7 @@
85 std::shared_ptr<frontend::BufferStream> get_buffer_stream(frontend::BufferStreamId stream) const override;85 std::shared_ptr<frontend::BufferStream> get_buffer_stream(frontend::BufferStreamId stream) const override;
86 frontend::BufferStreamId create_buffer_stream(graphics::BufferProperties const& params) override;86 frontend::BufferStreamId create_buffer_stream(graphics::BufferProperties const& params) override;
87 void destroy_buffer_stream(frontend::BufferStreamId stream) override;87 void destroy_buffer_stream(frontend::BufferStreamId stream) override;
88 void configure_streams(Surface& surface, std::vector<shell::StreamSpecification> const& config) override;
8889
89protected:90protected:
90 ApplicationSession(ApplicationSession const&) = delete;91 ApplicationSession(ApplicationSession const&) = delete;
9192
=== modified file 'src/server/scene/basic_surface.cpp'
--- src/server/scene/basic_surface.cpp 2015-06-08 17:22:32 +0000
+++ src/server/scene/basic_surface.cpp 2015-06-16 12:28:06 +0000
@@ -844,15 +844,18 @@
844844
845void ms::BasicSurface::set_streams(std::list<scene::StreamInfo> const& s)845void ms::BasicSurface::set_streams(std::list<scene::StreamInfo> const& s)
846{846{
847 std::unique_lock<std::mutex> lk(guard);
848
849 if (s.end() == std::find_if(s.begin(), s.end(),
850 [this] (ms::StreamInfo const& info) { return info.stream == surface_buffer_stream; }))
851 {847 {
852 BOOST_THROW_EXCEPTION(std::logic_error("cannot remove the created-with buffer stream yet"));848 std::unique_lock<std::mutex> lk(guard);
849
850 if (s.end() == std::find_if(s.begin(), s.end(),
851 [this] (ms::StreamInfo const& info) { return info.stream == surface_buffer_stream; }))
852 {
853 BOOST_THROW_EXCEPTION(std::logic_error("cannot remove the created-with buffer stream yet"));
854 }
855
856 layers = s;
853 }857 }
854858 observers.moved_to(surface_rect.top_left);
855 layers = s;
856}859}
857860
858mg::RenderableList ms::BasicSurface::generate_renderables(mc::CompositorID id) const861mg::RenderableList ms::BasicSurface::generate_renderables(mc::CompositorID id) const
859862
=== modified file 'src/server/shell/canonical_window_manager.cpp'
--- src/server/shell/canonical_window_manager.cpp 2015-06-11 09:41:30 +0000
+++ src/server/shell/canonical_window_manager.cpp 2015-06-16 12:28:06 +0000
@@ -274,7 +274,7 @@
274}274}
275275
276void msh::CanonicalWindowManagerPolicy::handle_modify_surface(276void msh::CanonicalWindowManagerPolicy::handle_modify_surface(
277 std::shared_ptr<scene::Session> const& /*session*/,277 std::shared_ptr<scene::Session> const& session,
278 std::shared_ptr<scene::Surface> const& surface,278 std::shared_ptr<scene::Surface> const& surface,
279 SurfaceSpecification const& modifications)279 SurfaceSpecification const& modifications)
280{280{
@@ -369,6 +369,13 @@
369 if (modifications.name.is_set())369 if (modifications.name.is_set())
370 surface->rename(modifications.name.value());370 surface->rename(modifications.name.value());
371371
372 if (modifications.streams.is_set())
373 {
374 auto v = modifications.streams.value();
375 std::vector<shell::StreamSpecification> l (v.begin(), v.end());
376 session->configure_streams(*surface, l);
377 }
378
372 if (modifications.width.is_set() || modifications.height.is_set())379 if (modifications.width.is_set() || modifications.height.is_set())
373 {380 {
374 auto new_size = surface->size();381 auto new_size = surface->size();
375382
=== modified file 'tests/acceptance-tests/CMakeLists.txt'
--- tests/acceptance-tests/CMakeLists.txt 2015-06-11 09:41:30 +0000
+++ tests/acceptance-tests/CMakeLists.txt 2015-06-16 12:28:06 +0000
@@ -32,6 +32,7 @@
32 test_prompt_session_client_api.cpp32 test_prompt_session_client_api.cpp
33 test_client_screencast.cpp33 test_client_screencast.cpp
34 test_client_surface_visibility.cpp34 test_client_surface_visibility.cpp
35 test_buffer_stream_arrangement.cpp
35 test_client_with_custom_display_config_deadlock.cpp36 test_client_with_custom_display_config_deadlock.cpp
36 test_server_without_active_outputs.cpp37 test_server_without_active_outputs.cpp
37 test_server_startup.cpp38 test_server_startup.cpp
3839
=== added file 'tests/acceptance-tests/test_buffer_stream_arrangement.cpp'
--- tests/acceptance-tests/test_buffer_stream_arrangement.cpp 1970-01-01 00:00:00 +0000
+++ tests/acceptance-tests/test_buffer_stream_arrangement.cpp 2015-06-16 12:28:06 +0000
@@ -0,0 +1,239 @@
1/*
2 * Copyright © 2015 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
17 */
18
19#include "mir_toolkit/mir_client_library.h"
20#include "mir_test_framework/connected_client_with_a_surface.h"
21#include "mir/compositor/display_buffer_compositor.h"
22#include "mir/compositor/display_buffer_compositor_factory.h"
23#include "mir/compositor/scene_element.h"
24#include "mir/graphics/renderable.h"
25#include "mir/graphics/cursor.h"
26#include "mir/geometry/displacement.h"
27
28#include <mutex>
29#include <condition_variable>
30#include <stdexcept>
31#include <gtest/gtest.h>
32#include <gmock/gmock.h>
33
34namespace mtf = mir_test_framework;
35namespace geom = mir::geometry;
36namespace mc = mir::compositor;
37namespace mg = mir::graphics;
38namespace
39{
40
41MirPixelFormat an_available_format(MirConnection* connection)
42{
43 using namespace testing;
44 MirPixelFormat format{mir_pixel_format_invalid};
45 unsigned int valid_formats{0};
46 mir_connection_get_available_surface_formats(connection, &format, 1, &valid_formats);
47 return format;
48}
49
50struct Stream
51{
52 Stream(MirBufferStream* stream, geom::Point pt) :
53 stream(stream),
54 pos{pt},
55 needs_release{false}
56 {
57 mir_buffer_stream_swap_buffers_sync(stream);
58 }
59
60 Stream(MirConnection* connection, geom::Rectangle rect) :
61 stream(mir_connection_create_buffer_stream_sync(
62 connection,
63 rect.size.width.as_int(),
64 rect.size.height.as_int(),
65 an_available_format(connection),
66 mir_buffer_usage_hardware)),
67 pos{rect.top_left},
68 needs_release{true}
69 {
70 mir_buffer_stream_swap_buffers_sync(stream);
71 }
72
73 ~Stream()
74 {
75 if (needs_release)
76 mir_buffer_stream_release_sync(stream);
77 }
78
79 MirBufferStream* handle() const
80 {
81 return stream;
82 }
83
84 geom::Point position()
85 {
86 return pos;
87 }
88
89 Stream(Stream const&) = delete;
90 Stream& operator=(Stream const&) = delete;
91private:
92 MirBufferStream* stream;
93 geom::Point const pos;
94 bool const needs_release;
95};
96
97struct Ordering
98{
99 void note_scene_element_sequence(mc::SceneElementSequence& sequence)
100 {
101 if (sequence.empty())
102 return;
103
104 std::unique_lock<decltype(mutex)> lk(mutex);
105 displacements.clear();
106
107 auto first_position = (*sequence.begin())->renderable()->screen_position().top_left;
108 for (auto const& element : sequence)
109 displacements.emplace_back(element->renderable()->screen_position().top_left - first_position);
110 post_count++;
111
112 cv.notify_all();
113 }
114
115 template<typename T, typename S>
116 bool wait_for_another_post_within(std::chrono::duration<T,S> duration)
117 {
118 std::unique_lock<decltype(mutex)> lk(mutex);
119 auto count = post_count + 1;
120 return cv.wait_for(lk, duration, [this, count]{return (post_count >= count);});
121 }
122
123 std::vector<geom::Displacement> last_ordering()
124 {
125 return displacements;
126 }
127private:
128 std::mutex mutex;
129 std::condition_variable cv;
130 unsigned int post_count{0};
131 std::vector<geom::Displacement> displacements;
132};
133
134struct OrderTrackingDBC : mc::DisplayBufferCompositor
135{
136 OrderTrackingDBC(
137 std::shared_ptr<mc::DisplayBufferCompositor> const& wrapped,
138 std::shared_ptr<Ordering> const& ordering) :
139 wrapped(wrapped),
140 ordering(ordering)
141 {
142 }
143
144 void composite(mc::SceneElementSequence&& scene_sequence) override
145 {
146 ordering->note_scene_element_sequence(scene_sequence);
147 wrapped->composite(std::move(scene_sequence));
148 }
149
150 std::shared_ptr<mc::DisplayBufferCompositor> const wrapped;
151 std::shared_ptr<Ordering> const ordering;
152};
153
154struct OrderTrackingDBCFactory : mc::DisplayBufferCompositorFactory
155{
156 OrderTrackingDBCFactory(
157 std::shared_ptr<mc::DisplayBufferCompositorFactory> const& wrapped,
158 std::shared_ptr<Ordering> const& ordering) :
159 wrapped(wrapped),
160 ordering(ordering)
161 {
162 }
163
164 std::unique_ptr<mc::DisplayBufferCompositor> create_compositor_for(mg::DisplayBuffer& db) override
165 {
166 return std::make_unique<OrderTrackingDBC>(wrapped->create_compositor_for(db), ordering);
167 }
168
169 std::shared_ptr<OrderTrackingDBC> last_dbc{nullptr};
170 std::shared_ptr<mc::DisplayBufferCompositorFactory> const wrapped;
171 std::shared_ptr<Ordering> const ordering;
172};
173
174struct BufferStreamArrangement : mtf::ConnectedClientWithASurface
175{
176 void SetUp() override
177 {
178 ordering = std::make_shared<Ordering>();
179 server.wrap_display_buffer_compositor_factory(
180 [this](std::shared_ptr<mc::DisplayBufferCompositorFactory> const& wrapped)
181 {
182 order_tracker = std::make_shared<OrderTrackingDBCFactory>(wrapped, ordering);
183 return order_tracker;
184 });
185
186 ConnectedClientWithASurface::SetUp();
187 server.the_cursor()->hide();
188
189 streams.emplace_back(
190 std::make_unique<Stream>(mir_surface_get_buffer_stream(surface), geom::Point{0,0}));
191 int const additional_streams{3};
192 for (auto i = 0; i < additional_streams; i++)
193 {
194 geom::Size size{30 * i + 1, 40* i + 1};
195 geom::Point position{i * 2, i * 3};
196 streams.emplace_back(std::make_unique<Stream>(connection, geom::Rectangle{position, size}));
197 }
198 }
199
200 void TearDown() override
201 {
202 streams.clear();
203 ConnectedClientWithASurface::TearDown();
204 }
205
206 std::shared_ptr<Ordering> ordering;
207 std::shared_ptr<OrderTrackingDBCFactory> order_tracker{nullptr};
208 std::vector<std::unique_ptr<Stream>> streams;
209};
210}
211
212TEST_F(BufferStreamArrangement, arrangements_are_applied)
213{
214 using namespace testing;
215 std::vector<MirBufferStreamInfo> infos(streams.size());
216 auto i = 0u;
217 for (auto const& stream : streams)
218 {
219 infos[i++] = MirBufferStreamInfo{
220 stream->handle(),
221 stream->position().x.as_int(),
222 stream->position().y.as_int()};
223 }
224
225 auto change_spec = mir_connection_create_spec_for_changes(connection);
226 mir_surface_spec_set_streams(change_spec, infos.data(), infos.size());
227 mir_surface_apply_spec(surface, change_spec);
228 mir_surface_spec_release(change_spec);
229
230 std::vector<geom::Displacement> displacements;
231 for (auto& info : infos)
232 displacements.emplace_back(geom::Displacement{info.displacement_x, info.displacement_y});
233
234 //check that the compositor rendered correctly
235 using namespace std::literals::chrono_literals;
236 EXPECT_TRUE(ordering->wait_for_another_post_within(5s))
237 << "timed out waiting for another post";
238 EXPECT_THAT(ordering->last_ordering(), ContainerEq(displacements));
239}
0240
=== modified file 'tests/include/mir_test_doubles/mock_scene_session.h'
--- tests/include/mir_test_doubles/mock_scene_session.h 2015-05-19 21:34:34 +0000
+++ tests/include/mir_test_doubles/mock_scene_session.h 2015-06-16 12:28:06 +0000
@@ -20,6 +20,7 @@
20#define MIR_TEST_DOUBLES_MOCK_SCENE_SESSION_H_20#define MIR_TEST_DOUBLES_MOCK_SCENE_SESSION_H_
2121
22#include "mir/scene/session.h"22#include "mir/scene/session.h"
23#include "mir/scene/surface.h"
23#include "mir/scene/surface_creation_parameters.h"24#include "mir/scene/surface_creation_parameters.h"
24#include "mir/graphics/display_configuration.h"25#include "mir/graphics/display_configuration.h"
2526
@@ -64,6 +65,7 @@
64 MOCK_METHOD1(destroy_buffer_stream, void(frontend::BufferStreamId));65 MOCK_METHOD1(destroy_buffer_stream, void(frontend::BufferStreamId));
65 MOCK_METHOD1(create_buffer_stream, frontend::BufferStreamId(graphics::BufferProperties const&));66 MOCK_METHOD1(create_buffer_stream, frontend::BufferStreamId(graphics::BufferProperties const&));
66 67
68 MOCK_METHOD2(configure_streams, void(scene::Surface&, std::vector<shell::StreamSpecification> const&));
67};69};
6870
69}71}
7072
=== modified file 'tests/include/mir_test_doubles/mock_surface.h'
--- tests/include/mir_test_doubles/mock_surface.h 2015-06-08 17:28:38 +0000
+++ tests/include/mir_test_doubles/mock_surface.h 2015-06-16 12:28:06 +0000
@@ -74,6 +74,7 @@
74 MOCK_METHOD1(consume, void(MirEvent const&));74 MOCK_METHOD1(consume, void(MirEvent const&));
7575
76 MOCK_CONST_METHOD0(primary_buffer_stream, std::shared_ptr<frontend::BufferStream>());76 MOCK_CONST_METHOD0(primary_buffer_stream, std::shared_ptr<frontend::BufferStream>());
77 MOCK_METHOD1(set_streams, void(std::list<scene::StreamInfo> const&));
7778
78};79};
7980
8081
=== modified file 'tests/include/mir_test_doubles/stub_scene_session.h'
--- tests/include/mir_test_doubles/stub_scene_session.h 2015-05-19 21:34:34 +0000
+++ tests/include/mir_test_doubles/stub_scene_session.h 2015-06-16 12:28:06 +0000
@@ -117,6 +117,10 @@
117 return frontend::BufferStreamId();117 return frontend::BufferStreamId();
118 }118 }
119119
120 void configure_streams(scene::Surface&, std::vector<shell::StreamSpecification> const&)
121 {
122 }
123
120 pid_t const pid;124 pid_t const pid;
121};125};
122126
123127
=== modified file 'tests/unit-tests/scene/test_application_session.cpp'
--- tests/unit-tests/scene/test_application_session.cpp 2015-05-29 17:36:46 +0000
+++ tests/unit-tests/scene/test_application_session.cpp 2015-06-16 12:28:06 +0000
@@ -515,6 +515,53 @@
515 session->destroy_surface(id);515 session->destroy_surface(id);
516}516}
517517
518MATCHER(StreamEq, "")
519{
520 return (std::get<0>(arg).stream == std::get<1>(arg).stream) &&
521 (std::get<0>(arg).displacement == std::get<1>(arg).displacement);
522}
523
524TEST_F(ApplicationSession, sets_and_looks_up_surface_streams)
525{
526 using namespace testing;
527 NiceMock<MockBufferStreamFactory> mock_bufferstream_factory;
528 NiceMock<MockSurfaceFactory> mock_surface_factory;
529
530 auto mock_surface = make_mock_surface();
531 EXPECT_CALL(mock_surface_factory, create_surface(_,_))
532 .WillOnce(Return(mock_surface));
533
534 std::array<std::shared_ptr<mc::BufferStream>,3> streams {{
535 std::make_shared<mtd::StubBufferStream>(),
536 std::make_shared<mtd::StubBufferStream>(),
537 std::make_shared<mtd::StubBufferStream>()
538 }};
539 EXPECT_CALL(mock_bufferstream_factory, create_buffer_stream(_))
540 .WillOnce(Return(streams[0]))
541 .WillOnce(Return(streams[1]))
542 .WillOnce(Return(streams[2]));
543
544 auto stream_properties = mg::BufferProperties{{8,8}, mir_pixel_format_argb_8888, mg::BufferUsage::hardware};
545 auto session = make_application_session(
546 mt::fake_shared(mock_bufferstream_factory),
547 mt::fake_shared(mock_surface_factory));
548 auto stream_id0 = mf::BufferStreamId(session->create_surface(ms::a_surface().of_position({1,1})).as_value());
549 auto stream_id1 = session->create_buffer_stream(stream_properties);
550 auto stream_id2 = session->create_buffer_stream(stream_properties);
551
552 std::list<ms::StreamInfo> info {
553 {streams[2], geom::Displacement{0,3}},
554 {streams[0], geom::Displacement{-1,1}},
555 {streams[1], geom::Displacement{0,2}}
556 };
557 EXPECT_CALL(*mock_surface, set_streams(Pointwise(StreamEq(), info)));
558 session->configure_streams(*mock_surface, {
559 {stream_id2, geom::Displacement{0,3}},
560 {stream_id0, geom::Displacement{-1,1}},
561 {stream_id1, geom::Displacement{0,2}}
562 });
563}
564
518TEST_F(ApplicationSession, buffer_stream_constructed_with_requested_parameters)565TEST_F(ApplicationSession, buffer_stream_constructed_with_requested_parameters)
519{566{
520 using namespace ::testing;567 using namespace ::testing;

Subscribers

People subscribed via source and target branches