Mir

Merge lp:~vanvugt/mir/switch into lp:~mir-team/mir/trunk

Proposed by Daniel van Vugt
Status: Superseded
Proposed branch: lp:~vanvugt/mir/switch
Merge into: lp:~mir-team/mir/trunk
Diff against target: 5327 lines (+1319/-3186)
55 files modified
debian/control (+2/-2)
debian/libmirserver1.install (+1/-1)
examples/buffer_render_target.cpp (+8/-0)
examples/buffer_render_target.h (+1/-0)
include/server/mir/compositor/back_buffer_strategy.h (+0/-47)
include/server/mir/compositor/buffer_allocation_strategy.h (+0/-63)
include/server/mir/compositor/buffer_stream_factory.h (+6/-6)
include/server/mir/compositor/buffer_stream_surfaces.h (+0/-1)
include/server/mir/compositor/buffer_swapper.h (+0/-131)
include/server/mir/compositor/buffer_swapper_exceptions.h (+0/-42)
include/server/mir/compositor/buffer_swapper_multi.h (+0/-66)
include/server/mir/compositor/buffer_swapper_spin.h (+0/-73)
include/server/mir/compositor/multi_acquisition_back_buffer_strategy.h (+0/-66)
include/server/mir/compositor/swapper_factory.h (+0/-55)
include/server/mir/default_server_configuration.h (+0/-2)
include/test/mir_test_doubles/mock_buffer_bundle.h (+2/-0)
include/test/mir_test_doubles/mock_swapper.h (+0/-66)
include/test/mir_test_doubles/mock_swapper_factory.h (+0/-47)
src/server/CMakeLists.txt (+1/-1)
src/server/compositor/CMakeLists.txt (+0/-5)
src/server/compositor/buffer_bundle.h (+2/-0)
src/server/compositor/buffer_stream_factory.cpp (+5/-5)
src/server/compositor/buffer_stream_surfaces.cpp (+4/-7)
src/server/compositor/buffer_swapper_multi.cpp (+0/-174)
src/server/compositor/buffer_swapper_spin.cpp (+0/-114)
src/server/compositor/multi_acquisition_back_buffer_strategy.cpp (+0/-119)
src/server/compositor/rw_lock.cpp (+0/-71)
src/server/compositor/rw_lock.h (+0/-88)
src/server/compositor/swapper_factory.cpp (+0/-118)
src/server/compositor/switching_bundle.cpp (+356/-51)
src/server/compositor/switching_bundle.h (+55/-11)
src/server/compositor/temporary_buffers.cpp (+16/-7)
src/server/compositor/temporary_buffers.h (+13/-2)
src/server/default_server_configuration.cpp (+1/-14)
tests/integration-tests/compositor/CMakeLists.txt (+0/-1)
tests/integration-tests/compositor/test_buffer_stream.cpp (+132/-130)
tests/integration-tests/compositor/test_stress_buffer_swapper.cpp (+0/-308)
tests/integration-tests/compositor/test_swapping_swappers.cpp (+3/-6)
tests/integration-tests/graphics/android/test_buffer_integration.cpp (+5/-6)
tests/integration-tests/graphics/android/test_internal_client.cpp (+1/-4)
tests/integration-tests/shell/test_session.cpp (+1/-0)
tests/integration-tests/shell/test_session_manager.cpp (+0/-1)
tests/integration-tests/test_surfaceloop.cpp (+8/-39)
tests/unit-tests/compositor/CMakeLists.txt (+0/-6)
tests/unit-tests/compositor/test_buffer_stream.cpp (+14/-2)
tests/unit-tests/compositor/test_buffer_swapper.cpp (+0/-156)
tests/unit-tests/compositor/test_buffer_swapper_double.cpp (+0/-207)
tests/unit-tests/compositor/test_buffer_swapper_spin_triple.cpp (+0/-213)
tests/unit-tests/compositor/test_buffer_swapper_triple.cpp (+0/-125)
tests/unit-tests/compositor/test_rw_lock.cpp (+0/-173)
tests/unit-tests/compositor/test_swapper_factory.cpp (+0/-221)
tests/unit-tests/compositor/test_switching_bundle.cpp (+671/-111)
tests/unit-tests/compositor/test_temporary_buffers.cpp (+9/-21)
tests/unit-tests/graphics/android/test_internal_client_interpreter.cpp (+0/-1)
tests/unit-tests/surfaces/test_surface_stack.cpp (+2/-0)
To merge this branch: bzr merge lp:~vanvugt/mir/switch
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Alexandros Frantzis Pending
Review via email: mp+178527@code.launchpad.net

This proposal supersedes a proposal from 2013-08-02.

This proposal has been superseded by a proposal from 2013-08-07.

Commit message

Simplify and generalize buffer swapping to support arbitrary numbers of:
  - buffers
  - compositors
  - clients

This is a unified N-buffers algorithm which supports any positive number of
buffers, as well as dynamically switching between synchronous and
asynchronous behaviour. So it does everything the existing code does and
more.

The key requirement is to support an arbitrary number of (different)
simultaneous compositor acquisitions, as is needed for bypass support
(coming soon). This then leads to the requirement that a compositor and a
snapshot buffer should be acquired differently. Because a snapshot should
never consume frames, only observe them. On the other hand, a compositior
acquire must consume a frame (if available) so as to guarantee correct
ordering when more than one are acquired simultaneously in bypass mode.

Also fixes LP: #1199717 and is half the fix for LP: #1199450.

Description of the change

Advantages over the existing buffer swapping logic:

  - Completely generalized to support N-buffering, with N > 0.
  - Compositor acquisitions are guaranteed to consume frames (if available),
    even with multiple acquired (required for bypass).
  - Snapshots never consume/steal compositor frames. I suspect this could
    happen in the old code, but at least it's now guaranteed not to.
  - Frame ordering is easier to follow and guarantee as buffers are kept in
    a single ring.
  - The code is much smaller, and easier to fully absorb for new developers,
    than the thousands of lines it replaces.
  - Simpler logic provides clearer guarantees, and fewer exceptions are
    possible.
  - Short term: It works with bypass, today. Unblocking that task.
  - Long term: Much easier to maintain a smaller code base (providing there's
    adequate test coverage).
  - Also fixes LP: #1199717 and is half the fix for LP: #1199450.

Disadvantages:

  - Newer code is less mature by definition, so always carries risk.
  - More concentrated code is more sensitive to programming mistakes. Though
    that's only a problem if tests are lacking.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote : Posted in a previous version of this proposal

Not a thorough review yet... some problems I noticed while trying the branch out (I also cherrypicked the changes from multimonitor-examples MP to be able to easily try out multimonitor support):

1. render_surfaces is rendering in a small part of the output (instead of taking up the whole screen)
2. mir_demo_client_accelerated seems a bit choppy vs when running under lp:mir
3. Multimonitor support (non-cloned) is not working. I get a "compositor release out of order" when a surface is displayed on two outputs. It seems that this MP changes/removes some of the mechanism needed for MM support without providing an alternative.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Thanks for the quick response Alexandros. All fixed!

Unfortunately I had to drop the original fix/workaround for bug 1199450. It was a too hacky for my liking anyway. An alternative is proposed in lp:~vanvugt/mir/fix-1199450.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

Failure looks like intrastructure - restarting

Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

63 + GLint old_viewport[4];
...
50 + glViewport(old_viewport[0], old_viewport[1],
51 + old_viewport[2], old_viewport[3]);

Maybe I'm missing something, but why use a GLint array and "magic number" indexes?

Oh, I see - glGetIntegerv(GLenum pname, GLint * params) - that's an inconsistent API.

I guess if this is all it is used for it's OK.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote : Posted in a previous version of this proposal

This version doesn't crash with multiple monitors anymore. However, there are still some issues with multiple monitors, and in particular when a surface is visible on more than one (non-cloned) outputs. Because of the removal of MultiAcquisitionBackBufferStrategy (which significantly improved, but didn't completely cure the problem), it's much more likely that the compositor for an ouput will miss a frame (because it was consumed by the compositor of another output) and use the next available one. Depending on the relative timings of the vsyncs of the outputs, this causes some stuttering and increased frame rates for applications that continously update, but may lead to serious output inconsistencies for apps that update occasionally.

Note that this is not needed for XMir (and the system compositor in general?), since they deal with fullscreen surfaces only, so it may be OK to postpone solving this for a little while. However, it is an important issue and we should work to find an acceptable solution. As discussed in other occasions, it could be the case that there is no perfect solution and we will just have to find a compromise that minimizes artifacts and keeps frame rates sane.

1961 + BOOST_THROW_EXCEPTION(std::logic_error(
1962 + "compositor_acquire would block; probably too many clients."));

This concerns me. The swapper/bundle should never get into this situation. Previously we guaranteed this by blocking the client if it was about to get a buffer that would lead to the compositor not having any buffers. Can't we do the same in the new mechanism?

review: Needs Information
Revision history for this message
Alexandros Frantzis (afrantzis) wrote : Posted in a previous version of this proposal

A possible way forward is to keep MultiAcquisitionBackBufferStrategy, until we find a better solution, but only for normal buffer bundles. Bypassing buffer bundles can use a different, trivial back buffer strategy.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Alexandros,

I did expect some multi-monitor problems, and certainly expected the high-framerate/stutter issue. I believe we already agreed to discuss this problem starting today... I have one workaround in mind that would work, but it's not elegant: Just don't give out new compositor buffers any more frequently than about 10ms. I was hoping our discussions might lead to a more elegant solution though.

Bypass requires that successive compositor acquisitions get different buffers. So MultiAcquisitionBackBufferStrategy won't work there. I suggest either the timing approach in the short term, or we discuss how to change the API to compositor_acquire so that it is more multi-monitor friendly, and the reuse rules more explicit.

P.S. Has sufficient multi-monitor support landed in trunk so that I can test it myself?

As for:
  "compositor_acquire would block; probably too many clients."
It's guaranteed to not happen in the current Mir logic, so not a huge issue. I did think the same about guaranteeing it never happens by limiting nclients to 1 or <nbuffers, but that would make the "generalized" algorithm less generalized. Less elegant.

Revision history for this message
Alexandros Frantzis (afrantzis) wrote : Posted in a previous version of this proposal

> Bypass requires that successive compositor acquisitions get different buffers. So MultiAcquisitionBackBufferStrategy > won't work there. I suggest either the timing approach in the short term, or we discuss how to change the API to
> compositor_acquire so that it is more multi-monitor friendly, and the reuse rules more explicit.

Since I think we both agree that this is not needed urgently for XMir/system compositor, let's make this MP lighter by leaving it out for now, with the understanding that we will need to look at it in the near future. We can try various solutions and see which gives the best visual result.

> "compositor_acquire would block; probably too many clients."
> It's guaranteed to not happen in the current Mir logic, so not a huge issue. I did think the same about guaranteeing > it never happens by limiting nclients to 1 or <nbuffers, but that would make the "generalized" algorithm less
> generalized. Less elegant.

... but more robust and correct. Since it is a core assumption that the compositor can always get a buffer without delay, I think it is preferable to enforce it, than to fail if the code that uses the swapper doesn't behave as expected. Not a blocker, but worth rethinking/revisiting IMO.

From IRC:

> <duflu> alf__: I just realized the primary thing keeping it at double was removed when I fixed those issues on
> Friday. Now it's only timing keeping it at double. If a client tries to render without using
> a timer (limited only by swapping) then it will expend to triple very quickly now :/

We should fix this... we shouldn't be "wasting" buffers this way if the app doesn't really need them (i.e. it's not framedropping or bypass-ing).

Revision history for this message
Alexandros Frantzis (afrantzis) wrote : Posted in a previous version of this proposal

There are some issues discussed in previous comments that can be handled in upcoming MPs. The only issue from the ones mentioned that I would prefer if we fixed in this MP (with a test if possible) is:

> If a client tries to render without using a timer (limited only by swapping) then it will expend to triple very quickly now :/

> (first_client + nclients) % nbuffers;
> (i + 1) % nbuffers;
...

I think it would make it easier to understand the algorithms if we express such calculations more descriptively, e.g.:

a = first_free();
b = next_buffer(i);

> 1774 + if (nbuffers < 1)
> 1775 + BOOST_THROW_EXCEPTION(std::logic_error("SwitchingBundle requires a "
> 1776 + "positive number of buffers"));

> 1930 + if (nclients <= 0 || ring[first_client].buf != released_buffer)
> 1931 + BOOST_THROW_EXCEPTION(std::logic_error(
> 1932 + "Client release out of order"));

... and at other places

multi-line statement should be placed in a block

> 2159 + SharedBuffer *ring;

std::vector<SharedBuffer> ring ?

> 4649 +TEST_F(SwitchingBundleTest, out_of_order_compositor_release)

Needs a rename?

review: Needs Fixing
Revision history for this message
Daniel van Vugt (vanvugt) wrote : Posted in a previous version of this proposal

Alexandros,

Multi-monitor wrong frame rate: FIXED
compositor_acquire would block: TODO (started, but not sure if I agree)
Limit most clients to double-buffering (again): TODO (probably... I need to rethink this)
More descriptive ring functions: FIXED
Multi-line statements in blocks: FIXED
Ring is a vector: I disagree. We don't need any vector template operations.
Rename out_of_order_compositor_release: FIXED

Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

> Ring is a vector: I disagree. We don't need any vector template operations.

std::vector provides indexing operations that are as efficient as normal C array indexing operations in proper implementations, and it's safer memory-wise than using new/delete explicitly.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

Hitting EOD, so I'll just drop some notes without voting yet.

~~~~

SwitchingBundle appears to work, but the style seems a bit cryptic. Like Alexandros, I see no advantage to manual memory management. I too prefer std::vector. (Or even an array - is there really any reason why we support nbuffers > 3?).

And then we are using indexes into the "ring" rather than iterators. The issue with this approach is that it mixes switching logic with with "ring iterator" implementation - making both harder to validate individually. (On the other hand it makes for convenient use of the remainder operator - which can aid efficiency.) But like I said, it appears to work.

~~~~

I'd appreciate a brief description of the numerous member variables and the invariant relationships between them. Otherwise it one has to read the code to discover which "int"s perform which roles: e.g. "first_client;" is the index into the ring of the first client whereas "int nclients;" is the current number of buffers /acquired/ by clients. (None of this is hard once familiar with the code, but it eases the learning code.)

~~~~

1866 + auto tmp = ring[slot];
1867 + ring[slot] = ring[i];
1868 + ring[i] = tmp;

    std::swap(ring[slot], ring[i]); // does the same thing, but says what it does.

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Alan,

Memory management: FIXED; converted to a fixed array, max 5 for testing generic N-buffering. Templates I will avoid until they're necessary. I don't want to contribute further to Mir's code bloat with single use template instantiations.

Iterators: I don't think an iterator pattern is appropriate. There is no "begin" or "end", and even an empty sub-queue (nclients==0) should still return a valid position (not end()). Also, I feel a bespoke iterator in this case would hinder understanding of the logic. Because knowing it's a ring is really important. Not something to abstract or hide.

Detailed documentation: Already exists at the top of switching_bundle.cpp

std::swap(): FIXED

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2013-08-06 22:24:54 +0000
3+++ debian/control 2013-08-07 10:49:30 +0000
4@@ -69,7 +69,7 @@
5 .
6 Contains the protocol's definition files.
7
8-Package: libmirserver0
9+Package: libmirserver1
10 Section: libs
11 Architecture: i386 amd64 armhf arm64
12 Multi-Arch: same
13@@ -99,7 +99,7 @@
14 Architecture: i386 amd64 armhf arm64
15 Multi-Arch: same
16 Pre-Depends: ${misc:Pre-Depends}
17-Depends: libmirserver0 (= ${binary:Version}),
18+Depends: libmirserver1 (= ${binary:Version}),
19 libmirprotobuf-dev (= ${binary:Version}),
20 mircommon-dev (= ${binary:Version}),
21 libglm-dev,
22
23=== renamed file 'debian/libmirserver0.install' => 'debian/libmirserver1.install'
24--- debian/libmirserver0.install 2013-08-05 10:56:41 +0000
25+++ debian/libmirserver1.install 2013-08-07 10:49:30 +0000
26@@ -1,3 +1,3 @@
27-usr/lib/*/libmirserver.so.0
28+usr/lib/*/libmirserver.so.1
29 usr/lib/*/libmirplatform.so
30 usr/lib/*/libmirplatformgraphics.so
31
32=== modified file 'examples/buffer_render_target.cpp'
33--- examples/buffer_render_target.cpp 2013-07-17 16:38:25 +0000
34+++ examples/buffer_render_target.cpp 2013-08-07 10:49:30 +0000
35@@ -29,12 +29,20 @@
36 mt::BufferRenderTarget::BufferRenderTarget(mg::Buffer& buffer)
37 : buffer(buffer)
38 {
39+ /*
40+ * With the new lazy buffer allocation method, we may be executing inside
41+ * the compositor's GL context. So be careful to save and restore what
42+ * we change...
43+ */
44+ glGetIntegerv(GL_VIEWPORT, old_viewport);
45 resources.setup(buffer);
46 }
47
48 mt::BufferRenderTarget::~BufferRenderTarget()
49 {
50 glFinish();
51+ glViewport(old_viewport[0], old_viewport[1],
52+ old_viewport[2], old_viewport[3]);
53 }
54
55 void mt::BufferRenderTarget::make_current()
56
57=== modified file 'examples/buffer_render_target.h'
58--- examples/buffer_render_target.h 2013-07-17 16:31:45 +0000
59+++ examples/buffer_render_target.h 2013-08-07 10:49:30 +0000
60@@ -58,6 +58,7 @@
61
62 Resources resources;
63 mir::graphics::Buffer& buffer;
64+ GLint old_viewport[4];
65 };
66
67 }
68
69=== removed file 'include/server/mir/compositor/back_buffer_strategy.h'
70--- include/server/mir/compositor/back_buffer_strategy.h 2013-07-17 16:31:45 +0000
71+++ include/server/mir/compositor/back_buffer_strategy.h 1970-01-01 00:00:00 +0000
72@@ -1,47 +0,0 @@
73-/*
74- * Copyright © 2013 Canonical Ltd.
75- *
76- * This program is free software: you can redistribute it and/or modify it
77- * under the terms of the GNU General Public License version 3,
78- * as published by the Free Software Foundation.
79- *
80- * This program is distributed in the hope that it will be useful,
81- * but WITHOUT ANY WARRANTY; without even the implied warranty of
82- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
83- * GNU General Public License for more details.
84- *
85- * You should have received a copy of the GNU General Public License
86- * along with this program. If not, see <http://www.gnu.org/licenses/>.
87- *
88- * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
89- */
90-
91-#ifndef MIR_COMPOSITOR_BACK_BUFFER_STRATEGY_H_
92-#define MIR_COMPOSITOR_BACK_BUFFER_STRATEGY_H_
93-
94-#include <memory>
95-
96-namespace mir
97-{
98-namespace graphics { class Buffer; }
99-
100-namespace compositor
101-{
102-class BackBufferStrategy
103-{
104-public:
105- virtual ~BackBufferStrategy() = default;
106-
107- virtual std::shared_ptr<graphics::Buffer> acquire() = 0;
108- virtual void release(std::shared_ptr<graphics::Buffer> const& buffer) = 0;
109-
110-protected:
111- BackBufferStrategy() = default;
112- BackBufferStrategy(BackBufferStrategy const&) = delete;
113- BackBufferStrategy& operator=(BackBufferStrategy const&) = delete;
114-};
115-
116-}
117-}
118-
119-#endif /* MIR_COMPOSITOR_BACK_BUFFER_STRATEGY_H_ */
120
121=== removed file 'include/server/mir/compositor/buffer_allocation_strategy.h'
122--- include/server/mir/compositor/buffer_allocation_strategy.h 2013-07-31 13:05:21 +0000
123+++ include/server/mir/compositor/buffer_allocation_strategy.h 1970-01-01 00:00:00 +0000
124@@ -1,63 +0,0 @@
125-/*
126- * Copyright © 2012 Canonical Ltd.
127- *
128- * This program is free software: you can redistribute it and/or modify it
129- * under the terms of the GNU General Public License version 3,
130- * as published by the Free Software Foundation.
131- *
132- * This program is distributed in the hope that it will be useful,
133- * but WITHOUT ANY WARRANTY; without even the implied warranty of
134- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
135- * GNU General Public License for more details.
136- *
137- * You should have received a copy of the GNU General Public License
138- * along with this program. If not, see <http://www.gnu.org/licenses/>.
139- *
140- * Authored by:
141- * Alan Griffiths <alan@octopull.co.uk>
142- * Thomas Voss <thomas.voss@canonical.com>
143- */
144-
145-#ifndef MIR_COMPOSITOR_BUFFER_ALLOCATION_STRATEGY_H_
146-#define MIR_COMPOSITOR_BUFFER_ALLOCATION_STRATEGY_H_
147-
148-#include "mir/graphics/buffer.h"
149-
150-#include <vector>
151-#include <memory>
152-
153-namespace mir
154-{
155-namespace graphics { struct BufferProperties; }
156-
157-namespace compositor
158-{
159-class BufferSwapper;
160-
161-enum class SwapperType
162-{
163- synchronous,
164- framedropping,
165- bypass
166-};
167-
168-class BufferAllocationStrategy
169-{
170-public:
171- virtual std::shared_ptr<BufferSwapper> create_swapper_reuse_buffers(graphics::BufferProperties const&,
172- std::vector<std::shared_ptr<graphics::Buffer>>&, size_t, SwapperType) const = 0;
173- virtual std::shared_ptr<BufferSwapper> create_swapper_new_buffers(
174- graphics::BufferProperties& actual_properties, graphics::BufferProperties const& requested_properties, SwapperType) const = 0;
175-
176-protected:
177- BufferAllocationStrategy() {}
178- virtual ~BufferAllocationStrategy() { /* TODO: make nothrow */ }
179-
180- BufferAllocationStrategy(const BufferAllocationStrategy&);
181- BufferAllocationStrategy& operator=(const BufferAllocationStrategy& );
182-};
183-
184-}
185-}
186-
187-#endif // MIR_COMPOSITOR_BUFFER_ALLOCATION_STRATEGY_H_
188
189=== modified file 'include/server/mir/compositor/buffer_stream_factory.h'
190--- include/server/mir/compositor/buffer_stream_factory.h 2013-07-31 11:00:22 +0000
191+++ include/server/mir/compositor/buffer_stream_factory.h 2013-08-07 10:49:30 +0000
192@@ -27,27 +27,27 @@
193
194 namespace mir
195 {
196+namespace graphics
197+{
198+class GraphicBufferAllocator;
199+}
200 namespace compositor
201 {
202
203-class BufferAllocationStrategy;
204-class GraphicBufferAllocator;
205-
206 class BufferStreamFactory : public surfaces::BufferStreamFactory
207 {
208 public:
209
210 explicit BufferStreamFactory(
211- const std::shared_ptr<BufferAllocationStrategy>& strategy);
212+ const std::shared_ptr<graphics::GraphicBufferAllocator> &gralloc);
213
214 virtual ~BufferStreamFactory() {}
215
216- // From BufferStreamFactory
217 virtual std::shared_ptr<surfaces::BufferStream> create_buffer_stream(
218 graphics::BufferProperties const& buffer_properties);
219
220 private:
221- std::shared_ptr<BufferAllocationStrategy> swapper_factory;
222+ std::shared_ptr<graphics::GraphicBufferAllocator> gralloc;
223
224 };
225
226
227=== modified file 'include/server/mir/compositor/buffer_stream_surfaces.h'
228--- include/server/mir/compositor/buffer_stream_surfaces.h 2013-07-31 11:00:22 +0000
229+++ include/server/mir/compositor/buffer_stream_surfaces.h 2013-08-07 10:49:30 +0000
230@@ -55,7 +55,6 @@
231
232 private:
233 std::shared_ptr<BufferBundle> const buffer_bundle;
234- std::shared_ptr<BackBufferStrategy> const back_buffer_strategy;
235 };
236
237 }
238
239=== removed file 'include/server/mir/compositor/buffer_swapper.h'
240--- include/server/mir/compositor/buffer_swapper.h 2013-07-17 16:31:45 +0000
241+++ include/server/mir/compositor/buffer_swapper.h 1970-01-01 00:00:00 +0000
242@@ -1,131 +0,0 @@
243-/*
244- * Copyright © 2012 Canonical Ltd.
245- *
246- * This program is free software: you can redistribute it and/or modify it
247- * under the terms of the GNU General Public License version 3,
248- * as published by the Free Software Foundation.
249- *
250- * This program is distributed in the hope that it will be useful,
251- * but WITHOUT ANY WARRANTY; without even the implied warranty of
252- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
253- * GNU General Public License for more details.
254- *
255- * You should have received a copy of the GNU General Public License
256- * along with this program. If not, see <http://www.gnu.org/licenses/>.
257- *
258- * Authored by:
259- * Kevin DuBois <kevin.dubois@canonical.com>
260- */
261-
262-#ifndef MIR_COMPOSITOR_BUFFER_SWAPPER_H_
263-#define MIR_COMPOSITOR_BUFFER_SWAPPER_H_
264-
265-#include <vector>
266-#include <memory>
267-
268-namespace mir
269-{
270-namespace graphics { class Buffer; }
271-
272-namespace compositor
273-{
274-class BufferSwapper
275-{
276-public:
277- /**
278- * Acquires a free client buffer.
279- *
280- * Callers of client_acquire() are returned a pointer to the currently
281- * usable buffer. Depending on the swapper implementation, this call
282- * may potentially wait for a buffer to become available.
283- *
284- * May throw a mc::BufferSwapperRequestAbortedException.
285- */
286- virtual std::shared_ptr<graphics::Buffer> client_acquire() = 0;
287-
288- /**
289- * Releases a client buffer, making it available to the compositor.
290- */
291- virtual void client_release(std::shared_ptr<graphics::Buffer> const& queued_buffer) = 0;
292-
293- /**
294- * Acquires the last posted buffer.
295- *
296- * Callers of compositor_acquire() should get no-wait access to the
297- * last posted buffer. However, the client will potentially stall
298- * until control of the buffer is returned via a call to
299- * compositor_release().
300- *
301- * Calling compositor_acquire() while a buffer is acquired causes
302- * undefined behavior.
303- *
304- * May throw a mc::BufferSwapperOutOfBuffersException.
305- */
306- virtual std::shared_ptr<graphics::Buffer> compositor_acquire() = 0;
307-
308- /**
309- * Releases a compositor buffer, making it available to the client.
310- */
311- virtual void compositor_release(std::shared_ptr<graphics::Buffer> const& released_buffer) = 0;
312-
313- /**
314- * Forces client requests on the buffer swapper to abort.
315- *
316- * client_acquire is the only function that can block to provide sync.
317- * This function unblocks client_acquire, generally resulting in an
318- * mc::BufferSwapperRequestAbortedException in threads with a waiting
319- * client_acquire().
320- *
321- * After this request, the compositor can keep acquiring and releasing buffers
322- * but the client cannot. This used in shutdown of the swapper, the client cannot
323- * be reactivated after this call completes.
324- */
325- virtual void force_client_abort() = 0;
326-
327- /**
328- * Forces requests on the buffer swapper to complete.
329- *
330- * Requests, like client_acquire(), can block waiting for a buffer to
331- * become available. This method tries to force the request to
332- * complete while ensuring that swapper keeps functioning properly.
333- *
334- * Note that it's not always possible to force a request to complete
335- * without breaking the swapper. It's a logic error to attempt to call
336- * this method if the circumstances don't allow a forced completion.
337- *
338- * To successfully use this method you should ensure that (i.e. the
339- * preconditions for calling this method are):
340- *
341- * - The compositor is not holding any buffers (e.g., it has been stopped).
342- * - The client is trying to acquire at most one buffer at a time (which is
343- * normal usage, and enforced by the high level API).
344- */
345- virtual void force_requests_to_complete() = 0;
346-
347- /**
348- * Ends synchronization of buffers. All buffers owned by the swapper
349- * at the time of this call are transferred to the 'buffers' parameter.
350- * The swapper specifies the number of buffers it was managing (buffers owned by
351- * the swapper plus any outstanding buffers) in 'original_size'.
352- * After the completion of this call, neither the client, nor the compositor can
353- * continue to request or return buffers to this swapper.
354- */
355- virtual void end_responsibility(std::vector<std::shared_ptr<graphics::Buffer>>& buffers, size_t& original_size) = 0;
356-
357- /**
358- * If the swapper has been used, and you want to preserve the buffers that have been used,
359- * it is advisable to shutdown the BufferSwapper by using force_client_abort()
360- * and then end_responsibility(). If these are not called, all buffers within the swapper
361- * will be deallocated
362- */
363- virtual ~BufferSwapper() = default;
364-protected:
365- BufferSwapper() = default;
366- BufferSwapper(BufferSwapper const&) = delete;
367- BufferSwapper& operator=(BufferSwapper const&) = delete;
368-};
369-
370-}
371-}
372-
373-#endif /* MIR_COMPOSITOR_BUFFER_SWAPPER_H_ */
374
375=== removed file 'include/server/mir/compositor/buffer_swapper_exceptions.h'
376--- include/server/mir/compositor/buffer_swapper_exceptions.h 2013-06-15 11:09:16 +0000
377+++ include/server/mir/compositor/buffer_swapper_exceptions.h 1970-01-01 00:00:00 +0000
378@@ -1,42 +0,0 @@
379-/*
380- * Copyright © 2013 Canonical Ltd.
381- *
382- * This program is free software: you can redistribute it and/or modify it
383- * under the terms of the GNU General Public License version 3,
384- * as published by the Free Software Foundation.
385- *
386- * This program is distributed in the hope that it will be useful,
387- * but WITHOUT ANY WARRANTY; without even the implied warranty of
388- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
389- * GNU General Public License for more details.
390- *
391- * You should have received a copy of the GNU General Public License
392- * along with this program. If not, see <http://www.gnu.org/licenses/>.
393- *
394- * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
395- */
396-
397-#ifndef MIR_COMPOSITOR_BUFFER_SWAPPER_EXCEPTIONS_H_
398-#define MIR_COMPOSITOR_BUFFER_SWAPPER_EXCEPTIONS_H_
399-
400-#include <stdexcept>
401-
402-namespace mir
403-{
404-namespace compositor
405-{
406-
407-struct BufferSwapperRequestAbortedException : public std::runtime_error
408-{
409- BufferSwapperRequestAbortedException() : std::runtime_error("Request aborted") {}
410-};
411-
412-struct BufferSwapperOutOfBuffersException : public std::logic_error
413-{
414- BufferSwapperOutOfBuffersException() : std::logic_error("Out of buffers") {}
415-};
416-
417-}
418-}
419-
420-#endif /* MIR_COMPOSITOR_BUFFER_SWAPPER_EXCEPTIONS_H_ */
421
422=== removed file 'include/server/mir/compositor/buffer_swapper_multi.h'
423--- include/server/mir/compositor/buffer_swapper_multi.h 2013-07-17 16:31:45 +0000
424+++ include/server/mir/compositor/buffer_swapper_multi.h 1970-01-01 00:00:00 +0000
425@@ -1,66 +0,0 @@
426-/*
427- * Copyright © 2012 Canonical Ltd.
428- *
429- * This program is free software: you can redistribute it and/or modify it
430- * under the terms of the GNU General Public License version 3,
431- * as published by the Free Software Foundation.
432- *
433- * This program is distributed in the hope that it will be useful,
434- * but WITHOUT ANY WARRANTY; without even the implied warranty of
435- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
436- * GNU General Public License for more details.
437- *
438- * You should have received a copy of the GNU General Public License
439- * along with this program. If not, see <http://www.gnu.org/licenses/>.
440- *
441- * Authored by:
442- * Kevin DuBois <kevin.dubois@canonical.com>
443- */
444-
445-#ifndef MIR_COMPOSITOR_BUFFER_SWAPPER_MULTI_H_
446-#define MIR_COMPOSITOR_BUFFER_SWAPPER_MULTI_H_
447-
448-#include "buffer_swapper.h"
449-
450-#include <mutex>
451-#include <condition_variable>
452-#include <vector>
453-#include <memory>
454-#include <deque>
455-#include <map>
456-
457-namespace mir
458-{
459-namespace compositor
460-{
461-
462-class BufferSwapperMulti : public BufferSwapper
463-{
464-public:
465- explicit BufferSwapperMulti(std::vector<std::shared_ptr<graphics::Buffer>>& buffer_list, size_t swapper_size);
466-
467- std::shared_ptr<graphics::Buffer> client_acquire();
468- void client_release(std::shared_ptr<graphics::Buffer> const& queued_buffer);
469- std::shared_ptr<graphics::Buffer> compositor_acquire();
470- void compositor_release(std::shared_ptr<graphics::Buffer> const& released_buffer);
471-
472- void force_client_abort();
473- void force_requests_to_complete();
474- void end_responsibility(std::vector<std::shared_ptr<graphics::Buffer>>&, size_t&);
475-
476-private:
477- std::mutex swapper_mutex;
478- std::condition_variable client_available_cv;
479-
480- std::deque<std::shared_ptr<graphics::Buffer>> client_queue;
481- std::deque<std::shared_ptr<graphics::Buffer>> compositor_queue;
482- unsigned int in_use_by_client;
483- unsigned int const swapper_size;
484- int clients_trying_to_acquire;
485- bool force_clients_to_abort;
486-};
487-
488-}
489-}
490-
491-#endif /* MIR_COMPOSITOR_BUFFER_SWAPPER_MULTI_H_ */
492
493=== removed file 'include/server/mir/compositor/buffer_swapper_spin.h'
494--- include/server/mir/compositor/buffer_swapper_spin.h 2013-07-17 16:31:45 +0000
495+++ include/server/mir/compositor/buffer_swapper_spin.h 1970-01-01 00:00:00 +0000
496@@ -1,73 +0,0 @@
497-/*
498- * Copyright © 2013 Canonical Ltd.
499- *
500- * This program is free software: you can redistribute it and/or modify it
501- * under the terms of the GNU General Public License version 3,
502- * as published by the Free Software Foundation.
503- *
504- * This program is distributed in the hope that it will be useful,
505- * but WITHOUT ANY WARRANTY; without even the implied warranty of
506- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
507- * GNU General Public License for more details.
508- *
509- * You should have received a copy of the GNU General Public License
510- * along with this program. If not, see <http://www.gnu.org/licenses/>.
511- *
512- * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
513- */
514-
515-#ifndef MIR_COMPOSITOR_BUFFER_SWAPPER_SPIN_H_
516-#define MIR_COMPOSITOR_BUFFER_SWAPPER_SPIN_H_
517-
518-#include "buffer_swapper.h"
519-
520-#include <mutex>
521-#include <vector>
522-#include <memory>
523-#include <deque>
524-
525-#include <boost/throw_exception.hpp>
526-
527-namespace mir
528-{
529-namespace compositor
530-{
531-
532-class Buffer;
533-
534-/**
535- * Spinning buffer swapping variant
536- *
537- * BufferSwapperSpin provides a "spinning" swapping variant, in which the
538- * client always has an available buffer to draw to, and can submit buffers
539- * unrestricted by the vsync rate. When the compositor needs a buffer, it
540- * uses the last submitted one, and the client continues to "spin" between
541- * the remaining buffers.
542- */
543-class BufferSwapperSpin : public BufferSwapper
544-{
545-public:
546- BufferSwapperSpin(std::vector<std::shared_ptr<graphics::Buffer>>& buffer_list, size_t swapper_size);
547-
548- std::shared_ptr<graphics::Buffer> client_acquire();
549- void client_release(std::shared_ptr<graphics::Buffer> const& queued_buffer);
550- std::shared_ptr<graphics::Buffer> compositor_acquire();
551- void compositor_release(std::shared_ptr<graphics::Buffer> const& released_buffer);
552-
553- void force_client_abort();
554- void force_requests_to_complete();
555- void end_responsibility(std::vector<std::shared_ptr<graphics::Buffer>>&, size_t&);
556-
557-private:
558- std::mutex swapper_mutex;
559-
560- std::deque<std::shared_ptr<graphics::Buffer>> buffer_queue;
561- unsigned int in_use_by_client;
562- bool client_submitted_new_buffer;
563- size_t const swapper_size;
564-};
565-
566-}
567-}
568-
569-#endif /* MIR_COMPOSITOR_BUFFER_SWAPPER_MULTI_SPIN_H_ */
570
571=== removed file 'include/server/mir/compositor/multi_acquisition_back_buffer_strategy.h'
572--- include/server/mir/compositor/multi_acquisition_back_buffer_strategy.h 2013-07-17 16:31:45 +0000
573+++ include/server/mir/compositor/multi_acquisition_back_buffer_strategy.h 1970-01-01 00:00:00 +0000
574@@ -1,66 +0,0 @@
575-/*
576- * Copyright © 2013 Canonical Ltd.
577- *
578- * This program is free software: you can redistribute it and/or modify it
579- * under the terms of the GNU General Public License version 3,
580- * as published by the Free Software Foundation.
581- *
582- * This program is distributed in the hope that it will be useful,
583- * but WITHOUT ANY WARRANTY; without even the implied warranty of
584- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
585- * GNU General Public License for more details.
586- *
587- * You should have received a copy of the GNU General Public License
588- * along with this program. If not, see <http://www.gnu.org/licenses/>.
589- *
590- * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
591- */
592-
593-#ifndef MIR_COMPOSITOR_MULTI_ACQUISTION_BACK_BUFFER_STRATEGY_H_
594-#define MIR_COMPOSITOR_MULTI_ACQUISTION_BACK_BUFFER_STRATEGY_H_
595-
596-#include "mir/compositor/back_buffer_strategy.h"
597-
598-#include <memory>
599-#include <vector>
600-#include <mutex>
601-
602-namespace mir
603-{
604-namespace compositor
605-{
606-class BufferBundle;
607-
608-namespace detail
609-{
610-
611-struct AcquiredBufferInfo
612-{
613- std::weak_ptr<graphics::Buffer> buffer;
614- bool partly_released;
615- int use_count;
616-};
617-
618-}
619-
620-class MultiAcquisitionBackBufferStrategy : public BackBufferStrategy
621-{
622-public:
623- MultiAcquisitionBackBufferStrategy(std::shared_ptr<BufferBundle> const& buffer_bundle);
624-
625- std::shared_ptr<graphics::Buffer> acquire();
626- void release(std::shared_ptr<graphics::Buffer> const& buffer);
627-
628-private:
629- std::vector<detail::AcquiredBufferInfo>::iterator find_info(
630- std::shared_ptr<graphics::Buffer> const& buffer);
631-
632- std::shared_ptr<BufferBundle> const buffer_bundle;
633- std::vector<detail::AcquiredBufferInfo> acquired_buffers;
634- std::mutex mutex;
635-};
636-
637-}
638-}
639-
640-#endif /* MIR_COMPOSITOR_MULTI_ACQUISTION_BACK_BUFFER_STRATEGY_H_ */
641
642=== removed file 'include/server/mir/compositor/swapper_factory.h'
643--- include/server/mir/compositor/swapper_factory.h 2013-07-31 11:00:22 +0000
644+++ include/server/mir/compositor/swapper_factory.h 1970-01-01 00:00:00 +0000
645@@ -1,55 +0,0 @@
646-/*
647- * Copyright © 2012 Canonical Ltd.
648- *
649- * This program is free software: you can redistribute it and/or modify it
650- * under the terms of the GNU General Public License version 3,
651- * as published by the Free Software Foundation.
652- *
653- * This program is distributed in the hope that it will be useful,
654- * but WITHOUT ANY WARRANTY; without even the implied warranty of
655- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
656- * GNU General Public License for more details.
657- *
658- * You should have received a copy of the GNU General Public License
659- * along with this program. If not, see <http://www.gnu.org/licenses/>.
660- *
661- * Authored by: Thomas Voss <thomas.voss@canonical.com>
662- */
663-
664-#ifndef MIR_COMPOSITOR_SWAPPER_FACTORY_H_
665-#define MIR_COMPOSITOR_SWAPPER_FACTORY_H_
666-
667-#include "mir/compositor/buffer_allocation_strategy.h"
668-
669-namespace mir
670-{
671-namespace graphics { class GraphicBufferAllocator; }
672-
673-namespace compositor
674-{
675-class SwapperFactory : public BufferAllocationStrategy
676-{
677-public:
678- explicit SwapperFactory(
679- std::shared_ptr<graphics::GraphicBufferAllocator> const& gr_alloc);
680- SwapperFactory(
681- std::shared_ptr<graphics::GraphicBufferAllocator> const& gr_alloc,
682- int number_of_buffers);
683-
684- std::shared_ptr<BufferSwapper> create_swapper_reuse_buffers(graphics::BufferProperties const&,
685- std::vector<std::shared_ptr<graphics::Buffer>>&, size_t, SwapperType) const;
686- std::shared_ptr<BufferSwapper> create_swapper_new_buffers(
687- graphics::BufferProperties& actual_properties, graphics::BufferProperties const& requested_properties, SwapperType) const;
688-
689-private:
690- void change_swapper_size(
691- std::vector<std::shared_ptr<graphics::Buffer>>&, size_t const, size_t, graphics::BufferProperties const&) const;
692-
693- std::shared_ptr<graphics::GraphicBufferAllocator> const gr_allocator;
694- unsigned int const synchronous_number_of_buffers;
695- unsigned int const spin_number_of_buffers;
696-};
697-}
698-}
699-
700-#endif // MIR_COMPOSITOR_SWAPPER_FACTORY_H_
701
702=== modified file 'include/server/mir/default_server_configuration.h'
703--- include/server/mir/default_server_configuration.h 2013-08-06 10:39:53 +0000
704+++ include/server/mir/default_server_configuration.h 2013-08-07 10:49:30 +0000
705@@ -137,7 +137,6 @@
706 * @{ */
707 virtual std::shared_ptr<compositor::DisplayBufferCompositorFactory> the_display_buffer_compositor_factory();
708 virtual std::shared_ptr<compositor::OverlayRenderer> the_overlay_renderer();
709- virtual std::shared_ptr<compositor::BufferAllocationStrategy> the_buffer_allocation_strategy();
710 /** @} */
711
712 /** @name compositor configuration - dependencies
713@@ -247,7 +246,6 @@
714 CachedPtr<frontend::SessionMediatorReport> session_mediator_report;
715 CachedPtr<frontend::MessageProcessorReport> message_processor_report;
716 CachedPtr<frontend::SessionAuthorizer> session_authorizer;
717- CachedPtr<compositor::BufferAllocationStrategy> buffer_allocation_strategy;
718 CachedPtr<compositor::RendererFactory> renderer_factory;
719 CachedPtr<compositor::BufferStreamFactory> buffer_stream_factory;
720 CachedPtr<surfaces::SurfaceStack> surface_stack;
721
722=== modified file 'include/test/mir_test_doubles/mock_buffer_bundle.h'
723--- include/test/mir_test_doubles/mock_buffer_bundle.h 2013-07-31 11:00:22 +0000
724+++ include/test/mir_test_doubles/mock_buffer_bundle.h 2013-08-07 10:49:30 +0000
725@@ -41,6 +41,8 @@
726 MOCK_METHOD1(client_release, void(std::shared_ptr<graphics::Buffer> const&));
727 MOCK_METHOD0(compositor_acquire, std::shared_ptr<graphics::Buffer>());
728 MOCK_METHOD1(compositor_release, void(std::shared_ptr<graphics::Buffer> const&));
729+ MOCK_METHOD0(snapshot_acquire, std::shared_ptr<graphics::Buffer>());
730+ MOCK_METHOD1(snapshot_release, void(std::shared_ptr<graphics::Buffer> const&));
731 MOCK_METHOD1(allow_framedropping, void(bool));
732 MOCK_CONST_METHOD0(properties, graphics::BufferProperties());
733 MOCK_METHOD0(force_client_abort, void());
734
735=== removed file 'include/test/mir_test_doubles/mock_swapper.h'
736--- include/test/mir_test_doubles/mock_swapper.h 2013-07-17 16:31:45 +0000
737+++ include/test/mir_test_doubles/mock_swapper.h 1970-01-01 00:00:00 +0000
738@@ -1,66 +0,0 @@
739-/*
740- * Copyright © 2012 Canonical Ltd.
741- *
742- * This program is free software: you can redistribute it and/or modify it
743- * under the terms of the GNU General Public License version 3,
744- * as published by the Free Software Foundation.
745- *
746- * This program is distributed in the hope that it will be useful,
747- * but WITHOUT ANY WARRANTY; without even the implied warranty of
748- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
749- * GNU General Public License for more details.
750- *
751- * You should have received a copy of the GNU General Public License
752- * along with this program. If not, see <http://www.gnu.org/licenses/>.
753- *
754- * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
755- */
756-#ifndef MIR_TEST_DOUBLES_MOCK_SWAPPER_H_
757-#define MIR_TEST_DOUBLES_MOCK_SWAPPER_H_
758-
759-#include "mir/compositor/buffer_swapper.h"
760-
761-#include <gmock/gmock.h>
762-
763-namespace mir
764-{
765-namespace test
766-{
767-namespace doubles
768-{
769-
770-struct MockSwapper : public compositor::BufferSwapper
771-{
772-public:
773- MockSwapper() {}
774- ~MockSwapper() noexcept {}
775-
776- MockSwapper(std::shared_ptr<graphics::Buffer> buffer)
777- : default_buffer(buffer)
778- {
779- using namespace testing;
780-
781- ON_CALL(*this, compositor_acquire())
782- .WillByDefault(Return(default_buffer));
783- ON_CALL(*this, client_acquire())
784- .WillByDefault(Return(default_buffer));
785- }
786-
787- MOCK_METHOD0(client_acquire, std::shared_ptr<graphics::Buffer>());
788- MOCK_METHOD1(client_release, void(std::shared_ptr<graphics::Buffer> const&));
789- MOCK_METHOD0(compositor_acquire, std::shared_ptr<graphics::Buffer>());
790- MOCK_METHOD1(compositor_release, void(std::shared_ptr<graphics::Buffer> const&));
791- MOCK_METHOD0(force_client_abort, void());
792- MOCK_METHOD0(force_requests_to_complete, void());
793-
794- MOCK_METHOD2(end_responsibility, void(std::vector<std::shared_ptr<graphics::Buffer>>&, size_t&));
795-
796-private:
797- std::shared_ptr<graphics::Buffer> default_buffer;
798-};
799-
800-}
801-}
802-}
803-
804-#endif /* MIR_TEST_DOUBLES_MOCK_SWAPPER_H_ */
805
806=== removed file 'include/test/mir_test_doubles/mock_swapper_factory.h'
807--- include/test/mir_test_doubles/mock_swapper_factory.h 2013-07-31 11:00:22 +0000
808+++ include/test/mir_test_doubles/mock_swapper_factory.h 1970-01-01 00:00:00 +0000
809@@ -1,47 +0,0 @@
810-/*
811- * Copyright © 2013 Canonical Ltd.
812- *
813- * This program is free software: you can redistribute it and/or modify it
814- * under the terms of the GNU General Public License version 3,
815- * as published by the Free Software Foundation.
816- *
817- * This program is distributed in the hope that it will be useful,
818- * but WITHOUT ANY WARRANTY; without even the implied warranty of
819- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
820- * GNU General Public License for more details.
821- *
822- * You should have received a copy of the GNU General Public License
823- * along with this program. If not, see <http://www.gnu.org/licenses/>.
824- *
825- * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
826- */
827-#ifndef MIR_TEST_DOUBLES_MOCK_SWAPPER_FACTORY_H_
828-#define MIR_TEST_DOUBLES_MOCK_SWAPPER_FACTORY_H_
829-
830-#include "mir/compositor/buffer_allocation_strategy.h"
831-
832-#include <gmock/gmock.h>
833-
834-namespace mir
835-{
836-namespace test
837-{
838-namespace doubles
839-{
840-class MockSwapperFactory : public compositor::BufferAllocationStrategy
841-{
842-public:
843- ~MockSwapperFactory() noexcept {}
844-
845- MOCK_CONST_METHOD4(create_swapper_reuse_buffers,
846- std::shared_ptr<compositor::BufferSwapper>(graphics::BufferProperties const&,
847- std::vector<std::shared_ptr<graphics::Buffer>>&, size_t, compositor::SwapperType));
848- MOCK_CONST_METHOD3(create_swapper_new_buffers,
849- std::shared_ptr<compositor::BufferSwapper>(
850- graphics::BufferProperties&, graphics::BufferProperties const&, compositor::SwapperType));
851-};
852-}
853-}
854-}
855-
856-#endif /* MIR_TEST_DOUBLES_MOCK_SWAPPER_FACTORY_H_ */
857
858=== modified file 'src/server/CMakeLists.txt'
859--- src/server/CMakeLists.txt 2013-08-06 07:20:02 +0000
860+++ src/server/CMakeLists.txt 2013-08-07 10:49:30 +0000
861@@ -84,7 +84,7 @@
862 )
863 endif()
864
865-set(MIRSERVER_ABI 0)
866+set(MIRSERVER_ABI 1)
867
868 set_target_properties(
869 mirserver
870
871=== modified file 'src/server/compositor/CMakeLists.txt'
872--- src/server/compositor/CMakeLists.txt 2013-07-26 05:12:14 +0000
873+++ src/server/compositor/CMakeLists.txt 2013-08-07 10:49:30 +0000
874@@ -7,16 +7,11 @@
875 temporary_buffers.cpp
876 buffer_stream_factory.cpp
877 buffer_stream_surfaces.cpp
878- buffer_swapper_multi.cpp
879- buffer_swapper_spin.cpp
880- swapper_factory.cpp
881 rendering_operator.cpp
882 gl_renderer.cpp
883 gl_renderer_factory.cpp
884 multi_threaded_compositor.cpp
885 switching_bundle.cpp
886- rw_lock.cpp
887- multi_acquisition_back_buffer_strategy.cpp
888 )
889
890 ADD_LIBRARY(
891
892=== modified file 'src/server/compositor/buffer_bundle.h'
893--- src/server/compositor/buffer_bundle.h 2013-07-31 13:05:21 +0000
894+++ src/server/compositor/buffer_bundle.h 2013-08-07 10:49:30 +0000
895@@ -38,6 +38,8 @@
896 virtual void client_release(std::shared_ptr<graphics::Buffer> const&) = 0;
897 virtual std::shared_ptr<graphics::Buffer> compositor_acquire() = 0;
898 virtual void compositor_release(std::shared_ptr<graphics::Buffer> const&) = 0;
899+ virtual std::shared_ptr<graphics::Buffer> snapshot_acquire() = 0;
900+ virtual void snapshot_release(std::shared_ptr<graphics::Buffer> const&) = 0;
901
902 virtual graphics::BufferProperties properties() const = 0;
903 virtual void allow_framedropping(bool dropping_allowed) = 0;
904
905=== modified file 'src/server/compositor/buffer_stream_factory.cpp'
906--- src/server/compositor/buffer_stream_factory.cpp 2013-07-31 11:18:25 +0000
907+++ src/server/compositor/buffer_stream_factory.cpp 2013-08-07 10:49:30 +0000
908@@ -18,7 +18,6 @@
909 * Thomas Voss <thomas.voss@canonical.com>
910 */
911
912-#include "mir/compositor/buffer_allocation_strategy.h"
913 #include "mir/compositor/buffer_stream_factory.h"
914 #include "mir/compositor/buffer_stream_surfaces.h"
915 #include "mir/graphics/buffer_properties.h"
916@@ -36,16 +35,17 @@
917 namespace ms = mir::surfaces;
918
919 mc::BufferStreamFactory::BufferStreamFactory(
920- const std::shared_ptr<BufferAllocationStrategy>& strategy)
921- : swapper_factory(strategy)
922+ const std::shared_ptr<mg::GraphicBufferAllocator> &gralloc)
923+ : gralloc(gralloc)
924 {
925- assert(strategy);
926+ assert(gralloc);
927 }
928
929
930 std::shared_ptr<ms::BufferStream> mc::BufferStreamFactory::create_buffer_stream(
931 mg::BufferProperties const& buffer_properties)
932 {
933- auto switching_bundle = std::make_shared<mc::SwitchingBundle>(swapper_factory, buffer_properties);
934+ // Note: Framedropping and bypass both require a minimum 3 buffers
935+ auto switching_bundle = std::make_shared<mc::SwitchingBundle>(3, gralloc, buffer_properties);
936 return std::make_shared<mc::BufferStreamSurfaces>(switching_bundle);
937 }
938
939=== modified file 'src/server/compositor/buffer_stream_surfaces.cpp'
940--- src/server/compositor/buffer_stream_surfaces.cpp 2013-07-31 11:18:25 +0000
941+++ src/server/compositor/buffer_stream_surfaces.cpp 2013-08-07 10:49:30 +0000
942@@ -20,7 +20,6 @@
943 #include "mir/compositor/buffer_stream_surfaces.h"
944 #include "buffer_bundle.h"
945 #include "mir/graphics/buffer_properties.h"
946-#include "mir/compositor/multi_acquisition_back_buffer_strategy.h"
947
948 #include "temporary_buffers.h"
949
950@@ -29,25 +28,23 @@
951 namespace geom = mir::geometry;
952
953 mc::BufferStreamSurfaces::BufferStreamSurfaces(std::shared_ptr<BufferBundle> const& buffer_bundle)
954- : buffer_bundle(buffer_bundle),
955- back_buffer_strategy(
956- std::make_shared<MultiAcquisitionBackBufferStrategy>(buffer_bundle))
957+ : buffer_bundle(buffer_bundle)
958 {
959 }
960
961 mc::BufferStreamSurfaces::~BufferStreamSurfaces()
962 {
963+ force_requests_to_complete();
964 }
965
966 std::shared_ptr<mg::Buffer> mc::BufferStreamSurfaces::lock_compositor_buffer()
967 {
968- return std::make_shared<mc::TemporaryCompositorBuffer>(back_buffer_strategy);
969+ return std::make_shared<mc::TemporaryCompositorBuffer>(buffer_bundle);
970 }
971
972 std::shared_ptr<mg::Buffer> mc::BufferStreamSurfaces::lock_snapshot_buffer()
973 {
974- // TODO (duflu): Implement differently for bypass
975- return std::make_shared<mc::TemporaryCompositorBuffer>(back_buffer_strategy);
976+ return std::make_shared<mc::TemporarySnapshotBuffer>(buffer_bundle);
977 }
978
979 std::shared_ptr<mg::Buffer> mc::BufferStreamSurfaces::secure_client_buffer()
980
981=== removed file 'src/server/compositor/buffer_swapper_multi.cpp'
982--- src/server/compositor/buffer_swapper_multi.cpp 2013-07-17 16:31:45 +0000
983+++ src/server/compositor/buffer_swapper_multi.cpp 1970-01-01 00:00:00 +0000
984@@ -1,174 +0,0 @@
985-/*
986- * Copyright © 2012 Canonical Ltd.
987- *
988- * This program is free software: you can redistribute it and/or modify it
989- * under the terms of the GNU General Public License version 3,
990- * as published by the Free Software Foundation.
991- *
992- * This program is distributed in the hope that it will be useful,
993- * but WITHOUT ANY WARRANTY; without even the implied warranty of
994- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
995- * GNU General Public License for more details.
996- *
997- * You should have received a copy of the GNU General Public License
998- * along with this program. If not, see <http://www.gnu.org/licenses/>.
999- *
1000- * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
1001- */
1002-
1003-#include "mir/compositor/buffer_swapper_multi.h"
1004-#include "mir/compositor/buffer_swapper_exceptions.h"
1005-#include <boost/throw_exception.hpp>
1006-
1007-namespace mc = mir::compositor;
1008-namespace mg = mir::graphics;
1009-
1010-mc::BufferSwapperMulti::BufferSwapperMulti(std::vector<std::shared_ptr<mg::Buffer>>& buffer_list, size_t swapper_size)
1011- : in_use_by_client(0),
1012- swapper_size(swapper_size),
1013- clients_trying_to_acquire(0),
1014- force_clients_to_abort(false)
1015-{
1016- if ((swapper_size != 2) && (swapper_size != 3))
1017- {
1018- BOOST_THROW_EXCEPTION(std::logic_error("BufferSwapperMulti is only validated for 2 or 3 buffers"));
1019- }
1020-
1021- for (auto& buffer : buffer_list)
1022- {
1023- client_queue.push_back(buffer);
1024- }
1025-}
1026-
1027-std::shared_ptr<mg::Buffer> mc::BufferSwapperMulti::client_acquire()
1028-{
1029- std::unique_lock<std::mutex> lk(swapper_mutex);
1030-
1031- clients_trying_to_acquire++;
1032-
1033- /*
1034- * Don't allow the client to acquire all the buffers, because then the
1035- * compositor won't have a buffer to display.
1036- */
1037- while ((!force_clients_to_abort) &&
1038- (client_queue.empty() || (in_use_by_client == (swapper_size - 1))))
1039- {
1040- client_available_cv.wait(lk);
1041- }
1042-
1043- //we have been forced to shutdown
1044- if (force_clients_to_abort)
1045- {
1046- clients_trying_to_acquire--;
1047- BOOST_THROW_EXCEPTION(BufferSwapperRequestAbortedException());
1048- }
1049-
1050- auto dequeued_buffer = client_queue.front();
1051- client_queue.pop_front();
1052- in_use_by_client++;
1053-
1054- clients_trying_to_acquire--;
1055-
1056- return dequeued_buffer;
1057-}
1058-
1059-void mc::BufferSwapperMulti::client_release(std::shared_ptr<mg::Buffer> const& queued_buffer)
1060-{
1061- std::unique_lock<std::mutex> lk(swapper_mutex);
1062-
1063- compositor_queue.push_back(queued_buffer);
1064- in_use_by_client--;
1065-
1066- /*
1067- * At this point we could signal the client_available_cv. However, we
1068- * won't do so, because the cv will get signaled after the next
1069- * compositor_release anyway, and we want to avoid the overhead of
1070- * signaling at every client_release just to ensure quicker client
1071- * notification in an abnormal situation.
1072- */
1073-}
1074-
1075-std::shared_ptr<mg::Buffer> mc::BufferSwapperMulti::compositor_acquire()
1076-{
1077- std::unique_lock<std::mutex> lk(swapper_mutex);
1078-
1079- std::shared_ptr<mg::Buffer> dequeued_buffer;
1080-
1081- if (!compositor_queue.empty())
1082- {
1083- dequeued_buffer = compositor_queue.front();
1084- compositor_queue.pop_front();
1085- }
1086- else if (!client_queue.empty())
1087- {
1088- dequeued_buffer = client_queue.back();
1089- client_queue.pop_back();
1090- }
1091- else
1092- {
1093- BOOST_THROW_EXCEPTION(BufferSwapperOutOfBuffersException());
1094- }
1095-
1096- return dequeued_buffer;
1097-}
1098-
1099-void mc::BufferSwapperMulti::compositor_release(std::shared_ptr<mg::Buffer> const& released_buffer)
1100-{
1101- std::unique_lock<std::mutex> lk(swapper_mutex);
1102- client_queue.push_back(released_buffer);
1103- client_available_cv.notify_one();
1104-}
1105-
1106-void mc::BufferSwapperMulti::force_client_abort()
1107-{
1108- std::unique_lock<std::mutex> lk(swapper_mutex);
1109- force_clients_to_abort = true;
1110- client_available_cv.notify_all();
1111-}
1112-
1113-void mc::BufferSwapperMulti::force_requests_to_complete()
1114-{
1115- if (in_use_by_client == swapper_size - 1 && clients_trying_to_acquire > 0)
1116- {
1117- BOOST_THROW_EXCEPTION(
1118- std::logic_error("BufferSwapperMulti is not able to force requests to complete:"
1119- " the client is trying to acquire all buffers"));
1120- }
1121-
1122- if (client_queue.empty())
1123- {
1124- if (compositor_queue.empty())
1125- {
1126- BOOST_THROW_EXCEPTION(
1127- std::logic_error("BufferSwapperMulti is not able to force requests to complete:"
1128- " all buffers are acquired"));
1129- }
1130-
1131- auto dequeued_buffer = compositor_queue.front();
1132- compositor_queue.pop_front();
1133- client_queue.push_back(dequeued_buffer);
1134- }
1135-
1136- client_available_cv.notify_all();
1137-}
1138-
1139-
1140-void mc::BufferSwapperMulti::end_responsibility(std::vector<std::shared_ptr<mg::Buffer>>& buffers,
1141- size_t& size)
1142-{
1143- std::unique_lock<std::mutex> lk(swapper_mutex);
1144-
1145- while(!compositor_queue.empty())
1146- {
1147- buffers.push_back(compositor_queue.back());
1148- compositor_queue.pop_back();
1149- }
1150-
1151- while(!client_queue.empty())
1152- {
1153- buffers.push_back(client_queue.back());
1154- client_queue.pop_back();
1155- }
1156-
1157- size = swapper_size;
1158-}
1159
1160=== removed file 'src/server/compositor/buffer_swapper_spin.cpp'
1161--- src/server/compositor/buffer_swapper_spin.cpp 2013-07-17 16:31:45 +0000
1162+++ src/server/compositor/buffer_swapper_spin.cpp 1970-01-01 00:00:00 +0000
1163@@ -1,114 +0,0 @@
1164-/*
1165- * Copyright © 2013 Canonical Ltd.
1166- *
1167- * This program is free software: you can redistribute it and/or modify it
1168- * under the terms of the GNU General Public License version 3,
1169- * as published by the Free Software Foundation.
1170- *
1171- * This program is distributed in the hope that it will be useful,
1172- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1173- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1174- * GNU General Public License for more details.
1175- *
1176- * You should have received a copy of the GNU General Public License
1177- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1178- *
1179- * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
1180- */
1181-
1182-#include "mir/compositor/buffer_swapper_spin.h"
1183-
1184-namespace mc = mir::compositor;
1185-namespace mg = mir::graphics;
1186-
1187-mc::BufferSwapperSpin::BufferSwapperSpin(
1188- std::vector<std::shared_ptr<mg::Buffer>>& buffer_list, size_t swapper_size)
1189- : buffer_queue{buffer_list.begin(), buffer_list.end()},
1190- in_use_by_client{0},
1191- swapper_size{swapper_size}
1192-{
1193- if (swapper_size != 3)
1194- {
1195- BOOST_THROW_EXCEPTION(
1196- std::logic_error("BufferSwapperSpin is only validated for 3 buffers"));
1197- }
1198-}
1199-
1200-std::shared_ptr<mg::Buffer> mc::BufferSwapperSpin::client_acquire()
1201-{
1202- std::lock_guard<std::mutex> lg{swapper_mutex};
1203-
1204- /*
1205- * Don't allow the client to acquire all the buffers, because then the
1206- * compositor won't have a buffer to display.
1207- */
1208- if (in_use_by_client == swapper_size - 1)
1209- {
1210- BOOST_THROW_EXCEPTION(std::logic_error("Client is trying to acquire all buffers at once"));
1211- }
1212-
1213- auto dequeued_buffer = buffer_queue.back();
1214- buffer_queue.pop_back();
1215- in_use_by_client++;
1216-
1217- return dequeued_buffer;
1218-}
1219-
1220-void mc::BufferSwapperSpin::client_release(std::shared_ptr<mg::Buffer> const& queued_buffer)
1221-{
1222- std::lock_guard<std::mutex> lg{swapper_mutex};
1223-
1224- buffer_queue.push_front(queued_buffer);
1225- in_use_by_client--;
1226- client_submitted_new_buffer = true;
1227-}
1228-
1229-std::shared_ptr<mg::Buffer> mc::BufferSwapperSpin::compositor_acquire()
1230-{
1231- std::lock_guard<std::mutex> lg{swapper_mutex};
1232-
1233- auto dequeued_buffer = buffer_queue.front();
1234- buffer_queue.pop_front();
1235- client_submitted_new_buffer = false;
1236-
1237- return dequeued_buffer;
1238-}
1239-
1240-void mc::BufferSwapperSpin::compositor_release(std::shared_ptr<mg::Buffer> const& released_buffer)
1241-{
1242- std::lock_guard<std::mutex> lg{swapper_mutex};
1243-
1244- /*
1245- * If the client didn't submit a new buffer while the compositor was
1246- * holding a buffer, the compositor's buffer is still the newest one, so
1247- * place it at the front of the buffer queue. Otherwise, place it at the
1248- * back of the buffer queue.
1249- */
1250- if (client_submitted_new_buffer)
1251- buffer_queue.push_back(released_buffer);
1252- else
1253- buffer_queue.push_front(released_buffer);
1254-}
1255-
1256-void mc::BufferSwapperSpin::force_client_abort()
1257-{
1258-}
1259-
1260-void mc::BufferSwapperSpin::force_requests_to_complete()
1261-{
1262-}
1263-
1264-
1265-void mc::BufferSwapperSpin::end_responsibility(std::vector<std::shared_ptr<mg::Buffer>>& buffers,
1266- size_t& size)
1267-{
1268- std::lock_guard<std::mutex> lg{swapper_mutex};
1269-
1270- while(!buffer_queue.empty())
1271- {
1272- buffers.push_back(buffer_queue.back());
1273- buffer_queue.pop_back();
1274- }
1275-
1276- size = swapper_size;
1277-}
1278
1279=== removed file 'src/server/compositor/multi_acquisition_back_buffer_strategy.cpp'
1280--- src/server/compositor/multi_acquisition_back_buffer_strategy.cpp 2013-07-17 16:31:45 +0000
1281+++ src/server/compositor/multi_acquisition_back_buffer_strategy.cpp 1970-01-01 00:00:00 +0000
1282@@ -1,119 +0,0 @@
1283-/*
1284- * Copyright © 2013 Canonical Ltd.
1285- *
1286- * This program is free software: you can redistribute it and/or modify it
1287- * under the terms of the GNU General Public License version 3,
1288- * as published by the Free Software Foundation.
1289- *
1290- * This program is distributed in the hope that it will be useful,
1291- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1292- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1293- * GNU General Public License for more details.
1294- *
1295- * You should have received a copy of the GNU General Public License
1296- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1297- *
1298- * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
1299- */
1300-
1301-#include "mir/compositor/multi_acquisition_back_buffer_strategy.h"
1302-#include "mir/compositor/buffer_swapper_exceptions.h"
1303-#include "buffer_bundle.h"
1304-
1305-#include <algorithm>
1306-
1307-namespace mc = mir::compositor;
1308-namespace mg = mir::graphics;
1309-
1310-mc::MultiAcquisitionBackBufferStrategy::MultiAcquisitionBackBufferStrategy(
1311- std::shared_ptr<BufferBundle> const& buffer_bundle)
1312- : buffer_bundle{buffer_bundle}
1313-{
1314-}
1315-
1316-std::shared_ptr<mg::Buffer> mc::MultiAcquisitionBackBufferStrategy::acquire()
1317-{
1318- std::lock_guard<std::mutex> lg{mutex};
1319-
1320- /* Try to find an already acquired buffer, that hasn't been partly released */
1321- auto iter = std::find_if(acquired_buffers.begin(), acquired_buffers.end(),
1322- [] (detail::AcquiredBufferInfo const& info)
1323- {
1324- return info.partly_released == false;
1325- });
1326-
1327- std::shared_ptr<mg::Buffer> buffer;
1328-
1329- if (iter != acquired_buffers.end())
1330- {
1331- buffer = iter->buffer.lock();
1332- }
1333- else
1334- {
1335- /*
1336- * If we couldn't get a non-partly-released acquired buffer,
1337- * try to get a new one. If that fails, try to give back a partly
1338- * released acquired buffer.
1339- */
1340- try
1341- {
1342- buffer = buffer_bundle->compositor_acquire();
1343- }
1344- catch (mc::BufferSwapperOutOfBuffersException const& e)
1345- {
1346- if (!acquired_buffers.empty())
1347- buffer = acquired_buffers.back().buffer.lock();
1348- else
1349- throw;
1350- }
1351-
1352- iter = find_info(buffer);
1353- }
1354-
1355-
1356- if (iter != acquired_buffers.end())
1357- ++iter->use_count;
1358- else
1359- acquired_buffers.push_back(detail::AcquiredBufferInfo{buffer, false, 1});
1360-
1361- return buffer;
1362-}
1363-
1364-void mc::MultiAcquisitionBackBufferStrategy::release(std::shared_ptr<mg::Buffer> const& buffer)
1365-{
1366- std::lock_guard<std::mutex> lg{mutex};
1367-
1368- auto iter = find_info(buffer);
1369-
1370- bool should_be_released{true};
1371-
1372- if (iter != acquired_buffers.end())
1373- {
1374- detail::AcquiredBufferInfo& info = *iter;
1375-
1376- --info.use_count;
1377-
1378- if (info.use_count == 0)
1379- {
1380- acquired_buffers.erase(iter);
1381- }
1382- else
1383- {
1384- info.partly_released = true;
1385- should_be_released = false;
1386- }
1387- }
1388-
1389- if (should_be_released)
1390- buffer_bundle->compositor_release(buffer);
1391-}
1392-
1393-std::vector<mc::detail::AcquiredBufferInfo>::iterator
1394-mc::MultiAcquisitionBackBufferStrategy::find_info(std::shared_ptr<mg::Buffer> const& buffer)
1395-{
1396- return std::find_if(acquired_buffers.begin(), acquired_buffers.end(),
1397- [&buffer] (detail::AcquiredBufferInfo const& info)
1398- {
1399- return info.buffer.lock() == buffer;
1400- });
1401-}
1402
1403=== removed file 'src/server/compositor/rw_lock.cpp'
1404--- src/server/compositor/rw_lock.cpp 2013-06-07 15:23:27 +0000
1405+++ src/server/compositor/rw_lock.cpp 1970-01-01 00:00:00 +0000
1406@@ -1,71 +0,0 @@
1407-/*
1408- * Copyright © 2012 Canonical Ltd.
1409- *
1410- * This program is free software: you can redistribute it and/or modify it
1411- * under the terms of the GNU General Public License version 3,
1412- * as published by the Free Software Foundation.
1413- *
1414- * This program is distributed in the hope that it will be useful,
1415- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1416- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1417- * GNU General Public License for more details.
1418- *
1419- * You should have received a copy of the GNU General Public License
1420- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1421- *
1422- * Authored by:
1423- * Kevin DuBois <kevin.dubois@canonical.com>
1424- */
1425-
1426-#include "rw_lock.h"
1427-
1428-namespace mc=mir::compositor;
1429-
1430-mc::RWLockWriterBias::RWLockWriterBias()
1431- : readers(0),
1432- writers(0),
1433- waiting_writers(0)
1434-{
1435-}
1436-
1437-void mc::RWLockWriterBias::read_lock()
1438-{
1439- std::unique_lock<std::mutex> lk(mut);
1440- while ((waiting_writers > 0) || (writers > 0))
1441- {
1442- reader_cv.wait(lk);
1443- }
1444- readers++;
1445-}
1446-
1447-void mc::RWLockWriterBias::read_unlock()
1448-{
1449- std::unique_lock<std::mutex> lk(mut);
1450- readers--;
1451- if (readers == 0)
1452- {
1453- writer_cv.notify_all();
1454- }
1455-}
1456-
1457-void mc::RWLockWriterBias::write_lock()
1458-{
1459- std::unique_lock<std::mutex> lk(mut);
1460- waiting_writers++;
1461- while ((readers > 0) || (writers > 0))
1462- {
1463- writer_cv.wait(lk);
1464- }
1465- waiting_writers--;
1466- writers++;
1467-}
1468-
1469-void mc::RWLockWriterBias::write_unlock()
1470-{
1471- std::unique_lock<std::mutex> lk(mut);
1472- writers--;
1473-
1474- reader_cv.notify_all();
1475- if (waiting_writers > 0)
1476- writer_cv.notify_all();
1477-}
1478
1479=== removed file 'src/server/compositor/rw_lock.h'
1480--- src/server/compositor/rw_lock.h 2013-06-14 14:41:33 +0000
1481+++ src/server/compositor/rw_lock.h 1970-01-01 00:00:00 +0000
1482@@ -1,88 +0,0 @@
1483-/*
1484- * Copyright © 2012 Canonical Ltd.
1485- *
1486- * This program is free software: you can redistribute it and/or modify it
1487- * under the terms of the GNU General Public License version 3,
1488- * as published by the Free Software Foundation.
1489- *
1490- * This program is distributed in the hope that it will be useful,
1491- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1492- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1493- * GNU General Public License for more details.
1494- *
1495- * You should have received a copy of the GNU General Public License
1496- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1497- *
1498- * Authored by:
1499- * Kevin DuBois <kevin.dubois@canonical.com>
1500- */
1501-
1502-#ifndef MIR_COMPOSITOR_RW_LOCK_H_
1503-#define MIR_COMPOSITOR_RW_LOCK_H_
1504-
1505-#include <mutex>
1506-#include <condition_variable>
1507-
1508-namespace mir
1509-{
1510-namespace compositor
1511-{
1512-
1513-class ReadLock
1514-{
1515-public:
1516- void lock() { read_lock(); }
1517- void unlock() { read_unlock(); }
1518-
1519- virtual ~ReadLock() = default;
1520-protected:
1521- ReadLock()
1522- {
1523- }
1524-private:
1525- virtual void read_lock() = 0;
1526- virtual void read_unlock() = 0;
1527-
1528- ReadLock(ReadLock const&) = delete;
1529- ReadLock& operator=(ReadLock const&) = delete;
1530-};
1531-
1532-class WriteLock
1533-{
1534-public:
1535- void lock() { write_lock(); }
1536- void unlock() { write_unlock(); }
1537-
1538- virtual ~WriteLock() = default;
1539-protected:
1540- WriteLock()
1541- {
1542- }
1543-private:
1544- virtual void write_lock() = 0;
1545- virtual void write_unlock() = 0;
1546-
1547- WriteLock(WriteLock const&) = delete;
1548- WriteLock& operator=(WriteLock const&) = delete;
1549-};
1550-
1551-class RWLockWriterBias : public ReadLock, public WriteLock
1552-{
1553-public:
1554- RWLockWriterBias();
1555-private:
1556- void write_lock();
1557- void write_unlock();
1558- void read_lock();
1559- void read_unlock();
1560- std::mutex mut;
1561- std::condition_variable reader_cv, writer_cv;
1562- unsigned int readers;
1563- unsigned int writers;
1564- unsigned int waiting_writers;
1565-};
1566-
1567-}
1568-}
1569-
1570-#endif /* MIR_COMPOSITOR_RW_LOCK_H_ */
1571
1572=== removed file 'src/server/compositor/swapper_factory.cpp'
1573--- src/server/compositor/swapper_factory.cpp 2013-07-31 11:18:25 +0000
1574+++ src/server/compositor/swapper_factory.cpp 1970-01-01 00:00:00 +0000
1575@@ -1,118 +0,0 @@
1576-/*
1577- * Copyright © 2012 Canonical Ltd.
1578- *
1579- * This program is free software: you can redistribute it and/or modify it
1580- * under the terms of the GNU General Public License version 3,
1581- * as published by the Free Software Foundation.
1582- *
1583- * This program is distributed in the hope that it will be useful,
1584- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1585- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1586- * GNU General Public License for more details.
1587- *
1588- * You should have received a copy of the GNU General Public License
1589- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1590- *
1591- * Authored by: Alan Griffiths <alan@octopull.co.uk>
1592- */
1593-
1594-#include "mir/compositor/swapper_factory.h"
1595-#include "mir/compositor/buffer_allocation_strategy.h"
1596-#include "mir/graphics/buffer_properties.h"
1597-#include "mir/graphics/graphic_buffer_allocator.h"
1598-#include "mir/compositor/buffer_swapper_multi.h"
1599-#include "mir/compositor/buffer_swapper_spin.h"
1600-#include "mir/graphics/buffer_id.h"
1601-#include "mir/geometry/dimensions.h"
1602-#include "switching_bundle.h"
1603-
1604-#include <initializer_list>
1605-#include <vector>
1606-#include <cassert>
1607-
1608-namespace mc = mir::compositor;
1609-namespace mg = mir::graphics;
1610-
1611-mc::SwapperFactory::SwapperFactory(
1612- std::shared_ptr<mg::GraphicBufferAllocator> const& gr_alloc,
1613- int number_of_buffers)
1614- : gr_allocator(gr_alloc),
1615- synchronous_number_of_buffers(number_of_buffers),
1616- spin_number_of_buffers(3) //spin algorithm always takes 3 buffers
1617-{
1618-}
1619-
1620-mc::SwapperFactory::SwapperFactory(
1621- std::shared_ptr<mg::GraphicBufferAllocator> const& gr_alloc)
1622- : SwapperFactory(gr_alloc, 2)
1623-{
1624-}
1625-
1626-void mc::SwapperFactory::change_swapper_size(
1627- std::vector<std::shared_ptr<mg::Buffer>>& list,
1628- size_t const desired_size, size_t current_size, mg::BufferProperties const& buffer_properties) const
1629-{
1630- while (current_size < desired_size)
1631- {
1632- list.push_back(gr_allocator->alloc_buffer(buffer_properties));
1633- current_size++;
1634- }
1635-
1636- while (current_size > desired_size)
1637- {
1638- if (list.empty())
1639- {
1640- BOOST_THROW_EXCEPTION(std::logic_error("SwapperFactory could not change algorithm"));
1641- }
1642- else
1643- {
1644- list.pop_back();
1645- current_size--;
1646- }
1647- }
1648-}
1649-
1650-std::shared_ptr<mc::BufferSwapper> mc::SwapperFactory::create_swapper_reuse_buffers(
1651- mg::BufferProperties const& buffer_properties, std::vector<std::shared_ptr<mg::Buffer>>& list,
1652- size_t buffer_num, SwapperType type) const
1653-{
1654- if (type == mc::SwapperType::synchronous)
1655- {
1656- change_swapper_size(list, synchronous_number_of_buffers, buffer_num, buffer_properties);
1657- return std::make_shared<mc::BufferSwapperMulti>(list, synchronous_number_of_buffers);
1658- }
1659- else
1660- {
1661- change_swapper_size(list, spin_number_of_buffers, buffer_num, buffer_properties);
1662- return std::make_shared<mc::BufferSwapperSpin>(list, spin_number_of_buffers);
1663- }
1664-}
1665-
1666-std::shared_ptr<mc::BufferSwapper> mc::SwapperFactory::create_swapper_new_buffers(
1667- mg::BufferProperties& actual_buffer_properties,
1668- mg::BufferProperties const& requested_buffer_properties, SwapperType type) const
1669-{
1670- std::vector<std::shared_ptr<mg::Buffer>> list;
1671- std::shared_ptr<mc::BufferSwapper> new_swapper;
1672-
1673- if (type == mc::SwapperType::synchronous)
1674- {
1675- for(auto i=0u; i< synchronous_number_of_buffers; i++)
1676- {
1677- list.push_back(gr_allocator->alloc_buffer(requested_buffer_properties));
1678- }
1679- new_swapper = std::make_shared<mc::BufferSwapperMulti>(list, synchronous_number_of_buffers);
1680- }
1681- else
1682- {
1683- for(auto i=0u; i < spin_number_of_buffers; i++)
1684- {
1685- list.push_back(gr_allocator->alloc_buffer(requested_buffer_properties));
1686- }
1687- new_swapper = std::make_shared<mc::BufferSwapperSpin>(list, spin_number_of_buffers);
1688- }
1689-
1690- actual_buffer_properties = mg::BufferProperties{
1691- list[0]->size(), list[0]->pixel_format(), requested_buffer_properties.usage};
1692- return new_swapper;
1693-}
1694
1695=== modified file 'src/server/compositor/switching_bundle.cpp'
1696--- src/server/compositor/switching_bundle.cpp 2013-07-31 11:00:22 +0000
1697+++ src/server/compositor/switching_bundle.cpp 2013-08-07 10:49:30 +0000
1698@@ -13,91 +13,396 @@
1699 * You should have received a copy of the GNU General Public License
1700 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1701 *
1702- * Authored by:
1703- * Kevin DuBois <kevin.dubois@canonical.com>
1704+ * Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com>
1705+ *
1706+ *
1707+ * The "bundle" of buffers is actually a ring (circular array) from which
1708+ * buffers are allocated and progress through stages.
1709+ *
1710+ * The stages of a buffer are:
1711+ * free -> client -> ready -> compositor <-> free
1712+ * ready (dropped)-> free
1713+ *
1714+ * Dropping only happens when it's enabled, and only if the ring is
1715+ * completely full.
1716+ *
1717+ * The successive stages are contiguous elements in the ring (starting at
1718+ * element "first_compositor"):
1719+ * first_compositor * ncompositors(zero or more)
1720+ * first_ready * nready(zero or more)
1721+ * first_client * nclients(zero or more)
1722+ *
1723+ * Therefore you will find:
1724+ * first_compositor + ncompositors == first_ready
1725+ * first_ready + nready == first_client
1726+ * although the ring wraps around, so all addition is modulo (%) nbuffers.
1727+ *
1728+ * "free" is an implicit state for any buffer that is not in any of the
1729+ * above three groups. So the next free buffer is always:
1730+ * first_client + nclients
1731+ * and free buffers extend up to but not including first_compositor.
1732+ *
1733+ * |<--------------------- nbuffers ----------------------->|
1734+ * | ncompos | nready | nclients|
1735+ * +----------+---------+--------------+---------+----------+
1736+ * | ... free | | | | | | | | free ... |
1737+ * +----------+---------+--------------+---------+----------+
1738+ * ^ ^ first_ready ^ first_client
1739+ * first_compositor
1740+ *
1741+ * Finally, there is a floating pointer called "snapshot" which can point to
1742+ * any buffer other than an active client. If nsnappshotters>0 then "snapshot"
1743+ * currently points to a buffer that is being snapshotted by one or more
1744+ * threads.
1745 */
1746
1747-#include "mir/compositor/buffer_swapper.h"
1748-#include "mir/compositor/buffer_swapper_exceptions.h"
1749-#include "mir/compositor/buffer_allocation_strategy.h"
1750+#include "mir/graphics/graphic_buffer_allocator.h"
1751 #include "switching_bundle.h"
1752
1753 #include <boost/throw_exception.hpp>
1754+#include <utility>
1755
1756 namespace mc=mir::compositor;
1757 namespace mg = mir::graphics;
1758
1759 mc::SwitchingBundle::SwitchingBundle(
1760- std::shared_ptr<BufferAllocationStrategy> const& swapper_factory, mg::BufferProperties const& property_request)
1761- : swapper_factory(swapper_factory),
1762- swapper(swapper_factory->create_swapper_new_buffers(
1763- bundle_properties, property_request, mc::SwapperType::synchronous))
1764-{
1765+ int nbuffers,
1766+ const std::shared_ptr<graphics::GraphicBufferAllocator> &gralloc,
1767+ const mg::BufferProperties &property_request)
1768+ : bundle_properties{property_request},
1769+ gralloc{gralloc},
1770+ nbuffers{nbuffers},
1771+ first_compositor{0}, ncompositors{0},
1772+ first_ready{0}, nready{0},
1773+ first_client{0}, nclients{0},
1774+ snapshot{-1}, nsnapshotters{0},
1775+ overlapping_compositors{false},
1776+ framedropping{false}, force_drop{0}
1777+{
1778+ if (nbuffers < 1 || nbuffers > MAX_NBUFFERS)
1779+ {
1780+ BOOST_THROW_EXCEPTION(std::logic_error("SwitchingBundle only supports "
1781+ "nbuffers betwee 1 and " +
1782+ std::to_string(MAX_NBUFFERS)));
1783+ }
1784+
1785+ for (int i = 0; i < nbuffers; i++)
1786+ ring[i].users = 0;
1787+
1788+ last_consumed = now() - std::chrono::seconds(1);
1789+}
1790+
1791+int mc::SwitchingBundle::nfree() const
1792+{
1793+ return nbuffers - ncompositors - nready - nclients;
1794+}
1795+
1796+int mc::SwitchingBundle::first_free() const
1797+{
1798+ return (first_client + nclients) % nbuffers;
1799+}
1800+
1801+int mc::SwitchingBundle::next(int slot) const
1802+{
1803+ return (slot + 1) % nbuffers;
1804+}
1805+
1806+int mc::SwitchingBundle::prev(int slot) const
1807+{
1808+ return (slot + nbuffers - 1) % nbuffers;
1809+}
1810+
1811+int mc::SwitchingBundle::last_compositor() const
1812+{
1813+ return (first_compositor + ncompositors - 1) % nbuffers;
1814+}
1815+
1816+int mc::SwitchingBundle::drop_frames(int max)
1817+{
1818+ // Drop up to max of the oldest ready frames, and put them on the free list
1819+ int dropped = (max > nready) ? nready : max;
1820+
1821+ for (int d = 0; d < dropped; d++)
1822+ {
1823+ auto tmp = ring[first_ready];
1824+ nready--;
1825+ first_client = prev(first_client);
1826+ int end = first_free();
1827+ int new_snapshot = snapshot;
1828+
1829+ for (int i = first_ready, j = 0; i != end; i = j)
1830+ {
1831+ j = next(i);
1832+ ring[i] = ring[j];
1833+ if (j == snapshot)
1834+ new_snapshot = i;
1835+ }
1836+
1837+ if (snapshot == first_ready)
1838+ new_snapshot = end;
1839+
1840+ snapshot = new_snapshot;
1841+
1842+ ring[end] = tmp;
1843+ }
1844+
1845+ return dropped;
1846+}
1847+
1848+const std::shared_ptr<mg::Buffer> &mc::SwitchingBundle::alloc_buffer(int slot)
1849+{
1850+ /*
1851+ * Many clients will behave in a way that never requires more than 2 or 3
1852+ * buffers, even though nbuffers may be higher. So to optimize memory
1853+ * usage for this common case, try to avoid allocating new buffers if
1854+ * we don't need to.
1855+ */
1856+ if (!ring[slot].buf)
1857+ {
1858+ int i = first_free();
1859+ int n = nfree();
1860+ while (n && !ring[i].buf)
1861+ {
1862+ i = next(i);
1863+ n--;
1864+ }
1865+
1866+ if (i != slot && ring[i].buf && ring[i].buf.unique())
1867+ {
1868+ std::swap(ring[slot], ring[i]);
1869+ }
1870+ else
1871+ {
1872+ ring[slot].buf = gralloc->alloc_buffer(bundle_properties);
1873+ }
1874+ }
1875+
1876+ return ring[slot].buf;
1877 }
1878
1879 std::shared_ptr<mg::Buffer> mc::SwitchingBundle::client_acquire()
1880 {
1881- /* lock is for use of 'swapper' below' */
1882- std::unique_lock<mc::ReadLock> lk(rw_lock);
1883-
1884- std::shared_ptr<mg::Buffer> buffer = nullptr;
1885- while (!buffer)
1886- {
1887- try
1888- {
1889- buffer = swapper->client_acquire();
1890- }
1891- catch (BufferSwapperRequestAbortedException const& e)
1892- {
1893- /* wait for the swapper to change before retrying */
1894- cv.wait(lk);
1895- }
1896- }
1897- return buffer;
1898+ std::unique_lock<std::mutex> lock(guard);
1899+
1900+ if ((framedropping || force_drop) && nbuffers > 1)
1901+ {
1902+ if (nfree() <= 0)
1903+ {
1904+ while (nready == 0)
1905+ cond.wait(lock);
1906+
1907+ drop_frames(1);
1908+ }
1909+ }
1910+ else
1911+ {
1912+ /*
1913+ * Even if there are free buffers available, we might wish to still
1914+ * wait. This is so we don't touch (hence allocate) a third or higher
1915+ * buffer until/unless it's absolutely necessary. It becomes necessary
1916+ * only when framedropping (above) or with overlapping compositors
1917+ * (like with bypass).
1918+ * The performance benefit of triple buffering is usually minimal,
1919+ * but always uses 50% more memory. So try to avoid it when possible.
1920+ */
1921+
1922+ int min_free =
1923+#if 0 // FIXME: This memory optimization breaks timing tests
1924+ (nbuffers > 2 && !overlapping_compositors) ? nbuffers - 1 : 1;
1925+#else
1926+ 1;
1927+#endif
1928+
1929+ while (nfree() < min_free)
1930+ cond.wait(lock);
1931+ }
1932+
1933+ if (force_drop > 0)
1934+ force_drop--;
1935+
1936+ int client = first_free();
1937+ nclients++;
1938+
1939+ auto ret = alloc_buffer(client);
1940+ if (client == snapshot)
1941+ {
1942+ /*
1943+ * In the rare case where a snapshot is still being taken of what is
1944+ * the new client buffer, try to move it out the way, or if you can't
1945+ * then wait for the snapshot to finish.
1946+ */
1947+ if (nfree() > 0)
1948+ {
1949+ snapshot = next(client);
1950+ std::swap(ring[snapshot], ring[client]);
1951+ ret = alloc_buffer(client);
1952+ }
1953+ else
1954+ {
1955+ while (client == snapshot)
1956+ cond.wait(lock);
1957+ }
1958+ }
1959+
1960+ return ret;
1961 }
1962
1963 void mc::SwitchingBundle::client_release(std::shared_ptr<mg::Buffer> const& released_buffer)
1964 {
1965- std::unique_lock<mc::ReadLock> lk(rw_lock);
1966- return swapper->client_release(released_buffer);
1967+ std::unique_lock<std::mutex> lock(guard);
1968+
1969+ if (nclients <= 0 || ring[first_client].buf != released_buffer)
1970+ {
1971+ BOOST_THROW_EXCEPTION(std::logic_error(
1972+ "Client release out of order"));
1973+ }
1974+
1975+ first_client = next(first_client);
1976+ nclients--;
1977+ nready++;
1978+ cond.notify_all();
1979 }
1980
1981 std::shared_ptr<mg::Buffer> mc::SwitchingBundle::compositor_acquire()
1982 {
1983- std::unique_lock<mc::ReadLock> lk(rw_lock);
1984- return swapper->compositor_acquire();
1985+ std::unique_lock<std::mutex> lock(guard);
1986+ int compositor;
1987+
1988+ auto t = now();
1989+
1990+ // Multi-monitor acquires close to each other get the same frame:
1991+ bool same_frame = (t - last_consumed) < std::chrono::milliseconds(10);
1992+
1993+ int avail = nfree();
1994+ bool can_recycle = ncompositors || avail;
1995+
1996+ if (!nready || (same_frame && can_recycle))
1997+ {
1998+ if (ncompositors)
1999+ {
2000+ compositor = last_compositor();
2001+ }
2002+ else if (avail)
2003+ {
2004+ first_compositor = prev(first_compositor);
2005+ compositor = first_compositor;
2006+ ncompositors++;
2007+ }
2008+ else
2009+ {
2010+ BOOST_THROW_EXCEPTION(std::logic_error(
2011+ "compositor_acquire would block; probably too many clients."));
2012+ }
2013+ }
2014+ else
2015+ {
2016+ compositor = first_ready;
2017+ first_ready = next(first_ready);
2018+ nready--;
2019+ ncompositors++;
2020+ last_consumed = t;
2021+ }
2022+
2023+ overlapping_compositors = (ncompositors > 1);
2024+
2025+ ring[compositor].users++;
2026+ return alloc_buffer(compositor);
2027 }
2028
2029 void mc::SwitchingBundle::compositor_release(std::shared_ptr<mg::Buffer> const& released_buffer)
2030 {
2031- std::unique_lock<mc::ReadLock> lk(rw_lock);
2032- return swapper->compositor_release(released_buffer);
2033+ std::unique_lock<std::mutex> lock(guard);
2034+ int compositor = -1;
2035+
2036+ for (int n = 0, i = first_compositor; n < ncompositors; n++, i = next(i))
2037+ {
2038+ if (ring[i].buf == released_buffer)
2039+ {
2040+ compositor = i;
2041+ break;
2042+ }
2043+ }
2044+
2045+ if (compositor < 0)
2046+ {
2047+ BOOST_THROW_EXCEPTION(std::logic_error(
2048+ "compositor_release given a non-compositor buffer"));
2049+ }
2050+
2051+ ring[compositor].users--;
2052+ if (compositor == first_compositor)
2053+ {
2054+ while (!ring[first_compositor].users && ncompositors)
2055+ {
2056+ first_compositor = next(first_compositor);
2057+ ncompositors--;
2058+ }
2059+ cond.notify_all();
2060+ }
2061+}
2062+
2063+std::shared_ptr<mg::Buffer> mc::SwitchingBundle::snapshot_acquire()
2064+{
2065+ std::unique_lock<std::mutex> lock(guard);
2066+
2067+ /*
2068+ * Note that "nsnapshotters" is a separate counter to ring[x].users.
2069+ * This is because snapshotters should be completely passive and should
2070+ * not affect the compositing logic.
2071+ */
2072+
2073+ if (!nsnapshotters)
2074+ {
2075+ /*
2076+ * Always snapshot the newest complete frame, which is always the
2077+ * one before the first client. But make sure there is at least one
2078+ * non-client buffer first...
2079+ */
2080+ while (nclients >= nbuffers)
2081+ cond.wait(lock);
2082+
2083+ if (!nsnapshotters)
2084+ snapshot = prev(first_client);
2085+ }
2086+
2087+ nsnapshotters++;
2088+ return alloc_buffer(snapshot);
2089+}
2090+
2091+void mc::SwitchingBundle::snapshot_release(std::shared_ptr<mg::Buffer> const& released_buffer)
2092+{
2093+ std::unique_lock<std::mutex> lock(guard);
2094+
2095+ if (nsnapshotters <= 0 || ring[snapshot].buf != released_buffer)
2096+ {
2097+ BOOST_THROW_EXCEPTION(std::logic_error(
2098+ "snapshot_release passed a non-snapshot buffer"));
2099+ }
2100+
2101+ nsnapshotters--;
2102+
2103+ if (!nsnapshotters)
2104+ snapshot = -1;
2105+
2106+ cond.notify_all();
2107 }
2108
2109 void mc::SwitchingBundle::force_requests_to_complete()
2110 {
2111- std::unique_lock<mc::ReadLock> lk(rw_lock);
2112- swapper->force_requests_to_complete();
2113+ std::unique_lock<std::mutex> lock(guard);
2114+ drop_frames(nready);
2115+ force_drop = nbuffers + 1;
2116+ cond.notify_all();
2117 }
2118
2119 void mc::SwitchingBundle::allow_framedropping(bool allow_dropping)
2120 {
2121- {
2122- std::unique_lock<mc::ReadLock> lk(rw_lock);
2123- swapper->force_client_abort();
2124- }
2125-
2126- std::unique_lock<mc::WriteLock> lk(rw_lock);
2127- std::vector<std::shared_ptr<mg::Buffer>> list{};
2128- size_t size = 0;
2129- swapper->end_responsibility(list, size);
2130-
2131- if (allow_dropping)
2132- swapper = swapper_factory->create_swapper_reuse_buffers(bundle_properties, list, size, mc::SwapperType::framedropping);
2133- else
2134- swapper = swapper_factory->create_swapper_reuse_buffers(bundle_properties, list, size, mc::SwapperType::synchronous);
2135-
2136- cv.notify_all();
2137+ framedropping = allow_dropping;
2138+}
2139+
2140+bool mc::SwitchingBundle::framedropping_allowed() const
2141+{
2142+ return framedropping;
2143 }
2144
2145 mg::BufferProperties mc::SwitchingBundle::properties() const
2146
2147=== modified file 'src/server/compositor/switching_bundle.h'
2148--- src/server/compositor/switching_bundle.h 2013-07-31 11:00:22 +0000
2149+++ src/server/compositor/switching_bundle.h 2013-08-07 10:49:30 +0000
2150@@ -21,23 +21,27 @@
2151 #define MIR_COMPOSITOR_SWITCHING_BUNDLE_H_
2152
2153 #include "buffer_bundle.h"
2154-#include "rw_lock.h"
2155 #include <condition_variable>
2156+#include <mutex>
2157 #include <memory>
2158-#include <atomic>
2159+#include <chrono>
2160
2161 namespace mir
2162 {
2163+namespace graphics
2164+{
2165+class Buffer;
2166+class GraphicBufferAllocator;
2167+}
2168 namespace compositor
2169 {
2170-class Buffer;
2171-class BufferSwapper;
2172-class BufferAllocationStrategy;
2173
2174 class SwitchingBundle : public BufferBundle
2175 {
2176 public:
2177- SwitchingBundle(std::shared_ptr<BufferAllocationStrategy> const& swapper_factory, graphics::BufferProperties const&);
2178+ SwitchingBundle(int nbuffers,
2179+ const std::shared_ptr<graphics::GraphicBufferAllocator> &,
2180+ const graphics::BufferProperties &);
2181
2182 graphics::BufferProperties properties() const;
2183
2184@@ -45,15 +49,55 @@
2185 void client_release(std::shared_ptr<graphics::Buffer> const&);
2186 std::shared_ptr<graphics::Buffer> compositor_acquire();
2187 void compositor_release(std::shared_ptr<graphics::Buffer> const& released_buffer);
2188+ std::shared_ptr<graphics::Buffer> snapshot_acquire();
2189+ void snapshot_release(std::shared_ptr<graphics::Buffer> const& released_buffer);
2190 void force_requests_to_complete();
2191 void allow_framedropping(bool dropping_allowed);
2192+ bool framedropping_allowed() const;
2193
2194 private:
2195- graphics::BufferProperties bundle_properties; //must be before swapper
2196- std::shared_ptr<BufferAllocationStrategy> const swapper_factory;
2197- std::shared_ptr<BufferSwapper> swapper;
2198- RWLockWriterBias rw_lock;
2199- std::condition_variable_any cv;
2200+ graphics::BufferProperties bundle_properties;
2201+ std::shared_ptr<graphics::GraphicBufferAllocator> gralloc;
2202+
2203+ int drop_frames(int max);
2204+ int nfree() const;
2205+ int first_free() const;
2206+ int next(int slot) const;
2207+ int prev(int slot) const;
2208+ int last_compositor() const;
2209+
2210+ const std::shared_ptr<graphics::Buffer> &alloc_buffer(int slot);
2211+
2212+ enum {MAX_NBUFFERS = 5};
2213+ struct SharedBuffer
2214+ {
2215+ std::shared_ptr<graphics::Buffer> buf;
2216+ int users; // presently just a count of compositors sharing the buf
2217+ };
2218+ SharedBuffer ring[MAX_NBUFFERS];
2219+
2220+ const int nbuffers;
2221+ int first_compositor;
2222+ int ncompositors;
2223+ int first_ready;
2224+ int nready;
2225+ int first_client;
2226+ int nclients;
2227+ int snapshot;
2228+ int nsnapshotters;
2229+
2230+ std::mutex guard;
2231+ std::condition_variable cond;
2232+
2233+ typedef std::chrono::high_resolution_clock::time_point time_point;
2234+ static time_point now()
2235+ { return std::chrono::high_resolution_clock::now(); }
2236+ time_point last_consumed;
2237+
2238+ bool overlapping_compositors;
2239+
2240+ bool framedropping;
2241+ int force_drop;
2242 };
2243
2244 }
2245
2246=== modified file 'src/server/compositor/temporary_buffers.cpp'
2247--- src/server/compositor/temporary_buffers.cpp 2013-07-17 16:31:45 +0000
2248+++ src/server/compositor/temporary_buffers.cpp 2013-08-07 10:49:30 +0000
2249@@ -16,8 +16,6 @@
2250 * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
2251 */
2252
2253-#include "mir/compositor/back_buffer_strategy.h"
2254-
2255 #include "buffer_bundle.h"
2256 #include "temporary_buffers.h"
2257
2258@@ -43,16 +41,27 @@
2259 }
2260
2261 mc::TemporaryCompositorBuffer::TemporaryCompositorBuffer(
2262- std::shared_ptr<BackBufferStrategy> const& back_buffer_strategy)
2263- : TemporaryBuffer(back_buffer_strategy->acquire()),
2264- back_buffer_strategy(back_buffer_strategy)
2265+ std::shared_ptr<BufferBundle> const& bun)
2266+ : TemporaryBuffer(bun->compositor_acquire()),
2267+ bundle(bun)
2268 {
2269 }
2270
2271 mc::TemporaryCompositorBuffer::~TemporaryCompositorBuffer()
2272 {
2273- if (auto strategy = back_buffer_strategy.lock())
2274- strategy->release(buffer);
2275+ bundle->compositor_release(buffer);
2276+}
2277+
2278+mc::TemporarySnapshotBuffer::TemporarySnapshotBuffer(
2279+ std::shared_ptr<BufferBundle> const& bun)
2280+ : TemporaryBuffer(bun->snapshot_acquire()),
2281+ bundle(bun)
2282+{
2283+}
2284+
2285+mc::TemporarySnapshotBuffer::~TemporarySnapshotBuffer()
2286+{
2287+ bundle->snapshot_release(buffer);
2288 }
2289
2290 geom::Size mc::TemporaryBuffer::size() const
2291
2292=== modified file 'src/server/compositor/temporary_buffers.h'
2293--- src/server/compositor/temporary_buffers.h 2013-07-17 16:38:25 +0000
2294+++ src/server/compositor/temporary_buffers.h 2013-08-07 10:49:30 +0000
2295@@ -61,11 +61,22 @@
2296 {
2297 public:
2298 explicit TemporaryCompositorBuffer(
2299- std::shared_ptr<BackBufferStrategy> const& back_buffer_strategy);
2300+ std::shared_ptr<BufferBundle> const& bun);
2301 ~TemporaryCompositorBuffer();
2302
2303 private:
2304- std::weak_ptr<BackBufferStrategy> const back_buffer_strategy;
2305+ std::shared_ptr<BufferBundle> const bundle;
2306+};
2307+
2308+class TemporarySnapshotBuffer : public TemporaryBuffer
2309+{
2310+public:
2311+ explicit TemporarySnapshotBuffer(
2312+ std::shared_ptr<BufferBundle> const& bun);
2313+ ~TemporarySnapshotBuffer();
2314+
2315+private:
2316+ std::shared_ptr<BufferBundle> const bundle;
2317 };
2318
2319 }
2320
2321=== modified file 'src/server/default_server_configuration.cpp'
2322--- src/server/default_server_configuration.cpp 2013-08-06 10:39:53 +0000
2323+++ src/server/default_server_configuration.cpp 2013-08-07 10:49:30 +0000
2324@@ -22,12 +22,9 @@
2325 #include "mir/shared_library.h"
2326
2327 #include "mir/options/program_option.h"
2328-#include "mir/compositor/buffer_allocation_strategy.h"
2329-#include "mir/compositor/buffer_swapper.h"
2330 #include "mir/compositor/buffer_stream_factory.h"
2331 #include "mir/compositor/default_display_buffer_compositor_factory.h"
2332 #include "mir/compositor/multi_threaded_compositor.h"
2333-#include "mir/compositor/swapper_factory.h"
2334 #include "mir/compositor/overlay_renderer.h"
2335 #include "mir/frontend/protobuf_ipc_factory.h"
2336 #include "mir/frontend/session_mediator_report.h"
2337@@ -354,16 +351,6 @@
2338 });
2339 }
2340
2341-std::shared_ptr<mc::BufferAllocationStrategy>
2342-mir::DefaultServerConfiguration::the_buffer_allocation_strategy()
2343-{
2344- return buffer_allocation_strategy(
2345- [this]()
2346- {
2347- return std::make_shared<mc::SwapperFactory>(the_buffer_allocator());
2348- });
2349-}
2350-
2351 std::shared_ptr<mc::RendererFactory> mir::DefaultServerConfiguration::the_renderer_factory()
2352 {
2353 return renderer_factory(
2354@@ -699,7 +686,7 @@
2355 return buffer_stream_factory(
2356 [this]()
2357 {
2358- return std::make_shared<mc::BufferStreamFactory>(the_buffer_allocation_strategy());
2359+ return std::make_shared<mc::BufferStreamFactory>(the_buffer_allocator());
2360 });
2361 }
2362
2363
2364=== modified file 'tests/integration-tests/compositor/CMakeLists.txt'
2365--- tests/integration-tests/compositor/CMakeLists.txt 2013-06-17 15:55:04 +0000
2366+++ tests/integration-tests/compositor/CMakeLists.txt 2013-08-07 10:49:30 +0000
2367@@ -1,6 +1,5 @@
2368 list(
2369 APPEND INTEGRATION_TESTS_SRCS
2370- ${CMAKE_CURRENT_SOURCE_DIR}/test_stress_buffer_swapper.cpp
2371 ${CMAKE_CURRENT_SOURCE_DIR}/test_swapping_swappers.cpp
2372 ${CMAKE_CURRENT_SOURCE_DIR}/test_synchronizer.cpp
2373 ${CMAKE_CURRENT_SOURCE_DIR}/test_buffer_stream.cpp
2374
2375=== modified file 'tests/integration-tests/compositor/test_buffer_stream.cpp'
2376--- tests/integration-tests/compositor/test_buffer_stream.cpp 2013-07-31 11:18:25 +0000
2377+++ tests/integration-tests/compositor/test_buffer_stream.cpp 2013-08-07 10:49:30 +0000
2378@@ -17,7 +17,6 @@
2379 */
2380
2381 #include "mir/compositor/buffer_stream_surfaces.h"
2382-#include "mir/compositor/swapper_factory.h"
2383 #include "mir/graphics/graphic_buffer_allocator.h"
2384 #include "src/server/compositor/switching_bundle.h"
2385
2386@@ -29,6 +28,7 @@
2387
2388 #include <thread>
2389 #include <chrono>
2390+#include <atomic>
2391
2392 namespace mc = mir::compositor;
2393 namespace mg = mir::graphics;
2394@@ -43,69 +43,95 @@
2395 struct BufferStreamTest : public ::testing::Test
2396 {
2397 BufferStreamTest()
2398- : buffer_stream{create_bundle()}
2399+ : nbuffers{3},
2400+ buffer_stream{create_bundle()}
2401 {
2402 }
2403
2404 std::shared_ptr<mc::BufferBundle> create_bundle()
2405 {
2406 auto allocator = std::make_shared<mtd::StubBufferAllocator>();
2407- auto factory = std::make_shared<mc::SwapperFactory>(allocator);
2408 mg::BufferProperties properties{geom::Size{380, 210},
2409 geom::PixelFormat::abgr_8888,
2410 mg::BufferUsage::hardware};
2411
2412- return std::make_shared<mc::SwitchingBundle>(factory, properties);
2413- }
2414-
2415- void terminate_child_thread(mt::Synchronizer& controller)
2416- {
2417- controller.ensure_child_is_waiting();
2418- controller.kill_thread();
2419- controller.activate_waiting_child();
2420- }
2421-
2422+ return std::make_shared<mc::SwitchingBundle>(nbuffers,
2423+ allocator,
2424+ properties);
2425+ }
2426+
2427+ const int nbuffers;
2428 mc::BufferStreamSurfaces buffer_stream;
2429- std::atomic<bool> client_thread_done;
2430 };
2431
2432-}
2433-
2434-TEST_F(BufferStreamTest, gives_same_back_buffer_until_one_is_released)
2435-{
2436- buffer_stream.secure_client_buffer().reset();
2437- buffer_stream.secure_client_buffer().reset();
2438+void sleep_one_frame()
2439+{
2440+ std::this_thread::sleep_for(std::chrono::milliseconds(16));
2441+}
2442+
2443+}
2444+
2445+TEST_F(BufferStreamTest, gives_same_back_buffer_until_more_available)
2446+{
2447+ auto client1 = buffer_stream.secure_client_buffer();
2448+ auto client1_id = client1->id();
2449+ client1.reset();
2450
2451 auto comp1 = buffer_stream.lock_compositor_buffer();
2452 auto comp2 = buffer_stream.lock_compositor_buffer();
2453
2454 EXPECT_EQ(comp1->id(), comp2->id());
2455+ EXPECT_EQ(comp1->id(), client1_id);
2456
2457 comp1.reset();
2458
2459+ buffer_stream.secure_client_buffer().reset();
2460+ sleep_one_frame();
2461 auto comp3 = buffer_stream.lock_compositor_buffer();
2462
2463- EXPECT_NE(comp2->id(), comp3->id());
2464-}
2465-
2466-TEST_F(BufferStreamTest, multiply_acquired_back_buffer_is_returned_to_client)
2467-{
2468- buffer_stream.secure_client_buffer().reset();
2469- buffer_stream.secure_client_buffer().reset();
2470-
2471- auto comp1 = buffer_stream.lock_compositor_buffer();
2472- auto comp2 = buffer_stream.lock_compositor_buffer();
2473-
2474- EXPECT_EQ(comp1->id(), comp2->id());
2475-
2476- auto comp_id = comp1->id();
2477-
2478- comp1.reset();
2479+ EXPECT_NE(client1_id, comp3->id());
2480+
2481 comp2.reset();
2482-
2483- auto client1 = buffer_stream.secure_client_buffer();
2484-
2485- EXPECT_EQ(comp_id, client1->id());
2486+ auto comp3_id = comp3->id();
2487+ comp3.reset();
2488+
2489+ auto comp4 = buffer_stream.lock_compositor_buffer();
2490+ EXPECT_EQ(comp3_id, comp4->id());
2491+}
2492+
2493+TEST_F(BufferStreamTest, gives_all_monitors_the_same_buffer)
2494+{
2495+ for (int i = 0; i < nbuffers - 1; i++)
2496+ buffer_stream.secure_client_buffer().reset();
2497+
2498+ auto first_monitor = buffer_stream.lock_compositor_buffer();
2499+ auto first_compositor_id = first_monitor->id();
2500+ first_monitor.reset();
2501+
2502+ for (int m = 0; m < 10; m++)
2503+ {
2504+ auto monitor = buffer_stream.lock_compositor_buffer();
2505+ ASSERT_EQ(first_compositor_id, monitor->id());
2506+ }
2507+}
2508+
2509+TEST_F(BufferStreamTest, gives_different_back_buffer_asap)
2510+{
2511+ if (nbuffers > 1)
2512+ {
2513+ buffer_stream.secure_client_buffer().reset();
2514+ auto comp1 = buffer_stream.lock_compositor_buffer();
2515+
2516+ sleep_one_frame();
2517+
2518+ buffer_stream.secure_client_buffer().reset();
2519+ auto comp2 = buffer_stream.lock_compositor_buffer();
2520+
2521+ EXPECT_NE(comp1->id(), comp2->id());
2522+
2523+ comp1.reset();
2524+ comp2.reset();
2525+ }
2526 }
2527
2528 TEST_F(BufferStreamTest, can_get_partly_released_back_buffer)
2529@@ -128,32 +154,42 @@
2530 namespace
2531 {
2532
2533-void client_request_loop(std::shared_ptr<mg::Buffer>& out_buffer,
2534- mt::SynchronizerSpawned& synchronizer,
2535- ms::BufferStream& stream)
2536+void client_loop(int nframes, ms::BufferStream& stream)
2537 {
2538- for(;;)
2539+ for (int f = 0; f < nframes; f++)
2540 {
2541- out_buffer = stream.secure_client_buffer();
2542+ auto out_buffer = stream.secure_client_buffer();
2543 ASSERT_NE(nullptr, out_buffer);
2544-
2545- if (synchronizer.child_enter_wait()) return;
2546-
2547- std::this_thread::yield();
2548- }
2549-}
2550-
2551-void back_buffer_loop(std::shared_ptr<mg::Buffer>& out_region,
2552- mt::SynchronizerSpawned& synchronizer,
2553- ms::BufferStream& stream)
2554-{
2555- for(;;)
2556- {
2557- out_region = stream.lock_compositor_buffer();
2558+ std::this_thread::yield();
2559+ }
2560+}
2561+
2562+void compositor_loop(ms::BufferStream &stream,
2563+ std::atomic<bool> &done)
2564+{
2565+ while (!done.load())
2566+ {
2567+ auto comp1 = stream.lock_compositor_buffer();
2568+ ASSERT_NE(nullptr, comp1);
2569+
2570+ // Also stress test getting a second compositor buffer before yielding
2571+ auto comp2 = stream.lock_compositor_buffer();
2572+ ASSERT_NE(nullptr, comp2);
2573+
2574+ std::this_thread::yield();
2575+
2576+ comp1.reset();
2577+ comp2.reset();
2578+ }
2579+}
2580+
2581+void snapshot_loop(ms::BufferStream &stream,
2582+ std::atomic<bool> &done)
2583+{
2584+ while (!done.load())
2585+ {
2586+ auto out_region = stream.lock_snapshot_buffer();
2587 ASSERT_NE(nullptr, out_region);
2588-
2589- if (synchronizer.child_enter_wait()) return;
2590-
2591 std::this_thread::yield();
2592 }
2593 }
2594@@ -162,72 +198,38 @@
2595
2596 TEST_F(BufferStreamTest, stress_test_distinct_buffers)
2597 {
2598- unsigned int const num_compositors{3};
2599- unsigned int const num_iterations{500};
2600- std::chrono::microseconds const sleep_duration{50};
2601-
2602- struct CompositorInfo
2603- {
2604- CompositorInfo(ms::BufferStream& stream)
2605- : thread{back_buffer_loop, std::ref(back_buffer),
2606- std::ref(sync), std::ref(stream)}
2607- {
2608- }
2609-
2610- mt::Synchronizer sync;
2611- std::shared_ptr<mg::Buffer> back_buffer;
2612- std::thread thread;
2613- };
2614-
2615- std::vector<std::unique_ptr<CompositorInfo>> compositors;
2616-
2617- mt::Synchronizer client_sync;
2618- std::shared_ptr<mg::Buffer> client_buffer;
2619- auto client_thread = std::thread(client_request_loop, std::ref(client_buffer),
2620- std::ref(client_sync), std::ref(buffer_stream));
2621-
2622- for (unsigned int i = 0; i < num_compositors; i++)
2623- {
2624- auto raw = new CompositorInfo{buffer_stream};
2625- compositors.push_back(std::unique_ptr<CompositorInfo>(raw));
2626- }
2627-
2628- for(unsigned int i = 0; i < num_iterations; i++)
2629- {
2630- /* Pause the threads */
2631- for (auto& info : compositors)
2632- {
2633- info->sync.ensure_child_is_waiting();
2634- }
2635- client_sync.ensure_child_is_waiting();
2636-
2637- /*
2638- * Check that no compositor has the client's buffer, and release
2639- * all the buffers.
2640- */
2641- for (auto& info : compositors)
2642- {
2643- EXPECT_NE(info->back_buffer->id(), client_buffer->id());
2644- info->back_buffer.reset();
2645- }
2646- client_buffer.reset();
2647-
2648- /* Restart threads */
2649- for (auto& info : compositors)
2650- {
2651- info->sync.activate_waiting_child();
2652- }
2653- client_sync.activate_waiting_child();
2654-
2655- std::this_thread::sleep_for(sleep_duration);
2656- }
2657-
2658- terminate_child_thread(client_sync);
2659- client_thread.join();
2660-
2661- for (auto& info : compositors)
2662- {
2663- terminate_child_thread(info->sync);
2664- info->thread.join();
2665- }
2666+ // More would be good, but armhf takes too long
2667+ const int num_snapshotters{2};
2668+ const int num_frames{200};
2669+
2670+ std::atomic<bool> done;
2671+ done = false;
2672+
2673+ std::thread client(client_loop,
2674+ num_frames,
2675+ std::ref(buffer_stream));
2676+
2677+ std::thread compositor(compositor_loop,
2678+ std::ref(buffer_stream),
2679+ std::ref(done));
2680+
2681+ std::vector<std::shared_ptr<std::thread>> snapshotters;
2682+ for (unsigned int i = 0; i < num_snapshotters; i++)
2683+ {
2684+ snapshotters.push_back(
2685+ std::make_shared<std::thread>(snapshot_loop,
2686+ std::ref(buffer_stream),
2687+ std::ref(done)));
2688+ }
2689+
2690+ client.join();
2691+
2692+ done = true;
2693+
2694+ buffer_stream.force_requests_to_complete();
2695+
2696+ compositor.join();
2697+
2698+ for (auto &s : snapshotters)
2699+ s->join();
2700 }
2701
2702=== removed file 'tests/integration-tests/compositor/test_stress_buffer_swapper.cpp'
2703--- tests/integration-tests/compositor/test_stress_buffer_swapper.cpp 2013-07-17 16:38:25 +0000
2704+++ tests/integration-tests/compositor/test_stress_buffer_swapper.cpp 1970-01-01 00:00:00 +0000
2705@@ -1,308 +0,0 @@
2706-/*
2707- * Copyright © 2012 Canonical Ltd.
2708- *
2709- * This program is free software: you can redistribute it and/or modify
2710- * it under the terms of the GNU General Public License version 3 as
2711- * published by the Free Software Foundation.
2712- *
2713- * This program is distributed in the hope that it will be useful,
2714- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2715- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2716- * GNU General Public License for more details.
2717- *
2718- * You should have received a copy of the GNU General Public License
2719- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2720- *
2721- * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
2722- */
2723-
2724-#include "mir_test_doubles/stub_buffer.h"
2725-#include "multithread_harness.h"
2726-
2727-#include "mir/compositor/buffer_swapper_multi.h"
2728-#include "mir/graphics/buffer_id.h"
2729-
2730-#include <thread>
2731-#include <chrono>
2732-
2733-namespace mc = mir::compositor;
2734-namespace mg = mir::graphics;
2735-namespace mt = mir::testing;
2736-namespace geom = mir::geometry;
2737-namespace mtd = mir::test::doubles;
2738-
2739-struct BufferSwapperStress : public ::testing::Test
2740-{
2741-public:
2742- BufferSwapperStress()
2743- : sleep_duration(50),
2744- num_iterations(500)
2745- {
2746- buffer_a = std::make_shared<mtd::StubBuffer>();
2747- buffer_b = std::make_shared<mtd::StubBuffer>();
2748- buffer_c = std::make_shared<mtd::StubBuffer>();
2749- }
2750-
2751- void terminate_child_thread(mt::Synchronizer& controller)
2752- {
2753- controller.ensure_child_is_waiting();
2754- controller.kill_thread();
2755- controller.activate_waiting_child();
2756- }
2757-
2758- mt::Synchronizer compositor_controller;
2759- mt::Synchronizer client_controller;
2760-
2761- std::chrono::microseconds const sleep_duration;
2762- int const num_iterations;
2763-
2764- std::thread thread1;
2765- std::thread thread2;
2766-
2767- void test_distinct_buffers(mc::BufferSwapper& swapper);
2768- void test_valid_buffers(mc::BufferSwapper& swapper);
2769- void test_wait_situation(std::vector<std::shared_ptr<mg::Buffer>>& compositor_output_buffers,
2770- std::vector<std::shared_ptr<mg::Buffer>>& client_output_buffers,
2771- mc::BufferSwapper& swapper,
2772- unsigned int number_of_client_requests_to_make);
2773- void test_last_posted(mc::BufferSwapper& swapper);
2774-
2775- std::shared_ptr<mg::Buffer> buffer_a;
2776- std::shared_ptr<mg::Buffer> buffer_b;
2777- std::shared_ptr<mg::Buffer> buffer_c;
2778-};
2779-
2780-void main_test_loop_pause(std::chrono::microseconds duration)
2781-{
2782- std::this_thread::sleep_for(duration);
2783-}
2784-
2785-void client_request_loop(std::shared_ptr<mg::Buffer>& out_buffer, mt::SynchronizerSpawned& synchronizer,
2786- mc::BufferSwapper& swapper)
2787-{
2788- for(;;)
2789- {
2790- out_buffer = swapper.client_acquire();
2791- EXPECT_NE(nullptr, out_buffer);
2792- if (synchronizer.child_enter_wait()) return;
2793-
2794- swapper.client_release(out_buffer);
2795- if (synchronizer.child_enter_wait()) return;
2796-
2797- std::this_thread::yield();
2798- }
2799-}
2800-
2801-void compositor_grab_loop(std::shared_ptr<mg::Buffer>& out_buffer, mt::SynchronizerSpawned& synchronizer,
2802- mc::BufferSwapper& swapper)
2803-{
2804- for(;;)
2805- {
2806- out_buffer = swapper.compositor_acquire();
2807- EXPECT_NE(nullptr, out_buffer);
2808- if (synchronizer.child_enter_wait()) return;
2809-
2810- swapper.compositor_release(out_buffer);
2811- if (synchronizer.child_enter_wait()) return;
2812- std::this_thread::yield();
2813- }
2814-}
2815-
2816-/* test that the compositor and the client are never in ownership of the same
2817- buffer */
2818-void BufferSwapperStress::test_distinct_buffers(mc::BufferSwapper& swapper)
2819-{
2820- std::shared_ptr<mg::Buffer> compositor_buffer;
2821- std::shared_ptr<mg::Buffer> client_buffer;
2822-
2823- thread1 = std::thread(compositor_grab_loop, std::ref(compositor_buffer),
2824- std::ref(compositor_controller), std::ref(swapper));
2825- thread2 = std::thread(client_request_loop, std::ref(client_buffer),
2826- std::ref(client_controller), std::ref(swapper));
2827-
2828- for(int i=0; i< num_iterations; i++)
2829- {
2830- compositor_controller.ensure_child_is_waiting();
2831- client_controller.ensure_child_is_waiting();
2832-
2833- EXPECT_NE(compositor_buffer, client_buffer);
2834-
2835- compositor_controller.activate_waiting_child();
2836- client_controller.activate_waiting_child();
2837-
2838- main_test_loop_pause(sleep_duration);
2839- }
2840-
2841- terminate_child_thread(client_controller);
2842- terminate_child_thread(compositor_controller);
2843- thread2.join();
2844- thread1.join();
2845-}
2846-
2847-TEST_F(BufferSwapperStress, distinct_and_valid_double_buffers_in_client_and_compositor)
2848-{
2849- auto double_list = std::vector<std::shared_ptr<mg::Buffer>>{buffer_a, buffer_b};
2850- mc::BufferSwapperMulti double_swapper(double_list, double_list.size());
2851- test_distinct_buffers(double_swapper);
2852-}
2853-TEST_F(BufferSwapperStress, distinct_and_valid_triple_buffers_in_client_and_compositor)
2854-{
2855- auto triple_list = std::vector<std::shared_ptr<mg::Buffer>>{buffer_a, buffer_b, buffer_c};
2856- mc::BufferSwapperMulti triple_swapper(triple_list, triple_list.size());
2857- test_distinct_buffers(triple_swapper);
2858-}
2859-
2860-void client_request_loop_finite(std::vector<std::shared_ptr<mg::Buffer>>& buffers,
2861- mt::SynchronizerSpawned& synchronizer,
2862- mc::BufferSwapper& swapper,
2863- int const number_of_requests_to_make)
2864-{
2865- for(auto i=0; i < number_of_requests_to_make; i++)
2866- {
2867- auto buffer = swapper.client_acquire();
2868- swapper.client_release(buffer);
2869- buffers.push_back(buffer);
2870- }
2871-
2872- synchronizer.child_enter_wait();
2873- synchronizer.child_enter_wait();
2874-}
2875-
2876-void compositor_grab(std::vector<std::shared_ptr<mg::Buffer>>& buffers,
2877- mt::SynchronizerSpawned& synchronizer,
2878- mc::BufferSwapper& swapper)
2879-{
2880- synchronizer.child_enter_wait();
2881-
2882- auto buffer = swapper.compositor_acquire();
2883- swapper.compositor_release(buffer);
2884- buffers.push_back(buffer);
2885-
2886- synchronizer.child_enter_wait();
2887-}
2888-
2889-void BufferSwapperStress::test_wait_situation(std::vector<std::shared_ptr<mg::Buffer>>& compositor_output_buffers,
2890- std::vector<std::shared_ptr<mg::Buffer>>& client_output_buffers,
2891- mc::BufferSwapper& swapper,
2892- unsigned int const number_of_client_requests_to_make)
2893-{
2894- thread1 = std::thread(compositor_grab, std::ref(compositor_output_buffers),
2895- std::ref(compositor_controller), std::ref(swapper));
2896- thread2 = std::thread(client_request_loop_finite, std::ref(client_output_buffers),
2897- std::ref(client_controller), std::ref(swapper), number_of_client_requests_to_make);
2898-
2899- compositor_controller.ensure_child_is_waiting();
2900-
2901- client_controller.ensure_child_is_waiting();
2902- client_controller.activate_waiting_child();
2903-
2904- compositor_controller.activate_waiting_child();
2905- compositor_controller.ensure_child_is_waiting();
2906-
2907- terminate_child_thread(client_controller);
2908- terminate_child_thread(compositor_controller);
2909- thread2.join();
2910- thread1.join();
2911-
2912- ASSERT_EQ(client_output_buffers.size(), number_of_client_requests_to_make);
2913- ASSERT_EQ(compositor_output_buffers.size(), static_cast<unsigned int>(1));
2914-}
2915-
2916-TEST_F(BufferSwapperStress, double_test_wait_situation)
2917-{
2918- std::vector<std::shared_ptr<mg::Buffer>> client_buffers;
2919- std::vector<std::shared_ptr<mg::Buffer>> compositor_buffers;
2920- /* a double buffered client should stall on the second request without the compositor running */
2921- auto double_list = std::vector<std::shared_ptr<mg::Buffer>>{buffer_a, buffer_b};
2922- mc::BufferSwapperMulti double_swapper(double_list, double_list.size());
2923- test_wait_situation(compositor_buffers, client_buffers, double_swapper, 2);
2924-
2925- EXPECT_EQ(client_buffers.at(0), compositor_buffers.at(0));
2926-}
2927-
2928-TEST_F(BufferSwapperStress, triple_test_wait_situation)
2929-{
2930- std::vector<std::shared_ptr<mg::Buffer>> client_buffers;
2931- std::vector<std::shared_ptr<mg::Buffer>> compositor_buffers;
2932- auto triple_list = std::vector<std::shared_ptr<mg::Buffer>>{buffer_a, buffer_b, buffer_c};
2933- mc::BufferSwapperMulti triple_swapper(triple_list, triple_list.size());
2934- /* a triple buffered client should stall on the third request without the compositor running */
2935- test_wait_situation(compositor_buffers, client_buffers, triple_swapper, 3);
2936-
2937- EXPECT_EQ(client_buffers.at(0), compositor_buffers.at(0));
2938-}
2939-
2940-void client_request_loop_with_wait(std::shared_ptr<mg::Buffer>& out_buffer, mt::SynchronizerSpawned& synchronizer,
2941- mc::BufferSwapper& swapper)
2942-{
2943- bool wait_request = false;
2944- for(;;)
2945- {
2946- wait_request = synchronizer.child_check_wait_request();
2947-
2948- out_buffer = swapper.client_acquire();
2949- swapper.client_release(out_buffer);
2950-
2951- if (wait_request)
2952- if (synchronizer.child_enter_wait()) return;
2953-
2954- std::this_thread::yield();
2955- }
2956-}
2957-
2958-void compositor_grab_loop_with_wait(std::shared_ptr<mg::Buffer>& out_buffer, mt::SynchronizerSpawned& synchronizer,
2959- mc::BufferSwapper& swapper)
2960-{
2961- std::shared_ptr<mg::Buffer> buffer_ref;
2962- bool wait_request = false;
2963- for(;;)
2964- {
2965- wait_request = synchronizer.child_check_wait_request();
2966-
2967- out_buffer = swapper.compositor_acquire();
2968- swapper.compositor_release(out_buffer);
2969-
2970- if (wait_request)
2971- {
2972- out_buffer = swapper.compositor_acquire();
2973- if (synchronizer.child_enter_wait()) return;
2974- swapper.compositor_release(out_buffer);
2975- }
2976-
2977- std::this_thread::yield();
2978- }
2979-}
2980-
2981-void BufferSwapperStress::test_last_posted(mc::BufferSwapper& swapper)
2982-{
2983- std::shared_ptr<mg::Buffer> compositor_buffer;
2984- std::shared_ptr<mg::Buffer> client_buffer;
2985-
2986- thread1 = std::thread(compositor_grab_loop_with_wait, std::ref(compositor_buffer), std::ref(compositor_controller), std::ref(swapper));
2987- thread2 = std::thread(client_request_loop_with_wait, std::ref(client_buffer), std::ref(client_controller), std::ref(swapper));
2988-
2989- for(int i=0; i< num_iterations; i++)
2990- {
2991- client_controller.ensure_child_is_waiting();
2992- compositor_controller.ensure_child_is_waiting();
2993-
2994- EXPECT_EQ(compositor_buffer, client_buffer);
2995-
2996- compositor_controller.activate_waiting_child();
2997- client_controller.activate_waiting_child();
2998-
2999- main_test_loop_pause(sleep_duration);
3000- }
3001-
3002- terminate_child_thread(client_controller);
3003- terminate_child_thread(compositor_controller);
3004- thread2.join();
3005- thread1.join();
3006-}
3007-
3008-TEST_F(BufferSwapperStress, double_test_last_posted)
3009-{
3010- auto double_list = std::vector<std::shared_ptr<mg::Buffer>>{buffer_a, buffer_b};
3011- mc::BufferSwapperMulti double_swapper(double_list, double_list.size());
3012- test_last_posted(double_swapper);
3013-}
3014
3015=== modified file 'tests/integration-tests/compositor/test_swapping_swappers.cpp'
3016--- tests/integration-tests/compositor/test_swapping_swappers.cpp 2013-07-31 11:18:25 +0000
3017+++ tests/integration-tests/compositor/test_swapping_swappers.cpp 2013-08-07 10:49:30 +0000
3018@@ -20,10 +20,7 @@
3019 #include "multithread_harness.h"
3020
3021 #include "src/server/compositor/switching_bundle.h"
3022-#include "mir/compositor/buffer_swapper_multi.h"
3023-#include "mir/compositor/buffer_swapper_spin.h"
3024 #include "mir/compositor/buffer_stream_surfaces.h"
3025-#include "mir/compositor/swapper_factory.h"
3026 #include "mir/graphics/graphic_buffer_allocator.h"
3027
3028 #include <gmock/gmock.h>
3029@@ -45,10 +42,10 @@
3030 void SetUp()
3031 {
3032 auto allocator = std::make_shared<mtd::StubBufferAllocator>();
3033- auto factory = std::make_shared<mc::SwapperFactory>(allocator, 3);
3034 auto properties = mg::BufferProperties{geom::Size{380, 210},
3035- geom::PixelFormat::abgr_8888, mg::BufferUsage::hardware};
3036- switching_bundle = std::make_shared<mc::SwitchingBundle>(factory, properties);
3037+ geom::PixelFormat::abgr_8888,
3038+ mg::BufferUsage::hardware};
3039+ switching_bundle = std::make_shared<mc::SwitchingBundle>(3, allocator, properties);
3040 }
3041
3042 std::shared_ptr<mc::SwitchingBundle> switching_bundle;
3043
3044=== modified file 'tests/integration-tests/graphics/android/test_buffer_integration.cpp'
3045--- tests/integration-tests/graphics/android/test_buffer_integration.cpp 2013-07-31 11:18:25 +0000
3046+++ tests/integration-tests/graphics/android/test_buffer_integration.cpp 2013-08-07 10:49:30 +0000
3047@@ -17,10 +17,9 @@
3048 */
3049
3050 #include "src/server/graphics/android/android_graphic_buffer_allocator.h"
3051+#include "src/server/compositor/switching_bundle.h"
3052 #include "mir/graphics/buffer_initializer.h"
3053 #include "mir/graphics/null_display_report.h"
3054-#include "mir/compositor/swapper_factory.h"
3055-#include "mir/compositor/buffer_swapper.h"
3056 #include "mir/graphics/buffer_properties.h"
3057
3058 #include "mir_test/draw/android_graphics.h"
3059@@ -89,10 +88,10 @@
3060 using namespace testing;
3061
3062 auto allocator = std::make_shared<mga::AndroidGraphicBufferAllocator>(null_buffer_initializer);
3063- auto strategy = std::make_shared<mc::SwapperFactory>(allocator);
3064- mg::BufferProperties actual;
3065- auto swapper = strategy->create_swapper_new_buffers(actual, buffer_properties, mc::SwapperType::synchronous);
3066- auto returned_buffer = swapper->client_acquire();
3067+
3068+ mc::SwitchingBundle swapper(2, allocator, buffer_properties);
3069+
3070+ auto returned_buffer = swapper.client_acquire();
3071
3072 EXPECT_NE(nullptr, returned_buffer);
3073 }
3074
3075=== modified file 'tests/integration-tests/graphics/android/test_internal_client.cpp'
3076--- tests/integration-tests/graphics/android/test_internal_client.cpp 2013-08-02 03:13:38 +0000
3077+++ tests/integration-tests/graphics/android/test_internal_client.cpp 2013-08-07 10:49:30 +0000
3078@@ -19,8 +19,6 @@
3079 #include "src/server/graphics/android/android_graphic_buffer_allocator.h"
3080 #include "src/server/graphics/android/internal_client_window.h"
3081 #include "src/server/graphics/android/interpreter_cache.h"
3082-#include "mir/compositor/swapper_factory.h"
3083-#include "mir/compositor/buffer_swapper.h"
3084 #include "mir/compositor/buffer_stream_factory.h"
3085 #include "mir/graphics/buffer_initializer.h"
3086 #include "mir/graphics/null_display_report.h"
3087@@ -105,8 +103,7 @@
3088 auto stub_input_registrar = std::make_shared<mtd::StubInputRegistrar>();
3089 auto null_buffer_initializer = std::make_shared<mg::NullBufferInitializer>();
3090 auto allocator = std::make_shared<mga::AndroidGraphicBufferAllocator>(null_buffer_initializer);
3091- auto strategy = std::make_shared<mc::SwapperFactory>(allocator);
3092- auto buffer_stream_factory = std::make_shared<mc::BufferStreamFactory>(strategy);
3093+ auto buffer_stream_factory = std::make_shared<mc::BufferStreamFactory>(allocator);
3094 auto surface_allocator = std::make_shared<ms::SurfaceAllocator>(buffer_stream_factory, stub_input_factory);
3095 auto ss = std::make_shared<ms::SurfaceStack>(surface_allocator, stub_input_registrar);
3096 auto surface_controller = std::make_shared<ms::SurfaceController>(ss);
3097
3098=== modified file 'tests/integration-tests/shell/test_session.cpp'
3099--- tests/integration-tests/shell/test_session.cpp 2013-08-01 08:24:23 +0000
3100+++ tests/integration-tests/shell/test_session.cpp 2013-08-07 10:49:30 +0000
3101@@ -184,6 +184,7 @@
3102 auto compositor = conf.the_compositor();
3103
3104 compositor->start();
3105+ session.default_surface()->allow_framedropping(true);
3106
3107 std::thread client_thread{
3108 [&session]
3109
3110=== modified file 'tests/integration-tests/shell/test_session_manager.cpp'
3111--- tests/integration-tests/shell/test_session_manager.cpp 2013-07-25 23:02:51 +0000
3112+++ tests/integration-tests/shell/test_session_manager.cpp 2013-08-07 10:49:30 +0000
3113@@ -25,7 +25,6 @@
3114 #include "mir/shell/null_session_listener.h"
3115 #include "mir/surfaces/buffer_stream.h"
3116 #include "mir/surfaces/surface.h"
3117-#include "mir/compositor/buffer_swapper.h"
3118 #include "mir/shell/surface_creation_parameters.h"
3119
3120 #include "mir_test/gmock_fixes.h"
3121
3122=== modified file 'tests/integration-tests/test_surfaceloop.cpp'
3123--- tests/integration-tests/test_surfaceloop.cpp 2013-07-31 11:18:25 +0000
3124+++ tests/integration-tests/test_surfaceloop.cpp 2013-08-07 10:49:30 +0000
3125@@ -17,9 +17,7 @@
3126 */
3127
3128 #include "mir/graphics/graphic_buffer_allocator.h"
3129-#include "mir/compositor/swapper_factory.h"
3130 #include "src/server/compositor/switching_bundle.h"
3131-#include "mir/compositor/buffer_swapper_multi.h"
3132 #include "mir/graphics/buffer_properties.h"
3133 #include "mir/graphics/buffer_id.h"
3134 #include "mir/graphics/buffer_basic.h"
3135@@ -29,7 +27,6 @@
3136
3137 #include "mir_test_framework/display_server_test_fixture.h"
3138 #include "mir_test_doubles/stub_buffer.h"
3139-#include "mir_test_doubles/mock_swapper_factory.h"
3140 #include "mir_test_doubles/null_platform.h"
3141 #include "mir_test_doubles/null_display.h"
3142 #include "mir_test_doubles/stub_display_buffer.h"
3143@@ -219,36 +216,7 @@
3144
3145 TEST_F(SurfaceLoop, creating_a_client_surface_allocates_buffer_swapper_on_server)
3146 {
3147- struct ServerConfig : TestingServerConfiguration
3148- {
3149- std::shared_ptr<mc::BufferAllocationStrategy> the_buffer_allocation_strategy()
3150- {
3151- using namespace testing;
3152-
3153- if (!buffer_allocation_strategy)
3154- {
3155- using testing::_;
3156- buffer_allocation_strategy = std::make_shared<mtd::MockSwapperFactory>();
3157-
3158- EXPECT_CALL(*buffer_allocation_strategy, create_swapper_new_buffers(_,_,_))
3159- .WillOnce(testing::Invoke(this, &ServerConfig::on_create_swapper));
3160- }
3161- return buffer_allocation_strategy;
3162- }
3163-
3164- std::shared_ptr<mc::BufferSwapper> on_create_swapper(mg::BufferProperties& actual,
3165- mg::BufferProperties const& requested,
3166- mc::SwapperType)
3167- {
3168- actual = requested;
3169- auto stub_buffer_a = std::make_shared<mtd::StubBuffer>(::buffer_properties);
3170- auto stub_buffer_b = std::make_shared<mtd::StubBuffer>(::buffer_properties);
3171- std::vector<std::shared_ptr<mg::Buffer>> list = {stub_buffer_a, stub_buffer_b};
3172- return std::make_shared<mc::BufferSwapperMulti>(list, list.size());
3173- }
3174-
3175- std::shared_ptr<mtd::MockSwapperFactory> buffer_allocation_strategy;
3176- } server_config;
3177+ TestingServerConfiguration server_config;
3178
3179 launch_server_process(server_config);
3180
3181@@ -316,10 +284,11 @@
3182 std::shared_ptr<mg::GraphicBufferAllocator> create_buffer_allocator(
3183 const std::shared_ptr<mg::BufferInitializer>& /*buffer_initializer*/) override
3184 {
3185- using testing::AtLeast;
3186+ using testing::AtMost;
3187
3188 auto buffer_allocator = std::make_shared<testing::NiceMock<MockGraphicBufferAllocator>>();
3189- EXPECT_CALL(*buffer_allocator, alloc_buffer(buffer_properties)).Times(AtLeast(2));
3190+ EXPECT_CALL(*buffer_allocator, alloc_buffer(buffer_properties))
3191+ .Times(AtMost(3));
3192 return buffer_allocator;
3193 }
3194
3195@@ -474,8 +443,8 @@
3196 {
3197 void on_exit() override
3198 {
3199- EXPECT_EQ(2*ClientConfigCommon::max_surface_count, CountingStubBuffer::buffers_created.load());
3200- EXPECT_EQ(2*ClientConfigCommon::max_surface_count, CountingStubBuffer::buffers_destroyed.load());
3201+ EXPECT_EQ(CountingStubBuffer::buffers_created.load(),
3202+ CountingStubBuffer::buffers_destroyed.load());
3203 }
3204
3205 } server_config;
3206@@ -523,8 +492,8 @@
3207 {
3208 void on_exit() override
3209 {
3210- EXPECT_EQ(2*ClientConfigCommon::max_surface_count, CountingStubBuffer::buffers_created.load());
3211- EXPECT_EQ(2*ClientConfigCommon::max_surface_count, CountingStubBuffer::buffers_destroyed.load());
3212+ EXPECT_EQ(CountingStubBuffer::buffers_created.load(),
3213+ CountingStubBuffer::buffers_destroyed.load());
3214 }
3215
3216 } server_config;
3217
3218=== modified file 'tests/unit-tests/compositor/CMakeLists.txt'
3219--- tests/unit-tests/compositor/CMakeLists.txt 2013-07-31 14:21:34 +0000
3220+++ tests/unit-tests/compositor/CMakeLists.txt 2013-08-07 10:49:30 +0000
3221@@ -1,16 +1,10 @@
3222 list(APPEND UNIT_TEST_SOURCES
3223 ${CMAKE_CURRENT_SOURCE_DIR}/test_default_display_buffer_compositor.cpp
3224 ${CMAKE_CURRENT_SOURCE_DIR}/test_buffer_stream.cpp
3225- ${CMAKE_CURRENT_SOURCE_DIR}/test_buffer_swapper.cpp
3226- ${CMAKE_CURRENT_SOURCE_DIR}/test_buffer_swapper_double.cpp
3227- ${CMAKE_CURRENT_SOURCE_DIR}/test_buffer_swapper_triple.cpp
3228- ${CMAKE_CURRENT_SOURCE_DIR}/test_buffer_swapper_spin_triple.cpp
3229 ${CMAKE_CURRENT_SOURCE_DIR}/test_temporary_buffers.cpp
3230- ${CMAKE_CURRENT_SOURCE_DIR}/test_swapper_factory.cpp
3231 ${CMAKE_CURRENT_SOURCE_DIR}/test_rendering_operator.cpp
3232 ${CMAKE_CURRENT_SOURCE_DIR}/test_multi_threaded_compositor.cpp
3233 ${CMAKE_CURRENT_SOURCE_DIR}/test_switching_bundle.cpp
3234- ${CMAKE_CURRENT_SOURCE_DIR}/test_rw_lock.cpp
3235 ${CMAKE_CURRENT_SOURCE_DIR}/test_gl_renderer.cpp
3236 )
3237
3238
3239=== modified file 'tests/unit-tests/compositor/test_buffer_stream.cpp'
3240--- tests/unit-tests/compositor/test_buffer_stream.cpp 2013-07-31 11:00:22 +0000
3241+++ tests/unit-tests/compositor/test_buffer_stream.cpp 2013-08-07 10:49:30 +0000
3242@@ -34,10 +34,14 @@
3243 class BufferStreamTest : public ::testing::Test
3244 {
3245 protected:
3246- virtual void SetUp()
3247+ BufferStreamTest()
3248 {
3249 mock_buffer = std::make_shared<mtd::StubBuffer>();
3250 mock_bundle = std::make_shared<mtd::MockBufferBundle>();
3251+
3252+ // Two of the tests care about this, the rest should not...
3253+ EXPECT_CALL(*mock_bundle, force_requests_to_complete())
3254+ .Times(::testing::AnyNumber());
3255 }
3256
3257 std::shared_ptr<mtd::StubBuffer> mock_buffer;
3258@@ -73,12 +77,20 @@
3259 TEST_F(BufferStreamTest, force_requests_to_complete)
3260 {
3261 EXPECT_CALL(*mock_bundle, force_requests_to_complete())
3262- .Times(1);
3263+ .Times(2); // Once explcit, once on destruction
3264
3265 mc::BufferStreamSurfaces buffer_stream(mock_bundle);
3266 buffer_stream.force_requests_to_complete();
3267 }
3268
3269+TEST_F(BufferStreamTest, requests_are_completed_before_destruction)
3270+{
3271+ EXPECT_CALL(*mock_bundle, force_requests_to_complete())
3272+ .Times(1);
3273+
3274+ mc::BufferStreamSurfaces buffer_stream(mock_bundle);
3275+}
3276+
3277 TEST_F(BufferStreamTest, get_buffer_for_compositor_handles_resources)
3278 {
3279 using namespace testing;
3280
3281=== removed file 'tests/unit-tests/compositor/test_buffer_swapper.cpp'
3282--- tests/unit-tests/compositor/test_buffer_swapper.cpp 2013-07-17 16:31:45 +0000
3283+++ tests/unit-tests/compositor/test_buffer_swapper.cpp 1970-01-01 00:00:00 +0000
3284@@ -1,156 +0,0 @@
3285-/*
3286- * Copyright © 2012 Canonical Ltd.
3287- *
3288- * This program is free software: you can redistribute it and/or modify
3289- * it under the terms of the GNU General Public License version 3 as
3290- * published by the Free Software Foundation.
3291- *
3292- * This program is distributed in the hope that it will be useful,
3293- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3294- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3295- * GNU General Public License for more details.
3296- *
3297- * You should have received a copy of the GNU General Public License
3298- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3299- *
3300- * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
3301- */
3302-
3303-#include "mir/compositor/buffer_swapper_multi.h"
3304-#include "mir_test_doubles/stub_buffer.h"
3305-#include <gmock/gmock.h>
3306-#include <gtest/gtest.h>
3307-
3308-namespace mc = mir::compositor;
3309-namespace mg = mir::graphics;
3310-namespace geom = mir::geometry;
3311-namespace mtd = mir::test::doubles;
3312-
3313-struct BufferSwapperConstruction : testing::Test
3314-{
3315- BufferSwapperConstruction()
3316- {
3317- buffer_a = std::make_shared<mtd::StubBuffer>();
3318- buffer_b = std::make_shared<mtd::StubBuffer>();
3319- buffer_c = std::make_shared<mtd::StubBuffer>();
3320- }
3321-
3322- std::shared_ptr<mg::Buffer> buffer_a;
3323- std::shared_ptr<mg::Buffer> buffer_b;
3324- std::shared_ptr<mg::Buffer> buffer_c;
3325-};
3326-
3327-TEST_F(BufferSwapperConstruction, basic_double_construction_vector)
3328-{
3329- std::vector<std::shared_ptr<mg::Buffer>> buffers{buffer_a, buffer_b, buffer_c};
3330-
3331- auto use_count_before_a = buffer_a.use_count();
3332- auto use_count_before_b = buffer_b.use_count();
3333- mc::BufferSwapperMulti swapper(buffers, buffers.size());
3334-
3335- EXPECT_EQ(buffer_a.use_count(), use_count_before_a + 1);
3336- EXPECT_EQ(buffer_b.use_count(), use_count_before_b + 1);
3337-
3338- /* just to keep ref */
3339- swapper.force_client_abort();
3340-}
3341-
3342-TEST_F(BufferSwapperConstruction, basic_double_construction_initializer)
3343-{
3344- std::vector<std::shared_ptr<mg::Buffer>> buffers{buffer_a, buffer_b};
3345-
3346- auto use_count_before_a = buffer_a.use_count();
3347- auto use_count_before_b = buffer_b.use_count();
3348-
3349- mc::BufferSwapperMulti swapper(buffers, buffers.size());
3350-
3351- EXPECT_EQ(buffer_a.use_count(), use_count_before_a + 1);
3352- EXPECT_EQ(buffer_b.use_count(), use_count_before_b + 1);
3353-
3354- /* just to keep ref */
3355- swapper.force_client_abort();
3356-}
3357-
3358-TEST_F(BufferSwapperConstruction, basic_triple_construction_initializer)
3359-{
3360- std::vector<std::shared_ptr<mg::Buffer>> buffers{buffer_a, buffer_b, buffer_c};
3361- auto use_count_before_a = buffer_a.use_count();
3362- auto use_count_before_b = buffer_b.use_count();
3363- auto use_count_before_c = buffer_c.use_count();
3364- mc::BufferSwapperMulti swapper(buffers, buffers.size());
3365-
3366- EXPECT_EQ(buffer_a.use_count(), use_count_before_a + 1);
3367- EXPECT_EQ(buffer_b.use_count(), use_count_before_b + 1);
3368- EXPECT_EQ(buffer_c.use_count(), use_count_before_c + 1);
3369-
3370- /* just to keep ref */
3371- swapper.force_client_abort();
3372-}
3373-
3374-TEST_F(BufferSwapperConstruction, buffers_out_come_from_init_double)
3375-{
3376- std::vector<std::shared_ptr<mg::Buffer>> buffers{buffer_a, buffer_b};
3377- mc::BufferSwapperMulti swapper(buffers, buffers.size());
3378-
3379- auto buffer_1 = swapper.compositor_acquire();
3380- auto buffer_2 = swapper.client_acquire();
3381- /* swapper is now 'empty' */
3382-
3383- EXPECT_TRUE((buffer_a == buffer_1) || (buffer_b == buffer_1) );
3384- EXPECT_TRUE((buffer_a == buffer_2) || (buffer_b == buffer_2) );
3385-}
3386-
3387-TEST_F(BufferSwapperConstruction, buffers_out_come_from_init_triple)
3388-{
3389- std::vector<std::shared_ptr<mg::Buffer>> buffers{buffer_a, buffer_b, buffer_c};
3390- mc::BufferSwapperMulti swapper(buffers, buffers.size());
3391-
3392- auto buffer_1 = swapper.compositor_acquire();
3393- auto buffer_2 = swapper.client_acquire();
3394- swapper.client_release(buffer_2);
3395- auto buffer_3 = swapper.client_acquire();
3396- /* swapper is now 'empty' */
3397-
3398- EXPECT_TRUE((buffer_a == buffer_1) || (buffer_b == buffer_1) || (buffer_c == buffer_1));
3399- EXPECT_TRUE((buffer_a == buffer_2) || (buffer_b == buffer_2) || (buffer_c == buffer_2));
3400- EXPECT_TRUE((buffer_a == buffer_3) || (buffer_b == buffer_3) || (buffer_c == buffer_3));
3401-}
3402-
3403-
3404-TEST_F(BufferSwapperConstruction, buffer_transfer_triple_all_owned)
3405-{
3406- std::vector<std::shared_ptr<mg::Buffer>> buffers{buffer_a, buffer_b, buffer_c};
3407- mc::BufferSwapperMulti swapper(buffers, buffers.size());
3408-
3409- size_t test_size;
3410- std::vector<std::shared_ptr<mg::Buffer>> list;
3411- swapper.end_responsibility(list, test_size);
3412-
3413- auto res1 = std::find(list.begin(), list.end(), buffer_a);
3414- auto res2 = std::find(list.begin(), list.end(), buffer_b);
3415- auto res3 = std::find(list.begin(), list.end(), buffer_c);
3416- EXPECT_EQ(3u, list.size());
3417- EXPECT_NE(list.end(), res1);
3418- EXPECT_NE(list.end(), res2);
3419- EXPECT_NE(list.end(), res3);
3420-
3421- EXPECT_EQ(3u, test_size);
3422-}
3423-
3424-TEST_F(BufferSwapperConstruction, buffer_transfer_triple_some_not_owned)
3425-{
3426- std::vector<std::shared_ptr<mg::Buffer>> buffers{buffer_a, buffer_b, buffer_c};
3427- mc::BufferSwapperMulti swapper(buffers, buffers.size());
3428-
3429- auto acquired_buffer = swapper.client_acquire();
3430-
3431- size_t test_size;
3432- std::vector<std::shared_ptr<mg::Buffer>> list;
3433- swapper.end_responsibility(list, test_size);
3434-
3435- auto res1 = std::find(list.begin(), list.end(), acquired_buffer);
3436- EXPECT_EQ(2u, list.size());
3437- EXPECT_EQ(list.end(), res1); //acquired_buffer should not be in list
3438-
3439- EXPECT_EQ(3u, test_size);
3440-}
3441
3442=== removed file 'tests/unit-tests/compositor/test_buffer_swapper_double.cpp'
3443--- tests/unit-tests/compositor/test_buffer_swapper_double.cpp 2013-07-17 16:38:25 +0000
3444+++ tests/unit-tests/compositor/test_buffer_swapper_double.cpp 1970-01-01 00:00:00 +0000
3445@@ -1,207 +0,0 @@
3446-/*
3447- * Copyright © 2012, 2013 Canonical Ltd.
3448- *
3449- * This program is free software: you can redistribute it and/or modify
3450- * it under the terms of the GNU General Public License version 3 as
3451- * published by the Free Software Foundation.
3452- *
3453- * This program is distributed in the hope that it will be useful,
3454- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3455- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3456- * GNU General Public License for more details.
3457- *
3458- * You should have received a copy of the GNU General Public License
3459- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3460- *
3461- * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
3462- */
3463-
3464-
3465-#include "mir_test_doubles/stub_buffer.h"
3466-
3467-#include "mir/compositor/buffer_swapper_multi.h"
3468-#include "mir/graphics/buffer_id.h"
3469-
3470-#include <gmock/gmock.h>
3471-#include <gtest/gtest.h>
3472-
3473-#include <future>
3474-#include <thread>
3475-
3476-namespace mc = mir::compositor;
3477-namespace mg = mir::graphics;
3478-namespace geom = mir::geometry;
3479-namespace mtd = mir::test::doubles;
3480-
3481-namespace
3482-{
3483-struct BufferSwapperDouble : testing::Test
3484-{
3485- void SetUp()
3486- {
3487- buffer_a = std::make_shared<mtd::StubBuffer>();
3488- buffer_b = std::make_shared<mtd::StubBuffer>();
3489-
3490- auto double_list = std::vector<std::shared_ptr<mg::Buffer>>{buffer_a, buffer_b};
3491- swapper = std::make_shared<mc::BufferSwapperMulti>(double_list, double_list.size());
3492-
3493- }
3494-
3495- std::shared_ptr<mg::Buffer> buffer_a;
3496- std::shared_ptr<mg::Buffer> buffer_b;
3497-
3498- std::shared_ptr<mc::BufferSwapper> swapper;
3499-};
3500-
3501-}
3502-
3503-TEST_F(BufferSwapperDouble, test_valid_buffer_returned)
3504-{
3505- auto buffer = swapper->client_acquire();
3506-
3507- EXPECT_TRUE((buffer == buffer_a) || (buffer == buffer_b));
3508-}
3509-
3510-TEST_F(BufferSwapperDouble, test_valid_and_unique_with_two_acquires)
3511-{
3512- auto buffer_1 = swapper->client_acquire();
3513- swapper->client_release(buffer_1);
3514-
3515- auto buffer_tmp = swapper->compositor_acquire();
3516- swapper->compositor_release(buffer_tmp);
3517-
3518- auto buffer_2 = swapper->client_acquire();
3519- swapper->client_release(buffer_2);
3520-
3521- EXPECT_NE(buffer_1, buffer_2);
3522-
3523- EXPECT_TRUE((buffer_1 == buffer_a) || (buffer_1 == buffer_b));
3524- EXPECT_TRUE((buffer_2 == buffer_a) || (buffer_2 == buffer_b));
3525-}
3526-
3527-TEST_F(BufferSwapperDouble, test_compositor_gets_valid)
3528-{
3529- auto buffer = swapper->compositor_acquire();
3530- EXPECT_TRUE((buffer == buffer_a) || (buffer == buffer_b));
3531-}
3532-
3533-TEST_F(BufferSwapperDouble, test_compositor_gets_last_posted)
3534-{
3535- auto buffer_1 = swapper->client_acquire();
3536- swapper->client_release(buffer_1);
3537-
3538- auto buffer_2 = swapper->compositor_acquire();
3539- swapper->compositor_release(buffer_2);
3540-
3541- EXPECT_EQ(buffer_1, buffer_2);
3542-}
3543-
3544-TEST_F(BufferSwapperDouble, test_two_grabs_without_a_client_release)
3545-{
3546- swapper->client_acquire();
3547-
3548- auto buffer_1 = swapper->compositor_acquire();
3549- swapper->compositor_release(buffer_1);
3550-
3551- auto buffer_2 = swapper->compositor_acquire();
3552- EXPECT_EQ(buffer_1, buffer_2);
3553-}
3554-
3555-TEST_F(BufferSwapperDouble, test_client_and_compositor_advance_buffers_in_serial_pattern)
3556-{
3557- auto buffer_1 = swapper->client_acquire();
3558- swapper->client_release(buffer_1);
3559-
3560- auto buffer_2 = swapper->compositor_acquire();
3561- swapper->compositor_release(buffer_2);
3562-
3563- auto buffer_3 = swapper->client_acquire();
3564- swapper->client_release(buffer_3);
3565-
3566- auto buffer_4 = swapper->compositor_acquire();
3567-
3568- EXPECT_NE(buffer_1, buffer_3);
3569- EXPECT_NE(buffer_2, buffer_4);
3570-}
3571-
3572-TEST_F(BufferSwapperDouble, force_client_abort_works_causes_rc_failure)
3573-{
3574- auto client_buffer = swapper->client_acquire();
3575- swapper->client_release(client_buffer);
3576-
3577- client_buffer = swapper->client_acquire();
3578- swapper->client_release(client_buffer);
3579-
3580- /*
3581- * Unblock the the upcoming client_acquire() call. There is no guarantee
3582- * that force_client_abort will run after client_acquire() is
3583- * blocked, but it doesn't matter. As long as the client uses only one
3584- * buffer at a time, BufferSwapperMulti::force_client_abort() ensures
3585- * that either a currently blocked request will unblock, or the next
3586- * request will not block.
3587- */
3588- auto f = std::async(std::launch::async,
3589- [this]
3590- {
3591- std::this_thread::sleep_for(std::chrono::milliseconds{10});
3592- swapper->force_client_abort();
3593- });
3594-
3595- EXPECT_THROW({
3596- swapper->client_acquire();
3597- }, std::runtime_error);
3598-}
3599-
3600-TEST_F(BufferSwapperDouble, force_client_abort_works)
3601-{
3602- swapper->client_acquire();
3603-
3604- auto f = std::async(std::launch::async,
3605- [this]
3606- {
3607- std::this_thread::sleep_for(std::chrono::milliseconds{10});
3608- swapper->force_client_abort();
3609- });
3610-
3611- EXPECT_THROW({
3612- swapper->client_acquire();
3613- }, std::runtime_error);
3614-}
3615-
3616-TEST_F(BufferSwapperDouble, force_requests_to_complete_works)
3617-{
3618- auto client_buffer = swapper->client_acquire();
3619- swapper->client_release(client_buffer);
3620-
3621- /*
3622- * Unblock the the upcoming client_acquire() call. There is no guarantee
3623- * that force_requests_to_complete will run after client_acquire() is
3624- * blocked, but it doesn't matter. As long as the client uses only one
3625- * buffer at a time, BufferSwapperMulti::force_requests_to_complete() ensures
3626- * that either a currently blocked request will unblock, or the next
3627- * request will not block.
3628- */
3629- auto f = std::async(std::launch::async,
3630- [this]
3631- {
3632- std::this_thread::sleep_for(std::chrono::milliseconds{10});
3633- swapper->force_requests_to_complete();
3634- });
3635-
3636- client_buffer = swapper->client_acquire();
3637-
3638- EXPECT_NE(nullptr, client_buffer);
3639-}
3640-
3641-TEST_F(BufferSwapperDouble, force_requests_to_complete_throws_if_all_buffers_are_acquired)
3642-{
3643- auto client_buffer = swapper->client_acquire();
3644- swapper->client_release(client_buffer);
3645-
3646- client_buffer = swapper->client_acquire();
3647- auto comp_buffer = swapper->compositor_acquire();
3648-
3649- EXPECT_THROW({
3650- swapper->force_requests_to_complete();
3651- }, std::logic_error);
3652-}
3653
3654=== removed file 'tests/unit-tests/compositor/test_buffer_swapper_spin_triple.cpp'
3655--- tests/unit-tests/compositor/test_buffer_swapper_spin_triple.cpp 2013-07-17 16:31:45 +0000
3656+++ tests/unit-tests/compositor/test_buffer_swapper_spin_triple.cpp 1970-01-01 00:00:00 +0000
3657@@ -1,213 +0,0 @@
3658-/*
3659- * Copyright © 2013 Canonical Ltd.
3660- *
3661- * This program is free software: you can redistribute it and/or modify
3662- * it under the terms of the GNU General Public License version 3 as
3663- * published by the Free Software Foundation.
3664- *
3665- * This program is distributed in the hope that it will be useful,
3666- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3667- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3668- * GNU General Public License for more details.
3669- *
3670- * You should have received a copy of the GNU General Public License
3671- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3672- *
3673- * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
3674- */
3675-
3676-#include "mir/compositor/buffer_swapper_spin.h"
3677-
3678-#include "mir_test_doubles/stub_buffer.h"
3679-#include "mir_test_doubles/mock_swapper.h"
3680-
3681-#include <gtest/gtest.h>
3682-
3683-#include <algorithm>
3684-
3685-namespace mc = mir::compositor;
3686-namespace mg = mir::graphics;
3687-namespace mtd = mir::test::doubles;
3688-
3689-namespace
3690-{
3691-
3692-struct BufferSwapperSpinTriple : testing::Test
3693-{
3694- BufferSwapperSpinTriple()
3695- : buffer_a{std::make_shared<mtd::StubBuffer>()},
3696- buffer_b{std::make_shared<mtd::StubBuffer>()},
3697- buffer_c{std::make_shared<mtd::StubBuffer>()}
3698- {
3699- auto list = std::vector<std::shared_ptr<mg::Buffer>>{buffer_a, buffer_b, buffer_c};
3700- swapper = std::make_shared<mc::BufferSwapperSpin>(list, list.size());
3701- }
3702-
3703- std::shared_ptr<mg::Buffer> const buffer_a;
3704- std::shared_ptr<mg::Buffer> const buffer_b;
3705- std::shared_ptr<mg::Buffer> const buffer_c;
3706-
3707- std::shared_ptr<mc::BufferSwapper> swapper;
3708-};
3709-
3710-}
3711-
3712-TEST_F(BufferSwapperSpinTriple, client_can_always_get_new_buffer)
3713-{
3714- std::vector<std::shared_ptr<mg::Buffer>> expected_buffers;
3715-
3716- for (unsigned int i = 0; i < 10; i++)
3717- {
3718- auto buf = swapper->client_acquire();
3719-
3720- /* Check that the client doesn't reuse a buffer until there is no choice */
3721- if (expected_buffers.empty())
3722- {
3723- expected_buffers.push_back(buffer_a);
3724- expected_buffers.push_back(buffer_b);
3725- expected_buffers.push_back(buffer_c);
3726- }
3727-
3728- auto buf_iter = std::find(expected_buffers.begin(), expected_buffers.end(), buf);
3729- bool acquired_buf_in_expected_buffers = (buf_iter != expected_buffers.end());
3730-
3731- EXPECT_TRUE(acquired_buf_in_expected_buffers) << "buf: " << buf;
3732-
3733- if (acquired_buf_in_expected_buffers)
3734- expected_buffers.erase(buf_iter);
3735-
3736- swapper->client_release(buf);
3737- }
3738-}
3739-
3740-TEST_F(BufferSwapperSpinTriple, client_can_always_get_new_buffer_while_compositor_has_one)
3741-{
3742- std::vector<std::shared_ptr<mg::Buffer>> expected_buffers;
3743-
3744- auto comp_buf = swapper->compositor_acquire();
3745-
3746- for (unsigned int i = 0; i < 10; i++)
3747- {
3748- auto buf = swapper->client_acquire();
3749-
3750- /* Check that the client doesn't reuse a buffer until there is no choice */
3751- if (expected_buffers.empty())
3752- {
3753- if (comp_buf != buffer_a)
3754- expected_buffers.push_back(buffer_a);
3755- if (comp_buf != buffer_b)
3756- expected_buffers.push_back(buffer_b);
3757- if (comp_buf != buffer_c)
3758- expected_buffers.push_back(buffer_c);
3759- }
3760-
3761- auto buf_iter = std::find(expected_buffers.begin(), expected_buffers.end(), buf);
3762- bool acquired_buf_in_expected_buffers = (buf_iter != expected_buffers.end());
3763-
3764- EXPECT_TRUE(acquired_buf_in_expected_buffers) << "buf: " << buf;
3765-
3766- if (acquired_buf_in_expected_buffers)
3767- expected_buffers.erase(buf_iter);
3768-
3769- swapper->client_release(buf);
3770- }
3771-
3772- swapper->compositor_release(comp_buf);
3773-}
3774-
3775-TEST_F(BufferSwapperSpinTriple, compositor_gets_last_posted_client_buffer)
3776-{
3777- auto buf_a = swapper->client_acquire();
3778- swapper->client_release(buf_a);
3779-
3780- auto comp_buf1 = swapper->compositor_acquire();
3781- swapper->compositor_release(comp_buf1);
3782-
3783- EXPECT_EQ(buf_a, comp_buf1);
3784-
3785- auto comp_buf2 = swapper->compositor_acquire();
3786- swapper->compositor_release(comp_buf2);
3787-
3788- EXPECT_EQ(buf_a, comp_buf2);
3789-}
3790-
3791-TEST_F(BufferSwapperSpinTriple, compositor_gets_last_posted_client_buffer_interleaved)
3792-{
3793- auto buf_a = swapper->client_acquire();
3794- swapper->client_release(buf_a);
3795-
3796- auto comp_buf1 = swapper->compositor_acquire();
3797-
3798- auto buf_b = swapper->client_acquire();
3799- swapper->client_release(buf_b);
3800-
3801- swapper->compositor_release(comp_buf1);
3802-
3803- EXPECT_EQ(buf_a, comp_buf1);
3804-
3805- auto comp_buf2 = swapper->compositor_acquire();
3806- swapper->compositor_release(comp_buf2);
3807-
3808- EXPECT_EQ(buf_b, comp_buf2);
3809-}
3810-
3811-TEST_F(BufferSwapperSpinTriple, compositor_release_makes_buffer_available_to_client)
3812-{
3813- auto comp_buf = swapper->compositor_acquire();
3814-
3815- /* Check that the compositor's buffer is not available to the client */
3816- for (auto i = 0; i < 3; i++)
3817- {
3818- auto buf = swapper->client_acquire();
3819- EXPECT_NE(comp_buf, buf);
3820- swapper->client_release(buf);
3821- }
3822-
3823- swapper->compositor_release(comp_buf);
3824-
3825- /* After the release, the compositor's buffer should be available to the client */
3826- std::vector<std::shared_ptr<mg::Buffer>> client_buffers;
3827-
3828- for (auto i = 0; i < 3; i++)
3829- {
3830- auto buf = swapper->client_acquire();
3831- client_buffers.push_back(buf);
3832- swapper->client_release(buf);
3833- }
3834-
3835- EXPECT_TRUE(client_buffers[0] == comp_buf ||
3836- client_buffers[1] == comp_buf ||
3837- client_buffers[2] == comp_buf);
3838-}
3839-
3840-TEST_F(BufferSwapperSpinTriple, buffer_transfer_triple_all_owned)
3841-{
3842- size_t test_size;
3843- std::vector<std::shared_ptr<mg::Buffer>> list;
3844- swapper->end_responsibility(list, test_size);
3845-
3846- auto res1 = std::find(list.begin(), list.end(), buffer_a);
3847- auto res2 = std::find(list.begin(), list.end(), buffer_b);
3848- auto res3 = std::find(list.begin(), list.end(), buffer_c);
3849- EXPECT_EQ(3u, list.size());
3850- EXPECT_NE(list.end(), res1);
3851- EXPECT_NE(list.end(), res2);
3852- EXPECT_NE(list.end(), res3);
3853-
3854- EXPECT_EQ(3u, test_size);
3855-}
3856-
3857-TEST_F(BufferSwapperSpinTriple, buffer_transfer_triple_some_not_owned)
3858-{
3859- auto acquired_buffer = swapper->client_acquire();
3860-
3861- size_t test_size;
3862- std::vector<std::shared_ptr<mg::Buffer>> list;
3863- swapper->end_responsibility(list, test_size);
3864-
3865- auto res1 = std::find(list.begin(), list.end(), acquired_buffer);
3866- EXPECT_EQ(2u, list.size());
3867- EXPECT_EQ(list.end(), res1); //acquired_buffer should not be in list
3868-
3869- EXPECT_EQ(3u, test_size);
3870-}
3871
3872=== removed file 'tests/unit-tests/compositor/test_buffer_swapper_triple.cpp'
3873--- tests/unit-tests/compositor/test_buffer_swapper_triple.cpp 2013-07-17 16:38:25 +0000
3874+++ tests/unit-tests/compositor/test_buffer_swapper_triple.cpp 1970-01-01 00:00:00 +0000
3875@@ -1,125 +0,0 @@
3876-/*
3877- * Copyright © 2012, 2013 Canonical Ltd.
3878- *
3879- * This program is free software: you can redistribute it and/or modify
3880- * it under the terms of the GNU General Public License version 3 as
3881- * published by the Free Software Foundation.
3882- *
3883- * This program is distributed in the hope that it will be useful,
3884- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3885- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3886- * GNU General Public License for more details.
3887- *
3888- * You should have received a copy of the GNU General Public License
3889- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3890- *
3891- * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
3892- */
3893-
3894-#include "mir_test_doubles/stub_buffer.h"
3895-
3896-#include "mir/compositor/buffer_swapper_multi.h"
3897-#include "mir/graphics/buffer_id.h"
3898-
3899-#include <gmock/gmock.h>
3900-#include <gtest/gtest.h>
3901-
3902-namespace mc = mir::compositor;
3903-namespace mg = mir::graphics;
3904-namespace geom = mir::geometry;
3905-namespace mtd = mir::test::doubles;
3906-namespace
3907-{
3908-
3909-struct BufferSwapperTriple : testing::Test
3910-{
3911- void SetUp()
3912- {
3913- buffer_a = std::make_shared<mtd::StubBuffer>();
3914- buffer_b = std::make_shared<mtd::StubBuffer>();
3915- buffer_c = std::make_shared<mtd::StubBuffer>();
3916-
3917- auto triple_list = std::vector<std::shared_ptr<mg::Buffer>>{buffer_a, buffer_b, buffer_c};
3918- swapper = std::make_shared<mc::BufferSwapperMulti>(triple_list, triple_list.size());
3919-
3920- }
3921-
3922- std::shared_ptr<mg::Buffer> buffer_a;
3923- std::shared_ptr<mg::Buffer> buffer_b;
3924- std::shared_ptr<mg::Buffer> buffer_c;
3925-
3926- std::shared_ptr<mc::BufferSwapper> swapper;
3927-};
3928-
3929-}
3930-
3931-TEST_F(BufferSwapperTriple, test_valid_buffer_returned)
3932-{
3933- auto buf = swapper->client_acquire();
3934-
3935- EXPECT_TRUE((buf == buffer_a) || (buf == buffer_b) || (buf = buffer_c));
3936-}
3937-
3938-TEST_F(BufferSwapperTriple, test_valid_and_unique_with_two_acquires)
3939-{
3940- auto buffer_1 = swapper->client_acquire();
3941- swapper->client_release(buffer_1);
3942-
3943- //just so one thread operation is ok
3944- auto buffer_tmp = swapper->compositor_acquire();
3945- swapper->compositor_release(buffer_tmp);
3946-
3947- auto buffer_2 = swapper->client_acquire();
3948- swapper->client_release(buffer_2);
3949-
3950- auto buffer_3 = swapper->client_acquire();
3951- swapper->client_release(buffer_3);
3952-
3953- EXPECT_NE(buffer_1, buffer_2);
3954- EXPECT_NE(buffer_1, buffer_3);
3955- EXPECT_NE(buffer_2, buffer_3);
3956-}
3957-
3958-TEST_F(BufferSwapperTriple, test_compositor_gets_clients_last_buffer)
3959-{
3960- auto buffer_a = swapper->client_acquire();
3961- swapper->client_release(buffer_a);
3962-
3963- auto comp_buffer = swapper->compositor_acquire();
3964- EXPECT_EQ(buffer_a, comp_buffer);
3965-}
3966-
3967-/* this would stall a double buffer */
3968-TEST_F(BufferSwapperTriple, test_client_can_get_two_buffers_without_compositor_consuming_two_buffers)
3969-{
3970- auto buffer_1 = swapper->compositor_acquire();
3971-
3972- auto buffer_2 = swapper->client_acquire();
3973- swapper->client_release(buffer_2);
3974-
3975- auto buffer_3 = swapper->client_acquire();
3976- swapper->client_release(buffer_3);
3977-
3978- EXPECT_NE(buffer_2, buffer_3);
3979-}
3980-
3981-TEST_F(BufferSwapperTriple, test_compositor_gets_last_posted_in_order)
3982-{
3983- auto first_comp_buffer = swapper->compositor_acquire();
3984-
3985- auto first_client_buffer = swapper->client_acquire();
3986- swapper->client_release(first_client_buffer);
3987-
3988- auto second_client_buffer = swapper->client_acquire();
3989- swapper->client_release(second_client_buffer);
3990-
3991- swapper->compositor_release(first_comp_buffer);
3992-
3993- auto second_comp_buffer = swapper->compositor_acquire();
3994- swapper->compositor_release(second_comp_buffer);
3995-
3996- auto third_comp_buffer = swapper->compositor_acquire();
3997-
3998- EXPECT_EQ(second_comp_buffer, first_client_buffer);
3999- EXPECT_EQ(third_comp_buffer, second_client_buffer);
4000-}
4001
4002=== removed file 'tests/unit-tests/compositor/test_rw_lock.cpp'
4003--- tests/unit-tests/compositor/test_rw_lock.cpp 2013-06-07 15:23:27 +0000
4004+++ tests/unit-tests/compositor/test_rw_lock.cpp 1970-01-01 00:00:00 +0000
4005@@ -1,173 +0,0 @@
4006-/*
4007- * Copyright © 2012 Canonical Ltd.
4008- *
4009- * This program is free software: you can redistribute it and/or modify
4010- * it under the terms of the GNU General Public License version 3 as
4011- * published by the Free Software Foundation.
4012- *
4013- * This program is distributed in the hope that it will be useful,
4014- * but WITHOUT ANY WARRANTY; without even the implied warranty of
4015- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4016- * GNU General Public License for more details.
4017- *
4018- * You should have received a copy of the GNU General Public License
4019- * along with this program. If not, see <http://www.gnu.org/licenses/>.
4020- *
4021- * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
4022- */
4023-
4024-#include "src/server/compositor/rw_lock.h"
4025-#include <gtest/gtest.h>
4026-#include <vector>
4027-#include <future>
4028-#include <thread>
4029-
4030-namespace mc=mir::compositor;
4031-TEST(RWLockWriterBiasTest, multi_readers_dont_block)
4032-{
4033- int const num_asyncs = 33;
4034-
4035- mc::RWLockWriterBias lock;
4036- int locked_value = 45;
4037-
4038- std::vector<std::future<int>> asyncs;
4039-
4040- {
4041- std::unique_lock<mc::ReadLock> lk(lock);
4042- for(auto i = 0; i < num_asyncs; i++)
4043- {
4044- asyncs.push_back(std::async(std::launch::async,
4045- [&]
4046- {
4047- std::unique_lock<mc::ReadLock> lk(lock);
4048- return locked_value;
4049- }));
4050- }
4051-
4052- for(auto& i : asyncs)
4053- {
4054- i.wait();
4055- }
4056- }
4057-
4058- for(auto& i : asyncs)
4059- {
4060- EXPECT_EQ(locked_value, i.get());
4061- }
4062-}
4063-
4064-TEST(RWLockWriterBiasTest, multi_writers)
4065-{
4066- int const num_asyncs = 10, num_loops = 100;
4067-
4068- mc::RWLockWriterBias lock;
4069- int locked_value = 0;
4070-
4071- std::vector<std::future<void>> asyncs;
4072- for(auto i = 0; i < num_asyncs; i++)
4073- {
4074- asyncs.push_back(std::async(std::launch::async,
4075- [&]
4076- {
4077- std::unique_lock<mc::WriteLock> lk(lock);
4078- for(auto j=0; j < num_loops; j++)
4079- {
4080- locked_value++;
4081- }
4082- }));
4083- }
4084-
4085- for(auto& i : asyncs)
4086- {
4087- i.wait();
4088- }
4089-
4090- EXPECT_EQ(num_asyncs * num_loops, locked_value);
4091-}
4092-
4093-TEST(RWLockWriterBiasTest, writers_force_wait)
4094-{
4095- int const num_asyncs = 100;
4096- int const before = 66;
4097- int const increment = 1000;
4098- int const after = before + increment;
4099- int locked_value = before;
4100- std::vector<std::future<int>> reader_asyncs;
4101-
4102- mc::RWLockWriterBias lock;
4103-
4104- {
4105- std::unique_lock<mc::WriteLock> lk(lock);
4106-
4107- /* since all the readers are fired off while the write lock is held,
4108- they should all return the 'after' value*/
4109- for(auto i = 0; i < num_asyncs; i++)
4110- {
4111- reader_asyncs.push_back(std::async(std::launch::async,
4112- [&]
4113- {
4114- std::unique_lock<mc::ReadLock> lk(lock);
4115- return locked_value;
4116- }));
4117- }
4118-
4119- for(auto i=0; i < increment; i++)
4120- {
4121- locked_value++;
4122- }
4123- }
4124-
4125- for(auto& i : reader_asyncs)
4126- {
4127- i.wait();
4128- EXPECT_EQ(after, i.get());
4129- }
4130-}
4131-
4132-TEST(RWLockWriterBiasTest, readers_and_writers)
4133-{
4134- int const num_asyncs = 10;
4135- std::vector<std::future<int>> reader_asyncs;
4136-
4137- mc::RWLockWriterBias lock;
4138- int const before = 66, after = 1066;
4139- int locked_value = before;
4140-
4141- for(auto i = 0; i < num_asyncs; i++)
4142- {
4143- reader_asyncs.push_back(std::async(std::launch::async,
4144- [&]
4145- {
4146- std::unique_lock<mc::ReadLock> lk(lock);
4147- return locked_value;
4148- }));
4149- }
4150-
4151- auto writer_async = std::async(std::launch::async,
4152- [&]
4153- {
4154- std::unique_lock<mc::WriteLock> lk(lock);
4155- for(auto j=0; j<1000; j++)
4156- {
4157- locked_value++;
4158- }
4159- });
4160- writer_async.wait();
4161-
4162- for(auto i = 0; i < num_asyncs; i++)
4163- {
4164- reader_asyncs.push_back(std::async(std::launch::async,
4165- [&]
4166- {
4167- std::unique_lock<mc::ReadLock> lk(lock);
4168- return locked_value;
4169- }));
4170- }
4171-
4172- for(auto& i : reader_asyncs)
4173- {
4174- i.wait();
4175- auto value = i.get();
4176- EXPECT_TRUE( ((value == before) || (value == after)) );
4177- }
4178-}
4179
4180=== removed file 'tests/unit-tests/compositor/test_swapper_factory.cpp'
4181--- tests/unit-tests/compositor/test_swapper_factory.cpp 2013-07-31 11:18:25 +0000
4182+++ tests/unit-tests/compositor/test_swapper_factory.cpp 1970-01-01 00:00:00 +0000
4183@@ -1,221 +0,0 @@
4184-/*
4185- * Copyright © 2012 Canonical Ltd.
4186- *
4187- * This program is free software: you can redistribute it and/or modify
4188- * it under the terms of the GNU General Public License version 3 as
4189- * published by the Free Software Foundation.
4190- *
4191- * This program is distributed in the hope that it will be useful,
4192- * but WITHOUT ANY WARRANTY; without even the implied warranty of
4193- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4194- * GNU General Public License for more details.
4195- *
4196- * You should have received a copy of the GNU General Public License
4197- * along with this program. If not, see <http://www.gnu.org/licenses/>.
4198- *
4199- * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
4200- */
4201-
4202-#include "mir/compositor/swapper_factory.h"
4203-#include "mir/graphics/buffer_basic.h"
4204-#include "mir/graphics/buffer_properties.h"
4205-#include "mir/compositor/buffer_swapper.h"
4206-#include "mir/graphics/graphic_buffer_allocator.h"
4207-#include "mir_test_doubles/stub_buffer.h"
4208-#include "src/server/compositor/buffer_bundle.h"
4209-
4210-#include <gmock/gmock.h>
4211-#include <gtest/gtest.h>
4212-
4213-namespace mc = mir::compositor;
4214-namespace mg = mir::graphics;
4215-namespace geom = mir::geometry;
4216-namespace mtd = mir::test::doubles;
4217-
4218-namespace
4219-{
4220-static geom::Size const buf_size{100, 121};
4221-static geom::PixelFormat const buf_pixel_format{geom::PixelFormat::xbgr_8888};
4222-
4223-class MockGraphicBufferAllocator : public mg::GraphicBufferAllocator
4224-{
4225-public:
4226- MockGraphicBufferAllocator()
4227- {
4228- using namespace testing;
4229- mg::BufferProperties properties(buf_size, buf_pixel_format, mg::BufferUsage::hardware);
4230- ON_CALL(*this, alloc_buffer(_))
4231- .WillByDefault(Return(std::make_shared<mtd::StubBuffer>(properties)));
4232- }
4233- MOCK_METHOD1(alloc_buffer, std::shared_ptr<mg::Buffer>(mg::BufferProperties const&));
4234- MOCK_METHOD0(supported_pixel_formats, std::vector<geom::PixelFormat>());
4235-
4236- ~MockGraphicBufferAllocator() noexcept {}
4237-};
4238-
4239-struct SwapperFactoryTest : testing::Test
4240-{
4241- SwapperFactoryTest()
4242- : mock_buffer_allocator{std::make_shared<testing::NiceMock<MockGraphicBufferAllocator>>()},
4243- size{10, 20},
4244- pf{geom::PixelFormat::abgr_8888},
4245- usage{mg::BufferUsage::hardware},
4246- properties{size, pf, usage}
4247-
4248- {
4249- }
4250-
4251- std::shared_ptr<MockGraphicBufferAllocator> const mock_buffer_allocator;
4252- geom::Size const size;
4253- geom::PixelFormat const pf;
4254- mg::BufferUsage const usage;
4255- mg::BufferProperties const properties;
4256-};
4257-}
4258-
4259-/* default number of buffers is 2 */
4260-TEST_F(SwapperFactoryTest, create_sync_uses_default_number_of_buffers)
4261-{
4262- using namespace testing;
4263-
4264- mg::BufferProperties actual_properties;
4265- int default_num_of_buffers = 2;
4266- EXPECT_CALL(*mock_buffer_allocator, alloc_buffer(properties))
4267- .Times(default_num_of_buffers);
4268-
4269- mc::SwapperFactory strategy(mock_buffer_allocator);
4270- auto swapper = strategy.create_swapper_new_buffers(
4271- actual_properties, properties, mc::SwapperType::synchronous);
4272-}
4273-
4274-TEST_F(SwapperFactoryTest, create_sync_with_two_makes_double_buffer)
4275-{
4276- using namespace testing;
4277-
4278- int num_of_buffers = 2;
4279- mg::BufferProperties actual_properties;
4280-
4281- EXPECT_CALL(*mock_buffer_allocator, alloc_buffer(properties))
4282- .Times(num_of_buffers);
4283-
4284- mc::SwapperFactory strategy(mock_buffer_allocator, num_of_buffers);
4285- auto swapper = strategy.create_swapper_new_buffers(
4286- actual_properties, properties, mc::SwapperType::synchronous);
4287-}
4288-
4289-TEST_F(SwapperFactoryTest, create_sync_with_three_makes_triple_buffer)
4290-{
4291- using namespace testing;
4292-
4293- int num_of_buffers = 3;
4294- mg::BufferProperties actual_properties;
4295-
4296- EXPECT_CALL(*mock_buffer_allocator, alloc_buffer(properties))
4297- .Times(num_of_buffers);
4298-
4299- mc::SwapperFactory strategy(mock_buffer_allocator, num_of_buffers);
4300- auto swapper = strategy.create_swapper_new_buffers(
4301- actual_properties, properties, mc::SwapperType::synchronous);
4302-}
4303-
4304-TEST_F(SwapperFactoryTest, create_async_ignores_preference)
4305-{
4306- using namespace testing;
4307-
4308- mg::BufferProperties actual_properties;
4309-
4310- int num_of_buffers = 3;
4311- EXPECT_CALL(*mock_buffer_allocator, alloc_buffer(properties))
4312- .Times(num_of_buffers);
4313-
4314- mc::SwapperFactory strategy(mock_buffer_allocator);
4315- auto swapper = strategy.create_swapper_new_buffers(
4316- actual_properties, properties, mc::SwapperType::framedropping);
4317-}
4318-
4319-TEST_F(SwapperFactoryTest, creation_returns_new_parameters)
4320-{
4321- mg::BufferProperties actual1, actual2;
4322- mc::SwapperFactory strategy(mock_buffer_allocator);
4323- strategy.create_swapper_new_buffers(actual1, properties, mc::SwapperType::synchronous);
4324-
4325- EXPECT_EQ(buf_size, actual1.size);
4326- EXPECT_EQ(buf_pixel_format, actual1.format);
4327- EXPECT_EQ(usage, actual1.usage);
4328-}
4329-
4330-TEST_F(SwapperFactoryTest, create_async_reuse)
4331-{
4332- using namespace testing;
4333-
4334- mg::BufferProperties properties;
4335- std::vector<std::shared_ptr<mg::Buffer>> list {};
4336- size_t size = 3;
4337-
4338- EXPECT_CALL(*mock_buffer_allocator, alloc_buffer(properties))
4339- .Times(0);
4340-
4341- mc::SwapperFactory strategy(mock_buffer_allocator);
4342- auto swapper = strategy.create_swapper_reuse_buffers(properties, list, size, mc::SwapperType::framedropping);
4343-}
4344-
4345-TEST_F(SwapperFactoryTest, create_sync_reuse)
4346-{
4347- using namespace testing;
4348-
4349- mg::BufferProperties properties;
4350- std::vector<std::shared_ptr<mg::Buffer>> list;
4351- size_t size = 3;
4352-
4353- EXPECT_CALL(*mock_buffer_allocator, alloc_buffer(properties))
4354- .Times(0);
4355-
4356- mc::SwapperFactory strategy(mock_buffer_allocator, 3);
4357- auto swapper = strategy.create_swapper_reuse_buffers(properties, list, size, mc::SwapperType::synchronous);
4358-}
4359-
4360-TEST_F(SwapperFactoryTest, reuse_drop_unneeded_buffer)
4361-{
4362- using namespace testing;
4363-
4364- mc::SwapperFactory strategy(mock_buffer_allocator, 2);
4365-
4366- auto buffer = std::make_shared<mtd::StubBuffer>();
4367- {
4368- size_t size = 3;
4369- std::vector<std::shared_ptr<mg::Buffer>> list{buffer};
4370-
4371- auto swapper = strategy.create_swapper_reuse_buffers(
4372- properties, list, size, mc::SwapperType::synchronous);
4373- }
4374- EXPECT_EQ(1, buffer.use_count());
4375-}
4376-
4377-TEST_F(SwapperFactoryTest, reuse_drop_unneeded_buffer_error)
4378-{
4379- using namespace testing;
4380-
4381- mc::SwapperFactory strategy(mock_buffer_allocator, 2);
4382-
4383- size_t size = 3;
4384- std::vector<std::shared_ptr<mg::Buffer>> list{};
4385-
4386- EXPECT_THROW({
4387- strategy.create_swapper_reuse_buffers(
4388- properties, list, size, mc::SwapperType::synchronous);
4389- }, std::logic_error);
4390-}
4391-
4392-TEST_F(SwapperFactoryTest, reuse_alloc_additional_buffer_for_framedropping)
4393-{
4394- using namespace testing;
4395-
4396- EXPECT_CALL(*mock_buffer_allocator, alloc_buffer(_))
4397- .Times(1);
4398- mc::SwapperFactory strategy(mock_buffer_allocator);
4399-
4400- size_t size = 2;
4401- std::vector<std::shared_ptr<mg::Buffer>> list{};
4402- auto swapper = strategy.create_swapper_reuse_buffers(
4403- properties, list, size, mc::SwapperType::framedropping);
4404-}
4405
4406=== modified file 'tests/unit-tests/compositor/test_switching_bundle.cpp'
4407--- tests/unit-tests/compositor/test_switching_bundle.cpp 2013-07-31 11:00:22 +0000
4408+++ tests/unit-tests/compositor/test_switching_bundle.cpp 2013-08-07 10:49:30 +0000
4409@@ -13,144 +13,704 @@
4410 * You should have received a copy of the GNU General Public License
4411 * along with this program. If not, see <http://www.gnu.org/licenses/>.
4412 *
4413- * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
4414+ * Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com>
4415 */
4416
4417 #include "src/server/compositor/switching_bundle.h"
4418-#include "mir/compositor/swapper_factory.h"
4419+#include "mir_test_doubles/stub_buffer_allocator.h"
4420 #include "mir_test_doubles/stub_buffer.h"
4421-#include "mir_test_doubles/mock_swapper.h"
4422-#include "mir_test_doubles/mock_swapper_factory.h"
4423
4424 #include <gtest/gtest.h>
4425
4426+#include <atomic>
4427+#include <thread>
4428+#include <chrono>
4429+
4430 namespace geom=mir::geometry;
4431 namespace mtd=mir::test::doubles;
4432 namespace mc=mir::compositor;
4433 namespace mg = mir::graphics;
4434
4435+using namespace testing;
4436+
4437 struct SwitchingBundleTest : public ::testing::Test
4438 {
4439 void SetUp()
4440 {
4441- using namespace testing;
4442- mock_swapper_factory = std::make_shared<testing::NiceMock<mtd::MockSwapperFactory>>();
4443- mock_default_swapper = std::make_shared<testing::NiceMock<mtd::MockSwapper>>();
4444- mock_secondary_swapper = std::make_shared<testing::NiceMock<mtd::MockSwapper>>();
4445- stub_buffer = std::make_shared<mtd::StubBuffer>();
4446- properties = mg::BufferProperties{geom::Size{4, 2},
4447- geom::PixelFormat::abgr_8888, mg::BufferUsage::hardware};
4448-
4449- ON_CALL(*mock_swapper_factory, create_swapper_new_buffers(_,_,_))
4450- .WillByDefault(Return(mock_default_swapper));
4451+ allocator = std::make_shared<mtd::StubBufferAllocator>();
4452+ basic_properties =
4453+ {
4454+ geom::Size{3, 4},
4455+ geom::PixelFormat::abgr_8888,
4456+ mg::BufferUsage::hardware
4457+ };
4458 }
4459
4460- std::shared_ptr<mtd::MockSwapperFactory> mock_swapper_factory;
4461- std::shared_ptr<mtd::MockSwapper> mock_default_swapper;
4462- std::shared_ptr<mtd::MockSwapper> mock_secondary_swapper;
4463- std::shared_ptr<mg::Buffer> stub_buffer;
4464- mg::BufferProperties properties;
4465+ std::shared_ptr<mtd::StubBufferAllocator> allocator;
4466+
4467+ mg::BufferProperties basic_properties;
4468 };
4469
4470 TEST_F(SwitchingBundleTest, sync_swapper_by_default)
4471 {
4472- using namespace testing;
4473- auto actual_properties = mg::BufferProperties{geom::Size{7, 8},
4474- geom::PixelFormat::argb_8888, mg::BufferUsage::software};
4475- EXPECT_CALL(*mock_swapper_factory, create_swapper_new_buffers(_,_,mc::SwapperType::synchronous))
4476- .Times(1)
4477- .WillOnce(DoAll(SetArgReferee<0>(actual_properties),
4478- Return(mock_default_swapper)));
4479-
4480- mc::SwitchingBundle switcher(mock_swapper_factory, properties);
4481- EXPECT_EQ(actual_properties, switcher.properties());
4482+ mg::BufferProperties properties{geom::Size{7, 8},
4483+ geom::PixelFormat::argb_8888,
4484+ mg::BufferUsage::software};
4485+
4486+ for (int nbuffers = 1; nbuffers <= 5; nbuffers++)
4487+ {
4488+ mc::SwitchingBundle bundle(nbuffers, allocator, properties);
4489+
4490+ EXPECT_FALSE(bundle.framedropping_allowed());
4491+ EXPECT_EQ(properties, bundle.properties());
4492+ }
4493+}
4494+
4495+TEST_F(SwitchingBundleTest, invalid_nbuffers)
4496+{
4497+ EXPECT_THROW(
4498+ mc::SwitchingBundle a(0, allocator, basic_properties),
4499+ std::logic_error
4500+ );
4501+
4502+ EXPECT_THROW(
4503+ mc::SwitchingBundle b(-1, allocator, basic_properties),
4504+ std::logic_error
4505+ );
4506+
4507+ EXPECT_THROW(
4508+ mc::SwitchingBundle c(-123, allocator, basic_properties),
4509+ std::logic_error
4510+ );
4511+
4512+ EXPECT_THROW(
4513+ mc::SwitchingBundle d(10, allocator, basic_properties),
4514+ std::logic_error
4515+ );
4516 }
4517
4518 TEST_F(SwitchingBundleTest, client_acquire_basic)
4519 {
4520- using namespace testing;
4521- mc::SwitchingBundle switcher(mock_swapper_factory, properties);
4522-
4523- EXPECT_CALL(*mock_default_swapper, client_acquire())
4524- .Times(1)
4525- .WillOnce(Return(stub_buffer));
4526- EXPECT_CALL(*mock_default_swapper, client_release(stub_buffer))
4527- .Times(1);
4528-
4529- auto buffer = switcher.client_acquire();
4530- switcher.client_release(buffer);
4531-}
4532-
4533-TEST_F(SwitchingBundleTest, client_acquire_with_switch)
4534-{
4535- using namespace testing;
4536- mc::SwitchingBundle switcher(mock_swapper_factory, properties);
4537-
4538- EXPECT_CALL(*mock_default_swapper, client_acquire())
4539- .Times(1)
4540- .WillOnce(Return(stub_buffer));
4541- EXPECT_CALL(*mock_secondary_swapper, client_release(stub_buffer))
4542- .Times(1);
4543- EXPECT_CALL(*mock_swapper_factory, create_swapper_reuse_buffers(_,_,_,_))
4544- .Times(1)
4545- .WillOnce(Return(mock_secondary_swapper));
4546-
4547- auto buffer = switcher.client_acquire();
4548- switcher.allow_framedropping(true);
4549-
4550- switcher.client_release(buffer);
4551+ for (int nbuffers = 1; nbuffers <= 5; nbuffers++)
4552+ {
4553+ mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties);
4554+
4555+ auto buffer = bundle.client_acquire();
4556+ bundle.client_release(buffer);
4557+ }
4558+}
4559+
4560+namespace
4561+{
4562+ const int frame_rate = 60;
4563+ const std::chrono::microseconds frame_time(1000000 / frame_rate);
4564+
4565+ void sleep_one_frame()
4566+ {
4567+ std::this_thread::sleep_for(frame_time);
4568+ }
4569+
4570+ void composite_thread(mc::SwitchingBundle &bundle,
4571+ mg::BufferID &composited)
4572+ {
4573+ sleep_one_frame();
4574+ auto buffer = bundle.compositor_acquire();
4575+ composited = buffer->id();
4576+ bundle.compositor_release(buffer);
4577+ }
4578+}
4579+
4580+TEST_F(SwitchingBundleTest, is_really_synchronous)
4581+{
4582+ for (int nbuffers = 1; nbuffers < 5; nbuffers++)
4583+ {
4584+ mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties);
4585+ mg::BufferID prev_id, prev_prev_id;
4586+
4587+ ASSERT_FALSE(bundle.framedropping_allowed());
4588+
4589+ for (int i = 0; i < 50; i++)
4590+ {
4591+ auto client1 = bundle.client_acquire();
4592+ mg::BufferID expect_id = client1->id(), composited_id;
4593+ bundle.client_release(client1);
4594+
4595+ std::thread compositor(composite_thread,
4596+ std::ref(bundle),
4597+ std::ref(composited_id));
4598+
4599+ compositor.join();
4600+ ASSERT_EQ(expect_id, composited_id);
4601+
4602+ if (i >= 2 && nbuffers == 2)
4603+ ASSERT_EQ(composited_id, prev_prev_id);
4604+
4605+ prev_prev_id = prev_id;
4606+ prev_id = composited_id;
4607+
4608+ auto second_monitor = bundle.compositor_acquire();
4609+ ASSERT_EQ(composited_id, second_monitor->id());
4610+ bundle.compositor_release(second_monitor);
4611+ }
4612+ }
4613+}
4614+
4615+TEST_F(SwitchingBundleTest, framedropping_clients_never_block)
4616+{
4617+ for (int nbuffers = 2; nbuffers < 5; nbuffers++)
4618+ {
4619+ mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties);
4620+
4621+ bundle.allow_framedropping(true);
4622+ mg::BufferID last_client_id;
4623+
4624+ for (int i = 0; i < 50; i++)
4625+ {
4626+ for (int j = 0; j < 100; j++)
4627+ {
4628+ auto client = bundle.client_acquire();
4629+ last_client_id = client->id();
4630+ bundle.client_release(client);
4631+ }
4632+
4633+ // Flush the pipeline of previously ready buffers
4634+ for (int k = 0; k < nbuffers-1; k++)
4635+ {
4636+ bundle.compositor_release(bundle.compositor_acquire());
4637+ sleep_one_frame();
4638+ }
4639+
4640+ auto compositor = bundle.compositor_acquire();
4641+ ASSERT_EQ(last_client_id, compositor->id());
4642+ bundle.compositor_release(compositor);
4643+ }
4644+ }
4645+}
4646+
4647+TEST_F(SwitchingBundleTest, out_of_order_client_release)
4648+{
4649+ for (int nbuffers = 2; nbuffers <= 5; nbuffers++)
4650+ {
4651+ mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties);
4652+
4653+ auto client1 = bundle.client_acquire();
4654+ auto client2 = bundle.client_acquire();
4655+ EXPECT_THROW(
4656+ bundle.client_release(client2),
4657+ std::logic_error
4658+ );
4659+
4660+ bundle.client_release(client1);
4661+ EXPECT_THROW(
4662+ bundle.client_release(client1),
4663+ std::logic_error
4664+ );
4665+ }
4666 }
4667
4668 TEST_F(SwitchingBundleTest, compositor_acquire_basic)
4669 {
4670- using namespace testing;
4671- mc::SwitchingBundle switcher(mock_swapper_factory, properties);
4672-
4673- EXPECT_CALL(*mock_default_swapper, compositor_acquire())
4674- .Times(1)
4675- .WillOnce(Return(stub_buffer));
4676- EXPECT_CALL(*mock_default_swapper, compositor_release(stub_buffer))
4677- .Times(1);
4678-
4679- auto buffer = switcher.compositor_acquire();
4680- switcher.compositor_release(buffer);
4681-}
4682-
4683-TEST_F(SwitchingBundleTest, compositor_acquire_with_switch)
4684-{
4685- using namespace testing;
4686-
4687- mc::SwitchingBundle switcher(mock_swapper_factory, properties);
4688-
4689- EXPECT_CALL(*mock_default_swapper, compositor_acquire())
4690- .Times(1)
4691- .WillOnce(Return(stub_buffer));
4692- EXPECT_CALL(*mock_secondary_swapper, compositor_release(stub_buffer))
4693- .Times(1);
4694- EXPECT_CALL(*mock_swapper_factory, create_swapper_reuse_buffers(_,_,_,_))
4695- .Times(1)
4696- .WillOnce(Return(mock_secondary_swapper));
4697-
4698- auto buffer = switcher.compositor_acquire();
4699-
4700- switcher.allow_framedropping(true);
4701-
4702- switcher.compositor_release(buffer);
4703-}
4704-
4705-TEST_F(SwitchingBundleTest, switch_sequence)
4706-{
4707- using namespace testing;
4708- mc::SwitchingBundle switcher(mock_swapper_factory, properties);
4709-
4710- InSequence seq;
4711- EXPECT_CALL(*mock_default_swapper, force_client_abort())
4712- .Times(1);
4713- EXPECT_CALL(*mock_default_swapper, end_responsibility(_,_))
4714- .Times(1);
4715- EXPECT_CALL(*mock_swapper_factory, create_swapper_reuse_buffers(_,_,_,mc::SwapperType::framedropping))
4716- .Times(1)
4717- .WillOnce(Return(mock_secondary_swapper));
4718-
4719- switcher.allow_framedropping(true);
4720-}
4721+ for (int nbuffers = 1; nbuffers <= 5; nbuffers++)
4722+ {
4723+ mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties);
4724+
4725+ auto client = bundle.client_acquire();
4726+ auto client_id = client->id();
4727+ bundle.client_release(client);
4728+
4729+ for (int monitor = 0; monitor < 10; monitor++)
4730+ {
4731+ auto compositor = bundle.compositor_acquire();
4732+ ASSERT_EQ(client_id, compositor->id());
4733+ bundle.compositor_release(compositor);
4734+ }
4735+ }
4736+}
4737+
4738+TEST_F(SwitchingBundleTest, compositor_acquire_never_blocks)
4739+{
4740+ for (int nbuffers = 1; nbuffers <= 5; nbuffers++)
4741+ {
4742+ mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties);
4743+ const int N = 100;
4744+
4745+ bundle.force_requests_to_complete();
4746+
4747+ std::shared_ptr<mg::Buffer> buf[N];
4748+ for (int i = 0; i < N; i++)
4749+ buf[i] = bundle.compositor_acquire();
4750+
4751+ for (int i = 0; i < N; i++)
4752+ bundle.compositor_release(buf[i]);
4753+ }
4754+}
4755+
4756+TEST_F(SwitchingBundleTest, compositor_acquire_recycles_latest_ready_buffer)
4757+{
4758+ for (int nbuffers = 1; nbuffers < 5; nbuffers++)
4759+ {
4760+ mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties);
4761+
4762+ mg::BufferID client_id;
4763+
4764+ for (int i = 0; i < 50; i++)
4765+ {
4766+ if (i % 10 == 0)
4767+ {
4768+ auto client = bundle.client_acquire();
4769+ client_id = client->id();
4770+ bundle.client_release(client);
4771+ }
4772+
4773+ for (int monitor_id = 0; monitor_id < 10; monitor_id++)
4774+ {
4775+ auto compositor = bundle.compositor_acquire();
4776+ ASSERT_EQ(client_id, compositor->id());
4777+ bundle.compositor_release(compositor);
4778+ }
4779+
4780+ sleep_one_frame();
4781+ }
4782+ }
4783+}
4784+
4785+TEST_F(SwitchingBundleTest, compositor_release_verifies_parameter)
4786+{
4787+ for (int nbuffers = 2; nbuffers <= 5; nbuffers++)
4788+ {
4789+ mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties);
4790+
4791+ auto client = bundle.client_acquire();
4792+
4793+ EXPECT_THROW(
4794+ bundle.compositor_release(client),
4795+ std::logic_error
4796+ );
4797+ bundle.client_release(client);
4798+
4799+ auto compositor1 = bundle.compositor_acquire();
4800+ bundle.compositor_release(compositor1);
4801+ EXPECT_THROW(
4802+ bundle.compositor_release(compositor1),
4803+ std::logic_error
4804+ );
4805+ }
4806+}
4807+
4808+TEST_F(SwitchingBundleTest, overlapping_compositors_get_different_frames)
4809+{
4810+ // This test simulates bypass behaviour
4811+ for (int nbuffers = 2; nbuffers < 5; nbuffers++)
4812+ {
4813+ mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties);
4814+
4815+ std::shared_ptr<mg::Buffer> compositor[2];
4816+
4817+ bundle.client_release(bundle.client_acquire());
4818+ compositor[0] = bundle.compositor_acquire();
4819+
4820+ sleep_one_frame();
4821+ bundle.client_release(bundle.client_acquire());
4822+ compositor[1] = bundle.compositor_acquire();
4823+
4824+ for (int i = 0; i < 50; i++)
4825+ {
4826+ // Two compositors acquired, and they're always different...
4827+ ASSERT_NE(compositor[0]->id(), compositor[1]->id());
4828+
4829+ // One of the compositors (the oldest one) gets a new buffer...
4830+ int oldest = i & 1;
4831+ bundle.compositor_release(compositor[oldest]);
4832+ bundle.client_release(bundle.client_acquire());
4833+ sleep_one_frame();
4834+ compositor[oldest] = bundle.compositor_acquire();
4835+ }
4836+
4837+ bundle.compositor_release(compositor[0]);
4838+ bundle.compositor_release(compositor[1]);
4839+ }
4840+}
4841+
4842+TEST_F(SwitchingBundleTest, snapshot_acquire_basic)
4843+{
4844+ for (int nbuffers = 1; nbuffers <= 5; nbuffers++)
4845+ {
4846+ mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties);
4847+
4848+ auto compositor = bundle.compositor_acquire();
4849+ auto snapshot = bundle.snapshot_acquire();
4850+ EXPECT_EQ(snapshot->id(), compositor->id());
4851+ bundle.compositor_release(compositor);
4852+ bundle.snapshot_release(snapshot);
4853+ }
4854+}
4855+
4856+TEST_F(SwitchingBundleTest, snapshot_acquire_never_blocks)
4857+{
4858+ for (int nbuffers = 1; nbuffers <= 5; nbuffers++)
4859+ {
4860+ mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties);
4861+ const int N = 100;
4862+
4863+ std::shared_ptr<mg::Buffer> buf[N];
4864+ for (int i = 0; i < N; i++)
4865+ buf[i] = bundle.snapshot_acquire();
4866+
4867+ for (int i = 0; i < N; i++)
4868+ bundle.snapshot_release(buf[i]);
4869+ }
4870+}
4871+
4872+TEST_F(SwitchingBundleTest, snapshot_release_verifies_parameter)
4873+{
4874+ for (int nbuffers = 2; nbuffers <= 5; nbuffers++)
4875+ {
4876+ mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties);
4877+
4878+ auto compositor = bundle.compositor_acquire();
4879+
4880+ EXPECT_THROW(
4881+ bundle.snapshot_release(compositor),
4882+ std::logic_error
4883+ );
4884+
4885+ auto client = bundle.client_acquire();
4886+ auto snapshot = bundle.snapshot_acquire();
4887+
4888+ EXPECT_EQ(compositor->id(), snapshot->id());
4889+
4890+ EXPECT_NE(client->id(), snapshot->id());
4891+
4892+ EXPECT_THROW(
4893+ bundle.snapshot_release(client),
4894+ std::logic_error
4895+ );
4896+
4897+ bundle.snapshot_release(snapshot);
4898+
4899+ EXPECT_THROW(
4900+ bundle.snapshot_release(snapshot),
4901+ std::logic_error
4902+ );
4903+ }
4904+}
4905+
4906+namespace
4907+{
4908+ void compositor_thread(mc::SwitchingBundle &bundle,
4909+ std::atomic<bool> &done)
4910+ {
4911+ while (!done)
4912+ {
4913+ bundle.compositor_release(bundle.compositor_acquire());
4914+ std::this_thread::yield();
4915+ }
4916+ }
4917+
4918+ void snapshot_thread(mc::SwitchingBundle &bundle,
4919+ std::atomic<bool> &done)
4920+ {
4921+ while (!done)
4922+ {
4923+ bundle.snapshot_release(bundle.snapshot_acquire());
4924+ std::this_thread::yield();
4925+ }
4926+ }
4927+
4928+ void client_thread(mc::SwitchingBundle &bundle, int nframes)
4929+ {
4930+ for (int i = 0; i < nframes; i++)
4931+ {
4932+ bundle.client_release(bundle.client_acquire());
4933+ std::this_thread::yield();
4934+ }
4935+ }
4936+
4937+ void switching_client_thread(mc::SwitchingBundle &bundle, int nframes)
4938+ {
4939+ for (int i = 0; i < nframes; i += 10)
4940+ {
4941+ bundle.allow_framedropping(false);
4942+ for (int j = 0; j < 5; j++)
4943+ bundle.client_release(bundle.client_acquire());
4944+ std::this_thread::yield();
4945+
4946+ bundle.allow_framedropping(true);
4947+ for (int j = 0; j < 5; j++)
4948+ bundle.client_release(bundle.client_acquire());
4949+ std::this_thread::yield();
4950+ }
4951+ }
4952+}
4953+
4954+TEST_F(SwitchingBundleTest, stress)
4955+{
4956+ for (int nbuffers = 2; nbuffers <= 5; nbuffers++)
4957+ {
4958+ mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties);
4959+
4960+ std::atomic<bool> done;
4961+ done = false;
4962+
4963+ std::thread compositor(compositor_thread,
4964+ std::ref(bundle),
4965+ std::ref(done));
4966+ std::thread snapshotter1(snapshot_thread,
4967+ std::ref(bundle),
4968+ std::ref(done));
4969+ std::thread snapshotter2(snapshot_thread,
4970+ std::ref(bundle),
4971+ std::ref(done));
4972+
4973+ bundle.allow_framedropping(false);
4974+ std::thread client1(client_thread, std::ref(bundle), 1000);
4975+ client1.join();
4976+
4977+ bundle.allow_framedropping(true);
4978+ std::thread client2(client_thread, std::ref(bundle), 1000);
4979+ client2.join();
4980+
4981+ std::thread client3(switching_client_thread, std::ref(bundle), 1000);
4982+ client3.join();
4983+
4984+ done = true;
4985+
4986+ compositor.join();
4987+ snapshotter1.join();
4988+ snapshotter2.join();
4989+ }
4990+}
4991+
4992+#if 0 // FIXME (enabling this optimization breaks timing tests)
4993+TEST_F(SwitchingBundleTest, synchronous_clients_only_get_two_real_buffers)
4994+{
4995+ /*
4996+ * You might ask for more buffers, but we should only allocate two
4997+ * unique ones while it makes sense to do so. Buffers are big things and
4998+ * should be allocated sparingly...
4999+ */
5000+ for (int nbuffers = 1; nbuffers <= 5; nbuffers++)
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches