Mir

Merge lp:~kdub/mir/interval0-signal into lp:~mir-team/mir/trunk

Proposed by Kevin DuBois
Status: Merged
Approved by: Daniel van Vugt
Approved revision: no longer in the source branch.
Merged at revision: 780
Proposed branch: lp:~kdub/mir/interval0-signal
Merge into: lp:~mir-team/mir/trunk
Prerequisite: lp:~kdub/mir/anativewindow-external-refcount
Diff against target: 786 lines (+418/-23)
24 files modified
include/client/mir_toolkit/mir_client_library.h (+21/-0)
include/server/mir/compositor/buffer_allocation_strategy.h (+1/-1)
include/server/mir/compositor/buffer_stream_surfaces.h (+1/-0)
include/server/mir/compositor/swapper_factory.h (+6/-2)
include/server/mir/shell/surface.h (+1/-0)
include/server/mir/surfaces/buffer_stream.h (+1/-0)
include/server/mir/surfaces/surface.h (+2/-0)
include/shared/mir_toolkit/common.h (+1/-1)
include/test/mir_test_doubles/mock_buffer_stream.h (+2/-0)
include/test/mir_test_doubles/mock_swapper_factory.h (+2/-2)
include/test/mir_test_doubles/stub_buffer_stream.h (+4/-0)
src/client/mir_client_library.cpp (+12/-0)
src/client/mir_surface.cpp (+2/-0)
src/server/compositor/buffer_stream_surfaces.cpp (+4/-0)
src/server/compositor/swapper_factory.cpp (+36/-9)
src/server/compositor/switching_bundle.cpp (+2/-2)
src/server/shell/surface.cpp (+14/-1)
src/server/surfaces/surface.cpp (+5/-0)
tests/integration-tests/CMakeLists.txt (+1/-0)
tests/integration-tests/test_swapinterval.cpp (+226/-0)
tests/unit-tests/compositor/test_buffer_stream.cpp (+9/-0)
tests/unit-tests/compositor/test_swapper_factory.cpp (+50/-2)
tests/unit-tests/compositor/test_switching_bundle.cpp (+3/-3)
tests/unit-tests/surfaces/test_surface.cpp (+12/-0)
To merge this branch: bzr merge lp:~kdub/mir/interval0-signal
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Daniel van Vugt Approve
Alexandros Frantzis (community) Approve
Review via email: mp+170423@code.launchpad.net

This proposal supersedes a proposal from 2013-06-17.

Commit message

Activate sending a "swapinterval" signal over IPC. Add client api for software clients to request different swapintervals. (eglSwapInterval is not glued together just yet)
Currently only swapinterval of 0 or 1 is supported.

Description of the change

Activate sending a "swapinterval" signal over IPC. Add client api for software clients to request different swapintervals. (eglSwapInterval is not glued together just yet)
Currently only swapinterval of 0 or 1 is supported.

note that the actual path taken over ipc is via the surface parameters, there is no new protobuf message introduced to support the message.

tests/integration-tests/test_swapinterval.cpp tests from the client's request until the point that the request hits the compositor systems at mc::BufferStream

still in pre-review, dependent on anativewindow-external-refcount

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

FAILED: Continuous integration, rev:759
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~kdub/mir/interval0-signal/+merge/170423/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/mir-ci/771/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-android-saucy-i386-build/969
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-clang-saucy-amd64-build/851
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-saucy-amd64-ci/9
        deb: http://jenkins.qa.ubuntu.com/job/mir-saucy-amd64-ci/9/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins:8080/job/mir-ci/771/rebuild

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

1. Swap interval >1 is valid, but not usually useful. I wonder if there's any value in generalizing so interval>1 is supported...?

2. Documentation on the limitations of swap interval ([0,1]) is missing from the comment for mir_surface_set_swapinterval.

3. Consistency:
132 +typedef enum MirSurfacePerformanceHint
133 +{
134 + mir_surface_hint_synchronous,
135 + mir_surface_hint_drop_frames,
136 + mir_surface_hint_arraysize_
137 +} MirSurfacePerformanceHint;
"MirSurfacePerformanceHint" != "mir_surface_hint". I suggest removing the word "Performance". Also from:
124 + mir_surface_attrib_performance_hint,
Although "hint" is a bit vague. Why not make the attribute named "swap_interval" or similar? Then you don't need MirSurfacePerformanceHint at all because it's just an int.

4. Lack of indentation under "196 + switch (interval)" is a style I haven't seen in Mir before. Is it within policy? Do we care?

5. I tried adding mir_surface_set_swapinterval(surface, 0) to demo_client_unaccelerated and didn't expect what I saw:
I see the swap happening *much* less often with 0 than 1. However adding a frame rate counter in the client shows it's higher for the client, as it should be. I suspect we have a buffer scheduling problem that makes interval=0 look much slower than it should. But it might just be the natural randomness of frame dropping making longer periods of green/blue appear in demo_client_unaccelerated. I will have to modify/create a software client (to actually animate something) to investigate further if this is a real issue. And even if there is an issue with it I'm not even sure this branch is to blame...

So really just #2-#4 need attention right now.

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

> 4. Lack of indentation under "196 + switch (interval)" is a style I haven't seen in Mir before.
> Is it within policy? Do we care?

I see more indentation that we normally use, not a lack of it :)

274 + void mc::SwapperFactory::change_swapper_size(
297 + create_swapper_reuse_buffers(
298 - std::vector<std::shared_ptr<Buffer>>& list, size_t buffer_num, SwapperType type) const
299 + BufferProperties const& buffer_properties, std::vector<std::shared_ptr<Buffer>>& list

It feels strange that we remove/add buffers to the vector that is handed to us (although it has no ill effect, since the caller doesn't care about the buffers). I think it would be cleaner to create and manipulate a new vector internally (and make the create_swapper_reuse_buffers() parameter const).

289 + } else

else should be on separate line

review: Needs Fixing
Revision history for this message
Kevin DuBois (kdub) wrote :

@Daniel
#1, we don't have a driving use case for >1 swapinterval at the moment, plus it would take some changes to the swappers, so we can put it on the wishlist.
#2 hopefully better documentation added
#3 good idea, code is cleaner with this
#4 just bad indentation, was eliminated with #3
#5 i think this is just the unaccelerated client picking blue or green frames multiple times in a row. If you call this function with an eglapp.c based gl client, you'll see higher than vsync framerates reported.

@Alexandros
I agree, have to come up with a solution to allocate a buffer when going from 2->3 buffers, and preserve the buffer for any future 3->2 transitions. The android drivers didn't like switching buffers of the same size/format/usage out from under them.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Thanks Kevin. I can see the requested changes made but have not re-reviewed yet.

review: Abstain
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

A lot has landed today. So now we have:

Text conflict in src/server/shell/surface.cpp
Text conflict in tests/unit-tests/surfaces/test_surface.cpp
2 conflicts encountered.

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

1. Conflicts:
Text conflict in src/server/shell/surface.cpp
Text conflict in tests/unit-tests/surfaces/test_surface.cpp

2. Please resolve this inconsistency: "swapinterval" and "swap_interval".

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

Looks good.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

OK, I have no more complaints. But I'm not going to redo all the testing I've already done on earlier revisions.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/client/mir_toolkit/mir_client_library.h'
2--- include/client/mir_toolkit/mir_client_library.h 2013-06-20 09:43:30 +0000
3+++ include/client/mir_toolkit/mir_client_library.h 2013-06-25 19:32:30 +0000
4@@ -293,6 +293,27 @@
5 */
6 MirSurfaceState mir_surface_get_state(MirSurface *surface);
7
8+/**
9+ * Set the swapinterval for mir_surface_swap_buffers. EGL users should use
10+ * eglSwapInterval directly.
11+ * At the time being, only swapinterval of 0 or 1 is supported.
12+ * \param [in] surface The surface to operate on
13+ * \param [in] interval The number of vblank signals that
14+ * mir_surface_swap_buffers will wait for
15+ * \return A wait handle that can be passed to mir_wait_for,
16+ * or NULL if the interval could not be supported
17+ */
18+MirWaitHandle* mir_surface_set_swapinterval(MirSurface* surface, int interval);
19+
20+/**
21+ * Query the swapinterval that the surface is operating with.
22+ * The default interval is 1.
23+ * \param [in] surface The surface to operate on
24+ * \return The swapinterval value that the client is operating with.
25+ * Returns -1 if surface is invalid.
26+ */
27+int mir_surface_get_swapinterval(MirSurface* surface);
28+
29 #ifdef __cplusplus
30 }
31 /**@}*/
32
33=== modified file 'include/server/mir/compositor/buffer_allocation_strategy.h'
34--- include/server/mir/compositor/buffer_allocation_strategy.h 2013-06-17 10:26:18 +0000
35+++ include/server/mir/compositor/buffer_allocation_strategy.h 2013-06-25 19:32:30 +0000
36@@ -45,7 +45,7 @@
37 class BufferAllocationStrategy
38 {
39 public:
40- virtual std::shared_ptr<BufferSwapper> create_swapper_reuse_buffers(
41+ virtual std::shared_ptr<BufferSwapper> create_swapper_reuse_buffers(BufferProperties const&,
42 std::vector<std::shared_ptr<Buffer>>&, size_t, SwapperType) const = 0;
43 virtual std::shared_ptr<BufferSwapper> create_swapper_new_buffers(
44 BufferProperties& actual_properties, BufferProperties const& requested_properties, SwapperType) const = 0;
45
46=== modified file 'include/server/mir/compositor/buffer_stream_surfaces.h'
47--- include/server/mir/compositor/buffer_stream_surfaces.h 2013-06-20 09:39:10 +0000
48+++ include/server/mir/compositor/buffer_stream_surfaces.h 2013-06-25 19:32:30 +0000
49@@ -46,6 +46,7 @@
50
51 geometry::PixelFormat get_stream_pixel_format();
52 geometry::Size stream_size();
53+ void allow_framedropping(bool);
54 void force_requests_to_complete();
55
56 protected:
57
58=== modified file 'include/server/mir/compositor/swapper_factory.h'
59--- include/server/mir/compositor/swapper_factory.h 2013-06-11 15:05:27 +0000
60+++ include/server/mir/compositor/swapper_factory.h 2013-06-25 19:32:30 +0000
61@@ -38,14 +38,18 @@
62 std::shared_ptr<GraphicBufferAllocator> const& gr_alloc,
63 int number_of_buffers);
64
65- std::shared_ptr<BufferSwapper> create_swapper_reuse_buffers(
66+ std::shared_ptr<BufferSwapper> create_swapper_reuse_buffers(BufferProperties const&,
67 std::vector<std::shared_ptr<Buffer>>&, size_t, SwapperType) const;
68 std::shared_ptr<BufferSwapper> create_swapper_new_buffers(
69 BufferProperties& actual_properties, BufferProperties const& requested_properties, SwapperType) const;
70
71 private:
72+ void change_swapper_size(
73+ std::vector<std::shared_ptr<Buffer>>&, size_t const, size_t, BufferProperties const&) const;
74+
75 std::shared_ptr<GraphicBufferAllocator> const gr_allocator;
76- int const number_of_buffers;
77+ unsigned int const synchronous_number_of_buffers;
78+ unsigned int const spin_number_of_buffers;
79 };
80 }
81 }
82
83=== modified file 'include/server/mir/shell/surface.h'
84--- include/server/mir/shell/surface.h 2013-06-25 05:42:49 +0000
85+++ include/server/mir/shell/surface.h 2013-06-25 19:32:30 +0000
86@@ -87,6 +87,7 @@
87
88 virtual void take_input_focus(std::shared_ptr<InputTargeter> const& targeter);
89
90+ virtual void allow_framedropping(bool);
91 private:
92 bool set_type(MirSurfaceType t); // Use configure() to make public changes
93 bool set_state(MirSurfaceState s);
94
95=== modified file 'include/server/mir/surfaces/buffer_stream.h'
96--- include/server/mir/surfaces/buffer_stream.h 2013-06-20 09:39:10 +0000
97+++ include/server/mir/surfaces/buffer_stream.h 2013-06-25 19:32:30 +0000
98@@ -45,6 +45,7 @@
99 virtual std::shared_ptr<compositor::Buffer> lock_back_buffer() = 0;
100 virtual geometry::PixelFormat get_stream_pixel_format() = 0;
101 virtual geometry::Size stream_size() = 0;
102+ virtual void allow_framedropping(bool) = 0;
103 virtual void force_requests_to_complete() = 0;
104 };
105
106
107=== modified file 'include/server/mir/surfaces/surface.h'
108--- include/server/mir/surfaces/surface.h 2013-06-25 05:42:49 +0000
109+++ include/server/mir/surfaces/surface.h 2013-06-25 19:32:30 +0000
110@@ -81,6 +81,8 @@
111 bool supports_input() const;
112 int client_input_fd() const;
113 int server_input_fd() const;
114+
115+ void allow_framedropping(bool);
116 private:
117 std::string surface_name;
118 geometry::Point top_left_point;
119
120=== modified file 'include/shared/mir_toolkit/common.h'
121--- include/shared/mir_toolkit/common.h 2013-05-03 22:53:42 +0000
122+++ include/shared/mir_toolkit/common.h 2013-06-25 19:32:30 +0000
123@@ -35,6 +35,7 @@
124 {
125 mir_surface_attrib_type,
126 mir_surface_attrib_state,
127+ mir_surface_attrib_swapinterval,
128 mir_surface_attrib_arraysize_
129 } MirSurfaceAttrib;
130
131@@ -62,7 +63,6 @@
132 mir_surface_state_fullscreen,
133 mir_surface_state_arraysize_
134 } MirSurfaceState;
135-
136 /**@}*/
137
138 #endif
139
140=== modified file 'include/test/mir_test_doubles/mock_buffer_stream.h'
141--- include/test/mir_test_doubles/mock_buffer_stream.h 2013-06-19 16:41:13 +0000
142+++ include/test/mir_test_doubles/mock_buffer_stream.h 2013-06-25 19:32:30 +0000
143@@ -36,6 +36,8 @@
144
145 MOCK_METHOD0(get_stream_pixel_format, geometry::PixelFormat());
146 MOCK_METHOD0(stream_size, geometry::Size());
147+ MOCK_METHOD0(force_client_completion, void());
148+ MOCK_METHOD1(allow_framedropping, void(bool));
149 MOCK_METHOD0(force_requests_to_complete, void());
150 };
151 }
152
153=== modified file 'include/test/mir_test_doubles/mock_swapper_factory.h'
154--- include/test/mir_test_doubles/mock_swapper_factory.h 2013-06-11 14:27:33 +0000
155+++ include/test/mir_test_doubles/mock_swapper_factory.h 2013-06-25 19:32:30 +0000
156@@ -33,8 +33,8 @@
157 public:
158 ~MockSwapperFactory() noexcept {}
159
160- MOCK_CONST_METHOD3(create_swapper_reuse_buffers,
161- std::shared_ptr<compositor::BufferSwapper>(
162+ MOCK_CONST_METHOD4(create_swapper_reuse_buffers,
163+ std::shared_ptr<compositor::BufferSwapper>(compositor::BufferProperties const&,
164 std::vector<std::shared_ptr<compositor::Buffer>>&, size_t, compositor::SwapperType));
165 MOCK_CONST_METHOD3(create_swapper_new_buffers,
166 std::shared_ptr<compositor::BufferSwapper>(
167
168=== modified file 'include/test/mir_test_doubles/stub_buffer_stream.h'
169--- include/test/mir_test_doubles/stub_buffer_stream.h 2013-06-19 16:41:13 +0000
170+++ include/test/mir_test_doubles/stub_buffer_stream.h 2013-06-25 19:32:30 +0000
171@@ -61,6 +61,10 @@
172 {
173 }
174
175+ void allow_framedropping(bool)
176+ {
177+ }
178+
179 std::shared_ptr<compositor::Buffer> stub_client_buffer;
180 std::shared_ptr<compositor::Buffer> stub_compositor_buffer;
181 };
182
183=== modified file 'src/client/mir_client_library.cpp'
184--- src/client/mir_client_library.cpp 2013-06-20 09:43:30 +0000
185+++ src/client/mir_client_library.cpp 2013-06-25 19:32:30 +0000
186@@ -316,3 +316,15 @@
187
188 return state;
189 }
190+
191+MirWaitHandle* mir_surface_set_swapinterval(MirSurface* surf, int interval)
192+{
193+ if ((interval < 0) || (interval > 1))
194+ return NULL;
195+ return surf ? surf->configure(mir_surface_attrib_swapinterval, interval) : NULL;
196+}
197+
198+int mir_surface_get_swapinterval(MirSurface* surf)
199+{
200+ return surf ? surf->attrib(mir_surface_attrib_swapinterval) : -1;
201+}
202
203=== modified file 'src/client/mir_surface.cpp'
204--- src/client/mir_surface.cpp 2013-06-20 09:43:30 +0000
205+++ src/client/mir_surface.cpp 2013-06-25 19:32:30 +0000
206@@ -58,6 +58,7 @@
207 attrib_cache[i] = -1;
208 attrib_cache[mir_surface_attrib_type] = mir_surface_type_normal;
209 attrib_cache[mir_surface_attrib_state] = mir_surface_state_unknown;
210+ attrib_cache[mir_surface_attrib_swapinterval] = 1;
211 }
212
213 MirSurface::~MirSurface()
214@@ -269,6 +270,7 @@
215 {
216 case mir_surface_attrib_type:
217 case mir_surface_attrib_state:
218+ case mir_surface_attrib_swapinterval:
219 if (configure_result.has_ivalue())
220 attrib_cache[a] = configure_result.ivalue();
221 else
222
223=== modified file 'src/server/compositor/buffer_stream_surfaces.cpp'
224--- src/server/compositor/buffer_stream_surfaces.cpp 2013-06-19 16:41:13 +0000
225+++ src/server/compositor/buffer_stream_surfaces.cpp 2013-06-25 19:32:30 +0000
226@@ -63,3 +63,7 @@
227 buffer_bundle->force_requests_to_complete();
228 }
229
230+void mc::BufferStreamSurfaces::allow_framedropping(bool allow)
231+{
232+ buffer_bundle->allow_framedropping(allow);
233+}
234
235=== modified file 'src/server/compositor/swapper_factory.cpp'
236--- src/server/compositor/swapper_factory.cpp 2013-06-11 19:55:10 +0000
237+++ src/server/compositor/swapper_factory.cpp 2013-06-25 19:32:30 +0000
238@@ -36,7 +36,8 @@
239 std::shared_ptr<GraphicBufferAllocator> const& gr_alloc,
240 int number_of_buffers)
241 : gr_allocator(gr_alloc),
242- number_of_buffers(number_of_buffers)
243+ synchronous_number_of_buffers(number_of_buffers),
244+ spin_number_of_buffers(3) //spin algorithm always takes 3 buffers
245 {
246 }
247
248@@ -46,16 +47,43 @@
249 {
250 }
251
252+void mc::SwapperFactory::change_swapper_size(
253+ std::vector<std::shared_ptr<mc::Buffer>>& list,
254+ size_t const desired_size, size_t current_size, BufferProperties const& buffer_properties) const
255+{
256+ while (current_size < desired_size)
257+ {
258+ list.push_back(gr_allocator->alloc_buffer(buffer_properties));
259+ current_size++;
260+ }
261+
262+ while (current_size > desired_size)
263+ {
264+ if (list.empty())
265+ {
266+ BOOST_THROW_EXCEPTION(std::logic_error("SwapperFactory could not change algorithm"));
267+ }
268+ else
269+ {
270+ list.pop_back();
271+ current_size--;
272+ }
273+ }
274+}
275+
276 std::shared_ptr<mc::BufferSwapper> mc::SwapperFactory::create_swapper_reuse_buffers(
277- std::vector<std::shared_ptr<Buffer>>& list, size_t buffer_num, SwapperType type) const
278+ BufferProperties const& buffer_properties, std::vector<std::shared_ptr<Buffer>>& list,
279+ size_t buffer_num, SwapperType type) const
280 {
281 if (type == mc::SwapperType::synchronous)
282 {
283- return std::make_shared<mc::BufferSwapperMulti>(list, buffer_num);
284+ change_swapper_size(list, synchronous_number_of_buffers, buffer_num, buffer_properties);
285+ return std::make_shared<mc::BufferSwapperMulti>(list, synchronous_number_of_buffers);
286 }
287 else
288 {
289- return std::make_shared<mc::BufferSwapperSpin>(list, buffer_num);
290+ change_swapper_size(list, spin_number_of_buffers, buffer_num, buffer_properties);
291+ return std::make_shared<mc::BufferSwapperSpin>(list, spin_number_of_buffers);
292 }
293 }
294
295@@ -68,20 +96,19 @@
296
297 if (type == mc::SwapperType::synchronous)
298 {
299- for(auto i=0; i< number_of_buffers; i++)
300+ for(auto i=0u; i< synchronous_number_of_buffers; i++)
301 {
302 list.push_back(gr_allocator->alloc_buffer(requested_buffer_properties));
303 }
304- new_swapper = std::make_shared<mc::BufferSwapperMulti>(list, number_of_buffers);
305+ new_swapper = std::make_shared<mc::BufferSwapperMulti>(list, synchronous_number_of_buffers);
306 }
307 else
308 {
309- int const async_buffer_count = 3; //async only can accept 3 buffers, so ignore constructor request
310- for(auto i=0; i < async_buffer_count; i++)
311+ for(auto i=0u; i < spin_number_of_buffers; i++)
312 {
313 list.push_back(gr_allocator->alloc_buffer(requested_buffer_properties));
314 }
315- new_swapper = std::make_shared<mc::BufferSwapperSpin>(list, async_buffer_count);
316+ new_swapper = std::make_shared<mc::BufferSwapperSpin>(list, spin_number_of_buffers);
317 }
318
319 actual_buffer_properties = BufferProperties{
320
321=== modified file 'src/server/compositor/switching_bundle.cpp'
322--- src/server/compositor/switching_bundle.cpp 2013-06-15 11:09:16 +0000
323+++ src/server/compositor/switching_bundle.cpp 2013-06-25 19:32:30 +0000
324@@ -92,9 +92,9 @@
325 swapper->end_responsibility(list, size);
326
327 if (allow_dropping)
328- swapper = swapper_factory->create_swapper_reuse_buffers(list, size, mc::SwapperType::framedropping);
329+ swapper = swapper_factory->create_swapper_reuse_buffers(bundle_properties, list, size, mc::SwapperType::framedropping);
330 else
331- swapper = swapper_factory->create_swapper_reuse_buffers(list, size, mc::SwapperType::synchronous);
332+ swapper = swapper_factory->create_swapper_reuse_buffers(bundle_properties, list, size, mc::SwapperType::synchronous);
333
334 cv.notify_all();
335 }
336
337=== modified file 'src/server/shell/surface.cpp'
338--- src/server/shell/surface.cpp 2013-06-25 05:42:49 +0000
339+++ src/server/shell/surface.cpp 2013-06-25 19:32:30 +0000
340@@ -189,6 +189,14 @@
341 }
342 }
343
344+void msh::Surface::allow_framedropping(bool allow)
345+{
346+ if (auto const& s = surface.lock())
347+ {
348+ s->allow_framedropping(allow);
349+ }
350+}
351+
352 void msh::Surface::with_most_recent_buffer_do(
353 std::function<void(mc::Buffer&)> const& exec)
354 {
355@@ -242,7 +250,7 @@
356 int msh::Surface::configure(MirSurfaceAttrib attrib, int value)
357 {
358 int result = 0;
359-
360+ bool allow_dropping = false;
361 /*
362 * TODO: In future, query the shell implementation for the subset of
363 * attributes/types it implements.
364@@ -261,6 +269,11 @@
365 BOOST_THROW_EXCEPTION(std::logic_error("Invalid surface state."));
366 result = state();
367 break;
368+ case mir_surface_attrib_swapinterval:
369+ allow_dropping = (value == 0);
370+ allow_framedropping(allow_dropping);
371+ result = value;
372+ break;
373 default:
374 BOOST_THROW_EXCEPTION(std::logic_error("Invalid surface "
375 "attribute."));
376
377=== modified file 'src/server/surfaces/surface.cpp'
378--- src/server/surfaces/surface.cpp 2013-06-25 05:42:49 +0000
379+++ src/server/surfaces/surface.cpp 2013-06-25 19:32:30 +0000
380@@ -176,6 +176,11 @@
381 return buffer_stream->secure_client_buffer();
382 }
383
384+void ms::Surface::allow_framedropping(bool allow)
385+{
386+ buffer_stream->allow_framedropping(allow);
387+}
388+
389 std::shared_ptr<mc::Buffer> ms::Surface::compositor_buffer() const
390 {
391 return buffer_stream->lock_back_buffer();
392
393=== modified file 'tests/integration-tests/CMakeLists.txt'
394--- tests/integration-tests/CMakeLists.txt 2013-06-25 03:25:49 +0000
395+++ tests/integration-tests/CMakeLists.txt 2013-06-25 19:32:30 +0000
396@@ -7,6 +7,7 @@
397 test_display_info.cpp
398 test_display_server_main_loop_events.cpp
399 test_surface_first_frame_sync.cpp
400+ test_swapinterval.cpp
401 )
402
403 add_subdirectory(client/)
404
405=== added file 'tests/integration-tests/test_swapinterval.cpp'
406--- tests/integration-tests/test_swapinterval.cpp 1970-01-01 00:00:00 +0000
407+++ tests/integration-tests/test_swapinterval.cpp 2013-06-25 19:32:30 +0000
408@@ -0,0 +1,226 @@
409+/*
410+ * Copyright © 2013 Canonical Ltd.
411+ *
412+ * This program is free software: you can redistribute it and/or modify
413+ * it under the terms of the GNU General Public License version 3 as
414+ * published by the Free Software Foundation.
415+ *
416+ * This program is distributed in the hope that it will be useful,
417+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
418+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
419+ * GNU General Public License for more details.
420+ *
421+ * You should have received a copy of the GNU General Public License
422+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
423+ *
424+ * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
425+ */
426+
427+#include "mir/geometry/rectangle.h"
428+#include "mir/graphics/display.h"
429+#include "mir/graphics/display_buffer.h"
430+#include "mir/graphics/renderer.h"
431+#include "mir/graphics/renderable.h"
432+#include "mir/compositor/compositor.h"
433+#include "mir/compositor/compositing_strategy.h"
434+#include "mir/compositor/renderables.h"
435+#include "mir/surfaces/buffer_stream.h"
436+#include "mir/surfaces/buffer_stream_factory.h"
437+
438+#include "mir_test_framework/display_server_test_fixture.h"
439+#include "mir_test_doubles/stub_buffer.h"
440+
441+#include "mir_toolkit/mir_client_library.h"
442+
443+#include <gtest/gtest.h>
444+
445+#include <thread>
446+#include <unistd.h>
447+#include <fcntl.h>
448+
449+namespace geom = mir::geometry;
450+namespace mg = mir::graphics;
451+namespace mc = mir::compositor;
452+namespace mtf = mir_test_framework;
453+namespace ms = mir::surfaces;
454+namespace mtd = mir::test::doubles;
455+
456+namespace
457+{
458+char const* const mir_test_socket = mtf::test_socket_file().c_str();
459+
460+class CountingBufferStream : public ms::BufferStream
461+{
462+public:
463+ CountingBufferStream(int render_operations_fd)
464+ : render_operations_fd(render_operations_fd)
465+ {
466+ }
467+
468+ std::shared_ptr<mc::Buffer> secure_client_buffer() { return std::make_shared<mtd::StubBuffer>(); }
469+ std::shared_ptr<mc::Buffer> lock_back_buffer() { return std::make_shared<mtd::StubBuffer>(); }
470+ geom::PixelFormat get_stream_pixel_format() { return geom::PixelFormat::abgr_8888; }
471+ geom::Size stream_size() { return geom::Size{}; }
472+ void force_requests_to_complete() {}
473+ void allow_framedropping(bool)
474+ {
475+ while (write(render_operations_fd, "a", 1) != 1) continue;
476+ }
477+
478+private:
479+ int render_operations_fd;
480+};
481+
482+class StubStreamFactory : public ms::BufferStreamFactory
483+{
484+public:
485+ StubStreamFactory(int render_operations_fd)
486+ : render_operations_fd(render_operations_fd)
487+ {
488+ }
489+
490+ std::shared_ptr<ms::BufferStream> create_buffer_stream(mc::BufferProperties const&)
491+ {
492+ return std::make_shared<CountingBufferStream>(render_operations_fd);
493+ }
494+private:
495+ int render_operations_fd;
496+};
497+
498+}
499+
500+using SwapIntervalSignalTest = BespokeDisplayServerTestFixture;
501+TEST_F(SwapIntervalSignalTest, swapinterval_test)
502+{
503+ static std::string const swapinterval_set{"swapinterval_set_952f3f10.tmp"};
504+ static std::string const do_client_finish{"do_client_finish_952f3f10.tmp"};
505+
506+ std::remove(swapinterval_set.c_str());
507+ std::remove(do_client_finish.c_str());
508+
509+ struct ServerConfig : TestingServerConfiguration
510+ {
511+ ServerConfig()
512+ {
513+ if (pipe(rendering_ops_pipe) != 0)
514+ {
515+ BOOST_THROW_EXCEPTION(
516+ std::runtime_error("Failed to create pipe"));
517+ }
518+
519+ if (fcntl(rendering_ops_pipe[0], F_SETFL, O_NONBLOCK) != 0)
520+ {
521+ BOOST_THROW_EXCEPTION(
522+ std::runtime_error("Failed to make the read end of the pipe non-blocking"));
523+ }
524+ }
525+
526+ ~ServerConfig()
527+ {
528+ if (rendering_ops_pipe[0] >= 0)
529+ close(rendering_ops_pipe[0]);
530+ if (rendering_ops_pipe[1] >= 0)
531+ close(rendering_ops_pipe[1]);
532+ }
533+
534+ std::shared_ptr<ms::BufferStreamFactory> the_buffer_stream_factory() override
535+ {
536+ if (!stub_stream_factory)
537+ stub_stream_factory = std::make_shared<StubStreamFactory>(rendering_ops_pipe[1]);
538+ return stub_stream_factory;
539+ }
540+
541+ int num_of_swapinterval_commands()
542+ {
543+ char c;
544+ int ops{0};
545+
546+ while (read(rendering_ops_pipe[0], &c, 1) == 1)
547+ ops++;
548+
549+ return ops;
550+ }
551+
552+ int rendering_ops_pipe[2];
553+ std::shared_ptr<StubStreamFactory> stub_stream_factory;
554+ } server_config;
555+
556+ launch_server_process(server_config);
557+
558+ struct ClientConfig : TestingClientConfiguration
559+ {
560+ ClientConfig(std::string const& swapinterval_set,
561+ std::string const& do_client_finish)
562+ : swapinterval_set{swapinterval_set},
563+ do_client_finish{do_client_finish}
564+ {
565+ }
566+
567+ static void surface_callback(MirSurface*, void*)
568+ {
569+ }
570+
571+ void exec()
572+ {
573+ MirSurfaceParameters request_params =
574+ {
575+ __PRETTY_FUNCTION__,
576+ 640, 480,
577+ mir_pixel_format_abgr_8888,
578+ mir_buffer_usage_hardware
579+ };
580+
581+ MirConnection* connection = mir_connect_sync(mir_test_socket, "testapp");
582+ MirSurface* surface = mir_connection_create_surface_sync(connection, &request_params);
583+
584+ //1 is the default swapinterval
585+ EXPECT_EQ(1, mir_surface_get_swapinterval(surface));
586+
587+ mir_wait_for(mir_surface_set_swapinterval(surface, 0));
588+ EXPECT_EQ(0, mir_surface_get_swapinterval(surface));
589+
590+ mir_wait_for(mir_surface_set_swapinterval(surface, 1));
591+ EXPECT_EQ(1, mir_surface_get_swapinterval(surface));
592+
593+ //swapinterval 2 not supported
594+ EXPECT_EQ(NULL, mir_surface_set_swapinterval(surface, 2));
595+ EXPECT_EQ(1, mir_surface_get_swapinterval(surface));
596+
597+ set_flag(swapinterval_set);
598+ wait_for(do_client_finish);
599+
600+ mir_surface_release_sync(surface);
601+ mir_connection_release(connection);
602+ }
603+
604+ /* TODO: Extract this flag mechanism and make it reusable */
605+ void set_flag(std::string const& flag_file)
606+ {
607+ close(open(flag_file.c_str(), O_CREAT, S_IWUSR | S_IRUSR));
608+ }
609+
610+ void wait_for(std::string const& flag_file)
611+ {
612+ int fd = -1;
613+ while ((fd = open(flag_file.c_str(), O_RDONLY, S_IWUSR | S_IRUSR)) == -1)
614+ {
615+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
616+ }
617+ close(fd);
618+ }
619+
620+ std::string const swapinterval_set;
621+ std::string const do_client_finish;
622+ } client_config{swapinterval_set, do_client_finish};
623+
624+ launch_client_process(client_config);
625+
626+ run_in_test_process([&]
627+ {
628+ client_config.wait_for(swapinterval_set);
629+
630+ EXPECT_EQ(2, server_config.num_of_swapinterval_commands());
631+
632+ client_config.set_flag(do_client_finish);
633+ });
634+}
635
636=== modified file 'tests/unit-tests/compositor/test_buffer_stream.cpp'
637--- tests/unit-tests/compositor/test_buffer_stream.cpp 2013-06-17 15:55:04 +0000
638+++ tests/unit-tests/compositor/test_buffer_stream.cpp 2013-06-25 19:32:30 +0000
639@@ -122,3 +122,12 @@
640
641 buffer_stream.secure_client_buffer();
642 }
643+
644+TEST_F(BufferStreamTest, allow_framedropping_command)
645+{
646+ EXPECT_CALL(*mock_bundle, allow_framedropping(true))
647+ .Times(1);
648+
649+ mc::BufferStreamSurfaces buffer_stream(mock_bundle);
650+ buffer_stream.allow_framedropping(true);
651+}
652
653=== modified file 'tests/unit-tests/compositor/test_swapper_factory.cpp'
654--- tests/unit-tests/compositor/test_swapper_factory.cpp 2013-06-11 19:55:10 +0000
655+++ tests/unit-tests/compositor/test_swapper_factory.cpp 2013-06-25 19:32:30 +0000
656@@ -147,6 +147,7 @@
657 {
658 using namespace testing;
659
660+ mc::BufferProperties properties;
661 std::vector<std::shared_ptr<mc::Buffer>> list {};
662 size_t size = 3;
663
664@@ -154,19 +155,66 @@
665 .Times(0);
666
667 mc::SwapperFactory strategy(mock_buffer_allocator);
668- auto swapper = strategy.create_swapper_reuse_buffers(list, size, mc::SwapperType::framedropping);
669+ auto swapper = strategy.create_swapper_reuse_buffers(properties, list, size, mc::SwapperType::framedropping);
670 }
671
672 TEST_F(SwapperFactoryTest, create_sync_reuse)
673 {
674 using namespace testing;
675
676+ mc::BufferProperties properties;
677 std::vector<std::shared_ptr<mc::Buffer>> list;
678 size_t size = 3;
679
680 EXPECT_CALL(*mock_buffer_allocator, alloc_buffer(properties))
681 .Times(0);
682
683+ mc::SwapperFactory strategy(mock_buffer_allocator, 3);
684+ auto swapper = strategy.create_swapper_reuse_buffers(properties, list, size, mc::SwapperType::synchronous);
685+}
686+
687+TEST_F(SwapperFactoryTest, reuse_drop_unneeded_buffer)
688+{
689+ using namespace testing;
690+
691+ mc::SwapperFactory strategy(mock_buffer_allocator, 2);
692+
693+ auto buffer = std::make_shared<mtd::StubBuffer>();
694+ {
695+ size_t size = 3;
696+ std::vector<std::shared_ptr<mc::Buffer>> list{buffer};
697+
698+ auto swapper = strategy.create_swapper_reuse_buffers(
699+ properties, list, size, mc::SwapperType::synchronous);
700+ }
701+ EXPECT_EQ(1, buffer.use_count());
702+}
703+
704+TEST_F(SwapperFactoryTest, reuse_drop_unneeded_buffer_error)
705+{
706+ using namespace testing;
707+
708+ mc::SwapperFactory strategy(mock_buffer_allocator, 2);
709+
710+ size_t size = 3;
711+ std::vector<std::shared_ptr<mc::Buffer>> list{};
712+
713+ EXPECT_THROW({
714+ strategy.create_swapper_reuse_buffers(
715+ properties, list, size, mc::SwapperType::synchronous);
716+ }, std::logic_error);
717+}
718+
719+TEST_F(SwapperFactoryTest, reuse_alloc_additional_buffer_for_framedropping)
720+{
721+ using namespace testing;
722+
723+ EXPECT_CALL(*mock_buffer_allocator, alloc_buffer(_))
724+ .Times(1);
725 mc::SwapperFactory strategy(mock_buffer_allocator);
726- auto swapper = strategy.create_swapper_reuse_buffers(list, size, mc::SwapperType::synchronous);
727+
728+ size_t size = 2;
729+ std::vector<std::shared_ptr<mc::Buffer>> list{};
730+ auto swapper = strategy.create_swapper_reuse_buffers(
731+ properties, list, size, mc::SwapperType::framedropping);
732 }
733
734=== modified file 'tests/unit-tests/compositor/test_switching_bundle.cpp'
735--- tests/unit-tests/compositor/test_switching_bundle.cpp 2013-06-13 08:59:25 +0000
736+++ tests/unit-tests/compositor/test_switching_bundle.cpp 2013-06-25 19:32:30 +0000
737@@ -90,7 +90,7 @@
738 .WillOnce(Return(stub_buffer));
739 EXPECT_CALL(*mock_secondary_swapper, client_release(stub_buffer))
740 .Times(1);
741- EXPECT_CALL(*mock_swapper_factory, create_swapper_reuse_buffers(_,_,_))
742+ EXPECT_CALL(*mock_swapper_factory, create_swapper_reuse_buffers(_,_,_,_))
743 .Times(1)
744 .WillOnce(Return(mock_secondary_swapper));
745
746@@ -126,7 +126,7 @@
747 .WillOnce(Return(stub_buffer));
748 EXPECT_CALL(*mock_secondary_swapper, compositor_release(stub_buffer))
749 .Times(1);
750- EXPECT_CALL(*mock_swapper_factory, create_swapper_reuse_buffers(_,_,_))
751+ EXPECT_CALL(*mock_swapper_factory, create_swapper_reuse_buffers(_,_,_,_))
752 .Times(1)
753 .WillOnce(Return(mock_secondary_swapper));
754
755@@ -147,7 +147,7 @@
756 .Times(1);
757 EXPECT_CALL(*mock_default_swapper, end_responsibility(_,_))
758 .Times(1);
759- EXPECT_CALL(*mock_swapper_factory, create_swapper_reuse_buffers(_,_,mc::SwapperType::framedropping))
760+ EXPECT_CALL(*mock_swapper_factory, create_swapper_reuse_buffers(_,_,_,mc::SwapperType::framedropping))
761 .Times(1)
762 .WillOnce(Return(mock_secondary_swapper));
763
764
765=== modified file 'tests/unit-tests/surfaces/test_surface.cpp'
766--- tests/unit-tests/surfaces/test_surface.cpp 2013-06-25 05:42:49 +0000
767+++ tests/unit-tests/surfaces/test_surface.cpp 2013-06-25 19:32:30 +0000
768@@ -445,6 +445,18 @@
769 surf.force_requests_to_complete();
770 }
771
772+TEST_F(SurfaceCreation, test_surface_allow_framedropping)
773+{
774+ using namespace testing;
775+
776+ EXPECT_CALL(*mock_buffer_stream, allow_framedropping(true))
777+ .Times(1);
778+
779+ ms::Surface surf{surface_name, geom::Point(), mock_buffer_stream,
780+ std::shared_ptr<mi::InputChannel>(), mock_change_cb};
781+ surf.allow_framedropping(true);
782+}
783+
784 TEST_F(SurfaceCreation, test_surface_next_buffer_does_not_set_valid_until_second_frame)
785 {
786 ms::Surface surf{surface_name, geom::Point(), mock_buffer_stream,

Subscribers

People subscribed via source and target branches