Mir

Merge lp:~vanvugt/mir/manual-vsync-api-v3 into lp:mir

Proposed by Daniel van Vugt on 2017-05-01
Status: Merged
Approved by: Daniel van Vugt on 2017-05-08
Approved revision: 4164
Merged at revision: 4165
Proposed branch: lp:~vanvugt/mir/manual-vsync-api-v3
Merge into: lp:mir
Diff against target: 339 lines (+135/-2)
13 files modified
examples/eglapp.c (+18/-1)
include/client/mir_toolkit/mir_buffer_stream.h (+20/-0)
src/client/buffer_stream.cpp (+33/-0)
src/client/buffer_stream.h (+3/-0)
src/client/error_stream.cpp (+6/-0)
src/client/error_stream.h (+1/-0)
src/client/mir_buffer_stream_api.cpp (+7/-0)
src/client/screencast_stream.cpp (+5/-0)
src/client/screencast_stream.h (+1/-0)
src/client/symbols.map (+6/-1)
src/include/client/mir/mir_buffer_stream.h (+2/-0)
tests/acceptance-tests/test_latency.cpp (+32/-0)
tests/include/mir/test/doubles/mock_mir_buffer_stream.h (+1/-0)
To merge this branch: bzr merge lp:~vanvugt/mir/manual-vsync-api-v3
Reviewer Review Type Date Requested Status
Mir CI Bot continuous-integration Approve on 2017-05-08
Andreas Pokorny (community) Approve on 2017-05-05
Mir development team 2017-05-01 Pending
Review via email: mp+323452@code.launchpad.net

Commit message

Introducing a trivial API function that allows clients to throttle
themselves without ever blocking inside any thirdparty code. This is
useful for single-threaded apps/toolkits that want to achieve vsync
but don't want callbacks, or to make any blocking function calls
outside their main loop.

The intended methodology is for a client to set swap interval zero
and then use this new function to throttle its own swaps.

      mir_buffer_stream_set_swapinterval(s, 0);
      while (running)
      {
          sleep_for(mir_buffer_stream_get_microseconds_till_vblank(s));
          render();
          mir_buffer_stream_swap_buffers_sync(s);
      }

Description of the change

Q: Why relative timing?
A: Because it's portable to arbitrary clock/timing APIs that clients and
   toolkits may use. The loss of precision in using relative over absolute
   timestamps will never be perceptible because we still have microsecond
   accuracy, which is well below human perception. Also, the loss of
   precision will be self-correcting on every frame (never accumulates)
   since Mir tracks timestamps more precisely internally.

Q: Why provide a MirBufferStream function and not a MirWindow function?
A: Because each buffer stream contains a little bit of state
   information that allows FrameClock to vary the result depending on
   whether the specific stream is hitting frame deadlines (and if not will
   get a boost instead of decimating to half frame rate).

Q: What's wrong with the existing callback approach?
A: The problem with mir_buffer_stream_swap_buffers is that it hasn't yet
   been ported to use client-side vsync (for lower latency and higher
   smoothness). If we were to port it blindly then re-implementing swap
   interval one behaviour would require libmirclient to implement the
   delay itself by either blocking the RPC thread or by introducing a new
   hidden thread to do the blocking-before-callback. The proposed function
   here allows us to avoid that ugliness in libmirclient and move
   responsibility for the blocking into the app/toolkit code. Thus we
   never need to fully port mir_buffer_stream_swap_buffers to client-side
   vsync because it will be redundant and can be deprecated or ignored.

To post a comment you must log in.
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:4163
https://mir-jenkins.ubuntu.com/job/mir-ci/3384/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4582/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4710
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4699
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4699
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4614/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4614
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4614/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4614
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4614/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4614
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4614/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4614
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4614/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3384/rebuild

review: Needs Fixing (continuous-integration)
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:4164
https://mir-jenkins.ubuntu.com/job/mir-ci/3387/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/4585
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4713
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4702
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4702
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4617
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4617/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4617
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4617/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4617
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4617/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4617
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4617/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4617
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4617/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3387/rebuild

review: Approve (continuous-integration)
Andreas Pokorny (andreas-pokorny) wrote :

Really as a method on buffer stream? I am confused about your bufferstream answer..
Especially since EGL clients would not have access to the buffer stream...

Otherwise lgtm

review: Needs Information
Daniel van Vugt (vanvugt) wrote :

Yes, it can be implemented as a MirWindow function or a MirBufferStream function. However because swaps are per-stream, implementing it as a MirWindow function lacks information about past swaps, and so you lose the ability to catch up after missed frame deadlines. The result then is 1/2, 1/3, or 1/4 ... frame rate.

As a MirBufferStream function we get to use information from the last swap to determine whether we really need to wait for the next vsync or if we already missed the deadline (and so should not wait at all). So as a MirBufferStream function you avoid slow clients decimating to half/third/whatever frame rate. The MirWindow prototype of this branch lacks that ability, which is a major feature of FrameClock that would have gone to waste (although users of eglSwapBuffers with interval>=1 still get it for free).

I only just noticed recently that mir_window_get_buffer_stream is marked as deprecated. That's fine - we already knew that whoever completed the transition to MirRenderSurface would need to also port client-side vsync. So if that eventually happens a new function would be required that operates on a render surface.

If it's too contentious I can propose the MirWindow version of this, but it would be sad to drop the catch-up feature and end up decimating.

Andreas Pokorny (andreas-pokorny) wrote :

> I only just noticed recently that mir_window_get_buffer_stream is marked as
> deprecated. That's fine - we already knew that whoever completed the
> transition to MirRenderSurface would need to also port client-side vsync. So
> if that eventually happens a new function would be required that operates on a
> render surface.

Ok I think render surface is good too.

review: Approve
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Autolanding.
More details in the following jenkins job:
https://mir-jenkins.ubuntu.com/job/mir-autolanding/1298/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4601/console
    None: https://mir-jenkins.ubuntu.com/job/generic-land-mp/1382/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/4729
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/4718
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/4718
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4633
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4633/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4633
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/4633/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4633/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4633
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4633/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4633
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/4633/artifact/output/*zip*/output.zip

review: Needs Fixing (continuous-integration)
Daniel van Vugt (vanvugt) wrote :
Mir CI Bot (mir-ci-bot) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'examples/eglapp.c'
2--- examples/eglapp.c 2017-04-28 09:52:43 +0000
3+++ examples/eglapp.c 2017-05-02 02:51:32 +0000
4@@ -22,6 +22,7 @@
5 #include <stdlib.h>
6 #include <signal.h>
7 #include <time.h>
8+#include <errno.h>
9 #include <string.h>
10 #include <EGL/egl.h>
11 #include <GLES2/gl2.h>
12@@ -38,6 +39,7 @@
13 static EGLSurface eglsurface;
14 static volatile sig_atomic_t running = 0;
15 static double refresh_rate = 0.0;
16+static mir_eglapp_bool alt_vsync = 0;
17
18 #pragma GCC diagnostic push
19 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
20@@ -84,6 +86,15 @@
21 return running;
22 }
23
24+/* Apparently usleep is deprecated so we write own own... */
25+static void micro_sleep(unsigned long usec)
26+{
27+ struct timespec ts = {0, usec * 1000};
28+ while (nanosleep(&ts, &ts) && errno == EINTR)
29+ {
30+ }
31+}
32+
33 void mir_eglapp_swap_buffers(void)
34 {
35 EGLint width, height;
36@@ -92,6 +103,11 @@
37 return;
38
39 eglSwapBuffers(egldisplay, eglsurface);
40+ if (alt_vsync)
41+ {
42+ MirBufferStream* bs = mir_window_get_buffer_stream(window);
43+ micro_sleep(mir_buffer_stream_get_microseconds_till_vblank(bs));
44+ }
45
46 /*
47 * Querying the surface (actually the current buffer) dimensions here is
48@@ -347,6 +363,7 @@
49 {"-h", "!", &help, "Show this help text"},
50 {"-m <socket>", "=", &mir_socket, "Mir server socket"},
51 {"-n", "!", &no_vsync, "Don't sync to vblank"},
52+ {"-v", "!", &alt_vsync, "Sync to vblank using the alternate method (manual timing)"},
53 {"-o <id>", "%u", &output_id, "Force placement on output monitor ID"},
54 {"-q", "!", &quiet, "Quiet mode (no messages output)"},
55 {"-s <width>x<height>", "=", &dims, "Force window size"},
56@@ -372,7 +389,7 @@
57 return 0;
58 }
59
60- if (no_vsync)
61+ if (no_vsync || alt_vsync)
62 swapinterval = 0;
63
64 if (dims)
65
66=== modified file 'include/client/mir_toolkit/mir_buffer_stream.h'
67--- include/client/mir_toolkit/mir_buffer_stream.h 2017-04-13 07:00:27 +0000
68+++ include/client/mir_toolkit/mir_buffer_stream.h 2017-05-02 02:51:32 +0000
69@@ -256,6 +256,26 @@
70 int mir_buffer_stream_get_swapinterval(MirBufferStream* stream);
71
72 /**
73+ * Query the approximate time interval in microseconds until the next vblank
74+ * for a given buffer stream (actually the next vblank for the monitor deemed
75+ * most relevant to the window using the buffer stream). The result of
76+ * (current_time + mir_buffer_stream_get_microseconds_till_vblank()) is the
77+ * precise time at which the client should start rendering the next frame (or
78+ * at least when it should sample its inputs/scene) so as to produce perfectly
79+ * smooth rendering.
80+ *
81+ * \note This function is only needed for streams that have been configured
82+ * with a swap interval of zero. Streams with non-zero swap intervals
83+ * already have accurate synchronization and throttling built in to the
84+ * mir_buffer_stream_swap_buffers_sync() function.
85+ *
86+ * \param [in] stream The buffer stream
87+ * \return Time in microseconds to the next vblank for the
88+ * given buffer stream (may be as low as zero).
89+ */
90+unsigned long mir_buffer_stream_get_microseconds_till_vblank(MirBufferStream const* stream);
91+
92+/**
93 * Set the physical size of the buffers provided by the buffer stream.
94 *
95 * \warning: This does not affect the size of the current buffer.
96
97=== modified file 'src/client/buffer_stream.cpp'
98--- src/client/buffer_stream.cpp 2017-04-13 07:00:27 +0000
99+++ src/client/buffer_stream.cpp 2017-05-02 02:51:32 +0000
100@@ -436,6 +436,36 @@
101 }
102 #pragma GCC diagnostic pop
103
104+std::chrono::microseconds mcl::BufferStream::microseconds_till_vblank() const
105+{
106+ std::chrono::microseconds ret(0);
107+ mir::time::PosixTimestamp last;
108+ std::shared_ptr<FrameClock> clock;
109+
110+ {
111+ std::lock_guard<decltype(mutex)> lock(mutex);
112+ last = last_vsync;
113+ clock = frame_clock;
114+ }
115+
116+ if (clock)
117+ {
118+ // We are unlocked because in future this call might ping the server:
119+ mir::time::PosixTimestamp const target = clock->next_frame_after(last);
120+ auto const now = mir::time::PosixTimestamp::now(target.clock_id);
121+ if (target > now)
122+ {
123+ ret = std::chrono::duration_cast<std::chrono::microseconds>(
124+ target - now);
125+ }
126+
127+ std::lock_guard<decltype(mutex)> lock(mutex);
128+ next_vsync = target;
129+ }
130+
131+ return ret;
132+}
133+
134 void mcl::BufferStream::wait_for_vsync()
135 {
136 mir::time::PosixTimestamp last, target;
137@@ -503,6 +533,9 @@
138 int interval = swap_interval();
139 for (int i = 0; i < interval; ++i)
140 wait_for_vsync();
141+
142+ if (!interval) // wait_for_vsync wasn't called to update last_vsync
143+ last_vsync = next_vsync;
144 }
145
146 void mcl::BufferStream::request_and_wait_for_configure(MirWindowAttrib attrib, int interval)
147
148=== modified file 'src/client/buffer_stream.h'
149--- src/client/buffer_stream.h 2017-04-13 07:00:27 +0000
150+++ src/client/buffer_stream.h 2017-05-02 02:51:32 +0000
151@@ -137,6 +137,8 @@
152 MirRenderSurface* render_surface() const override;
153 #pragma GCC diagnostic pop
154
155+ std::chrono::microseconds microseconds_till_vblank() const override;
156+
157 protected:
158 BufferStream(BufferStream const&) = delete;
159 BufferStream& operator=(BufferStream const&) = delete;
160@@ -181,6 +183,7 @@
161 std::unordered_set<MirWindow*> users;
162 std::shared_ptr<FrameClock> frame_clock;
163 mir::time::PosixTimestamp last_vsync;
164+ mutable mir::time::PosixTimestamp next_vsync;
165 };
166
167 }
168
169=== modified file 'src/client/error_stream.cpp'
170--- src/client/error_stream.cpp 2017-04-13 07:00:27 +0000
171+++ src/client/error_stream.cpp 2017-05-02 02:51:32 +0000
172@@ -106,6 +106,12 @@
173 void mcl::ErrorStream::unadopted_by(MirWindow*)
174 {
175 }
176+
177+std::chrono::microseconds mcl::ErrorStream::microseconds_till_vblank() const
178+{
179+ return std::chrono::microseconds::zero();
180+}
181+
182 MirNativeBuffer* mcl::ErrorStream::get_current_buffer_package()
183 {
184 BOOST_THROW_EXCEPTION(std::runtime_error(error));
185
186=== modified file 'src/client/error_stream.h'
187--- src/client/error_stream.h 2017-04-13 07:00:27 +0000
188+++ src/client/error_stream.h 2017-05-02 02:51:32 +0000
189@@ -45,6 +45,7 @@
190 MirWaitHandle* set_swap_interval(int interval) override;
191 void adopted_by(MirWindow*) override;
192 void unadopted_by(MirWindow*) override;
193+ std::chrono::microseconds microseconds_till_vblank() const override;
194 MirNativeBuffer* get_current_buffer_package() override;
195 MirPlatformType platform_type() override;
196 frontend::BufferStreamId rpc_id() const override;
197
198=== modified file 'src/client/mir_buffer_stream_api.cpp'
199--- src/client/mir_buffer_stream_api.cpp 2017-04-13 07:00:27 +0000
200+++ src/client/mir_buffer_stream_api.cpp 2017-05-02 02:51:32 +0000
201@@ -251,6 +251,13 @@
202 return -1;
203 }
204
205+unsigned long mir_buffer_stream_get_microseconds_till_vblank(
206+ MirBufferStream const* stream)
207+{
208+ mir::require(stream);
209+ return stream->microseconds_till_vblank().count();
210+}
211+
212 void mir_buffer_stream_set_size(MirBufferStream* stream, int width, int height)
213 try
214 {
215
216=== modified file 'src/client/screencast_stream.cpp'
217--- src/client/screencast_stream.cpp 2017-04-13 07:00:27 +0000
218+++ src/client/screencast_stream.cpp 2017-05-02 02:51:32 +0000
219@@ -278,6 +278,11 @@
220 {
221 }
222
223+std::chrono::microseconds mcl::ScreencastStream::microseconds_till_vblank() const
224+{
225+ return std::chrono::microseconds::zero();
226+}
227+
228 void mcl::ScreencastStream::set_size(geom::Size)
229 {
230 BOOST_THROW_EXCEPTION(std::logic_error("Attempt to set size on screencast is invalid"));
231
232=== modified file 'src/client/screencast_stream.h'
233--- src/client/screencast_stream.h 2017-04-13 07:00:27 +0000
234+++ src/client/screencast_stream.h 2017-05-02 02:51:32 +0000
235@@ -82,6 +82,7 @@
236 MirWaitHandle* set_swap_interval(int interval) override;
237 void adopted_by(MirWindow*) override;
238 void unadopted_by(MirWindow*) override;
239+ std::chrono::microseconds microseconds_till_vblank() const override;
240 void set_buffer_cache_size(unsigned int) override;
241
242 EGLNativeWindowType egl_native_window() override;
243
244=== modified file 'src/client/symbols.map'
245--- src/client/symbols.map 2017-04-13 07:00:27 +0000
246+++ src/client/symbols.map 2017-05-02 02:51:32 +0000
247@@ -579,7 +579,7 @@
248 };
249 } MIR_CLIENT_DETAIL_0.26.1;
250
251-MIR_CLIENT_0.27 { # New functions in Mir 0.27 or 1.0
252+MIR_CLIENT_0.27 { # New functions in Mir 0.27
253 global:
254 mir_connection_apply_session_input_config;
255 mir_connection_set_base_input_config;
256@@ -611,3 +611,8 @@
257 mir_touchscreen_config_set_mapping_mode;
258 mir_touchscreen_config_set_output_id;
259 } MIR_CLIENT_0.26.1;
260+
261+MIR_CLIENT_0.28 { # New functions in Mir 0.28 (or 1.0)
262+ global:
263+ mir_buffer_stream_get_microseconds_till_vblank;
264+} MIR_CLIENT_0.27;
265
266=== modified file 'src/include/client/mir/mir_buffer_stream.h'
267--- src/include/client/mir/mir_buffer_stream.h 2017-04-21 03:08:25 +0000
268+++ src/include/client/mir/mir_buffer_stream.h 2017-05-02 02:51:32 +0000
269@@ -28,6 +28,7 @@
270 #include "mir_toolkit/client_types.h"
271 #include "mir_toolkit/mir_native_buffer.h"
272
273+#include <chrono>
274 #include <memory>
275 #include <functional>
276 #include <EGL/eglplatform.h>
277@@ -94,6 +95,7 @@
278 virtual MirWaitHandle* set_swap_interval(int interval) = 0;
279 virtual void adopted_by(MirWindow*) = 0;
280 virtual void unadopted_by(MirWindow*) = 0;
281+ virtual std::chrono::microseconds microseconds_till_vblank() const = 0;
282
283 virtual MirNativeBuffer* get_current_buffer_package() = 0;
284 virtual MirPlatformType platform_type() = 0;
285
286=== modified file 'tests/acceptance-tests/test_latency.cpp'
287--- tests/acceptance-tests/test_latency.cpp 2017-04-13 07:00:27 +0000
288+++ tests/acceptance-tests/test_latency.cpp 2017-05-02 02:51:32 +0000
289@@ -341,6 +341,38 @@
290 EXPECT_NEAR(1.0f, average_latency, error_margin);
291 }
292
293+TEST_F(ClientLatency, manual_vsync_latency_is_one_frame)
294+{
295+#pragma GCC diagnostic push
296+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
297+ auto stream = mir_window_get_buffer_stream(surface);
298+#pragma GCC diagnostic pop
299+ mir_buffer_stream_set_swapinterval(stream, 0);
300+ stats.swap_interval = 0;
301+
302+ auto const deadline = steady_clock::now() + 60s;
303+
304+ while (stats.frames_composited() < test_frames &&
305+ steady_clock::now() < deadline)
306+ {
307+ auto const us = mir_buffer_stream_get_microseconds_till_vblank(stream);
308+ std::this_thread::sleep_for(microseconds(us));
309+
310+ auto submission_id = mir_debug_window_current_buffer_id(surface);
311+ stats.record_submission(submission_id);
312+ mir_buffer_stream_swap_buffers_sync(stream);
313+ }
314+
315+ ASSERT_THAT(stats.frames_composited(), Ge(test_frames));
316+
317+ if (server.get_options()->get<bool>(mtd::logging_opt))
318+ display.group.dump_latency();
319+
320+ auto average_latency = display.group.average_latency();
321+
322+ EXPECT_NEAR(1.0f, average_latency, error_margin);
323+}
324+
325 TEST_F(ClientLatency, max_latency_is_limited_to_nbuffers)
326 {
327 #pragma GCC diagnostic push
328
329=== modified file 'tests/include/mir/test/doubles/mock_mir_buffer_stream.h'
330--- tests/include/mir/test/doubles/mock_mir_buffer_stream.h 2017-04-13 07:00:27 +0000
331+++ tests/include/mir/test/doubles/mock_mir_buffer_stream.h 2017-05-02 02:51:32 +0000
332@@ -47,6 +47,7 @@
333 MOCK_METHOD1(set_swap_interval, MirWaitHandle*(int));
334 MOCK_METHOD1(adopted_by, void(MirWindow*));
335 MOCK_METHOD1(unadopted_by, void(MirWindow*));
336+ MOCK_CONST_METHOD0(microseconds_till_vblank, std::chrono::microseconds());
337 MOCK_METHOD0(platform_type, MirPlatformType(void));
338 MOCK_METHOD0(get_current_buffer_package, MirNativeBuffer*(void));
339 MOCK_METHOD0(get_create_wait_handle, MirWaitHandle*(void));

Subscribers

People subscribed via source and target branches