Mir

Merge lp:~raof/mir/further-buffer-plumbing-cleanup into lp:mir

Proposed by Chris Halse Rogers on 2017-07-07
Status: Superseded
Proposed branch: lp:~raof/mir/further-buffer-plumbing-cleanup
Merge into: lp:mir
Diff against target: 4309 lines (+993/-1595)
52 files modified
examples/render_surfaces.cpp (+1/-3)
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/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/server/compositor/CMakeLists.txt (+0/-2)
src/server/compositor/buffer_acquisition.h (+17/-2)
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/-22)
src/server/compositor/dropping_schedule.h (+1/-5)
src/server/compositor/multi_monitor_arbiter.cpp (+11/-70)
src/server/compositor/multi_monitor_arbiter.h (+1/-18)
src/server/compositor/queueing_schedule.cpp (+0/-7)
src/server/compositor/queueing_schedule.h (+0/-2)
src/server/compositor/schedule.h (+0/-3)
src/server/compositor/stream.cpp (+9/-39)
src/server/compositor/stream.h (+1/-2)
src/server/compositor/temporary_buffers.cpp (+0/-81)
src/server/compositor/temporary_buffers.h (+0/-74)
src/server/frontend/default_ipc_factory.cpp (+66/-2)
src/server/frontend/default_ipc_factory.h (+4/-0)
src/server/frontend/session_mediator.cpp (+117/-33)
src/server/frontend/session_mediator.h (+10/-2)
src/server/scene/application_session.cpp (+1/-53)
src/server/scene/application_session.h (+0/-7)
src/server/shell/window_management_info.cpp (+13/-26)
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 (+51/-16)
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_framework/stub_session.cpp (+0/-25)
tests/unit-tests/compositor/CMakeLists.txt (+0/-2)
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 (+250/-183)
tests/unit-tests/compositor/test_queueing_schedule.cpp (+0/-19)
tests/unit-tests/compositor/test_stream.cpp (+27/-68)
tests/unit-tests/compositor/test_temporary_buffers.cpp (+0/-143)
tests/unit-tests/frontend/test_session_mediator.cpp (+200/-69)
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/further-buffer-plumbing-cleanup
Reviewer Review Type Date Requested Status
Mir development team 2017-07-07 Pending
Review via email: mp+326986@code.launchpad.net

Commit message

Remove even more manual reference counting of mg::Buffer-s.

To post a comment you must log in.
4217. By Chris Halse Rogers on 2017-07-10

Fix potential deadlock in buffer-release IPC thread Executor.

It's not clear to me how this could be deadlocking in practise, but it's definitely a
possible deadlock. Let's see if that fixes CI!

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

Merge prerequisite

4222. By Chris Halse Rogers on 2017-08-08

Merge prereq, fix CI

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

Subscribers

People subscribed via source and target branches