Mir

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

Proposed by Chris Halse Rogers on 2017-07-04
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 on 2017-07-12
Mir CI Bot continuous-integration Needs Fixing on 2017-07-12
Brandon Schaefer (community) 2017-07-04 Approve on 2017-07-11
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.
lp:~raof/mir/better-buffer-plumbing updated on 2017-07-04
4210. By Chris Halse Rogers on 2017-07-04

Remove copy of mutex.h that I didn't end up using

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)
lp:~raof/mir/better-buffer-plumbing updated on 2017-07-05
4211. By Chris Halse Rogers on 2017-07-05

Actually test whether or not buffer_released is *true*, rather than just a non-null shared_ptr.

Oops.

Thanks, Xenial, for failing to compile this! No love, more recent compilers.

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)
lp:~raof/mir/better-buffer-plumbing updated on 2017-07-05
4212. By Chris Halse Rogers on 2017-07-05

...and fix the test of which the previous problem was masking the failure.

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)
lp:~raof/mir/better-buffer-plumbing updated on 2017-07-06
4213. By Chris Halse Rogers on 2017-07-06

Test SubmitBuffer: A little threadsafety paranoia

4214. By Chris Halse Rogers on 2017-07-06

Fix race in SubmitBuffer.server_can_send_buffer.

We have to repeatedly check the buffers the server has allocated, as buffer allocation will
occur *after* mir_window_create_sync() (and hence mtf::make_any_surface()) has returned.

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)
Brandon Schaefer (brandontschaefer) wrote :

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

review: Approve
Alan Griffiths (alan-griffiths) wrote :

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

Alan Griffiths (alan-griffiths) wrote :

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

/sigh I guess that's pre-existing.

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.

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
Chris Halse Rogers (raof) wrote :

Interesting. I'll investigate!

lp:~raof/mir/better-buffer-plumbing updated on 2017-07-12
4215. By Chris Halse Rogers on 2017-07-12

client: Don't set an invalid BufferStreamID for native buffer allocations

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)
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
Chris Halse Rogers (raof) wrote :

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

Urgh. Let's try multistream!

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.

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.

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!

lp:~raof/mir/better-buffer-plumbing updated on 2017-07-19
4216. By Chris Halse Rogers on 2017-07-17

Merge don't-ack-release-buffers prerequisite

4217. By Chris Halse Rogers on 2017-07-17

Merge dont-ack-buffer-release harder

4218. By Chris Halse Rogers on 2017-07-18

Add lots of tests for buffer IPC to TestSessionMediator

4219. By Chris Halse Rogers on 2017-07-18

SessionMediator: std::logic_error is not derived from std::runtime_error.

So we need to catch std::exception in order to actually send error-buffers rather than crash
the server!

4220. By Chris Halse Rogers on 2017-07-18

SessionMediator: Better validation for buffer requests

4221. By Chris Halse Rogers on 2017-07-18

SessionMediator: Send a real buffer XOR an error buffer, never both

4222. By Chris Halse Rogers on 2017-07-19

Merge trunk, resolving trivial example/render_surfaces.cpp conflict

4223. By Chris Halse Rogers on 2017-07-19

Merge prereq

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'examples/render_surfaces.cpp'
2--- examples/render_surfaces.cpp 2017-05-08 03:04:26 +0000
3+++ examples/render_surfaces.cpp 2017-07-18 03:23:56 +0000
4@@ -34,7 +34,6 @@
5 #include "mir/scene/surface_factory.h"
6 #include "mir/shell/surface_stack.h"
7 #include "mir/frontend/buffer_sink.h"
8-#include "mir/frontend/client_buffers.h"
9 #include "mir/server.h"
10 #include "mir/report_exception.h"
11 #include "mir/renderer/gl/context.h"
12@@ -391,13 +390,11 @@
13 {
14 void send_buffer(mf::BufferStreamId, mg::Buffer&, mg::BufferIpcMsgType) override {}
15 void add_buffer(mg::Buffer&) override {}
16- void remove_buffer(mg::Buffer&) override {}
17 void update_buffer(mg::Buffer&) override {}
18 void error_buffer(geom::Size, MirPixelFormat, std::string const&) override {}
19 };
20
21- auto buffers = buffer_stream_factory->create_buffer_map(std::make_shared<NullBufferSink>());
22- auto const stream = buffer_stream_factory->create_buffer_stream({}, buffers, properties);
23+ auto const stream = buffer_stream_factory->create_buffer_stream({}, properties);
24 auto const surface = surface_factory->create_surface(
25 {ms::StreamInfo{stream, {}, {}}}, params);
26 surface_stack->add_surface(surface, params.input_mode);
27
28=== modified file 'examples/server_example_canonical_window_manager.cpp'
29--- examples/server_example_canonical_window_manager.cpp 2017-05-25 04:33:43 +0000
30+++ examples/server_example_canonical_window_manager.cpp 2017-07-18 03:23:56 +0000
31@@ -54,9 +54,11 @@
32
33 me::CanonicalWindowManagerPolicyCopy::CanonicalWindowManagerPolicyCopy(
34 WindowManagerTools* const tools,
35- std::shared_ptr<shell::DisplayLayout> const& display_layout) :
36+ std::shared_ptr<shell::DisplayLayout> const& display_layout,
37+ std::shared_ptr<graphics::GraphicBufferAllocator> const& allocator) :
38 tools{tools},
39- display_layout{display_layout}
40+ display_layout{display_layout},
41+ allocator{allocator}
42 {
43 }
44
45@@ -276,7 +278,7 @@
46 surface_map.emplace(titlebar, SurfaceInfo{session, titlebar, {}}).first->second;
47 titlebar_info.is_titlebar = true;
48 titlebar_info.parent = surface;
49- titlebar_info.init_titlebar(session, titlebar);
50+ titlebar_info.init_titlebar(*allocator, titlebar);
51 }
52
53 void me::CanonicalWindowManagerPolicyCopy::handle_new_surface(std::shared_ptr<ms::Session> const& session, std::shared_ptr<ms::Surface> const& surface)
54
55=== modified file 'examples/server_example_canonical_window_manager.h'
56--- examples/server_example_canonical_window_manager.h 2017-05-08 03:04:26 +0000
57+++ examples/server_example_canonical_window_manager.h 2017-07-18 03:23:56 +0000
58@@ -32,6 +32,10 @@
59 namespace mir
60 {
61 namespace shell { class DisplayLayout; }
62+namespace graphics
63+{
64+class GraphicBufferAllocator;
65+}
66 namespace examples
67 {
68 // standard window management algorithm:
69@@ -48,7 +52,8 @@
70
71 explicit CanonicalWindowManagerPolicyCopy(
72 WindowManagerTools* const tools,
73- std::shared_ptr<shell::DisplayLayout> const& display_layout);
74+ std::shared_ptr<shell::DisplayLayout> const& display_layout,
75+ std::shared_ptr<graphics::GraphicBufferAllocator> const& allocator);
76
77 void click(geometry::Point cursor);
78
79@@ -118,6 +123,7 @@
80
81 WindowManagerTools* const tools;
82 std::shared_ptr<shell::DisplayLayout> const display_layout;
83+ std::shared_ptr<graphics::GraphicBufferAllocator> const allocator;
84
85 geometry::Rectangle display_area;
86 geometry::Point old_cursor{};
87
88=== modified file 'examples/server_example_window_management.cpp'
89--- examples/server_example_window_management.cpp 2017-05-08 03:04:26 +0000
90+++ examples/server_example_window_management.cpp 2017-07-18 03:23:56 +0000
91@@ -28,6 +28,8 @@
92 #include "mir/scene/surface_creation_parameters.h"
93 #include "mir/shell/display_layout.h"
94 #include "mir/shell/system_compositor_window_manager.h"
95+#include "mir/graphics/platform.h"
96+#include "mir/graphics/graphic_buffer_allocator.h"
97
98 namespace me = mir::examples;
99 namespace mf = mir::frontend;
100@@ -134,7 +136,10 @@
101 }
102 else if (selection == wm_canonical)
103 {
104- return std::make_shared<CanonicalWindowManager>(focus_controller, server.the_shell_display_layout());
105+ return std::make_shared<CanonicalWindowManager>(
106+ focus_controller,
107+ server.the_shell_display_layout(),
108+ server.the_graphics_platform()->create_buffer_allocator());
109 }
110 else if (selection == wm_system_compositor)
111 {
112
113=== modified file 'include/server/mir/frontend/buffer_sink.h'
114--- include/server/mir/frontend/buffer_sink.h 2017-05-08 03:04:26 +0000
115+++ include/server/mir/frontend/buffer_sink.h 2017-07-18 03:23:56 +0000
116@@ -37,7 +37,6 @@
117 virtual void send_buffer(frontend::BufferStreamId id, graphics::Buffer& buffer, graphics::BufferIpcMsgType) = 0;
118 virtual void add_buffer(graphics::Buffer&) = 0;
119 virtual void error_buffer(geometry::Size req_size, MirPixelFormat req_format, std::string const& error_msg) = 0;
120- virtual void remove_buffer(graphics::Buffer&) = 0;
121 virtual void update_buffer(graphics::Buffer&) = 0;
122
123 protected:
124
125=== removed file 'include/server/mir/frontend/client_buffers.h'
126--- include/server/mir/frontend/client_buffers.h 2017-05-08 03:04:26 +0000
127+++ include/server/mir/frontend/client_buffers.h 1970-01-01 00:00:00 +0000
128@@ -1,46 +0,0 @@
129-/*
130- * Copyright © 2015 Canonical Ltd.
131- *
132- * This program is free software: you can redistribute it and/or modify
133- * it under the terms of the GNU General Public License version 3 as
134- * published by the Free Software Foundation.
135- *
136- * This program is distributed in the hope that it will be useful,
137- * but WITHOUT ANY WARRANTY; without even the implied warranty of
138- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
139- * GNU General Public License for more details.
140- *
141- * You should have received a copy of the GNU General Public License
142- * along with this program. If not, see <http://www.gnu.org/licenses/>.
143- *
144- * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
145- */
146-
147-#ifndef MIR_FRONTEND_CLIENT_BUFFERS_H_
148-#define MIR_FRONTEND_CLIENT_BUFFERS_H_
149-
150-#include "mir/graphics/buffer_id.h"
151-#include <memory>
152-
153-namespace mir
154-{
155-namespace graphics { class Buffer; }
156-namespace frontend
157-{
158-class ClientBuffers
159-{
160-public:
161- virtual graphics::BufferID add_buffer(std::shared_ptr<graphics::Buffer> const& properties) = 0;
162- virtual void remove_buffer(graphics::BufferID id) = 0;
163- virtual std::shared_ptr<graphics::Buffer> get(graphics::BufferID) const = 0;
164- virtual void send_buffer(graphics::BufferID id) = 0;
165- virtual void receive_buffer(graphics::BufferID id) = 0;
166-
167- ClientBuffers(ClientBuffers const&) = delete;
168- ClientBuffers& operator=(ClientBuffers const&) = delete;
169- virtual ~ClientBuffers() = default;
170- ClientBuffers() = default;
171-};
172-}
173-}
174-#endif /* MIR_FRONTEND_CLIENT_BUFFERS_H_ */
175
176=== modified file 'include/server/mir/frontend/session.h'
177--- include/server/mir/frontend/session.h 2017-05-08 03:04:26 +0000
178+++ include/server/mir/frontend/session.h 2017-07-18 03:23:56 +0000
179@@ -57,12 +57,6 @@
180 virtual BufferStreamId create_buffer_stream(graphics::BufferProperties const& props) = 0;
181 virtual void destroy_buffer_stream(BufferStreamId stream) = 0;
182
183- virtual graphics::BufferID create_buffer(graphics::BufferProperties const& properties) = 0;
184- virtual graphics::BufferID create_buffer(geometry::Size, MirPixelFormat) = 0;
185- virtual graphics::BufferID create_buffer(geometry::Size, uint32_t native_format, uint32_t native_flags) = 0;
186- virtual void destroy_buffer(graphics::BufferID) = 0;
187- virtual std::shared_ptr<graphics::Buffer> get_buffer(graphics::BufferID) = 0;
188-
189 virtual std::string name() const = 0;
190
191 virtual void send_display_config(graphics::DisplayConfiguration const&) = 0;
192
193=== modified file 'include/server/mir/scene/buffer_stream_factory.h'
194--- include/server/mir/scene/buffer_stream_factory.h 2017-05-08 03:04:26 +0000
195+++ include/server/mir/scene/buffer_stream_factory.h 2017-07-18 03:23:56 +0000
196@@ -28,7 +28,6 @@
197 {
198 namespace compositor { class BufferStream; }
199 namespace graphics { struct BufferProperties; }
200-namespace frontend { class ClientBuffers; class BufferSink; }
201 namespace scene
202 {
203 class BufferStreamFactory
204@@ -37,13 +36,12 @@
205 virtual ~BufferStreamFactory() = default;
206
207 virtual std::shared_ptr<compositor::BufferStream> create_buffer_stream(
208- frontend::BufferStreamId, std::shared_ptr<frontend::ClientBuffers> const& sink,
209- int nbuffers, graphics::BufferProperties const& buffer_properties) = 0;
210+ frontend::BufferStreamId,
211+ int nbuffers,
212+ graphics::BufferProperties const& buffer_properties) = 0;
213 virtual std::shared_ptr<compositor::BufferStream> create_buffer_stream(
214- frontend::BufferStreamId, std::shared_ptr<frontend::ClientBuffers> const& sink,
215+ frontend::BufferStreamId,
216 graphics::BufferProperties const& buffer_properties) = 0;
217- virtual std::shared_ptr<frontend::ClientBuffers> create_buffer_map(
218- std::shared_ptr<frontend::BufferSink> const& sink) = 0;
219
220 protected:
221 BufferStreamFactory() = default;
222
223=== modified file 'include/server/mir/scene/session.h'
224--- include/server/mir/scene/session.h 2017-05-08 03:04:26 +0000
225+++ include/server/mir/scene/session.h 2017-07-18 03:23:56 +0000
226@@ -65,12 +65,6 @@
227 virtual void destroy_buffer_stream(frontend::BufferStreamId stream) = 0;
228 virtual void configure_streams(Surface& surface, std::vector<shell::StreamSpecification> const& config) = 0;
229 virtual void destroy_surface(std::weak_ptr<Surface> const& surface) = 0;
230-
231- virtual graphics::BufferID create_buffer(graphics::BufferProperties const& properties) = 0;
232- virtual graphics::BufferID create_buffer(geometry::Size, MirPixelFormat) = 0;
233- virtual graphics::BufferID create_buffer(geometry::Size, uint32_t native_format, uint32_t native_flags) = 0;
234- virtual void destroy_buffer(graphics::BufferID) = 0;
235- virtual std::shared_ptr<graphics::Buffer> get_buffer(graphics::BufferID) = 0;
236 };
237 }
238 }
239
240=== modified file 'include/server/mir/shell/window_management_info.h'
241--- include/server/mir/shell/window_management_info.h 2017-05-08 03:04:26 +0000
242+++ include/server/mir/shell/window_management_info.h 2017-07-18 03:23:56 +0000
243@@ -28,6 +28,10 @@
244 namespace mir
245 {
246 namespace scene { class Session; class Surface; struct SurfaceCreationParameters; }
247+namespace graphics
248+{
249+class GraphicBufferAllocator;
250+}
251 namespace shell
252 {
253 struct SurfaceInfo
254@@ -78,7 +82,7 @@
255 mir::optional_value<graphics::DisplayConfigurationOutputId> output_id;
256 mir::optional_value<MirPointerConfinementState> confine_pointer;
257
258- void init_titlebar(std::shared_ptr<scene::Session> const& session, std::shared_ptr<scene::Surface> const& surface);
259+ void init_titlebar(graphics::GraphicBufferAllocator& allocator, std::shared_ptr<scene::Surface> const& surface);
260 void paint_titlebar(int intensity);
261
262 private:
263
264=== modified file 'include/test/mir/test/doubles/stub_session.h'
265--- include/test/mir/test/doubles/stub_session.h 2017-05-08 03:04:26 +0000
266+++ include/test/mir/test/doubles/stub_session.h 2017-07-18 03:23:56 +0000
267@@ -89,12 +89,6 @@
268
269 void send_input_config(MirInputConfig const& config) override;
270
271- graphics::BufferID create_buffer(graphics::BufferProperties const& properties) override;
272- graphics::BufferID create_buffer(geometry::Size, MirPixelFormat) override;
273- graphics::BufferID create_buffer(geometry::Size, uint32_t native_format, uint32_t native_flags) override;
274- void destroy_buffer(graphics::BufferID) override;
275- std::shared_ptr<graphics::Buffer> get_buffer(graphics::BufferID) override;
276-
277 pid_t pid;
278 };
279 }
280
281=== modified file 'src/client/buffer_vault.cpp'
282--- src/client/buffer_vault.cpp 2017-05-17 04:48:46 +0000
283+++ src/client/buffer_vault.cpp 2017-07-18 03:23:56 +0000
284@@ -86,11 +86,15 @@
285 {
286 if (auto map = surface_map.lock())
287 {
288- auto buffer = map->buffer(it.first);
289- buffer->set_callback(ignore_buffer, nullptr);
290+ if (auto buffer = map->buffer(it.first))
291+ {
292+ buffer->set_callback(ignore_buffer, nullptr);
293+ }
294 }
295 if (!disconnected_)
296+ {
297 free_buffer(it.first);
298+ }
299 }
300 catch (...)
301 {
302@@ -110,6 +114,10 @@
303 void mcl::BufferVault::free_buffer(int free_id)
304 {
305 server_requests->free_buffer(free_id);
306+ if (auto map = surface_map.lock())
307+ {
308+ map->erase(free_id);
309+ }
310 }
311
312 void mcl::BufferVault::realloc_buffer(int free_id, geom::Size size, MirPixelFormat format, int usage)
313
314=== modified file 'src/client/connection_surface_map.cpp'
315--- src/client/connection_surface_map.cpp 2017-05-08 03:04:26 +0000
316+++ src/client/connection_surface_map.cpp 2017-07-18 03:23:56 +0000
317@@ -107,7 +107,7 @@
318 if (it != buffers.end())
319 return it->second;
320 else
321- BOOST_THROW_EXCEPTION(std::runtime_error("could not find buffer"));
322+ return nullptr;
323 }
324
325 void mcl::ConnectionSurfaceMap::erase(void* render_surface_key)
326
327=== modified file 'src/client/mir_connection.cpp'
328--- src/client/mir_connection.cpp 2017-06-30 11:32:37 +0000
329+++ src/client/mir_connection.cpp 2017-07-18 03:23:56 +0000
330@@ -1305,7 +1305,6 @@
331 MirBufferCallback callback, void* context)
332 {
333 mp::BufferAllocation request;
334- request.mutable_id()->set_value(-1);
335 auto buffer_request = request.add_buffer_requests();
336 buffer_request->set_width(size.width.as_int());
337 buffer_request->set_height(size.height.as_int());
338@@ -1323,16 +1322,15 @@
339
340 void MirConnection::release_buffer(mcl::MirBuffer* buffer)
341 {
342- if (!buffer->valid())
343+ if (buffer->valid())
344 {
345- surface_map->erase(buffer->rpc_id());
346- return;
347+ mp::BufferRelease request;
348+ auto released_buffer = request.add_buffers();
349+ released_buffer->set_buffer_id(buffer->rpc_id());
350+ server.release_buffers(&request, ignored.get(), gp::NewCallback(ignore));
351 }
352
353- mp::BufferRelease request;
354- auto released_buffer = request.add_buffers();
355- released_buffer->set_buffer_id(buffer->rpc_id());
356- server.release_buffers(&request, ignored.get(), gp::NewCallback(ignore));
357+ surface_map->erase(buffer->rpc_id());
358 }
359
360 void MirConnection::release_render_surface_with_content(
361
362=== modified file 'src/client/rpc/mir_protobuf_rpc_channel.cpp'
363--- src/client/rpc/mir_protobuf_rpc_channel.cpp 2017-05-08 03:04:26 +0000
364+++ src/client/rpc/mir_protobuf_rpc_channel.cpp 2017-07-18 03:23:56 +0000
365@@ -359,11 +359,19 @@
366 buffer->received();
367 break;
368 case mp::BufferOperation::update:
369- map->buffer(buffer_id)->received(
370- *mcl::protobuf_to_native_buffer(seq.buffer_request().buffer()));
371+ buffer = map->buffer(buffer_id);
372+ if (buffer)
373+ {
374+ buffer->received(
375+ *mcl::protobuf_to_native_buffer(seq.buffer_request().buffer()));
376+ }
377 break;
378 case mp::BufferOperation::remove:
379- map->erase(buffer_id);
380+ /* The server never sends us an unsolicited ::remove request
381+ * (and clients have no way of dealing with one)
382+ *
383+ * Just ignore it, because we've already deleted our buffer.
384+ */
385 break;
386 default:
387 BOOST_THROW_EXCEPTION(std::runtime_error("unknown buffer operation"));
388
389=== modified file 'src/server/compositor/CMakeLists.txt'
390--- src/server/compositor/CMakeLists.txt 2017-05-08 03:04:26 +0000
391+++ src/server/compositor/CMakeLists.txt 2017-07-18 03:23:56 +0000
392@@ -18,7 +18,6 @@
393 compositing_screencast.cpp
394 stream.cpp
395 multi_monitor_arbiter.cpp
396- buffer_map.cpp
397 dropping_schedule.cpp
398 queueing_schedule.cpp
399 )
400
401=== removed file 'src/server/compositor/buffer_map.cpp'
402--- src/server/compositor/buffer_map.cpp 2017-05-08 03:04:26 +0000
403+++ src/server/compositor/buffer_map.cpp 1970-01-01 00:00:00 +0000
404@@ -1,116 +0,0 @@
405-/*
406- * Copyright © 2015 Canonical Ltd.
407- *
408- * This program is free software: you can redistribute it and/or modify
409- * it under the terms of the GNU General Public License version 3 as
410- * published by the Free Software Foundation.
411- *
412- * This program is distributed in the hope that it will be useful,
413- * but WITHOUT ANY WARRANTY; without even the implied warranty of
414- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
415- * GNU General Public License for more details.
416- *
417- * You should have received a copy of the GNU General Public License
418- * along with this program. If not, see <http://www.gnu.org/licenses/>.
419- *
420- * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
421- */
422-
423-#include "mir/graphics/buffer.h"
424-#include "mir/frontend/buffer_sink.h"
425-#include "buffer_map.h"
426-#include <boost/throw_exception.hpp>
427-#include <algorithm>
428-
429-namespace mc = mir::compositor;
430-namespace mf = mir::frontend;
431-namespace mg = mir::graphics;
432-
433-namespace mir
434-{
435-namespace compositor
436-{
437-enum class BufferMap::Owner
438-{
439- server,
440- client
441-};
442-}
443-}
444-
445-mc::BufferMap::BufferMap(std::shared_ptr<mf::BufferSink> const& sink) :
446- sink(sink)
447-{
448-}
449-
450-mg::BufferID mc::BufferMap::add_buffer(std::shared_ptr<mg::Buffer> const& buffer)
451-{
452- try
453- {
454- std::unique_lock<decltype(mutex)> lk(mutex);
455- buffers[buffer->id()] = {buffer, Owner::client};
456- if (auto s = sink.lock())
457- s->add_buffer(*buffer);
458- return buffer->id();
459- } catch (std::exception& e)
460- {
461- if (auto s = sink.lock())
462- s->error_buffer(buffer->size(), buffer->pixel_format(), e.what());
463- throw;
464- }
465-}
466-
467-void mc::BufferMap::remove_buffer(mg::BufferID id)
468-{
469- std::unique_lock<decltype(mutex)> lk(mutex);
470- auto it = checked_buffers_find(id, lk);
471- if (auto s = sink.lock())
472- s->remove_buffer(*it->second.buffer);
473- buffers.erase(it);
474-}
475-
476-void mc::BufferMap::send_buffer(mg::BufferID id)
477-{
478- std::unique_lock<decltype(mutex)> lk(mutex);
479- auto it = buffers.find(id);
480- if (it != buffers.end())
481- {
482- auto buffer = it->second.buffer;
483- it->second.owner = Owner::client;
484- lk.unlock();
485- if (auto s = sink.lock())
486- s->update_buffer(*buffer);
487- }
488-}
489-
490-void mc::BufferMap::receive_buffer(graphics::BufferID id)
491-{
492- std::unique_lock<decltype(mutex)> lk(mutex);
493- auto it = buffers.find(id);
494- if (it != buffers.end())
495- it->second.owner = Owner::server;
496-}
497-
498-std::shared_ptr<mg::Buffer> mc::BufferMap::get(mg::BufferID id) const
499-{
500- std::unique_lock<decltype(mutex)> lk(mutex);
501- return checked_buffers_find(id, lk)->second.buffer;
502-}
503-
504-mc::BufferMap::Map::iterator mc::BufferMap::checked_buffers_find(
505- mg::BufferID id, std::unique_lock<std::mutex> const&)
506-{
507- auto it = buffers.find(id);
508- if (it == buffers.end())
509- BOOST_THROW_EXCEPTION(std::logic_error("cannot find buffer by id"));
510- return it;
511-}
512-
513-mc::BufferMap::Map::const_iterator mc::BufferMap::checked_buffers_find(
514- mg::BufferID id, std::unique_lock<std::mutex> const&) const
515-{
516- auto it = buffers.find(id);
517- if (it == buffers.end())
518- BOOST_THROW_EXCEPTION(std::logic_error("cannot find buffer by id"));
519- return it;
520-}
521
522=== removed file 'src/server/compositor/buffer_map.h'
523--- src/server/compositor/buffer_map.h 2017-05-08 03:04:26 +0000
524+++ src/server/compositor/buffer_map.h 1970-01-01 00:00:00 +0000
525@@ -1,65 +0,0 @@
526-/*
527- * Copyright © 2015 Canonical Ltd.
528- *
529- * This program is free software: you can redistribute it and/or modify
530- * it under the terms of the GNU General Public License version 3 as
531- * published by the Free Software Foundation.
532- *
533- * This program is distributed in the hope that it will be useful,
534- * but WITHOUT ANY WARRANTY; without even the implied warranty of
535- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
536- * GNU General Public License for more details.
537- *
538- * You should have received a copy of the GNU General Public License
539- * along with this program. If not, see <http://www.gnu.org/licenses/>.
540- *
541- * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
542- */
543-
544-#ifndef MIR_COMPOSITOR_BUFFER_MAP_H_
545-#define MIR_COMPOSITOR_BUFFER_MAP_H_
546-
547-#include "mir/frontend/client_buffers.h"
548-#include <mutex>
549-#include <map>
550-
551-namespace mir
552-{
553-namespace frontend { class BufferSink; }
554-namespace compositor
555-{
556-class BufferMap : public frontend::ClientBuffers
557-{
558-public:
559- BufferMap(std::shared_ptr<frontend::BufferSink> const& sink);
560-
561- graphics::BufferID add_buffer(std::shared_ptr<graphics::Buffer> const& buffer) override;
562- void remove_buffer(graphics::BufferID id) override;
563-
564- void receive_buffer(graphics::BufferID id) override;
565- void send_buffer(graphics::BufferID id) override;
566-
567- std::shared_ptr<graphics::Buffer> get(graphics::BufferID) const override;
568-
569-private:
570- std::mutex mutable mutex;
571-
572- enum class Owner;
573- struct MapEntry
574- {
575- std::shared_ptr<graphics::Buffer> buffer;
576- Owner owner;
577- };
578- typedef std::map<graphics::BufferID, MapEntry> Map;
579- //used to keep strong reference
580- Map buffers;
581- Map::iterator checked_buffers_find(graphics::BufferID, std::unique_lock<std::mutex> const&);
582- Map::const_iterator checked_buffers_find(graphics::BufferID, std::unique_lock<std::mutex> const&) const;
583-
584- //would be better to schedule the async buffer callbacks in the ipc subsystem,
585- //instead of driving from within the compositor threads (LP: #1395421)
586- std::weak_ptr<frontend::BufferSink> const sink;
587-};
588-}
589-}
590-#endif /* MIR_COMPOSITOR_BUFFER_MAP_H_ */
591
592=== modified file 'src/server/compositor/buffer_stream_factory.cpp'
593--- src/server/compositor/buffer_stream_factory.cpp 2017-05-08 03:04:26 +0000
594+++ src/server/compositor/buffer_stream_factory.cpp 2017-07-18 03:23:56 +0000
595@@ -21,7 +21,6 @@
596 #include "buffer_stream_factory.h"
597 #include "mir/graphics/buffer_properties.h"
598 #include "stream.h"
599-#include "buffer_map.h"
600 #include "mir/graphics/buffer.h"
601 #include "mir/graphics/buffer_id.h"
602 #include "mir/graphics/graphic_buffer_allocator.h"
603@@ -40,23 +39,17 @@
604 }
605
606 std::shared_ptr<mc::BufferStream> mc::BufferStreamFactory::create_buffer_stream(
607- mf::BufferStreamId id, std::shared_ptr<mf::ClientBuffers> const& buffers,
608+ mf::BufferStreamId id,
609 mg::BufferProperties const& buffer_properties)
610 {
611- return create_buffer_stream(id, buffers, 0, buffer_properties);
612+ return create_buffer_stream(id, 0, buffer_properties);
613 }
614
615 std::shared_ptr<mc::BufferStream> mc::BufferStreamFactory::create_buffer_stream(
616- mf::BufferStreamId, std::shared_ptr<mf::ClientBuffers> const& buffers,
617- int, mg::BufferProperties const& buffer_properties)
618+ mf::BufferStreamId,
619+ int,
620+ mg::BufferProperties const& buffer_properties)
621 {
622 return std::make_shared<mc::Stream>(
623- buffers,
624 buffer_properties.size, buffer_properties.format);
625 }
626-
627-std::shared_ptr<mf::ClientBuffers> mc::BufferStreamFactory::create_buffer_map(
628- std::shared_ptr<mf::BufferSink> const& sink)
629-{
630- return std::make_shared<mc::BufferMap>(sink);
631-}
632
633=== modified file 'src/server/compositor/buffer_stream_factory.h'
634--- src/server/compositor/buffer_stream_factory.h 2017-05-08 03:04:26 +0000
635+++ src/server/compositor/buffer_stream_factory.h 2017-07-18 03:23:56 +0000
636@@ -42,13 +42,12 @@
637 virtual ~BufferStreamFactory() {}
638
639 virtual std::shared_ptr<compositor::BufferStream> create_buffer_stream(
640- frontend::BufferStreamId, std::shared_ptr<frontend::ClientBuffers> const& sink,
641- int nbuffers, graphics::BufferProperties const& buffer_properties) override;
642+ frontend::BufferStreamId,
643+ int nbuffers,
644+ graphics::BufferProperties const& buffer_properties) override;
645 virtual std::shared_ptr<BufferStream> create_buffer_stream(
646- frontend::BufferStreamId, std::shared_ptr<frontend::ClientBuffers> const& sink,
647+ frontend::BufferStreamId,
648 graphics::BufferProperties const&) override;
649- virtual std::shared_ptr<frontend::ClientBuffers> create_buffer_map(
650- std::shared_ptr<frontend::BufferSink> const& sink) override;
651 };
652
653 }
654
655=== modified file 'src/server/compositor/dropping_schedule.cpp'
656--- src/server/compositor/dropping_schedule.cpp 2017-05-08 03:04:26 +0000
657+++ src/server/compositor/dropping_schedule.cpp 2017-07-18 03:23:56 +0000
658@@ -17,16 +17,13 @@
659 */
660
661 #include "dropping_schedule.h"
662-#include "mir/frontend/client_buffers.h"
663 #include "mir/graphics/buffer.h"
664
665 #include <boost/throw_exception.hpp>
666-namespace mf = mir::frontend;
667 namespace mg = mir::graphics;
668 namespace mc = mir::compositor;
669
670-mc::DroppingSchedule::DroppingSchedule(std::shared_ptr<mf::ClientBuffers> const& client_buffers) :
671- sender(client_buffers)
672+mc::DroppingSchedule::DroppingSchedule()
673 {
674 }
675
676@@ -42,14 +39,6 @@
677 {
678 std::future<void> drop;
679 std::lock_guard<decltype(mutex)> lk(mutex);
680- if ((the_only_buffer != buffer) && the_only_buffer)
681- {
682- drop = std::async(std::launch::deferred,
683- [sender=sender, dropped=the_only_buffer]()
684- {
685- sender->send_buffer(dropped->id());
686- });
687- }
688 the_only_buffer = buffer;
689 return drop;
690 }
691
692=== modified file 'src/server/compositor/dropping_schedule.h'
693--- src/server/compositor/dropping_schedule.h 2017-05-08 03:04:26 +0000
694+++ src/server/compositor/dropping_schedule.h 2017-07-18 03:23:56 +0000
695@@ -25,13 +25,12 @@
696 namespace mir
697 {
698 namespace graphics { class Buffer; }
699-namespace frontend { class ClientBuffers; }
700 namespace compositor
701 {
702 class DroppingSchedule : public Schedule
703 {
704 public:
705- DroppingSchedule(std::shared_ptr<frontend::ClientBuffers> const&);
706+ DroppingSchedule();
707 void schedule(std::shared_ptr<graphics::Buffer> const& buffer) override;
708 std::future<void> schedule_nonblocking(
709 std::shared_ptr<graphics::Buffer> const& buffer) override;
710@@ -40,7 +39,6 @@
711
712 private:
713 std::mutex mutable mutex;
714- std::shared_ptr<frontend::ClientBuffers> const sender;
715 std::shared_ptr<graphics::Buffer> the_only_buffer;
716 };
717 }
718
719=== modified file 'src/server/compositor/multi_monitor_arbiter.cpp'
720--- src/server/compositor/multi_monitor_arbiter.cpp 2017-05-26 12:45:45 +0000
721+++ src/server/compositor/multi_monitor_arbiter.cpp 2017-07-18 03:23:56 +0000
722@@ -20,7 +20,6 @@
723 #include "mir/graphics/buffer.h"
724 #include "mir/graphics/graphic_buffer_allocator.h"
725 #include "mir/frontend/event_sink.h"
726-#include "mir/frontend/client_buffers.h"
727 #include "schedule.h"
728 #include <boost/throw_exception.hpp>
729 #include <algorithm>
730@@ -30,9 +29,7 @@
731 namespace mf = mir::frontend;
732
733 mc::MultiMonitorArbiter::MultiMonitorArbiter(
734- std::shared_ptr<frontend::ClientBuffers> const& map,
735 std::shared_ptr<Schedule> const& schedule) :
736- map(map),
737 schedule(schedule)
738 {
739 }
740@@ -43,7 +40,7 @@
741 for(auto it = onscreen_buffers.begin(); it != onscreen_buffers.end(); it++)
742 {
743 if (it->use_count == 0)
744- map->send_buffer(it->buffer->id());
745+ it->buffer.reset();
746 }
747
748 }
749@@ -96,7 +93,6 @@
750 if ((it->use_count == 0) &&
751 (it != onscreen_buffers.begin() || schedule->num_scheduled())) //ensure monitors always have a buffer
752 {
753- map->send_buffer(it->buffer->id());
754 it = onscreen_buffers.erase(it);
755 }
756 else
757
758=== modified file 'src/server/compositor/multi_monitor_arbiter.h'
759--- src/server/compositor/multi_monitor_arbiter.h 2017-05-25 05:49:36 +0000
760+++ src/server/compositor/multi_monitor_arbiter.h 2017-07-18 03:23:56 +0000
761@@ -38,7 +38,6 @@
762 {
763 public:
764 MultiMonitorArbiter(
765- std::shared_ptr<frontend::ClientBuffers> const& map,
766 std::shared_ptr<Schedule> const& schedule);
767 ~MultiMonitorArbiter();
768
769@@ -56,7 +55,6 @@
770 void clean_onscreen_buffers(std::lock_guard<std::mutex> const&);
771
772 std::mutex mutable mutex;
773- std::shared_ptr<frontend::ClientBuffers> const map;
774 struct ScheduleEntry
775 {
776 ScheduleEntry(std::shared_ptr<graphics::Buffer> const& buffer, unsigned int use_count) :
777
778=== modified file 'src/server/compositor/stream.cpp'
779--- src/server/compositor/stream.cpp 2017-05-25 05:49:36 +0000
780+++ src/server/compositor/stream.cpp 2017-07-18 03:23:56 +0000
781@@ -21,7 +21,6 @@
782 #include "queueing_schedule.h"
783 #include "dropping_schedule.h"
784 #include "temporary_buffers.h"
785-#include "mir/frontend/client_buffers.h"
786 #include "mir/graphics/buffer.h"
787 #include <boost/throw_exception.hpp>
788
789@@ -37,22 +36,17 @@
790 };
791
792 mc::Stream::Stream(
793- std::shared_ptr<frontend::ClientBuffers> map, geom::Size size, MirPixelFormat pf) :
794+ geom::Size size, MirPixelFormat pf) :
795 schedule_mode(ScheduleMode::Queueing),
796 schedule(std::make_shared<mc::QueueingSchedule>()),
797- buffers(map),
798- arbiter(std::make_shared<mc::MultiMonitorArbiter>(buffers, schedule)),
799+ arbiter(std::make_shared<mc::MultiMonitorArbiter>(schedule)),
800 size(size),
801 pf(pf),
802 first_frame_posted(false)
803 {
804 }
805
806-mc::Stream::~Stream()
807-{
808- while(schedule->num_scheduled())
809- buffers->send_buffer(schedule->next_buffer()->id());
810-}
811+mc::Stream::~Stream() = default;
812
813 unsigned int mc::Stream::client_owned_buffer_count(std::lock_guard<decltype(mutex)> const&) const
814 {
815@@ -72,9 +66,8 @@
816 {
817 std::lock_guard<decltype(mutex)> lk(mutex);
818 first_frame_posted = true;
819- buffers->receive_buffer(buffer->id());
820- deferred_io = schedule->schedule_nonblocking(buffers->get(buffer->id()));
821 pf = buffer->pixel_format();
822+ deferred_io = schedule->schedule_nonblocking(buffer);
823 }
824 observers.frame_posted(1, buffer->size());
825
826@@ -134,7 +127,7 @@
827 std::lock_guard<decltype(mutex)> lk(mutex);
828 if (dropping && schedule_mode == ScheduleMode::Queueing)
829 {
830- transition_schedule(std::make_shared<mc::DroppingSchedule>(buffers), lk);
831+ transition_schedule(std::make_shared<mc::DroppingSchedule>(), lk);
832 schedule_mode = ScheduleMode::Dropping;
833 }
834 else if (!dropping && schedule_mode == ScheduleMode::Dropping)
835@@ -182,9 +175,6 @@
836 transferred_buffers.pop_back();
837 }
838
839- for (auto &buffer : transferred_buffers)
840- buffers->send_buffer(buffer->id());
841-
842 arbiter->advance_schedule();
843 }
844
845@@ -214,15 +204,7 @@
846
847 bool mc::Stream::suitable_for_cursor() const
848 {
849- if (associated_buffers.empty())
850- {
851- return true;
852- }
853- else
854- {
855- for (auto it : associated_buffers)
856- if (buffers->get(it)->pixel_format() != mir_pixel_format_argb_8888)
857- return false;
858- }
859+ // We can't reasonably answer this question -
860+ // Suitability for cursor use is a per-buffer property, not a per-stream property.
861 return true;
862 }
863
864=== modified file 'src/server/compositor/stream.h'
865--- src/server/compositor/stream.h 2017-05-22 11:53:51 +0000
866+++ src/server/compositor/stream.h 2017-07-18 03:23:56 +0000
867@@ -39,7 +39,7 @@
868 class Stream : public BufferStream
869 {
870 public:
871- Stream(std::shared_ptr<frontend::ClientBuffers>, geometry::Size sz, MirPixelFormat format);
872+ Stream(geometry::Size sz, MirPixelFormat format);
873 ~Stream();
874
875 void submit_buffer(std::shared_ptr<graphics::Buffer> const& buffer) override;
876@@ -68,7 +68,6 @@
877 std::mutex mutable mutex;
878 ScheduleMode schedule_mode;
879 std::shared_ptr<Schedule> schedule;
880- std::shared_ptr<frontend::ClientBuffers> const buffers;
881 std::shared_ptr<MultiMonitorArbiter> const arbiter;
882 geometry::Size size;
883 MirPixelFormat pf;
884
885=== modified file 'src/server/frontend/default_ipc_factory.cpp'
886--- src/server/frontend/default_ipc_factory.cpp 2017-05-08 03:04:26 +0000
887+++ src/server/frontend/default_ipc_factory.cpp 2017-07-18 03:23:56 +0000
888@@ -26,6 +26,7 @@
889 #include "resource_cache.h"
890 #include "mir/frontend/session_authorizer.h"
891 #include "mir/frontend/event_sink.h"
892+#include "event_sink_factory.h"
893 #include "mir/graphics/graphic_buffer_allocator.h"
894 #include "mir/cookie/authority.h"
895
896@@ -150,5 +151,6 @@
897 anr_detector,
898 cookie_authority,
899 input_changer,
900- extensions);
901+ extensions,
902+ buffer_allocator);
903 }
904
905=== modified file 'src/server/frontend/event_sender.cpp'
906--- src/server/frontend/event_sender.cpp 2017-05-08 03:04:26 +0000
907+++ src/server/frontend/event_sender.cpp 2017-07-18 03:23:56 +0000
908@@ -143,14 +143,6 @@
909 send_event_sequence(seq, {});
910 }
911
912-void mfd::EventSender::remove_buffer(graphics::Buffer& buffer)
913-{
914- mp::EventSequence seq;
915- auto request = seq.mutable_buffer_request();
916- request->set_operation(mir::protobuf::BufferOperation::remove);
917- send_buffer(seq, buffer, mg::BufferIpcMsgType::update_msg);
918-}
919-
920 void mfd::EventSender::update_buffer(graphics::Buffer& buffer)
921 {
922 mp::EventSequence seq;
923
924=== modified file 'src/server/frontend/event_sender.h'
925--- src/server/frontend/event_sender.h 2017-05-08 03:04:26 +0000
926+++ src/server/frontend/event_sender.h 2017-07-18 03:23:56 +0000
927@@ -52,7 +52,6 @@
928 void send_buffer(frontend::BufferStreamId id, graphics::Buffer& buffer, graphics::BufferIpcMsgType) override;
929 void add_buffer(graphics::Buffer&) override;
930 void error_buffer(geometry::Size, MirPixelFormat, std::string const&) override;
931- void remove_buffer(graphics::Buffer&) override;
932 void update_buffer(graphics::Buffer&) override;
933
934 private:
935
936=== modified file 'src/server/frontend/session_mediator.cpp'
937--- src/server/frontend/session_mediator.cpp 2017-06-01 13:04:37 +0000
938+++ src/server/frontend/session_mediator.cpp 2017-07-18 03:23:56 +0000
939@@ -59,6 +59,7 @@
940 #include "mir/fd.h"
941 #include "mir/cookie/authority.h"
942 #include "mir/module_properties.h"
943+#include "mir/graphics/graphic_buffer_allocator.h"
944
945 #include "mir/geometry/rectangles.h"
946 #include "protobuf_buffer_packer.h"
947@@ -110,7 +111,8 @@
948 std::shared_ptr<scene::ApplicationNotRespondingDetector> const& anr_detector,
949 std::shared_ptr<mir::cookie::Authority> const& cookie_authority,
950 std::shared_ptr<mf::InputConfigurationChanger> const& input_changer,
951- std::vector<mir::ExtensionDescription> const& extensions) :
952+ std::vector<mir::ExtensionDescription> const& extensions,
953+ std::shared_ptr<mg::GraphicBufferAllocator> const& allocator) :
954 client_pid_(0),
955 shell(shell),
956 ipc_operations(ipc_operations),
957@@ -128,7 +130,8 @@
958 anr_detector{anr_detector},
959 cookie_authority(cookie_authority),
960 input_changer(input_changer),
961- extensions(extensions)
962+ extensions(extensions),
963+ allocator{allocator}
964 {
965 }
966
967@@ -374,6 +377,58 @@
968 buffering_sender->uncork();
969 }
970
971+namespace
972+{
973+ class AutoSendBuffer : public mg::Buffer
974+ {
975+ public:
976+ AutoSendBuffer(
977+ std::shared_ptr<mg::Buffer> const& wrapped,
978+ std::weak_ptr<mf::BufferSink> const& sink)
979+ : buffer{wrapped},
980+ sink{sink}
981+ {
982+ }
983+ ~AutoSendBuffer()
984+ {
985+ if (auto live_sink = sink.lock())
986+ {
987+ live_sink->update_buffer(*buffer);
988+ }
989+ }
990+
991+ std::shared_ptr<mir::graphics::NativeBuffer> native_buffer_handle() const override
992+ {
993+ return buffer->native_buffer_handle();
994+ }
995+
996+ mir::graphics::BufferID id() const override
997+ {
998+ return buffer->id();
999+ }
1000+
1001+ mir::geometry::Size size() const override
1002+ {
1003+ return buffer->size();
1004+ }
1005+
1006+ MirPixelFormat pixel_format() const override
1007+ {
1008+ return buffer->pixel_format();
1009+ }
1010+
1011+ mir::graphics::NativeBufferBase *native_buffer_base() override
1012+ {
1013+ return buffer->native_buffer_base();
1014+ }
1015+
1016+ private:
1017+ std::shared_ptr<mg::Buffer> const buffer;
1018+ std::weak_ptr<mf::BufferSink> const sink;
1019+ };
1020+
1021+}
1022+
1023 void mf::SessionMediator::submit_buffer(
1024 mir::protobuf::BufferRequest const* request,
1025 mir::protobuf::Void*,
1026@@ -388,15 +443,37 @@
1027 auto stream = session->get_buffer_stream(stream_id);
1028
1029 mfd::ProtobufBufferPacker request_msg{const_cast<mir::protobuf::Buffer*>(&request->buffer())};
1030- auto b = session->get_buffer(buffer_id);
1031+ auto b = buffer_cache.at(buffer_id);
1032 ipc_operations->unpack_buffer(request_msg, *b);
1033
1034- stream->submit_buffer(b);
1035+ stream->submit_buffer(std::make_shared<AutoSendBuffer>(b, event_sink));
1036
1037 done->Run();
1038 }
1039
1040-void mf::SessionMediator::allocate_buffers(
1041+namespace
1042+{
1043+bool validate_buffer_request(mir::protobuf::BufferStreamParameters const& req)
1044+{
1045+ // A valid buffer request has either flags & native_format set
1046+ // or buffer_usage & pixel_format set, not both.
1047+ return
1048+ (
1049+ req.has_pixel_format() &&
1050+ req.has_buffer_usage() &&
1051+ !req.has_native_format() &&
1052+ !req.has_flags()
1053+ ) ||
1054+ (
1055+ !req.has_pixel_format() &&
1056+ !req.has_buffer_usage() &&
1057+ req.has_native_format() &&
1058+ req.has_flags()
1059+ );
1060+}
1061+}
1062+
1063+void mf::SessionMediator::allocate_buffers(
1064 mir::protobuf::BufferAllocation const* request,
1065 mir::protobuf::Void*,
1066 google::protobuf::Closure* done)
1067@@ -409,36 +486,54 @@
1068 for (auto i = 0; i < request->buffer_requests().size(); i++)
1069 {
1070 auto const& req = request->buffer_requests(i);
1071+ std::shared_ptr<mg::Buffer> buffer;
1072+ try
1073+ {
1074+ if (!validate_buffer_request(req))
1075+ {
1076+ BOOST_THROW_EXCEPTION(std::logic_error("Invalid buffer request"));
1077+ }
1078
1079- mg::BufferID id;
1080- if (req.has_flags() && req.has_native_format())
1081- {
1082- id = session->create_buffer({req.width(), req.height()}, req.native_format(), req.flags());
1083- }
1084- else if (req.has_buffer_usage() && req.has_pixel_format())
1085- {
1086- auto const usage = static_cast<mg::BufferUsage>(req.buffer_usage());
1087- geom::Size const size{req.width(), req.height()};
1088- auto const pf = static_cast<MirPixelFormat>(req.pixel_format());
1089- if (usage == mg::BufferUsage::software)
1090+ if (req.has_flags() && req.has_native_format())
1091 {
1092- id = session->create_buffer(size, pf);
1093+ buffer = allocator->alloc_buffer(
1094+ {req.width(), req.height()},
1095+ req.native_format(),
1096+ req.flags());
1097 }
1098 else
1099 {
1100- //legacy route, server-selected pf and usage
1101- id = session->create_buffer(mg::BufferProperties{size, pf, mg::BufferUsage::hardware});
1102- }
1103- }
1104- else
1105- {
1106- BOOST_THROW_EXCEPTION(std::logic_error("Invalid buffer request"));
1107- }
1108-
1109- if (request->has_id())
1110- {
1111- auto stream = session->get_buffer_stream(mf::BufferStreamId(request->id().value()));
1112- stream->associate_buffer(id);
1113+ auto const usage = static_cast<mg::BufferUsage>(req.buffer_usage());
1114+ geom::Size const size{req.width(), req.height()};
1115+ auto const pf = static_cast<MirPixelFormat>(req.pixel_format());
1116+ if (usage == mg::BufferUsage::software)
1117+ {
1118+ buffer = allocator->alloc_software_buffer(size, pf);
1119+ }
1120+ else
1121+ {
1122+ //legacy route, server-selected pf and usage
1123+ buffer =
1124+ allocator->alloc_buffer(mg::BufferProperties{size, pf, mg::BufferUsage::hardware});
1125+ }
1126+ }
1127+
1128+ if (request->has_id())
1129+ {
1130+ auto stream = session->get_buffer_stream(mf::BufferStreamId(request->id().value()));
1131+ stream->associate_buffer(buffer->id());
1132+ }
1133+
1134+ // TODO: Throw if insert fails (duplicate ID)?
1135+ buffer_cache.insert(std::make_pair(buffer->id(), buffer));
1136+ event_sink->add_buffer(*buffer);
1137+ }
1138+ catch (std::exception const& err)
1139+ {
1140+ event_sink->error_buffer(
1141+ geom::Size{req.width(), req.height()},
1142+ static_cast<MirPixelFormat>(req.pixel_format()),
1143+ err.what());
1144 }
1145 }
1146 done->Run();
1147@@ -473,7 +568,7 @@
1148 for (auto i = 0; i < request->buffers().size(); i++)
1149 {
1150 mg::BufferID buffer_id{static_cast<uint32_t>(request->buffers(i).buffer_id())};
1151- session->destroy_buffer(buffer_id);
1152+ buffer_cache.erase(buffer_id);
1153 }
1154 done->Run();
1155 }
1156@@ -869,7 +964,7 @@
1157 {
1158 auto session = weak_session.lock();
1159 ScreencastSessionId const screencast_session_id{request->id().value()};
1160- auto buffer = session->get_buffer(mg::BufferID{request->buffer_id()});
1161+ auto buffer = buffer_cache.at(mg::BufferID{request->buffer_id()});
1162 screencast->capture(screencast_session_id, buffer);
1163 done->Run();
1164 }
1165
1166=== modified file 'src/server/frontend/session_mediator.h'
1167--- src/server/frontend/session_mediator.h 2017-05-08 03:04:26 +0000
1168+++ src/server/frontend/session_mediator.h 2017-07-18 03:23:56 +0000
1169@@ -28,6 +28,7 @@
1170 #include "mir/frontend/surface_id.h"
1171 #include "mir/frontend/buffer_stream_id.h"
1172 #include "mir/graphics/platform_ipc_operations.h"
1173+#include "mir/graphics/buffer_id.h"
1174 #include "mir/protobuf/display_server_debug.h"
1175 #include "mir_toolkit/common.h"
1176
1177@@ -77,6 +78,7 @@
1178 class PromptSession;
1179 class BufferStream;
1180 class InputConfigurationChanger;
1181+class BufferMap;
1182
1183 namespace detail
1184 {
1185@@ -124,8 +126,8 @@
1186 std::shared_ptr<scene::ApplicationNotRespondingDetector> const& anr_detector,
1187 std::shared_ptr<cookie::Authority> const& cookie_authority,
1188 std::shared_ptr<InputConfigurationChanger> const& input_changer,
1189- std::vector<mir::ExtensionDescription> const& extensions
1190- );
1191+ std::vector<mir::ExtensionDescription> const& extensions,
1192+ std::shared_ptr<graphics::GraphicBufferAllocator> const& allocator);
1193
1194 ~SessionMediator() noexcept;
1195
1196@@ -299,6 +301,8 @@
1197 std::shared_ptr<cookie::Authority> const cookie_authority;
1198 std::shared_ptr<InputConfigurationChanger> const input_changer;
1199 std::vector<mir::ExtensionDescription> const extensions;
1200+ std::unordered_map<graphics::BufferID, std::shared_ptr<graphics::Buffer>> buffer_cache;
1201+ std::shared_ptr<graphics::GraphicBufferAllocator> const allocator;
1202
1203 ScreencastBufferTracker screencast_buffer_tracker;
1204
1205
1206=== modified file 'src/server/scene/application_session.cpp'
1207--- src/server/scene/application_session.cpp 2017-05-25 08:58:03 +0000
1208+++ src/server/scene/application_session.cpp 2017-07-18 03:23:56 +0000
1209@@ -20,7 +20,6 @@
1210 #include "snapshot_strategy.h"
1211 #include "default_session_container.h"
1212 #include "output_properties_cache.h"
1213-#include "../compositor/buffer_map.h"
1214
1215 #include "mir/scene/surface.h"
1216 #include "mir/scene/surface_event_source.h"
1217@@ -68,7 +67,6 @@
1218 snapshot_strategy(snapshot_strategy),
1219 session_listener(session_listener),
1220 event_sink(sink),
1221- buffers(buffer_stream_factory->create_buffer_map(sink)),
1222 gralloc(gralloc),
1223 next_surface_id(0)
1224 {
1225@@ -372,7 +370,7 @@
1226 mf::BufferStreamId ms::ApplicationSession::create_buffer_stream(mg::BufferProperties const& props)
1227 {
1228 auto const id = static_cast<mf::BufferStreamId>(next_id().as_value());
1229- auto stream = buffer_stream_factory->create_buffer_stream(id, buffers, props);
1230+ auto stream = buffer_stream_factory->create_buffer_stream(id, props);
1231
1232 std::unique_lock<std::mutex> lock(surfaces_and_streams_mutex);
1233 streams[id] = stream;
1234@@ -429,56 +427,6 @@
1235 surface_stack->remove_surface(surface);
1236 }
1237
1238-mg::BufferID ms::ApplicationSession::create_buffer(mg::BufferProperties const& properties)
1239-{
1240- try
1241- {
1242- return buffers->add_buffer(gralloc->alloc_buffer(properties));
1243- }
1244- catch (std::exception& e)
1245- {
1246- event_sink->error_buffer(properties.size, properties.format, e.what());
1247- throw;
1248- }
1249-}
1250-
1251-mg::BufferID ms::ApplicationSession::create_buffer(mir::geometry::Size size, MirPixelFormat format)
1252-{
1253- try
1254- {
1255- return buffers->add_buffer(gralloc->alloc_software_buffer(size, format));
1256- }
1257- catch (std::exception& e)
1258- {
1259- event_sink->error_buffer(size, format, e.what());
1260- throw;
1261- }
1262-}
1263-
1264-mg::BufferID ms::ApplicationSession::create_buffer(
1265- mir::geometry::Size size, uint32_t native_format, uint32_t native_flags)
1266-{
1267- try
1268- {
1269- return buffers->add_buffer(gralloc->alloc_buffer(size, native_format, native_flags));
1270- }
1271- catch (std::exception& e)
1272- {
1273- event_sink->error_buffer(size, static_cast<MirPixelFormat>(native_format), e.what());
1274- throw;
1275- }
1276-}
1277-
1278-void ms::ApplicationSession::destroy_buffer(mg::BufferID id)
1279-{
1280- buffers->remove_buffer(id);
1281-}
1282-
1283-std::shared_ptr<mg::Buffer> ms::ApplicationSession::get_buffer(mg::BufferID id)
1284-{
1285- return buffers->get(id);
1286-}
1287-
1288 void ms::ApplicationSession::send_error(mir::ClientVisibleError const& error)
1289 {
1290 event_sink->handle_error(error);
1291
1292=== modified file 'src/server/scene/application_session.h'
1293--- src/server/scene/application_session.h 2017-05-08 03:04:26 +0000
1294+++ src/server/scene/application_session.h 2017-07-18 03:23:56 +0000
1295@@ -100,12 +100,6 @@
1296 void destroy_buffer_stream(frontend::BufferStreamId stream) override;
1297 void configure_streams(Surface& surface, std::vector<shell::StreamSpecification> const& config) override;
1298 void destroy_surface(std::weak_ptr<Surface> const& surface) override;
1299-
1300- graphics::BufferID create_buffer(graphics::BufferProperties const& properties) override;
1301- graphics::BufferID create_buffer(geometry::Size, MirPixelFormat) override;
1302- graphics::BufferID create_buffer(geometry::Size, uint32_t native_format, uint32_t native_flags) override;
1303- void destroy_buffer(graphics::BufferID) override;
1304- std::shared_ptr<graphics::Buffer> get_buffer(graphics::BufferID) override;
1305 protected:
1306 ApplicationSession(ApplicationSession const&) = delete;
1307 ApplicationSession& operator=(ApplicationSession const&) = delete;
1308@@ -119,7 +113,6 @@
1309 std::shared_ptr<SnapshotStrategy> const snapshot_strategy;
1310 std::shared_ptr<SessionListener> const session_listener;
1311 std::shared_ptr<frontend::EventSink> const event_sink;
1312- std::shared_ptr<frontend::ClientBuffers> const buffers;
1313 std::shared_ptr<graphics::GraphicBufferAllocator> const gralloc;
1314
1315 frontend::SurfaceId next_id();
1316
1317=== modified file 'src/server/scene/global_event_sender.cpp'
1318--- src/server/scene/global_event_sender.cpp 2017-05-08 03:04:26 +0000
1319+++ src/server/scene/global_event_sender.cpp 2017-07-18 03:23:56 +0000
1320@@ -67,10 +67,6 @@
1321 {
1322 }
1323
1324-void ms::GlobalEventSender::remove_buffer(graphics::Buffer&)
1325-{
1326-}
1327-
1328 void ms::GlobalEventSender::update_buffer(graphics::Buffer&)
1329 {
1330 }
1331
1332=== modified file 'src/server/scene/global_event_sender.h'
1333--- src/server/scene/global_event_sender.h 2017-05-08 03:04:26 +0000
1334+++ src/server/scene/global_event_sender.h 2017-07-18 03:23:56 +0000
1335@@ -41,7 +41,6 @@
1336 void send_ping(int32_t serial) override;
1337 void send_buffer(frontend::BufferStreamId id, graphics::Buffer& buffer, graphics::BufferIpcMsgType) override;
1338 void add_buffer(graphics::Buffer&) override;
1339- void remove_buffer(graphics::Buffer&) override;
1340 void update_buffer(graphics::Buffer&) override;
1341 void error_buffer(geometry::Size, MirPixelFormat, std::string const&) override;
1342 private:
1343
1344=== modified file 'src/server/shell/window_management_info.cpp'
1345--- src/server/shell/window_management_info.cpp 2017-05-08 03:04:26 +0000
1346+++ src/server/shell/window_management_info.cpp 2017-07-18 03:23:56 +0000
1347@@ -24,6 +24,7 @@
1348
1349 #include "mir/graphics/buffer.h"
1350 #include "mir/renderer/sw/pixel_source.h"
1351+#include "mir/graphics/graphic_buffer_allocator.h"
1352
1353 #include <atomic>
1354
1355@@ -173,54 +174,40 @@
1356 {
1357 AllocatingPainter(
1358 std::shared_ptr<frontend::BufferStream> const& buffer_stream,
1359- std::shared_ptr<scene::Session> const& session,
1360+ mg::GraphicBufferAllocator& allocator,
1361 Size size) :
1362 buffer_stream(buffer_stream),
1363- session(session),
1364- properties({
1365- size,
1366- buffer_stream->pixel_format(),
1367- mg::BufferUsage::software
1368- }),
1369- front_buffer(session->create_buffer(properties)),
1370- back_buffer(session->create_buffer(properties))
1371+ front_buffer{allocator.alloc_software_buffer(size, buffer_stream->pixel_format())},
1372+ back_buffer{allocator.alloc_software_buffer(size, buffer_stream->pixel_format())}
1373 {
1374 }
1375
1376 void paint(int intensity) override
1377 {
1378- auto buffer = session->get_buffer(back_buffer);
1379-
1380- auto const format = buffer->pixel_format();
1381- auto const sz = buffer->size().height.as_int() *
1382- buffer->size().width.as_int() * MIR_BYTES_PER_PIXEL(format);
1383+ auto const format = back_buffer->pixel_format();
1384+ auto const sz = back_buffer->size().height.as_int() *
1385+ back_buffer->size().width.as_int() * MIR_BYTES_PER_PIXEL(format);
1386 std::vector<unsigned char> pixels(sz, intensity);
1387- if (auto pixel_source = dynamic_cast<mrs::PixelSource*>(buffer->native_buffer_base()))
1388+ if (auto pixel_source = dynamic_cast<mrs::PixelSource*>(back_buffer->native_buffer_base()))
1389 pixel_source->write(pixels.data(), sz);
1390- buffer_stream->submit_buffer(buffer);
1391+ buffer_stream->submit_buffer(back_buffer);
1392
1393 std::swap(front_buffer, back_buffer);
1394 }
1395
1396- ~AllocatingPainter()
1397- {
1398- session->destroy_buffer(front_buffer);
1399- session->destroy_buffer(back_buffer);
1400- }
1401-
1402 std::shared_ptr<frontend::BufferStream> const buffer_stream;
1403 std::shared_ptr<scene::Session> const session;
1404 mg::BufferProperties properties;
1405- mg::BufferID front_buffer;
1406- mg::BufferID back_buffer;
1407+ std::shared_ptr<mg::Buffer> front_buffer;
1408+ std::shared_ptr<mg::Buffer> back_buffer;
1409 };
1410
1411 void msh::SurfaceInfo::init_titlebar(
1412- std::shared_ptr<scene::Session> const& session,
1413+ mg::GraphicBufferAllocator& allocator,
1414 std::shared_ptr<scene::Surface> const& surface)
1415 {
1416 auto stream = surface->primary_buffer_stream();
1417- stream_painter = std::make_shared<AllocatingPainter>(stream, session, surface->size());
1418+ stream_painter = std::make_shared<AllocatingPainter>(stream, allocator, surface->size());
1419 }
1420
1421 void msh::SurfaceInfo::paint_titlebar(int intensity)
1422
1423=== modified file 'tests/include/mir/test/doubles/mock_event_sink.h'
1424--- tests/include/mir/test/doubles/mock_event_sink.h 2017-05-08 03:04:26 +0000
1425+++ tests/include/mir/test/doubles/mock_event_sink.h 2017-07-18 03:23:56 +0000
1426@@ -42,7 +42,6 @@
1427 MOCK_METHOD1(send_ping, void(int32_t));
1428 MOCK_METHOD3(send_buffer, void(frontend::BufferStreamId, graphics::Buffer&, graphics::BufferIpcMsgType));
1429 MOCK_METHOD1(add_buffer, void(graphics::Buffer&));
1430- MOCK_METHOD1(remove_buffer, void(graphics::Buffer&));
1431 MOCK_METHOD1(update_buffer, void(graphics::Buffer&));
1432 MOCK_METHOD3(error_buffer, void(geometry::Size, MirPixelFormat, std::string const&));
1433 MOCK_METHOD1(handle_input_config_change, void(MirInputConfig const&));
1434
1435=== modified file 'tests/include/mir/test/doubles/null_event_sink.h'
1436--- tests/include/mir/test/doubles/null_event_sink.h 2017-05-08 03:04:26 +0000
1437+++ tests/include/mir/test/doubles/null_event_sink.h 2017-07-18 03:23:56 +0000
1438@@ -44,7 +44,6 @@
1439 void send_buffer(frontend::BufferStreamId, graphics::Buffer&, graphics::BufferIpcMsgType) override {}
1440 void handle_input_config_change(MirInputConfig const&) override {}
1441 void add_buffer(graphics::Buffer&) override {}
1442- void remove_buffer(graphics::Buffer&) override {}
1443 void update_buffer(graphics::Buffer&) override {}
1444 void error_buffer(geometry::Size, MirPixelFormat, std::string const&) override {}
1445 };
1446
1447=== modified file 'tests/include/mir/test/doubles/stub_buffer_stream_factory.h'
1448--- tests/include/mir/test/doubles/stub_buffer_stream_factory.h 2017-05-08 03:04:26 +0000
1449+++ tests/include/mir/test/doubles/stub_buffer_stream_factory.h 2017-07-18 03:23:56 +0000
1450@@ -19,7 +19,6 @@
1451 #ifndef MIR_TEST_DOUBLES_STUB_BUFFER_STREAM_FACTORY_H_
1452 #define MIR_TEST_DOUBLES_STUB_BUFFER_STREAM_FACTORY_H_
1453
1454-#include "mir/frontend/client_buffers.h"
1455 #include "mir/scene/buffer_stream_factory.h"
1456 #include "stub_buffer_stream.h"
1457
1458@@ -30,40 +29,20 @@
1459 namespace doubles
1460 {
1461
1462-struct StubClientBuffers : frontend::ClientBuffers
1463-{
1464- graphics::BufferID add_buffer(std::shared_ptr<graphics::Buffer> const&) override
1465- {
1466- return {};
1467- }
1468- void remove_buffer(graphics::BufferID) override
1469- {
1470- }
1471- std::shared_ptr<graphics::Buffer> get(graphics::BufferID) const override
1472- {
1473- return buffer;
1474- }
1475- void send_buffer(graphics::BufferID) override
1476- {
1477- }
1478- void receive_buffer(graphics::BufferID) override
1479- {
1480- }
1481- std::shared_ptr<graphics::Buffer> buffer;
1482-};
1483-
1484 struct StubBufferStreamFactory : public scene::BufferStreamFactory
1485 {
1486 std::shared_ptr<compositor::BufferStream> create_buffer_stream(
1487- frontend::BufferStreamId i, std::shared_ptr<frontend::ClientBuffers> const& s,
1488- int, graphics::BufferProperties const& p) { return create_buffer_stream(i, s, p); }
1489+ frontend::BufferStreamId i,
1490+ int,
1491+ graphics::BufferProperties const& p)
1492+ {
1493+ return create_buffer_stream(i, p);
1494+ }
1495 std::shared_ptr<compositor::BufferStream> create_buffer_stream(
1496- frontend::BufferStreamId, std::shared_ptr<frontend::ClientBuffers> const&,
1497- graphics::BufferProperties const&) { return std::make_shared<StubBufferStream>(); }
1498- std::shared_ptr<frontend::ClientBuffers> create_buffer_map(
1499- std::shared_ptr<frontend::BufferSink> const&)
1500+ frontend::BufferStreamId,
1501+ graphics::BufferProperties const&)
1502 {
1503- return std::make_shared<StubClientBuffers>();
1504+ return std::make_shared<StubBufferStream>();
1505 }
1506 };
1507 }
1508
1509=== modified file 'tests/integration-tests/compositor/test_swapping_swappers.cpp'
1510--- tests/integration-tests/compositor/test_swapping_swappers.cpp 2017-05-08 03:04:26 +0000
1511+++ tests/integration-tests/compositor/test_swapping_swappers.cpp 2017-07-18 03:23:56 +0000
1512@@ -19,7 +19,6 @@
1513 #include "multithread_harness.h"
1514
1515 #include "src/server/compositor/stream.h"
1516-#include "src/server/compositor/buffer_map.h"
1517 #include "mir/graphics/graphic_buffer_allocator.h"
1518
1519 #include <gmock/gmock.h>
1520@@ -30,6 +29,7 @@
1521 #include <atomic>
1522
1523 namespace mc = mir::compositor;
1524+namespace mf = mir::frontend;
1525 namespace mg = mir::graphics;
1526 namespace mt = mir::testing;
1527 namespace geom = mir::geometry;
1528@@ -42,7 +42,6 @@
1529 void SetUp()
1530 {
1531 stream = std::make_shared<mc::Stream>(
1532- std::make_shared<mc::BufferMap>(nullptr),
1533 geom::Size{380, 210}, mir_pixel_format_abgr_8888);
1534 }
1535
1536
1537=== modified file 'tests/integration-tests/test_buffer_scheduling.cpp'
1538--- tests/integration-tests/test_buffer_scheduling.cpp 2017-05-25 05:49:36 +0000
1539+++ tests/integration-tests/test_buffer_scheduling.cpp 2017-07-18 03:23:56 +0000
1540@@ -16,17 +16,15 @@
1541 * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
1542 */
1543
1544-#include "mir/frontend/client_buffers.h"
1545 #include "mir/frontend/event_sink.h"
1546 #include "mir/frontend/buffer_sink.h"
1547 #include "mir/renderer/sw/pixel_source.h"
1548 #include "src/client/buffer_vault.h"
1549 #include "src/client/buffer_factory.h"
1550-#include "src/client/buffer_factory.h"
1551 #include "src/client/protobuf_to_native_buffer.h"
1552 #include "src/client/connection_surface_map.h"
1553 #include "src/server/compositor/stream.h"
1554-#include "src/server/compositor/buffer_map.h"
1555+#include "src/server/compositor/temporary_buffers.h"
1556 #include "mir/test/doubles/stub_client_buffer_factory.h"
1557 #include "mir/test/doubles/mock_client_buffer_factory.h"
1558 #include "mir/test/doubles/stub_buffer_allocator.h"
1559@@ -48,12 +46,6 @@
1560 namespace
1561 {
1562
1563-enum class TestType
1564-{
1565- ExchangeSemantics,
1566- SubmitSemantics
1567-};
1568-
1569 enum class Access
1570 {
1571 blocked,
1572@@ -462,6 +454,24 @@
1573 return never_blocks;
1574 }
1575
1576+class AutoSendBuffer : public mc::TemporaryBuffer
1577+{
1578+public:
1579+ AutoSendBuffer(
1580+ std::shared_ptr<mg::Buffer> const& wrapped,
1581+ std::shared_ptr<mf::BufferSink> const& sink)
1582+ : TemporaryBuffer(wrapped),
1583+ sink{sink}
1584+ {
1585+ }
1586+
1587+ ~AutoSendBuffer()
1588+ {
1589+ sink->update_buffer(*buffer);
1590+ }
1591+private:
1592+ std::shared_ptr<mf::BufferSink> const sink;
1593+};
1594
1595 //test infrastructure
1596 struct BufferScheduling : public Test, ::testing::WithParamInterface<int>
1597@@ -470,9 +480,7 @@
1598 {
1599 ipc = std::make_shared<StubIpcSystem>();
1600 sink = std::make_shared<StubEventSink>(ipc);
1601- map = std::make_shared<mc::BufferMap>(sink);
1602 auto submit_stream = std::make_shared<mc::Stream>(
1603- map,
1604 geom::Size{100,100},
1605 mir_pixel_format_abgr_8888);
1606 auto weak_stream = std::weak_ptr<mc::Stream>(submit_stream);
1607@@ -483,12 +491,15 @@
1608 if (!submit_stream)
1609 return;
1610 mg::BufferID id{static_cast<unsigned int>(buffer.buffer_id())};
1611- submit_stream->submit_buffer(map->get(id));
1612+ submit_stream->submit_buffer(
1613+ std::make_shared<AutoSendBuffer>(map.at(id), sink));
1614 });
1615 ipc->on_allocate(
1616 [this](geom::Size sz)
1617 {
1618- map->add_buffer(std::make_shared<mtd::StubBuffer>(sz));
1619+ auto const buffer = std::make_shared<mtd::StubBuffer>(sz);
1620+ map[buffer->id()] = buffer;
1621+ sink->add_buffer(*buffer);
1622 });
1623
1624 consumer = std::make_unique<ScheduledConsumer>(submit_stream);
1625@@ -529,7 +540,7 @@
1626 std::unique_ptr<ConsumerSystem> consumer;
1627 std::unique_ptr<ConsumerSystem> second_consumer;
1628 std::unique_ptr<ConsumerSystem> third_consumer;
1629- std::shared_ptr<mc::BufferMap> map;
1630+ std::unordered_map<mg::BufferID, std::shared_ptr<mg::Buffer>> map;
1631 };
1632
1633 struct WithAnyNumberOfBuffers : BufferScheduling {};
1634
1635=== modified file 'tests/integration-tests/test_session.cpp'
1636--- tests/integration-tests/test_session.cpp 2017-05-08 03:04:26 +0000
1637+++ tests/integration-tests/test_session.cpp 2017-07-18 03:23:56 +0000
1638@@ -80,7 +80,7 @@
1639 struct StubGLBufferStreamFactory : public mtd::StubBufferStreamFactory
1640 {
1641 std::shared_ptr<mc::BufferStream> create_buffer_stream(
1642- mf::BufferStreamId, std::shared_ptr<mf::ClientBuffers> const&,
1643+ mf::BufferStreamId,
1644 mg::BufferProperties const&) override
1645 {
1646 return std::make_shared<StubGLBufferStream>();
1647
1648=== modified file 'tests/integration-tests/test_submit_buffer.cpp'
1649--- tests/integration-tests/test_submit_buffer.cpp 2017-05-08 03:04:26 +0000
1650+++ tests/integration-tests/test_submit_buffer.cpp 2017-07-18 03:23:56 +0000
1651@@ -32,7 +32,6 @@
1652 #include "mir/frontend/event_sink.h"
1653 #include "mir/compositor/buffer_stream.h"
1654 #include "src/server/compositor/stream.h"
1655-#include "src/server/compositor/buffer_map.h"
1656 #include "mir_toolkit/mir_client_library.h"
1657 #include "mir_toolkit/debug/surface.h"
1658 #include "src/client/mir_connection.h"
1659@@ -70,96 +69,17 @@
1660 {}
1661
1662 std::shared_ptr<mc::BufferStream> create_buffer_stream(
1663- mf::BufferStreamId i, std::shared_ptr<mf::ClientBuffers> const& s,
1664+ mf::BufferStreamId i,
1665 int, mg::BufferProperties const& p) override
1666 {
1667- return create_buffer_stream(i, s, p);
1668+ return create_buffer_stream(i, p);
1669 }
1670
1671 std::shared_ptr<mc::BufferStream> create_buffer_stream(
1672- mf::BufferStreamId, std::shared_ptr<mf::ClientBuffers> const& sink,
1673+ mf::BufferStreamId,
1674 mg::BufferProperties const& properties) override
1675 {
1676- return std::make_shared<mc::Stream>(sink, properties.size, properties.format);
1677- }
1678-
1679- std::shared_ptr<mf::ClientBuffers> create_buffer_map(std::shared_ptr<mf::BufferSink> const& sink) override
1680- {
1681- struct BufferMap : mf::ClientBuffers
1682- {
1683- BufferMap(
1684- std::shared_ptr<mf::BufferSink> const& sink,
1685- std::vector<mg::BufferID> const& ids) :
1686- sink(sink),
1687- buffer_id_seq(ids)
1688- {
1689- std::reverse(buffer_id_seq.begin(), buffer_id_seq.end());
1690- }
1691-
1692- mg::BufferID add_buffer(std::shared_ptr<mg::Buffer> const& buffer) override
1693- {
1694- struct BufferIdWrapper : mg::Buffer
1695- {
1696- BufferIdWrapper(std::shared_ptr<mg::Buffer> const& b, mg::BufferID id) :
1697- wrapped(b),
1698- id_(id)
1699- {
1700- }
1701-
1702- std::shared_ptr<mg::NativeBuffer> native_buffer_handle() const override
1703- {
1704- return wrapped->native_buffer_handle();
1705- }
1706- mg::BufferID id() const override
1707- {
1708- return id_;
1709- }
1710- geom::Size size() const override
1711- {
1712- return wrapped->size();
1713- }
1714- MirPixelFormat pixel_format() const override
1715- {
1716- return wrapped->pixel_format();
1717- }
1718- mg::NativeBufferBase* native_buffer_base() override
1719- {
1720- return wrapped->native_buffer_base();
1721- }
1722- std::shared_ptr<mg::Buffer> const wrapped;
1723- mg::BufferID const id_;
1724- };
1725-
1726- auto id = buffer_id_seq.back();
1727- buffer_id_seq.pop_back();
1728- b = std::make_shared<BufferIdWrapper>(buffer, id);
1729- sink->add_buffer(*b);
1730- return id;
1731- }
1732-
1733- void remove_buffer(mg::BufferID) override
1734- {
1735- }
1736-
1737- std::shared_ptr<mg::Buffer> get(mg::BufferID) const override
1738- {
1739- return b;
1740- }
1741-
1742- void send_buffer(mg::BufferID) override
1743- {
1744- }
1745-
1746- void receive_buffer(mg::BufferID) override
1747- {
1748- }
1749-
1750- std::shared_ptr<mg::Buffer> b;
1751- std::shared_ptr<mf::BufferSink> const sink;
1752- std::shared_ptr<mtd::StubBufferAllocator> alloc{std::make_shared<mtd::StubBufferAllocator>()};
1753- std::vector<mg::BufferID> buffer_id_seq;
1754- };
1755- return std::make_shared<BufferMap>(sink, buffer_id_seq);
1756+ return std::make_shared<mc::Stream>(properties.size, properties.format);
1757 }
1758
1759 std::vector<mg::BufferID> const buffer_id_seq;
1760@@ -204,6 +124,66 @@
1761 std::shared_ptr<mg::PlatformIpcOperations> const underlying_ops;
1762 };
1763
1764+class RecordingBufferAllocator : public mg::GraphicBufferAllocator
1765+{
1766+public:
1767+ RecordingBufferAllocator(
1768+ std::shared_ptr<mg::GraphicBufferAllocator> const& wrapped,
1769+ std::vector<std::weak_ptr<mg::Buffer>>& allocated_buffers,
1770+ std::mutex& buffer_mutex)
1771+ : allocated_buffers{allocated_buffers},
1772+ underlying_allocator{wrapped},
1773+ buffer_mutex{buffer_mutex}
1774+ {
1775+ }
1776+
1777+ std::shared_ptr<mg::Buffer> alloc_buffer(
1778+ mg::BufferProperties const& buffer_properties) override
1779+ {
1780+ auto const buf = underlying_allocator->alloc_buffer(buffer_properties);
1781+ {
1782+ std::lock_guard<std::mutex> lock{buffer_mutex};
1783+ allocated_buffers.push_back(buf);
1784+ }
1785+ return buf;
1786+ }
1787+
1788+ std::vector<MirPixelFormat> supported_pixel_formats() override
1789+ {
1790+ return underlying_allocator->supported_pixel_formats();
1791+ }
1792+
1793+ std::shared_ptr<mg::Buffer> alloc_buffer(
1794+ geom::Size size,
1795+ uint32_t native_format,
1796+ uint32_t native_flags) override
1797+ {
1798+ auto const buf = underlying_allocator->alloc_buffer(size, native_format, native_flags);
1799+ {
1800+ std::lock_guard<std::mutex> lock{buffer_mutex};
1801+ allocated_buffers.push_back(buf);
1802+ }
1803+ return buf;
1804+ }
1805+
1806+ std::shared_ptr<mg::Buffer> alloc_software_buffer(
1807+ geom::Size size,
1808+ MirPixelFormat format) override
1809+ {
1810+ auto const buf = underlying_allocator->alloc_software_buffer(size, format);
1811+ {
1812+ std::lock_guard<std::mutex> lock{buffer_mutex};
1813+ allocated_buffers.push_back(buf);
1814+ }
1815+ return buf;
1816+ }
1817+
1818+ std::vector<std::weak_ptr<mg::Buffer>>& allocated_buffers;
1819+private:
1820+ std::shared_ptr<mg::GraphicBufferAllocator> const underlying_allocator;
1821+ std::mutex& buffer_mutex;
1822+};
1823+
1824 struct StubPlatform : public mg::Platform
1825 {
1826 StubPlatform(std::shared_ptr<mir::Fd> const& last_fd)
1827@@ -214,7 +194,10 @@
1828
1829 mir::UniqueModulePtr<mg::GraphicBufferAllocator> create_buffer_allocator() override
1830 {
1831- return underlying_platform->create_buffer_allocator();
1832+ return mir::make_module_ptr<RecordingBufferAllocator>(
1833+ underlying_platform->create_buffer_allocator(),
1834+ allocated_buffers,
1835+ buffer_mutex);
1836 }
1837
1838 mir::UniqueModulePtr<mg::PlatformIpcOperations> make_ipc_operations() const override
1839@@ -231,20 +214,28 @@
1840 return underlying_platform->create_display(policy, config);
1841 }
1842
1843+ std::vector<std::weak_ptr<mg::Buffer>> get_allocated_buffers()
1844+ {
1845+ std::lock_guard<std::mutex> lock{buffer_mutex};
1846+ return allocated_buffers;
1847+ }
1848+
1849 mg::NativeRenderingPlatform* native_rendering_platform() override { return nullptr; }
1850 mg::NativeDisplayPlatform* native_display_platform() override { return nullptr; }
1851 std::vector<mir::ExtensionDescription> extensions() const override { return {}; }
1852
1853 std::shared_ptr<mir::Fd> const last_fd;
1854 std::shared_ptr<mg::Platform> const underlying_platform;
1855+
1856+private:
1857+ std::mutex buffer_mutex;
1858+ std::vector<std::weak_ptr<mg::Buffer>> allocated_buffers;
1859 };
1860
1861 struct ExchangeServerConfiguration : mtf::StubbedServerConfiguration
1862 {
1863 ExchangeServerConfiguration(
1864- std::vector<mg::BufferID> const& id_seq,
1865 std::shared_ptr<mir::Fd> const& last_unpacked_fd) :
1866- stream_factory{std::make_shared<StubStreamFactory>(id_seq)},
1867 platform{std::make_shared<StubPlatform>(last_unpacked_fd)}
1868 {
1869 }
1870@@ -254,24 +245,20 @@
1871 return platform;
1872 }
1873
1874- std::shared_ptr<msc::BufferStreamFactory> the_buffer_stream_factory() override
1875- {
1876- return stream_factory;
1877- }
1878-
1879- std::shared_ptr<StubStreamFactory> const stream_factory;
1880- std::shared_ptr<mg::Platform> const platform;
1881+ std::shared_ptr<StubPlatform> const platform;
1882 };
1883
1884 struct SubmitBuffer : mir_test_framework::InProcessServer
1885 {
1886- std::vector<mg::BufferID> const buffer_id_exchange_seq{
1887- mg::BufferID{4}, mg::BufferID{8}, mg::BufferID{9}, mg::BufferID{3}, mg::BufferID{4}};
1888-
1889 std::shared_ptr<mir::Fd> last_unpacked_fd{std::make_shared<mir::Fd>()};
1890- ExchangeServerConfiguration server_configuration{buffer_id_exchange_seq, last_unpacked_fd};
1891+ ExchangeServerConfiguration server_configuration{last_unpacked_fd};
1892 mir::DefaultServerConfiguration& server_config() override { return server_configuration; }
1893
1894+ std::vector<std::weak_ptr<mg::Buffer>> get_allocated_buffers()
1895+ {
1896+ return server_configuration.platform->get_allocated_buffers();
1897+ }
1898+
1899 void request_completed()
1900 {
1901 std::unique_lock<decltype(mutex)> lk(mutex);
1902@@ -287,7 +274,7 @@
1903 google::protobuf::NewCallback(this, &SubmitBuffer::request_completed));
1904
1905 arrived = false;
1906- return cv.wait_for(lk, std::chrono::seconds(5), [this]() {return arrived;});
1907+ return cv.wait_for(lk, std::chrono::seconds(500), [this]() {return arrived;});
1908 }
1909
1910 bool allocate_buffers(mclr::DisplayServer& server, mp::BufferAllocation& request)
1911@@ -318,13 +305,18 @@
1912 mp::BufferRequest buffer_request;
1913 };
1914 template<class Clock>
1915-bool spin_wait_for_id(mg::BufferID id, MirWindow* window, std::chrono::time_point<Clock> const& pt)
1916+bool spin_wait_for_id(
1917+ std::function<std::vector<mg::BufferID>()> const& id_generator,
1918+ MirWindow* window,
1919+ std::chrono::time_point<Clock> const& pt)
1920 {
1921 while(Clock::now() < pt)
1922 {
1923- //auto z = mir_debug_window_current_buffer_id(window);
1924- if (mir_debug_window_current_buffer_id(window) == id.as_value())
1925- return true;
1926+ for (auto const& id : id_generator())
1927+ {
1928+ if (mir_debug_window_current_buffer_id(window) == id.as_value())
1929+ return true;
1930+ }
1931 std::this_thread::yield();
1932 }
1933 return false;
1934@@ -353,7 +345,17 @@
1935 for (auto i = 0; i < buffer_request.buffer().fd().size(); i++)
1936 ::close(buffer_request.buffer().fd(i));
1937
1938- buffer_request.mutable_buffer()->set_buffer_id(buffer_id_exchange_seq.begin()->as_value());
1939+ mp::BufferAllocation allocation_request;
1940+ auto allocate = allocation_request.add_buffer_requests();
1941+ allocate->set_buffer_usage(static_cast<int32_t>(mg::BufferUsage::software));
1942+ allocate->set_pixel_format(mir_pixel_format_abgr_8888);
1943+ allocate->set_width(320);
1944+ allocate->set_height(240);
1945+
1946+ ASSERT_THAT(allocate_buffers(server, allocation_request), DidNotTimeOut());
1947+
1948+ buffer_request.mutable_buffer()->set_buffer_id(
1949+ get_allocated_buffers().back().lock()->id().as_value());
1950 buffer_request.mutable_buffer()->add_fd(file);
1951
1952 ASSERT_THAT(submit_buffer(server, buffer_request), DidNotTimeOut());
1953@@ -377,10 +379,22 @@
1954 auto rpc_channel = connection->rpc_channel();
1955 mclr::DisplayServer server(rpc_channel);
1956
1957+ for(int i = 0; i < 5; ++i)
1958+ {
1959+ mp::BufferAllocation allocation_request;
1960+ auto allocate = allocation_request.add_buffer_requests();
1961+ allocate->set_buffer_usage(static_cast<int32_t>(mg::BufferUsage::software));
1962+ allocate->set_pixel_format(mir_pixel_format_abgr_8888);
1963+ allocate->set_width(320);
1964+ allocate->set_height(240);
1965+
1966+ allocate_buffers(server, allocation_request);
1967+ }
1968+
1969 mp::BufferRequest request;
1970- for (auto const& id : buffer_id_exchange_seq)
1971+ for (auto weak_buffer : get_allocated_buffers())
1972 {
1973- buffer_request.mutable_buffer()->set_buffer_id(id.as_value());
1974+ buffer_request.mutable_buffer()->set_buffer_id(weak_buffer.lock()->id().as_value());
1975 ASSERT_THAT(submit_buffer(server, buffer_request), DidNotTimeOut());
1976 }
1977
1978@@ -396,8 +410,32 @@
1979 auto window = mtf::make_any_surface(connection);
1980
1981 auto timeout = std::chrono::steady_clock::now() + 5s;
1982- EXPECT_TRUE(spin_wait_for_id(buffer_id_exchange_seq.back(), window, timeout))
1983- << "failed to see the last scheduled buffer become the current one";
1984+
1985+ EXPECT_TRUE(
1986+ spin_wait_for_id(
1987+ [this]()
1988+ {
1989+ /* We expect to receive one of the implicitly allocated buffers
1990+ * We don't care which one we get.
1991+ *
1992+ * We need to repeatedly check the allocated buffers, because
1993+ * buffer allocation is asynchronous WRT window creation.
1994+ */
1995+ std::vector<mg::BufferID> candidate_ids;
1996+ for (auto const weak_buffer : get_allocated_buffers())
1997+ {
1998+ auto const buffer = weak_buffer.lock();
1999+ if (buffer)
2000+ {
2001+ // If there are any expired buffers we don't care about them
2002+ candidate_ids.push_back(buffer->id());
2003+ }
2004+ }
2005+ return candidate_ids;
2006+ },
2007+ window,
2008+ timeout))
2009+ << "failed to see buffer";
2010
2011 mir_window_release_sync(window);
2012 mir_connection_release(connection);
2013
2014=== modified file 'tests/integration-tests/test_surface_stack_with_compositor.cpp'
2015--- tests/integration-tests/test_surface_stack_with_compositor.cpp 2017-05-08 03:04:26 +0000
2016+++ tests/integration-tests/test_surface_stack_with_compositor.cpp 2017-07-18 03:23:56 +0000
2017@@ -24,7 +24,6 @@
2018 #include "src/server/scene/basic_surface.h"
2019 #include "src/server/compositor/default_display_buffer_compositor_factory.h"
2020 #include "src/server/compositor/multi_threaded_compositor.h"
2021-#include "src/server/compositor/buffer_map.h"
2022 #include "src/server/compositor/stream.h"
2023 #include "mir/test/fake_shared.h"
2024 #include "mir/test/doubles/mock_buffer_stream.h"
2025@@ -47,6 +46,7 @@
2026 namespace mr = mir::report;
2027 namespace mc = mir::compositor;
2028 namespace mg = mir::graphics;
2029+namespace mf = mir::frontend;
2030 namespace geom = mir::geometry;
2031 using namespace testing;
2032
2033@@ -123,8 +123,7 @@
2034 {
2035 SurfaceStackCompositor() :
2036 timeout{std::chrono::system_clock::now() + std::chrono::seconds(5)},
2037- buffers(std::make_shared<mc::BufferMap>(std::make_shared<NiceMock<mtd::MockEventSink>>())),
2038- stream(std::make_shared<mc::Stream>(buffers, geom::Size{ 1, 1 }, mir_pixel_format_abgr_8888 )),
2039+ stream(std::make_shared<mc::Stream>(geom::Size{ 1, 1 }, mir_pixel_format_abgr_8888 )),
2040 mock_buffer_stream(std::make_shared<NiceMock<mtd::MockBufferStream>>()),
2041 streams({ { stream, {0,0}, {} } }),
2042 stub_surface{std::make_shared<ms::BasicSurface>(
2043@@ -136,7 +135,6 @@
2044 null_scene_report)},
2045 stub_buffer(std::make_shared<mtd::StubBuffer>())
2046 {
2047- buffers->add_buffer(stub_buffer);
2048 ON_CALL(*mock_buffer_stream, lock_compositor_buffer(_))
2049 .WillByDefault(Return(mt::fake_shared(*stub_buffer)));
2050 }
2051@@ -145,7 +143,6 @@
2052 std::shared_ptr<mc::CompositorReport> null_comp_report{mr::null_compositor_report()};
2053 StubRendererFactory renderer_factory;
2054 std::chrono::system_clock::time_point timeout;
2055- std::shared_ptr<mc::BufferMap> buffers;
2056 std::shared_ptr<mc::Stream> stream;
2057 std::shared_ptr<mtd::MockBufferStream> mock_buffer_stream;
2058 std::list<ms::StreamInfo> const streams;
2059
2060=== modified file 'tests/integration-tests/test_swapinterval.cpp'
2061--- tests/integration-tests/test_swapinterval.cpp 2017-05-08 03:04:26 +0000
2062+++ tests/integration-tests/test_swapinterval.cpp 2017-07-18 03:23:56 +0000
2063@@ -67,24 +67,19 @@
2064 }
2065
2066 std::shared_ptr<mc::BufferStream> create_buffer_stream(
2067- mf::BufferStreamId id, std::shared_ptr<mf::ClientBuffers> const& sink,
2068+ mf::BufferStreamId id,
2069 int, mg::BufferProperties const& p) override
2070 {
2071- return create_buffer_stream(id, sink, p);
2072+ return create_buffer_stream(id, p);
2073 }
2074
2075 std::shared_ptr<mc::BufferStream> create_buffer_stream(
2076- mf::BufferStreamId, std::shared_ptr<mf::ClientBuffers> const&,
2077+ mf::BufferStreamId,
2078 mg::BufferProperties const&) override
2079 {
2080 return std::make_shared<StubBufferStream>(framedropping_enabled);
2081 }
2082
2083- std::shared_ptr<mf::ClientBuffers> create_buffer_map(std::shared_ptr<mf::BufferSink> const&) override
2084- {
2085- return std::make_shared<mtd::StubClientBuffers>();
2086- }
2087-
2088 private:
2089 std::atomic<bool>& framedropping_enabled;
2090 };
2091
2092=== modified file 'tests/mir_test_doubles/mock_event_sink_factory.cpp'
2093--- tests/mir_test_doubles/mock_event_sink_factory.cpp 2017-05-08 03:04:26 +0000
2094+++ tests/mir_test_doubles/mock_event_sink_factory.cpp 2017-07-18 03:23:56 +0000
2095@@ -42,7 +42,6 @@
2096 void send_buffer(mf::BufferStreamId id, mg::Buffer& buf, mg::BufferIpcMsgType type) override;
2097 void handle_input_config_change(MirInputConfig const& devices) override;
2098 void add_buffer(mir::graphics::Buffer&) override;
2099- void remove_buffer(mir::graphics::Buffer&) override;
2100 void update_buffer(mir::graphics::Buffer&) override;
2101 void error_buffer(mir::geometry::Size, MirPixelFormat, std::string const&) override;
2102
2103@@ -106,11 +105,6 @@
2104 underlying_sink->error_buffer(sz, pf, error);
2105 }
2106
2107-void GloballyUniqueMockEventSink::remove_buffer(mir::graphics::Buffer& buffer)
2108-{
2109- underlying_sink->remove_buffer(buffer);
2110-}
2111-
2112 void GloballyUniqueMockEventSink::update_buffer(mir::graphics::Buffer& buffer)
2113 {
2114 underlying_sink->update_buffer(buffer);
2115
2116=== modified file 'tests/mir_test_framework/stub_session.cpp'
2117--- tests/mir_test_framework/stub_session.cpp 2017-05-08 03:04:26 +0000
2118+++ tests/mir_test_framework/stub_session.cpp 2017-07-18 03:23:56 +0000
2119@@ -143,31 +143,6 @@
2120 {
2121 }
2122
2123-mir::graphics::BufferID mtd::StubSession::create_buffer(mir::graphics::BufferProperties const&)
2124-{
2125- return mir::graphics::BufferID(3);
2126-}
2127-
2128-mir::graphics::BufferID mtd::StubSession::create_buffer(mir::geometry::Size, uint32_t, uint32_t)
2129-{
2130- return mir::graphics::BufferID(3);
2131-}
2132-
2133-mir::graphics::BufferID mtd::StubSession::create_buffer(mir::geometry::Size, MirPixelFormat)
2134-{
2135- return mir::graphics::BufferID(3);
2136-}
2137-
2138-void mtd::StubSession::destroy_buffer(mir::graphics::BufferID)
2139-{
2140-}
2141-
2142-std::shared_ptr<mir::graphics::Buffer> mtd::StubSession::get_buffer(graphics::BufferID)
2143-{
2144- return std::make_shared<mtd::StubBuffer>(
2145- std::make_shared<mir_test_framework::NativeBuffer>(graphics::BufferProperties{}));
2146-}
2147-
2148 namespace
2149 {
2150 // Ensure we don't accidentally have an abstract class
2151
2152=== modified file 'tests/unit-tests/client/test_client_buffer_stream.cpp'
2153--- tests/unit-tests/client/test_client_buffer_stream.cpp 2017-05-17 04:48:46 +0000
2154+++ tests/unit-tests/client/test_client_buffer_stream.cpp 2017-07-18 03:23:56 +0000
2155@@ -204,16 +204,15 @@
2156
2157 void async_buffer_arrives(mp::Buffer& buffer)
2158 {
2159- try
2160+ if (auto buf = map->buffer(buffer.buffer_id()))
2161 {
2162- map->buffer(buffer.buffer_id())->received(*mcl::protobuf_to_native_buffer(buffer));
2163+ buf->received(*mcl::protobuf_to_native_buffer(buffer));
2164 }
2165- catch (std::runtime_error& e)
2166+ else
2167 {
2168- auto bb = factory->generate_buffer(buffer);
2169- auto braw = bb.get();
2170- map->insert(buffer.buffer_id(), std::move(bb));
2171- braw->received();
2172+ map->insert(buffer.buffer_id(), factory->generate_buffer(buffer));
2173+ buf = map->buffer(buffer.buffer_id());
2174+ buf->received();
2175 }
2176 }
2177
2178
2179=== modified file 'tests/unit-tests/client/test_connection_resource_map.cpp'
2180--- tests/unit-tests/client/test_connection_resource_map.cpp 2017-05-08 03:04:26 +0000
2181+++ tests/unit-tests/client/test_connection_resource_map.cpp 2017-07-18 03:23:56 +0000
2182@@ -97,17 +97,13 @@
2183 {
2184 using namespace testing;
2185 mcl::ConnectionSurfaceMap map;
2186- EXPECT_THROW({
2187- map.buffer(buffer_id);
2188- }, std::runtime_error);
2189+ EXPECT_THAT(map.buffer(buffer_id), IsNull());
2190
2191 map.insert(buffer_id, buffer);
2192 EXPECT_THAT(map.buffer(buffer_id), Eq(buffer));
2193 map.erase(buffer_id);
2194
2195- EXPECT_THROW({
2196- map.buffer(buffer_id);
2197- }, std::runtime_error);
2198+ EXPECT_THAT(map.buffer(buffer_id), IsNull());
2199 }
2200
2201 TEST_F(ConnectionResourceMap, can_access_buffers_from_surface)
2202
2203=== modified file 'tests/unit-tests/client/test_mir_connection.cpp'
2204--- tests/unit-tests/client/test_mir_connection.cpp 2017-05-25 06:28:52 +0000
2205+++ tests/unit-tests/client/test_mir_connection.cpp 2017-07-18 03:23:56 +0000
2206@@ -873,7 +873,6 @@
2207 auto native_format = 342u;
2208 auto native_flags = 0x44;
2209 mp::BufferAllocation mp_alloc;
2210- mp_alloc.mutable_id()->set_value(-1);
2211 auto params = mp_alloc.add_buffer_requests();
2212 params->set_width(size.width.as_int());
2213 params->set_height(size.height.as_int());
2214
2215=== modified file 'tests/unit-tests/client/test_protobuf_rpc_channel.cpp'
2216--- tests/unit-tests/client/test_protobuf_rpc_channel.cpp 2017-05-08 03:04:26 +0000
2217+++ tests/unit-tests/client/test_protobuf_rpc_channel.cpp 2017-07-18 03:23:56 +0000
2218@@ -840,3 +840,27 @@
2219 std::make_shared<mtd::NullClientEventSink>()};
2220 channel.on_data_available();
2221 }
2222+
2223+TEST_F(MirProtobufRpcChannelTest, ignores_update_message_for_unknown_buffer)
2224+{
2225+ mir::protobuf::EventSequence seq;
2226+ auto request = seq.mutable_buffer_request();
2227+ request->mutable_buffer()->set_buffer_id(42);
2228+ request->set_operation(mir::protobuf::BufferOperation::update);
2229+
2230+ set_async_buffer_message(seq, *transport);
2231+
2232+ channel->on_data_available();
2233+}
2234+
2235+TEST_F(MirProtobufRpcChannelTest, ignores_delete_message_for_unknown_buffer)
2236+{
2237+ mir::protobuf::EventSequence seq;
2238+ auto request = seq.mutable_buffer_request();
2239+ request->mutable_buffer()->set_buffer_id(42);
2240+ request->set_operation(mir::protobuf::BufferOperation::remove);
2241+
2242+ set_async_buffer_message(seq, *transport);
2243+
2244+ channel->on_data_available();
2245+}
2246
2247=== modified file 'tests/unit-tests/compositor/CMakeLists.txt'
2248--- tests/unit-tests/compositor/CMakeLists.txt 2017-05-08 03:04:26 +0000
2249+++ tests/unit-tests/compositor/CMakeLists.txt 2017-07-18 03:23:56 +0000
2250@@ -7,7 +7,6 @@
2251 ${CMAKE_CURRENT_SOURCE_DIR}/test_screencast_display_buffer.cpp
2252 ${CMAKE_CURRENT_SOURCE_DIR}/test_compositing_screencast.cpp
2253 ${CMAKE_CURRENT_SOURCE_DIR}/test_multi_monitor_arbiter.cpp
2254- ${CMAKE_CURRENT_SOURCE_DIR}/test_client_buffers.cpp
2255 ${CMAKE_CURRENT_SOURCE_DIR}/test_dropping_schedule.cpp
2256 ${CMAKE_CURRENT_SOURCE_DIR}/test_queueing_schedule.cpp
2257 )
2258
2259=== removed file 'tests/unit-tests/compositor/test_client_buffers.cpp'
2260--- tests/unit-tests/compositor/test_client_buffers.cpp 2017-05-08 03:04:26 +0000
2261+++ tests/unit-tests/compositor/test_client_buffers.cpp 1970-01-01 00:00:00 +0000
2262@@ -1,119 +0,0 @@
2263-/*
2264- * Copyright © 2015 Canonical Ltd.
2265- *
2266- * This program is free software: you can redistribute it and/or modify
2267- * it under the terms of the GNU General Public License version 3 as
2268- * published by the Free Software Foundation.
2269- *
2270- * This program is distributed in the hope that it will be useful,
2271- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2272- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2273- * GNU General Public License for more details.
2274- *
2275- * You should have received a copy of the GNU General Public License
2276- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2277- *
2278- * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
2279- */
2280-
2281-#include "mir/test/doubles/mock_event_sink.h"
2282-#include "mir/test/fake_shared.h"
2283-#include "mir/test/doubles/stub_buffer_allocator.h"
2284-#include "src/server/compositor/buffer_map.h"
2285-#include "mir/graphics/display_configuration.h"
2286-
2287-#include <gtest/gtest.h>
2288-using namespace testing;
2289-namespace mt = mir::test;
2290-namespace mtd = mir::test::doubles;
2291-namespace mc = mir::compositor;
2292-namespace mg = mir::graphics;
2293-namespace mf = mir::frontend;
2294-namespace geom = mir::geometry;
2295-
2296-struct ClientBuffers : public Test
2297-{
2298- std::shared_ptr<mtd::MockEventSink> mock_sink = std::make_shared<testing::NiceMock<mtd::MockEventSink>>();
2299- mg::BufferProperties properties{geom::Size{42,43}, mir_pixel_format_abgr_8888, mg::BufferUsage::hardware};
2300- mtd::StubBuffer stub_buffer{properties};
2301- mc::BufferMap map{mock_sink};
2302-};
2303-
2304-TEST_F(ClientBuffers, sends_full_buffer_on_allocation)
2305-{
2306- EXPECT_CALL(*mock_sink, add_buffer(Ref(stub_buffer)));
2307- mc::BufferMap map{mock_sink};
2308- EXPECT_THAT(map.add_buffer(mt::fake_shared(stub_buffer)), Eq(stub_buffer.id()));
2309-}
2310-
2311-TEST_F(ClientBuffers, access_of_nonexistent_buffer_throws)
2312-{
2313- EXPECT_THROW({
2314- auto buffer = map.get(stub_buffer.id());
2315- }, std::logic_error);
2316-}
2317-
2318-TEST_F(ClientBuffers, removal_of_nonexistent_buffer_throws)
2319-{
2320- EXPECT_THROW({
2321- map.remove_buffer(stub_buffer.id());
2322- }, std::logic_error);
2323-}
2324-
2325-TEST_F(ClientBuffers, can_access_once_added)
2326-{
2327- auto id = map.add_buffer(mt::fake_shared(stub_buffer));
2328- EXPECT_THAT(map.get(id).get(), Eq(&stub_buffer));
2329-}
2330-
2331-TEST_F(ClientBuffers, sends_update_msg_to_send_buffer)
2332-{
2333- auto id = map.add_buffer(mt::fake_shared(stub_buffer));
2334- auto buffer = map.get(id);
2335- EXPECT_CALL(*mock_sink, update_buffer(Ref(*buffer)));
2336- map.send_buffer(id);
2337-}
2338-
2339-TEST_F(ClientBuffers, sends_no_update_msg_if_buffer_is_not_around)
2340-{
2341- auto id = map.add_buffer(mt::fake_shared(stub_buffer));
2342- auto buffer = map.get(id);
2343-
2344- EXPECT_CALL(*mock_sink, remove_buffer(Ref(*buffer)));
2345- map.remove_buffer(id);
2346- map.send_buffer(id);
2347-}
2348-
2349-TEST_F(ClientBuffers, can_remove_buffer_from_send_callback)
2350-{
2351- auto id = map.add_buffer(mt::fake_shared(stub_buffer));
2352- ON_CALL(*mock_sink, update_buffer(_))
2353- .WillByDefault(Invoke(
2354- [&] (mg::Buffer& buffer)
2355- {
2356- map.remove_buffer(buffer.id());
2357- }));
2358-
2359- map.send_buffer(id);
2360-}
2361-
2362-TEST_F(ClientBuffers, ignores_unknown_receive)
2363-{
2364- EXPECT_CALL(*mock_sink, add_buffer(_))
2365- .Times(1);
2366- auto id = map.add_buffer(mt::fake_shared(stub_buffer));
2367- map.remove_buffer(id);
2368- map.send_buffer(id);
2369-}
2370-
2371-TEST_F(ClientBuffers, sends_error_buffer_when_alloc_fails)
2372-{
2373- std::string error_msg = "a reason";
2374- EXPECT_CALL(*mock_sink, add_buffer(_))
2375- .WillOnce(Throw(std::runtime_error(error_msg)));
2376- EXPECT_CALL(*mock_sink, error_buffer(stub_buffer.size(), stub_buffer.pixel_format(), StrEq(error_msg)));
2377- mc::BufferMap map{mock_sink};
2378- EXPECT_THROW({
2379- map.add_buffer(mt::fake_shared(stub_buffer));
2380- }, std::runtime_error);
2381-}
2382
2383=== modified file 'tests/unit-tests/compositor/test_dropping_schedule.cpp'
2384--- tests/unit-tests/compositor/test_dropping_schedule.cpp 2017-05-08 03:04:26 +0000
2385+++ tests/unit-tests/compositor/test_dropping_schedule.cpp 2017-07-18 03:23:56 +0000
2386@@ -16,7 +16,6 @@
2387 * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
2388 */
2389
2390-#include "mir/frontend/client_buffers.h"
2391 #include "src/server/compositor/dropping_schedule.h"
2392 #include "mir/test/doubles/stub_buffer.h"
2393 #include "mir/test/fake_shared.h"
2394@@ -28,20 +27,9 @@
2395 namespace mt = mir::test;
2396 namespace mg = mir::graphics;
2397 namespace mc = mir::compositor;
2398-namespace mf = mir::frontend;
2399 namespace
2400 {
2401
2402-struct MockBufferMap : mf::ClientBuffers
2403-{
2404- MOCK_METHOD1(add_buffer, mg::BufferID(std::shared_ptr<mg::Buffer> const&));
2405- MOCK_METHOD1(remove_buffer, void(mg::BufferID id));
2406- MOCK_METHOD1(send_buffer, void(mg::BufferID id));
2407- MOCK_METHOD1(receive_buffer, void(mg::BufferID id));
2408- MOCK_CONST_METHOD0(client_owned_buffer_count, size_t());
2409- MOCK_CONST_METHOD1(get, std::shared_ptr<mg::Buffer>(mg::BufferID));
2410-};
2411-
2412 struct DroppingSchedule : Test
2413 {
2414 DroppingSchedule()
2415@@ -52,8 +40,7 @@
2416 unsigned int const num_buffers{5};
2417 std::vector<std::shared_ptr<mg::Buffer>> buffers;
2418
2419- MockBufferMap mock_client_buffers;
2420- mc::DroppingSchedule schedule{mt::fake_shared(mock_client_buffers)};
2421+ mc::DroppingSchedule schedule;
2422 std::vector<std::shared_ptr<mg::Buffer>> drain_queue()
2423 {
2424 std::vector<std::shared_ptr<mg::Buffer>> scheduled_buffers;
2425@@ -74,49 +61,23 @@
2426
2427 TEST_F(DroppingSchedule, drops_excess_buffers)
2428 {
2429- InSequence seq;
2430- EXPECT_CALL(mock_client_buffers, send_buffer(buffers[0]->id()));
2431- EXPECT_CALL(mock_client_buffers, send_buffer(buffers[1]->id()));
2432- EXPECT_CALL(mock_client_buffers, send_buffer(buffers[2]->id()));
2433- EXPECT_CALL(mock_client_buffers, send_buffer(buffers[3]->id()));
2434-
2435 for(auto i = 0u; i < num_buffers; i++)
2436 schedule.schedule(buffers[i]);
2437
2438 auto queue = drain_queue();
2439 ASSERT_THAT(queue, SizeIs(1));
2440+
2441+ // The 5th buffer should be scheduled...
2442 EXPECT_THAT(queue[0]->id(), Eq(buffers[4]->id()));
2443-}
2444-
2445-TEST_F(DroppingSchedule, nonblocking_schedule_avoids_socket_io)
2446-{
2447- for (auto i = 0u; i < num_buffers; i++)
2448+ for (int i = 0; i < 4 ; ++i)
2449 {
2450- EXPECT_CALL(mock_client_buffers, send_buffer(_))
2451- .Times(0);
2452-
2453- auto deferred_io = schedule.schedule_nonblocking(buffers[i]);
2454-
2455- testing::Mock::VerifyAndClearExpectations(&mock_client_buffers);
2456- if (i > 0)
2457- {
2458- EXPECT_CALL(mock_client_buffers, send_buffer(buffers[i-1]->id()))
2459- .Times(1);
2460- ASSERT_TRUE(deferred_io.valid());
2461- deferred_io.wait();
2462- testing::Mock::VerifyAndClearExpectations(&mock_client_buffers);
2463- }
2464+ // ...and all the others should have no external references
2465+ EXPECT_TRUE(buffers[i].unique());
2466 }
2467-
2468- auto queue = drain_queue();
2469- ASSERT_THAT(queue, SizeIs(1));
2470- EXPECT_THAT(queue[0]->id(), Eq(buffers[4]->id()));
2471 }
2472
2473 TEST_F(DroppingSchedule, queueing_same_buffer_many_times_doesnt_drop)
2474 {
2475- EXPECT_CALL(mock_client_buffers, send_buffer(_)).Times(0);
2476-
2477 schedule.schedule(buffers[2]);
2478 schedule.schedule(buffers[2]);
2479 schedule.schedule(buffers[2]);
2480
2481=== modified file 'tests/unit-tests/compositor/test_multi_monitor_arbiter.cpp'
2482--- tests/unit-tests/compositor/test_multi_monitor_arbiter.cpp 2017-05-26 12:45:45 +0000
2483+++ tests/unit-tests/compositor/test_multi_monitor_arbiter.cpp 2017-07-18 03:23:56 +0000
2484@@ -21,7 +21,7 @@
2485 #include "mir/test/doubles/stub_buffer_allocator.h"
2486 #include "src/server/compositor/multi_monitor_arbiter.h"
2487 #include "src/server/compositor/schedule.h"
2488-#include "mir/frontend/client_buffers.h"
2489+#include "src/server/compositor/temporary_buffers.h"
2490
2491 #include <gtest/gtest.h>
2492 using namespace testing;
2493@@ -33,16 +33,6 @@
2494
2495 namespace
2496 {
2497-struct MockBufferMap : mf::ClientBuffers
2498-{
2499- MOCK_METHOD1(add_buffer, mg::BufferID(std::shared_ptr<mg::Buffer> const&));
2500- MOCK_METHOD1(remove_buffer, void(mg::BufferID id));
2501- MOCK_METHOD1(receive_buffer, void(mg::BufferID id));
2502- MOCK_METHOD1(send_buffer, void(mg::BufferID id));
2503- MOCK_CONST_METHOD0(client_owned_buffer_count, size_t());
2504- MOCK_CONST_METHOD1(get, std::shared_ptr<mg::Buffer>(mg::BufferID));
2505-};
2506-
2507 struct FixedSchedule : mc::Schedule
2508 {
2509 void schedule(std::shared_ptr<mg::Buffer> const&) override
2510@@ -63,7 +53,9 @@
2511 {
2512 if (sched.empty() || current == sched.size())
2513 throw std::runtime_error("no buffer scheduled");
2514- return sched[current++];
2515+ auto buf = sched.front();
2516+ sched.erase(sched.begin());
2517+ return buf;
2518 }
2519 void set_schedule(std::vector<std::shared_ptr<mg::Buffer>> s)
2520 {
2521@@ -84,10 +76,40 @@
2522 }
2523 unsigned int const num_buffers{6u};
2524 std::vector<std::shared_ptr<mg::Buffer>> buffers;
2525- NiceMock<MockBufferMap> mock_map;
2526 FixedSchedule schedule;
2527- mc::MultiMonitorArbiter arbiter{mt::fake_shared(mock_map), mt::fake_shared(schedule)};
2528+ mc::MultiMonitorArbiter arbiter{mt::fake_shared(schedule)};
2529 };
2530+
2531+MATCHER_P(IsSameBufferAs, buffer, "")
2532+{
2533+ return buffer->id() == arg->id();
2534+}
2535+
2536+std::shared_ptr<mg::Buffer> wrap_with_destruction_notifier(
2537+ std::shared_ptr<mg::Buffer> const& buffer,
2538+ std::shared_ptr<bool> const& destroyed)
2539+{
2540+ class DestructionNotifyingBuffer : public mc::TemporaryBuffer
2541+ {
2542+ public:
2543+ DestructionNotifyingBuffer(
2544+ std::shared_ptr<mg::Buffer> const& buffer,
2545+ std::shared_ptr<bool> const& destroyed)
2546+ : TemporaryBuffer(buffer),
2547+ destroyed{destroyed}
2548+ {
2549+ }
2550+
2551+ ~DestructionNotifyingBuffer()
2552+ {
2553+ *destroyed = true;
2554+ }
2555+ private:
2556+ std::shared_ptr<bool> const destroyed;
2557+ };
2558+
2559+ return std::make_shared<DestructionNotifyingBuffer>(buffer, destroyed);
2560+}
2561 }
2562
2563 TEST_F(MultiMonitorArbiter, compositor_access_before_any_submission_throws)
2564@@ -107,32 +129,30 @@
2565 {
2566 schedule.set_schedule({buffers[0]});
2567 auto cbuffer = arbiter.compositor_acquire(this);
2568- EXPECT_THAT(cbuffer, Eq(buffers[0]));
2569+ EXPECT_THAT(cbuffer, IsSameBufferAs(buffers[0]));
2570 }
2571
2572 TEST_F(MultiMonitorArbiter, compositor_release_sends_buffer_back)
2573 {
2574- EXPECT_CALL(mock_map, send_buffer(buffers[0]->id()));
2575-
2576- schedule.set_schedule({buffers[0]});
2577+ auto buffer_released = std::make_shared<bool>(false);
2578+ schedule.set_schedule({ wrap_with_destruction_notifier(buffers[0], buffer_released) });
2579
2580 auto cbuffer = arbiter.compositor_acquire(this);
2581 schedule.set_schedule({buffers[1]});
2582 arbiter.compositor_release(cbuffer);
2583+ cbuffer.reset();
2584+ // We need to acquire a new buffer - the current one is on-screen, so can't be sent back.
2585+ arbiter.compositor_acquire(this);
2586+ EXPECT_TRUE(*buffer_released);
2587 }
2588
2589 TEST_F(MultiMonitorArbiter, compositor_can_acquire_different_buffers)
2590 {
2591- EXPECT_CALL(mock_map, send_buffer(buffers[0]->id()));
2592-
2593 schedule.set_schedule({buffers[0]});
2594 auto cbuffer1 = arbiter.compositor_acquire(this);
2595 schedule.set_schedule({buffers[1]});
2596 auto cbuffer2 = arbiter.compositor_acquire(this);
2597- EXPECT_THAT(cbuffer1, Ne(cbuffer2));
2598- arbiter.compositor_release(cbuffer2);
2599- arbiter.compositor_release(cbuffer1);
2600- Mock::VerifyAndClearExpectations(&mock_map);
2601+ EXPECT_THAT(cbuffer1, Not(IsSameBufferAs(cbuffer2)));
2602 }
2603
2604 TEST_F(MultiMonitorArbiter, compositor_buffer_syncs_to_fastest_compositor)
2605@@ -155,13 +175,13 @@
2606 auto cbuffer6 = arbiter.compositor_acquire(&comp_id2);
2607 auto cbuffer7 = arbiter.compositor_acquire(&comp_id2);
2608
2609- EXPECT_THAT(cbuffer1, Eq(buffers[0]));
2610- EXPECT_THAT(cbuffer2, Eq(buffers[0]));
2611- EXPECT_THAT(cbuffer3, Eq(buffers[1]));
2612- EXPECT_THAT(cbuffer4, Eq(buffers[0]));
2613- EXPECT_THAT(cbuffer5, Eq(buffers[0]));
2614- EXPECT_THAT(cbuffer6, Eq(buffers[1]));
2615- EXPECT_THAT(cbuffer7, Eq(buffers[1]));
2616+ EXPECT_THAT(cbuffer1, IsSameBufferAs(buffers[0]));
2617+ EXPECT_THAT(cbuffer2, IsSameBufferAs(buffers[0]));
2618+ EXPECT_THAT(cbuffer3, IsSameBufferAs(buffers[1]));
2619+ EXPECT_THAT(cbuffer4, IsSameBufferAs(buffers[0]));
2620+ EXPECT_THAT(cbuffer5, IsSameBufferAs(buffers[0]));
2621+ EXPECT_THAT(cbuffer6, IsSameBufferAs(buffers[1]));
2622+ EXPECT_THAT(cbuffer7, IsSameBufferAs(buffers[1]));
2623 }
2624
2625 TEST_F(MultiMonitorArbiter, compositor_consumes_all_buffers_when_operating_as_a_composited_scene_would)
2626@@ -179,11 +199,11 @@
2627 auto cbuffer5 = arbiter.compositor_acquire(this);
2628 arbiter.compositor_release(cbuffer5);
2629
2630- EXPECT_THAT(cbuffer1, Eq(buffers[0]));
2631- EXPECT_THAT(cbuffer2, Eq(buffers[1]));
2632- EXPECT_THAT(cbuffer3, Eq(buffers[2]));
2633- EXPECT_THAT(cbuffer4, Eq(buffers[3]));
2634- EXPECT_THAT(cbuffer5, Eq(buffers[4]));
2635+ EXPECT_THAT(cbuffer1, IsSameBufferAs(buffers[0]));
2636+ EXPECT_THAT(cbuffer2, IsSameBufferAs(buffers[1]));
2637+ EXPECT_THAT(cbuffer3, IsSameBufferAs(buffers[2]));
2638+ EXPECT_THAT(cbuffer4, IsSameBufferAs(buffers[3]));
2639+ EXPECT_THAT(cbuffer5, IsSameBufferAs(buffers[4]));
2640 }
2641
2642 TEST_F(MultiMonitorArbiter, compositor_consumes_all_buffers_when_operating_as_a_bypassed_buffer_would)
2643@@ -201,11 +221,11 @@
2644 arbiter.compositor_release(cbuffer4);
2645 arbiter.compositor_release(cbuffer5);
2646
2647- EXPECT_THAT(cbuffer1, Eq(buffers[0]));
2648- EXPECT_THAT(cbuffer2, Eq(buffers[1]));
2649- EXPECT_THAT(cbuffer3, Eq(buffers[2]));
2650- EXPECT_THAT(cbuffer4, Eq(buffers[3]));
2651- EXPECT_THAT(cbuffer5, Eq(buffers[4]));
2652+ EXPECT_THAT(cbuffer1, IsSameBufferAs(buffers[0]));
2653+ EXPECT_THAT(cbuffer2, IsSameBufferAs(buffers[1]));
2654+ EXPECT_THAT(cbuffer3, IsSameBufferAs(buffers[2]));
2655+ EXPECT_THAT(cbuffer4, IsSameBufferAs(buffers[3]));
2656+ EXPECT_THAT(cbuffer5, IsSameBufferAs(buffers[4]));
2657 }
2658
2659 TEST_F(MultiMonitorArbiter, multimonitor_compositor_buffer_syncs_to_fastest_with_more_queueing)
2660@@ -228,18 +248,18 @@
2661 auto cbuffer7 = arbiter.compositor_acquire(&comp_id2); //buffer[4]
2662 auto cbuffer8 = arbiter.compositor_acquire(&comp_id1); //buffer[4]
2663
2664- EXPECT_THAT(cbuffer1, Eq(buffers[0]));
2665- EXPECT_THAT(cbuffer2, Eq(buffers[0]));
2666-
2667- EXPECT_THAT(cbuffer3, Eq(buffers[1]));
2668-
2669- EXPECT_THAT(cbuffer4, Eq(buffers[2]));
2670- EXPECT_THAT(cbuffer5, Eq(buffers[2]));
2671-
2672- EXPECT_THAT(cbuffer6, Eq(buffers[3]));
2673-
2674- EXPECT_THAT(cbuffer7, Eq(buffers[4]));
2675- EXPECT_THAT(cbuffer8, Eq(buffers[4]));
2676+ EXPECT_THAT(cbuffer1, IsSameBufferAs(buffers[0]));
2677+ EXPECT_THAT(cbuffer2, IsSameBufferAs(buffers[0]));
2678+
2679+ EXPECT_THAT(cbuffer3, IsSameBufferAs(buffers[1]));
2680+
2681+ EXPECT_THAT(cbuffer4, IsSameBufferAs(buffers[2]));
2682+ EXPECT_THAT(cbuffer5, IsSameBufferAs(buffers[2]));
2683+
2684+ EXPECT_THAT(cbuffer6, IsSameBufferAs(buffers[3]));
2685+
2686+ EXPECT_THAT(cbuffer7, IsSameBufferAs(buffers[4]));
2687+ EXPECT_THAT(cbuffer8, IsSameBufferAs(buffers[4]));
2688 }
2689
2690 TEST_F(MultiMonitorArbiter, can_set_a_new_schedule)
2691@@ -252,8 +272,8 @@
2692 arbiter.set_schedule(mt::fake_shared(another_schedule));
2693 auto cbuffer2 = arbiter.compositor_acquire(this);
2694
2695- EXPECT_THAT(cbuffer1, Eq(buffers[3]));
2696- EXPECT_THAT(cbuffer2, Eq(buffers[0]));
2697+ EXPECT_THAT(cbuffer1, IsSameBufferAs(buffers[3]));
2698+ EXPECT_THAT(cbuffer2, IsSameBufferAs(buffers[0]));
2699 }
2700
2701 TEST_F(MultiMonitorArbiter, basic_snapshot_equals_compositor_buffer)
2702@@ -262,7 +282,7 @@
2703
2704 auto cbuffer1 = arbiter.compositor_acquire(this);
2705 auto sbuffer1 = arbiter.snapshot_acquire();
2706- EXPECT_EQ(cbuffer1, sbuffer1);
2707+ EXPECT_THAT(cbuffer1, IsSameBufferAs(sbuffer1));
2708 }
2709
2710 TEST_F(MultiMonitorArbiter, basic_snapshot_equals_latest_compositor_buffer)
2711@@ -278,8 +298,8 @@
2712 cbuffer2 = arbiter.compositor_acquire(&that);
2713
2714 auto sbuffer2 = arbiter.snapshot_acquire();
2715- EXPECT_EQ(cbuffer1, sbuffer1);
2716- EXPECT_EQ(cbuffer2, sbuffer2);
2717+ EXPECT_THAT(cbuffer1, IsSameBufferAs(sbuffer1));
2718+ EXPECT_THAT(cbuffer2, IsSameBufferAs(sbuffer2));
2719 }
2720
2721 TEST_F(MultiMonitorArbiter, snapshot_cycling_doesnt_advance_buffer_for_compositors)
2722@@ -297,8 +317,8 @@
2723 }
2724 auto cbuffer2 = arbiter.compositor_acquire(&that);
2725
2726- EXPECT_THAT(cbuffer1, Eq(cbuffer2));
2727- EXPECT_THAT(snapshot_buffers, Each(cbuffer1));
2728+ EXPECT_THAT(cbuffer1, IsSameBufferAs(cbuffer2));
2729+ EXPECT_THAT(snapshot_buffers, Each(IsSameBufferAs(cbuffer1)));
2730 }
2731
2732 TEST_F(MultiMonitorArbiter, no_buffers_available_throws_on_snapshot)
2733@@ -311,29 +331,48 @@
2734
2735 TEST_F(MultiMonitorArbiter, snapshotting_will_release_buffer_if_it_was_the_last_owner)
2736 {
2737- EXPECT_CALL(mock_map, send_buffer(_)).Times(0);
2738- schedule.set_schedule({buffers[3],buffers[4]});
2739+ auto buffer_released = std::make_shared<bool>(false);
2740+ schedule.set_schedule(
2741+ {
2742+ wrap_with_destruction_notifier(buffers[3], buffer_released),
2743+ buffers[4]
2744+ });
2745 auto cbuffer1 = arbiter.compositor_acquire(this);
2746 auto sbuffer1 = arbiter.snapshot_acquire();
2747 arbiter.compositor_release(cbuffer1);
2748-
2749- Mock::VerifyAndClearExpectations(&mock_map);
2750- EXPECT_CALL(mock_map, send_buffer(sbuffer1->id()));
2751+ cbuffer1.reset();
2752+
2753+ // Acquire a new buffer so first one is no longer onscreen.
2754+ arbiter.compositor_acquire(this);
2755+
2756+ EXPECT_FALSE(*buffer_released);
2757 arbiter.snapshot_release(sbuffer1);
2758+ sbuffer1.reset();
2759+ EXPECT_TRUE(*buffer_released);
2760 }
2761
2762 TEST_F(MultiMonitorArbiter, compositor_can_acquire_a_few_times_and_only_sends_on_the_last_release)
2763 {
2764 int comp_id1{0};
2765 int comp_id2{0};
2766- schedule.set_schedule({buffers[0], buffers[1]});
2767+
2768+ auto buffer_released = std::make_shared<bool>(false);
2769+ schedule.set_schedule(
2770+ {
2771+ wrap_with_destruction_notifier(buffers[0], buffer_released),
2772+ buffers[1]
2773+ });
2774 auto cbuffer1 = arbiter.compositor_acquire(&comp_id1);
2775 auto cbuffer2 = arbiter.compositor_acquire(&comp_id2);
2776- EXPECT_THAT(cbuffer1, Eq(cbuffer2));
2777- EXPECT_CALL(mock_map, send_buffer(buffers[0]->id())).Times(Exactly(1));
2778+ EXPECT_THAT(cbuffer1, IsSameBufferAs(cbuffer2));
2779+
2780 auto cbuffer3 = arbiter.compositor_acquire(&comp_id1);
2781 arbiter.compositor_release(cbuffer2);
2782+ EXPECT_FALSE(*buffer_released);
2783 arbiter.compositor_release(cbuffer1);
2784+ cbuffer1.reset();
2785+ cbuffer2.reset();
2786+ EXPECT_TRUE(*buffer_released);
2787 }
2788
2789 TEST_F(MultiMonitorArbiter, advance_on_fastest_has_same_buffer)
2790@@ -349,29 +388,29 @@
2791
2792 auto cbuffer3 = arbiter.compositor_acquire(&comp_id1); //buffer[1]
2793
2794- EXPECT_THAT(cbuffer1, Eq(cbuffer2));
2795- EXPECT_THAT(cbuffer1, Eq(buffers[0]));
2796- EXPECT_THAT(cbuffer3, Eq(buffers[1]));
2797-}
2798-
2799-TEST_F(MultiMonitorArbiter, compositor_acquire_sends_buffer_back_with_fastest_guarantee)
2800-{
2801- EXPECT_CALL(mock_map, send_buffer(buffers[0]->id()));
2802-
2803- schedule.set_schedule({buffers[0], buffers[1]});
2804-
2805- auto cbuffer = arbiter.compositor_acquire(this);
2806- schedule.set_schedule({buffers[1]});
2807- arbiter.compositor_release(cbuffer);
2808- cbuffer = arbiter.compositor_acquire(this);
2809+ EXPECT_THAT(cbuffer1, IsSameBufferAs(cbuffer2));
2810+ EXPECT_THAT(cbuffer1, IsSameBufferAs(buffers[0]));
2811+ EXPECT_THAT(cbuffer3, IsSameBufferAs(buffers[1]));
2812 }
2813
2814 TEST_F(MultiMonitorArbiter, buffers_are_sent_back)
2815 {
2816- EXPECT_CALL(mock_map, send_buffer(_)).Times(3);
2817+ std::array<std::shared_ptr<bool>, 3> buffer_released = {
2818+ {
2819+ std::make_shared<bool>(false),
2820+ std::make_shared<bool>(false),
2821+ std::make_shared<bool>(false)
2822+ }};
2823 int comp_id1{0};
2824 int comp_id2{0};
2825- schedule.set_schedule({buffers[0], buffers[1], buffers[2], buffers[3]});
2826+
2827+ schedule.set_schedule(
2828+ {
2829+ wrap_with_destruction_notifier(buffers[0], buffer_released[0]),
2830+ wrap_with_destruction_notifier(buffers[1], buffer_released[1]),
2831+ wrap_with_destruction_notifier(buffers[2], buffer_released[2]),
2832+ buffers[3]
2833+ });
2834
2835 auto b1 = arbiter.compositor_acquire(&comp_id1);
2836 arbiter.compositor_release(b1);
2837@@ -386,7 +425,14 @@
2838 auto b6 = arbiter.compositor_acquire(&comp_id1);
2839 arbiter.compositor_release(b6);
2840
2841- Mock::VerifyAndClearExpectations(&mock_map);
2842+ b1.reset();
2843+ b2.reset();
2844+ b3.reset();
2845+ b4.reset();
2846+ b5.reset();
2847+ b6.reset();
2848+
2849+ EXPECT_THAT(buffer_released, Each(Pointee(true)));
2850 }
2851
2852 TEST_F(MultiMonitorArbiter, can_check_if_buffers_are_ready)
2853@@ -442,17 +488,28 @@
2854 TEST_F(MultiMonitorArbiter, will_release_buffer_in_nbuffers_2_overlay_scenario)
2855 {
2856 int comp_id1{0};
2857- schedule.set_schedule({buffers[0], buffers[1], buffers[0], buffers[1]});
2858+ auto buffer_released = std::make_shared<bool>(false);
2859+ auto notifying_buffer = wrap_with_destruction_notifier(buffers[0], buffer_released);
2860+ schedule.set_schedule(
2861+ {
2862+ notifying_buffer,
2863+ buffers[1],
2864+ buffers[0], // We only want to be notified when the first submission is released
2865+ buffers[1]
2866+ });
2867+ notifying_buffer.reset();
2868
2869- EXPECT_CALL(mock_map, send_buffer(buffers[0]->id()));
2870 auto b1 = arbiter.compositor_acquire(&comp_id1);
2871 auto b2 = arbiter.compositor_acquire(&comp_id1);
2872- EXPECT_THAT(b1, Eq(buffers[0]));
2873- EXPECT_THAT(b2, Eq(buffers[1]));
2874+ EXPECT_THAT(b1, IsSameBufferAs(buffers[0]));
2875+ EXPECT_THAT(b2, IsSameBufferAs(buffers[1]));
2876 arbiter.compositor_release(b1);
2877 arbiter.compositor_release(b2);
2878- Mock::VerifyAndClearExpectations(&mock_map);
2879-}
2880+ b1.reset();
2881+ b2.reset();
2882+
2883+ EXPECT_TRUE(*buffer_released);
2884+}
2885
2886 TEST_F(MultiMonitorArbiter, will_release_buffer_in_nbuffers_2_starvation_scenario)
2887 {
2888@@ -471,10 +528,10 @@
2889 arbiter.compositor_release(b2);
2890 arbiter.compositor_release(b4);
2891
2892- EXPECT_THAT(b1, Eq(buffers[0]));
2893- EXPECT_THAT(b2, Eq(buffers[1]));
2894- EXPECT_THAT(b3, Eq(buffers[1]));
2895- EXPECT_THAT(b4, Eq(buffers[0]));
2896+ EXPECT_THAT(b1, IsSameBufferAs(buffers[0]));
2897+ EXPECT_THAT(b2, IsSameBufferAs(buffers[1]));
2898+ EXPECT_THAT(b3, IsSameBufferAs(buffers[1]));
2899+ EXPECT_THAT(b4, IsSameBufferAs(buffers[0]));
2900
2901 }
2902
2903@@ -482,13 +539,12 @@
2904 {
2905 int comp_id1{0};
2906 int comp_id2{0};
2907+
2908 schedule.set_schedule({
2909 buffers[0], buffers[1], buffers[2],
2910 buffers[0], buffers[1], buffers[2],
2911 buffers[0], buffers[1], buffers[2]});
2912
2913- EXPECT_CALL(mock_map, send_buffer(buffers[0]->id()));
2914-
2915 auto b1 = arbiter.compositor_acquire(&comp_id1);
2916 auto b2 = arbiter.compositor_acquire(&comp_id2);
2917 arbiter.compositor_release(b1); //send nothing
2918@@ -502,13 +558,12 @@
2919 auto b5 = arbiter.compositor_acquire(&comp_id1);
2920 arbiter.compositor_release(b5); //send nothing
2921
2922- EXPECT_THAT(b1, Eq(buffers[0]));
2923- EXPECT_THAT(b2, Eq(buffers[0]));
2924- EXPECT_THAT(b3, Eq(buffers[1]));
2925- EXPECT_THAT(b4, Eq(buffers[1]));
2926- EXPECT_THAT(b5, Eq(buffers[2]));
2927- Mock::VerifyAndClearExpectations(&mock_map);
2928-}
2929+ EXPECT_THAT(b1, IsSameBufferAs(buffers[0]));
2930+ EXPECT_THAT(b2, IsSameBufferAs(buffers[0]));
2931+ EXPECT_THAT(b3, IsSameBufferAs(buffers[1]));
2932+ EXPECT_THAT(b4, IsSameBufferAs(buffers[1]));
2933+ EXPECT_THAT(b5, IsSameBufferAs(buffers[2]));
2934+}
2935
2936 TEST_F(MultiMonitorArbiter, can_advance_buffer_manually)
2937 {
2938@@ -521,11 +576,11 @@
2939
2940 auto b1 = arbiter.compositor_acquire(&comp_id1);
2941 auto b2 = arbiter.compositor_acquire(&comp_id2);
2942- EXPECT_THAT(b1->id(), Eq(buffers[1]->id()));
2943- EXPECT_THAT(b2->id(), Eq(buffers[1]->id()));
2944+ EXPECT_THAT(b1, IsSameBufferAs(buffers[1]));
2945+ EXPECT_THAT(b2, IsSameBufferAs(buffers[1]));
2946
2947 auto b3 = arbiter.compositor_acquire(&comp_id1);
2948- EXPECT_THAT(b3->id(), Eq(buffers[2]->id()));
2949+ EXPECT_THAT(b3, IsSameBufferAs(buffers[2]));
2950 }
2951
2952 TEST_F(MultiMonitorArbiter, checks_if_buffer_is_valid_after_clean_onscreen_buffer)
2953@@ -547,8 +602,12 @@
2954
2955 TEST_F(MultiMonitorArbiter, releases_buffer_on_destruction)
2956 {
2957- mc::MultiMonitorArbiter arbiter{mt::fake_shared(mock_map), mt::fake_shared(schedule)};
2958- EXPECT_CALL(mock_map, send_buffer(buffers[0]->id()));
2959- schedule.set_schedule({buffers[0]});
2960- arbiter.advance_schedule();
2961+ auto buffer_released = std::make_shared<bool>(false);
2962+ schedule.set_schedule({wrap_with_destruction_notifier(buffers[0], buffer_released)});
2963+
2964+ {
2965+ mc::MultiMonitorArbiter arbiter{mt::fake_shared(schedule)};
2966+ arbiter.advance_schedule();
2967+ }
2968+ EXPECT_TRUE(*buffer_released);
2969 }
2970
2971=== modified file 'tests/unit-tests/compositor/test_stream.cpp'
2972--- tests/unit-tests/compositor/test_stream.cpp 2017-05-08 03:04:26 +0000
2973+++ tests/unit-tests/compositor/test_stream.cpp 2017-07-18 03:23:56 +0000
2974@@ -22,7 +22,6 @@
2975 #include "mir/test/fake_shared.h"
2976 #include "src/server/compositor/stream.h"
2977 #include "mir/scene/null_surface_observer.h"
2978-#include "mir/frontend/client_buffers.h"
2979
2980 #include <gmock/gmock.h>
2981 #include <gtest/gtest.h>
2982@@ -41,45 +40,6 @@
2983 MOCK_METHOD2(frame_posted, void(int, geom::Size const&));
2984 };
2985
2986-struct StubBufferMap : mf::ClientBuffers
2987-{
2988- StubBufferMap(mf::EventSink& sink, std::vector<std::shared_ptr<mg::Buffer>>& buffers) :
2989- buffers{buffers},
2990- sink{sink}
2991- {
2992- }
2993- mg::BufferID add_buffer(std::shared_ptr<mg::Buffer> const&)
2994- {
2995- return mg::BufferID{};
2996- }
2997- void remove_buffer(mg::BufferID)
2998- {
2999- }
3000- void with_buffer(mg::BufferID, std::function<void(mg::Buffer&)> const&)
3001- {
3002- }
3003- void receive_buffer(mg::BufferID)
3004- {
3005- }
3006- void send_buffer(mg::BufferID id)
3007- {
3008- sink.send_buffer(mf::BufferStreamId{33}, *get(id), mg::BufferIpcMsgType::update_msg);
3009- }
3010- std::shared_ptr<mg::Buffer> get(mg::BufferID id) const
3011- {
3012- auto it = std::find_if(buffers.begin(), buffers.end(),
3013- [id](std::shared_ptr<mg::Buffer> const& b)
3014- {
3015- return b->id() == id;
3016- });
3017- if (it == buffers.end())
3018- throw std::logic_error("cannot find buffer in map");
3019- return *it;
3020- }
3021- std::vector<std::shared_ptr<mg::Buffer>>& buffers;
3022- mf::EventSink& sink;
3023-};
3024-
3025 struct Stream : Test
3026 {
3027 Stream() :
3028@@ -94,16 +54,14 @@
3029
3030 geom::Size initial_size{44,2};
3031 std::vector<std::shared_ptr<mg::Buffer>> buffers;
3032- NiceMock<mtd::MockEventSink> mock_sink;
3033 MirPixelFormat construction_format{mir_pixel_format_rgb_565};
3034 mc::Stream stream{
3035- std::make_unique<StubBufferMap>(mock_sink, buffers), initial_size, construction_format};
3036+ initial_size, construction_format};
3037 };
3038 }
3039
3040 TEST_F(Stream, transitions_from_queuing_to_framedropping)
3041 {
3042- EXPECT_CALL(mock_sink, send_buffer(_,_,_)).Times(buffers.size() - 1);
3043 for(auto& buffer : buffers)
3044 stream.submit_buffer(buffer);
3045 stream.allow_framedropping(true);
3046@@ -111,25 +69,37 @@
3047 std::vector<std::shared_ptr<mg::Buffer>> cbuffers;
3048 while(stream.buffers_ready_for_compositor(this))
3049 cbuffers.push_back(stream.lock_compositor_buffer(this));
3050+ // Transition to framedropping should have dropped all queued buffers but the last...
3051 ASSERT_THAT(cbuffers, SizeIs(1));
3052 EXPECT_THAT(cbuffers[0]->id(), Eq(buffers.back()->id()));
3053- Mock::VerifyAndClearExpectations(&mock_sink);
3054+
3055+ for (unsigned long i = 0; i < buffers.size() - 1; ++i)
3056+ {
3057+ // ...and so all the previous buffers should no longer have external references
3058+ EXPECT_TRUE(buffers[i].unique());
3059+ }
3060 }
3061
3062 TEST_F(Stream, transitions_from_framedropping_to_queuing)
3063 {
3064 stream.allow_framedropping(true);
3065- Mock::VerifyAndClearExpectations(&mock_sink);
3066
3067- EXPECT_CALL(mock_sink, send_buffer(_,_,_)).Times(buffers.size() - 1);
3068 for(auto& buffer : buffers)
3069 stream.submit_buffer(buffer);
3070
3071+ // Only the last buffer should be owned by the stream...
3072+ EXPECT_THAT(
3073+ std::make_tuple(buffers.data(), buffers.size() - 1),
3074+ Each(Property(&std::shared_ptr<mg::Buffer>::unique, Eq(true))));
3075+
3076 stream.allow_framedropping(false);
3077 for(auto& buffer : buffers)
3078 stream.submit_buffer(buffer);
3079
3080- Mock::VerifyAndClearExpectations(&mock_sink);
3081+ // All buffers should be now owned by the the stream
3082+ EXPECT_THAT(
3083+ buffers,
3084+ Each(Property(&std::shared_ptr<mg::Buffer>::unique, Eq(false))));
3085
3086 std::vector<std::shared_ptr<mg::Buffer>> cbuffers;
3087 while(stream.buffers_ready_for_compositor(this))
3088@@ -180,23 +150,6 @@
3089 stream.submit_buffer(buffers[0]);
3090 }
3091
3092-TEST_F(Stream, wakes_compositor_before_starting_socket_io)
3093-{
3094- auto observer = std::make_shared<MockSurfaceObserver>();
3095-
3096- InSequence seq;
3097- EXPECT_CALL(*observer, frame_posted(_,_)).Times(2);
3098- EXPECT_CALL(mock_sink, send_buffer(_,_,_)).Times(1);
3099-
3100- stream.add_observer(observer);
3101- stream.allow_framedropping(true);
3102- stream.submit_buffer(buffers[0]);
3103- stream.submit_buffer(buffers[1]);
3104- stream.remove_observer(observer);
3105-
3106- Mock::VerifyAndClearExpectations(&mock_sink);
3107-}
3108-
3109 TEST_F(Stream, calls_observers_call_doesnt_hold_lock)
3110 {
3111 auto observer = std::make_shared<MockSurfaceObserver>();
3112@@ -269,9 +222,15 @@
3113 stream.submit_buffer(buffers[1]);
3114 stream.submit_buffer(buffers[2]);
3115
3116- Mock::VerifyAndClearExpectations(&mock_sink);
3117- EXPECT_CALL(mock_sink, send_buffer(_,Ref(*buffers[0]),_));
3118- EXPECT_CALL(mock_sink, send_buffer(_,Ref(*buffers[1]),_));
3119+ // Buffers should be owned by the stream, and our test
3120+ ASSERT_THAT(buffers[0].use_count(), Eq(2));
3121+ ASSERT_THAT(buffers[1].use_count(), Eq(2));
3122+ ASSERT_THAT(buffers[2].use_count(), Eq(2));
3123+
3124 stream.drop_old_buffers();
3125- Mock::VerifyAndClearExpectations(&mock_sink);
3126+
3127+ // Stream should have released ownership of all but the most recent buffer
3128+ EXPECT_THAT(buffers[0].use_count(), Eq(1));
3129+ EXPECT_THAT(buffers[1].use_count(), Eq(1));
3130+ EXPECT_THAT(buffers[2].use_count(), Eq(2));
3131 }
3132
3133=== modified file 'tests/unit-tests/frontend/test_session_mediator.cpp'
3134--- tests/unit-tests/frontend/test_session_mediator.cpp 2017-05-25 08:58:03 +0000
3135+++ tests/unit-tests/frontend/test_session_mediator.cpp 2017-07-18 03:23:56 +0000
3136@@ -32,6 +32,7 @@
3137 #include "mir/graphics/buffer_ipc_message.h"
3138 #include "mir/graphics/platform_operation_message.h"
3139 #include "mir/graphics/buffer_id.h"
3140+#include "mir/graphics/graphic_buffer_allocator.h"
3141 #include "mir/input/cursor_images.h"
3142 #include "mir/graphics/platform_ipc_operations.h"
3143 #include "mir/scene/coordinate_translator.h"
3144@@ -61,6 +62,7 @@
3145 #include "mir/test/doubles/mock_message_sender.h"
3146 #include "mir/test/doubles/mock_input_config_changer.h"
3147 #include "mir/test/doubles/stub_input_device.h"
3148+#include "mir/test/doubles/stub_buffer.h"
3149 #include "mir/test/display_config_matchers.h"
3150 #include "mir/test/input_devices_matcher.h"
3151 #include "mir/test/fake_shared.h"
3152@@ -119,11 +121,6 @@
3153 class StubbedSession : public mtd::StubSession
3154 {
3155 public:
3156- StubbedSession()
3157- {
3158- ON_CALL(*this, destroy_buffer(_))
3159- .WillByDefault(Invoke([this](mg::BufferID){ ++destroy_buffers;}));
3160- }
3161 std::shared_ptr<mf::Surface> get_surface(mf::SurfaceId surface) const override
3162 {
3163 if (mock_surfaces.find(surface) == mock_surfaces.end())
3164@@ -195,27 +192,8 @@
3165 mock_surfaces.erase(surface);
3166 }
3167
3168-
3169- mg::BufferID create_buffer(mg::BufferProperties const&) override
3170- {
3171- buffer_count++;
3172- return mg::BufferID{3};
3173- }
3174-
3175- mg::BufferID create_buffer(geom::Size, MirPixelFormat) override
3176- {
3177- buffer_count++;
3178- return mg::BufferID{3};
3179- }
3180-
3181- mg::BufferID create_buffer(geom::Size, uint32_t, uint32_t) override
3182- {
3183- native_buffer_count++;
3184- return mg::BufferID{3};
3185- }
3186
3187 MOCK_METHOD1(destroy_buffer_stream, void(mf::BufferStreamId));
3188- MOCK_METHOD1(destroy_buffer, void(mg::BufferID));
3189
3190 int num_alloc_requests()
3191 {
3192@@ -258,6 +236,42 @@
3193 }
3194 };
3195
3196+struct RecordingBufferAllocator : public mg::GraphicBufferAllocator
3197+{
3198+ std::shared_ptr<mg::Buffer> alloc_buffer(mg::BufferProperties const& buffer_properties) override
3199+ {
3200+ auto const buf = std::make_shared<mtd::StubBuffer>(buffer_properties);
3201+ allocated_buffers.push_back(buf);
3202+ return buf;
3203+ }
3204+
3205+ std::vector<MirPixelFormat> supported_pixel_formats() override
3206+ {
3207+ return {};
3208+ }
3209+
3210+ std::shared_ptr<mg::Buffer> alloc_buffer(
3211+ geom::Size size, uint32_t /*native_format*/, uint32_t /*native_flags*/) override
3212+ {
3213+ auto const buf = std::make_shared<mtd::StubBuffer>(size);
3214+ allocated_buffers.push_back(buf);
3215+ return buf;
3216+ }
3217+
3218+ std::shared_ptr<mg::Buffer> alloc_software_buffer(
3219+ geom::Size size, MirPixelFormat format) override
3220+ {
3221+ if ((format >= mir_pixel_formats) || format == mir_pixel_format_invalid)
3222+ BOOST_THROW_EXCEPTION((std::runtime_error{"Invalid pixel format"}));
3223+
3224+ auto const buf = std::make_shared<mtd::StubBuffer>(size);
3225+ allocated_buffers.push_back(buf);
3226+ return buf;
3227+ }
3228+
3229+ std::vector<std::weak_ptr<mg::Buffer>> allocated_buffers;
3230+};
3231+
3232 struct SessionMediator : public ::testing::Test
3233 {
3234 SessionMediator()
3235@@ -269,6 +283,7 @@
3236 stub_screencast{std::make_shared<StubScreencast>()},
3237 stubbed_session{std::make_shared<NiceMock<StubbedSession>>()},
3238 null_callback{google::protobuf::NewPermanentCallback(google::protobuf::DoNothing)},
3239+ allocator{std::make_shared<RecordingBufferAllocator>()},
3240 mediator{
3241 shell, mt::fake_shared(mock_ipc_operations), graphics_changer,
3242 surface_pixel_formats, report,
3243@@ -280,7 +295,8 @@
3244 std::make_shared<mtd::NullANRDetector>(),
3245 mir::cookie::Authority::create(),
3246 mt::fake_shared(mock_input_config_changer),
3247- {}}
3248+ {},
3249+ allocator}
3250 {
3251 using namespace ::testing;
3252
3253@@ -310,7 +326,8 @@
3254 std::make_shared<NullCoordinateTranslator>(),
3255 std::make_shared<mtd::NullANRDetector>(),
3256 mir::cookie::Authority::create(),
3257- mt::fake_shared(mock_input_config_changer), std::vector<mir::ExtensionDescription>{});
3258+ mt::fake_shared(mock_input_config_changer), std::vector<mir::ExtensionDescription>{},
3259+ allocator);
3260 }
3261
3262 std::shared_ptr<mf::SessionMediator> create_session_mediator_with_screencast(
3263@@ -325,7 +342,112 @@
3264 std::make_shared<NullCoordinateTranslator>(),
3265 std::make_shared<mtd::NullANRDetector>(),
3266 mir::cookie::Authority::create(),
3267- mt::fake_shared(mock_input_config_changer), std::vector<mir::ExtensionDescription>{});
3268+ mt::fake_shared(mock_input_config_changer), std::vector<mir::ExtensionDescription>{},
3269+ allocator);
3270+ }
3271+
3272+ std::shared_ptr<mf::SessionMediator> create_session_mediator_with_event_sink(
3273+ std::shared_ptr<mf::EventSink> const& sink)
3274+ {
3275+ class WrappingEventSink : public mf::EventSink
3276+ {
3277+ public:
3278+ WrappingEventSink(std::shared_ptr<mf::EventSink> const& wrapped)
3279+ : wrapped{wrapped}
3280+ {
3281+ }
3282+
3283+ void handle_event(MirEvent const &e) override
3284+ {
3285+ wrapped->handle_event(e);
3286+ }
3287+
3288+ void handle_lifecycle_event(MirLifecycleState state) override
3289+ {
3290+ wrapped->handle_lifecycle_event(state);
3291+ }
3292+
3293+ void handle_display_config_change(
3294+ mg::DisplayConfiguration const& config) override
3295+ {
3296+ wrapped->handle_display_config_change(config);
3297+ }
3298+
3299+ void send_ping(int32_t serial) override
3300+ {
3301+ wrapped->send_ping(serial);
3302+ }
3303+
3304+ void handle_input_config_change(MirInputConfig const& config) override
3305+ {
3306+ wrapped->handle_input_config_change(config);
3307+ }
3308+
3309+ void handle_error(mir::ClientVisibleError const& error) override
3310+ {
3311+ wrapped->handle_error(error);
3312+ }
3313+
3314+ void send_buffer(
3315+ mf::BufferStreamId id,
3316+ mg::Buffer& buffer,
3317+ mg::BufferIpcMsgType type) override
3318+ {
3319+ wrapped->send_buffer(id, buffer, type);
3320+ }
3321+
3322+ void add_buffer(mg::Buffer& buffer) override
3323+ {
3324+ wrapped->add_buffer(buffer);
3325+ }
3326+
3327+ void error_buffer(
3328+ geom::Size req_size,
3329+ MirPixelFormat req_format,
3330+ std::string const &error_msg) override
3331+ {
3332+ wrapped->error_buffer(req_size, req_format, error_msg);
3333+ }
3334+
3335+ void update_buffer(mg::Buffer &buffer) override
3336+ {
3337+ wrapped->update_buffer(buffer);
3338+ }
3339+
3340+ private:
3341+ std::shared_ptr<mf::EventSink> const wrapped;
3342+ };
3343+
3344+ class EventSinkFactory : public mf::EventSinkFactory
3345+ {
3346+ public:
3347+ EventSinkFactory(std::shared_ptr<mf::EventSink> const& sink)
3348+ : the_sink{sink}
3349+ {
3350+ }
3351+
3352+ std::unique_ptr<mf::EventSink> create_sink(
3353+ std::shared_ptr<mf::MessageSender> const&) override
3354+ {
3355+ return std::make_unique<WrappingEventSink>(the_sink);
3356+ }
3357+
3358+ private:
3359+ std::shared_ptr<mf::EventSink> const the_sink;
3360+ };
3361+
3362+ return std::make_shared<mf::SessionMediator>(
3363+ shell, mt::fake_shared(mock_ipc_operations), graphics_changer,
3364+ surface_pixel_formats, report,
3365+ std::make_shared<EventSinkFactory>(sink),
3366+ std::make_shared<mtd::NullMessageSender>(),
3367+ resource_cache, stub_screencast, &connector, nullptr,
3368+ std::make_shared<NullCoordinateTranslator>(),
3369+ std::make_shared<mtd::NullANRDetector>(),
3370+ mir::cookie::Authority::create(),
3371+ mt::fake_shared(mock_input_config_changer),
3372+ std::vector<mir::ExtensionDescription>{},
3373+ allocator);
3374 }
3375
3376 MockConnector connector;
3377@@ -339,6 +461,7 @@
3378 std::shared_ptr<StubScreencast> const stub_screencast;
3379 std::shared_ptr<NiceMock<StubbedSession>> const stubbed_session;
3380 std::unique_ptr<google::protobuf::Closure> null_callback;
3381+ std::shared_ptr<RecordingBufferAllocator> const allocator;
3382 mf::SessionMediator mediator;
3383
3384 mp::ConnectParameters connect_parameters;
3385@@ -383,7 +506,8 @@
3386 std::make_shared<NullCoordinateTranslator>(),
3387 std::make_shared<mtd::NullANRDetector>(),
3388 mir::cookie::Authority::create(),
3389- mt::fake_shared(mock_input_config_changer), {}};
3390+ mt::fake_shared(mock_input_config_changer), {},
3391+ allocator};
3392
3393 EXPECT_THAT(connects_handled_count, Eq(0));
3394
3395@@ -413,21 +537,6 @@
3396 }, std::logic_error);
3397 }
3398
3399-TEST_F(SessionMediator, calling_methods_after_connect_works)
3400-{
3401- mediator.connect(&connect_parameters, &connection, null_callback.get());
3402-
3403- EXPECT_NO_THROW({
3404- mediator.create_surface(&surface_parameters, &surface_response, null_callback.get());
3405- *buffer_request.mutable_buffer() = surface_response.buffer_stream().buffer();
3406- buffer_request.mutable_id()->set_value(surface_response.id().value());
3407- mediator.submit_buffer(&buffer_request, nullptr, null_callback.get());
3408- mediator.release_surface(&surface_id_request, nullptr, null_callback.get());
3409- });
3410-
3411- mediator.disconnect(nullptr, nullptr, null_callback.get());
3412-}
3413-
3414 TEST_F(SessionMediator, calling_methods_after_disconnect_throws)
3415 {
3416 mediator.connect(&connect_parameters, &connection, null_callback.get());
3417@@ -701,15 +810,20 @@
3418 mediator.modify_surface(&mods, &null, null_callback.get());
3419 }
3420
3421-TEST_F(SessionMediator, allocates_software_buffers_from_the_session)
3422+TEST_F(SessionMediator, allocates_software_buffers)
3423 {
3424 using namespace testing;
3425+
3426+ auto sink = std::make_shared<NiceMock<mtd::MockEventSink>>();
3427+ auto mediator = create_session_mediator_with_event_sink(sink);
3428+
3429+ mediator->connect(&connect_parameters, &connection, null_callback.get());
3430+ mediator->create_surface(&surface_parameters, &surface_response, null_callback.get());
3431+
3432 auto num_requests = 3;
3433 mp::Void null;
3434- mp::BufferStreamId id;
3435- id.set_value(0);
3436 mp::BufferAllocation request;
3437- *request.mutable_id() = id;
3438+ *request.mutable_id() = surface_response.buffer_stream().id();
3439 mg::BufferProperties properties(geom::Size{34, 84}, mir_pixel_format_abgr_8888, mg::BufferUsage::hardware);
3440 for(auto i = 0; i < num_requests; i++)
3441 {
3442@@ -720,58 +834,79 @@
3443 buffer_request->set_buffer_usage((int)properties.usage);
3444 }
3445
3446- mediator.connect(&connect_parameters, &connection, null_callback.get());
3447- mediator.create_surface(&surface_parameters, &surface_response, null_callback.get());
3448
3449- mediator.allocate_buffers(&request, &null, null_callback.get());
3450- EXPECT_THAT(stubbed_session->num_alloc_requests(), Eq(num_requests));
3451+ EXPECT_CALL(*sink, add_buffer(_)).Times(num_requests);
3452+ EXPECT_CALL(*sink, error_buffer(_,_,_)).Times(0);
3453+ mediator->allocate_buffers(&request, &null, null_callback.get());
3454+ EXPECT_THAT(allocator->allocated_buffers.size(), Eq(num_requests));
3455 }
3456
3457-TEST_F(SessionMediator, allocates_native_buffers_from_the_session)
3458+TEST_F(SessionMediator, allocates_native_buffers)
3459 {
3460 using namespace testing;
3461+
3462+ auto sink = std::make_shared<NiceMock<mtd::MockEventSink>>();
3463+ auto mediator = create_session_mediator_with_event_sink(sink);
3464+
3465+ mediator->connect(&connect_parameters, &connection, null_callback.get());
3466+ mediator->create_surface(&surface_parameters, &surface_response, null_callback.get());
3467+
3468 geom::Size const size { 1029, 10302 };
3469 auto native_flags = 24u;
3470 auto native_format = 124u;
3471 mp::Void null;
3472- mp::BufferStreamId id;
3473- id.set_value(0);
3474 mp::BufferAllocation request;
3475- *request.mutable_id() = id;
3476+ *request.mutable_id() = surface_response.buffer_stream().id();
3477 auto buffer_request = request.add_buffer_requests();
3478 buffer_request->set_width(size.width.as_int());
3479 buffer_request->set_height(size.height.as_int());
3480 buffer_request->set_native_format(native_format);
3481 buffer_request->set_flags(native_flags);
3482
3483- mediator.connect(&connect_parameters, &connection, null_callback.get());
3484- mediator.create_surface(&surface_parameters, &surface_response, null_callback.get());
3485-
3486- mediator.allocate_buffers(&request, &null, null_callback.get());
3487- EXPECT_THAT(stubbed_session->native_buffer_count, Eq(1));
3488+ EXPECT_CALL(*sink, add_buffer(_)).Times(1);
3489+ EXPECT_CALL(*sink, error_buffer(_,_,_)).Times(0);
3490+ mediator->allocate_buffers(&request, &null, null_callback.get());
3491+ EXPECT_THAT(allocator->allocated_buffers.size(), Eq(1));
3492 }
3493
3494-TEST_F(SessionMediator, removes_buffer_from_the_session)
3495+TEST_F(SessionMediator, removes_buffer)
3496 {
3497 using namespace testing;
3498 auto num_requests = 3;
3499 mp::Void null;
3500- mp::BufferStreamId id;
3501- id.set_value(0);
3502 mp::BufferRelease request;
3503- *request.mutable_id() = id;
3504- auto buffer_id = 442u;
3505+
3506+ // Allocate some buffers so we can release them later...
3507+ mp::BufferAllocation allocate_request;
3508 for(auto i = 0; i < num_requests; i++)
3509 {
3510- auto buffer_request = request.add_buffers();
3511- buffer_request->set_buffer_id(buffer_id);
3512+ auto allocate = allocate_request.add_buffer_requests();
3513+ allocate->set_buffer_usage(static_cast<int32_t>(mg::BufferUsage::software));
3514+ allocate->set_pixel_format(mir_pixel_format_abgr_8888);
3515+ allocate->set_width(640);
3516+ allocate->set_height(480);
3517 }
3518
3519 mediator.connect(&connect_parameters, &connection, null_callback.get());
3520- mediator.create_surface(&surface_parameters, &surface_response, null_callback.get());
3521-
3522+ mediator.allocate_buffers(&allocate_request, &null, null_callback.get());
3523+
3524+ ASSERT_THAT(allocator->allocated_buffers.size(), Eq(num_requests));
3525+
3526+ // ...Pull out the BufferIDs of the buffers we've allocated...
3527+ for (auto weak_buffer : allocator->allocated_buffers)
3528+ {
3529+ auto buffer = weak_buffer.lock();
3530+ ASSERT_THAT(buffer, NotNull());
3531+
3532+ auto release_buffer = request.add_buffers();
3533+ release_buffer->set_buffer_id(buffer->id().as_value());
3534+ }
3535+
3536+ // ...and now release all those buffers.
3537 mediator.release_buffers(&request, &null, null_callback.get());
3538- EXPECT_THAT(stubbed_session->num_destroy_requests(), Eq(num_requests));
3539+ EXPECT_THAT(
3540+ allocator->allocated_buffers,
3541+ Each(Property(&std::weak_ptr<mg::Buffer>::expired, Eq(true))));
3542 }
3543
3544 TEST_F(SessionMediator, configures_swap_intervals_on_streams)
3545@@ -861,7 +996,8 @@
3546 std::make_shared<NullCoordinateTranslator>(),
3547 std::make_shared<mtd::NullANRDetector>(),
3548 mir::cookie::Authority::create(),
3549- mt::fake_shared(mock_input_config_changer), {}};
3550+ mt::fake_shared(mock_input_config_changer), {},
3551+ allocator};
3552
3553 ON_CALL(*shell, create_surface( _, _, _))
3554 .WillByDefault(
3555@@ -1022,22 +1158,49 @@
3556 TEST_F(SessionMediator, disassociates_buffers_from_stream_before_destroying)
3557 {
3558 mp::BufferRelease release_buffer;
3559+ mp::BufferAllocation allocate_buffer;
3560 mp::Void null;
3561
3562+ // Add a fake BufferStream...
3563 auto stream_id = mf::BufferStreamId{42};
3564- auto buffer_id = mir::graphics::BufferID{42};
3565 auto stream = stubbed_session->create_mock_stream(stream_id);
3566- auto buffer1 = std::make_shared<mtd::StubBuffer>();
3567+
3568+ // ...and allocate a buffer to it
3569+ allocate_buffer.mutable_id()->set_value(42);
3570+ auto buffer_props = allocate_buffer.add_buffer_requests();
3571+ buffer_props->set_buffer_usage(0);
3572+ buffer_props->set_pixel_format(0);
3573+ buffer_props->set_width(230);
3574+ buffer_props->set_height(230);
3575+
3576+ mediator.connect(&connect_parameters, &connection, null_callback.get());
3577+ mediator.allocate_buffers(&allocate_buffer, &null, null_callback.get());
3578+
3579+ ASSERT_THAT(allocator->allocated_buffers.size(), Eq(1));
3580+ auto allocated_buffer = allocator->allocated_buffers.front().lock();
3581+ ASSERT_THAT(allocated_buffer, NotNull());
3582+
3583+ auto const buffer_id = allocated_buffer->id();
3584+
3585+ // Release our share of the buffer ownership.
3586+ allocated_buffer.reset();
3587
3588 auto buffer_item = release_buffer.add_buffers();
3589 buffer_item->set_buffer_id(buffer_id.as_value());
3590 release_buffer.mutable_id()->set_value(stream_id.as_value());
3591
3592- EXPECT_CALL(*stream, disassociate_buffer(buffer_id));
3593- EXPECT_CALL(*stubbed_session, destroy_buffer(buffer_id));
3594+ EXPECT_CALL(*stream, disassociate_buffer(buffer_id))
3595+ .WillOnce(InvokeWithoutArgs(
3596+ [weak_buffer = allocator->allocated_buffers.front()]()
3597+ {
3598+ // The buffer should be live here!
3599+ EXPECT_THAT(weak_buffer.lock(), NotNull());
3600+ }));
3601
3602- mediator.connect(&connect_parameters, &connection, null_callback.get());
3603 mediator.release_buffers(&release_buffer, &null, null_callback.get());
3604+
3605+ // And now we expect the buffer to have been destroyed.
3606+ EXPECT_THAT(allocator->allocated_buffers.front().lock(), IsNull());
3607 }
3608
3609 TEST_F(SessionMediator, releases_buffers_of_unknown_buffer_stream_does_not_throw)
3610@@ -1046,10 +1209,30 @@
3611 mp::BufferRelease release_buffer;
3612 mp::Void null;
3613
3614+ // Add a fake BufferStream...
3615 auto stream_id = mf::BufferStreamId{42};
3616- auto buffer_id = mir::graphics::BufferID{42};
3617 auto stream = stubbed_session->create_mock_stream(stream_id);
3618- auto buffer1 = std::make_shared<mtd::StubBuffer>();
3619+
3620+ // ...and allocate a buffer to it
3621+ mp::BufferAllocation allocate_buffer;
3622+ allocate_buffer.mutable_id()->set_value(42);
3623+ auto buffer_props = allocate_buffer.add_buffer_requests();
3624+ buffer_props->set_buffer_usage(0);
3625+ buffer_props->set_pixel_format(0);
3626+ buffer_props->set_width(230);
3627+ buffer_props->set_height(230);
3628+
3629+ mediator.connect(&connect_parameters, &connection, null_callback.get());
3630+ mediator.allocate_buffers(&allocate_buffer, &null, null_callback.get());
3631+
3632+ ASSERT_THAT(allocator->allocated_buffers.size(), Eq(1));
3633+ auto allocated_buffer = allocator->allocated_buffers.front().lock();
3634+ ASSERT_THAT(allocated_buffer, NotNull());
3635+
3636+ auto const buffer_id = allocated_buffer->id();
3637+
3638+ // Release our share of the buffer ownership.
3639+ allocated_buffer.reset();
3640
3641 auto buffer_item = release_buffer.add_buffers();
3642 buffer_item->set_buffer_id(buffer_id.as_value());
3643@@ -1058,15 +1241,15 @@
3644 stream_to_release.set_value(stream_id.as_value());
3645
3646 EXPECT_CALL(*stubbed_session, destroy_buffer_stream(stream_id));
3647- EXPECT_CALL(*stubbed_session, destroy_buffer(buffer_id));
3648
3649- mediator.connect(&connect_parameters, &connection, null_callback.get());
3650 mediator.release_buffer_stream(&stream_to_release, &null, null_callback.get());
3651 stream.reset();
3652
3653 EXPECT_NO_THROW(
3654 mediator.release_buffers(&release_buffer, &null, null_callback.get());
3655 );
3656+
3657+ EXPECT_TRUE(allocator->allocated_buffers.front().expired());
3658 }
3659
3660 MATCHER_P3(CursorIs, id_value, x_value, y_value, "cursor configuration match")
3661@@ -1165,7 +1348,6 @@
3662 buffer_request->set_height(129);
3663 buffer_request->set_pixel_format(mir_pixel_format_abgr_8888);
3664 buffer_request->set_buffer_usage(mir_buffer_usage_hardware);
3665- int buffer_id = 3;
3666 mf::ScreencastSessionId screencast_id{7};
3667 auto mock_screencast = std::make_shared<NiceMock<mtd::MockScreencast>>();
3668
3669@@ -1181,7 +1363,180 @@
3670 mp::ScreencastRequest screencast_request;
3671
3672 screencast_request.mutable_id()->set_value(screencast_id.as_value());
3673- screencast_request.set_buffer_id(buffer_id);
3674+ screencast_request.set_buffer_id(allocator->allocated_buffers.front().lock()->id().as_value());
3675
3676 mediator->screencast_to_buffer(&screencast_request, &null, null_callback.get());
3677 }
3678+
3679+namespace
3680+{
3681+void add_software_buffer_request(
3682+ mp::BufferAllocation& request,
3683+ int width,
3684+ int height,
3685+ MirPixelFormat format)
3686+{
3687+ auto buffer_request = request.add_buffer_requests();
3688+ buffer_request->set_width(width);
3689+ buffer_request->set_height(height);
3690+ buffer_request->set_pixel_format(format);
3691+ buffer_request->set_buffer_usage(static_cast<int>(mg::BufferUsage::software));
3692+}
3693+
3694+void add_hardware_request(
3695+ mp::BufferAllocation& request,
3696+ int width,
3697+ int height,
3698+ int native_format,
3699+ int flags)
3700+{
3701+ auto buffer_request = request.add_buffer_requests();
3702+
3703+ buffer_request->set_width(width);
3704+ buffer_request->set_height(height);
3705+ buffer_request->set_native_format(native_format);
3706+ buffer_request->set_flags(flags);
3707+}
3708+}
3709+
3710+TEST_F(SessionMediator, invalid_buffer_stream_in_software_buffer_allocation_sends_only_error_buffer)
3711+{
3712+ using namespace testing;
3713+
3714+ auto sink = std::make_shared<NiceMock<mtd::MockEventSink>>();
3715+ auto mediator = create_session_mediator_with_event_sink(sink);
3716+
3717+ mediator->connect(&connect_parameters, &connection, null_callback.get());
3718+
3719+ auto num_requests = 3;
3720+ mp::Void null;
3721+ mp::BufferAllocation request;
3722+ request.mutable_id()->set_value(-1);
3723+ mg::BufferProperties properties(geom::Size{34, 84}, mir_pixel_format_abgr_8888, mg::BufferUsage::software);
3724+ for(auto i = 0; i < num_requests; i++)
3725+ {
3726+ add_software_buffer_request(
3727+ request,
3728+ properties.size.width.as_int(),
3729+ properties.size.height.as_int(),
3730+ properties.format);
3731+ }
3732+
3733+ EXPECT_CALL(*sink, add_buffer(_)).Times(0);
3734+ EXPECT_CALL(*sink, error_buffer(_,_,_)).Times(num_requests);
3735+ mediator->allocate_buffers(&request, &null, null_callback.get());
3736+ EXPECT_THAT(allocator->allocated_buffers.size(), Eq(num_requests));
3737+}
3738+
3739+TEST_F(SessionMediator, invalid_request_sends_error_buffer)
3740+{
3741+ using namespace testing;
3742+
3743+ auto sink = std::make_shared<NiceMock<mtd::MockEventSink>>();
3744+ auto mediator = create_session_mediator_with_event_sink(sink);
3745+
3746+ mediator->connect(&connect_parameters, &connection, null_callback.get());
3747+ mediator->create_surface(&surface_parameters, &surface_response, null_callback.get());
3748+
3749+ mp::Void null;
3750+ mp::BufferAllocation request;
3751+ *request.mutable_id() = surface_response.buffer_stream().id();
3752+
3753+ decltype(request.add_buffer_requests()) buffer_request;
3754+
3755+ // Loop through all possibilities of has_flags, has_native_format,
3756+ // has_buffer_usage, has_pixel_format
3757+ for (int i = 0 ; i < 1<<4; ++i)
3758+ {
3759+ buffer_request = request.add_buffer_requests();
3760+ buffer_request->set_width(1024);
3761+ buffer_request->set_height(768);
3762+
3763+ if (i & 1<<0)
3764+ buffer_request->set_flags(0xfaac);
3765+ if (i & 1<<1)
3766+ buffer_request->set_native_format(0xdeeb);
3767+ if (i & 1<<2)
3768+ buffer_request->set_pixel_format(mir_pixel_format_abgr_8888);
3769+ if (i & 1<<3)
3770+ buffer_request->set_buffer_usage(static_cast<int>(mg::BufferUsage::software));
3771+ }
3772+
3773+ // There are two valid allocations here - one with flags and native_format set,
3774+ // one with pixel_format and buffer_usage set.
3775+ EXPECT_CALL(*sink, add_buffer(_)).Times(2);
3776+
3777+ EXPECT_CALL(*sink, error_buffer(_,_,_)).Times(16 - 2);
3778+ mediator->allocate_buffers(&request, &null, null_callback.get());
3779+ EXPECT_THAT(allocator->allocated_buffers.size(), Eq(2));
3780+}
3781+
3782+TEST_F(SessionMediator, sends_errors_only_for_invalid_buffer_parameters)
3783+{
3784+ using namespace testing;
3785+
3786+ auto sink = std::make_shared<NiceMock<mtd::MockEventSink>>();
3787+ auto mediator = create_session_mediator_with_event_sink(sink);
3788+
3789+ mediator->connect(&connect_parameters, &connection, null_callback.get());
3790+ mediator->create_surface(&surface_parameters, &surface_response, null_callback.get());
3791+
3792+ auto const num_requests = 3;
3793+ mp::Void null;
3794+ mp::BufferAllocation request;
3795+ *request.mutable_id() = surface_response.buffer_stream().id();
3796+ mg::BufferProperties properties(geom::Size{34, 84}, mir_pixel_format_abgr_8888, mg::BufferUsage::software);
3797+ for(auto i = 0; i < num_requests; i++)
3798+ {
3799+ add_software_buffer_request(
3800+ request,
3801+ properties.size.width.as_int(),
3802+ properties.size.height.as_int(),
3803+ properties.format);
3804+ }
3805+
3806+ // Make the 2nd buffer request invalid, leaving the 1st and 3rd valid
3807+ request.mutable_buffer_requests(1)->set_pixel_format(mir_pixel_format_invalid);
3808+
3809+ EXPECT_CALL(*sink, add_buffer(_)).Times(num_requests - 1);
3810+ EXPECT_CALL(*sink, error_buffer(_,_,_)).Times(1);
3811+ mediator->allocate_buffers(&request, &null, null_callback.get());
3812+ EXPECT_THAT(allocator->allocated_buffers.size(), Eq(num_requests - 1));
3813+}
3814+
3815+TEST_F(SessionMediator, invalid_buffer_stream_in_native_buffer_allocation_sends_only_error_buffer)
3816+{
3817+ using namespace testing;
3818+
3819+ auto const num_requests = 3;
3820+
3821+ auto sink = std::make_shared<NiceMock<mtd::MockEventSink>>();
3822+ auto mediator = create_session_mediator_with_event_sink(sink);
3823+
3824+ mediator->connect(&connect_parameters, &connection, null_callback.get());
3825+
3826+ geom::Size const size { 1029, 10302 };
3827+ auto native_flags = 24u;
3828+ auto native_format = 124u;
3829+ mp::Void null;
3830+ mp::BufferAllocation request;
3831+ request.mutable_id()->set_value(42);
3832+
3833+ for (auto i = 0; i < num_requests; ++i)
3834+ {
3835+ add_hardware_request(
3836+ request,
3837+ size.width.as_int(),
3838+ size.height.as_int(),
3839+ native_format,
3840+ native_flags);
3841+ }
3842+
3843+ EXPECT_CALL(*sink, add_buffer(_)).Times(0);
3844+ EXPECT_CALL(*sink, error_buffer(_,_,_)).Times(num_requests);
3845+ mediator->allocate_buffers(&request, &null, null_callback.get());
3846+ // We don't much care if the buffers were allocated and then freed or never allocated
3847+ EXPECT_THAT(
3848+ allocator->allocated_buffers,
3849+ Each(Property(&std::weak_ptr<mg::Buffer>::expired, Eq(true))));
3850+}
3851
3852=== modified file 'tests/unit-tests/scene/test_application_session.cpp'
3853--- tests/unit-tests/scene/test_application_session.cpp 2017-05-25 04:43:29 +0000
3854+++ tests/unit-tests/scene/test_application_session.cpp 2017-07-18 03:23:56 +0000
3855@@ -63,17 +63,10 @@
3856
3857 struct MockBufferStreamFactory : public ms::BufferStreamFactory
3858 {
3859- MockBufferStreamFactory()
3860- {
3861- ON_CALL(*this, create_buffer_map(testing::_))
3862- .WillByDefault(testing::Return(std::make_shared<mtd::StubClientBuffers>()));
3863- }
3864+ MOCK_METHOD2(create_buffer_stream, std::shared_ptr<mc::BufferStream>(
3865+ mf::BufferStreamId, mg::BufferProperties const&));
3866 MOCK_METHOD3(create_buffer_stream, std::shared_ptr<mc::BufferStream>(
3867- mf::BufferStreamId, std::shared_ptr<mf::ClientBuffers> const&, mg::BufferProperties const&));
3868- MOCK_METHOD4(create_buffer_stream, std::shared_ptr<mc::BufferStream>(
3869- mf::BufferStreamId, std::shared_ptr<mf::ClientBuffers> const&, int, mg::BufferProperties const&));
3870- MOCK_METHOD1(create_buffer_map, std::shared_ptr<mf::ClientBuffers>(
3871- std::shared_ptr<mf::BufferSink> const&));
3872+ mf::BufferStreamId, int, mg::BufferProperties const&));
3873 };
3874
3875
3876@@ -488,7 +481,7 @@
3877 NiceMock<MockSurfaceFactory> surface_factory;
3878 MockBufferStreamFactory mock_buffer_stream_factory;
3879 std::shared_ptr<mc::BufferStream> const mock_stream = std::make_shared<mtd::MockBufferStream>();
3880- ON_CALL(mock_buffer_stream_factory, create_buffer_stream(_,_,_)).WillByDefault(Return(mock_stream));
3881+ ON_CALL(mock_buffer_stream_factory, create_buffer_stream(_,_)).WillByDefault(Return(mock_stream));
3882 ON_CALL(surface_factory, create_surface(_,_)).WillByDefault(Return(mock_surface));
3883 NiceMock<mtd::MockSurfaceStack> surface_stack;
3884
3885@@ -588,7 +581,7 @@
3886 std::make_shared<mtd::StubBufferStream>(),
3887 std::make_shared<mtd::StubBufferStream>()
3888 }};
3889- EXPECT_CALL(mock_bufferstream_factory, create_buffer_stream(_,_,_))
3890+ EXPECT_CALL(mock_bufferstream_factory, create_buffer_stream(_,_))
3891 .WillOnce(Return(streams[0]))
3892 .WillOnce(Return(streams[1]))
3893 .WillOnce(Return(streams[2]));
3894@@ -630,7 +623,7 @@
3895
3896 mg::BufferProperties properties(buffer_size, mir_pixel_format_argb_8888, mg::BufferUsage::software);
3897
3898- EXPECT_CALL(factory, create_buffer_stream(_,_,properties)).Times(1)
3899+ EXPECT_CALL(factory, create_buffer_stream(_,properties)).Times(1)
3900 .WillOnce(Return(mt::fake_shared(stream)));
3901
3902 auto session = make_application_session_with_buffer_stream_factory(mt::fake_shared(factory));
3903@@ -658,7 +651,7 @@
3904
3905 EXPECT_CALL(stream, allow_framedropping(true))
3906 .Times(0);
3907- EXPECT_CALL(factory, create_buffer_stream(_,_,properties)).Times(1)
3908+ EXPECT_CALL(factory, create_buffer_stream(_,properties)).Times(1)
3909 .WillOnce(Return(mt::fake_shared(stream)));
3910
3911 auto session = make_application_session_with_buffer_stream_factory(mt::fake_shared(factory));
3912
3913=== modified file 'tests/unit-tests/scene/test_surface_stack.cpp'
3914--- tests/unit-tests/scene/test_surface_stack.cpp 2017-05-08 03:04:26 +0000
3915+++ tests/unit-tests/scene/test_surface_stack.cpp 2017-07-18 03:23:56 +0000
3916@@ -289,17 +289,7 @@
3917 ms::SurfaceStack stack{report};
3918 stack.register_compositor(this);
3919
3920- struct StubBuffers : mtd::StubClientBuffers
3921- {
3922- std::shared_ptr<mg::Buffer> get(mg::BufferID) const override
3923- {
3924- return buffer;
3925- }
3926- std::shared_ptr<mg::Buffer> buffer {std::make_shared<mtd::StubBuffer>()};
3927- };
3928-
3929- auto buffers = std::make_shared<StubBuffers>();
3930- auto stream = std::make_shared<mc::Stream>(buffers, geom::Size{ 1, 1 }, mir_pixel_format_abgr_8888);
3931+ auto stream = std::make_shared<mc::Stream>(geom::Size{ 1, 1 }, mir_pixel_format_abgr_8888);
3932
3933 auto surface = std::make_shared<ms::BasicSurface>(
3934 std::string("stub"),

Subscribers

People subscribed via source and target branches