Mir

Merge lp:~raof/mir/better-buffer-plumbing into lp:mir

Proposed by Chris Halse Rogers
Status: Superseded
Proposed branch: lp:~raof/mir/better-buffer-plumbing
Merge into: lp:mir
Diff against target: 3934 lines (+1094/-1145)
59 files modified
examples/render_surfaces.cpp (+1/-4)
examples/server_example_canonical_window_manager.cpp (+5/-3)
examples/server_example_canonical_window_manager.h (+7/-1)
examples/server_example_window_management.cpp (+6/-1)
include/server/mir/frontend/buffer_sink.h (+0/-1)
include/server/mir/frontend/client_buffers.h (+0/-46)
include/server/mir/frontend/session.h (+0/-6)
include/server/mir/scene/buffer_stream_factory.h (+4/-6)
include/server/mir/scene/session.h (+0/-6)
include/server/mir/shell/window_management_info.h (+5/-1)
include/test/mir/test/doubles/stub_session.h (+0/-6)
src/client/buffer_vault.cpp (+10/-2)
src/client/connection_surface_map.cpp (+1/-1)
src/client/mir_connection.cpp (+6/-8)
src/client/rpc/mir_protobuf_rpc_channel.cpp (+11/-3)
src/server/compositor/CMakeLists.txt (+0/-1)
src/server/compositor/buffer_map.cpp (+0/-116)
src/server/compositor/buffer_map.h (+0/-65)
src/server/compositor/buffer_stream_factory.cpp (+5/-12)
src/server/compositor/buffer_stream_factory.h (+4/-5)
src/server/compositor/dropping_schedule.cpp (+1/-12)
src/server/compositor/dropping_schedule.h (+1/-3)
src/server/compositor/multi_monitor_arbiter.cpp (+1/-5)
src/server/compositor/multi_monitor_arbiter.h (+0/-2)
src/server/compositor/stream.cpp (+7/-25)
src/server/compositor/stream.h (+1/-2)
src/server/frontend/default_ipc_factory.cpp (+3/-1)
src/server/frontend/event_sender.cpp (+0/-8)
src/server/frontend/event_sender.h (+0/-1)
src/server/frontend/session_mediator.cpp (+127/-32)
src/server/frontend/session_mediator.h (+6/-2)
src/server/scene/application_session.cpp (+1/-53)
src/server/scene/application_session.h (+0/-7)
src/server/scene/global_event_sender.cpp (+0/-4)
src/server/scene/global_event_sender.h (+0/-1)
src/server/shell/window_management_info.cpp (+13/-26)
tests/include/mir/test/doubles/mock_event_sink.h (+0/-1)
tests/include/mir/test/doubles/null_event_sink.h (+0/-1)
tests/include/mir/test/doubles/stub_buffer_stream_factory.h (+9/-30)
tests/integration-tests/compositor/test_swapping_swappers.cpp (+1/-2)
tests/integration-tests/test_buffer_scheduling.cpp (+25/-14)
tests/integration-tests/test_session.cpp (+1/-1)
tests/integration-tests/test_submit_buffer.cpp (+146/-108)
tests/integration-tests/test_surface_stack_with_compositor.cpp (+2/-5)
tests/integration-tests/test_swapinterval.cpp (+3/-8)
tests/mir_test_doubles/mock_event_sink_factory.cpp (+0/-6)
tests/mir_test_framework/stub_session.cpp (+0/-25)
tests/unit-tests/client/test_client_buffer_stream.cpp (+6/-7)
tests/unit-tests/client/test_connection_resource_map.cpp (+2/-6)
tests/unit-tests/client/test_mir_connection.cpp (+0/-1)
tests/unit-tests/client/test_protobuf_rpc_channel.cpp (+24/-0)
tests/unit-tests/compositor/CMakeLists.txt (+0/-1)
tests/unit-tests/compositor/test_client_buffers.cpp (+0/-119)
tests/unit-tests/compositor/test_dropping_schedule.cpp (+6/-45)
tests/unit-tests/compositor/test_multi_monitor_arbiter.cpp (+171/-112)
tests/unit-tests/compositor/test_stream.cpp (+27/-68)
tests/unit-tests/frontend/test_session_mediator.cpp (+437/-82)
tests/unit-tests/scene/test_application_session.cpp (+7/-14)
tests/unit-tests/scene/test_surface_stack.cpp (+1/-11)
To merge this branch: bzr merge lp:~raof/mir/better-buffer-plumbing
Reviewer Review Type Date Requested Status
Alan Griffiths Needs Fixing
Mir CI Bot continuous-integration Needs Fixing
Brandon Schaefer (community) Approve
Review via email: mp+326728@code.launchpad.net

This proposal has been superseded by a proposal from 2017-07-18.

Commit message

Move full responsibility for buffer IPC into the frontend.

Currently buffer IPC is split between the frontend and various things which shared an mf::BufferMap.

This branch consolidates everything so that, outside the SessionMediator, everything is dealing with
a std::shared_ptr<mg::Buffer>.

In addition to consolidating IPC into the frontend where it belongs, this makes it easy
to submit client-allocated buffers.

To post a comment you must log in.
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:4210
https://mir-jenkins.ubuntu.com/job/mir-ci/3472/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4745/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4903
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/4892
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/4892
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4892
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4782/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4782
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4782/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4782
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4782/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4782/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4782
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4782/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4782
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4782/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4782
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4782/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4782/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3472/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:4211
https://mir-jenkins.ubuntu.com/job/mir-ci/3475/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4748/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4906
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/4895
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/4895
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4895
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4785/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4785/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4785/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4785/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4785/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4785
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4785/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4785
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4785/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4785/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3475/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:4212
https://mir-jenkins.ubuntu.com/job/mir-ci/3476/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4749/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4907
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/4896
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/4896
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4896
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4786/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4786
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4786/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4786
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4786/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4786
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4786/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4786/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4786
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4786/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4786
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4786/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4786
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4786/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3476/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:4214
https://mir-jenkins.ubuntu.com/job/mir-ci/3477/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/4750
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4908
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/4897
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/4897
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4897
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4787
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4787/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4787
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4787/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4787
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4787/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4787
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4787/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4787
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4787/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4787
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4787/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4787
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4787/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4787
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4787/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3477/rebuild

review: Approve (continuous-integration)
Revision history for this message
Brandon Schaefer (brandontschaefer) wrote :

Nice, lgtm. Now we can accept gbm buffers easier then the way it looked before :)

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

The name "mir::graphics::GraphicBufferAllocator" seems tautological why not "mir::graphics::BufferAllocator"?

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

> The name "mir::graphics::GraphicBufferAllocator" seems tautological why not
> "mir::graphics::BufferAllocator"?

/sigh I guess that's pre-existing.

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

nits

+ // We can't reasonably answer this question -
+ // Suitability for cursor use is a per-buffer property, not a per-stream property.
return true;

Instead of hard coding this to true wouldn't it be less misleading to remove the calls to this function?

~~~~

Looks like this changes the mirserver ABI - there ought to be removals from the symbols script (e.g. mir::frontend::ClientBuffers) and a bump to the SONAME.

But that can be done separately.

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

This breaks when starting a load of clients. (I built lp:miral against it and...)

$ cat `which mir_demo_client_all`
#!/bin/sh
mir_demo_client_animated_cursor&mir_demo_client_eglsquare&mir_demo_client_prerendered_frames&mir_demo_client_basic&mir_demo_client_eglstateswitcher&mir_demo_client_progressbar&mir_demo_client_camera&mir_demo_client_egltriangle&mir_demo_client_prompt_session&mir_demo_client_cursors&mir_demo_client_fingerpaint&mir_demo_client_release_at_exit&mir_demo_client_display_config&mir_demo_client_flicker&mir_demo_client_scroll&mir_demo_client_eglcounter&mir_demo_client_input_shapes&mir_demo_client_target&mir_demo_client_eglflash&mir_demo_client_multistream&mir_demo_client_tooltip&mir_demo_client_eglplasma&mir_demo_client_multiwin&mir_demo_client_touch_validator&

$miral-app

[in the miral terminal]
$ mir_demo_client_all

Expect: all the demos clients start
Actual: miral-shell crashes

I don't see this without this MP.

review: Needs Fixing
Revision history for this message
Chris Halse Rogers (raof) wrote :

Interesting. I'll investigate!

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:4215
https://mir-jenkins.ubuntu.com/job/mir-ci/3484/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4759/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4920
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/4909
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/4909
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4909
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4796/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4796
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4796/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4796/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4796
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4796/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4796
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4796/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4796/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4796
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4796/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4796
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4796/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3484/rebuild

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

Works much better but...

$ miral-app -launcher mir_demo_client_multistream

Wait about 30sec and it locks up

review: Needs Fixing
Revision history for this message
Chris Halse Rogers (raof) wrote :

Huh. Artful build failures are due to Artful (specifically, dh_strip_nondeterminism) being broken.

Urgh. Let's try multistream!

Revision history for this message
Chris Halse Rogers (raof) wrote :

Ah, good. This also happens with mir_demo_server, which is easier to deal with.

But only multistream? Not the EGL demos, as far as I can tell. Odd.

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

Thinking about it - a client setting a bad BufferStreamID shouldn't crash the server. It should simply kill the session.

Revision history for this message
Chris Halse Rogers (raof) wrote :

Setting a bad BufferStreamID doesn't crash the server. At least, not that alone.

Hah! The hang in mir_demo_client_multistream is a client buffer leak, leading to fd starvation. Yay!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'examples/render_surfaces.cpp'
--- examples/render_surfaces.cpp 2017-05-08 03:04:26 +0000
+++ examples/render_surfaces.cpp 2017-07-18 03:23:56 +0000
@@ -34,7 +34,6 @@
34#include "mir/scene/surface_factory.h"34#include "mir/scene/surface_factory.h"
35#include "mir/shell/surface_stack.h"35#include "mir/shell/surface_stack.h"
36#include "mir/frontend/buffer_sink.h"36#include "mir/frontend/buffer_sink.h"
37#include "mir/frontend/client_buffers.h"
38#include "mir/server.h"37#include "mir/server.h"
39#include "mir/report_exception.h"38#include "mir/report_exception.h"
40#include "mir/renderer/gl/context.h"39#include "mir/renderer/gl/context.h"
@@ -391,13 +390,11 @@
391 {390 {
392 void send_buffer(mf::BufferStreamId, mg::Buffer&, mg::BufferIpcMsgType) override {}391 void send_buffer(mf::BufferStreamId, mg::Buffer&, mg::BufferIpcMsgType) override {}
393 void add_buffer(mg::Buffer&) override {}392 void add_buffer(mg::Buffer&) override {}
394 void remove_buffer(mg::Buffer&) override {}
395 void update_buffer(mg::Buffer&) override {}393 void update_buffer(mg::Buffer&) override {}
396 void error_buffer(geom::Size, MirPixelFormat, std::string const&) override {}394 void error_buffer(geom::Size, MirPixelFormat, std::string const&) override {}
397 };395 };
398396
399 auto buffers = buffer_stream_factory->create_buffer_map(std::make_shared<NullBufferSink>());397 auto const stream = buffer_stream_factory->create_buffer_stream({}, properties);
400 auto const stream = buffer_stream_factory->create_buffer_stream({}, buffers, properties);
401 auto const surface = surface_factory->create_surface(398 auto const surface = surface_factory->create_surface(
402 {ms::StreamInfo{stream, {}, {}}}, params);399 {ms::StreamInfo{stream, {}, {}}}, params);
403 surface_stack->add_surface(surface, params.input_mode);400 surface_stack->add_surface(surface, params.input_mode);
404401
=== modified file 'examples/server_example_canonical_window_manager.cpp'
--- examples/server_example_canonical_window_manager.cpp 2017-05-25 04:33:43 +0000
+++ examples/server_example_canonical_window_manager.cpp 2017-07-18 03:23:56 +0000
@@ -54,9 +54,11 @@
5454
55me::CanonicalWindowManagerPolicyCopy::CanonicalWindowManagerPolicyCopy(55me::CanonicalWindowManagerPolicyCopy::CanonicalWindowManagerPolicyCopy(
56 WindowManagerTools* const tools,56 WindowManagerTools* const tools,
57 std::shared_ptr<shell::DisplayLayout> const& display_layout) :57 std::shared_ptr<shell::DisplayLayout> const& display_layout,
58 std::shared_ptr<graphics::GraphicBufferAllocator> const& allocator) :
58 tools{tools},59 tools{tools},
59 display_layout{display_layout}60 display_layout{display_layout},
61 allocator{allocator}
60{62{
61}63}
6264
@@ -276,7 +278,7 @@
276 surface_map.emplace(titlebar, SurfaceInfo{session, titlebar, {}}).first->second;278 surface_map.emplace(titlebar, SurfaceInfo{session, titlebar, {}}).first->second;
277 titlebar_info.is_titlebar = true;279 titlebar_info.is_titlebar = true;
278 titlebar_info.parent = surface;280 titlebar_info.parent = surface;
279 titlebar_info.init_titlebar(session, titlebar);281 titlebar_info.init_titlebar(*allocator, titlebar);
280}282}
281283
282void me::CanonicalWindowManagerPolicyCopy::handle_new_surface(std::shared_ptr<ms::Session> const& session, std::shared_ptr<ms::Surface> const& surface)284void me::CanonicalWindowManagerPolicyCopy::handle_new_surface(std::shared_ptr<ms::Session> const& session, std::shared_ptr<ms::Surface> const& surface)
283285
=== modified file 'examples/server_example_canonical_window_manager.h'
--- examples/server_example_canonical_window_manager.h 2017-05-08 03:04:26 +0000
+++ examples/server_example_canonical_window_manager.h 2017-07-18 03:23:56 +0000
@@ -32,6 +32,10 @@
32namespace mir32namespace mir
33{33{
34namespace shell { class DisplayLayout; }34namespace shell { class DisplayLayout; }
35namespace graphics
36{
37class GraphicBufferAllocator;
38}
35namespace examples39namespace examples
36{40{
37// standard window management algorithm:41// standard window management algorithm:
@@ -48,7 +52,8 @@
4852
49 explicit CanonicalWindowManagerPolicyCopy(53 explicit CanonicalWindowManagerPolicyCopy(
50 WindowManagerTools* const tools,54 WindowManagerTools* const tools,
51 std::shared_ptr<shell::DisplayLayout> const& display_layout);55 std::shared_ptr<shell::DisplayLayout> const& display_layout,
56 std::shared_ptr<graphics::GraphicBufferAllocator> const& allocator);
5257
53 void click(geometry::Point cursor);58 void click(geometry::Point cursor);
5459
@@ -118,6 +123,7 @@
118123
119 WindowManagerTools* const tools;124 WindowManagerTools* const tools;
120 std::shared_ptr<shell::DisplayLayout> const display_layout;125 std::shared_ptr<shell::DisplayLayout> const display_layout;
126 std::shared_ptr<graphics::GraphicBufferAllocator> const allocator;
121127
122 geometry::Rectangle display_area;128 geometry::Rectangle display_area;
123 geometry::Point old_cursor{};129 geometry::Point old_cursor{};
124130
=== modified file 'examples/server_example_window_management.cpp'
--- examples/server_example_window_management.cpp 2017-05-08 03:04:26 +0000
+++ examples/server_example_window_management.cpp 2017-07-18 03:23:56 +0000
@@ -28,6 +28,8 @@
28#include "mir/scene/surface_creation_parameters.h"28#include "mir/scene/surface_creation_parameters.h"
29#include "mir/shell/display_layout.h"29#include "mir/shell/display_layout.h"
30#include "mir/shell/system_compositor_window_manager.h"30#include "mir/shell/system_compositor_window_manager.h"
31#include "mir/graphics/platform.h"
32#include "mir/graphics/graphic_buffer_allocator.h"
3133
32namespace me = mir::examples;34namespace me = mir::examples;
33namespace mf = mir::frontend;35namespace mf = mir::frontend;
@@ -134,7 +136,10 @@
134 }136 }
135 else if (selection == wm_canonical)137 else if (selection == wm_canonical)
136 {138 {
137 return std::make_shared<CanonicalWindowManager>(focus_controller, server.the_shell_display_layout());139 return std::make_shared<CanonicalWindowManager>(
140 focus_controller,
141 server.the_shell_display_layout(),
142 server.the_graphics_platform()->create_buffer_allocator());
138 }143 }
139 else if (selection == wm_system_compositor)144 else if (selection == wm_system_compositor)
140 {145 {
141146
=== modified file 'include/server/mir/frontend/buffer_sink.h'
--- include/server/mir/frontend/buffer_sink.h 2017-05-08 03:04:26 +0000
+++ include/server/mir/frontend/buffer_sink.h 2017-07-18 03:23:56 +0000
@@ -37,7 +37,6 @@
37 virtual void send_buffer(frontend::BufferStreamId id, graphics::Buffer& buffer, graphics::BufferIpcMsgType) = 0;37 virtual void send_buffer(frontend::BufferStreamId id, graphics::Buffer& buffer, graphics::BufferIpcMsgType) = 0;
38 virtual void add_buffer(graphics::Buffer&) = 0;38 virtual void add_buffer(graphics::Buffer&) = 0;
39 virtual void error_buffer(geometry::Size req_size, MirPixelFormat req_format, std::string const& error_msg) = 0;39 virtual void error_buffer(geometry::Size req_size, MirPixelFormat req_format, std::string const& error_msg) = 0;
40 virtual void remove_buffer(graphics::Buffer&) = 0;
41 virtual void update_buffer(graphics::Buffer&) = 0;40 virtual void update_buffer(graphics::Buffer&) = 0;
4241
43protected:42protected:
4443
=== removed file 'include/server/mir/frontend/client_buffers.h'
--- include/server/mir/frontend/client_buffers.h 2017-05-08 03:04:26 +0000
+++ include/server/mir/frontend/client_buffers.h 1970-01-01 00:00:00 +0000
@@ -1,46 +0,0 @@
1/*
2 * Copyright © 2015 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * 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#ifndef MIR_FRONTEND_CLIENT_BUFFERS_H_
20#define MIR_FRONTEND_CLIENT_BUFFERS_H_
21
22#include "mir/graphics/buffer_id.h"
23#include <memory>
24
25namespace mir
26{
27namespace graphics { class Buffer; }
28namespace frontend
29{
30class ClientBuffers
31{
32public:
33 virtual graphics::BufferID add_buffer(std::shared_ptr<graphics::Buffer> const& properties) = 0;
34 virtual void remove_buffer(graphics::BufferID id) = 0;
35 virtual std::shared_ptr<graphics::Buffer> get(graphics::BufferID) const = 0;
36 virtual void send_buffer(graphics::BufferID id) = 0;
37 virtual void receive_buffer(graphics::BufferID id) = 0;
38
39 ClientBuffers(ClientBuffers const&) = delete;
40 ClientBuffers& operator=(ClientBuffers const&) = delete;
41 virtual ~ClientBuffers() = default;
42 ClientBuffers() = default;
43};
44}
45}
46#endif /* MIR_FRONTEND_CLIENT_BUFFERS_H_ */
470
=== modified file 'include/server/mir/frontend/session.h'
--- include/server/mir/frontend/session.h 2017-05-08 03:04:26 +0000
+++ include/server/mir/frontend/session.h 2017-07-18 03:23:56 +0000
@@ -57,12 +57,6 @@
57 virtual BufferStreamId create_buffer_stream(graphics::BufferProperties const& props) = 0;57 virtual BufferStreamId create_buffer_stream(graphics::BufferProperties const& props) = 0;
58 virtual void destroy_buffer_stream(BufferStreamId stream) = 0;58 virtual void destroy_buffer_stream(BufferStreamId stream) = 0;
5959
60 virtual graphics::BufferID create_buffer(graphics::BufferProperties const& properties) = 0;
61 virtual graphics::BufferID create_buffer(geometry::Size, MirPixelFormat) = 0;
62 virtual graphics::BufferID create_buffer(geometry::Size, uint32_t native_format, uint32_t native_flags) = 0;
63 virtual void destroy_buffer(graphics::BufferID) = 0;
64 virtual std::shared_ptr<graphics::Buffer> get_buffer(graphics::BufferID) = 0;
65
66 virtual std::string name() const = 0;60 virtual std::string name() const = 0;
6761
68 virtual void send_display_config(graphics::DisplayConfiguration const&) = 0;62 virtual void send_display_config(graphics::DisplayConfiguration const&) = 0;
6963
=== modified file 'include/server/mir/scene/buffer_stream_factory.h'
--- include/server/mir/scene/buffer_stream_factory.h 2017-05-08 03:04:26 +0000
+++ include/server/mir/scene/buffer_stream_factory.h 2017-07-18 03:23:56 +0000
@@ -28,7 +28,6 @@
28{28{
29namespace compositor { class BufferStream; }29namespace compositor { class BufferStream; }
30namespace graphics { struct BufferProperties; }30namespace graphics { struct BufferProperties; }
31namespace frontend { class ClientBuffers; class BufferSink; }
32namespace scene31namespace scene
33{32{
34class BufferStreamFactory33class BufferStreamFactory
@@ -37,13 +36,12 @@
37 virtual ~BufferStreamFactory() = default;36 virtual ~BufferStreamFactory() = default;
3837
39 virtual std::shared_ptr<compositor::BufferStream> create_buffer_stream(38 virtual std::shared_ptr<compositor::BufferStream> create_buffer_stream(
40 frontend::BufferStreamId, std::shared_ptr<frontend::ClientBuffers> const& sink,39 frontend::BufferStreamId,
41 int nbuffers, graphics::BufferProperties const& buffer_properties) = 0;40 int nbuffers,
41 graphics::BufferProperties const& buffer_properties) = 0;
42 virtual std::shared_ptr<compositor::BufferStream> create_buffer_stream(42 virtual std::shared_ptr<compositor::BufferStream> create_buffer_stream(
43 frontend::BufferStreamId, std::shared_ptr<frontend::ClientBuffers> const& sink,43 frontend::BufferStreamId,
44 graphics::BufferProperties const& buffer_properties) = 0;44 graphics::BufferProperties const& buffer_properties) = 0;
45 virtual std::shared_ptr<frontend::ClientBuffers> create_buffer_map(
46 std::shared_ptr<frontend::BufferSink> const& sink) = 0;
4745
48protected:46protected:
49 BufferStreamFactory() = default;47 BufferStreamFactory() = default;
5048
=== modified file 'include/server/mir/scene/session.h'
--- include/server/mir/scene/session.h 2017-05-08 03:04:26 +0000
+++ include/server/mir/scene/session.h 2017-07-18 03:23:56 +0000
@@ -65,12 +65,6 @@
65 virtual void destroy_buffer_stream(frontend::BufferStreamId stream) = 0;65 virtual void destroy_buffer_stream(frontend::BufferStreamId stream) = 0;
66 virtual void configure_streams(Surface& surface, std::vector<shell::StreamSpecification> const& config) = 0;66 virtual void configure_streams(Surface& surface, std::vector<shell::StreamSpecification> const& config) = 0;
67 virtual void destroy_surface(std::weak_ptr<Surface> const& surface) = 0;67 virtual void destroy_surface(std::weak_ptr<Surface> const& surface) = 0;
68
69 virtual graphics::BufferID create_buffer(graphics::BufferProperties const& properties) = 0;
70 virtual graphics::BufferID create_buffer(geometry::Size, MirPixelFormat) = 0;
71 virtual graphics::BufferID create_buffer(geometry::Size, uint32_t native_format, uint32_t native_flags) = 0;
72 virtual void destroy_buffer(graphics::BufferID) = 0;
73 virtual std::shared_ptr<graphics::Buffer> get_buffer(graphics::BufferID) = 0;
74};68};
75}69}
76}70}
7771
=== modified file 'include/server/mir/shell/window_management_info.h'
--- include/server/mir/shell/window_management_info.h 2017-05-08 03:04:26 +0000
+++ include/server/mir/shell/window_management_info.h 2017-07-18 03:23:56 +0000
@@ -28,6 +28,10 @@
28namespace mir28namespace mir
29{29{
30namespace scene { class Session; class Surface; struct SurfaceCreationParameters; }30namespace scene { class Session; class Surface; struct SurfaceCreationParameters; }
31namespace graphics
32{
33class GraphicBufferAllocator;
34}
31namespace shell35namespace shell
32{36{
33struct SurfaceInfo37struct SurfaceInfo
@@ -78,7 +82,7 @@
78 mir::optional_value<graphics::DisplayConfigurationOutputId> output_id;82 mir::optional_value<graphics::DisplayConfigurationOutputId> output_id;
79 mir::optional_value<MirPointerConfinementState> confine_pointer;83 mir::optional_value<MirPointerConfinementState> confine_pointer;
8084
81 void init_titlebar(std::shared_ptr<scene::Session> const& session, std::shared_ptr<scene::Surface> const& surface);85 void init_titlebar(graphics::GraphicBufferAllocator& allocator, std::shared_ptr<scene::Surface> const& surface);
82 void paint_titlebar(int intensity);86 void paint_titlebar(int intensity);
8387
84private:88private:
8589
=== modified file 'include/test/mir/test/doubles/stub_session.h'
--- include/test/mir/test/doubles/stub_session.h 2017-05-08 03:04:26 +0000
+++ include/test/mir/test/doubles/stub_session.h 2017-07-18 03:23:56 +0000
@@ -89,12 +89,6 @@
8989
90 void send_input_config(MirInputConfig const& config) override;90 void send_input_config(MirInputConfig const& config) override;
9191
92 graphics::BufferID create_buffer(graphics::BufferProperties const& properties) override;
93 graphics::BufferID create_buffer(geometry::Size, MirPixelFormat) override;
94 graphics::BufferID create_buffer(geometry::Size, uint32_t native_format, uint32_t native_flags) override;
95 void destroy_buffer(graphics::BufferID) override;
96 std::shared_ptr<graphics::Buffer> get_buffer(graphics::BufferID) override;
97
98 pid_t pid;92 pid_t pid;
99};93};
100}94}
10195
=== modified file 'src/client/buffer_vault.cpp'
--- src/client/buffer_vault.cpp 2017-05-17 04:48:46 +0000
+++ src/client/buffer_vault.cpp 2017-07-18 03:23:56 +0000
@@ -86,11 +86,15 @@
86 {86 {
87 if (auto map = surface_map.lock())87 if (auto map = surface_map.lock())
88 {88 {
89 auto buffer = map->buffer(it.first);89 if (auto buffer = map->buffer(it.first))
90 buffer->set_callback(ignore_buffer, nullptr);90 {
91 buffer->set_callback(ignore_buffer, nullptr);
92 }
91 } 93 }
92 if (!disconnected_)94 if (!disconnected_)
95 {
93 free_buffer(it.first);96 free_buffer(it.first);
97 }
94 }98 }
95 catch (...)99 catch (...)
96 {100 {
@@ -110,6 +114,10 @@
110void mcl::BufferVault::free_buffer(int free_id)114void mcl::BufferVault::free_buffer(int free_id)
111{115{
112 server_requests->free_buffer(free_id);116 server_requests->free_buffer(free_id);
117 if (auto map = surface_map.lock())
118 {
119 map->erase(free_id);
120 }
113}121}
114122
115void mcl::BufferVault::realloc_buffer(int free_id, geom::Size size, MirPixelFormat format, int usage)123void mcl::BufferVault::realloc_buffer(int free_id, geom::Size size, MirPixelFormat format, int usage)
116124
=== modified file 'src/client/connection_surface_map.cpp'
--- src/client/connection_surface_map.cpp 2017-05-08 03:04:26 +0000
+++ src/client/connection_surface_map.cpp 2017-07-18 03:23:56 +0000
@@ -107,7 +107,7 @@
107 if (it != buffers.end())107 if (it != buffers.end())
108 return it->second;108 return it->second;
109 else109 else
110 BOOST_THROW_EXCEPTION(std::runtime_error("could not find buffer"));110 return nullptr;
111}111}
112112
113void mcl::ConnectionSurfaceMap::erase(void* render_surface_key)113void mcl::ConnectionSurfaceMap::erase(void* render_surface_key)
114114
=== modified file 'src/client/mir_connection.cpp'
--- src/client/mir_connection.cpp 2017-06-30 11:32:37 +0000
+++ src/client/mir_connection.cpp 2017-07-18 03:23:56 +0000
@@ -1305,7 +1305,6 @@
1305 MirBufferCallback callback, void* context)1305 MirBufferCallback callback, void* context)
1306{1306{
1307 mp::BufferAllocation request;1307 mp::BufferAllocation request;
1308 request.mutable_id()->set_value(-1);
1309 auto buffer_request = request.add_buffer_requests();1308 auto buffer_request = request.add_buffer_requests();
1310 buffer_request->set_width(size.width.as_int());1309 buffer_request->set_width(size.width.as_int());
1311 buffer_request->set_height(size.height.as_int());1310 buffer_request->set_height(size.height.as_int());
@@ -1323,16 +1322,15 @@
13231322
1324void MirConnection::release_buffer(mcl::MirBuffer* buffer)1323void MirConnection::release_buffer(mcl::MirBuffer* buffer)
1325{1324{
1326 if (!buffer->valid())1325 if (buffer->valid())
1327 {1326 {
1328 surface_map->erase(buffer->rpc_id());1327 mp::BufferRelease request;
1329 return;1328 auto released_buffer = request.add_buffers();
1329 released_buffer->set_buffer_id(buffer->rpc_id());
1330 server.release_buffers(&request, ignored.get(), gp::NewCallback(ignore));
1330 }1331 }
13311332
1332 mp::BufferRelease request;1333 surface_map->erase(buffer->rpc_id());
1333 auto released_buffer = request.add_buffers();
1334 released_buffer->set_buffer_id(buffer->rpc_id());
1335 server.release_buffers(&request, ignored.get(), gp::NewCallback(ignore));
1336}1334}
13371335
1338void MirConnection::release_render_surface_with_content(1336void MirConnection::release_render_surface_with_content(
13391337
=== modified file 'src/client/rpc/mir_protobuf_rpc_channel.cpp'
--- src/client/rpc/mir_protobuf_rpc_channel.cpp 2017-05-08 03:04:26 +0000
+++ src/client/rpc/mir_protobuf_rpc_channel.cpp 2017-07-18 03:23:56 +0000
@@ -359,11 +359,19 @@
359 buffer->received();359 buffer->received();
360 break;360 break;
361 case mp::BufferOperation::update:361 case mp::BufferOperation::update:
362 map->buffer(buffer_id)->received(362 buffer = map->buffer(buffer_id);
363 *mcl::protobuf_to_native_buffer(seq.buffer_request().buffer()));363 if (buffer)
364 {
365 buffer->received(
366 *mcl::protobuf_to_native_buffer(seq.buffer_request().buffer()));
367 }
364 break;368 break;
365 case mp::BufferOperation::remove:369 case mp::BufferOperation::remove:
366 map->erase(buffer_id);370 /* The server never sends us an unsolicited ::remove request
371 * (and clients have no way of dealing with one)
372 *
373 * Just ignore it, because we've already deleted our buffer.
374 */
367 break;375 break;
368 default:376 default:
369 BOOST_THROW_EXCEPTION(std::runtime_error("unknown buffer operation"));377 BOOST_THROW_EXCEPTION(std::runtime_error("unknown buffer operation"));
370378
=== modified file 'src/server/compositor/CMakeLists.txt'
--- src/server/compositor/CMakeLists.txt 2017-05-08 03:04:26 +0000
+++ src/server/compositor/CMakeLists.txt 2017-07-18 03:23:56 +0000
@@ -18,7 +18,6 @@
18 compositing_screencast.cpp18 compositing_screencast.cpp
19 stream.cpp19 stream.cpp
20 multi_monitor_arbiter.cpp20 multi_monitor_arbiter.cpp
21 buffer_map.cpp
22 dropping_schedule.cpp21 dropping_schedule.cpp
23 queueing_schedule.cpp22 queueing_schedule.cpp
24)23)
2524
=== removed file 'src/server/compositor/buffer_map.cpp'
--- src/server/compositor/buffer_map.cpp 2017-05-08 03:04:26 +0000
+++ src/server/compositor/buffer_map.cpp 1970-01-01 00:00:00 +0000
@@ -1,116 +0,0 @@
1/*
2 * Copyright © 2015 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * 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/graphics/buffer.h"
20#include "mir/frontend/buffer_sink.h"
21#include "buffer_map.h"
22#include <boost/throw_exception.hpp>
23#include <algorithm>
24
25namespace mc = mir::compositor;
26namespace mf = mir::frontend;
27namespace mg = mir::graphics;
28
29namespace mir
30{
31namespace compositor
32{
33enum class BufferMap::Owner
34{
35 server,
36 client
37};
38}
39}
40
41mc::BufferMap::BufferMap(std::shared_ptr<mf::BufferSink> const& sink) :
42 sink(sink)
43{
44}
45
46mg::BufferID mc::BufferMap::add_buffer(std::shared_ptr<mg::Buffer> const& buffer)
47{
48 try
49 {
50 std::unique_lock<decltype(mutex)> lk(mutex);
51 buffers[buffer->id()] = {buffer, Owner::client};
52 if (auto s = sink.lock())
53 s->add_buffer(*buffer);
54 return buffer->id();
55 } catch (std::exception& e)
56 {
57 if (auto s = sink.lock())
58 s->error_buffer(buffer->size(), buffer->pixel_format(), e.what());
59 throw;
60 }
61}
62
63void mc::BufferMap::remove_buffer(mg::BufferID id)
64{
65 std::unique_lock<decltype(mutex)> lk(mutex);
66 auto it = checked_buffers_find(id, lk);
67 if (auto s = sink.lock())
68 s->remove_buffer(*it->second.buffer);
69 buffers.erase(it);
70}
71
72void mc::BufferMap::send_buffer(mg::BufferID id)
73{
74 std::unique_lock<decltype(mutex)> lk(mutex);
75 auto it = buffers.find(id);
76 if (it != buffers.end())
77 {
78 auto buffer = it->second.buffer;
79 it->second.owner = Owner::client;
80 lk.unlock();
81 if (auto s = sink.lock())
82 s->update_buffer(*buffer);
83 }
84}
85
86void mc::BufferMap::receive_buffer(graphics::BufferID id)
87{
88 std::unique_lock<decltype(mutex)> lk(mutex);
89 auto it = buffers.find(id);
90 if (it != buffers.end())
91 it->second.owner = Owner::server;
92}
93
94std::shared_ptr<mg::Buffer> mc::BufferMap::get(mg::BufferID id) const
95{
96 std::unique_lock<decltype(mutex)> lk(mutex);
97 return checked_buffers_find(id, lk)->second.buffer;
98}
99
100mc::BufferMap::Map::iterator mc::BufferMap::checked_buffers_find(
101 mg::BufferID id, std::unique_lock<std::mutex> const&)
102{
103 auto it = buffers.find(id);
104 if (it == buffers.end())
105 BOOST_THROW_EXCEPTION(std::logic_error("cannot find buffer by id"));
106 return it;
107}
108
109mc::BufferMap::Map::const_iterator mc::BufferMap::checked_buffers_find(
110 mg::BufferID id, std::unique_lock<std::mutex> const&) const
111{
112 auto it = buffers.find(id);
113 if (it == buffers.end())
114 BOOST_THROW_EXCEPTION(std::logic_error("cannot find buffer by id"));
115 return it;
116}
1170
=== removed file 'src/server/compositor/buffer_map.h'
--- src/server/compositor/buffer_map.h 2017-05-08 03:04:26 +0000
+++ src/server/compositor/buffer_map.h 1970-01-01 00:00:00 +0000
@@ -1,65 +0,0 @@
1/*
2 * Copyright © 2015 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * 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#ifndef MIR_COMPOSITOR_BUFFER_MAP_H_
20#define MIR_COMPOSITOR_BUFFER_MAP_H_
21
22#include "mir/frontend/client_buffers.h"
23#include <mutex>
24#include <map>
25
26namespace mir
27{
28namespace frontend { class BufferSink; }
29namespace compositor
30{
31class BufferMap : public frontend::ClientBuffers
32{
33public:
34 BufferMap(std::shared_ptr<frontend::BufferSink> const& sink);
35
36 graphics::BufferID add_buffer(std::shared_ptr<graphics::Buffer> const& buffer) override;
37 void remove_buffer(graphics::BufferID id) override;
38
39 void receive_buffer(graphics::BufferID id) override;
40 void send_buffer(graphics::BufferID id) override;
41
42 std::shared_ptr<graphics::Buffer> get(graphics::BufferID) const override;
43
44private:
45 std::mutex mutable mutex;
46
47 enum class Owner;
48 struct MapEntry
49 {
50 std::shared_ptr<graphics::Buffer> buffer;
51 Owner owner;
52 };
53 typedef std::map<graphics::BufferID, MapEntry> Map;
54 //used to keep strong reference
55 Map buffers;
56 Map::iterator checked_buffers_find(graphics::BufferID, std::unique_lock<std::mutex> const&);
57 Map::const_iterator checked_buffers_find(graphics::BufferID, std::unique_lock<std::mutex> const&) const;
58
59 //would be better to schedule the async buffer callbacks in the ipc subsystem,
60 //instead of driving from within the compositor threads (LP: #1395421)
61 std::weak_ptr<frontend::BufferSink> const sink;
62};
63}
64}
65#endif /* MIR_COMPOSITOR_BUFFER_MAP_H_ */
660
=== modified file 'src/server/compositor/buffer_stream_factory.cpp'
--- src/server/compositor/buffer_stream_factory.cpp 2017-05-08 03:04:26 +0000
+++ src/server/compositor/buffer_stream_factory.cpp 2017-07-18 03:23:56 +0000
@@ -21,7 +21,6 @@
21#include "buffer_stream_factory.h"21#include "buffer_stream_factory.h"
22#include "mir/graphics/buffer_properties.h"22#include "mir/graphics/buffer_properties.h"
23#include "stream.h"23#include "stream.h"
24#include "buffer_map.h"
25#include "mir/graphics/buffer.h"24#include "mir/graphics/buffer.h"
26#include "mir/graphics/buffer_id.h"25#include "mir/graphics/buffer_id.h"
27#include "mir/graphics/graphic_buffer_allocator.h"26#include "mir/graphics/graphic_buffer_allocator.h"
@@ -40,23 +39,17 @@
40}39}
4140
42std::shared_ptr<mc::BufferStream> mc::BufferStreamFactory::create_buffer_stream(41std::shared_ptr<mc::BufferStream> mc::BufferStreamFactory::create_buffer_stream(
43 mf::BufferStreamId id, std::shared_ptr<mf::ClientBuffers> const& buffers,42 mf::BufferStreamId id,
44 mg::BufferProperties const& buffer_properties)43 mg::BufferProperties const& buffer_properties)
45{44{
46 return create_buffer_stream(id, buffers, 0, buffer_properties);45 return create_buffer_stream(id, 0, buffer_properties);
47}46}
4847
49std::shared_ptr<mc::BufferStream> mc::BufferStreamFactory::create_buffer_stream(48std::shared_ptr<mc::BufferStream> mc::BufferStreamFactory::create_buffer_stream(
50 mf::BufferStreamId, std::shared_ptr<mf::ClientBuffers> const& buffers,49 mf::BufferStreamId,
51 int, mg::BufferProperties const& buffer_properties)50 int,
51 mg::BufferProperties const& buffer_properties)
52{52{
53 return std::make_shared<mc::Stream>(53 return std::make_shared<mc::Stream>(
54 buffers,
55 buffer_properties.size, buffer_properties.format);54 buffer_properties.size, buffer_properties.format);
56}55}
57
58std::shared_ptr<mf::ClientBuffers> mc::BufferStreamFactory::create_buffer_map(
59 std::shared_ptr<mf::BufferSink> const& sink)
60{
61 return std::make_shared<mc::BufferMap>(sink);
62}
6356
=== modified file 'src/server/compositor/buffer_stream_factory.h'
--- src/server/compositor/buffer_stream_factory.h 2017-05-08 03:04:26 +0000
+++ src/server/compositor/buffer_stream_factory.h 2017-07-18 03:23:56 +0000
@@ -42,13 +42,12 @@
42 virtual ~BufferStreamFactory() {}42 virtual ~BufferStreamFactory() {}
4343
44 virtual std::shared_ptr<compositor::BufferStream> create_buffer_stream(44 virtual std::shared_ptr<compositor::BufferStream> create_buffer_stream(
45 frontend::BufferStreamId, std::shared_ptr<frontend::ClientBuffers> const& sink,45 frontend::BufferStreamId,
46 int nbuffers, graphics::BufferProperties const& buffer_properties) override;46 int nbuffers,
47 graphics::BufferProperties const& buffer_properties) override;
47 virtual std::shared_ptr<BufferStream> create_buffer_stream(48 virtual std::shared_ptr<BufferStream> create_buffer_stream(
48 frontend::BufferStreamId, std::shared_ptr<frontend::ClientBuffers> const& sink,49 frontend::BufferStreamId,
49 graphics::BufferProperties const&) override;50 graphics::BufferProperties const&) override;
50 virtual std::shared_ptr<frontend::ClientBuffers> create_buffer_map(
51 std::shared_ptr<frontend::BufferSink> const& sink) override;
52};51};
5352
54}53}
5554
=== modified file 'src/server/compositor/dropping_schedule.cpp'
--- src/server/compositor/dropping_schedule.cpp 2017-05-08 03:04:26 +0000
+++ src/server/compositor/dropping_schedule.cpp 2017-07-18 03:23:56 +0000
@@ -17,16 +17,13 @@
17 */17 */
1818
19#include "dropping_schedule.h"19#include "dropping_schedule.h"
20#include "mir/frontend/client_buffers.h"
21#include "mir/graphics/buffer.h"20#include "mir/graphics/buffer.h"
2221
23#include <boost/throw_exception.hpp>22#include <boost/throw_exception.hpp>
24namespace mf = mir::frontend;
25namespace mg = mir::graphics;23namespace mg = mir::graphics;
26namespace mc = mir::compositor;24namespace mc = mir::compositor;
2725
28mc::DroppingSchedule::DroppingSchedule(std::shared_ptr<mf::ClientBuffers> const& client_buffers) :26mc::DroppingSchedule::DroppingSchedule()
29 sender(client_buffers)
30{27{
31}28}
3229
@@ -42,14 +39,6 @@
42{39{
43 std::future<void> drop;40 std::future<void> drop;
44 std::lock_guard<decltype(mutex)> lk(mutex);41 std::lock_guard<decltype(mutex)> lk(mutex);
45 if ((the_only_buffer != buffer) && the_only_buffer)
46 {
47 drop = std::async(std::launch::deferred,
48 [sender=sender, dropped=the_only_buffer]()
49 {
50 sender->send_buffer(dropped->id());
51 });
52 }
53 the_only_buffer = buffer;42 the_only_buffer = buffer;
54 return drop;43 return drop;
55}44}
5645
=== modified file 'src/server/compositor/dropping_schedule.h'
--- src/server/compositor/dropping_schedule.h 2017-05-08 03:04:26 +0000
+++ src/server/compositor/dropping_schedule.h 2017-07-18 03:23:56 +0000
@@ -25,13 +25,12 @@
25namespace mir25namespace mir
26{26{
27namespace graphics { class Buffer; }27namespace graphics { class Buffer; }
28namespace frontend { class ClientBuffers; }
29namespace compositor28namespace compositor
30{29{
31class DroppingSchedule : public Schedule30class DroppingSchedule : public Schedule
32{31{
33public:32public:
34 DroppingSchedule(std::shared_ptr<frontend::ClientBuffers> const&);33 DroppingSchedule();
35 void schedule(std::shared_ptr<graphics::Buffer> const& buffer) override;34 void schedule(std::shared_ptr<graphics::Buffer> const& buffer) override;
36 std::future<void> schedule_nonblocking(35 std::future<void> schedule_nonblocking(
37 std::shared_ptr<graphics::Buffer> const& buffer) override;36 std::shared_ptr<graphics::Buffer> const& buffer) override;
@@ -40,7 +39,6 @@
4039
41private:40private:
42 std::mutex mutable mutex;41 std::mutex mutable mutex;
43 std::shared_ptr<frontend::ClientBuffers> const sender;
44 std::shared_ptr<graphics::Buffer> the_only_buffer;42 std::shared_ptr<graphics::Buffer> the_only_buffer;
45};43};
46}44}
4745
=== modified file 'src/server/compositor/multi_monitor_arbiter.cpp'
--- src/server/compositor/multi_monitor_arbiter.cpp 2017-05-26 12:45:45 +0000
+++ src/server/compositor/multi_monitor_arbiter.cpp 2017-07-18 03:23:56 +0000
@@ -20,7 +20,6 @@
20#include "mir/graphics/buffer.h"20#include "mir/graphics/buffer.h"
21#include "mir/graphics/graphic_buffer_allocator.h"21#include "mir/graphics/graphic_buffer_allocator.h"
22#include "mir/frontend/event_sink.h"22#include "mir/frontend/event_sink.h"
23#include "mir/frontend/client_buffers.h"
24#include "schedule.h"23#include "schedule.h"
25#include <boost/throw_exception.hpp>24#include <boost/throw_exception.hpp>
26#include <algorithm>25#include <algorithm>
@@ -30,9 +29,7 @@
30namespace mf = mir::frontend;29namespace mf = mir::frontend;
3130
32mc::MultiMonitorArbiter::MultiMonitorArbiter(31mc::MultiMonitorArbiter::MultiMonitorArbiter(
33 std::shared_ptr<frontend::ClientBuffers> const& map,
34 std::shared_ptr<Schedule> const& schedule) :32 std::shared_ptr<Schedule> const& schedule) :
35 map(map),
36 schedule(schedule)33 schedule(schedule)
37{34{
38}35}
@@ -43,7 +40,7 @@
43 for(auto it = onscreen_buffers.begin(); it != onscreen_buffers.end(); it++)40 for(auto it = onscreen_buffers.begin(); it != onscreen_buffers.end(); it++)
44 {41 {
45 if (it->use_count == 0)42 if (it->use_count == 0)
46 map->send_buffer(it->buffer->id());43 it->buffer.reset();
47 }44 }
4845
49}46}
@@ -96,7 +93,6 @@
96 if ((it->use_count == 0) &&93 if ((it->use_count == 0) &&
97 (it != onscreen_buffers.begin() || schedule->num_scheduled())) //ensure monitors always have a buffer94 (it != onscreen_buffers.begin() || schedule->num_scheduled())) //ensure monitors always have a buffer
98 {95 {
99 map->send_buffer(it->buffer->id());
100 it = onscreen_buffers.erase(it);96 it = onscreen_buffers.erase(it);
101 }97 }
102 else98 else
10399
=== modified file 'src/server/compositor/multi_monitor_arbiter.h'
--- src/server/compositor/multi_monitor_arbiter.h 2017-05-25 05:49:36 +0000
+++ src/server/compositor/multi_monitor_arbiter.h 2017-07-18 03:23:56 +0000
@@ -38,7 +38,6 @@
38{38{
39public:39public:
40 MultiMonitorArbiter(40 MultiMonitorArbiter(
41 std::shared_ptr<frontend::ClientBuffers> const& map,
42 std::shared_ptr<Schedule> const& schedule);41 std::shared_ptr<Schedule> const& schedule);
43 ~MultiMonitorArbiter();42 ~MultiMonitorArbiter();
4443
@@ -56,7 +55,6 @@
56 void clean_onscreen_buffers(std::lock_guard<std::mutex> const&);55 void clean_onscreen_buffers(std::lock_guard<std::mutex> const&);
5756
58 std::mutex mutable mutex;57 std::mutex mutable mutex;
59 std::shared_ptr<frontend::ClientBuffers> const map;
60 struct ScheduleEntry58 struct ScheduleEntry
61 {59 {
62 ScheduleEntry(std::shared_ptr<graphics::Buffer> const& buffer, unsigned int use_count) :60 ScheduleEntry(std::shared_ptr<graphics::Buffer> const& buffer, unsigned int use_count) :
6361
=== modified file 'src/server/compositor/stream.cpp'
--- src/server/compositor/stream.cpp 2017-05-25 05:49:36 +0000
+++ src/server/compositor/stream.cpp 2017-07-18 03:23:56 +0000
@@ -21,7 +21,6 @@
21#include "queueing_schedule.h"21#include "queueing_schedule.h"
22#include "dropping_schedule.h"22#include "dropping_schedule.h"
23#include "temporary_buffers.h"23#include "temporary_buffers.h"
24#include "mir/frontend/client_buffers.h"
25#include "mir/graphics/buffer.h"24#include "mir/graphics/buffer.h"
26#include <boost/throw_exception.hpp>25#include <boost/throw_exception.hpp>
2726
@@ -37,22 +36,17 @@
37};36};
3837
39mc::Stream::Stream(38mc::Stream::Stream(
40 std::shared_ptr<frontend::ClientBuffers> map, geom::Size size, MirPixelFormat pf) :39 geom::Size size, MirPixelFormat pf) :
41 schedule_mode(ScheduleMode::Queueing),40 schedule_mode(ScheduleMode::Queueing),
42 schedule(std::make_shared<mc::QueueingSchedule>()),41 schedule(std::make_shared<mc::QueueingSchedule>()),
43 buffers(map),42 arbiter(std::make_shared<mc::MultiMonitorArbiter>(schedule)),
44 arbiter(std::make_shared<mc::MultiMonitorArbiter>(buffers, schedule)),
45 size(size),43 size(size),
46 pf(pf),44 pf(pf),
47 first_frame_posted(false)45 first_frame_posted(false)
48{46{
49}47}
5048
51mc::Stream::~Stream()49mc::Stream::~Stream() = default;
52{
53 while(schedule->num_scheduled())
54 buffers->send_buffer(schedule->next_buffer()->id());
55}
5650
57unsigned int mc::Stream::client_owned_buffer_count(std::lock_guard<decltype(mutex)> const&) const51unsigned int mc::Stream::client_owned_buffer_count(std::lock_guard<decltype(mutex)> const&) const
58{52{
@@ -72,9 +66,8 @@
72 {66 {
73 std::lock_guard<decltype(mutex)> lk(mutex); 67 std::lock_guard<decltype(mutex)> lk(mutex);
74 first_frame_posted = true;68 first_frame_posted = true;
75 buffers->receive_buffer(buffer->id());
76 deferred_io = schedule->schedule_nonblocking(buffers->get(buffer->id()));
77 pf = buffer->pixel_format();69 pf = buffer->pixel_format();
70 deferred_io = schedule->schedule_nonblocking(buffer);
78 }71 }
79 observers.frame_posted(1, buffer->size());72 observers.frame_posted(1, buffer->size());
8073
@@ -134,7 +127,7 @@
134 std::lock_guard<decltype(mutex)> lk(mutex); 127 std::lock_guard<decltype(mutex)> lk(mutex);
135 if (dropping && schedule_mode == ScheduleMode::Queueing)128 if (dropping && schedule_mode == ScheduleMode::Queueing)
136 {129 {
137 transition_schedule(std::make_shared<mc::DroppingSchedule>(buffers), lk);130 transition_schedule(std::make_shared<mc::DroppingSchedule>(), lk);
138 schedule_mode = ScheduleMode::Dropping;131 schedule_mode = ScheduleMode::Dropping;
139 }132 }
140 else if (!dropping && schedule_mode == ScheduleMode::Dropping)133 else if (!dropping && schedule_mode == ScheduleMode::Dropping)
@@ -182,9 +175,6 @@
182 transferred_buffers.pop_back();175 transferred_buffers.pop_back();
183 }176 }
184177
185 for (auto &buffer : transferred_buffers)
186 buffers->send_buffer(buffer->id());
187
188 arbiter->advance_schedule();178 arbiter->advance_schedule();
189}179}
190180
@@ -214,15 +204,7 @@
214204
215bool mc::Stream::suitable_for_cursor() const205bool mc::Stream::suitable_for_cursor() const
216{206{
217 if (associated_buffers.empty())207 // We can't reasonably answer this question -
218 {208 // Suitability for cursor use is a per-buffer property, not a per-stream property.
219 return true;
220 }
221 else
222 {
223 for (auto it : associated_buffers)
224 if (buffers->get(it)->pixel_format() != mir_pixel_format_argb_8888)
225 return false;
226 }
227 return true;209 return true;
228}210}
229211
=== modified file 'src/server/compositor/stream.h'
--- src/server/compositor/stream.h 2017-05-22 11:53:51 +0000
+++ src/server/compositor/stream.h 2017-07-18 03:23:56 +0000
@@ -39,7 +39,7 @@
39class Stream : public BufferStream39class Stream : public BufferStream
40{40{
41public:41public:
42 Stream(std::shared_ptr<frontend::ClientBuffers>, geometry::Size sz, MirPixelFormat format);42 Stream(geometry::Size sz, MirPixelFormat format);
43 ~Stream();43 ~Stream();
4444
45 void submit_buffer(std::shared_ptr<graphics::Buffer> const& buffer) override;45 void submit_buffer(std::shared_ptr<graphics::Buffer> const& buffer) override;
@@ -68,7 +68,6 @@
68 std::mutex mutable mutex;68 std::mutex mutable mutex;
69 ScheduleMode schedule_mode;69 ScheduleMode schedule_mode;
70 std::shared_ptr<Schedule> schedule;70 std::shared_ptr<Schedule> schedule;
71 std::shared_ptr<frontend::ClientBuffers> const buffers;
72 std::shared_ptr<MultiMonitorArbiter> const arbiter;71 std::shared_ptr<MultiMonitorArbiter> const arbiter;
73 geometry::Size size; 72 geometry::Size size;
74 MirPixelFormat pf;73 MirPixelFormat pf;
7574
=== modified file 'src/server/frontend/default_ipc_factory.cpp'
--- src/server/frontend/default_ipc_factory.cpp 2017-05-08 03:04:26 +0000
+++ src/server/frontend/default_ipc_factory.cpp 2017-07-18 03:23:56 +0000
@@ -26,6 +26,7 @@
26#include "resource_cache.h"26#include "resource_cache.h"
27#include "mir/frontend/session_authorizer.h"27#include "mir/frontend/session_authorizer.h"
28#include "mir/frontend/event_sink.h"28#include "mir/frontend/event_sink.h"
29#include "event_sink_factory.h"
29#include "mir/graphics/graphic_buffer_allocator.h"30#include "mir/graphics/graphic_buffer_allocator.h"
30#include "mir/cookie/authority.h"31#include "mir/cookie/authority.h"
3132
@@ -150,5 +151,6 @@
150 anr_detector,151 anr_detector,
151 cookie_authority,152 cookie_authority,
152 input_changer,153 input_changer,
153 extensions);154 extensions,
155 buffer_allocator);
154}156}
155157
=== modified file 'src/server/frontend/event_sender.cpp'
--- src/server/frontend/event_sender.cpp 2017-05-08 03:04:26 +0000
+++ src/server/frontend/event_sender.cpp 2017-07-18 03:23:56 +0000
@@ -143,14 +143,6 @@
143 send_event_sequence(seq, {});143 send_event_sequence(seq, {});
144}144}
145145
146void mfd::EventSender::remove_buffer(graphics::Buffer& buffer)
147{
148 mp::EventSequence seq;
149 auto request = seq.mutable_buffer_request();
150 request->set_operation(mir::protobuf::BufferOperation::remove);
151 send_buffer(seq, buffer, mg::BufferIpcMsgType::update_msg);
152}
153
154void mfd::EventSender::update_buffer(graphics::Buffer& buffer)146void mfd::EventSender::update_buffer(graphics::Buffer& buffer)
155{147{
156 mp::EventSequence seq;148 mp::EventSequence seq;
157149
=== modified file 'src/server/frontend/event_sender.h'
--- src/server/frontend/event_sender.h 2017-05-08 03:04:26 +0000
+++ src/server/frontend/event_sender.h 2017-07-18 03:23:56 +0000
@@ -52,7 +52,6 @@
52 void send_buffer(frontend::BufferStreamId id, graphics::Buffer& buffer, graphics::BufferIpcMsgType) override;52 void send_buffer(frontend::BufferStreamId id, graphics::Buffer& buffer, graphics::BufferIpcMsgType) override;
53 void add_buffer(graphics::Buffer&) override;53 void add_buffer(graphics::Buffer&) override;
54 void error_buffer(geometry::Size, MirPixelFormat, std::string const&) override;54 void error_buffer(geometry::Size, MirPixelFormat, std::string const&) override;
55 void remove_buffer(graphics::Buffer&) override;
56 void update_buffer(graphics::Buffer&) override;55 void update_buffer(graphics::Buffer&) override;
5756
58private:57private:
5958
=== modified file 'src/server/frontend/session_mediator.cpp'
--- src/server/frontend/session_mediator.cpp 2017-06-01 13:04:37 +0000
+++ src/server/frontend/session_mediator.cpp 2017-07-18 03:23:56 +0000
@@ -59,6 +59,7 @@
59#include "mir/fd.h"59#include "mir/fd.h"
60#include "mir/cookie/authority.h"60#include "mir/cookie/authority.h"
61#include "mir/module_properties.h"61#include "mir/module_properties.h"
62#include "mir/graphics/graphic_buffer_allocator.h"
6263
63#include "mir/geometry/rectangles.h"64#include "mir/geometry/rectangles.h"
64#include "protobuf_buffer_packer.h"65#include "protobuf_buffer_packer.h"
@@ -110,7 +111,8 @@
110 std::shared_ptr<scene::ApplicationNotRespondingDetector> const& anr_detector,111 std::shared_ptr<scene::ApplicationNotRespondingDetector> const& anr_detector,
111 std::shared_ptr<mir::cookie::Authority> const& cookie_authority,112 std::shared_ptr<mir::cookie::Authority> const& cookie_authority,
112 std::shared_ptr<mf::InputConfigurationChanger> const& input_changer,113 std::shared_ptr<mf::InputConfigurationChanger> const& input_changer,
113 std::vector<mir::ExtensionDescription> const& extensions) :114 std::vector<mir::ExtensionDescription> const& extensions,
115 std::shared_ptr<mg::GraphicBufferAllocator> const& allocator) :
114 client_pid_(0),116 client_pid_(0),
115 shell(shell),117 shell(shell),
116 ipc_operations(ipc_operations),118 ipc_operations(ipc_operations),
@@ -128,7 +130,8 @@
128 anr_detector{anr_detector},130 anr_detector{anr_detector},
129 cookie_authority(cookie_authority),131 cookie_authority(cookie_authority),
130 input_changer(input_changer),132 input_changer(input_changer),
131 extensions(extensions)133 extensions(extensions),
134 allocator{allocator}
132{135{
133}136}
134137
@@ -374,6 +377,58 @@
374 buffering_sender->uncork();377 buffering_sender->uncork();
375}378}
376379
380namespace
381{
382 class AutoSendBuffer : public mg::Buffer
383 {
384 public:
385 AutoSendBuffer(
386 std::shared_ptr<mg::Buffer> const& wrapped,
387 std::weak_ptr<mf::BufferSink> const& sink)
388 : buffer{wrapped},
389 sink{sink}
390 {
391 }
392 ~AutoSendBuffer()
393 {
394 if (auto live_sink = sink.lock())
395 {
396 live_sink->update_buffer(*buffer);
397 }
398 }
399
400 std::shared_ptr<mir::graphics::NativeBuffer> native_buffer_handle() const override
401 {
402 return buffer->native_buffer_handle();
403 }
404
405 mir::graphics::BufferID id() const override
406 {
407 return buffer->id();
408 }
409
410 mir::geometry::Size size() const override
411 {
412 return buffer->size();
413 }
414
415 MirPixelFormat pixel_format() const override
416 {
417 return buffer->pixel_format();
418 }
419
420 mir::graphics::NativeBufferBase *native_buffer_base() override
421 {
422 return buffer->native_buffer_base();
423 }
424
425 private:
426 std::shared_ptr<mg::Buffer> const buffer;
427 std::weak_ptr<mf::BufferSink> const sink;
428 };
429
430}
431
377void mf::SessionMediator::submit_buffer(432void mf::SessionMediator::submit_buffer(
378 mir::protobuf::BufferRequest const* request,433 mir::protobuf::BufferRequest const* request,
379 mir::protobuf::Void*,434 mir::protobuf::Void*,
@@ -388,15 +443,37 @@
388 auto stream = session->get_buffer_stream(stream_id);443 auto stream = session->get_buffer_stream(stream_id);
389444
390 mfd::ProtobufBufferPacker request_msg{const_cast<mir::protobuf::Buffer*>(&request->buffer())};445 mfd::ProtobufBufferPacker request_msg{const_cast<mir::protobuf::Buffer*>(&request->buffer())};
391 auto b = session->get_buffer(buffer_id);446 auto b = buffer_cache.at(buffer_id);
392 ipc_operations->unpack_buffer(request_msg, *b);447 ipc_operations->unpack_buffer(request_msg, *b);
393448
394 stream->submit_buffer(b);449 stream->submit_buffer(std::make_shared<AutoSendBuffer>(b, event_sink));
395450
396 done->Run();451 done->Run();
397}452}
398453
399void mf::SessionMediator::allocate_buffers( 454namespace
455{
456bool validate_buffer_request(mir::protobuf::BufferStreamParameters const& req)
457{
458 // A valid buffer request has either flags & native_format set
459 // or buffer_usage & pixel_format set, not both.
460 return
461 (
462 req.has_pixel_format() &&
463 req.has_buffer_usage() &&
464 !req.has_native_format() &&
465 !req.has_flags()
466 ) ||
467 (
468 !req.has_pixel_format() &&
469 !req.has_buffer_usage() &&
470 req.has_native_format() &&
471 req.has_flags()
472 );
473}
474}
475
476void mf::SessionMediator::allocate_buffers(
400 mir::protobuf::BufferAllocation const* request,477 mir::protobuf::BufferAllocation const* request,
401 mir::protobuf::Void*,478 mir::protobuf::Void*,
402 google::protobuf::Closure* done)479 google::protobuf::Closure* done)
@@ -409,36 +486,54 @@
409 for (auto i = 0; i < request->buffer_requests().size(); i++)486 for (auto i = 0; i < request->buffer_requests().size(); i++)
410 {487 {
411 auto const& req = request->buffer_requests(i);488 auto const& req = request->buffer_requests(i);
489 std::shared_ptr<mg::Buffer> buffer;
490 try
491 {
492 if (!validate_buffer_request(req))
493 {
494 BOOST_THROW_EXCEPTION(std::logic_error("Invalid buffer request"));
495 }
412496
413 mg::BufferID id;497 if (req.has_flags() && req.has_native_format())
414 if (req.has_flags() && req.has_native_format())
415 {
416 id = session->create_buffer({req.width(), req.height()}, req.native_format(), req.flags());
417 }
418 else if (req.has_buffer_usage() && req.has_pixel_format())
419 {
420 auto const usage = static_cast<mg::BufferUsage>(req.buffer_usage());
421 geom::Size const size{req.width(), req.height()};
422 auto const pf = static_cast<MirPixelFormat>(req.pixel_format());
423 if (usage == mg::BufferUsage::software)
424 {498 {
425 id = session->create_buffer(size, pf); 499 buffer = allocator->alloc_buffer(
500 {req.width(), req.height()},
501 req.native_format(),
502 req.flags());
426 }503 }
427 else504 else
428 {505 {
429 //legacy route, server-selected pf and usage506 auto const usage = static_cast<mg::BufferUsage>(req.buffer_usage());
430 id = session->create_buffer(mg::BufferProperties{size, pf, mg::BufferUsage::hardware});507 geom::Size const size{req.width(), req.height()};
431 }508 auto const pf = static_cast<MirPixelFormat>(req.pixel_format());
432 }509 if (usage == mg::BufferUsage::software)
433 else510 {
434 {511 buffer = allocator->alloc_software_buffer(size, pf);
435 BOOST_THROW_EXCEPTION(std::logic_error("Invalid buffer request"));512 }
436 }513 else
437514 {
438 if (request->has_id())515 //legacy route, server-selected pf and usage
439 {516 buffer =
440 auto stream = session->get_buffer_stream(mf::BufferStreamId(request->id().value()));517 allocator->alloc_buffer(mg::BufferProperties{size, pf, mg::BufferUsage::hardware});
441 stream->associate_buffer(id);518 }
519 }
520
521 if (request->has_id())
522 {
523 auto stream = session->get_buffer_stream(mf::BufferStreamId(request->id().value()));
524 stream->associate_buffer(buffer->id());
525 }
526
527 // TODO: Throw if insert fails (duplicate ID)?
528 buffer_cache.insert(std::make_pair(buffer->id(), buffer));
529 event_sink->add_buffer(*buffer);
530 }
531 catch (std::exception const& err)
532 {
533 event_sink->error_buffer(
534 geom::Size{req.width(), req.height()},
535 static_cast<MirPixelFormat>(req.pixel_format()),
536 err.what());
442 }537 }
443 }538 }
444 done->Run();539 done->Run();
@@ -473,7 +568,7 @@
473 for (auto i = 0; i < request->buffers().size(); i++)568 for (auto i = 0; i < request->buffers().size(); i++)
474 {569 {
475 mg::BufferID buffer_id{static_cast<uint32_t>(request->buffers(i).buffer_id())};570 mg::BufferID buffer_id{static_cast<uint32_t>(request->buffers(i).buffer_id())};
476 session->destroy_buffer(buffer_id);571 buffer_cache.erase(buffer_id);
477 }572 }
478 done->Run();573 done->Run();
479}574}
@@ -869,7 +964,7 @@
869{964{
870 auto session = weak_session.lock();965 auto session = weak_session.lock();
871 ScreencastSessionId const screencast_session_id{request->id().value()};966 ScreencastSessionId const screencast_session_id{request->id().value()};
872 auto buffer = session->get_buffer(mg::BufferID{request->buffer_id()});967 auto buffer = buffer_cache.at(mg::BufferID{request->buffer_id()});
873 screencast->capture(screencast_session_id, buffer);968 screencast->capture(screencast_session_id, buffer);
874 done->Run();969 done->Run();
875}970}
876971
=== modified file 'src/server/frontend/session_mediator.h'
--- src/server/frontend/session_mediator.h 2017-05-08 03:04:26 +0000
+++ src/server/frontend/session_mediator.h 2017-07-18 03:23:56 +0000
@@ -28,6 +28,7 @@
28#include "mir/frontend/surface_id.h"28#include "mir/frontend/surface_id.h"
29#include "mir/frontend/buffer_stream_id.h"29#include "mir/frontend/buffer_stream_id.h"
30#include "mir/graphics/platform_ipc_operations.h"30#include "mir/graphics/platform_ipc_operations.h"
31#include "mir/graphics/buffer_id.h"
31#include "mir/protobuf/display_server_debug.h"32#include "mir/protobuf/display_server_debug.h"
32#include "mir_toolkit/common.h"33#include "mir_toolkit/common.h"
3334
@@ -77,6 +78,7 @@
77class PromptSession;78class PromptSession;
78class BufferStream;79class BufferStream;
79class InputConfigurationChanger;80class InputConfigurationChanger;
81class BufferMap;
8082
81namespace detail83namespace detail
82{84{
@@ -124,8 +126,8 @@
124 std::shared_ptr<scene::ApplicationNotRespondingDetector> const& anr_detector,126 std::shared_ptr<scene::ApplicationNotRespondingDetector> const& anr_detector,
125 std::shared_ptr<cookie::Authority> const& cookie_authority,127 std::shared_ptr<cookie::Authority> const& cookie_authority,
126 std::shared_ptr<InputConfigurationChanger> const& input_changer,128 std::shared_ptr<InputConfigurationChanger> const& input_changer,
127 std::vector<mir::ExtensionDescription> const& extensions129 std::vector<mir::ExtensionDescription> const& extensions,
128 );130 std::shared_ptr<graphics::GraphicBufferAllocator> const& allocator);
129131
130 ~SessionMediator() noexcept;132 ~SessionMediator() noexcept;
131133
@@ -299,6 +301,8 @@
299 std::shared_ptr<cookie::Authority> const cookie_authority;301 std::shared_ptr<cookie::Authority> const cookie_authority;
300 std::shared_ptr<InputConfigurationChanger> const input_changer;302 std::shared_ptr<InputConfigurationChanger> const input_changer;
301 std::vector<mir::ExtensionDescription> const extensions;303 std::vector<mir::ExtensionDescription> const extensions;
304 std::unordered_map<graphics::BufferID, std::shared_ptr<graphics::Buffer>> buffer_cache;
305 std::shared_ptr<graphics::GraphicBufferAllocator> const allocator;
302306
303 ScreencastBufferTracker screencast_buffer_tracker;307 ScreencastBufferTracker screencast_buffer_tracker;
304308
305309
=== modified file 'src/server/scene/application_session.cpp'
--- src/server/scene/application_session.cpp 2017-05-25 08:58:03 +0000
+++ src/server/scene/application_session.cpp 2017-07-18 03:23:56 +0000
@@ -20,7 +20,6 @@
20#include "snapshot_strategy.h"20#include "snapshot_strategy.h"
21#include "default_session_container.h"21#include "default_session_container.h"
22#include "output_properties_cache.h"22#include "output_properties_cache.h"
23#include "../compositor/buffer_map.h"
2423
25#include "mir/scene/surface.h"24#include "mir/scene/surface.h"
26#include "mir/scene/surface_event_source.h"25#include "mir/scene/surface_event_source.h"
@@ -68,7 +67,6 @@
68 snapshot_strategy(snapshot_strategy),67 snapshot_strategy(snapshot_strategy),
69 session_listener(session_listener),68 session_listener(session_listener),
70 event_sink(sink),69 event_sink(sink),
71 buffers(buffer_stream_factory->create_buffer_map(sink)),
72 gralloc(gralloc),70 gralloc(gralloc),
73 next_surface_id(0)71 next_surface_id(0)
74{72{
@@ -372,7 +370,7 @@
372mf::BufferStreamId ms::ApplicationSession::create_buffer_stream(mg::BufferProperties const& props)370mf::BufferStreamId ms::ApplicationSession::create_buffer_stream(mg::BufferProperties const& props)
373{371{
374 auto const id = static_cast<mf::BufferStreamId>(next_id().as_value());372 auto const id = static_cast<mf::BufferStreamId>(next_id().as_value());
375 auto stream = buffer_stream_factory->create_buffer_stream(id, buffers, props);373 auto stream = buffer_stream_factory->create_buffer_stream(id, props);
376 374
377 std::unique_lock<std::mutex> lock(surfaces_and_streams_mutex);375 std::unique_lock<std::mutex> lock(surfaces_and_streams_mutex);
378 streams[id] = stream;376 streams[id] = stream;
@@ -429,56 +427,6 @@
429 surface_stack->remove_surface(surface);427 surface_stack->remove_surface(surface);
430}428}
431429
432mg::BufferID ms::ApplicationSession::create_buffer(mg::BufferProperties const& properties)
433{
434 try
435 {
436 return buffers->add_buffer(gralloc->alloc_buffer(properties));
437 }
438 catch (std::exception& e)
439 {
440 event_sink->error_buffer(properties.size, properties.format, e.what());
441 throw;
442 }
443}
444
445mg::BufferID ms::ApplicationSession::create_buffer(mir::geometry::Size size, MirPixelFormat format)
446{
447 try
448 {
449 return buffers->add_buffer(gralloc->alloc_software_buffer(size, format));
450 }
451 catch (std::exception& e)
452 {
453 event_sink->error_buffer(size, format, e.what());
454 throw;
455 }
456}
457
458mg::BufferID ms::ApplicationSession::create_buffer(
459 mir::geometry::Size size, uint32_t native_format, uint32_t native_flags)
460{
461 try
462 {
463 return buffers->add_buffer(gralloc->alloc_buffer(size, native_format, native_flags));
464 }
465 catch (std::exception& e)
466 {
467 event_sink->error_buffer(size, static_cast<MirPixelFormat>(native_format), e.what());
468 throw;
469 }
470}
471
472void ms::ApplicationSession::destroy_buffer(mg::BufferID id)
473{
474 buffers->remove_buffer(id);
475}
476
477std::shared_ptr<mg::Buffer> ms::ApplicationSession::get_buffer(mg::BufferID id)
478{
479 return buffers->get(id);
480}
481
482void ms::ApplicationSession::send_error(mir::ClientVisibleError const& error)430void ms::ApplicationSession::send_error(mir::ClientVisibleError const& error)
483{431{
484 event_sink->handle_error(error);432 event_sink->handle_error(error);
485433
=== modified file 'src/server/scene/application_session.h'
--- src/server/scene/application_session.h 2017-05-08 03:04:26 +0000
+++ src/server/scene/application_session.h 2017-07-18 03:23:56 +0000
@@ -100,12 +100,6 @@
100 void destroy_buffer_stream(frontend::BufferStreamId stream) override;100 void destroy_buffer_stream(frontend::BufferStreamId stream) override;
101 void configure_streams(Surface& surface, std::vector<shell::StreamSpecification> const& config) override;101 void configure_streams(Surface& surface, std::vector<shell::StreamSpecification> const& config) override;
102 void destroy_surface(std::weak_ptr<Surface> const& surface) override;102 void destroy_surface(std::weak_ptr<Surface> const& surface) override;
103
104 graphics::BufferID create_buffer(graphics::BufferProperties const& properties) override;
105 graphics::BufferID create_buffer(geometry::Size, MirPixelFormat) override;
106 graphics::BufferID create_buffer(geometry::Size, uint32_t native_format, uint32_t native_flags) override;
107 void destroy_buffer(graphics::BufferID) override;
108 std::shared_ptr<graphics::Buffer> get_buffer(graphics::BufferID) override;
109protected:103protected:
110 ApplicationSession(ApplicationSession const&) = delete;104 ApplicationSession(ApplicationSession const&) = delete;
111 ApplicationSession& operator=(ApplicationSession const&) = delete;105 ApplicationSession& operator=(ApplicationSession const&) = delete;
@@ -119,7 +113,6 @@
119 std::shared_ptr<SnapshotStrategy> const snapshot_strategy;113 std::shared_ptr<SnapshotStrategy> const snapshot_strategy;
120 std::shared_ptr<SessionListener> const session_listener;114 std::shared_ptr<SessionListener> const session_listener;
121 std::shared_ptr<frontend::EventSink> const event_sink;115 std::shared_ptr<frontend::EventSink> const event_sink;
122 std::shared_ptr<frontend::ClientBuffers> const buffers;
123 std::shared_ptr<graphics::GraphicBufferAllocator> const gralloc;116 std::shared_ptr<graphics::GraphicBufferAllocator> const gralloc;
124117
125 frontend::SurfaceId next_id();118 frontend::SurfaceId next_id();
126119
=== modified file 'src/server/scene/global_event_sender.cpp'
--- src/server/scene/global_event_sender.cpp 2017-05-08 03:04:26 +0000
+++ src/server/scene/global_event_sender.cpp 2017-07-18 03:23:56 +0000
@@ -67,10 +67,6 @@
67{67{
68}68}
6969
70void ms::GlobalEventSender::remove_buffer(graphics::Buffer&)
71{
72}
73
74void ms::GlobalEventSender::update_buffer(graphics::Buffer&)70void ms::GlobalEventSender::update_buffer(graphics::Buffer&)
75{71{
76}72}
7773
=== modified file 'src/server/scene/global_event_sender.h'
--- src/server/scene/global_event_sender.h 2017-05-08 03:04:26 +0000
+++ src/server/scene/global_event_sender.h 2017-07-18 03:23:56 +0000
@@ -41,7 +41,6 @@
41 void send_ping(int32_t serial) override;41 void send_ping(int32_t serial) override;
42 void send_buffer(frontend::BufferStreamId id, graphics::Buffer& buffer, graphics::BufferIpcMsgType) override;42 void send_buffer(frontend::BufferStreamId id, graphics::Buffer& buffer, graphics::BufferIpcMsgType) override;
43 void add_buffer(graphics::Buffer&) override;43 void add_buffer(graphics::Buffer&) override;
44 void remove_buffer(graphics::Buffer&) override;
45 void update_buffer(graphics::Buffer&) override;44 void update_buffer(graphics::Buffer&) override;
46 void error_buffer(geometry::Size, MirPixelFormat, std::string const&) override;45 void error_buffer(geometry::Size, MirPixelFormat, std::string const&) override;
47private:46private:
4847
=== modified file 'src/server/shell/window_management_info.cpp'
--- src/server/shell/window_management_info.cpp 2017-05-08 03:04:26 +0000
+++ src/server/shell/window_management_info.cpp 2017-07-18 03:23:56 +0000
@@ -24,6 +24,7 @@
2424
25#include "mir/graphics/buffer.h"25#include "mir/graphics/buffer.h"
26#include "mir/renderer/sw/pixel_source.h"26#include "mir/renderer/sw/pixel_source.h"
27#include "mir/graphics/graphic_buffer_allocator.h"
2728
28#include <atomic>29#include <atomic>
2930
@@ -173,54 +174,40 @@
173{174{
174 AllocatingPainter(175 AllocatingPainter(
175 std::shared_ptr<frontend::BufferStream> const& buffer_stream,176 std::shared_ptr<frontend::BufferStream> const& buffer_stream,
176 std::shared_ptr<scene::Session> const& session,177 mg::GraphicBufferAllocator& allocator,
177 Size size) :178 Size size) :
178 buffer_stream(buffer_stream),179 buffer_stream(buffer_stream),
179 session(session),180 front_buffer{allocator.alloc_software_buffer(size, buffer_stream->pixel_format())},
180 properties({181 back_buffer{allocator.alloc_software_buffer(size, buffer_stream->pixel_format())}
181 size,
182 buffer_stream->pixel_format(),
183 mg::BufferUsage::software
184 }),
185 front_buffer(session->create_buffer(properties)),
186 back_buffer(session->create_buffer(properties))
187 {182 {
188 }183 }
189184
190 void paint(int intensity) override185 void paint(int intensity) override
191 {186 {
192 auto buffer = session->get_buffer(back_buffer);187 auto const format = back_buffer->pixel_format();
193188 auto const sz = back_buffer->size().height.as_int() *
194 auto const format = buffer->pixel_format();189 back_buffer->size().width.as_int() * MIR_BYTES_PER_PIXEL(format);
195 auto const sz = buffer->size().height.as_int() *
196 buffer->size().width.as_int() * MIR_BYTES_PER_PIXEL(format);
197 std::vector<unsigned char> pixels(sz, intensity);190 std::vector<unsigned char> pixels(sz, intensity);
198 if (auto pixel_source = dynamic_cast<mrs::PixelSource*>(buffer->native_buffer_base()))191 if (auto pixel_source = dynamic_cast<mrs::PixelSource*>(back_buffer->native_buffer_base()))
199 pixel_source->write(pixels.data(), sz);192 pixel_source->write(pixels.data(), sz);
200 buffer_stream->submit_buffer(buffer);193 buffer_stream->submit_buffer(back_buffer);
201194
202 std::swap(front_buffer, back_buffer);195 std::swap(front_buffer, back_buffer);
203 }196 }
204197
205 ~AllocatingPainter()
206 {
207 session->destroy_buffer(front_buffer);
208 session->destroy_buffer(back_buffer);
209 }
210
211 std::shared_ptr<frontend::BufferStream> const buffer_stream;198 std::shared_ptr<frontend::BufferStream> const buffer_stream;
212 std::shared_ptr<scene::Session> const session;199 std::shared_ptr<scene::Session> const session;
213 mg::BufferProperties properties;200 mg::BufferProperties properties;
214 mg::BufferID front_buffer; 201 std::shared_ptr<mg::Buffer> front_buffer;
215 mg::BufferID back_buffer; 202 std::shared_ptr<mg::Buffer> back_buffer;
216};203};
217204
218void msh::SurfaceInfo::init_titlebar(205void msh::SurfaceInfo::init_titlebar(
219 std::shared_ptr<scene::Session> const& session,206 mg::GraphicBufferAllocator& allocator,
220 std::shared_ptr<scene::Surface> const& surface)207 std::shared_ptr<scene::Surface> const& surface)
221{208{
222 auto stream = surface->primary_buffer_stream();209 auto stream = surface->primary_buffer_stream();
223 stream_painter = std::make_shared<AllocatingPainter>(stream, session, surface->size());210 stream_painter = std::make_shared<AllocatingPainter>(stream, allocator, surface->size());
224}211}
225212
226void msh::SurfaceInfo::paint_titlebar(int intensity)213void msh::SurfaceInfo::paint_titlebar(int intensity)
227214
=== modified file 'tests/include/mir/test/doubles/mock_event_sink.h'
--- tests/include/mir/test/doubles/mock_event_sink.h 2017-05-08 03:04:26 +0000
+++ tests/include/mir/test/doubles/mock_event_sink.h 2017-07-18 03:23:56 +0000
@@ -42,7 +42,6 @@
42 MOCK_METHOD1(send_ping, void(int32_t));42 MOCK_METHOD1(send_ping, void(int32_t));
43 MOCK_METHOD3(send_buffer, void(frontend::BufferStreamId, graphics::Buffer&, graphics::BufferIpcMsgType));43 MOCK_METHOD3(send_buffer, void(frontend::BufferStreamId, graphics::Buffer&, graphics::BufferIpcMsgType));
44 MOCK_METHOD1(add_buffer, void(graphics::Buffer&));44 MOCK_METHOD1(add_buffer, void(graphics::Buffer&));
45 MOCK_METHOD1(remove_buffer, void(graphics::Buffer&));
46 MOCK_METHOD1(update_buffer, void(graphics::Buffer&));45 MOCK_METHOD1(update_buffer, void(graphics::Buffer&));
47 MOCK_METHOD3(error_buffer, void(geometry::Size, MirPixelFormat, std::string const&));46 MOCK_METHOD3(error_buffer, void(geometry::Size, MirPixelFormat, std::string const&));
48 MOCK_METHOD1(handle_input_config_change, void(MirInputConfig const&));47 MOCK_METHOD1(handle_input_config_change, void(MirInputConfig const&));
4948
=== modified file 'tests/include/mir/test/doubles/null_event_sink.h'
--- tests/include/mir/test/doubles/null_event_sink.h 2017-05-08 03:04:26 +0000
+++ tests/include/mir/test/doubles/null_event_sink.h 2017-07-18 03:23:56 +0000
@@ -44,7 +44,6 @@
44 void send_buffer(frontend::BufferStreamId, graphics::Buffer&, graphics::BufferIpcMsgType) override {}44 void send_buffer(frontend::BufferStreamId, graphics::Buffer&, graphics::BufferIpcMsgType) override {}
45 void handle_input_config_change(MirInputConfig const&) override {}45 void handle_input_config_change(MirInputConfig const&) override {}
46 void add_buffer(graphics::Buffer&) override {}46 void add_buffer(graphics::Buffer&) override {}
47 void remove_buffer(graphics::Buffer&) override {}
48 void update_buffer(graphics::Buffer&) override {}47 void update_buffer(graphics::Buffer&) override {}
49 void error_buffer(geometry::Size, MirPixelFormat, std::string const&) override {}48 void error_buffer(geometry::Size, MirPixelFormat, std::string const&) override {}
50};49};
5150
=== modified file 'tests/include/mir/test/doubles/stub_buffer_stream_factory.h'
--- tests/include/mir/test/doubles/stub_buffer_stream_factory.h 2017-05-08 03:04:26 +0000
+++ tests/include/mir/test/doubles/stub_buffer_stream_factory.h 2017-07-18 03:23:56 +0000
@@ -19,7 +19,6 @@
19#ifndef MIR_TEST_DOUBLES_STUB_BUFFER_STREAM_FACTORY_H_19#ifndef MIR_TEST_DOUBLES_STUB_BUFFER_STREAM_FACTORY_H_
20#define MIR_TEST_DOUBLES_STUB_BUFFER_STREAM_FACTORY_H_20#define MIR_TEST_DOUBLES_STUB_BUFFER_STREAM_FACTORY_H_
2121
22#include "mir/frontend/client_buffers.h"
23#include "mir/scene/buffer_stream_factory.h"22#include "mir/scene/buffer_stream_factory.h"
24#include "stub_buffer_stream.h"23#include "stub_buffer_stream.h"
2524
@@ -30,40 +29,20 @@
30namespace doubles29namespace doubles
31{30{
3231
33struct StubClientBuffers : frontend::ClientBuffers
34{
35 graphics::BufferID add_buffer(std::shared_ptr<graphics::Buffer> const&) override
36 {
37 return {};
38 }
39 void remove_buffer(graphics::BufferID) override
40 {
41 }
42 std::shared_ptr<graphics::Buffer> get(graphics::BufferID) const override
43 {
44 return buffer;
45 }
46 void send_buffer(graphics::BufferID) override
47 {
48 }
49 void receive_buffer(graphics::BufferID) override
50 {
51 }
52 std::shared_ptr<graphics::Buffer> buffer;
53};
54
55struct StubBufferStreamFactory : public scene::BufferStreamFactory32struct StubBufferStreamFactory : public scene::BufferStreamFactory
56{33{
57 std::shared_ptr<compositor::BufferStream> create_buffer_stream(34 std::shared_ptr<compositor::BufferStream> create_buffer_stream(
58 frontend::BufferStreamId i, std::shared_ptr<frontend::ClientBuffers> const& s,35 frontend::BufferStreamId i,
59 int, graphics::BufferProperties const& p) { return create_buffer_stream(i, s, p); }36 int,
37 graphics::BufferProperties const& p)
38 {
39 return create_buffer_stream(i, p);
40 }
60 std::shared_ptr<compositor::BufferStream> create_buffer_stream(41 std::shared_ptr<compositor::BufferStream> create_buffer_stream(
61 frontend::BufferStreamId, std::shared_ptr<frontend::ClientBuffers> const&,42 frontend::BufferStreamId,
62 graphics::BufferProperties const&) { return std::make_shared<StubBufferStream>(); }43 graphics::BufferProperties const&)
63 std::shared_ptr<frontend::ClientBuffers> create_buffer_map(
64 std::shared_ptr<frontend::BufferSink> const&)
65 {44 {
66 return std::make_shared<StubClientBuffers>();45 return std::make_shared<StubBufferStream>();
67 }46 }
68};47};
69}48}
7049
=== modified file 'tests/integration-tests/compositor/test_swapping_swappers.cpp'
--- tests/integration-tests/compositor/test_swapping_swappers.cpp 2017-05-08 03:04:26 +0000
+++ tests/integration-tests/compositor/test_swapping_swappers.cpp 2017-07-18 03:23:56 +0000
@@ -19,7 +19,6 @@
19#include "multithread_harness.h"19#include "multithread_harness.h"
2020
21#include "src/server/compositor/stream.h"21#include "src/server/compositor/stream.h"
22#include "src/server/compositor/buffer_map.h"
23#include "mir/graphics/graphic_buffer_allocator.h"22#include "mir/graphics/graphic_buffer_allocator.h"
2423
25#include <gmock/gmock.h>24#include <gmock/gmock.h>
@@ -30,6 +29,7 @@
30#include <atomic>29#include <atomic>
3130
32namespace mc = mir::compositor;31namespace mc = mir::compositor;
32namespace mf = mir::frontend;
33namespace mg = mir::graphics;33namespace mg = mir::graphics;
34namespace mt = mir::testing;34namespace mt = mir::testing;
35namespace geom = mir::geometry;35namespace geom = mir::geometry;
@@ -42,7 +42,6 @@
42 void SetUp()42 void SetUp()
43 {43 {
44 stream = std::make_shared<mc::Stream>(44 stream = std::make_shared<mc::Stream>(
45 std::make_shared<mc::BufferMap>(nullptr),
46 geom::Size{380, 210}, mir_pixel_format_abgr_8888);45 geom::Size{380, 210}, mir_pixel_format_abgr_8888);
47 }46 }
4847
4948
=== modified file 'tests/integration-tests/test_buffer_scheduling.cpp'
--- tests/integration-tests/test_buffer_scheduling.cpp 2017-05-25 05:49:36 +0000
+++ tests/integration-tests/test_buffer_scheduling.cpp 2017-07-18 03:23:56 +0000
@@ -16,17 +16,15 @@
16 * Authored by: Kevin DuBois <kevin.dubois@canonical.com>16 * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
17 */17 */
1818
19#include "mir/frontend/client_buffers.h"
20#include "mir/frontend/event_sink.h"19#include "mir/frontend/event_sink.h"
21#include "mir/frontend/buffer_sink.h"20#include "mir/frontend/buffer_sink.h"
22#include "mir/renderer/sw/pixel_source.h"21#include "mir/renderer/sw/pixel_source.h"
23#include "src/client/buffer_vault.h"22#include "src/client/buffer_vault.h"
24#include "src/client/buffer_factory.h"23#include "src/client/buffer_factory.h"
25#include "src/client/buffer_factory.h"
26#include "src/client/protobuf_to_native_buffer.h"24#include "src/client/protobuf_to_native_buffer.h"
27#include "src/client/connection_surface_map.h"25#include "src/client/connection_surface_map.h"
28#include "src/server/compositor/stream.h"26#include "src/server/compositor/stream.h"
29#include "src/server/compositor/buffer_map.h"27#include "src/server/compositor/temporary_buffers.h"
30#include "mir/test/doubles/stub_client_buffer_factory.h"28#include "mir/test/doubles/stub_client_buffer_factory.h"
31#include "mir/test/doubles/mock_client_buffer_factory.h"29#include "mir/test/doubles/mock_client_buffer_factory.h"
32#include "mir/test/doubles/stub_buffer_allocator.h"30#include "mir/test/doubles/stub_buffer_allocator.h"
@@ -48,12 +46,6 @@
48namespace46namespace
49{47{
5048
51enum class TestType
52{
53 ExchangeSemantics,
54 SubmitSemantics
55};
56
57enum class Access49enum class Access
58{50{
59 blocked,51 blocked,
@@ -462,6 +454,24 @@
462 return never_blocks; 454 return never_blocks;
463}455}
464456
457class AutoSendBuffer : public mc::TemporaryBuffer
458{
459public:
460 AutoSendBuffer(
461 std::shared_ptr<mg::Buffer> const& wrapped,
462 std::shared_ptr<mf::BufferSink> const& sink)
463 : TemporaryBuffer(wrapped),
464 sink{sink}
465 {
466 }
467
468 ~AutoSendBuffer()
469 {
470 sink->update_buffer(*buffer);
471 }
472private:
473 std::shared_ptr<mf::BufferSink> const sink;
474};
465475
466//test infrastructure476//test infrastructure
467struct BufferScheduling : public Test, ::testing::WithParamInterface<int>477struct BufferScheduling : public Test, ::testing::WithParamInterface<int>
@@ -470,9 +480,7 @@
470 {480 {
471 ipc = std::make_shared<StubIpcSystem>();481 ipc = std::make_shared<StubIpcSystem>();
472 sink = std::make_shared<StubEventSink>(ipc);482 sink = std::make_shared<StubEventSink>(ipc);
473 map = std::make_shared<mc::BufferMap>(sink);
474 auto submit_stream = std::make_shared<mc::Stream>(483 auto submit_stream = std::make_shared<mc::Stream>(
475 map,
476 geom::Size{100,100},484 geom::Size{100,100},
477 mir_pixel_format_abgr_8888);485 mir_pixel_format_abgr_8888);
478 auto weak_stream = std::weak_ptr<mc::Stream>(submit_stream);486 auto weak_stream = std::weak_ptr<mc::Stream>(submit_stream);
@@ -483,12 +491,15 @@
483 if (!submit_stream)491 if (!submit_stream)
484 return;492 return;
485 mg::BufferID id{static_cast<unsigned int>(buffer.buffer_id())};493 mg::BufferID id{static_cast<unsigned int>(buffer.buffer_id())};
486 submit_stream->submit_buffer(map->get(id));494 submit_stream->submit_buffer(
495 std::make_shared<AutoSendBuffer>(map.at(id), sink));
487 });496 });
488 ipc->on_allocate(497 ipc->on_allocate(
489 [this](geom::Size sz)498 [this](geom::Size sz)
490 {499 {
491 map->add_buffer(std::make_shared<mtd::StubBuffer>(sz));500 auto const buffer = std::make_shared<mtd::StubBuffer>(sz);
501 map[buffer->id()] = buffer;
502 sink->add_buffer(*buffer);
492 });503 });
493504
494 consumer = std::make_unique<ScheduledConsumer>(submit_stream);505 consumer = std::make_unique<ScheduledConsumer>(submit_stream);
@@ -529,7 +540,7 @@
529 std::unique_ptr<ConsumerSystem> consumer;540 std::unique_ptr<ConsumerSystem> consumer;
530 std::unique_ptr<ConsumerSystem> second_consumer;541 std::unique_ptr<ConsumerSystem> second_consumer;
531 std::unique_ptr<ConsumerSystem> third_consumer;542 std::unique_ptr<ConsumerSystem> third_consumer;
532 std::shared_ptr<mc::BufferMap> map;543 std::unordered_map<mg::BufferID, std::shared_ptr<mg::Buffer>> map;
533};544};
534545
535struct WithAnyNumberOfBuffers : BufferScheduling {};546struct WithAnyNumberOfBuffers : BufferScheduling {};
536547
=== modified file 'tests/integration-tests/test_session.cpp'
--- tests/integration-tests/test_session.cpp 2017-05-08 03:04:26 +0000
+++ tests/integration-tests/test_session.cpp 2017-07-18 03:23:56 +0000
@@ -80,7 +80,7 @@
80struct StubGLBufferStreamFactory : public mtd::StubBufferStreamFactory80struct StubGLBufferStreamFactory : public mtd::StubBufferStreamFactory
81{81{
82 std::shared_ptr<mc::BufferStream> create_buffer_stream(82 std::shared_ptr<mc::BufferStream> create_buffer_stream(
83 mf::BufferStreamId, std::shared_ptr<mf::ClientBuffers> const&,83 mf::BufferStreamId,
84 mg::BufferProperties const&) override84 mg::BufferProperties const&) override
85 {85 {
86 return std::make_shared<StubGLBufferStream>();86 return std::make_shared<StubGLBufferStream>();
8787
=== modified file 'tests/integration-tests/test_submit_buffer.cpp'
--- tests/integration-tests/test_submit_buffer.cpp 2017-05-08 03:04:26 +0000
+++ tests/integration-tests/test_submit_buffer.cpp 2017-07-18 03:23:56 +0000
@@ -32,7 +32,6 @@
32#include "mir/frontend/event_sink.h"32#include "mir/frontend/event_sink.h"
33#include "mir/compositor/buffer_stream.h"33#include "mir/compositor/buffer_stream.h"
34#include "src/server/compositor/stream.h"34#include "src/server/compositor/stream.h"
35#include "src/server/compositor/buffer_map.h"
36#include "mir_toolkit/mir_client_library.h"35#include "mir_toolkit/mir_client_library.h"
37#include "mir_toolkit/debug/surface.h"36#include "mir_toolkit/debug/surface.h"
38#include "src/client/mir_connection.h"37#include "src/client/mir_connection.h"
@@ -70,96 +69,17 @@
70 {}69 {}
7170
72 std::shared_ptr<mc::BufferStream> create_buffer_stream(71 std::shared_ptr<mc::BufferStream> create_buffer_stream(
73 mf::BufferStreamId i, std::shared_ptr<mf::ClientBuffers> const& s,72 mf::BufferStreamId i,
74 int, mg::BufferProperties const& p) override73 int, mg::BufferProperties const& p) override
75 {74 {
76 return create_buffer_stream(i, s, p);75 return create_buffer_stream(i, p);
77 }76 }
7877
79 std::shared_ptr<mc::BufferStream> create_buffer_stream(78 std::shared_ptr<mc::BufferStream> create_buffer_stream(
80 mf::BufferStreamId, std::shared_ptr<mf::ClientBuffers> const& sink,79 mf::BufferStreamId,
81 mg::BufferProperties const& properties) override80 mg::BufferProperties const& properties) override
82 {81 {
83 return std::make_shared<mc::Stream>(sink, properties.size, properties.format);82 return std::make_shared<mc::Stream>(properties.size, properties.format);
84 }
85
86 std::shared_ptr<mf::ClientBuffers> create_buffer_map(std::shared_ptr<mf::BufferSink> const& sink) override
87 {
88 struct BufferMap : mf::ClientBuffers
89 {
90 BufferMap(
91 std::shared_ptr<mf::BufferSink> const& sink,
92 std::vector<mg::BufferID> const& ids) :
93 sink(sink),
94 buffer_id_seq(ids)
95 {
96 std::reverse(buffer_id_seq.begin(), buffer_id_seq.end());
97 }
98
99 mg::BufferID add_buffer(std::shared_ptr<mg::Buffer> const& buffer) override
100 {
101 struct BufferIdWrapper : mg::Buffer
102 {
103 BufferIdWrapper(std::shared_ptr<mg::Buffer> const& b, mg::BufferID id) :
104 wrapped(b),
105 id_(id)
106 {
107 }
108
109 std::shared_ptr<mg::NativeBuffer> native_buffer_handle() const override
110 {
111 return wrapped->native_buffer_handle();
112 }
113 mg::BufferID id() const override
114 {
115 return id_;
116 }
117 geom::Size size() const override
118 {
119 return wrapped->size();
120 }
121 MirPixelFormat pixel_format() const override
122 {
123 return wrapped->pixel_format();
124 }
125 mg::NativeBufferBase* native_buffer_base() override
126 {
127 return wrapped->native_buffer_base();
128 }
129 std::shared_ptr<mg::Buffer> const wrapped;
130 mg::BufferID const id_;
131 };
132
133 auto id = buffer_id_seq.back();
134 buffer_id_seq.pop_back();
135 b = std::make_shared<BufferIdWrapper>(buffer, id);
136 sink->add_buffer(*b);
137 return id;
138 }
139
140 void remove_buffer(mg::BufferID) override
141 {
142 }
143
144 std::shared_ptr<mg::Buffer> get(mg::BufferID) const override
145 {
146 return b;
147 }
148
149 void send_buffer(mg::BufferID) override
150 {
151 }
152
153 void receive_buffer(mg::BufferID) override
154 {
155 }
156
157 std::shared_ptr<mg::Buffer> b;
158 std::shared_ptr<mf::BufferSink> const sink;
159 std::shared_ptr<mtd::StubBufferAllocator> alloc{std::make_shared<mtd::StubBufferAllocator>()};
160 std::vector<mg::BufferID> buffer_id_seq;
161 };
162 return std::make_shared<BufferMap>(sink, buffer_id_seq);
163 }83 }
16484
165 std::vector<mg::BufferID> const buffer_id_seq;85 std::vector<mg::BufferID> const buffer_id_seq;
@@ -204,6 +124,66 @@
204 std::shared_ptr<mg::PlatformIpcOperations> const underlying_ops;124 std::shared_ptr<mg::PlatformIpcOperations> const underlying_ops;
205};125};
206126
127class RecordingBufferAllocator : public mg::GraphicBufferAllocator
128{
129public:
130 RecordingBufferAllocator(
131 std::shared_ptr<mg::GraphicBufferAllocator> const& wrapped,
132 std::vector<std::weak_ptr<mg::Buffer>>& allocated_buffers,
133 std::mutex& buffer_mutex)
134 : allocated_buffers{allocated_buffers},
135 underlying_allocator{wrapped},
136 buffer_mutex{buffer_mutex}
137 {
138 }
139
140 std::shared_ptr<mg::Buffer> alloc_buffer(
141 mg::BufferProperties const& buffer_properties) override
142 {
143 auto const buf = underlying_allocator->alloc_buffer(buffer_properties);
144 {
145 std::lock_guard<std::mutex> lock{buffer_mutex};
146 allocated_buffers.push_back(buf);
147 }
148 return buf;
149 }
150
151 std::vector<MirPixelFormat> supported_pixel_formats() override
152 {
153 return underlying_allocator->supported_pixel_formats();
154 }
155
156 std::shared_ptr<mg::Buffer> alloc_buffer(
157 geom::Size size,
158 uint32_t native_format,
159 uint32_t native_flags) override
160 {
161 auto const buf = underlying_allocator->alloc_buffer(size, native_format, native_flags);
162 {
163 std::lock_guard<std::mutex> lock{buffer_mutex};
164 allocated_buffers.push_back(buf);
165 }
166 return buf;
167 }
168
169 std::shared_ptr<mg::Buffer> alloc_software_buffer(
170 geom::Size size,
171 MirPixelFormat format) override
172 {
173 auto const buf = underlying_allocator->alloc_software_buffer(size, format);
174 {
175 std::lock_guard<std::mutex> lock{buffer_mutex};
176 allocated_buffers.push_back(buf);
177 }
178 return buf;
179 }
180
181 std::vector<std::weak_ptr<mg::Buffer>>& allocated_buffers;
182private:
183 std::shared_ptr<mg::GraphicBufferAllocator> const underlying_allocator;
184 std::mutex& buffer_mutex;
185};
186
207struct StubPlatform : public mg::Platform187struct StubPlatform : public mg::Platform
208{188{
209 StubPlatform(std::shared_ptr<mir::Fd> const& last_fd)189 StubPlatform(std::shared_ptr<mir::Fd> const& last_fd)
@@ -214,7 +194,10 @@
214194
215 mir::UniqueModulePtr<mg::GraphicBufferAllocator> create_buffer_allocator() override195 mir::UniqueModulePtr<mg::GraphicBufferAllocator> create_buffer_allocator() override
216 {196 {
217 return underlying_platform->create_buffer_allocator();197 return mir::make_module_ptr<RecordingBufferAllocator>(
198 underlying_platform->create_buffer_allocator(),
199 allocated_buffers,
200 buffer_mutex);
218 }201 }
219202
220 mir::UniqueModulePtr<mg::PlatformIpcOperations> make_ipc_operations() const override203 mir::UniqueModulePtr<mg::PlatformIpcOperations> make_ipc_operations() const override
@@ -231,20 +214,28 @@
231 return underlying_platform->create_display(policy, config);214 return underlying_platform->create_display(policy, config);
232 }215 }
233216
217 std::vector<std::weak_ptr<mg::Buffer>> get_allocated_buffers()
218 {
219 std::lock_guard<std::mutex> lock{buffer_mutex};
220 return allocated_buffers;
221 }
222
234 mg::NativeRenderingPlatform* native_rendering_platform() override { return nullptr; }223 mg::NativeRenderingPlatform* native_rendering_platform() override { return nullptr; }
235 mg::NativeDisplayPlatform* native_display_platform() override { return nullptr; }224 mg::NativeDisplayPlatform* native_display_platform() override { return nullptr; }
236 std::vector<mir::ExtensionDescription> extensions() const override { return {}; }225 std::vector<mir::ExtensionDescription> extensions() const override { return {}; }
237226
238 std::shared_ptr<mir::Fd> const last_fd;227 std::shared_ptr<mir::Fd> const last_fd;
239 std::shared_ptr<mg::Platform> const underlying_platform;228 std::shared_ptr<mg::Platform> const underlying_platform;
229
230private:
231 std::mutex buffer_mutex;
232 std::vector<std::weak_ptr<mg::Buffer>> allocated_buffers;
240};233};
241234
242struct ExchangeServerConfiguration : mtf::StubbedServerConfiguration235struct ExchangeServerConfiguration : mtf::StubbedServerConfiguration
243{236{
244 ExchangeServerConfiguration(237 ExchangeServerConfiguration(
245 std::vector<mg::BufferID> const& id_seq,
246 std::shared_ptr<mir::Fd> const& last_unpacked_fd) :238 std::shared_ptr<mir::Fd> const& last_unpacked_fd) :
247 stream_factory{std::make_shared<StubStreamFactory>(id_seq)},
248 platform{std::make_shared<StubPlatform>(last_unpacked_fd)}239 platform{std::make_shared<StubPlatform>(last_unpacked_fd)}
249 {240 {
250 }241 }
@@ -254,24 +245,20 @@
254 return platform;245 return platform;
255 }246 }
256247
257 std::shared_ptr<msc::BufferStreamFactory> the_buffer_stream_factory() override248 std::shared_ptr<StubPlatform> const platform;
258 {
259 return stream_factory;
260 }
261
262 std::shared_ptr<StubStreamFactory> const stream_factory;
263 std::shared_ptr<mg::Platform> const platform;
264};249};
265250
266struct SubmitBuffer : mir_test_framework::InProcessServer251struct SubmitBuffer : mir_test_framework::InProcessServer
267{252{
268 std::vector<mg::BufferID> const buffer_id_exchange_seq{
269 mg::BufferID{4}, mg::BufferID{8}, mg::BufferID{9}, mg::BufferID{3}, mg::BufferID{4}};
270
271 std::shared_ptr<mir::Fd> last_unpacked_fd{std::make_shared<mir::Fd>()};253 std::shared_ptr<mir::Fd> last_unpacked_fd{std::make_shared<mir::Fd>()};
272 ExchangeServerConfiguration server_configuration{buffer_id_exchange_seq, last_unpacked_fd};254 ExchangeServerConfiguration server_configuration{last_unpacked_fd};
273 mir::DefaultServerConfiguration& server_config() override { return server_configuration; }255 mir::DefaultServerConfiguration& server_config() override { return server_configuration; }
274256
257 std::vector<std::weak_ptr<mg::Buffer>> get_allocated_buffers()
258 {
259 return server_configuration.platform->get_allocated_buffers();
260 }
261
275 void request_completed()262 void request_completed()
276 {263 {
277 std::unique_lock<decltype(mutex)> lk(mutex);264 std::unique_lock<decltype(mutex)> lk(mutex);
@@ -287,7 +274,7 @@
287 google::protobuf::NewCallback(this, &SubmitBuffer::request_completed));274 google::protobuf::NewCallback(this, &SubmitBuffer::request_completed));
288 275
289 arrived = false;276 arrived = false;
290 return cv.wait_for(lk, std::chrono::seconds(5), [this]() {return arrived;});277 return cv.wait_for(lk, std::chrono::seconds(500), [this]() {return arrived;});
291 }278 }
292279
293 bool allocate_buffers(mclr::DisplayServer& server, mp::BufferAllocation& request)280 bool allocate_buffers(mclr::DisplayServer& server, mp::BufferAllocation& request)
@@ -318,13 +305,18 @@
318 mp::BufferRequest buffer_request; 305 mp::BufferRequest buffer_request;
319};306};
320template<class Clock>307template<class Clock>
321bool spin_wait_for_id(mg::BufferID id, MirWindow* window, std::chrono::time_point<Clock> const& pt)308bool spin_wait_for_id(
309 std::function<std::vector<mg::BufferID>()> const& id_generator,
310 MirWindow* window,
311 std::chrono::time_point<Clock> const& pt)
322{312{
323 while(Clock::now() < pt)313 while(Clock::now() < pt)
324 {314 {
325 //auto z = mir_debug_window_current_buffer_id(window);315 for (auto const& id : id_generator())
326 if (mir_debug_window_current_buffer_id(window) == id.as_value())316 {
327 return true;317 if (mir_debug_window_current_buffer_id(window) == id.as_value())
318 return true;
319 }
328 std::this_thread::yield();320 std::this_thread::yield();
329 }321 }
330 return false;322 return false;
@@ -353,7 +345,17 @@
353 for (auto i = 0; i < buffer_request.buffer().fd().size(); i++)345 for (auto i = 0; i < buffer_request.buffer().fd().size(); i++)
354 ::close(buffer_request.buffer().fd(i));346 ::close(buffer_request.buffer().fd(i));
355347
356 buffer_request.mutable_buffer()->set_buffer_id(buffer_id_exchange_seq.begin()->as_value());348 mp::BufferAllocation allocation_request;
349 auto allocate = allocation_request.add_buffer_requests();
350 allocate->set_buffer_usage(static_cast<int32_t>(mg::BufferUsage::software));
351 allocate->set_pixel_format(mir_pixel_format_abgr_8888);
352 allocate->set_width(320);
353 allocate->set_height(240);
354
355 ASSERT_THAT(allocate_buffers(server, allocation_request), DidNotTimeOut());
356
357 buffer_request.mutable_buffer()->set_buffer_id(
358 get_allocated_buffers().back().lock()->id().as_value());
357 buffer_request.mutable_buffer()->add_fd(file);359 buffer_request.mutable_buffer()->add_fd(file);
358360
359 ASSERT_THAT(submit_buffer(server, buffer_request), DidNotTimeOut());361 ASSERT_THAT(submit_buffer(server, buffer_request), DidNotTimeOut());
@@ -377,10 +379,22 @@
377 auto rpc_channel = connection->rpc_channel();379 auto rpc_channel = connection->rpc_channel();
378 mclr::DisplayServer server(rpc_channel);380 mclr::DisplayServer server(rpc_channel);
379381
382 for(int i = 0; i < 5; ++i)
383 {
384 mp::BufferAllocation allocation_request;
385 auto allocate = allocation_request.add_buffer_requests();
386 allocate->set_buffer_usage(static_cast<int32_t>(mg::BufferUsage::software));
387 allocate->set_pixel_format(mir_pixel_format_abgr_8888);
388 allocate->set_width(320);
389 allocate->set_height(240);
390
391 allocate_buffers(server, allocation_request);
392 }
393
380 mp::BufferRequest request;394 mp::BufferRequest request;
381 for (auto const& id : buffer_id_exchange_seq)395 for (auto weak_buffer : get_allocated_buffers())
382 {396 {
383 buffer_request.mutable_buffer()->set_buffer_id(id.as_value());397 buffer_request.mutable_buffer()->set_buffer_id(weak_buffer.lock()->id().as_value());
384 ASSERT_THAT(submit_buffer(server, buffer_request), DidNotTimeOut());398 ASSERT_THAT(submit_buffer(server, buffer_request), DidNotTimeOut());
385 }399 }
386400
@@ -396,8 +410,32 @@
396 auto window = mtf::make_any_surface(connection);410 auto window = mtf::make_any_surface(connection);
397411
398 auto timeout = std::chrono::steady_clock::now() + 5s;412 auto timeout = std::chrono::steady_clock::now() + 5s;
399 EXPECT_TRUE(spin_wait_for_id(buffer_id_exchange_seq.back(), window, timeout))413
400 << "failed to see the last scheduled buffer become the current one";414 EXPECT_TRUE(
415 spin_wait_for_id(
416 [this]()
417 {
418 /* We expect to receive one of the implicitly allocated buffers
419 * We don't care which one we get.
420 *
421 * We need to repeatedly check the allocated buffers, because
422 * buffer allocation is asynchronous WRT window creation.
423 */
424 std::vector<mg::BufferID> candidate_ids;
425 for (auto const weak_buffer : get_allocated_buffers())
426 {
427 auto const buffer = weak_buffer.lock();
428 if (buffer)
429 {
430 // If there are any expired buffers we don't care about them
431 candidate_ids.push_back(buffer->id());
432 }
433 }
434 return candidate_ids;
435 },
436 window,
437 timeout))
438 << "failed to see buffer";
401439
402 mir_window_release_sync(window);440 mir_window_release_sync(window);
403 mir_connection_release(connection);441 mir_connection_release(connection);
404442
=== modified file 'tests/integration-tests/test_surface_stack_with_compositor.cpp'
--- tests/integration-tests/test_surface_stack_with_compositor.cpp 2017-05-08 03:04:26 +0000
+++ tests/integration-tests/test_surface_stack_with_compositor.cpp 2017-07-18 03:23:56 +0000
@@ -24,7 +24,6 @@
24#include "src/server/scene/basic_surface.h"24#include "src/server/scene/basic_surface.h"
25#include "src/server/compositor/default_display_buffer_compositor_factory.h"25#include "src/server/compositor/default_display_buffer_compositor_factory.h"
26#include "src/server/compositor/multi_threaded_compositor.h"26#include "src/server/compositor/multi_threaded_compositor.h"
27#include "src/server/compositor/buffer_map.h"
28#include "src/server/compositor/stream.h"27#include "src/server/compositor/stream.h"
29#include "mir/test/fake_shared.h"28#include "mir/test/fake_shared.h"
30#include "mir/test/doubles/mock_buffer_stream.h"29#include "mir/test/doubles/mock_buffer_stream.h"
@@ -47,6 +46,7 @@
47namespace mr = mir::report;46namespace mr = mir::report;
48namespace mc = mir::compositor;47namespace mc = mir::compositor;
49namespace mg = mir::graphics;48namespace mg = mir::graphics;
49namespace mf = mir::frontend;
50namespace geom = mir::geometry;50namespace geom = mir::geometry;
51using namespace testing;51using namespace testing;
5252
@@ -123,8 +123,7 @@
123{123{
124 SurfaceStackCompositor() :124 SurfaceStackCompositor() :
125 timeout{std::chrono::system_clock::now() + std::chrono::seconds(5)},125 timeout{std::chrono::system_clock::now() + std::chrono::seconds(5)},
126 buffers(std::make_shared<mc::BufferMap>(std::make_shared<NiceMock<mtd::MockEventSink>>())),126 stream(std::make_shared<mc::Stream>(geom::Size{ 1, 1 }, mir_pixel_format_abgr_8888 )),
127 stream(std::make_shared<mc::Stream>(buffers, geom::Size{ 1, 1 }, mir_pixel_format_abgr_8888 )),
128 mock_buffer_stream(std::make_shared<NiceMock<mtd::MockBufferStream>>()),127 mock_buffer_stream(std::make_shared<NiceMock<mtd::MockBufferStream>>()),
129 streams({ { stream, {0,0}, {} } }),128 streams({ { stream, {0,0}, {} } }),
130 stub_surface{std::make_shared<ms::BasicSurface>(129 stub_surface{std::make_shared<ms::BasicSurface>(
@@ -136,7 +135,6 @@
136 null_scene_report)},135 null_scene_report)},
137 stub_buffer(std::make_shared<mtd::StubBuffer>())136 stub_buffer(std::make_shared<mtd::StubBuffer>())
138 {137 {
139 buffers->add_buffer(stub_buffer);
140 ON_CALL(*mock_buffer_stream, lock_compositor_buffer(_))138 ON_CALL(*mock_buffer_stream, lock_compositor_buffer(_))
141 .WillByDefault(Return(mt::fake_shared(*stub_buffer)));139 .WillByDefault(Return(mt::fake_shared(*stub_buffer)));
142 }140 }
@@ -145,7 +143,6 @@
145 std::shared_ptr<mc::CompositorReport> null_comp_report{mr::null_compositor_report()};143 std::shared_ptr<mc::CompositorReport> null_comp_report{mr::null_compositor_report()};
146 StubRendererFactory renderer_factory;144 StubRendererFactory renderer_factory;
147 std::chrono::system_clock::time_point timeout;145 std::chrono::system_clock::time_point timeout;
148 std::shared_ptr<mc::BufferMap> buffers;
149 std::shared_ptr<mc::Stream> stream;146 std::shared_ptr<mc::Stream> stream;
150 std::shared_ptr<mtd::MockBufferStream> mock_buffer_stream;147 std::shared_ptr<mtd::MockBufferStream> mock_buffer_stream;
151 std::list<ms::StreamInfo> const streams;148 std::list<ms::StreamInfo> const streams;
152149
=== modified file 'tests/integration-tests/test_swapinterval.cpp'
--- tests/integration-tests/test_swapinterval.cpp 2017-05-08 03:04:26 +0000
+++ tests/integration-tests/test_swapinterval.cpp 2017-07-18 03:23:56 +0000
@@ -67,24 +67,19 @@
67 }67 }
6868
69 std::shared_ptr<mc::BufferStream> create_buffer_stream(69 std::shared_ptr<mc::BufferStream> create_buffer_stream(
70 mf::BufferStreamId id, std::shared_ptr<mf::ClientBuffers> const& sink,70 mf::BufferStreamId id,
71 int, mg::BufferProperties const& p) override71 int, mg::BufferProperties const& p) override
72 {72 {
73 return create_buffer_stream(id, sink, p);73 return create_buffer_stream(id, p);
74 }74 }
7575
76 std::shared_ptr<mc::BufferStream> create_buffer_stream(76 std::shared_ptr<mc::BufferStream> create_buffer_stream(
77 mf::BufferStreamId, std::shared_ptr<mf::ClientBuffers> const&,77 mf::BufferStreamId,
78 mg::BufferProperties const&) override78 mg::BufferProperties const&) override
79 {79 {
80 return std::make_shared<StubBufferStream>(framedropping_enabled);80 return std::make_shared<StubBufferStream>(framedropping_enabled);
81 }81 }
8282
83 std::shared_ptr<mf::ClientBuffers> create_buffer_map(std::shared_ptr<mf::BufferSink> const&) override
84 {
85 return std::make_shared<mtd::StubClientBuffers>();
86 }
87
88private:83private:
89 std::atomic<bool>& framedropping_enabled;84 std::atomic<bool>& framedropping_enabled;
90};85};
9186
=== modified file 'tests/mir_test_doubles/mock_event_sink_factory.cpp'
--- tests/mir_test_doubles/mock_event_sink_factory.cpp 2017-05-08 03:04:26 +0000
+++ tests/mir_test_doubles/mock_event_sink_factory.cpp 2017-07-18 03:23:56 +0000
@@ -42,7 +42,6 @@
42 void send_buffer(mf::BufferStreamId id, mg::Buffer& buf, mg::BufferIpcMsgType type) override;42 void send_buffer(mf::BufferStreamId id, mg::Buffer& buf, mg::BufferIpcMsgType type) override;
43 void handle_input_config_change(MirInputConfig const& devices) override;43 void handle_input_config_change(MirInputConfig const& devices) override;
44 void add_buffer(mir::graphics::Buffer&) override;44 void add_buffer(mir::graphics::Buffer&) override;
45 void remove_buffer(mir::graphics::Buffer&) override;
46 void update_buffer(mir::graphics::Buffer&) override;45 void update_buffer(mir::graphics::Buffer&) override;
47 void error_buffer(mir::geometry::Size, MirPixelFormat, std::string const&) override;46 void error_buffer(mir::geometry::Size, MirPixelFormat, std::string const&) override;
4847
@@ -106,11 +105,6 @@
106 underlying_sink->error_buffer(sz, pf, error);105 underlying_sink->error_buffer(sz, pf, error);
107}106}
108107
109void GloballyUniqueMockEventSink::remove_buffer(mir::graphics::Buffer& buffer)
110{
111 underlying_sink->remove_buffer(buffer);
112}
113
114void GloballyUniqueMockEventSink::update_buffer(mir::graphics::Buffer& buffer)108void GloballyUniqueMockEventSink::update_buffer(mir::graphics::Buffer& buffer)
115{109{
116 underlying_sink->update_buffer(buffer);110 underlying_sink->update_buffer(buffer);
117111
=== modified file 'tests/mir_test_framework/stub_session.cpp'
--- tests/mir_test_framework/stub_session.cpp 2017-05-08 03:04:26 +0000
+++ tests/mir_test_framework/stub_session.cpp 2017-07-18 03:23:56 +0000
@@ -143,31 +143,6 @@
143{143{
144}144}
145145
146mir::graphics::BufferID mtd::StubSession::create_buffer(mir::graphics::BufferProperties const&)
147{
148 return mir::graphics::BufferID(3);
149}
150
151mir::graphics::BufferID mtd::StubSession::create_buffer(mir::geometry::Size, uint32_t, uint32_t)
152{
153 return mir::graphics::BufferID(3);
154}
155
156mir::graphics::BufferID mtd::StubSession::create_buffer(mir::geometry::Size, MirPixelFormat)
157{
158 return mir::graphics::BufferID(3);
159}
160
161void mtd::StubSession::destroy_buffer(mir::graphics::BufferID)
162{
163}
164
165std::shared_ptr<mir::graphics::Buffer> mtd::StubSession::get_buffer(graphics::BufferID)
166{
167 return std::make_shared<mtd::StubBuffer>(
168 std::make_shared<mir_test_framework::NativeBuffer>(graphics::BufferProperties{}));
169}
170
171namespace146namespace
172{147{
173// Ensure we don't accidentally have an abstract class148// Ensure we don't accidentally have an abstract class
174149
=== modified file 'tests/unit-tests/client/test_client_buffer_stream.cpp'
--- tests/unit-tests/client/test_client_buffer_stream.cpp 2017-05-17 04:48:46 +0000
+++ tests/unit-tests/client/test_client_buffer_stream.cpp 2017-07-18 03:23:56 +0000
@@ -204,16 +204,15 @@
204204
205 void async_buffer_arrives(mp::Buffer& buffer)205 void async_buffer_arrives(mp::Buffer& buffer)
206 {206 {
207 try207 if (auto buf = map->buffer(buffer.buffer_id()))
208 {208 {
209 map->buffer(buffer.buffer_id())->received(*mcl::protobuf_to_native_buffer(buffer));209 buf->received(*mcl::protobuf_to_native_buffer(buffer));
210 }210 }
211 catch (std::runtime_error& e)211 else
212 {212 {
213 auto bb = factory->generate_buffer(buffer);213 map->insert(buffer.buffer_id(), factory->generate_buffer(buffer));
214 auto braw = bb.get();214 buf = map->buffer(buffer.buffer_id());
215 map->insert(buffer.buffer_id(), std::move(bb)); 215 buf->received();
216 braw->received();
217 }216 }
218 }217 }
219218
220219
=== modified file 'tests/unit-tests/client/test_connection_resource_map.cpp'
--- tests/unit-tests/client/test_connection_resource_map.cpp 2017-05-08 03:04:26 +0000
+++ tests/unit-tests/client/test_connection_resource_map.cpp 2017-07-18 03:23:56 +0000
@@ -97,17 +97,13 @@
97{97{
98 using namespace testing;98 using namespace testing;
99 mcl::ConnectionSurfaceMap map;99 mcl::ConnectionSurfaceMap map;
100 EXPECT_THROW({100 EXPECT_THAT(map.buffer(buffer_id), IsNull());
101 map.buffer(buffer_id);
102 }, std::runtime_error);
103101
104 map.insert(buffer_id, buffer);102 map.insert(buffer_id, buffer);
105 EXPECT_THAT(map.buffer(buffer_id), Eq(buffer));103 EXPECT_THAT(map.buffer(buffer_id), Eq(buffer));
106 map.erase(buffer_id);104 map.erase(buffer_id);
107105
108 EXPECT_THROW({106 EXPECT_THAT(map.buffer(buffer_id), IsNull());
109 map.buffer(buffer_id);
110 }, std::runtime_error);
111}107}
112108
113TEST_F(ConnectionResourceMap, can_access_buffers_from_surface)109TEST_F(ConnectionResourceMap, can_access_buffers_from_surface)
114110
=== modified file 'tests/unit-tests/client/test_mir_connection.cpp'
--- tests/unit-tests/client/test_mir_connection.cpp 2017-05-25 06:28:52 +0000
+++ tests/unit-tests/client/test_mir_connection.cpp 2017-07-18 03:23:56 +0000
@@ -873,7 +873,6 @@
873 auto native_format = 342u;873 auto native_format = 342u;
874 auto native_flags = 0x44;874 auto native_flags = 0x44;
875 mp::BufferAllocation mp_alloc;875 mp::BufferAllocation mp_alloc;
876 mp_alloc.mutable_id()->set_value(-1);
877 auto params = mp_alloc.add_buffer_requests();876 auto params = mp_alloc.add_buffer_requests();
878 params->set_width(size.width.as_int());877 params->set_width(size.width.as_int());
879 params->set_height(size.height.as_int());878 params->set_height(size.height.as_int());
880879
=== modified file 'tests/unit-tests/client/test_protobuf_rpc_channel.cpp'
--- tests/unit-tests/client/test_protobuf_rpc_channel.cpp 2017-05-08 03:04:26 +0000
+++ tests/unit-tests/client/test_protobuf_rpc_channel.cpp 2017-07-18 03:23:56 +0000
@@ -840,3 +840,27 @@
840 std::make_shared<mtd::NullClientEventSink>()};840 std::make_shared<mtd::NullClientEventSink>()};
841 channel.on_data_available();841 channel.on_data_available();
842}842}
843
844TEST_F(MirProtobufRpcChannelTest, ignores_update_message_for_unknown_buffer)
845{
846 mir::protobuf::EventSequence seq;
847 auto request = seq.mutable_buffer_request();
848 request->mutable_buffer()->set_buffer_id(42);
849 request->set_operation(mir::protobuf::BufferOperation::update);
850
851 set_async_buffer_message(seq, *transport);
852
853 channel->on_data_available();
854}
855
856TEST_F(MirProtobufRpcChannelTest, ignores_delete_message_for_unknown_buffer)
857{
858 mir::protobuf::EventSequence seq;
859 auto request = seq.mutable_buffer_request();
860 request->mutable_buffer()->set_buffer_id(42);
861 request->set_operation(mir::protobuf::BufferOperation::remove);
862
863 set_async_buffer_message(seq, *transport);
864
865 channel->on_data_available();
866}
843867
=== modified file 'tests/unit-tests/compositor/CMakeLists.txt'
--- tests/unit-tests/compositor/CMakeLists.txt 2017-05-08 03:04:26 +0000
+++ tests/unit-tests/compositor/CMakeLists.txt 2017-07-18 03:23:56 +0000
@@ -7,7 +7,6 @@
7 ${CMAKE_CURRENT_SOURCE_DIR}/test_screencast_display_buffer.cpp7 ${CMAKE_CURRENT_SOURCE_DIR}/test_screencast_display_buffer.cpp
8 ${CMAKE_CURRENT_SOURCE_DIR}/test_compositing_screencast.cpp8 ${CMAKE_CURRENT_SOURCE_DIR}/test_compositing_screencast.cpp
9 ${CMAKE_CURRENT_SOURCE_DIR}/test_multi_monitor_arbiter.cpp9 ${CMAKE_CURRENT_SOURCE_DIR}/test_multi_monitor_arbiter.cpp
10 ${CMAKE_CURRENT_SOURCE_DIR}/test_client_buffers.cpp
11 ${CMAKE_CURRENT_SOURCE_DIR}/test_dropping_schedule.cpp10 ${CMAKE_CURRENT_SOURCE_DIR}/test_dropping_schedule.cpp
12 ${CMAKE_CURRENT_SOURCE_DIR}/test_queueing_schedule.cpp11 ${CMAKE_CURRENT_SOURCE_DIR}/test_queueing_schedule.cpp
13)12)
1413
=== removed file 'tests/unit-tests/compositor/test_client_buffers.cpp'
--- tests/unit-tests/compositor/test_client_buffers.cpp 2017-05-08 03:04:26 +0000
+++ tests/unit-tests/compositor/test_client_buffers.cpp 1970-01-01 00:00:00 +0000
@@ -1,119 +0,0 @@
1/*
2 * Copyright © 2015 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 3 as
6 * 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/test/doubles/mock_event_sink.h"
20#include "mir/test/fake_shared.h"
21#include "mir/test/doubles/stub_buffer_allocator.h"
22#include "src/server/compositor/buffer_map.h"
23#include "mir/graphics/display_configuration.h"
24
25#include <gtest/gtest.h>
26using namespace testing;
27namespace mt = mir::test;
28namespace mtd = mir::test::doubles;
29namespace mc = mir::compositor;
30namespace mg = mir::graphics;
31namespace mf = mir::frontend;
32namespace geom = mir::geometry;
33
34struct ClientBuffers : public Test
35{
36 std::shared_ptr<mtd::MockEventSink> mock_sink = std::make_shared<testing::NiceMock<mtd::MockEventSink>>();
37 mg::BufferProperties properties{geom::Size{42,43}, mir_pixel_format_abgr_8888, mg::BufferUsage::hardware};
38 mtd::StubBuffer stub_buffer{properties};
39 mc::BufferMap map{mock_sink};
40};
41
42TEST_F(ClientBuffers, sends_full_buffer_on_allocation)
43{
44 EXPECT_CALL(*mock_sink, add_buffer(Ref(stub_buffer)));
45 mc::BufferMap map{mock_sink};
46 EXPECT_THAT(map.add_buffer(mt::fake_shared(stub_buffer)), Eq(stub_buffer.id()));
47}
48
49TEST_F(ClientBuffers, access_of_nonexistent_buffer_throws)
50{
51 EXPECT_THROW({
52 auto buffer = map.get(stub_buffer.id());
53 }, std::logic_error);
54}
55
56TEST_F(ClientBuffers, removal_of_nonexistent_buffer_throws)
57{
58 EXPECT_THROW({
59 map.remove_buffer(stub_buffer.id());
60 }, std::logic_error);
61}
62
63TEST_F(ClientBuffers, can_access_once_added)
64{
65 auto id = map.add_buffer(mt::fake_shared(stub_buffer));
66 EXPECT_THAT(map.get(id).get(), Eq(&stub_buffer));
67}
68
69TEST_F(ClientBuffers, sends_update_msg_to_send_buffer)
70{
71 auto id = map.add_buffer(mt::fake_shared(stub_buffer));
72 auto buffer = map.get(id);
73 EXPECT_CALL(*mock_sink, update_buffer(Ref(*buffer)));
74 map.send_buffer(id);
75}
76
77TEST_F(ClientBuffers, sends_no_update_msg_if_buffer_is_not_around)
78{
79 auto id = map.add_buffer(mt::fake_shared(stub_buffer));
80 auto buffer = map.get(id);
81
82 EXPECT_CALL(*mock_sink, remove_buffer(Ref(*buffer)));
83 map.remove_buffer(id);
84 map.send_buffer(id);
85}
86
87TEST_F(ClientBuffers, can_remove_buffer_from_send_callback)
88{
89 auto id = map.add_buffer(mt::fake_shared(stub_buffer));
90 ON_CALL(*mock_sink, update_buffer(_))
91 .WillByDefault(Invoke(
92 [&] (mg::Buffer& buffer)
93 {
94 map.remove_buffer(buffer.id());
95 }));
96
97 map.send_buffer(id);
98}
99
100TEST_F(ClientBuffers, ignores_unknown_receive)
101{
102 EXPECT_CALL(*mock_sink, add_buffer(_))
103 .Times(1);
104 auto id = map.add_buffer(mt::fake_shared(stub_buffer));
105 map.remove_buffer(id);
106 map.send_buffer(id);
107}
108
109TEST_F(ClientBuffers, sends_error_buffer_when_alloc_fails)
110{
111 std::string error_msg = "a reason";
112 EXPECT_CALL(*mock_sink, add_buffer(_))
113 .WillOnce(Throw(std::runtime_error(error_msg)));
114 EXPECT_CALL(*mock_sink, error_buffer(stub_buffer.size(), stub_buffer.pixel_format(), StrEq(error_msg)));
115 mc::BufferMap map{mock_sink};
116 EXPECT_THROW({
117 map.add_buffer(mt::fake_shared(stub_buffer));
118 }, std::runtime_error);
119}
1200
=== modified file 'tests/unit-tests/compositor/test_dropping_schedule.cpp'
--- tests/unit-tests/compositor/test_dropping_schedule.cpp 2017-05-08 03:04:26 +0000
+++ tests/unit-tests/compositor/test_dropping_schedule.cpp 2017-07-18 03:23:56 +0000
@@ -16,7 +16,6 @@
16 * Authored by: Kevin DuBois <kevin.dubois@canonical.com>16 * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
17 */17 */
1818
19#include "mir/frontend/client_buffers.h"
20#include "src/server/compositor/dropping_schedule.h"19#include "src/server/compositor/dropping_schedule.h"
21#include "mir/test/doubles/stub_buffer.h"20#include "mir/test/doubles/stub_buffer.h"
22#include "mir/test/fake_shared.h"21#include "mir/test/fake_shared.h"
@@ -28,20 +27,9 @@
28namespace mt = mir::test;27namespace mt = mir::test;
29namespace mg = mir::graphics;28namespace mg = mir::graphics;
30namespace mc = mir::compositor;29namespace mc = mir::compositor;
31namespace mf = mir::frontend;
32namespace30namespace
33{31{
3432
35struct MockBufferMap : mf::ClientBuffers
36{
37 MOCK_METHOD1(add_buffer, mg::BufferID(std::shared_ptr<mg::Buffer> const&));
38 MOCK_METHOD1(remove_buffer, void(mg::BufferID id));
39 MOCK_METHOD1(send_buffer, void(mg::BufferID id));
40 MOCK_METHOD1(receive_buffer, void(mg::BufferID id));
41 MOCK_CONST_METHOD0(client_owned_buffer_count, size_t());
42 MOCK_CONST_METHOD1(get, std::shared_ptr<mg::Buffer>(mg::BufferID));
43};
44
45struct DroppingSchedule : Test33struct DroppingSchedule : Test
46{34{
47 DroppingSchedule()35 DroppingSchedule()
@@ -52,8 +40,7 @@
52 unsigned int const num_buffers{5};40 unsigned int const num_buffers{5};
53 std::vector<std::shared_ptr<mg::Buffer>> buffers;41 std::vector<std::shared_ptr<mg::Buffer>> buffers;
5442
55 MockBufferMap mock_client_buffers;43 mc::DroppingSchedule schedule;
56 mc::DroppingSchedule schedule{mt::fake_shared(mock_client_buffers)};
57 std::vector<std::shared_ptr<mg::Buffer>> drain_queue()44 std::vector<std::shared_ptr<mg::Buffer>> drain_queue()
58 {45 {
59 std::vector<std::shared_ptr<mg::Buffer>> scheduled_buffers;46 std::vector<std::shared_ptr<mg::Buffer>> scheduled_buffers;
@@ -74,49 +61,23 @@
7461
75TEST_F(DroppingSchedule, drops_excess_buffers)62TEST_F(DroppingSchedule, drops_excess_buffers)
76{63{
77 InSequence seq;
78 EXPECT_CALL(mock_client_buffers, send_buffer(buffers[0]->id()));
79 EXPECT_CALL(mock_client_buffers, send_buffer(buffers[1]->id()));
80 EXPECT_CALL(mock_client_buffers, send_buffer(buffers[2]->id()));
81 EXPECT_CALL(mock_client_buffers, send_buffer(buffers[3]->id()));
82
83 for(auto i = 0u; i < num_buffers; i++)64 for(auto i = 0u; i < num_buffers; i++)
84 schedule.schedule(buffers[i]);65 schedule.schedule(buffers[i]);
8566
86 auto queue = drain_queue();67 auto queue = drain_queue();
87 ASSERT_THAT(queue, SizeIs(1));68 ASSERT_THAT(queue, SizeIs(1));
69
70 // The 5th buffer should be scheduled...
88 EXPECT_THAT(queue[0]->id(), Eq(buffers[4]->id()));71 EXPECT_THAT(queue[0]->id(), Eq(buffers[4]->id()));
89}72 for (int i = 0; i < 4 ; ++i)
90
91TEST_F(DroppingSchedule, nonblocking_schedule_avoids_socket_io)
92{
93 for (auto i = 0u; i < num_buffers; i++)
94 {73 {
95 EXPECT_CALL(mock_client_buffers, send_buffer(_))74 // ...and all the others should have no external references
96 .Times(0);75 EXPECT_TRUE(buffers[i].unique());
97
98 auto deferred_io = schedule.schedule_nonblocking(buffers[i]);
99
100 testing::Mock::VerifyAndClearExpectations(&mock_client_buffers);
101 if (i > 0)
102 {
103 EXPECT_CALL(mock_client_buffers, send_buffer(buffers[i-1]->id()))
104 .Times(1);
105 ASSERT_TRUE(deferred_io.valid());
106 deferred_io.wait();
107 testing::Mock::VerifyAndClearExpectations(&mock_client_buffers);
108 }
109 }76 }
110
111 auto queue = drain_queue();
112 ASSERT_THAT(queue, SizeIs(1));
113 EXPECT_THAT(queue[0]->id(), Eq(buffers[4]->id()));
114}77}
11578
116TEST_F(DroppingSchedule, queueing_same_buffer_many_times_doesnt_drop)79TEST_F(DroppingSchedule, queueing_same_buffer_many_times_doesnt_drop)
117{80{
118 EXPECT_CALL(mock_client_buffers, send_buffer(_)).Times(0);
119
120 schedule.schedule(buffers[2]);81 schedule.schedule(buffers[2]);
121 schedule.schedule(buffers[2]);82 schedule.schedule(buffers[2]);
122 schedule.schedule(buffers[2]);83 schedule.schedule(buffers[2]);
12384
=== modified file 'tests/unit-tests/compositor/test_multi_monitor_arbiter.cpp'
--- tests/unit-tests/compositor/test_multi_monitor_arbiter.cpp 2017-05-26 12:45:45 +0000
+++ tests/unit-tests/compositor/test_multi_monitor_arbiter.cpp 2017-07-18 03:23:56 +0000
@@ -21,7 +21,7 @@
21#include "mir/test/doubles/stub_buffer_allocator.h"21#include "mir/test/doubles/stub_buffer_allocator.h"
22#include "src/server/compositor/multi_monitor_arbiter.h"22#include "src/server/compositor/multi_monitor_arbiter.h"
23#include "src/server/compositor/schedule.h"23#include "src/server/compositor/schedule.h"
24#include "mir/frontend/client_buffers.h"24#include "src/server/compositor/temporary_buffers.h"
2525
26#include <gtest/gtest.h>26#include <gtest/gtest.h>
27using namespace testing;27using namespace testing;
@@ -33,16 +33,6 @@
3333
34namespace34namespace
35{35{
36struct MockBufferMap : mf::ClientBuffers
37{
38 MOCK_METHOD1(add_buffer, mg::BufferID(std::shared_ptr<mg::Buffer> const&));
39 MOCK_METHOD1(remove_buffer, void(mg::BufferID id));
40 MOCK_METHOD1(receive_buffer, void(mg::BufferID id));
41 MOCK_METHOD1(send_buffer, void(mg::BufferID id));
42 MOCK_CONST_METHOD0(client_owned_buffer_count, size_t());
43 MOCK_CONST_METHOD1(get, std::shared_ptr<mg::Buffer>(mg::BufferID));
44};
45
46struct FixedSchedule : mc::Schedule36struct FixedSchedule : mc::Schedule
47{37{
48 void schedule(std::shared_ptr<mg::Buffer> const&) override38 void schedule(std::shared_ptr<mg::Buffer> const&) override
@@ -63,7 +53,9 @@
63 {53 {
64 if (sched.empty() || current == sched.size())54 if (sched.empty() || current == sched.size())
65 throw std::runtime_error("no buffer scheduled");55 throw std::runtime_error("no buffer scheduled");
66 return sched[current++];56 auto buf = sched.front();
57 sched.erase(sched.begin());
58 return buf;
67 }59 }
68 void set_schedule(std::vector<std::shared_ptr<mg::Buffer>> s)60 void set_schedule(std::vector<std::shared_ptr<mg::Buffer>> s)
69 {61 {
@@ -84,10 +76,40 @@
84 }76 }
85 unsigned int const num_buffers{6u};77 unsigned int const num_buffers{6u};
86 std::vector<std::shared_ptr<mg::Buffer>> buffers;78 std::vector<std::shared_ptr<mg::Buffer>> buffers;
87 NiceMock<MockBufferMap> mock_map;
88 FixedSchedule schedule;79 FixedSchedule schedule;
89 mc::MultiMonitorArbiter arbiter{mt::fake_shared(mock_map), mt::fake_shared(schedule)};80 mc::MultiMonitorArbiter arbiter{mt::fake_shared(schedule)};
90};81};
82
83MATCHER_P(IsSameBufferAs, buffer, "")
84{
85 return buffer->id() == arg->id();
86}
87
88std::shared_ptr<mg::Buffer> wrap_with_destruction_notifier(
89 std::shared_ptr<mg::Buffer> const& buffer,
90 std::shared_ptr<bool> const& destroyed)
91{
92 class DestructionNotifyingBuffer : public mc::TemporaryBuffer
93 {
94 public:
95 DestructionNotifyingBuffer(
96 std::shared_ptr<mg::Buffer> const& buffer,
97 std::shared_ptr<bool> const& destroyed)
98 : TemporaryBuffer(buffer),
99 destroyed{destroyed}
100 {
101 }
102
103 ~DestructionNotifyingBuffer()
104 {
105 *destroyed = true;
106 }
107 private:
108 std::shared_ptr<bool> const destroyed;
109 };
110
111 return std::make_shared<DestructionNotifyingBuffer>(buffer, destroyed);
112}
91}113}
92114
93TEST_F(MultiMonitorArbiter, compositor_access_before_any_submission_throws)115TEST_F(MultiMonitorArbiter, compositor_access_before_any_submission_throws)
@@ -107,32 +129,30 @@
107{129{
108 schedule.set_schedule({buffers[0]});130 schedule.set_schedule({buffers[0]});
109 auto cbuffer = arbiter.compositor_acquire(this);131 auto cbuffer = arbiter.compositor_acquire(this);
110 EXPECT_THAT(cbuffer, Eq(buffers[0]));132 EXPECT_THAT(cbuffer, IsSameBufferAs(buffers[0]));
111}133}
112134
113TEST_F(MultiMonitorArbiter, compositor_release_sends_buffer_back)135TEST_F(MultiMonitorArbiter, compositor_release_sends_buffer_back)
114{136{
115 EXPECT_CALL(mock_map, send_buffer(buffers[0]->id()));137 auto buffer_released = std::make_shared<bool>(false);
116138 schedule.set_schedule({ wrap_with_destruction_notifier(buffers[0], buffer_released) });
117 schedule.set_schedule({buffers[0]});
118139
119 auto cbuffer = arbiter.compositor_acquire(this);140 auto cbuffer = arbiter.compositor_acquire(this);
120 schedule.set_schedule({buffers[1]});141 schedule.set_schedule({buffers[1]});
121 arbiter.compositor_release(cbuffer);142 arbiter.compositor_release(cbuffer);
143 cbuffer.reset();
144 // We need to acquire a new buffer - the current one is on-screen, so can't be sent back.
145 arbiter.compositor_acquire(this);
146 EXPECT_TRUE(*buffer_released);
122}147}
123148
124TEST_F(MultiMonitorArbiter, compositor_can_acquire_different_buffers)149TEST_F(MultiMonitorArbiter, compositor_can_acquire_different_buffers)
125{150{
126 EXPECT_CALL(mock_map, send_buffer(buffers[0]->id()));
127
128 schedule.set_schedule({buffers[0]});151 schedule.set_schedule({buffers[0]});
129 auto cbuffer1 = arbiter.compositor_acquire(this);152 auto cbuffer1 = arbiter.compositor_acquire(this);
130 schedule.set_schedule({buffers[1]});153 schedule.set_schedule({buffers[1]});
131 auto cbuffer2 = arbiter.compositor_acquire(this);154 auto cbuffer2 = arbiter.compositor_acquire(this);
132 EXPECT_THAT(cbuffer1, Ne(cbuffer2));155 EXPECT_THAT(cbuffer1, Not(IsSameBufferAs(cbuffer2)));
133 arbiter.compositor_release(cbuffer2);
134 arbiter.compositor_release(cbuffer1);
135 Mock::VerifyAndClearExpectations(&mock_map);
136}156}
137157
138TEST_F(MultiMonitorArbiter, compositor_buffer_syncs_to_fastest_compositor)158TEST_F(MultiMonitorArbiter, compositor_buffer_syncs_to_fastest_compositor)
@@ -155,13 +175,13 @@
155 auto cbuffer6 = arbiter.compositor_acquire(&comp_id2);175 auto cbuffer6 = arbiter.compositor_acquire(&comp_id2);
156 auto cbuffer7 = arbiter.compositor_acquire(&comp_id2);176 auto cbuffer7 = arbiter.compositor_acquire(&comp_id2);
157177
158 EXPECT_THAT(cbuffer1, Eq(buffers[0]));178 EXPECT_THAT(cbuffer1, IsSameBufferAs(buffers[0]));
159 EXPECT_THAT(cbuffer2, Eq(buffers[0]));179 EXPECT_THAT(cbuffer2, IsSameBufferAs(buffers[0]));
160 EXPECT_THAT(cbuffer3, Eq(buffers[1]));180 EXPECT_THAT(cbuffer3, IsSameBufferAs(buffers[1]));
161 EXPECT_THAT(cbuffer4, Eq(buffers[0]));181 EXPECT_THAT(cbuffer4, IsSameBufferAs(buffers[0]));
162 EXPECT_THAT(cbuffer5, Eq(buffers[0]));182 EXPECT_THAT(cbuffer5, IsSameBufferAs(buffers[0]));
163 EXPECT_THAT(cbuffer6, Eq(buffers[1]));183 EXPECT_THAT(cbuffer6, IsSameBufferAs(buffers[1]));
164 EXPECT_THAT(cbuffer7, Eq(buffers[1]));184 EXPECT_THAT(cbuffer7, IsSameBufferAs(buffers[1]));
165}185}
166186
167TEST_F(MultiMonitorArbiter, compositor_consumes_all_buffers_when_operating_as_a_composited_scene_would)187TEST_F(MultiMonitorArbiter, compositor_consumes_all_buffers_when_operating_as_a_composited_scene_would)
@@ -179,11 +199,11 @@
179 auto cbuffer5 = arbiter.compositor_acquire(this);199 auto cbuffer5 = arbiter.compositor_acquire(this);
180 arbiter.compositor_release(cbuffer5);200 arbiter.compositor_release(cbuffer5);
181201
182 EXPECT_THAT(cbuffer1, Eq(buffers[0]));202 EXPECT_THAT(cbuffer1, IsSameBufferAs(buffers[0]));
183 EXPECT_THAT(cbuffer2, Eq(buffers[1]));203 EXPECT_THAT(cbuffer2, IsSameBufferAs(buffers[1]));
184 EXPECT_THAT(cbuffer3, Eq(buffers[2]));204 EXPECT_THAT(cbuffer3, IsSameBufferAs(buffers[2]));
185 EXPECT_THAT(cbuffer4, Eq(buffers[3]));205 EXPECT_THAT(cbuffer4, IsSameBufferAs(buffers[3]));
186 EXPECT_THAT(cbuffer5, Eq(buffers[4]));206 EXPECT_THAT(cbuffer5, IsSameBufferAs(buffers[4]));
187}207}
188208
189TEST_F(MultiMonitorArbiter, compositor_consumes_all_buffers_when_operating_as_a_bypassed_buffer_would)209TEST_F(MultiMonitorArbiter, compositor_consumes_all_buffers_when_operating_as_a_bypassed_buffer_would)
@@ -201,11 +221,11 @@
201 arbiter.compositor_release(cbuffer4);221 arbiter.compositor_release(cbuffer4);
202 arbiter.compositor_release(cbuffer5);222 arbiter.compositor_release(cbuffer5);
203223
204 EXPECT_THAT(cbuffer1, Eq(buffers[0]));224 EXPECT_THAT(cbuffer1, IsSameBufferAs(buffers[0]));
205 EXPECT_THAT(cbuffer2, Eq(buffers[1]));225 EXPECT_THAT(cbuffer2, IsSameBufferAs(buffers[1]));
206 EXPECT_THAT(cbuffer3, Eq(buffers[2]));226 EXPECT_THAT(cbuffer3, IsSameBufferAs(buffers[2]));
207 EXPECT_THAT(cbuffer4, Eq(buffers[3]));227 EXPECT_THAT(cbuffer4, IsSameBufferAs(buffers[3]));
208 EXPECT_THAT(cbuffer5, Eq(buffers[4]));228 EXPECT_THAT(cbuffer5, IsSameBufferAs(buffers[4]));
209}229}
210230
211TEST_F(MultiMonitorArbiter, multimonitor_compositor_buffer_syncs_to_fastest_with_more_queueing)231TEST_F(MultiMonitorArbiter, multimonitor_compositor_buffer_syncs_to_fastest_with_more_queueing)
@@ -228,18 +248,18 @@
228 auto cbuffer7 = arbiter.compositor_acquire(&comp_id2); //buffer[4]248 auto cbuffer7 = arbiter.compositor_acquire(&comp_id2); //buffer[4]
229 auto cbuffer8 = arbiter.compositor_acquire(&comp_id1); //buffer[4]249 auto cbuffer8 = arbiter.compositor_acquire(&comp_id1); //buffer[4]
230250
231 EXPECT_THAT(cbuffer1, Eq(buffers[0]));251 EXPECT_THAT(cbuffer1, IsSameBufferAs(buffers[0]));
232 EXPECT_THAT(cbuffer2, Eq(buffers[0]));252 EXPECT_THAT(cbuffer2, IsSameBufferAs(buffers[0]));
233253
234 EXPECT_THAT(cbuffer3, Eq(buffers[1]));254 EXPECT_THAT(cbuffer3, IsSameBufferAs(buffers[1]));
235255
236 EXPECT_THAT(cbuffer4, Eq(buffers[2]));256 EXPECT_THAT(cbuffer4, IsSameBufferAs(buffers[2]));
237 EXPECT_THAT(cbuffer5, Eq(buffers[2]));257 EXPECT_THAT(cbuffer5, IsSameBufferAs(buffers[2]));
238258
239 EXPECT_THAT(cbuffer6, Eq(buffers[3]));259 EXPECT_THAT(cbuffer6, IsSameBufferAs(buffers[3]));
240260
241 EXPECT_THAT(cbuffer7, Eq(buffers[4]));261 EXPECT_THAT(cbuffer7, IsSameBufferAs(buffers[4]));
242 EXPECT_THAT(cbuffer8, Eq(buffers[4]));262 EXPECT_THAT(cbuffer8, IsSameBufferAs(buffers[4]));
243}263}
244264
245TEST_F(MultiMonitorArbiter, can_set_a_new_schedule)265TEST_F(MultiMonitorArbiter, can_set_a_new_schedule)
@@ -252,8 +272,8 @@
252 arbiter.set_schedule(mt::fake_shared(another_schedule));272 arbiter.set_schedule(mt::fake_shared(another_schedule));
253 auto cbuffer2 = arbiter.compositor_acquire(this);273 auto cbuffer2 = arbiter.compositor_acquire(this);
254274
255 EXPECT_THAT(cbuffer1, Eq(buffers[3]));275 EXPECT_THAT(cbuffer1, IsSameBufferAs(buffers[3]));
256 EXPECT_THAT(cbuffer2, Eq(buffers[0])); 276 EXPECT_THAT(cbuffer2, IsSameBufferAs(buffers[0]));
257}277}
258278
259TEST_F(MultiMonitorArbiter, basic_snapshot_equals_compositor_buffer)279TEST_F(MultiMonitorArbiter, basic_snapshot_equals_compositor_buffer)
@@ -262,7 +282,7 @@
262282
263 auto cbuffer1 = arbiter.compositor_acquire(this);283 auto cbuffer1 = arbiter.compositor_acquire(this);
264 auto sbuffer1 = arbiter.snapshot_acquire();284 auto sbuffer1 = arbiter.snapshot_acquire();
265 EXPECT_EQ(cbuffer1, sbuffer1);285 EXPECT_THAT(cbuffer1, IsSameBufferAs(sbuffer1));
266}286}
267287
268TEST_F(MultiMonitorArbiter, basic_snapshot_equals_latest_compositor_buffer)288TEST_F(MultiMonitorArbiter, basic_snapshot_equals_latest_compositor_buffer)
@@ -278,8 +298,8 @@
278 cbuffer2 = arbiter.compositor_acquire(&that);298 cbuffer2 = arbiter.compositor_acquire(&that);
279299
280 auto sbuffer2 = arbiter.snapshot_acquire();300 auto sbuffer2 = arbiter.snapshot_acquire();
281 EXPECT_EQ(cbuffer1, sbuffer1);301 EXPECT_THAT(cbuffer1, IsSameBufferAs(sbuffer1));
282 EXPECT_EQ(cbuffer2, sbuffer2);302 EXPECT_THAT(cbuffer2, IsSameBufferAs(sbuffer2));
283}303}
284304
285TEST_F(MultiMonitorArbiter, snapshot_cycling_doesnt_advance_buffer_for_compositors)305TEST_F(MultiMonitorArbiter, snapshot_cycling_doesnt_advance_buffer_for_compositors)
@@ -297,8 +317,8 @@
297 }317 }
298 auto cbuffer2 = arbiter.compositor_acquire(&that);318 auto cbuffer2 = arbiter.compositor_acquire(&that);
299319
300 EXPECT_THAT(cbuffer1, Eq(cbuffer2));320 EXPECT_THAT(cbuffer1, IsSameBufferAs(cbuffer2));
301 EXPECT_THAT(snapshot_buffers, Each(cbuffer1));321 EXPECT_THAT(snapshot_buffers, Each(IsSameBufferAs(cbuffer1)));
302}322}
303323
304TEST_F(MultiMonitorArbiter, no_buffers_available_throws_on_snapshot)324TEST_F(MultiMonitorArbiter, no_buffers_available_throws_on_snapshot)
@@ -311,29 +331,48 @@
311331
312TEST_F(MultiMonitorArbiter, snapshotting_will_release_buffer_if_it_was_the_last_owner)332TEST_F(MultiMonitorArbiter, snapshotting_will_release_buffer_if_it_was_the_last_owner)
313{333{
314 EXPECT_CALL(mock_map, send_buffer(_)).Times(0);334 auto buffer_released = std::make_shared<bool>(false);
315 schedule.set_schedule({buffers[3],buffers[4]});335 schedule.set_schedule(
336 {
337 wrap_with_destruction_notifier(buffers[3], buffer_released),
338 buffers[4]
339 });
316 auto cbuffer1 = arbiter.compositor_acquire(this);340 auto cbuffer1 = arbiter.compositor_acquire(this);
317 auto sbuffer1 = arbiter.snapshot_acquire();341 auto sbuffer1 = arbiter.snapshot_acquire();
318 arbiter.compositor_release(cbuffer1);342 arbiter.compositor_release(cbuffer1);
319343 cbuffer1.reset();
320 Mock::VerifyAndClearExpectations(&mock_map);344
321 EXPECT_CALL(mock_map, send_buffer(sbuffer1->id()));345 // Acquire a new buffer so first one is no longer onscreen.
346 arbiter.compositor_acquire(this);
347
348 EXPECT_FALSE(*buffer_released);
322 arbiter.snapshot_release(sbuffer1);349 arbiter.snapshot_release(sbuffer1);
350 sbuffer1.reset();
351 EXPECT_TRUE(*buffer_released);
323}352}
324353
325TEST_F(MultiMonitorArbiter, compositor_can_acquire_a_few_times_and_only_sends_on_the_last_release)354TEST_F(MultiMonitorArbiter, compositor_can_acquire_a_few_times_and_only_sends_on_the_last_release)
326{355{
327 int comp_id1{0};356 int comp_id1{0};
328 int comp_id2{0};357 int comp_id2{0};
329 schedule.set_schedule({buffers[0], buffers[1]});358
359 auto buffer_released = std::make_shared<bool>(false);
360 schedule.set_schedule(
361 {
362 wrap_with_destruction_notifier(buffers[0], buffer_released),
363 buffers[1]
364 });
330 auto cbuffer1 = arbiter.compositor_acquire(&comp_id1);365 auto cbuffer1 = arbiter.compositor_acquire(&comp_id1);
331 auto cbuffer2 = arbiter.compositor_acquire(&comp_id2);366 auto cbuffer2 = arbiter.compositor_acquire(&comp_id2);
332 EXPECT_THAT(cbuffer1, Eq(cbuffer2));367 EXPECT_THAT(cbuffer1, IsSameBufferAs(cbuffer2));
333 EXPECT_CALL(mock_map, send_buffer(buffers[0]->id())).Times(Exactly(1));368
334 auto cbuffer3 = arbiter.compositor_acquire(&comp_id1);369 auto cbuffer3 = arbiter.compositor_acquire(&comp_id1);
335 arbiter.compositor_release(cbuffer2);370 arbiter.compositor_release(cbuffer2);
371 EXPECT_FALSE(*buffer_released);
336 arbiter.compositor_release(cbuffer1);372 arbiter.compositor_release(cbuffer1);
373 cbuffer1.reset();
374 cbuffer2.reset();
375 EXPECT_TRUE(*buffer_released);
337}376}
338377
339TEST_F(MultiMonitorArbiter, advance_on_fastest_has_same_buffer)378TEST_F(MultiMonitorArbiter, advance_on_fastest_has_same_buffer)
@@ -349,29 +388,29 @@
349388
350 auto cbuffer3 = arbiter.compositor_acquire(&comp_id1); //buffer[1]389 auto cbuffer3 = arbiter.compositor_acquire(&comp_id1); //buffer[1]
351 390
352 EXPECT_THAT(cbuffer1, Eq(cbuffer2));391 EXPECT_THAT(cbuffer1, IsSameBufferAs(cbuffer2));
353 EXPECT_THAT(cbuffer1, Eq(buffers[0]));392 EXPECT_THAT(cbuffer1, IsSameBufferAs(buffers[0]));
354 EXPECT_THAT(cbuffer3, Eq(buffers[1]));393 EXPECT_THAT(cbuffer3, IsSameBufferAs(buffers[1]));
355}
356
357TEST_F(MultiMonitorArbiter, compositor_acquire_sends_buffer_back_with_fastest_guarantee)
358{
359 EXPECT_CALL(mock_map, send_buffer(buffers[0]->id()));
360
361 schedule.set_schedule({buffers[0], buffers[1]});
362
363 auto cbuffer = arbiter.compositor_acquire(this);
364 schedule.set_schedule({buffers[1]});
365 arbiter.compositor_release(cbuffer);
366 cbuffer = arbiter.compositor_acquire(this);
367}394}
368395
369TEST_F(MultiMonitorArbiter, buffers_are_sent_back)396TEST_F(MultiMonitorArbiter, buffers_are_sent_back)
370{397{
371 EXPECT_CALL(mock_map, send_buffer(_)).Times(3);398 std::array<std::shared_ptr<bool>, 3> buffer_released = {
399 {
400 std::make_shared<bool>(false),
401 std::make_shared<bool>(false),
402 std::make_shared<bool>(false)
403 }};
372 int comp_id1{0};404 int comp_id1{0};
373 int comp_id2{0};405 int comp_id2{0};
374 schedule.set_schedule({buffers[0], buffers[1], buffers[2], buffers[3]});406
407 schedule.set_schedule(
408 {
409 wrap_with_destruction_notifier(buffers[0], buffer_released[0]),
410 wrap_with_destruction_notifier(buffers[1], buffer_released[1]),
411 wrap_with_destruction_notifier(buffers[2], buffer_released[2]),
412 buffers[3]
413 });
375414
376 auto b1 = arbiter.compositor_acquire(&comp_id1);415 auto b1 = arbiter.compositor_acquire(&comp_id1);
377 arbiter.compositor_release(b1);416 arbiter.compositor_release(b1);
@@ -386,7 +425,14 @@
386 auto b6 = arbiter.compositor_acquire(&comp_id1);425 auto b6 = arbiter.compositor_acquire(&comp_id1);
387 arbiter.compositor_release(b6);426 arbiter.compositor_release(b6);
388427
389 Mock::VerifyAndClearExpectations(&mock_map);428 b1.reset();
429 b2.reset();
430 b3.reset();
431 b4.reset();
432 b5.reset();
433 b6.reset();
434
435 EXPECT_THAT(buffer_released, Each(Pointee(true)));
390}436}
391437
392TEST_F(MultiMonitorArbiter, can_check_if_buffers_are_ready)438TEST_F(MultiMonitorArbiter, can_check_if_buffers_are_ready)
@@ -442,17 +488,28 @@
442TEST_F(MultiMonitorArbiter, will_release_buffer_in_nbuffers_2_overlay_scenario)488TEST_F(MultiMonitorArbiter, will_release_buffer_in_nbuffers_2_overlay_scenario)
443{489{
444 int comp_id1{0};490 int comp_id1{0};
445 schedule.set_schedule({buffers[0], buffers[1], buffers[0], buffers[1]});491 auto buffer_released = std::make_shared<bool>(false);
492 auto notifying_buffer = wrap_with_destruction_notifier(buffers[0], buffer_released);
493 schedule.set_schedule(
494 {
495 notifying_buffer,
496 buffers[1],
497 buffers[0], // We only want to be notified when the first submission is released
498 buffers[1]
499 });
500 notifying_buffer.reset();
446501
447 EXPECT_CALL(mock_map, send_buffer(buffers[0]->id()));
448 auto b1 = arbiter.compositor_acquire(&comp_id1);502 auto b1 = arbiter.compositor_acquire(&comp_id1);
449 auto b2 = arbiter.compositor_acquire(&comp_id1);503 auto b2 = arbiter.compositor_acquire(&comp_id1);
450 EXPECT_THAT(b1, Eq(buffers[0]));504 EXPECT_THAT(b1, IsSameBufferAs(buffers[0]));
451 EXPECT_THAT(b2, Eq(buffers[1]));505 EXPECT_THAT(b2, IsSameBufferAs(buffers[1]));
452 arbiter.compositor_release(b1);506 arbiter.compositor_release(b1);
453 arbiter.compositor_release(b2);507 arbiter.compositor_release(b2);
454 Mock::VerifyAndClearExpectations(&mock_map);508 b1.reset();
455} 509 b2.reset();
510
511 EXPECT_TRUE(*buffer_released);
512}
456513
457TEST_F(MultiMonitorArbiter, will_release_buffer_in_nbuffers_2_starvation_scenario)514TEST_F(MultiMonitorArbiter, will_release_buffer_in_nbuffers_2_starvation_scenario)
458{515{
@@ -471,10 +528,10 @@
471 arbiter.compositor_release(b2);528 arbiter.compositor_release(b2);
472 arbiter.compositor_release(b4);529 arbiter.compositor_release(b4);
473530
474 EXPECT_THAT(b1, Eq(buffers[0]));531 EXPECT_THAT(b1, IsSameBufferAs(buffers[0]));
475 EXPECT_THAT(b2, Eq(buffers[1]));532 EXPECT_THAT(b2, IsSameBufferAs(buffers[1]));
476 EXPECT_THAT(b3, Eq(buffers[1]));533 EXPECT_THAT(b3, IsSameBufferAs(buffers[1]));
477 EXPECT_THAT(b4, Eq(buffers[0]));534 EXPECT_THAT(b4, IsSameBufferAs(buffers[0]));
478535
479} 536}
480537
@@ -482,13 +539,12 @@
482{539{
483 int comp_id1{0};540 int comp_id1{0};
484 int comp_id2{0};541 int comp_id2{0};
542
485 schedule.set_schedule({543 schedule.set_schedule({
486 buffers[0], buffers[1], buffers[2],544 buffers[0], buffers[1], buffers[2],
487 buffers[0], buffers[1], buffers[2],545 buffers[0], buffers[1], buffers[2],
488 buffers[0], buffers[1], buffers[2]});546 buffers[0], buffers[1], buffers[2]});
489547
490 EXPECT_CALL(mock_map, send_buffer(buffers[0]->id()));
491
492 auto b1 = arbiter.compositor_acquire(&comp_id1);548 auto b1 = arbiter.compositor_acquire(&comp_id1);
493 auto b2 = arbiter.compositor_acquire(&comp_id2);549 auto b2 = arbiter.compositor_acquire(&comp_id2);
494 arbiter.compositor_release(b1); //send nothing550 arbiter.compositor_release(b1); //send nothing
@@ -502,13 +558,12 @@
502 auto b5 = arbiter.compositor_acquire(&comp_id1);558 auto b5 = arbiter.compositor_acquire(&comp_id1);
503 arbiter.compositor_release(b5); //send nothing559 arbiter.compositor_release(b5); //send nothing
504560
505 EXPECT_THAT(b1, Eq(buffers[0]));561 EXPECT_THAT(b1, IsSameBufferAs(buffers[0]));
506 EXPECT_THAT(b2, Eq(buffers[0]));562 EXPECT_THAT(b2, IsSameBufferAs(buffers[0]));
507 EXPECT_THAT(b3, Eq(buffers[1]));563 EXPECT_THAT(b3, IsSameBufferAs(buffers[1]));
508 EXPECT_THAT(b4, Eq(buffers[1]));564 EXPECT_THAT(b4, IsSameBufferAs(buffers[1]));
509 EXPECT_THAT(b5, Eq(buffers[2]));565 EXPECT_THAT(b5, IsSameBufferAs(buffers[2]));
510 Mock::VerifyAndClearExpectations(&mock_map);566}
511}
512567
513TEST_F(MultiMonitorArbiter, can_advance_buffer_manually)568TEST_F(MultiMonitorArbiter, can_advance_buffer_manually)
514{569{
@@ -521,11 +576,11 @@
521576
522 auto b1 = arbiter.compositor_acquire(&comp_id1);577 auto b1 = arbiter.compositor_acquire(&comp_id1);
523 auto b2 = arbiter.compositor_acquire(&comp_id2);578 auto b2 = arbiter.compositor_acquire(&comp_id2);
524 EXPECT_THAT(b1->id(), Eq(buffers[1]->id()));579 EXPECT_THAT(b1, IsSameBufferAs(buffers[1]));
525 EXPECT_THAT(b2->id(), Eq(buffers[1]->id()));580 EXPECT_THAT(b2, IsSameBufferAs(buffers[1]));
526581
527 auto b3 = arbiter.compositor_acquire(&comp_id1);582 auto b3 = arbiter.compositor_acquire(&comp_id1);
528 EXPECT_THAT(b3->id(), Eq(buffers[2]->id()));583 EXPECT_THAT(b3, IsSameBufferAs(buffers[2]));
529}584}
530585
531TEST_F(MultiMonitorArbiter, checks_if_buffer_is_valid_after_clean_onscreen_buffer)586TEST_F(MultiMonitorArbiter, checks_if_buffer_is_valid_after_clean_onscreen_buffer)
@@ -547,8 +602,12 @@
547602
548TEST_F(MultiMonitorArbiter, releases_buffer_on_destruction)603TEST_F(MultiMonitorArbiter, releases_buffer_on_destruction)
549{604{
550 mc::MultiMonitorArbiter arbiter{mt::fake_shared(mock_map), mt::fake_shared(schedule)};605 auto buffer_released = std::make_shared<bool>(false);
551 EXPECT_CALL(mock_map, send_buffer(buffers[0]->id()));606 schedule.set_schedule({wrap_with_destruction_notifier(buffers[0], buffer_released)});
552 schedule.set_schedule({buffers[0]});607
553 arbiter.advance_schedule();608 {
609 mc::MultiMonitorArbiter arbiter{mt::fake_shared(schedule)};
610 arbiter.advance_schedule();
611 }
612 EXPECT_TRUE(*buffer_released);
554}613}
555614
=== modified file 'tests/unit-tests/compositor/test_stream.cpp'
--- tests/unit-tests/compositor/test_stream.cpp 2017-05-08 03:04:26 +0000
+++ tests/unit-tests/compositor/test_stream.cpp 2017-07-18 03:23:56 +0000
@@ -22,7 +22,6 @@
22#include "mir/test/fake_shared.h"22#include "mir/test/fake_shared.h"
23#include "src/server/compositor/stream.h"23#include "src/server/compositor/stream.h"
24#include "mir/scene/null_surface_observer.h"24#include "mir/scene/null_surface_observer.h"
25#include "mir/frontend/client_buffers.h"
2625
27#include <gmock/gmock.h>26#include <gmock/gmock.h>
28#include <gtest/gtest.h>27#include <gtest/gtest.h>
@@ -41,45 +40,6 @@
41 MOCK_METHOD2(frame_posted, void(int, geom::Size const&));40 MOCK_METHOD2(frame_posted, void(int, geom::Size const&));
42};41};
4342
44struct StubBufferMap : mf::ClientBuffers
45{
46 StubBufferMap(mf::EventSink& sink, std::vector<std::shared_ptr<mg::Buffer>>& buffers) :
47 buffers{buffers},
48 sink{sink}
49 {
50 }
51 mg::BufferID add_buffer(std::shared_ptr<mg::Buffer> const&)
52 {
53 return mg::BufferID{};
54 }
55 void remove_buffer(mg::BufferID)
56 {
57 }
58 void with_buffer(mg::BufferID, std::function<void(mg::Buffer&)> const&)
59 {
60 }
61 void receive_buffer(mg::BufferID)
62 {
63 }
64 void send_buffer(mg::BufferID id)
65 {
66 sink.send_buffer(mf::BufferStreamId{33}, *get(id), mg::BufferIpcMsgType::update_msg);
67 }
68 std::shared_ptr<mg::Buffer> get(mg::BufferID id) const
69 {
70 auto it = std::find_if(buffers.begin(), buffers.end(),
71 [id](std::shared_ptr<mg::Buffer> const& b)
72 {
73 return b->id() == id;
74 });
75 if (it == buffers.end())
76 throw std::logic_error("cannot find buffer in map");
77 return *it;
78 }
79 std::vector<std::shared_ptr<mg::Buffer>>& buffers;
80 mf::EventSink& sink;
81};
82
83struct Stream : Test43struct Stream : Test
84{44{
85 Stream() :45 Stream() :
@@ -94,16 +54,14 @@
9454
95 geom::Size initial_size{44,2};55 geom::Size initial_size{44,2};
96 std::vector<std::shared_ptr<mg::Buffer>> buffers;56 std::vector<std::shared_ptr<mg::Buffer>> buffers;
97 NiceMock<mtd::MockEventSink> mock_sink;
98 MirPixelFormat construction_format{mir_pixel_format_rgb_565};57 MirPixelFormat construction_format{mir_pixel_format_rgb_565};
99 mc::Stream stream{58 mc::Stream stream{
100 std::make_unique<StubBufferMap>(mock_sink, buffers), initial_size, construction_format};59 initial_size, construction_format};
101};60};
102}61}
10362
104TEST_F(Stream, transitions_from_queuing_to_framedropping)63TEST_F(Stream, transitions_from_queuing_to_framedropping)
105{64{
106 EXPECT_CALL(mock_sink, send_buffer(_,_,_)).Times(buffers.size() - 1);
107 for(auto& buffer : buffers)65 for(auto& buffer : buffers)
108 stream.submit_buffer(buffer);66 stream.submit_buffer(buffer);
109 stream.allow_framedropping(true);67 stream.allow_framedropping(true);
@@ -111,25 +69,37 @@
111 std::vector<std::shared_ptr<mg::Buffer>> cbuffers;69 std::vector<std::shared_ptr<mg::Buffer>> cbuffers;
112 while(stream.buffers_ready_for_compositor(this))70 while(stream.buffers_ready_for_compositor(this))
113 cbuffers.push_back(stream.lock_compositor_buffer(this));71 cbuffers.push_back(stream.lock_compositor_buffer(this));
72 // Transition to framedropping should have dropped all queued buffers but the last...
114 ASSERT_THAT(cbuffers, SizeIs(1));73 ASSERT_THAT(cbuffers, SizeIs(1));
115 EXPECT_THAT(cbuffers[0]->id(), Eq(buffers.back()->id()));74 EXPECT_THAT(cbuffers[0]->id(), Eq(buffers.back()->id()));
116 Mock::VerifyAndClearExpectations(&mock_sink);75
76 for (unsigned long i = 0; i < buffers.size() - 1; ++i)
77 {
78 // ...and so all the previous buffers should no longer have external references
79 EXPECT_TRUE(buffers[i].unique());
80 }
117}81}
11882
119TEST_F(Stream, transitions_from_framedropping_to_queuing)83TEST_F(Stream, transitions_from_framedropping_to_queuing)
120{84{
121 stream.allow_framedropping(true);85 stream.allow_framedropping(true);
122 Mock::VerifyAndClearExpectations(&mock_sink);
12386
124 EXPECT_CALL(mock_sink, send_buffer(_,_,_)).Times(buffers.size() - 1);
125 for(auto& buffer : buffers)87 for(auto& buffer : buffers)
126 stream.submit_buffer(buffer);88 stream.submit_buffer(buffer);
12789
90 // Only the last buffer should be owned by the stream...
91 EXPECT_THAT(
92 std::make_tuple(buffers.data(), buffers.size() - 1),
93 Each(Property(&std::shared_ptr<mg::Buffer>::unique, Eq(true))));
94
128 stream.allow_framedropping(false);95 stream.allow_framedropping(false);
129 for(auto& buffer : buffers)96 for(auto& buffer : buffers)
130 stream.submit_buffer(buffer);97 stream.submit_buffer(buffer);
13198
132 Mock::VerifyAndClearExpectations(&mock_sink);99 // All buffers should be now owned by the the stream
100 EXPECT_THAT(
101 buffers,
102 Each(Property(&std::shared_ptr<mg::Buffer>::unique, Eq(false))));
133103
134 std::vector<std::shared_ptr<mg::Buffer>> cbuffers;104 std::vector<std::shared_ptr<mg::Buffer>> cbuffers;
135 while(stream.buffers_ready_for_compositor(this))105 while(stream.buffers_ready_for_compositor(this))
@@ -180,23 +150,6 @@
180 stream.submit_buffer(buffers[0]);150 stream.submit_buffer(buffers[0]);
181}151}
182152
183TEST_F(Stream, wakes_compositor_before_starting_socket_io)
184{
185 auto observer = std::make_shared<MockSurfaceObserver>();
186
187 InSequence seq;
188 EXPECT_CALL(*observer, frame_posted(_,_)).Times(2);
189 EXPECT_CALL(mock_sink, send_buffer(_,_,_)).Times(1);
190
191 stream.add_observer(observer);
192 stream.allow_framedropping(true);
193 stream.submit_buffer(buffers[0]);
194 stream.submit_buffer(buffers[1]);
195 stream.remove_observer(observer);
196
197 Mock::VerifyAndClearExpectations(&mock_sink);
198}
199
200TEST_F(Stream, calls_observers_call_doesnt_hold_lock)153TEST_F(Stream, calls_observers_call_doesnt_hold_lock)
201{154{
202 auto observer = std::make_shared<MockSurfaceObserver>();155 auto observer = std::make_shared<MockSurfaceObserver>();
@@ -269,9 +222,15 @@
269 stream.submit_buffer(buffers[1]);222 stream.submit_buffer(buffers[1]);
270 stream.submit_buffer(buffers[2]);223 stream.submit_buffer(buffers[2]);
271224
272 Mock::VerifyAndClearExpectations(&mock_sink);225 // Buffers should be owned by the stream, and our test
273 EXPECT_CALL(mock_sink, send_buffer(_,Ref(*buffers[0]),_));226 ASSERT_THAT(buffers[0].use_count(), Eq(2));
274 EXPECT_CALL(mock_sink, send_buffer(_,Ref(*buffers[1]),_));227 ASSERT_THAT(buffers[1].use_count(), Eq(2));
228 ASSERT_THAT(buffers[2].use_count(), Eq(2));
229
275 stream.drop_old_buffers();230 stream.drop_old_buffers();
276 Mock::VerifyAndClearExpectations(&mock_sink);231
232 // Stream should have released ownership of all but the most recent buffer
233 EXPECT_THAT(buffers[0].use_count(), Eq(1));
234 EXPECT_THAT(buffers[1].use_count(), Eq(1));
235 EXPECT_THAT(buffers[2].use_count(), Eq(2));
277}236}
278237
=== modified file 'tests/unit-tests/frontend/test_session_mediator.cpp'
--- tests/unit-tests/frontend/test_session_mediator.cpp 2017-05-25 08:58:03 +0000
+++ tests/unit-tests/frontend/test_session_mediator.cpp 2017-07-18 03:23:56 +0000
@@ -32,6 +32,7 @@
32#include "mir/graphics/buffer_ipc_message.h"32#include "mir/graphics/buffer_ipc_message.h"
33#include "mir/graphics/platform_operation_message.h"33#include "mir/graphics/platform_operation_message.h"
34#include "mir/graphics/buffer_id.h"34#include "mir/graphics/buffer_id.h"
35#include "mir/graphics/graphic_buffer_allocator.h"
35#include "mir/input/cursor_images.h"36#include "mir/input/cursor_images.h"
36#include "mir/graphics/platform_ipc_operations.h"37#include "mir/graphics/platform_ipc_operations.h"
37#include "mir/scene/coordinate_translator.h"38#include "mir/scene/coordinate_translator.h"
@@ -61,6 +62,7 @@
61#include "mir/test/doubles/mock_message_sender.h"62#include "mir/test/doubles/mock_message_sender.h"
62#include "mir/test/doubles/mock_input_config_changer.h"63#include "mir/test/doubles/mock_input_config_changer.h"
63#include "mir/test/doubles/stub_input_device.h"64#include "mir/test/doubles/stub_input_device.h"
65#include "mir/test/doubles/stub_buffer.h"
64#include "mir/test/display_config_matchers.h"66#include "mir/test/display_config_matchers.h"
65#include "mir/test/input_devices_matcher.h"67#include "mir/test/input_devices_matcher.h"
66#include "mir/test/fake_shared.h"68#include "mir/test/fake_shared.h"
@@ -119,11 +121,6 @@
119class StubbedSession : public mtd::StubSession121class StubbedSession : public mtd::StubSession
120{122{
121public:123public:
122 StubbedSession()
123 {
124 ON_CALL(*this, destroy_buffer(_))
125 .WillByDefault(Invoke([this](mg::BufferID){ ++destroy_buffers;}));
126 }
127 std::shared_ptr<mf::Surface> get_surface(mf::SurfaceId surface) const override124 std::shared_ptr<mf::Surface> get_surface(mf::SurfaceId surface) const override
128 {125 {
129 if (mock_surfaces.find(surface) == mock_surfaces.end())126 if (mock_surfaces.find(surface) == mock_surfaces.end())
@@ -195,27 +192,8 @@
195 mock_surfaces.erase(surface);192 mock_surfaces.erase(surface);
196 }193 }
197194
198
199 mg::BufferID create_buffer(mg::BufferProperties const&) override
200 {
201 buffer_count++;
202 return mg::BufferID{3};
203 }
204
205 mg::BufferID create_buffer(geom::Size, MirPixelFormat) override
206 {
207 buffer_count++;
208 return mg::BufferID{3};
209 }
210
211 mg::BufferID create_buffer(geom::Size, uint32_t, uint32_t) override
212 {
213 native_buffer_count++;
214 return mg::BufferID{3};
215 }
216195
217 MOCK_METHOD1(destroy_buffer_stream, void(mf::BufferStreamId));196 MOCK_METHOD1(destroy_buffer_stream, void(mf::BufferStreamId));
218 MOCK_METHOD1(destroy_buffer, void(mg::BufferID));
219197
220 int num_alloc_requests()198 int num_alloc_requests()
221 {199 {
@@ -258,6 +236,42 @@
258 }236 }
259};237};
260238
239struct RecordingBufferAllocator : public mg::GraphicBufferAllocator
240{
241 std::shared_ptr<mg::Buffer> alloc_buffer(mg::BufferProperties const& buffer_properties) override
242 {
243 auto const buf = std::make_shared<mtd::StubBuffer>(buffer_properties);
244 allocated_buffers.push_back(buf);
245 return buf;
246 }
247
248 std::vector<MirPixelFormat> supported_pixel_formats() override
249 {
250 return {};
251 }
252
253 std::shared_ptr<mg::Buffer> alloc_buffer(
254 geom::Size size, uint32_t /*native_format*/, uint32_t /*native_flags*/) override
255 {
256 auto const buf = std::make_shared<mtd::StubBuffer>(size);
257 allocated_buffers.push_back(buf);
258 return buf;
259 }
260
261 std::shared_ptr<mg::Buffer> alloc_software_buffer(
262 geom::Size size, MirPixelFormat format) override
263 {
264 if ((format >= mir_pixel_formats) || format == mir_pixel_format_invalid)
265 BOOST_THROW_EXCEPTION((std::runtime_error{"Invalid pixel format"}));
266
267 auto const buf = std::make_shared<mtd::StubBuffer>(size);
268 allocated_buffers.push_back(buf);
269 return buf;
270 }
271
272 std::vector<std::weak_ptr<mg::Buffer>> allocated_buffers;
273};
274
261struct SessionMediator : public ::testing::Test275struct SessionMediator : public ::testing::Test
262{276{
263 SessionMediator()277 SessionMediator()
@@ -269,6 +283,7 @@
269 stub_screencast{std::make_shared<StubScreencast>()},283 stub_screencast{std::make_shared<StubScreencast>()},
270 stubbed_session{std::make_shared<NiceMock<StubbedSession>>()},284 stubbed_session{std::make_shared<NiceMock<StubbedSession>>()},
271 null_callback{google::protobuf::NewPermanentCallback(google::protobuf::DoNothing)},285 null_callback{google::protobuf::NewPermanentCallback(google::protobuf::DoNothing)},
286 allocator{std::make_shared<RecordingBufferAllocator>()},
272 mediator{287 mediator{
273 shell, mt::fake_shared(mock_ipc_operations), graphics_changer,288 shell, mt::fake_shared(mock_ipc_operations), graphics_changer,
274 surface_pixel_formats, report,289 surface_pixel_formats, report,
@@ -280,7 +295,8 @@
280 std::make_shared<mtd::NullANRDetector>(),295 std::make_shared<mtd::NullANRDetector>(),
281 mir::cookie::Authority::create(),296 mir::cookie::Authority::create(),
282 mt::fake_shared(mock_input_config_changer),297 mt::fake_shared(mock_input_config_changer),
283 {}}298 {},
299 allocator}
284 {300 {
285 using namespace ::testing;301 using namespace ::testing;
286302
@@ -310,7 +326,8 @@
310 std::make_shared<NullCoordinateTranslator>(),326 std::make_shared<NullCoordinateTranslator>(),
311 std::make_shared<mtd::NullANRDetector>(),327 std::make_shared<mtd::NullANRDetector>(),
312 mir::cookie::Authority::create(),328 mir::cookie::Authority::create(),
313 mt::fake_shared(mock_input_config_changer), std::vector<mir::ExtensionDescription>{});329 mt::fake_shared(mock_input_config_changer), std::vector<mir::ExtensionDescription>{},
330 allocator);
314 }331 }
315332
316 std::shared_ptr<mf::SessionMediator> create_session_mediator_with_screencast(333 std::shared_ptr<mf::SessionMediator> create_session_mediator_with_screencast(
@@ -325,7 +342,112 @@
325 std::make_shared<NullCoordinateTranslator>(),342 std::make_shared<NullCoordinateTranslator>(),
326 std::make_shared<mtd::NullANRDetector>(),343 std::make_shared<mtd::NullANRDetector>(),
327 mir::cookie::Authority::create(),344 mir::cookie::Authority::create(),
328 mt::fake_shared(mock_input_config_changer), std::vector<mir::ExtensionDescription>{});345 mt::fake_shared(mock_input_config_changer), std::vector<mir::ExtensionDescription>{},
346 allocator);
347 }
348
349 std::shared_ptr<mf::SessionMediator> create_session_mediator_with_event_sink(
350 std::shared_ptr<mf::EventSink> const& sink)
351 {
352 class WrappingEventSink : public mf::EventSink
353 {
354 public:
355 WrappingEventSink(std::shared_ptr<mf::EventSink> const& wrapped)
356 : wrapped{wrapped}
357 {
358 }
359
360 void handle_event(MirEvent const &e) override
361 {
362 wrapped->handle_event(e);
363 }
364
365 void handle_lifecycle_event(MirLifecycleState state) override
366 {
367 wrapped->handle_lifecycle_event(state);
368 }
369
370 void handle_display_config_change(
371 mg::DisplayConfiguration const& config) override
372 {
373 wrapped->handle_display_config_change(config);
374 }
375
376 void send_ping(int32_t serial) override
377 {
378 wrapped->send_ping(serial);
379 }
380
381 void handle_input_config_change(MirInputConfig const& config) override
382 {
383 wrapped->handle_input_config_change(config);
384 }
385
386 void handle_error(mir::ClientVisibleError const& error) override
387 {
388 wrapped->handle_error(error);
389 }
390
391 void send_buffer(
392 mf::BufferStreamId id,
393 mg::Buffer& buffer,
394 mg::BufferIpcMsgType type) override
395 {
396 wrapped->send_buffer(id, buffer, type);
397 }
398
399 void add_buffer(mg::Buffer& buffer) override
400 {
401 wrapped->add_buffer(buffer);
402 }
403
404 void error_buffer(
405 geom::Size req_size,
406 MirPixelFormat req_format,
407 std::string const &error_msg) override
408 {
409 wrapped->error_buffer(req_size, req_format, error_msg);
410 }
411
412 void update_buffer(mg::Buffer &buffer) override
413 {
414 wrapped->update_buffer(buffer);
415 }
416
417 private:
418 std::shared_ptr<mf::EventSink> const wrapped;
419 };
420
421 class EventSinkFactory : public mf::EventSinkFactory
422 {
423 public:
424 EventSinkFactory(std::shared_ptr<mf::EventSink> const& sink)
425 : the_sink{sink}
426 {
427 }
428
429 std::unique_ptr<mf::EventSink> create_sink(
430 std::shared_ptr<mf::MessageSender> const&) override
431 {
432 return std::make_unique<WrappingEventSink>(the_sink);
433 }
434
435 private:
436 std::shared_ptr<mf::EventSink> const the_sink;
437 };
438
439 return std::make_shared<mf::SessionMediator>(
440 shell, mt::fake_shared(mock_ipc_operations), graphics_changer,
441 surface_pixel_formats, report,
442 std::make_shared<EventSinkFactory>(sink),
443 std::make_shared<mtd::NullMessageSender>(),
444 resource_cache, stub_screencast, &connector, nullptr,
445 std::make_shared<NullCoordinateTranslator>(),
446 std::make_shared<mtd::NullANRDetector>(),
447 mir::cookie::Authority::create(),
448 mt::fake_shared(mock_input_config_changer),
449 std::vector<mir::ExtensionDescription>{},
450 allocator);
329 }451 }
330452
331 MockConnector connector;453 MockConnector connector;
@@ -339,6 +461,7 @@
339 std::shared_ptr<StubScreencast> const stub_screencast;461 std::shared_ptr<StubScreencast> const stub_screencast;
340 std::shared_ptr<NiceMock<StubbedSession>> const stubbed_session;462 std::shared_ptr<NiceMock<StubbedSession>> const stubbed_session;
341 std::unique_ptr<google::protobuf::Closure> null_callback;463 std::unique_ptr<google::protobuf::Closure> null_callback;
464 std::shared_ptr<RecordingBufferAllocator> const allocator;
342 mf::SessionMediator mediator;465 mf::SessionMediator mediator;
343466
344 mp::ConnectParameters connect_parameters;467 mp::ConnectParameters connect_parameters;
@@ -383,7 +506,8 @@
383 std::make_shared<NullCoordinateTranslator>(),506 std::make_shared<NullCoordinateTranslator>(),
384 std::make_shared<mtd::NullANRDetector>(),507 std::make_shared<mtd::NullANRDetector>(),
385 mir::cookie::Authority::create(),508 mir::cookie::Authority::create(),
386 mt::fake_shared(mock_input_config_changer), {}};509 mt::fake_shared(mock_input_config_changer), {},
510 allocator};
387511
388 EXPECT_THAT(connects_handled_count, Eq(0));512 EXPECT_THAT(connects_handled_count, Eq(0));
389513
@@ -413,21 +537,6 @@
413 }, std::logic_error);537 }, std::logic_error);
414}538}
415539
416TEST_F(SessionMediator, calling_methods_after_connect_works)
417{
418 mediator.connect(&connect_parameters, &connection, null_callback.get());
419
420 EXPECT_NO_THROW({
421 mediator.create_surface(&surface_parameters, &surface_response, null_callback.get());
422 *buffer_request.mutable_buffer() = surface_response.buffer_stream().buffer();
423 buffer_request.mutable_id()->set_value(surface_response.id().value());
424 mediator.submit_buffer(&buffer_request, nullptr, null_callback.get());
425 mediator.release_surface(&surface_id_request, nullptr, null_callback.get());
426 });
427
428 mediator.disconnect(nullptr, nullptr, null_callback.get());
429}
430
431TEST_F(SessionMediator, calling_methods_after_disconnect_throws)540TEST_F(SessionMediator, calling_methods_after_disconnect_throws)
432{541{
433 mediator.connect(&connect_parameters, &connection, null_callback.get());542 mediator.connect(&connect_parameters, &connection, null_callback.get());
@@ -701,15 +810,20 @@
701 mediator.modify_surface(&mods, &null, null_callback.get());810 mediator.modify_surface(&mods, &null, null_callback.get());
702}811}
703812
704TEST_F(SessionMediator, allocates_software_buffers_from_the_session)813TEST_F(SessionMediator, allocates_software_buffers)
705{814{
706 using namespace testing;815 using namespace testing;
816
817 auto sink = std::make_shared<NiceMock<mtd::MockEventSink>>();
818 auto mediator = create_session_mediator_with_event_sink(sink);
819
820 mediator->connect(&connect_parameters, &connection, null_callback.get());
821 mediator->create_surface(&surface_parameters, &surface_response, null_callback.get());
822
707 auto num_requests = 3;823 auto num_requests = 3;
708 mp::Void null;824 mp::Void null;
709 mp::BufferStreamId id;
710 id.set_value(0);
711 mp::BufferAllocation request;825 mp::BufferAllocation request;
712 *request.mutable_id() = id;826 *request.mutable_id() = surface_response.buffer_stream().id();
713 mg::BufferProperties properties(geom::Size{34, 84}, mir_pixel_format_abgr_8888, mg::BufferUsage::hardware);827 mg::BufferProperties properties(geom::Size{34, 84}, mir_pixel_format_abgr_8888, mg::BufferUsage::hardware);
714 for(auto i = 0; i < num_requests; i++)828 for(auto i = 0; i < num_requests; i++)
715 {829 {
@@ -720,58 +834,79 @@
720 buffer_request->set_buffer_usage((int)properties.usage);834 buffer_request->set_buffer_usage((int)properties.usage);
721 }835 }
722836
723 mediator.connect(&connect_parameters, &connection, null_callback.get());
724 mediator.create_surface(&surface_parameters, &surface_response, null_callback.get());
725837
726 mediator.allocate_buffers(&request, &null, null_callback.get());838 EXPECT_CALL(*sink, add_buffer(_)).Times(num_requests);
727 EXPECT_THAT(stubbed_session->num_alloc_requests(), Eq(num_requests));839 EXPECT_CALL(*sink, error_buffer(_,_,_)).Times(0);
840 mediator->allocate_buffers(&request, &null, null_callback.get());
841 EXPECT_THAT(allocator->allocated_buffers.size(), Eq(num_requests));
728}842}
729843
730TEST_F(SessionMediator, allocates_native_buffers_from_the_session)844TEST_F(SessionMediator, allocates_native_buffers)
731{845{
732 using namespace testing;846 using namespace testing;
847
848 auto sink = std::make_shared<NiceMock<mtd::MockEventSink>>();
849 auto mediator = create_session_mediator_with_event_sink(sink);
850
851 mediator->connect(&connect_parameters, &connection, null_callback.get());
852 mediator->create_surface(&surface_parameters, &surface_response, null_callback.get());
853
733 geom::Size const size { 1029, 10302 };854 geom::Size const size { 1029, 10302 };
734 auto native_flags = 24u;855 auto native_flags = 24u;
735 auto native_format = 124u;856 auto native_format = 124u;
736 mp::Void null;857 mp::Void null;
737 mp::BufferStreamId id;
738 id.set_value(0);
739 mp::BufferAllocation request;858 mp::BufferAllocation request;
740 *request.mutable_id() = id;859 *request.mutable_id() = surface_response.buffer_stream().id();
741 auto buffer_request = request.add_buffer_requests();860 auto buffer_request = request.add_buffer_requests();
742 buffer_request->set_width(size.width.as_int());861 buffer_request->set_width(size.width.as_int());
743 buffer_request->set_height(size.height.as_int());862 buffer_request->set_height(size.height.as_int());
744 buffer_request->set_native_format(native_format);863 buffer_request->set_native_format(native_format);
745 buffer_request->set_flags(native_flags);864 buffer_request->set_flags(native_flags);
746865
747 mediator.connect(&connect_parameters, &connection, null_callback.get());866 EXPECT_CALL(*sink, add_buffer(_)).Times(1);
748 mediator.create_surface(&surface_parameters, &surface_response, null_callback.get());867 EXPECT_CALL(*sink, error_buffer(_,_,_)).Times(0);
749868 mediator->allocate_buffers(&request, &null, null_callback.get());
750 mediator.allocate_buffers(&request, &null, null_callback.get());869 EXPECT_THAT(allocator->allocated_buffers.size(), Eq(1));
751 EXPECT_THAT(stubbed_session->native_buffer_count, Eq(1));
752}870}
753871
754TEST_F(SessionMediator, removes_buffer_from_the_session)872TEST_F(SessionMediator, removes_buffer)
755{873{
756 using namespace testing;874 using namespace testing;
757 auto num_requests = 3;875 auto num_requests = 3;
758 mp::Void null;876 mp::Void null;
759 mp::BufferStreamId id;
760 id.set_value(0);
761 mp::BufferRelease request;877 mp::BufferRelease request;
762 *request.mutable_id() = id;878
763 auto buffer_id = 442u;879 // Allocate some buffers so we can release them later...
880 mp::BufferAllocation allocate_request;
764 for(auto i = 0; i < num_requests; i++)881 for(auto i = 0; i < num_requests; i++)
765 {882 {
766 auto buffer_request = request.add_buffers();883 auto allocate = allocate_request.add_buffer_requests();
767 buffer_request->set_buffer_id(buffer_id);884 allocate->set_buffer_usage(static_cast<int32_t>(mg::BufferUsage::software));
885 allocate->set_pixel_format(mir_pixel_format_abgr_8888);
886 allocate->set_width(640);
887 allocate->set_height(480);
768 }888 }
769889
770 mediator.connect(&connect_parameters, &connection, null_callback.get());890 mediator.connect(&connect_parameters, &connection, null_callback.get());
771 mediator.create_surface(&surface_parameters, &surface_response, null_callback.get());891 mediator.allocate_buffers(&allocate_request, &null, null_callback.get());
772892
893 ASSERT_THAT(allocator->allocated_buffers.size(), Eq(num_requests));
894
895 // ...Pull out the BufferIDs of the buffers we've allocated...
896 for (auto weak_buffer : allocator->allocated_buffers)
897 {
898 auto buffer = weak_buffer.lock();
899 ASSERT_THAT(buffer, NotNull());
900
901 auto release_buffer = request.add_buffers();
902 release_buffer->set_buffer_id(buffer->id().as_value());
903 }
904
905 // ...and now release all those buffers.
773 mediator.release_buffers(&request, &null, null_callback.get());906 mediator.release_buffers(&request, &null, null_callback.get());
774 EXPECT_THAT(stubbed_session->num_destroy_requests(), Eq(num_requests));907 EXPECT_THAT(
908 allocator->allocated_buffers,
909 Each(Property(&std::weak_ptr<mg::Buffer>::expired, Eq(true))));
775}910}
776911
777TEST_F(SessionMediator, configures_swap_intervals_on_streams)912TEST_F(SessionMediator, configures_swap_intervals_on_streams)
@@ -861,7 +996,8 @@
861 std::make_shared<NullCoordinateTranslator>(),996 std::make_shared<NullCoordinateTranslator>(),
862 std::make_shared<mtd::NullANRDetector>(),997 std::make_shared<mtd::NullANRDetector>(),
863 mir::cookie::Authority::create(),998 mir::cookie::Authority::create(),
864 mt::fake_shared(mock_input_config_changer), {}};999 mt::fake_shared(mock_input_config_changer), {},
1000 allocator};
8651001
866 ON_CALL(*shell, create_surface( _, _, _))1002 ON_CALL(*shell, create_surface( _, _, _))
867 .WillByDefault(1003 .WillByDefault(
@@ -1022,22 +1158,49 @@
1022TEST_F(SessionMediator, disassociates_buffers_from_stream_before_destroying)1158TEST_F(SessionMediator, disassociates_buffers_from_stream_before_destroying)
1023{1159{
1024 mp::BufferRelease release_buffer;1160 mp::BufferRelease release_buffer;
1161 mp::BufferAllocation allocate_buffer;
1025 mp::Void null;1162 mp::Void null;
10261163
1164 // Add a fake BufferStream...
1027 auto stream_id = mf::BufferStreamId{42};1165 auto stream_id = mf::BufferStreamId{42};
1028 auto buffer_id = mir::graphics::BufferID{42};
1029 auto stream = stubbed_session->create_mock_stream(stream_id);1166 auto stream = stubbed_session->create_mock_stream(stream_id);
1030 auto buffer1 = std::make_shared<mtd::StubBuffer>();1167
1168 // ...and allocate a buffer to it
1169 allocate_buffer.mutable_id()->set_value(42);
1170 auto buffer_props = allocate_buffer.add_buffer_requests();
1171 buffer_props->set_buffer_usage(0);
1172 buffer_props->set_pixel_format(0);
1173 buffer_props->set_width(230);
1174 buffer_props->set_height(230);
1175
1176 mediator.connect(&connect_parameters, &connection, null_callback.get());
1177 mediator.allocate_buffers(&allocate_buffer, &null, null_callback.get());
1178
1179 ASSERT_THAT(allocator->allocated_buffers.size(), Eq(1));
1180 auto allocated_buffer = allocator->allocated_buffers.front().lock();
1181 ASSERT_THAT(allocated_buffer, NotNull());
1182
1183 auto const buffer_id = allocated_buffer->id();
1184
1185 // Release our share of the buffer ownership.
1186 allocated_buffer.reset();
10311187
1032 auto buffer_item = release_buffer.add_buffers();1188 auto buffer_item = release_buffer.add_buffers();
1033 buffer_item->set_buffer_id(buffer_id.as_value());1189 buffer_item->set_buffer_id(buffer_id.as_value());
1034 release_buffer.mutable_id()->set_value(stream_id.as_value());1190 release_buffer.mutable_id()->set_value(stream_id.as_value());
10351191
1036 EXPECT_CALL(*stream, disassociate_buffer(buffer_id));1192 EXPECT_CALL(*stream, disassociate_buffer(buffer_id))
1037 EXPECT_CALL(*stubbed_session, destroy_buffer(buffer_id));1193 .WillOnce(InvokeWithoutArgs(
1194 [weak_buffer = allocator->allocated_buffers.front()]()
1195 {
1196 // The buffer should be live here!
1197 EXPECT_THAT(weak_buffer.lock(), NotNull());
1198 }));
10381199
1039 mediator.connect(&connect_parameters, &connection, null_callback.get());
1040 mediator.release_buffers(&release_buffer, &null, null_callback.get());1200 mediator.release_buffers(&release_buffer, &null, null_callback.get());
1201
1202 // And now we expect the buffer to have been destroyed.
1203 EXPECT_THAT(allocator->allocated_buffers.front().lock(), IsNull());
1041}1204}
10421205
1043TEST_F(SessionMediator, releases_buffers_of_unknown_buffer_stream_does_not_throw)1206TEST_F(SessionMediator, releases_buffers_of_unknown_buffer_stream_does_not_throw)
@@ -1046,10 +1209,30 @@
1046 mp::BufferRelease release_buffer;1209 mp::BufferRelease release_buffer;
1047 mp::Void null;1210 mp::Void null;
10481211
1212 // Add a fake BufferStream...
1049 auto stream_id = mf::BufferStreamId{42};1213 auto stream_id = mf::BufferStreamId{42};
1050 auto buffer_id = mir::graphics::BufferID{42};
1051 auto stream = stubbed_session->create_mock_stream(stream_id);1214 auto stream = stubbed_session->create_mock_stream(stream_id);
1052 auto buffer1 = std::make_shared<mtd::StubBuffer>();1215
1216 // ...and allocate a buffer to it
1217 mp::BufferAllocation allocate_buffer;
1218 allocate_buffer.mutable_id()->set_value(42);
1219 auto buffer_props = allocate_buffer.add_buffer_requests();
1220 buffer_props->set_buffer_usage(0);
1221 buffer_props->set_pixel_format(0);
1222 buffer_props->set_width(230);
1223 buffer_props->set_height(230);
1224
1225 mediator.connect(&connect_parameters, &connection, null_callback.get());
1226 mediator.allocate_buffers(&allocate_buffer, &null, null_callback.get());
1227
1228 ASSERT_THAT(allocator->allocated_buffers.size(), Eq(1));
1229 auto allocated_buffer = allocator->allocated_buffers.front().lock();
1230 ASSERT_THAT(allocated_buffer, NotNull());
1231
1232 auto const buffer_id = allocated_buffer->id();
1233
1234 // Release our share of the buffer ownership.
1235 allocated_buffer.reset();
10531236
1054 auto buffer_item = release_buffer.add_buffers();1237 auto buffer_item = release_buffer.add_buffers();
1055 buffer_item->set_buffer_id(buffer_id.as_value());1238 buffer_item->set_buffer_id(buffer_id.as_value());
@@ -1058,15 +1241,15 @@
1058 stream_to_release.set_value(stream_id.as_value());1241 stream_to_release.set_value(stream_id.as_value());
10591242
1060 EXPECT_CALL(*stubbed_session, destroy_buffer_stream(stream_id));1243 EXPECT_CALL(*stubbed_session, destroy_buffer_stream(stream_id));
1061 EXPECT_CALL(*stubbed_session, destroy_buffer(buffer_id));
10621244
1063 mediator.connect(&connect_parameters, &connection, null_callback.get());
1064 mediator.release_buffer_stream(&stream_to_release, &null, null_callback.get());1245 mediator.release_buffer_stream(&stream_to_release, &null, null_callback.get());
1065 stream.reset();1246 stream.reset();
10661247
1067 EXPECT_NO_THROW(1248 EXPECT_NO_THROW(
1068 mediator.release_buffers(&release_buffer, &null, null_callback.get());1249 mediator.release_buffers(&release_buffer, &null, null_callback.get());
1069 );1250 );
1251
1252 EXPECT_TRUE(allocator->allocated_buffers.front().expired());
1070}1253}
10711254
1072MATCHER_P3(CursorIs, id_value, x_value, y_value, "cursor configuration match")1255MATCHER_P3(CursorIs, id_value, x_value, y_value, "cursor configuration match")
@@ -1165,7 +1348,6 @@
1165 buffer_request->set_height(129);1348 buffer_request->set_height(129);
1166 buffer_request->set_pixel_format(mir_pixel_format_abgr_8888);1349 buffer_request->set_pixel_format(mir_pixel_format_abgr_8888);
1167 buffer_request->set_buffer_usage(mir_buffer_usage_hardware);1350 buffer_request->set_buffer_usage(mir_buffer_usage_hardware);
1168 int buffer_id = 3;
1169 mf::ScreencastSessionId screencast_id{7};1351 mf::ScreencastSessionId screencast_id{7};
1170 auto mock_screencast = std::make_shared<NiceMock<mtd::MockScreencast>>();1352 auto mock_screencast = std::make_shared<NiceMock<mtd::MockScreencast>>();
11711353
@@ -1181,7 +1363,180 @@
1181 mp::ScreencastRequest screencast_request;1363 mp::ScreencastRequest screencast_request;
11821364
1183 screencast_request.mutable_id()->set_value(screencast_id.as_value());1365 screencast_request.mutable_id()->set_value(screencast_id.as_value());
1184 screencast_request.set_buffer_id(buffer_id);1366 screencast_request.set_buffer_id(allocator->allocated_buffers.front().lock()->id().as_value());
11851367
1186 mediator->screencast_to_buffer(&screencast_request, &null, null_callback.get());1368 mediator->screencast_to_buffer(&screencast_request, &null, null_callback.get());
1187}1369}
1370
1371namespace
1372{
1373void add_software_buffer_request(
1374 mp::BufferAllocation& request,
1375 int width,
1376 int height,
1377 MirPixelFormat format)
1378{
1379 auto buffer_request = request.add_buffer_requests();
1380 buffer_request->set_width(width);
1381 buffer_request->set_height(height);
1382 buffer_request->set_pixel_format(format);
1383 buffer_request->set_buffer_usage(static_cast<int>(mg::BufferUsage::software));
1384}
1385
1386void add_hardware_request(
1387 mp::BufferAllocation& request,
1388 int width,
1389 int height,
1390 int native_format,
1391 int flags)
1392{
1393 auto buffer_request = request.add_buffer_requests();
1394
1395 buffer_request->set_width(width);
1396 buffer_request->set_height(height);
1397 buffer_request->set_native_format(native_format);
1398 buffer_request->set_flags(flags);
1399}
1400}
1401
1402TEST_F(SessionMediator, invalid_buffer_stream_in_software_buffer_allocation_sends_only_error_buffer)
1403{
1404 using namespace testing;
1405
1406 auto sink = std::make_shared<NiceMock<mtd::MockEventSink>>();
1407 auto mediator = create_session_mediator_with_event_sink(sink);
1408
1409 mediator->connect(&connect_parameters, &connection, null_callback.get());
1410
1411 auto num_requests = 3;
1412 mp::Void null;
1413 mp::BufferAllocation request;
1414 request.mutable_id()->set_value(-1);
1415 mg::BufferProperties properties(geom::Size{34, 84}, mir_pixel_format_abgr_8888, mg::BufferUsage::software);
1416 for(auto i = 0; i < num_requests; i++)
1417 {
1418 add_software_buffer_request(
1419 request,
1420 properties.size.width.as_int(),
1421 properties.size.height.as_int(),
1422 properties.format);
1423 }
1424
1425 EXPECT_CALL(*sink, add_buffer(_)).Times(0);
1426 EXPECT_CALL(*sink, error_buffer(_,_,_)).Times(num_requests);
1427 mediator->allocate_buffers(&request, &null, null_callback.get());
1428 EXPECT_THAT(allocator->allocated_buffers.size(), Eq(num_requests));
1429}
1430
1431TEST_F(SessionMediator, invalid_request_sends_error_buffer)
1432{
1433 using namespace testing;
1434
1435 auto sink = std::make_shared<NiceMock<mtd::MockEventSink>>();
1436 auto mediator = create_session_mediator_with_event_sink(sink);
1437
1438 mediator->connect(&connect_parameters, &connection, null_callback.get());
1439 mediator->create_surface(&surface_parameters, &surface_response, null_callback.get());
1440
1441 mp::Void null;
1442 mp::BufferAllocation request;
1443 *request.mutable_id() = surface_response.buffer_stream().id();
1444
1445 decltype(request.add_buffer_requests()) buffer_request;
1446
1447 // Loop through all possibilities of has_flags, has_native_format,
1448 // has_buffer_usage, has_pixel_format
1449 for (int i = 0 ; i < 1<<4; ++i)
1450 {
1451 buffer_request = request.add_buffer_requests();
1452 buffer_request->set_width(1024);
1453 buffer_request->set_height(768);
1454
1455 if (i & 1<<0)
1456 buffer_request->set_flags(0xfaac);
1457 if (i & 1<<1)
1458 buffer_request->set_native_format(0xdeeb);
1459 if (i & 1<<2)
1460 buffer_request->set_pixel_format(mir_pixel_format_abgr_8888);
1461 if (i & 1<<3)
1462 buffer_request->set_buffer_usage(static_cast<int>(mg::BufferUsage::software));
1463 }
1464
1465 // There are two valid allocations here - one with flags and native_format set,
1466 // one with pixel_format and buffer_usage set.
1467 EXPECT_CALL(*sink, add_buffer(_)).Times(2);
1468
1469 EXPECT_CALL(*sink, error_buffer(_,_,_)).Times(16 - 2);
1470 mediator->allocate_buffers(&request, &null, null_callback.get());
1471 EXPECT_THAT(allocator->allocated_buffers.size(), Eq(2));
1472}
1473
1474TEST_F(SessionMediator, sends_errors_only_for_invalid_buffer_parameters)
1475{
1476 using namespace testing;
1477
1478 auto sink = std::make_shared<NiceMock<mtd::MockEventSink>>();
1479 auto mediator = create_session_mediator_with_event_sink(sink);
1480
1481 mediator->connect(&connect_parameters, &connection, null_callback.get());
1482 mediator->create_surface(&surface_parameters, &surface_response, null_callback.get());
1483
1484 auto const num_requests = 3;
1485 mp::Void null;
1486 mp::BufferAllocation request;
1487 *request.mutable_id() = surface_response.buffer_stream().id();
1488 mg::BufferProperties properties(geom::Size{34, 84}, mir_pixel_format_abgr_8888, mg::BufferUsage::software);
1489 for(auto i = 0; i < num_requests; i++)
1490 {
1491 add_software_buffer_request(
1492 request,
1493 properties.size.width.as_int(),
1494 properties.size.height.as_int(),
1495 properties.format);
1496 }
1497
1498 // Make the 2nd buffer request invalid, leaving the 1st and 3rd valid
1499 request.mutable_buffer_requests(1)->set_pixel_format(mir_pixel_format_invalid);
1500
1501 EXPECT_CALL(*sink, add_buffer(_)).Times(num_requests - 1);
1502 EXPECT_CALL(*sink, error_buffer(_,_,_)).Times(1);
1503 mediator->allocate_buffers(&request, &null, null_callback.get());
1504 EXPECT_THAT(allocator->allocated_buffers.size(), Eq(num_requests - 1));
1505}
1506
1507TEST_F(SessionMediator, invalid_buffer_stream_in_native_buffer_allocation_sends_only_error_buffer)
1508{
1509 using namespace testing;
1510
1511 auto const num_requests = 3;
1512
1513 auto sink = std::make_shared<NiceMock<mtd::MockEventSink>>();
1514 auto mediator = create_session_mediator_with_event_sink(sink);
1515
1516 mediator->connect(&connect_parameters, &connection, null_callback.get());
1517
1518 geom::Size const size { 1029, 10302 };
1519 auto native_flags = 24u;
1520 auto native_format = 124u;
1521 mp::Void null;
1522 mp::BufferAllocation request;
1523 request.mutable_id()->set_value(42);
1524
1525 for (auto i = 0; i < num_requests; ++i)
1526 {
1527 add_hardware_request(
1528 request,
1529 size.width.as_int(),
1530 size.height.as_int(),
1531 native_format,
1532 native_flags);
1533 }
1534
1535 EXPECT_CALL(*sink, add_buffer(_)).Times(0);
1536 EXPECT_CALL(*sink, error_buffer(_,_,_)).Times(num_requests);
1537 mediator->allocate_buffers(&request, &null, null_callback.get());
1538 // We don't much care if the buffers were allocated and then freed or never allocated
1539 EXPECT_THAT(
1540 allocator->allocated_buffers,
1541 Each(Property(&std::weak_ptr<mg::Buffer>::expired, Eq(true))));
1542}
11881543
=== modified file 'tests/unit-tests/scene/test_application_session.cpp'
--- tests/unit-tests/scene/test_application_session.cpp 2017-05-25 04:43:29 +0000
+++ tests/unit-tests/scene/test_application_session.cpp 2017-07-18 03:23:56 +0000
@@ -63,17 +63,10 @@
6363
64struct MockBufferStreamFactory : public ms::BufferStreamFactory64struct MockBufferStreamFactory : public ms::BufferStreamFactory
65{65{
66 MockBufferStreamFactory()66 MOCK_METHOD2(create_buffer_stream, std::shared_ptr<mc::BufferStream>(
67 {67 mf::BufferStreamId, mg::BufferProperties const&));
68 ON_CALL(*this, create_buffer_map(testing::_))
69 .WillByDefault(testing::Return(std::make_shared<mtd::StubClientBuffers>()));
70 }
71 MOCK_METHOD3(create_buffer_stream, std::shared_ptr<mc::BufferStream>(68 MOCK_METHOD3(create_buffer_stream, std::shared_ptr<mc::BufferStream>(
72 mf::BufferStreamId, std::shared_ptr<mf::ClientBuffers> const&, mg::BufferProperties const&));69 mf::BufferStreamId, int, mg::BufferProperties const&));
73 MOCK_METHOD4(create_buffer_stream, std::shared_ptr<mc::BufferStream>(
74 mf::BufferStreamId, std::shared_ptr<mf::ClientBuffers> const&, int, mg::BufferProperties const&));
75 MOCK_METHOD1(create_buffer_map, std::shared_ptr<mf::ClientBuffers>(
76 std::shared_ptr<mf::BufferSink> const&));
77};70};
7871
7972
@@ -488,7 +481,7 @@
488 NiceMock<MockSurfaceFactory> surface_factory;481 NiceMock<MockSurfaceFactory> surface_factory;
489 MockBufferStreamFactory mock_buffer_stream_factory;482 MockBufferStreamFactory mock_buffer_stream_factory;
490 std::shared_ptr<mc::BufferStream> const mock_stream = std::make_shared<mtd::MockBufferStream>();483 std::shared_ptr<mc::BufferStream> const mock_stream = std::make_shared<mtd::MockBufferStream>();
491 ON_CALL(mock_buffer_stream_factory, create_buffer_stream(_,_,_)).WillByDefault(Return(mock_stream));484 ON_CALL(mock_buffer_stream_factory, create_buffer_stream(_,_)).WillByDefault(Return(mock_stream));
492 ON_CALL(surface_factory, create_surface(_,_)).WillByDefault(Return(mock_surface));485 ON_CALL(surface_factory, create_surface(_,_)).WillByDefault(Return(mock_surface));
493 NiceMock<mtd::MockSurfaceStack> surface_stack;486 NiceMock<mtd::MockSurfaceStack> surface_stack;
494487
@@ -588,7 +581,7 @@
588 std::make_shared<mtd::StubBufferStream>(),581 std::make_shared<mtd::StubBufferStream>(),
589 std::make_shared<mtd::StubBufferStream>()582 std::make_shared<mtd::StubBufferStream>()
590 }};583 }};
591 EXPECT_CALL(mock_bufferstream_factory, create_buffer_stream(_,_,_))584 EXPECT_CALL(mock_bufferstream_factory, create_buffer_stream(_,_))
592 .WillOnce(Return(streams[0]))585 .WillOnce(Return(streams[0]))
593 .WillOnce(Return(streams[1]))586 .WillOnce(Return(streams[1]))
594 .WillOnce(Return(streams[2]));587 .WillOnce(Return(streams[2]));
@@ -630,7 +623,7 @@
630623
631 mg::BufferProperties properties(buffer_size, mir_pixel_format_argb_8888, mg::BufferUsage::software);624 mg::BufferProperties properties(buffer_size, mir_pixel_format_argb_8888, mg::BufferUsage::software);
632 625
633 EXPECT_CALL(factory, create_buffer_stream(_,_,properties)).Times(1)626 EXPECT_CALL(factory, create_buffer_stream(_,properties)).Times(1)
634 .WillOnce(Return(mt::fake_shared(stream)));627 .WillOnce(Return(mt::fake_shared(stream)));
635628
636 auto session = make_application_session_with_buffer_stream_factory(mt::fake_shared(factory));629 auto session = make_application_session_with_buffer_stream_factory(mt::fake_shared(factory));
@@ -658,7 +651,7 @@
658651
659 EXPECT_CALL(stream, allow_framedropping(true))652 EXPECT_CALL(stream, allow_framedropping(true))
660 .Times(0); 653 .Times(0);
661 EXPECT_CALL(factory, create_buffer_stream(_,_,properties)).Times(1)654 EXPECT_CALL(factory, create_buffer_stream(_,properties)).Times(1)
662 .WillOnce(Return(mt::fake_shared(stream)));655 .WillOnce(Return(mt::fake_shared(stream)));
663656
664 auto session = make_application_session_with_buffer_stream_factory(mt::fake_shared(factory));657 auto session = make_application_session_with_buffer_stream_factory(mt::fake_shared(factory));
665658
=== modified file 'tests/unit-tests/scene/test_surface_stack.cpp'
--- tests/unit-tests/scene/test_surface_stack.cpp 2017-05-08 03:04:26 +0000
+++ tests/unit-tests/scene/test_surface_stack.cpp 2017-07-18 03:23:56 +0000
@@ -289,17 +289,7 @@
289 ms::SurfaceStack stack{report};289 ms::SurfaceStack stack{report};
290 stack.register_compositor(this);290 stack.register_compositor(this);
291291
292 struct StubBuffers : mtd::StubClientBuffers292 auto stream = std::make_shared<mc::Stream>(geom::Size{ 1, 1 }, mir_pixel_format_abgr_8888);
293 {
294 std::shared_ptr<mg::Buffer> get(mg::BufferID) const override
295 {
296 return buffer;
297 }
298 std::shared_ptr<mg::Buffer> buffer {std::make_shared<mtd::StubBuffer>()};
299 };
300
301 auto buffers = std::make_shared<StubBuffers>();
302 auto stream = std::make_shared<mc::Stream>(buffers, geom::Size{ 1, 1 }, mir_pixel_format_abgr_8888);
303293
304 auto surface = std::make_shared<ms::BasicSurface>(294 auto surface = std::make_shared<ms::BasicSurface>(
305 std::string("stub"),295 std::string("stub"),

Subscribers

People subscribed via source and target branches