Merge lp:~vanvugt/mir/switch into lp:~mir-team/mir/trunk
- switch
- Merge into trunk
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 |
Related bugs: |
|
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.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
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-
1. render_surfaces is rendering in a small part of the output (instead of taking up the whole screen)
2. mir_demo_
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.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:996
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:997
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
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.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1002
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
deb: http://
Click here to trigger a rebuild:
http://
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal | # |
Failure looks like intrastructure - restarting
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal | # |
63 + GLint old_viewport[4];
...
50 + glViewport(
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(
I guess if this is all it is used for it's OK.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:1002
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
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 MultiAcquisitio
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_
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?
Alexandros Frantzis (afrantzis) wrote : Posted in a previous version of this proposal | # |
A possible way forward is to keep MultiAcquisitio
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:1003
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
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/
Bypass requires that successive compositor acquisitions get different buffers. So MultiAcquisitio
P.S. Has sufficient multi-monitor support landed in trunk so that I can test it myself?
As for:
"compositor_
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.
Alexandros Frantzis (afrantzis) wrote : Posted in a previous version of this proposal | # |
> Bypass requires that successive compositor acquisitions get different buffers. So MultiAcquisitio
> 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/
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).
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_
> 1776 + "positive number of buffers"));
> 1930 + if (nclients <= 0 || ring[first_
> 1931 + BOOST_THROW_
> 1932 + "Client release out of order"));
... and at other places
multi-line statement should be placed in a block
> 2159 + SharedBuffer *ring;
std::vector<
> 4649 +TEST_F(
Needs a rename?
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_
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.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1011
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
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:
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_
std::swap(): FIXED
Preview Diff
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++) |
FAILED: Continuous integration, rev:995 jenkins. qa.ubuntu. com/job/ mir-ci/ 1168/ jenkins. qa.ubuntu. com/job/ mir-android- saucy-i386- build/1537 jenkins. qa.ubuntu. com/job/ mir-clang- saucy-amd64- build/1422/ console jenkins. qa.ubuntu. com/job/ mir-saucy- amd64-ci/ 406 jenkins. qa.ubuntu. com/job/ mir-saucy- amd64-ci/ 406/artifact/ work/output/ *zip*/output. zip
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild: s-jenkins: 8080/job/ mir-ci/ 1168/rebuild
http://