Mir

Merge lp:~mir-team/mir/vsync-timings-from-server into lp:mir

Proposed by Robert Carr
Status: Work in progress
Proposed branch: lp:~mir-team/mir/vsync-timings-from-server
Merge into: lp:mir
Diff against target: 2744 lines (+983/-227)
77 files modified
benchmarks/frame-uniformity/vsync_simulating_graphics_platform.cpp (+36/-4)
client-ABI-sha1sums (+1/-1)
common-ABI-sha1sums (+1/-1)
include/client/mir_toolkit/mir_surface.h (+7/-0)
include/common/mir/input/input_receiver_thread.h (+4/-0)
include/platform/mir/graphics/display.h (+10/-0)
include/server/mir/default_server_configuration.h (+3/-0)
platform-ABI-sha1sums (+2/-2)
server-ABI-sha1sums (+3/-3)
src/client/mir_surface.cpp (+18/-1)
src/client/mir_surface.h (+5/-1)
src/client/mir_surface_api.cpp (+5/-0)
src/common/input/android/android_input_receiver.cpp (+45/-56)
src/common/input/android/android_input_receiver.h (+7/-0)
src/common/input/android/android_input_receiver_thread.cpp (+5/-0)
src/common/input/android/android_input_receiver_thread.h (+2/-0)
src/include/platform/mir/frontend/vsync_provider.h (+46/-0)
src/platform/graphics/android/display.cpp (+7/-0)
src/platform/graphics/android/display.h (+2/-0)
src/platform/graphics/android/display_builder.h (+3/-0)
src/platform/graphics/android/display_resource_factory.h (+3/-0)
src/platform/graphics/android/hwc_common_device.cpp (+4/-4)
src/platform/graphics/android/hwc_common_device.h (+2/-1)
src/platform/graphics/android/hwc_vsync.cpp (+25/-3)
src/platform/graphics/android/hwc_vsync.h (+10/-1)
src/platform/graphics/android/hwc_vsync_coordinator.h (+7/-2)
src/platform/graphics/android/output_builder.cpp (+6/-0)
src/platform/graphics/android/output_builder.h (+2/-0)
src/platform/graphics/android/platform.cpp (+4/-1)
src/platform/graphics/android/platform.h (+3/-0)
src/platform/graphics/android/resource_factory.cpp (+12/-4)
src/platform/graphics/android/resource_factory.h (+7/-0)
src/platform/graphics/mesa/display.cpp (+18/-1)
src/platform/graphics/mesa/display.h (+2/-0)
src/protobuf/mir_protobuf.proto (+2/-0)
src/server/frontend/default_configuration.cpp (+21/-9)
src/server/frontend/default_ipc_factory.cpp (+6/-2)
src/server/frontend/default_ipc_factory.h (+5/-1)
src/server/frontend/session_mediator.cpp (+8/-0)
src/server/frontend/session_mediator.h (+3/-0)
src/server/graphics/nested/CMakeLists.txt (+1/-0)
src/server/graphics/nested/host_connection.h (+3/-0)
src/server/graphics/nested/mir_client_host_connection.cpp (+5/-0)
src/server/graphics/nested/nested_display.cpp (+9/-1)
src/server/graphics/nested/nested_display.h (+4/-0)
src/server/graphics/nested/nested_output.cpp (+9/-2)
src/server/graphics/nested/nested_output.h (+9/-1)
src/server/graphics/nested/nested_platform.cpp (+2/-0)
src/server/graphics/nested/nested_vsync_provider.cpp (+45/-0)
src/server/graphics/nested/nested_vsync_provider.h (+49/-0)
src/server/graphics/offscreen/display.cpp (+16/-0)
src/server/graphics/offscreen/display.h (+2/-0)
src/server/symbols.map (+2/-0)
tests/acceptance-tests/test_client_library.cpp (+18/-13)
tests/include/mir_test_doubles/mock_display.h (+1/-0)
tests/include/mir_test_doubles/mock_hwc_vsync_coordinator.h (+3/-1)
tests/include/mir_test_doubles/null_display.h (+5/-0)
tests/include/mir_test_doubles/stub_display.h (+6/-0)
tests/include/mir_test_doubles/stub_display_builder.h (+5/-0)
tests/include/mir_test_doubles/stub_host_connection.h (+1/-0)
tests/include/mir_test_doubles/stub_vsync_provider.h (+43/-0)
tests/include/mir_test_framework/using_stub_client_platform.h (+2/-0)
tests/integration-tests/CMakeLists.txt (+1/-0)
tests/integration-tests/graphics/android/test_display_integration.cpp (+1/-0)
tests/integration-tests/test_surfaceloop.cpp (+7/-0)
tests/integration-tests/test_vsync_to_client.cpp (+225/-0)
tests/mir_test_framework/stubbed_graphics_platform.cpp (+2/-0)
tests/unit-tests/client/input/test_android_input_receiver.cpp (+0/-96)
tests/unit-tests/client/test_client_mir_surface.cpp (+1/-0)
tests/unit-tests/frontend/test_session_mediator.cpp (+48/-5)
tests/unit-tests/graphics/android/CMakeLists.txt (+1/-0)
tests/unit-tests/graphics/android/test_hwc_common_device.cpp (+5/-3)
tests/unit-tests/graphics/android/test_hwc_vsync.cpp (+68/-0)
tests/unit-tests/graphics/android/test_output_builder.cpp (+2/-0)
tests/unit-tests/graphics/android/test_resource_factory.cpp (+6/-3)
tests/unit-tests/graphics/nested/test_nested_display.cpp (+1/-0)
tests/unit-tests/graphics/nested/test_nested_display_buffer.cpp (+13/-4)
To merge this branch: bzr merge lp:~mir-team/mir/vsync-timings-from-server
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
Alberto Aguirre (community) Abstain
Kevin DuBois (community) Needs Fixing
Alan Griffiths Abstain
Daniel van Vugt Needs Fixing
Review via email: mp+240789@code.launchpad.net

Commit message

Send vsync times from server and use in input resampling

Description of the change

Implement vsync timed input resampling as discussed in DC. Lots of noise in the test framework generated by the discovery that UsingStubClientAPI was not working (discovered by the vsync->input thread integration test).

Please test on device and tell me what you think.

To post a comment you must log in.
2024. By Robert Carr

Cleanup

Revision history for this message
Robert Carr (robertcarr) wrote :

The score is consistently better on the frame uniformity test but still not as good as you would want...if you look at distance per sample you see it go down to near zero pixels, but then slowly creep back up 1 pixel at a time. Still its both more responsive and uniform than the existing code or the code before the "synthetic vsync interval" sort of approach.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:2023
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/~mir-team/mir/vsync-timings-from-server/+merge/240789/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/mir-ci/2012/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-android-vivid-i386-build/1
    FAILURE: http://jenkins.qa.ubuntu.com/job/mir-clang-vivid-amd64-build/1/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/mir-vivid-amd64-ci/1/console

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

review: Needs Fixing (continuous-integration)
Revision history for this message
Robert Carr (robertcarr) wrote :

When testing you may notice that shell elements, i.e. indicator bar seem more responsive than client elements...ultimately I think this is due to nesting.

I believe

https://code.launchpad.net/~mir-team/qtubuntu/dont-use-raw-pc/+merge/240796

presents some improvement though

2025. By Robert Carr

Update ABI sha1sums

2026. By Robert Carr

Fix lgpl license on vsync provideR

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: Needs Fixing (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Slightly scary diff size right now, but could prove worthwhile. Initial thoughts:

(1) Avoid naming anything "*Provider". If a more concrete noun can't be found for such classes then that's an indication the design needs improving.

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

Perhaps just a rename "VsyncSource". *shrug*

2027. By Robert Carr

Merge lp:mir

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

(2) Some very important regression tests have been deleted. I suspect it's possible to retain (convert?) them, so we should:
tests/unit-tests/client/input/test_android_input_receiver.cpp:
2488 -TEST_F(AndroidInputReceiverSetup, slow_raw_input_doesnt_cause_frameskipping)
2536 -TEST_F(AndroidInputReceiverSetup, rendering_does_not_lag_behind_input)

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

(3) Spurious line appears in a few files:
+e1be9faee8b844ca2ce617f8fd82c9ee08d56bed include/common/mir/graphics/#native_buffer.h#

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
2028. By Robert Carr

Fix swap files in sha1sums

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
2029. By Robert Carr

Remove backup file from sha1sums

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 :

Now tested manually (Nexus4 nested and non-nested), but needs work...

(1) VsyncProvider: name could be better. VsyncSource? But see also (4)

(2) Some very important regression tests have been deleted. I suspect it's possible to retain (convert?) them, so we should:
tests/unit-tests/client/input/test_android_input_receiver.cpp:
2488 -TEST_F(AndroidInputReceiverSetup, slow_raw_input_doesnt_cause_frameskipping)
2536 -TEST_F(AndroidInputReceiverSetup, rendering_does_not_lag_behind_input)

(3) Nested input (fingerpaint -w) is visibly more laggy with this branch. That probably would have been shown by the test cases (2) had they not been deleted.

(4) Input event spacing is significantly less smooth and irregular (both nested and non-nested) with this branch. Same kind of irregularity pictured in bug 1373692. Also the same kind of irregularity I encountered when I experimented with a virtual vsync timer (when the client receives the buffer). So there's presently no visible advantage to getting timings from the server over what you can calculate within the client.

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

(5) This looks like a bug and will cause resampling/prediction to be disabled:
480 + has_new_frame_time = false;

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

Actually (4) could easily be explained by (5) :) There always is a last frame time; it should be perfectly regular and always known (be it real or artificial). And fixing (5) might fix the lag too (3).

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
2030. By Robert Carr

Merge lp:mir

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
2031. By Robert Carr

Forjenkins

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
2032. By Robert Carr

Jenkins

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

CI failures logged as lp:1391488 (new) and lp:1391261 (confirmed)

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

71 + last_sync = std::chrono::high_resolution_clock::now();
72 + vsync_provider.notify_of_vsync(last_sync.time_since_epoch());

I note the use of real time within the tests - which is always a recipe for intermittent failures. I'd prefer to see a stubbed time source.

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

First pass:

Could VsyncProvider be in mir::graphics instead of mir::frontend?

new whitespace
324 +

int64_t mir_surface_get_last_display_time(MirSurface *surface)
The naming has some interesting implications... like could the client api user rely on this to roughly see how long the screen has been off? Also, I'd think that the vsync stuff would be in mir_connection with the rest of the display stuff.

599 + virtual std::chrono::nanoseconds last_vsync_for(graphics::DisplayConfigurationOutputId output) = 0;
and
204 + virtual std::shared_ptr<frontend::VsyncProvider> the_vsync_provider();
and
184 + virtual std::shared_ptr<frontend::VsyncProvider> vsync_provider() = 0;

Seems like a lot of rigging where we could just have
mg::Display::last_vsync_for(graphics::DisplayConfigurationOutputId output) = 0;
and the server code could just use the existing the_display() function.

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

int64_t mir_surface_get_last_display_time(MirSurface *surface)
Somewhat related to my previous comment on this function, but is this exposing too much to the user? Is there some client-side processing that could be done in libmirclient without exposing the timing details?

The driving test looks like:
 2184 +TEST_F(VsyncProviderTest, last_display_time)
but could the test make use of mir client internals to check the vsync timing? (or, an uglier compromise could be for this to be in the debug library)

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

1098 + optional int64 vsync_time = 9;

Related to my comment about whether vsync info lives in the mir_surface_ vs mir_connection_ functions, it also seems to me that vsync is an event that can we can asynchronously notify clients of, as opposed to having this be synchronous with the exchange_buffer rpc call. This would also let us untie the buffer swapping from the vsync notification. (in case input processing is needed without the client wanting to swap a buffer)

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

Vsync is more system-wide, certainly not per-connection. On the other hand you do need to avoid waking up all clients 60 times per second so querying per surface is a good compromise.

An even better solution is not having to get info from the server at all. So far there's no visible benefit in doing so, but if this branch gets fixed up and starts performing as well as trunk (or better!) then it could be justified.

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

> Vsync is more system-wide, certainly not per-connection. On the other hand you
> do need to avoid waking up all clients 60 times per second so querying per
> surface is a good compromise.

Sure, from a clients perspective though, the connection is the system wide graphics configuration. Its a good point that this would wake up the clients every time, perhaps that could be mitigated by the clients registering and deregistering a callback if they are interested.

If we tie the vsync to the buffers, we tie input processing tightly to the clients decision to submit new frames. (and the clients might submit dummy buffers they don't care about, just to get the vsync info)

> An even better solution is not having to get info from the server at all. So
> far there's no visible benefit in doing so, but if this branch gets fixed up
> and starts performing as well as trunk (or better!) then it could be
> justified.

Yes, this could be appropriate, but its tricky from the android platform at least (which only provides the vsync information from the hwc interface). Perhaps batching input at the same rate as one of the displays could be a way around.

Revision history for this message
Alberto Aguirre (albaguirre) wrote :

Text conflict in src/client/mir_surface_api.cpp

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

Remember "batching" happens on the client side, which is surprising at first but actually very desirable. It means we have the option in future of letting clients turn off resampling if they're competent to deal with the raw events.

Revision history for this message
Alberto Aguirre (albaguirre) wrote :

These are some videos I took.

I don't notice any significant difference

Vivid #19 in mako:
https://drive.google.com/file/d/0B0EbX_l-W2rBOTZMSS0xamhWNXM/view?usp=sharing

Vivid #19 in mako + this branch:
https://drive.google.com/file/d/0B0EbX_l-W2rBMHhnajVqX3FJT0E/view?usp=sharing

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

Alberto:
As racarr pointed out, native shell shell elements do perform OK still. However nested elements suffer significantly from this branch. To test nested elements you'll need to video something like a client (Ebay?), and not the shell itself.

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

Oh I can see the terminology I used is misleading and confusing.

What we're actually talking about is _clients_ of nested servers having lag problems. And on the phone, that's most of what people are touching.

Revision history for this message
Alberto Aguirre (albaguirre) wrote :

@Daniel,

I used that more as an illustration that I don't see any visual benefits from this branch so far.

review: Abstain
Revision history for this message
Chris Halse Rogers (raof) wrote :

Doesn't seem unreasonable. I'm with Kevin though - is there a particular reason why get_last_vsync_for isn't a part of the Display interface?

It's a bit annoying that it needs to be exposed through the client API though. There are lots and lots of different interesting time values (see, for example, https://www.opengl.org/registry/specs/OML/glx_sync_control.txt) that we'll probably want to expose at some point - EGL/GL Next look like they'll want access to those things in the nearish future. I guess we can expose them (and possibly deprecate this API) when we come to that.

Revision history for this message
Robert Carr (robertcarr) wrote :

Sad that no one else experiences the performance the way I do. I experience it basically the same except during fast scrolls where I believe it is significantly more accurate in finger tracking. This is agreed with by frame uniformity test results.

Still I will continue working to produce a more convincing metric.

It is frustrating that mir_surface_get_last_display_time has to be exposed for nested. I agree it has some weird semantics if you think of it as vsync time, hence why I chose this name.

As chris references some clients are interested in this, Chromium uses VSync times + prediction to do...something! not sure beyond that.

>> sn't seem unreasonable. I'm with Kevin though - is there a particular reason why
>> get_last_vsync_for isn't a part of the Display interface?

I think putting it on the "Display" interface just further confuses the "Display"/"Output" terminology further...if Display why not DisplayBuffer?

Revision history for this message
Robert Carr (robertcarr) wrote :

Will switch to work in progress in a day or two if I dont make any progress.

Has anyone besides alberto and daniel tested?

Daniel: I wonder if in testing the nested clients you used the recommended qtubuntu branch? https://code.launchpad.net/~mir-team/qtubuntu/dont-use-raw-pc

Alberto: Maybe you could try some videos with some fast scrolls if its not too hard to setup?

2033. By Robert Carr

Merge lp:mir

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
2034. By Robert Carr

Update sha1sums

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 :

Also note -- if QtMir switches to using the newish Qt code (if not already?) which apparently does input resampling then we could theoretically just throw away all the resampling logic in Mir itself for now :)

I could be persuaded that fingerpaint being very laggy is a non-issue, but only if it's proven that QtMir is now using the in-toolkit input resampling feature. But if that's true then we're better off just deleting the resampling logic from Mir instead of growing it here.

Revision history for this message
Robert Carr (robertcarr) wrote :

I believe Qt is just doing a subset that we would call event compression. Will confirm.

2035. By Robert Carr

Merge lp:mir

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

Unmerged revisions

2035. By Robert Carr

Merge lp:mir

2034. By Robert Carr

Update sha1sums

2033. By Robert Carr

Merge lp:mir

2032. By Robert Carr

Jenkins

2031. By Robert Carr

Forjenkins

2030. By Robert Carr

Merge lp:mir

2029. By Robert Carr

Remove backup file from sha1sums

2028. By Robert Carr

Fix swap files in sha1sums

2027. By Robert Carr

Merge lp:mir

2026. By Robert Carr

Fix lgpl license on vsync provideR

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'benchmarks/frame-uniformity/vsync_simulating_graphics_platform.cpp'
2--- benchmarks/frame-uniformity/vsync_simulating_graphics_platform.cpp 2014-11-13 16:41:26 +0000
3+++ benchmarks/frame-uniformity/vsync_simulating_graphics_platform.cpp 2014-11-18 19:29:59 +0000
4@@ -21,17 +21,23 @@
5 #include "mir/graphics/buffer_writer.h"
6 #include "mir/graphics/platform_ipc_operations.h"
7 #include "mir/graphics/platform_ipc_package.h"
8+#include "mir/frontend/vsync_provider.h"
9+
10+#include "mir_test/fake_shared.h"
11
12 #include "mir_test_doubles/stub_buffer_allocator.h"
13 #include "mir_test_doubles/stub_display.h"
14
15 #include <chrono>
16 #include <functional>
17+#include <mutex>
18
19+namespace mf = mir::frontend;
20 namespace mg = mir::graphics;
21 namespace geom = mir::geometry;
22
23-namespace mtd = mir::test::doubles;
24+namespace mt = mir::test;
25+namespace mtd = mt::doubles;
26
27 namespace
28 {
29@@ -43,7 +49,7 @@
30 }
31 };
32
33-class StubIpcOps : public mg::PlatformIpcOperations
34+struct StubIpcOps : public mg::PlatformIpcOperations
35 {
36 void pack_buffer(
37 mg::BufferIpcMessage&,
38@@ -68,6 +74,25 @@
39 }
40 };
41
42+struct StubVsyncProvider : public mf::VsyncProvider
43+{
44+ std::chrono::nanoseconds last_vsync_for(mg::DisplayConfigurationOutputId /* output */)
45+ {
46+ std::unique_lock<std::mutex> lg(last_vsync_guard);
47+
48+ return last_vsync;
49+ }
50+
51+ void notify_of_vsync(std::chrono::nanoseconds vsync)
52+ {
53+ std::unique_lock<std::mutex> lg(last_vsync_guard);
54+
55+ last_vsync = vsync;
56+ }
57+ std::mutex last_vsync_guard;
58+ std::chrono::nanoseconds last_vsync;
59+};
60+
61 struct StubDisplayBuffer : mtd::StubDisplayBuffer
62 {
63 StubDisplayBuffer(geom::Size output_size, int vsync_rate_in_hz)
64@@ -84,13 +109,15 @@
65
66 if (now < next_sync)
67 std::this_thread::sleep_for(next_sync - now);
68-
69- last_sync = now;
70+
71+ last_sync = std::chrono::high_resolution_clock::now();
72+ vsync_provider.notify_of_vsync(last_sync.time_since_epoch());
73 }
74
75 double const vsync_rate_in_hz;
76
77 std::chrono::high_resolution_clock::time_point last_sync;
78+ StubVsyncProvider vsync_provider;
79 };
80
81 struct StubDisplay : public mtd::StubDisplay
82@@ -105,6 +132,11 @@
83 {
84 exec(buffer);
85 }
86+
87+ std::shared_ptr<mf::VsyncProvider> vsync_provider() override
88+ {
89+ return mt::fake_shared(buffer.vsync_provider);
90+ }
91
92 StubDisplayBuffer buffer;
93 };
94
95=== modified file 'client-ABI-sha1sums'
96--- client-ABI-sha1sums 2014-11-12 05:01:53 +0000
97+++ client-ABI-sha1sums 2014-11-18 19:29:59 +0000
98@@ -5,7 +5,7 @@
99 1ef8f51a3e3f8d1559266c5af58fbfde7cfabf0a include/client/mir_toolkit/mir_cursor_configuration.h
100 9d50df5a141ca03ee8a79f7e844ed4b8b3b7d5d3 include/client/mir_toolkit/mir_prompt_session.h
101 21d07e655e85eeec8a3523e1c6f9c2252176ec01 include/client/mir_toolkit/mir_screencast.h
102-4f85e3d00314a7df869e56c3701a45310909fae2 include/client/mir_toolkit/mir_surface.h
103+1bacb90ea11be9c8fec6113a68391027ce518707 include/client/mir_toolkit/mir_surface.h
104 b141c4d79802ad626d969249c0004744e5c2a525 include/client/mir_toolkit/mir_wait.h
105 9907751d046e4aea81881cf19e5df52c7a6a813e include/common/mir_toolkit/client_types.h
106 2100c0674d9d882c1845550847357f6a5de5af66 include/common/mir_toolkit/common.h
107
108=== modified file 'common-ABI-sha1sums'
109--- common-ABI-sha1sums 2014-11-11 07:34:31 +0000
110+++ common-ABI-sha1sums 2014-11-18 19:29:59 +0000
111@@ -7,7 +7,7 @@
112 42646c2367b9821e3aa71feff6e31cf50526acaa include/common/mir/geometry/size.h
113 e1be9faee8b844ca2ce617f8fd82c9ee08d56bed include/common/mir/graphics/native_buffer.h
114 dcf8b8982f138bdde39a241825c610e955cd5e33 include/common/mir/input/input_platform.h
115-208cd6aed5ef5f8f39b3eb86604e4133cb840485 include/common/mir/input/input_receiver_thread.h
116+fc96edf0f28451af2009aff58b9da8c0d462a604 include/common/mir/input/input_receiver_thread.h
117 be7d58c9fde2ce91cc66dd6144b76e08b536266b include/common/mir/int_wrapper.h
118 9ae8473df05dd9e048a73797f01a2f34f7447554 include/common/mir/time/types.h
119 9907751d046e4aea81881cf19e5df52c7a6a813e include/common/mir_toolkit/client_types.h
120
121=== modified file 'include/client/mir_toolkit/mir_surface.h'
122--- include/client/mir_toolkit/mir_surface.h 2014-11-12 05:01:53 +0000
123+++ include/client/mir_toolkit/mir_surface.h 2014-11-18 19:29:59 +0000
124@@ -289,6 +289,13 @@
125 */
126 MirOrientation mir_surface_get_orientation(MirSurface *surface);
127
128+/**
129+ * Returns the last time a buffer from the surface was displayed on screen.
130+ * If possible this time will be sampled on the server side from hardware
131+ * vsync timings.
132+ */
133+int64_t mir_surface_get_last_display_time(MirSurface *surface);
134+
135 #ifdef __cplusplus
136 }
137 /**@}*/
138
139=== modified file 'include/common/mir/input/input_receiver_thread.h'
140--- include/common/mir/input/input_receiver_thread.h 2014-10-01 06:25:56 +0000
141+++ include/common/mir/input/input_receiver_thread.h 2014-11-18 19:29:59 +0000
142@@ -19,6 +19,8 @@
143 #ifndef MIR_INPUT_RECEIVER_RECEIVER_THREAD_H_
144 #define MIR_INPUT_RECEIVER_RECEIVER_THREAD_H_
145
146+#include <chrono>
147+
148 namespace mir
149 {
150 namespace input
151@@ -34,6 +36,8 @@
152 virtual void start() = 0;
153 virtual void stop() = 0;
154 virtual void join() = 0;
155+
156+ virtual void notify_of_frame_time(std::chrono::nanoseconds frame_time) = 0;
157
158 protected:
159 InputReceiverThread() = default;
160
161=== modified file 'include/platform/mir/graphics/display.h'
162--- include/platform/mir/graphics/display.h 2014-10-01 06:25:56 +0000
163+++ include/platform/mir/graphics/display.h 2014-11-18 19:29:59 +0000
164@@ -24,6 +24,10 @@
165
166 namespace mir
167 {
168+namespace frontend
169+{
170+class VsyncProvider;
171+}
172
173 namespace graphics
174 {
175@@ -101,6 +105,12 @@
176 * Create a hardware cursor object.
177 */
178 virtual std::shared_ptr<Cursor> create_hardware_cursor(std::shared_ptr<CursorImage> const& initial_image) = 0;
179+
180+ /**
181+ * Returns a vsync provider for the display which can provide per-output
182+ * information about vsync timings.
183+ */
184+ virtual std::shared_ptr<frontend::VsyncProvider> vsync_provider() = 0;
185
186 /**
187 * Creates a GLContext object that shares resources with the Display's GL context.
188
189=== modified file 'include/server/mir/default_server_configuration.h'
190--- include/server/mir/default_server_configuration.h 2014-11-18 17:26:29 +0000
191+++ include/server/mir/default_server_configuration.h 2014-11-18 19:29:59 +0000
192@@ -66,6 +66,7 @@
193 class EventSink;
194 class DisplayChanger;
195 class Screencast;
196+class VsyncProvider;
197 }
198
199 namespace shell
200@@ -234,6 +235,7 @@
201 virtual std::shared_ptr<frontend::EventSink> the_global_event_sink();
202 virtual std::shared_ptr<frontend::DisplayChanger> the_frontend_display_changer();
203 virtual std::shared_ptr<frontend::Screencast> the_screencast();
204+ virtual std::shared_ptr<frontend::VsyncProvider> the_vsync_provider();
205 /** @name frontend configuration - internal dependencies
206 * internal dependencies of frontend
207 * @{ */
208@@ -393,6 +395,7 @@
209 CachedPtr<frontend::ConnectionCreator> connection_creator;
210 CachedPtr<frontend::ConnectionCreator> prompt_connection_creator;
211 CachedPtr<frontend::Screencast> screencast;
212+ CachedPtr<frontend::VsyncProvider> vsync_provider;
213 CachedPtr<compositor::RendererFactory> renderer_factory;
214 CachedPtr<compositor::BufferStreamFactory> buffer_stream_factory;
215 CachedPtr<compositor::FrameDroppingPolicyFactory> frame_dropping_policy_factory;
216
217=== modified file 'platform-ABI-sha1sums'
218--- platform-ABI-sha1sums 2014-11-18 03:21:20 +0000
219+++ platform-ABI-sha1sums 2014-11-18 19:29:59 +0000
220@@ -7,7 +7,7 @@
221 42646c2367b9821e3aa71feff6e31cf50526acaa include/common/mir/geometry/size.h
222 e1be9faee8b844ca2ce617f8fd82c9ee08d56bed include/common/mir/graphics/native_buffer.h
223 dcf8b8982f138bdde39a241825c610e955cd5e33 include/common/mir/input/input_platform.h
224-208cd6aed5ef5f8f39b3eb86604e4133cb840485 include/common/mir/input/input_receiver_thread.h
225+fc96edf0f28451af2009aff58b9da8c0d462a604 include/common/mir/input/input_receiver_thread.h
226 be7d58c9fde2ce91cc66dd6144b76e08b536266b include/common/mir/int_wrapper.h
227 9ae8473df05dd9e048a73797f01a2f34f7447554 include/common/mir/time/types.h
228 9907751d046e4aea81881cf19e5df52c7a6a813e include/common/mir_toolkit/client_types.h
229@@ -28,7 +28,7 @@
230 986f5d0d8ea2c6a42cc320f468e682f81fec46ae include/platform/mir/graphics/display_buffer.h
231 f53a0020b8f1bd4a941a201eb26271cffee0a7dd include/platform/mir/graphics/display_configuration.h
232 6fe08da318c920b0d20ea8b8f560f5ac7ed389fe include/platform/mir/graphics/display_configuration_policy.h
233-41ea906d208b761e3d5d5056095de9de2d4ffa17 include/platform/mir/graphics/display.h
234+0eb20a383320790016fa22ae969e80fdecd20b8f include/platform/mir/graphics/display.h
235 815405c5aee8000bc18c1c9480bac620a451b416 include/platform/mir/graphics/event_handler_register.h
236 5dc095474ef3e294c0aa4008e9ed997bdb21d34c include/platform/mir/graphics/gl_config.h
237 d0442a5d5d88a4be6e3e1f99e433c1c43a86bfce include/platform/mir/graphics/gl_context.h
238
239=== modified file 'server-ABI-sha1sums'
240--- server-ABI-sha1sums 2014-11-18 17:26:29 +0000
241+++ server-ABI-sha1sums 2014-11-18 19:29:59 +0000
242@@ -7,7 +7,7 @@
243 42646c2367b9821e3aa71feff6e31cf50526acaa include/common/mir/geometry/size.h
244 e1be9faee8b844ca2ce617f8fd82c9ee08d56bed include/common/mir/graphics/native_buffer.h
245 dcf8b8982f138bdde39a241825c610e955cd5e33 include/common/mir/input/input_platform.h
246-208cd6aed5ef5f8f39b3eb86604e4133cb840485 include/common/mir/input/input_receiver_thread.h
247+fc96edf0f28451af2009aff58b9da8c0d462a604 include/common/mir/input/input_receiver_thread.h
248 be7d58c9fde2ce91cc66dd6144b76e08b536266b include/common/mir/int_wrapper.h
249 9ae8473df05dd9e048a73797f01a2f34f7447554 include/common/mir/time/types.h
250 9907751d046e4aea81881cf19e5df52c7a6a813e include/common/mir_toolkit/client_types.h
251@@ -28,7 +28,7 @@
252 986f5d0d8ea2c6a42cc320f468e682f81fec46ae include/platform/mir/graphics/display_buffer.h
253 f53a0020b8f1bd4a941a201eb26271cffee0a7dd include/platform/mir/graphics/display_configuration.h
254 6fe08da318c920b0d20ea8b8f560f5ac7ed389fe include/platform/mir/graphics/display_configuration_policy.h
255-41ea906d208b761e3d5d5056095de9de2d4ffa17 include/platform/mir/graphics/display.h
256+0eb20a383320790016fa22ae969e80fdecd20b8f include/platform/mir/graphics/display.h
257 815405c5aee8000bc18c1c9480bac620a451b416 include/platform/mir/graphics/event_handler_register.h
258 5dc095474ef3e294c0aa4008e9ed997bdb21d34c include/platform/mir/graphics/gl_config.h
259 d0442a5d5d88a4be6e3e1f99e433c1c43a86bfce include/platform/mir/graphics/gl_context.h
260@@ -50,7 +50,7 @@
261 d49eae4f986645b32e29ce2c1f99f524703ba3c0 include/server/mir/compositor/display_buffer_compositor.h
262 878ab5c4007d16dac213a3eb0105421d8ffad206 include/server/mir/compositor/scene_element.h
263 4fcf34e424128b87ddc76733594e32e09ebbd486 include/server/mir/compositor/scene.h
264-bd13887133bab2dfaab764077983311485b233d0 include/server/mir/default_server_configuration.h
265+67b99ce7b4571bc6141e7a1d6a0ea3e7de93a01b include/server/mir/default_server_configuration.h
266 af1ff0714be973ac76d56006a2e5991f68cd1dec include/server/mir/display_server.h
267 a35c5495d8fd28fc0e375b17495fc5caab51b329 include/server/mir/emergency_cleanup.h
268 938de641cb0e01e1098b007b39b151a7dfe4adc1 include/server/mir/frontend/display_changer.h
269
270=== modified file 'src/client/mir_surface.cpp'
271--- src/client/mir_surface.cpp 2014-11-11 15:50:11 +0000
272+++ src/client/mir_surface.cpp 2014-11-18 19:29:59 +0000
273@@ -87,7 +87,8 @@
274 debug{debug},
275 connection(allocating_connection),
276 buffer_depository(std::make_shared<mcl::ClientBufferDepository>(factory, mir::frontend::client_buffer_cache_size)),
277- input_platform(input_platform)
278+ input_platform(input_platform),
279+ last_display_time(std::chrono::nanoseconds::zero())
280 {
281 const char* report_target = getenv("MIR_CLIENT_PERF_REPORT");
282 if (report_target && !strcmp(report_target, "log"))
283@@ -248,6 +249,15 @@
284 surface.set_height(buffer.height());
285 }
286
287+ if (buffer.has_vsync_time())
288+ {
289+ last_display_time = std::chrono::nanoseconds(buffer.vsync_time());
290+ if (input_thread)
291+ {
292+ input_thread->notify_of_frame_time(last_display_time);
293+ }
294+ }
295+
296 auto surface_size = geom::Size{surface.width(), surface.height()};
297 auto surface_pf = convert_ipc_pf_to_geometry(surface.pixel_format());
298
299@@ -593,3 +603,10 @@
300
301 return orientation;
302 }
303+
304+std::chrono::nanoseconds MirSurface::get_last_display_time() const
305+{
306+ std::lock_guard<decltype(mutex)> lock(mutex);
307+
308+ return last_display_time;
309+}
310
311=== modified file 'src/client/mir_surface.h'
312--- src/client/mir_surface.h 2014-11-11 15:50:11 +0000
313+++ src/client/mir_surface.h 2014-11-18 19:29:59 +0000
314@@ -114,10 +114,12 @@
315 void set_event_handler(MirEventDelegate const* delegate);
316 void handle_event(MirEvent const& e);
317
318+ std::chrono::nanoseconds get_last_display_time() const;
319+
320 /* mir::client::ClientSurface */
321 void request_and_wait_for_next_buffer();
322 void request_and_wait_for_configure(MirSurfaceAttrib a, int value);
323-
324+
325 static bool is_valid(MirSurface* query);
326 private:
327 mutable std::mutex mutex; // Protects all members of *this
328@@ -147,6 +149,8 @@
329 std::shared_ptr<mir::client::MemoryRegion> secured_region;
330 std::shared_ptr<mir::client::ClientBufferDepository> buffer_depository;
331 std::shared_ptr<mir::input::receiver::InputPlatform> const input_platform;
332+
333+ std::chrono::nanoseconds last_display_time;
334
335 std::shared_ptr<EGLNativeWindowType> accelerated_window;
336
337
338=== modified file 'src/client/mir_surface_api.cpp'
339--- src/client/mir_surface_api.cpp 2014-11-12 05:01:53 +0000
340+++ src/client/mir_surface_api.cpp 2014-11-18 19:29:59 +0000
341@@ -332,3 +332,8 @@
342
343 return result;
344 }
345+
346+int64_t mir_surface_get_last_display_time(MirSurface *surface)
347+{
348+ return surface->get_last_display_time().count();
349+}
350
351=== modified file 'src/common/input/android/android_input_receiver.cpp'
352--- src/common/input/android/android_input_receiver.cpp 2014-10-21 16:21:14 +0000
353+++ src/common/input/android/android_input_receiver.cpp 2014-11-18 19:29:59 +0000
354@@ -39,7 +39,9 @@
355 looper(new droidinput::Looper(true)),
356 fd_added(false),
357 xkb_mapper(std::make_shared<mircv::XKBMapper>()),
358- android_clock(clock)
359+ android_clock(clock),
360+ has_new_frame_time(false),
361+ frame_time(-1)
362 {
363 }
364
365@@ -52,7 +54,9 @@
366 looper(new droidinput::Looper(true)),
367 fd_added(false),
368 xkb_mapper(std::make_shared<mircv::XKBMapper>()),
369- android_clock(clock)
370+ android_clock(clock),
371+ has_new_frame_time(false),
372+ frame_time(-1)
373 {
374 }
375
376@@ -85,49 +89,27 @@
377 droidinput::InputEvent *android_event;
378 uint32_t event_sequence_id;
379
380- /*
381- * Enable "Project Butter" input resampling in InputConsumer::consume():
382- * consumeBatches = true, so as to ensure the "cooked" event rate that
383- * clients experience is at least the minimum of event_rate_hz
384- * and the raw device event rate.
385- * frame_time = A regular interval. This provides a virtual frame
386- * interval during which InputConsumer will collect raw events,
387- * resample them and emit a "cooked" event back to us at roughly every
388- * 60th of a second. "cooked" events are both smoothed and
389- * extrapolated/predicted into the future (for tool=finger) giving the
390- * appearance of lower latency. Getting a real frame time from the
391- * graphics logic (which is messy) does not appear to be necessary to
392- * gain significant benefit.
393- *
394- * Note event_rate_hz is only 55Hz. This allows rendering to catch up and
395- * overtake the event rate every ~12th frame (200ms) on a 60Hz display.
396- * Thus on every 12th+1 frame, there will be zero buffer lag in responding
397- * to the cooked input event we have given the client.
398- * This phase control is useful as it eliminates the one frame of lag you
399- * would otherwise never catch up to if the event rate was exactly the same
400- * as the display refresh rate.
401- */
402-
403- nsecs_t const now = android_clock(SYSTEM_TIME_MONOTONIC);
404- int const event_rate_hz = 55;
405- nsecs_t const one_frame = 1000000000ULL / event_rate_hz;
406- nsecs_t frame_time = (now / one_frame) * one_frame;
407-
408- if (input_consumer->consume(&event_factory, true, frame_time,
409- &event_sequence_id, &android_event)
410- == droidinput::OK)
411+ droidinput::status_t status;
412+
413+ bool result = false;
414+
415+ if ((status = input_consumer->consume(&event_factory, true, has_new_frame_time ? frame_time : -1,
416+ &event_sequence_id, &android_event))
417+ == droidinput::OK)
418 {
419 mia::Lexicon::translate(android_event, ev);
420-
421 map_key_event(xkb_mapper, ev);
422
423 input_consumer->sendFinishedSignal(event_sequence_id, true);
424
425 report->received_event(ev);
426
427- return true;
428+ result = true;
429 }
430- return false;
431+
432+ has_new_frame_time = false;
433+
434+ return result;
435 }
436
437 // TODO: We use a droidinput::Looper here for polling functionality but it might be nice to integrate
438@@ -140,28 +122,22 @@
439 looper->addFd(fd(), fd(), ALOOPER_EVENT_INPUT, nullptr, nullptr);
440 fd_added = true;
441 }
442-
443+
444 auto reduced_timeout = timeout;
445- if (input_consumer->hasDeferredEvent())
446- {
447- // consume() didn't finish last time. Retry it immediately.
448- reduced_timeout = std::chrono::milliseconds::zero();
449- }
450- else if (input_consumer->hasPendingBatch())
451- {
452- // When in constant motion we will usually "hasPendingBatch".
453- // But the batch won't get flushed until the next frame interval,
454- // so be sure to use a non-zero sleep time to avoid spinning the CPU
455- // for the whole interval...
456-
457- // During tests with mocked clocks we may already have zero...
458- if (reduced_timeout != std::chrono::milliseconds::zero())
459- reduced_timeout = std::chrono::milliseconds(1);
460- }
461-
462- auto result = looper->pollOnce(reduced_timeout.count());
463- if (result == ALOOPER_POLL_WAKE)
464+
465+ if (input_consumer->hasPendingBatch())
466+ reduced_timeout = std::chrono::milliseconds(1);
467+
468+ int result = 0;
469+ if (!input_consumer->hasDeferredEvent())
470+ result = looper->pollOnce(reduced_timeout.count());
471+
472+ std::lock_guard<std::mutex> lg(frame_time_guard);
473+
474+ // If we are awoken and not by a frame time it is for shutdown.
475+ if (result == ALOOPER_POLL_WAKE && has_new_frame_time == false)
476 return false;
477+
478 if (result == ALOOPER_POLL_ERROR) // TODO: Exception?
479 return false;
480
481@@ -172,3 +148,16 @@
482 {
483 looper->wake();
484 }
485+
486+void mircva::InputReceiver::notify_of_frame_time(std::chrono::nanoseconds new_frame_time)
487+{
488+ {
489+ std::lock_guard<std::mutex> lg(frame_time_guard);
490+ has_new_frame_time = true;
491+ if (new_frame_time != std::chrono::nanoseconds::min())
492+ frame_time = new_frame_time.count();
493+ else
494+ frame_time = -1;
495+ }
496+ wake();
497+}
498
499=== modified file 'src/common/input/android/android_input_receiver.h'
500--- src/common/input/android/android_input_receiver.h 2014-10-01 06:25:56 +0000
501+++ src/common/input/android/android_input_receiver.h 2014-11-18 19:29:59 +0000
502@@ -26,6 +26,7 @@
503
504 #include <memory>
505 #include <chrono>
506+#include <mutex>
507
508 namespace droidinput = android;
509
510@@ -71,6 +72,8 @@
511
512 /// May be used from any thread to wake an InputReceiver blocked in next_event
513 virtual void wake();
514+
515+ virtual void notify_of_frame_time(std::chrono::nanoseconds frame_time);
516
517 protected:
518 InputReceiver(const InputReceiver&) = delete;
519@@ -89,6 +92,10 @@
520 std::shared_ptr<XKBMapper> xkb_mapper;
521
522 AndroidClock const android_clock;
523+
524+ std::mutex frame_time_guard;
525+ bool has_new_frame_time;
526+ int64_t frame_time;
527
528 bool try_next_event(MirEvent &ev);
529 };
530
531=== modified file 'src/common/input/android/android_input_receiver_thread.cpp'
532--- src/common/input/android/android_input_receiver_thread.cpp 2013-05-13 23:20:52 +0000
533+++ src/common/input/android/android_input_receiver_thread.cpp 2014-11-18 19:29:59 +0000
534@@ -66,3 +66,8 @@
535 std::this_thread::yield(); // yield() is needed to ensure reasonable runtime under valgrind
536 }
537 }
538+
539+void mircva::InputReceiverThread::notify_of_frame_time(std::chrono::nanoseconds frame_time)
540+{
541+ receiver->notify_of_frame_time(frame_time);
542+}
543
544=== modified file 'src/common/input/android/android_input_receiver_thread.h'
545--- src/common/input/android/android_input_receiver_thread.h 2014-03-06 06:05:17 +0000
546+++ src/common/input/android/android_input_receiver_thread.h 2014-11-18 19:29:59 +0000
547@@ -49,6 +49,8 @@
548 void start();
549 void stop();
550 void join();
551+
552+ void notify_of_frame_time(std::chrono::nanoseconds frame_time) override;
553
554 protected:
555 InputReceiverThread(const InputReceiverThread&) = delete;
556
557=== added directory 'src/include/platform/mir/frontend'
558=== added file 'src/include/platform/mir/frontend/vsync_provider.h'
559--- src/include/platform/mir/frontend/vsync_provider.h 1970-01-01 00:00:00 +0000
560+++ src/include/platform/mir/frontend/vsync_provider.h 2014-11-18 19:29:59 +0000
561@@ -0,0 +1,46 @@
562+/*
563+ * Copyright © 2014 Canonical Ltd.
564+ *
565+ * This program is free software: you can redistribute it and/or modify it
566+ * under the terms of the GNU Lesser General Public License version 3,
567+ * as published by the Free Software Foundation.
568+ *
569+ * This program is distributed in the hope that it will be useful,
570+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
571+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
572+ * GNU Lesser General Public License for more details.
573+ *
574+ * You should have received a copy of the GNU Lesser General Public License
575+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
576+ *
577+ * Authored by: Robert Carr <robert.carr@canonical.com>
578+ */
579+
580+#ifndef MIR_FRONTEND_VSYNC_PROVIDER_H_
581+#define MIR_FRONTEND_VSYNC_PROVIDER_H_
582+
583+#include "mir/graphics/display_configuration.h"
584+
585+#include <chrono>
586+
587+namespace mir
588+{
589+namespace frontend
590+{
591+class VsyncProvider
592+{
593+public:
594+ virtual ~VsyncProvider() = default;
595+
596+ virtual std::chrono::nanoseconds last_vsync_for(graphics::DisplayConfigurationOutputId output) = 0;
597+
598+protected:
599+ VsyncProvider() = default;
600+
601+ VsyncProvider& operator=(VsyncProvider const& other) = delete;
602+ VsyncProvider(VsyncProvider const& other) = delete;
603+};
604+}
605+}
606+
607+#endif // MIR_FRONTEND_VSYNC_PROVIDER_H_
608
609=== modified file 'src/platform/graphics/android/display.cpp'
610--- src/platform/graphics/android/display.cpp 2014-10-01 06:25:56 +0000
611+++ src/platform/graphics/android/display.cpp 2014-11-18 19:29:59 +0000
612@@ -22,6 +22,7 @@
613 #include "mir/graphics/display_buffer.h"
614 #include "mir/graphics/gl_context.h"
615 #include "mir/graphics/egl_resources.h"
616+#include "hwc_vsync.h"
617 #include "display.h"
618 #include "display_builder.h"
619 #include "mir/geometry/rectangle.h"
620@@ -30,6 +31,7 @@
621
622 namespace mga=mir::graphics::android;
623 namespace mg=mir::graphics;
624+namespace mf = mir::frontend;
625 namespace geom=mir::geometry;
626
627 mga::Display::Display(std::shared_ptr<mga::DisplayBuilder> const& display_builder,
628@@ -110,3 +112,8 @@
629 {
630 return std::unique_ptr<mg::GLContext>{new mga::PbufferGLContext(gl_context)};
631 }
632+
633+std::shared_ptr<mf::VsyncProvider> mga::Display::vsync_provider()
634+{
635+ return display_builder->vsync_coordinator();
636+}
637
638=== modified file 'src/platform/graphics/android/display.h'
639--- src/platform/graphics/android/display.h 2014-11-03 06:51:26 +0000
640+++ src/platform/graphics/android/display.h 2014-11-18 19:29:59 +0000
641@@ -67,6 +67,8 @@
642
643 std::shared_ptr<Cursor> create_hardware_cursor(std::shared_ptr<CursorImage> const& initial_image) override;
644 std::unique_ptr<graphics::GLContext> create_gl_context() override;
645+ std::shared_ptr<frontend::VsyncProvider> vsync_provider() override;
646+
647
648 private:
649 std::shared_ptr<DisplayBuilder> const display_builder;
650
651=== modified file 'src/platform/graphics/android/display_builder.h'
652--- src/platform/graphics/android/display_builder.h 2014-10-01 06:25:56 +0000
653+++ src/platform/graphics/android/display_builder.h 2014-11-18 19:29:59 +0000
654@@ -31,6 +31,7 @@
655 namespace android
656 {
657 class GLContext;
658+class HWCVsyncCoordinator;
659
660 class DisplayBuilder
661 {
662@@ -41,6 +42,8 @@
663 virtual std::unique_ptr<ConfigurableDisplayBuffer> create_display_buffer(
664 GLProgramFactory const& gl_program_factory, GLContext const& gl_context) = 0;
665
666+ virtual std::shared_ptr<HWCVsyncCoordinator> vsync_coordinator() const = 0;
667+
668 protected:
669 DisplayBuilder() = default;
670 DisplayBuilder(DisplayBuilder const&) = delete;
671
672=== modified file 'src/platform/graphics/android/display_resource_factory.h'
673--- src/platform/graphics/android/display_resource_factory.h 2014-10-01 06:25:56 +0000
674+++ src/platform/graphics/android/display_resource_factory.h 2014-11-18 19:29:59 +0000
675@@ -35,6 +35,7 @@
676 class DisplayDevice;
677 class FramebufferBundle;
678 class HwcWrapper;
679+class HWCVsyncCoordinator;
680
681 class DisplayResourceFactory
682 {
683@@ -54,6 +55,8 @@
684 virtual std::shared_ptr<DisplayDevice> create_hwc_fb_device(
685 std::shared_ptr<HwcWrapper> const& hwc_native_device,
686 std::shared_ptr<framebuffer_device_t> const& fb_native_device) const = 0;
687+
688+ virtual std::shared_ptr<HWCVsyncCoordinator> create_vsync_coordinator() const = 0;
689
690 protected:
691 DisplayResourceFactory() = default;
692
693=== modified file 'src/platform/graphics/android/hwc_common_device.cpp'
694--- src/platform/graphics/android/hwc_common_device.cpp 2014-10-01 06:25:56 +0000
695+++ src/platform/graphics/android/hwc_common_device.cpp 2014-11-18 19:29:59 +0000
696@@ -32,12 +32,12 @@
697 {
698 }
699
700-static void vsync_hook(const struct hwc_procs* procs, int /*disp*/, int64_t /*timestamp*/)
701+static void vsync_hook(const struct hwc_procs* procs, int /*disp*/, int64_t timestamp)
702 {
703 auto self = reinterpret_cast<mga::HWCCallbacks const*>(procs)->self.load();
704 if (!self)
705 return;
706- self->notify_vsync();
707+ self->notify_vsync(std::chrono::nanoseconds(timestamp));
708 }
709
710 static void hotplug_hook(const struct hwc_procs* /*procs*/, int /*disp*/, int /*connected*/)
711@@ -84,9 +84,9 @@
712 callbacks->self = nullptr;
713 }
714
715-void mga::HWCCommonDevice::notify_vsync()
716+void mga::HWCCommonDevice::notify_vsync(std::chrono::nanoseconds timestamp)
717 {
718- coordinator->notify_vsync();
719+ coordinator->notify_vsync(timestamp);
720 }
721
722 void mga::HWCCommonDevice::mode(MirPowerMode mode_request)
723
724=== modified file 'src/platform/graphics/android/hwc_common_device.h'
725--- src/platform/graphics/android/hwc_common_device.h 2014-10-01 06:25:56 +0000
726+++ src/platform/graphics/android/hwc_common_device.h 2014-11-18 19:29:59 +0000
727@@ -26,6 +26,7 @@
728 #include <mutex>
729 #include <condition_variable>
730 #include <atomic>
731+#include <chrono>
732
733 namespace mir
734 {
735@@ -48,7 +49,7 @@
736 public:
737 virtual ~HWCCommonDevice() noexcept;
738
739- void notify_vsync();
740+ void notify_vsync(std::chrono::nanoseconds timestamp);
741 void mode(MirPowerMode mode);
742 bool apply_orientation(MirOrientation orientation) const;
743
744
745=== modified file 'src/platform/graphics/android/hwc_vsync.cpp'
746--- src/platform/graphics/android/hwc_vsync.cpp 2014-03-06 06:05:17 +0000
747+++ src/platform/graphics/android/hwc_vsync.cpp 2014-11-18 19:29:59 +0000
748@@ -17,10 +17,17 @@
749 */
750
751 #include "hwc_vsync.h"
752-namespace mga=mir::graphics::android;
753+
754+#include <boost/throw_exception.hpp>
755+
756+#include <stdexcept>
757+
758+namespace mg = mir::graphics;
759+namespace mga = mg::android;
760
761 mga::HWCVsync::HWCVsync()
762- : vsync_occurred(false)
763+ : vsync_occurred(false),
764+ last_vsync(std::chrono::nanoseconds::zero())
765 {
766 }
767
768@@ -34,9 +41,24 @@
769 }
770 }
771
772-void mga::HWCVsync::notify_vsync()
773+void mga::HWCVsync::notify_vsync(std::chrono::nanoseconds time)
774 {
775 std::unique_lock<std::mutex> lk(vsync_wait_mutex);
776+
777 vsync_occurred = true;
778+ last_vsync = time;
779+
780 vsync_trigger.notify_all();
781 }
782+
783+std::chrono::nanoseconds mga::HWCVsync::last_vsync_for(mg::DisplayConfigurationOutputId output)
784+{
785+ if (output != mg::DisplayConfigurationOutputId{0})
786+ {
787+ BOOST_THROW_EXCEPTION(std::runtime_error(
788+ "HWCVsync got non zero output ID but multi-monitor is not yet supported"));
789+ }
790+
791+ std::unique_lock<std::mutex> lk(vsync_wait_mutex);
792+ return last_vsync;
793+}
794
795=== modified file 'src/platform/graphics/android/hwc_vsync.h'
796--- src/platform/graphics/android/hwc_vsync.h 2014-03-06 06:05:17 +0000
797+++ src/platform/graphics/android/hwc_vsync.h 2014-11-18 19:29:59 +0000
798@@ -19,9 +19,13 @@
799 #ifndef MIR_GRAPHICS_ANDROID_HWC_VSYNC_H_
800 #define MIR_GRAPHICS_ANDROID_HWC_VSYNC_H_
801
802+#include "mir/frontend/vsync_provider.h"
803+
804 #include "hwc_vsync_coordinator.h"
805+
806 #include <mutex>
807 #include <condition_variable>
808+#include <chrono>
809
810 namespace mir
811 {
812@@ -36,11 +40,16 @@
813 HWCVsync();
814
815 void wait_for_vsync();
816- void notify_vsync();
817+ void notify_vsync(std::chrono::nanoseconds time);
818+
819+ std::chrono::nanoseconds last_vsync_for(graphics::DisplayConfigurationOutputId output) override;
820+
821 private:
822 std::mutex vsync_wait_mutex;
823 std::condition_variable vsync_trigger;
824+
825 bool vsync_occurred;
826+ std::chrono::nanoseconds last_vsync;
827 };
828
829 }
830
831=== modified file 'src/platform/graphics/android/hwc_vsync_coordinator.h'
832--- src/platform/graphics/android/hwc_vsync_coordinator.h 2014-03-06 06:05:17 +0000
833+++ src/platform/graphics/android/hwc_vsync_coordinator.h 2014-11-18 19:29:59 +0000
834@@ -19,6 +19,10 @@
835 #ifndef MIR_GRAPHICS_ANDROID_HWC_VSYNC_COORDINATOR_H_
836 #define MIR_GRAPHICS_ANDROID_HWC_VSYNC_COORDINATOR_H_
837
838+#include "mir/frontend/vsync_provider.h"
839+
840+#include <chrono>
841+
842 namespace mir
843 {
844 namespace graphics
845@@ -26,13 +30,14 @@
846 namespace android
847 {
848
849-class HWCVsyncCoordinator
850+class HWCVsyncCoordinator : public frontend::VsyncProvider
851 {
852 public:
853 virtual ~HWCVsyncCoordinator() = default;
854
855 virtual void wait_for_vsync() = 0;
856- virtual void notify_vsync() = 0;
857+ virtual void notify_vsync(std::chrono::nanoseconds time) = 0;
858+ virtual std::chrono::nanoseconds last_vsync_for(DisplayConfigurationOutputId id) = 0;
859
860 protected:
861 HWCVsyncCoordinator() = default;
862
863=== modified file 'src/platform/graphics/android/output_builder.cpp'
864--- src/platform/graphics/android/output_builder.cpp 2014-10-01 06:25:56 +0000
865+++ src/platform/graphics/android/output_builder.cpp 2014-11-18 19:29:59 +0000
866@@ -41,6 +41,7 @@
867 : buffer_allocator(buffer_allocator),
868 res_factory(res_factory),
869 display_report(display_report),
870+ vsync_coordinator_(res_factory->create_vsync_coordinator()),
871 force_backup_display(false),
872 overlay_optimization(overlay_optimization)
873 {
874@@ -118,3 +119,8 @@
875 gl_program_factory,
876 overlay_optimization));
877 }
878+
879+std::shared_ptr<mga::HWCVsyncCoordinator> mga::OutputBuilder::vsync_coordinator() const
880+{
881+ return vsync_coordinator_;
882+}
883
884=== modified file 'src/platform/graphics/android/output_builder.h'
885--- src/platform/graphics/android/output_builder.h 2014-10-01 06:25:56 +0000
886+++ src/platform/graphics/android/output_builder.h 2014-11-18 19:29:59 +0000
887@@ -52,11 +52,13 @@
888 std::unique_ptr<ConfigurableDisplayBuffer> create_display_buffer(
889 GLProgramFactory const& gl_program_factory,
890 GLContext const& gl_context);
891+ std::shared_ptr<HWCVsyncCoordinator> vsync_coordinator() const;
892
893 private:
894 std::shared_ptr<GraphicBufferAllocator> const buffer_allocator;
895 std::shared_ptr<DisplayResourceFactory> const res_factory;
896 std::shared_ptr<DisplayReport> const display_report;
897+ std::shared_ptr<HWCVsyncCoordinator> const vsync_coordinator_;
898
899 std::shared_ptr<FramebufferBundle> framebuffers;
900 bool force_backup_display;
901
902=== modified file 'src/platform/graphics/android/platform.cpp'
903--- src/platform/graphics/android/platform.cpp 2014-11-18 03:21:20 +0000
904+++ src/platform/graphics/android/platform.cpp 2014-11-18 19:29:59 +0000
905@@ -26,6 +26,7 @@
906 #include "output_builder.h"
907 #include "buffer_writer.h"
908 #include "hwc_loggers.h"
909+#include "hwc_vsync.h"
910 #include "ipc_operations.h"
911 #include "mir/graphics/platform_ipc_package.h"
912 #include "mir/graphics/buffer_ipc_message.h"
913@@ -160,6 +161,7 @@
914 auto logger = make_logger(*options);
915 auto overlay_option = should_use_overlay_optimization(*options);
916 logger->log_overlay_optimization(overlay_option);
917+
918 auto display_resource_factory = std::make_shared<mga::ResourceFactory>();
919 auto fb_allocator = std::make_shared<mga::AndroidGraphicBufferAllocator>();
920 auto display_builder = std::make_shared<mga::OutputBuilder>(
921@@ -172,7 +174,8 @@
922 std::shared_ptr<mg::NestedContext> const&)
923 {
924 //TODO: remove nullptr parameter once platform classes are sorted.
925- // mg::NativePlatform cannot create a display anyways, so it doesnt need a display builder
926+ // mg::NativePlatform cannot create a display anyways, so it doesnt need a display builder or
927+ // a vsync provider.
928 return std::make_shared<mga::Platform>(nullptr, display_report);
929 }
930
931
932=== modified file 'src/platform/graphics/android/platform.h'
933--- src/platform/graphics/android/platform.h 2014-11-18 03:21:20 +0000
934+++ src/platform/graphics/android/platform.h 2014-11-18 19:29:59 +0000
935@@ -33,6 +33,7 @@
936 class GraphicBufferAllocator;
937 class FramebufferFactory;
938 class DisplayBuilder;
939+class HWCVsyncCoordinator;
940
941 class Platform : public graphics::Platform, public NativePlatform
942 {
943@@ -52,6 +53,7 @@
944 std::shared_ptr<PlatformIPCPackage> connection_ipc_package() override;
945 std::shared_ptr<InternalClient> create_internal_client() override;
946 std::shared_ptr<graphics::BufferWriter> make_buffer_writer() override;
947+
948 void fill_buffer_package(
949 BufferIpcMessage* packer, graphics::Buffer const* buffer, BufferIpcMsgType msg_type) const override;
950 EGLNativeDisplayType egl_native_display() const override;
951@@ -63,6 +65,7 @@
952
953 std::shared_ptr<DisplayBuilder> const display_builder;
954 std::shared_ptr<DisplayReport> const display_report;
955+
956 std::shared_ptr<PlatformIpcOperations> const ipc_operations;
957 DeviceQuirks quirks{PropertiesOps{}};
958 };
959
960=== modified file 'src/platform/graphics/android/resource_factory.cpp'
961--- src/platform/graphics/android/resource_factory.cpp 2014-10-01 06:25:56 +0000
962+++ src/platform/graphics/android/resource_factory.cpp 2014-11-18 19:29:59 +0000
963@@ -39,6 +39,11 @@
964 namespace mg = mir::graphics;
965 namespace mga=mir::graphics::android;
966
967+mga::ResourceFactory::ResourceFactory()
968+ : vsync_coordinator(std::make_shared<mga::HWCVsync>())
969+{
970+}
971+
972 std::shared_ptr<framebuffer_device_t> mga::ResourceFactory::create_fb_native_device() const
973 {
974 hw_module_t const* module;
975@@ -92,15 +97,18 @@
976 std::shared_ptr<mga::DisplayDevice> mga::ResourceFactory::create_hwc_device(
977 std::shared_ptr<HwcWrapper> const& wrapper) const
978 {
979- auto syncer = std::make_shared<mga::HWCVsync>();
980 auto file_ops = std::make_shared<mga::RealSyncFileOps>();
981- return std::make_shared<mga::HwcDevice>(wrapper, syncer, file_ops);
982+ return std::make_shared<mga::HwcDevice>(wrapper, vsync_coordinator, file_ops);
983 }
984
985 std::shared_ptr<mga::DisplayDevice> mga::ResourceFactory::create_hwc_fb_device(
986 std::shared_ptr<HwcWrapper> const& wrapper,
987 std::shared_ptr<framebuffer_device_t> const& fb_native_device) const
988 {
989- auto syncer = std::make_shared<mga::HWCVsync>();
990- return std::make_shared<mga::HwcFbDevice>(wrapper, fb_native_device, syncer);
991+ return std::make_shared<mga::HwcFbDevice>(wrapper, fb_native_device, vsync_coordinator);
992+}
993+
994+std::shared_ptr<mga::HWCVsyncCoordinator> mga::ResourceFactory::create_vsync_coordinator() const
995+{
996+ return vsync_coordinator;
997 }
998
999=== modified file 'src/platform/graphics/android/resource_factory.h'
1000--- src/platform/graphics/android/resource_factory.h 2014-10-01 06:25:56 +0000
1001+++ src/platform/graphics/android/resource_factory.h 2014-11-18 19:29:59 +0000
1002@@ -27,10 +27,12 @@
1003 {
1004 namespace android
1005 {
1006+class HWCVsyncCoordinator;
1007
1008 class ResourceFactory : public DisplayResourceFactory
1009 {
1010 public:
1011+ ResourceFactory();
1012 //native allocations
1013 std::shared_ptr<hwc_composer_device_1> create_hwc_native_device() const;
1014 std::shared_ptr<framebuffer_device_t> create_fb_native_device() const;
1015@@ -46,6 +48,11 @@
1016
1017 std::shared_ptr<ANativeWindow> create_native_window(
1018 std::shared_ptr<FramebufferBundle> const& fb_bundle) const;
1019+
1020+ std::shared_ptr<HWCVsyncCoordinator> create_vsync_coordinator() const;
1021+
1022+private:
1023+ std::shared_ptr<HWCVsyncCoordinator> const vsync_coordinator;
1024 };
1025
1026 }
1027
1028=== modified file 'src/platform/graphics/mesa/display.cpp'
1029--- src/platform/graphics/mesa/display.cpp 2014-10-01 06:25:56 +0000
1030+++ src/platform/graphics/mesa/display.cpp 2014-11-18 19:29:59 +0000
1031@@ -24,12 +24,15 @@
1032 #include "kms_output.h"
1033 #include "kms_page_flipper.h"
1034 #include "virtual_terminal.h"
1035+
1036 #include "mir/graphics/overlapping_output_grouping.h"
1037 #include "mir/graphics/event_handler_register.h"
1038-
1039 #include "mir/graphics/display_report.h"
1040 #include "mir/graphics/gl_context.h"
1041 #include "mir/graphics/display_configuration_policy.h"
1042+
1043+#include "mir/frontend/vsync_provider.h"
1044+
1045 #include "mir/geometry/rectangle.h"
1046
1047 #include <boost/throw_exception.hpp>
1048@@ -41,6 +44,7 @@
1049
1050 namespace mgm = mir::graphics::mesa;
1051 namespace mg = mir::graphics;
1052+namespace mf = mir::frontend;
1053 namespace geom = mir::geometry;
1054
1055 namespace
1056@@ -360,3 +364,16 @@
1057 }
1058 });
1059 }
1060+
1061+// TODO: Implement for Mesa to enable touch resampling
1062+std::shared_ptr<mf::VsyncProvider> mgm::Display::vsync_provider()
1063+{
1064+ struct NullVsyncProvider : public mf::VsyncProvider
1065+ {
1066+ std::chrono::nanoseconds last_vsync_for(graphics::DisplayConfigurationOutputId) override
1067+ {
1068+ return std::chrono::nanoseconds::zero();
1069+ }
1070+ };
1071+ return std::make_shared<NullVsyncProvider>();
1072+}
1073
1074=== modified file 'src/platform/graphics/mesa/display.h'
1075--- src/platform/graphics/mesa/display.h 2014-11-03 06:51:26 +0000
1076+++ src/platform/graphics/mesa/display.h 2014-11-18 19:29:59 +0000
1077@@ -81,6 +81,8 @@
1078
1079 std::shared_ptr<graphics::Cursor> create_hardware_cursor(std::shared_ptr<CursorImage> const& initial_image) override;
1080 std::unique_ptr<GLContext> create_gl_context() override;
1081+ std::shared_ptr<frontend::VsyncProvider> vsync_provider() override;
1082+
1083
1084 private:
1085 void clear_connected_unused_outputs();
1086
1087=== modified file 'src/protobuf/mir_protobuf.proto'
1088--- src/protobuf/mir_protobuf.proto 2014-10-27 22:31:16 +0000
1089+++ src/protobuf/mir_protobuf.proto 2014-11-18 19:29:59 +0000
1090@@ -39,6 +39,8 @@
1091 optional uint32 flags = 6;
1092 optional int32 width = 7;
1093 optional int32 height = 8;
1094+
1095+ optional int64 vsync_time = 9;
1096
1097 optional string error = 127;
1098 }
1099
1100=== modified file 'src/server/frontend/default_configuration.cpp'
1101--- src/server/frontend/default_configuration.cpp 2014-11-12 14:07:30 +0000
1102+++ src/server/frontend/default_configuration.cpp 2014-11-18 19:29:59 +0000
1103@@ -27,6 +27,7 @@
1104 #include "mir/graphics/platform.h"
1105 #include "mir/frontend/protobuf_connection_creator.h"
1106 #include "mir/frontend/session_authorizer.h"
1107+#include "mir/graphics/display.h"
1108 #include "mir/options/configuration.h"
1109 #include "mir/options/option.h"
1110
1111@@ -137,6 +138,16 @@
1112 });
1113 }
1114
1115+std::shared_ptr<mf::VsyncProvider>
1116+mir::DefaultServerConfiguration::the_vsync_provider()
1117+{
1118+ return vsync_provider(
1119+ [&]()
1120+ {
1121+ return the_display()->vsync_provider();
1122+ });
1123+}
1124+
1125 std::shared_ptr<mir::frontend::ProtobufIpcFactory>
1126 mir::DefaultServerConfiguration::new_ipc_factory(
1127 std::shared_ptr<mf::SessionAuthorizer> const& session_authorizer)
1128@@ -151,13 +162,14 @@
1129 translator = std::make_shared<mf::UnsupportedCoordinateTranslator>();
1130 }
1131 return std::make_shared<mf::DefaultIpcFactory>(
1132- the_frontend_shell(),
1133- the_session_mediator_report(),
1134- the_graphics_platform()->make_ipc_operations(),
1135- the_frontend_display_changer(),
1136- the_buffer_allocator(),
1137- the_screencast(),
1138- session_authorizer,
1139- the_cursor_images(),
1140- translator);
1141+ the_frontend_shell(),
1142+ the_session_mediator_report(),
1143+ the_graphics_platform()->make_ipc_operations(),
1144+ the_frontend_display_changer(),
1145+ the_buffer_allocator(),
1146+ the_screencast(),
1147+ session_authorizer,
1148+ the_cursor_images(),
1149+ the_vsync_provider(),
1150+ translator);
1151 }
1152
1153=== modified file 'src/server/frontend/default_ipc_factory.cpp'
1154--- src/server/frontend/default_ipc_factory.cpp 2014-11-12 14:07:30 +0000
1155+++ src/server/frontend/default_ipc_factory.cpp 2014-11-18 19:29:59 +0000
1156@@ -39,6 +39,7 @@
1157 std::shared_ptr<Screencast> const& screencast,
1158 std::shared_ptr<SessionAuthorizer> const& session_authorizer,
1159 std::shared_ptr<mi::CursorImages> const& cursor_images,
1160+ std::shared_ptr<mf::VsyncProvider> const& vsync_provider,
1161 std::shared_ptr<scene::CoordinateTranslator> const& translator) :
1162 shell(shell),
1163 no_prompt_shell(std::make_shared<NoPromptShell>(shell)),
1164@@ -50,6 +51,7 @@
1165 screencast(screencast),
1166 session_authorizer(session_authorizer),
1167 cursor_images(cursor_images),
1168+ vsync_provider(vsync_provider),
1169 translator{translator}
1170 {
1171 }
1172@@ -93,7 +95,7 @@
1173 sm_report,
1174 sink,
1175 effective_screencast,
1176- connection_context, cursor_images);
1177+ connection_context, cursor_images, vsync_provider);
1178 }
1179
1180 std::shared_ptr<mf::ResourceCache> mf::DefaultIpcFactory::resource_cache()
1181@@ -110,7 +112,8 @@
1182 std::shared_ptr<EventSink> const& sink,
1183 std::shared_ptr<Screencast> const& effective_screencast,
1184 ConnectionContext const& connection_context,
1185- std::shared_ptr<mi::CursorImages> const& cursor_images)
1186+ std::shared_ptr<mi::CursorImages> const& cursor_images,
1187+ std::shared_ptr<mf::VsyncProvider> const& vsync_provider)
1188 {
1189 return std::make_shared<SessionMediator>(
1190 shell,
1191@@ -123,5 +126,6 @@
1192 effective_screencast,
1193 connection_context,
1194 cursor_images,
1195+ vsync_provider,
1196 translator);
1197 }
1198
1199=== modified file 'src/server/frontend/default_ipc_factory.h'
1200--- src/server/frontend/default_ipc_factory.h 2014-11-12 14:07:30 +0000
1201+++ src/server/frontend/default_ipc_factory.h 2014-11-18 19:29:59 +0000
1202@@ -45,6 +45,7 @@
1203 class DisplayChanger;
1204 class Screencast;
1205 class SessionAuthorizer;
1206+class VsyncProvider;
1207
1208 class DefaultIpcFactory : public ProtobufIpcFactory
1209 {
1210@@ -58,6 +59,7 @@
1211 std::shared_ptr<Screencast> const& screencast,
1212 std::shared_ptr<SessionAuthorizer> const& session_authorizer,
1213 std::shared_ptr<input::CursorImages> const& cursor_images,
1214+ std::shared_ptr<VsyncProvider> const& vsync_provider,
1215 std::shared_ptr<scene::CoordinateTranslator> const& translator);
1216
1217 std::shared_ptr<detail::DisplayServer> make_ipc_server(
1218@@ -76,7 +78,8 @@
1219 std::shared_ptr<EventSink> const& sink,
1220 std::shared_ptr<Screencast> const& effective_screencast,
1221 ConnectionContext const& connection_context,
1222- std::shared_ptr<input::CursorImages> const& cursor_images);
1223+ std::shared_ptr<input::CursorImages> const& cursor_images,
1224+ std::shared_ptr<VsyncProvider> const& vsync_provider);
1225
1226 private:
1227 std::shared_ptr<Shell> const shell;
1228@@ -89,6 +92,7 @@
1229 std::shared_ptr<Screencast> const screencast;
1230 std::shared_ptr<SessionAuthorizer> const session_authorizer;
1231 std::shared_ptr<input::CursorImages> const cursor_images;
1232+ std::shared_ptr<frontend::VsyncProvider> const vsync_provider;
1233 std::shared_ptr<scene::CoordinateTranslator> const translator;
1234 };
1235 }
1236
1237=== modified file 'src/server/frontend/session_mediator.cpp'
1238--- src/server/frontend/session_mediator.cpp 2014-11-18 03:21:20 +0000
1239+++ src/server/frontend/session_mediator.cpp 2014-11-18 19:29:59 +0000
1240@@ -41,6 +41,7 @@
1241 #include "mir/frontend/event_sink.h"
1242 #include "mir/frontend/screencast.h"
1243 #include "mir/frontend/prompt_session.h"
1244+#include "mir/frontend/vsync_provider.h"
1245 #include "mir/scene/prompt_session_creation_parameters.h"
1246 #include "mir/fd.h"
1247
1248@@ -74,6 +75,7 @@
1249 std::shared_ptr<Screencast> const& screencast,
1250 ConnectionContext const& connection_context,
1251 std::shared_ptr<mi::CursorImages> const& cursor_images,
1252+ std::shared_ptr<mf::VsyncProvider> const& vsync_provider,
1253 std::shared_ptr<scene::CoordinateTranslator> const& translator) :
1254 client_pid_(0),
1255 shell(shell),
1256@@ -86,6 +88,7 @@
1257 screencast(screencast),
1258 connection_context(connection_context),
1259 cursor_images(cursor_images),
1260+ vsync_provider(vsync_provider),
1261 translator{translator},
1262 surface_tracker{static_cast<size_t>(client_buffer_cache_size)}
1263 {
1264@@ -671,6 +674,11 @@
1265 {
1266 protobuf_buffer.set_buffer_id(graphics_buffer->id().as_value());
1267
1268+ // TODO: ~racarr Enable MM touch resampling
1269+ auto vsync_time = vsync_provider->last_vsync_for(mg::DisplayConfigurationOutputId{0});
1270+ if (vsync_time != std::chrono::nanoseconds::zero())
1271+ protobuf_buffer.set_vsync_time(vsync_time.count());
1272+
1273 mfd::ProtobufBufferPacker packer{&protobuf_buffer};
1274 ipc_operations->pack_buffer(packer, *graphics_buffer, buffer_msg_type);
1275
1276
1277=== modified file 'src/server/frontend/session_mediator.h'
1278--- src/server/frontend/session_mediator.h 2014-11-12 14:07:30 +0000
1279+++ src/server/frontend/session_mediator.h 2014-11-18 19:29:59 +0000
1280@@ -63,6 +63,7 @@
1281 class DisplayChanger;
1282 class Screencast;
1283 class PromptSession;
1284+class VsyncProvider;
1285
1286 // SessionMediator relays requests from the client process into the server.
1287 class SessionMediator : public detail::DisplayServer, public mir::protobuf::Debug
1288@@ -80,6 +81,7 @@
1289 std::shared_ptr<Screencast> const& screencast,
1290 ConnectionContext const& connection_context,
1291 std::shared_ptr<input::CursorImages> const& cursor_images,
1292+ std::shared_ptr<VsyncProvider> const& vsync_provider,
1293 std::shared_ptr<scene::CoordinateTranslator> const& translator);
1294
1295 ~SessionMediator() noexcept;
1296@@ -203,6 +205,7 @@
1297 std::shared_ptr<Screencast> const screencast;
1298 ConnectionContext const connection_context;
1299 std::shared_ptr<input::CursorImages> const cursor_images;
1300+ std::shared_ptr<frontend::VsyncProvider> const vsync_provider;
1301 std::shared_ptr<scene::CoordinateTranslator> const translator;
1302
1303 SurfaceTracker surface_tracker;
1304
1305=== modified file 'src/server/graphics/nested/CMakeLists.txt'
1306--- src/server/graphics/nested/CMakeLists.txt 2014-10-01 06:25:56 +0000
1307+++ src/server/graphics/nested/CMakeLists.txt 2014-11-18 19:29:59 +0000
1308@@ -9,6 +9,7 @@
1309 nested_display_configuration.cpp
1310 nested_output.cpp
1311 nested_platform.cpp
1312+ nested_vsync_provider.cpp
1313 mir_client_host_connection.cpp
1314 )
1315
1316
1317=== modified file 'src/server/graphics/nested/host_connection.h'
1318--- src/server/graphics/nested/host_connection.h 2014-04-24 08:42:12 +0000
1319+++ src/server/graphics/nested/host_connection.h 2014-11-18 19:29:59 +0000
1320@@ -24,6 +24,7 @@
1321 #include <memory>
1322 #include <vector>
1323 #include <functional>
1324+#include <chrono>
1325
1326 #include <EGL/egl.h>
1327
1328@@ -43,6 +44,8 @@
1329
1330 virtual EGLNativeWindowType egl_native_window() = 0;
1331 virtual void set_event_handler(MirEventDelegate const* handler) = 0;
1332+
1333+ virtual std::chrono::nanoseconds last_display_time() = 0;
1334
1335 protected:
1336 HostSurface() = default;
1337
1338=== modified file 'src/server/graphics/nested/mir_client_host_connection.cpp'
1339--- src/server/graphics/nested/mir_client_host_connection.cpp 2014-10-01 06:25:56 +0000
1340+++ src/server/graphics/nested/mir_client_host_connection.cpp 2014-11-18 19:29:59 +0000
1341@@ -77,6 +77,11 @@
1342 {
1343 mir_surface_set_event_handler(mir_surface, handler);
1344 }
1345+
1346+ std::chrono::nanoseconds last_display_time() override
1347+ {
1348+ return std::chrono::nanoseconds(mir_surface_get_last_display_time(mir_surface));
1349+ }
1350
1351 private:
1352 MirSurface* const mir_surface;
1353
1354=== modified file 'src/server/graphics/nested/nested_display.cpp'
1355--- src/server/graphics/nested/nested_display.cpp 2014-10-01 06:25:56 +0000
1356+++ src/server/graphics/nested/nested_display.cpp 2014-11-18 19:29:59 +0000
1357@@ -19,6 +19,7 @@
1358 #include "nested_display.h"
1359 #include "nested_display_configuration.h"
1360 #include "nested_output.h"
1361+#include "nested_vsync_provider.h"
1362 #include "host_connection.h"
1363
1364 #include "mir/geometry/rectangle.h"
1365@@ -34,6 +35,7 @@
1366
1367 namespace mg = mir::graphics;
1368 namespace mgn = mir::graphics::nested;
1369+namespace mf = mir::frontend;
1370 namespace geom = mir::geometry;
1371
1372 EGLint const mgn::detail::nested_egl_context_attribs[] =
1373@@ -131,6 +133,7 @@
1374 dispatcher{dispatcher},
1375 display_report{display_report},
1376 egl_display{connection->egl_native_display(), gl_config},
1377+ vsync_provider_(std::make_shared<mgn::VsyncProvider>()),
1378 outputs{}
1379 {
1380 std::shared_ptr<DisplayConfiguration> conf(configuration());
1381@@ -211,7 +214,7 @@
1382 host_surface,
1383 area,
1384 dispatcher,
1385- output.current_format);
1386+ output.current_format, vsync_provider_, output.id);
1387 have_output_for_group = true;
1388 }
1389 });
1390@@ -267,3 +270,8 @@
1391 {
1392 return std::unique_ptr<mg::GLContext>{new SurfacelessEGLContext(egl_display, EGL_NO_CONTEXT)};
1393 }
1394+
1395+std::shared_ptr<mf::VsyncProvider> mgn::NestedDisplay::vsync_provider()
1396+{
1397+ return vsync_provider_;
1398+}
1399
1400=== modified file 'src/server/graphics/nested/nested_display.h'
1401--- src/server/graphics/nested/nested_display.h 2014-10-01 06:25:56 +0000
1402+++ src/server/graphics/nested/nested_display.h 2014-11-18 19:29:59 +0000
1403@@ -48,6 +48,7 @@
1404
1405 namespace nested
1406 {
1407+class VsyncProvider;
1408 namespace detail
1409 {
1410
1411@@ -124,6 +125,8 @@
1412
1413 std::shared_ptr<Cursor> create_hardware_cursor(std::shared_ptr<CursorImage> const& initial_image) override;
1414 std::unique_ptr<graphics::GLContext> create_gl_context() override;
1415+
1416+ std::shared_ptr<frontend::VsyncProvider> vsync_provider() override;
1417
1418 private:
1419 std::shared_ptr<Platform> const platform;
1420@@ -131,6 +134,7 @@
1421 std::shared_ptr<input::InputDispatcher> const dispatcher;
1422 std::shared_ptr<DisplayReport> const display_report;
1423 detail::EGLDisplayHandle egl_display;
1424+ std::shared_ptr<VsyncProvider> const vsync_provider_;
1425
1426 std::mutex outputs_mutex;
1427 std::unordered_map<DisplayConfigurationOutputId, std::shared_ptr<detail::NestedOutput>> outputs;
1428
1429=== modified file 'src/server/graphics/nested/nested_output.cpp'
1430--- src/server/graphics/nested/nested_output.cpp 2014-10-01 06:25:56 +0000
1431+++ src/server/graphics/nested/nested_output.cpp 2014-11-18 19:29:59 +0000
1432@@ -18,6 +18,8 @@
1433
1434 #include "nested_output.h"
1435 #include "host_connection.h"
1436+#include "nested_vsync_provider.h"
1437+
1438 #include "mir/input/input_dispatcher.h"
1439 #include "mir/graphics/pixel_format_utils.h"
1440
1441@@ -33,7 +35,9 @@
1442 std::shared_ptr<HostSurface> const& host_surface,
1443 geometry::Rectangle const& area,
1444 std::shared_ptr<input::InputDispatcher> const& dispatcher,
1445- MirPixelFormat preferred_format) :
1446+ MirPixelFormat preferred_format,
1447+ std::shared_ptr<mgn::VsyncProvider> const& vsync_provider,
1448+ mg::DisplayConfigurationOutputId id) :
1449 uses_alpha_{mg::contains_alpha(preferred_format)},
1450 egl_display(egl_display),
1451 host_surface{host_surface},
1452@@ -41,7 +45,9 @@
1453 egl_context{egl_display, eglCreateContext(egl_display, egl_config, egl_display.egl_context(), nested_egl_context_attribs)},
1454 area{area.top_left, area.size},
1455 dispatcher{dispatcher},
1456- egl_surface{egl_display, host_surface->egl_native_window(), egl_config}
1457+ egl_surface{egl_display, host_surface->egl_native_window(), egl_config},
1458+ vsync_provider(vsync_provider),
1459+ id(id)
1460 {
1461 MirEventDelegate ed = {event_thunk, this};
1462 host_surface->set_event_handler(&ed);
1463@@ -66,6 +72,7 @@
1464 void mgn::detail::NestedOutput::post_update()
1465 {
1466 eglSwapBuffers(egl_display, egl_surface);
1467+ vsync_provider->notify_of_vsync(id, host_surface->last_display_time());
1468 }
1469
1470 bool mgn::detail::NestedOutput::post_renderables_if_optimizable(RenderableList const&)
1471
1472=== modified file 'src/server/graphics/nested/nested_output.h'
1473--- src/server/graphics/nested/nested_output.h 2014-11-03 06:51:26 +0000
1474+++ src/server/graphics/nested/nested_output.h 2014-11-18 19:29:59 +0000
1475@@ -21,6 +21,8 @@
1476
1477 #include "nested_display.h"
1478
1479+#include "mir/graphics/display_configuration.h"
1480+
1481 namespace mir
1482 {
1483 namespace graphics
1484@@ -28,6 +30,7 @@
1485 namespace nested
1486 {
1487 class HostSurface;
1488+class VsyncProvider;
1489
1490 namespace detail
1491 {
1492@@ -40,7 +43,9 @@
1493 std::shared_ptr<HostSurface> const& host_surface,
1494 geometry::Rectangle const& area,
1495 std::shared_ptr<input::InputDispatcher> const& input_dispatcher,
1496- MirPixelFormat preferred_format);
1497+ MirPixelFormat preferred_format,
1498+ std::shared_ptr<VsyncProvider> const& vsync_provider,
1499+ DisplayConfigurationOutputId id);
1500
1501 ~NestedOutput() noexcept;
1502
1503@@ -64,6 +69,9 @@
1504 geometry::Rectangle const area;
1505 std::shared_ptr<input::InputDispatcher> const dispatcher;
1506 EGLSurfaceHandle const egl_surface;
1507+
1508+ std::shared_ptr<VsyncProvider> const vsync_provider;
1509+ DisplayConfigurationOutputId id;
1510
1511 static void event_thunk(MirSurface* surface, MirEvent const* event, void* context);
1512 void mir_event(MirEvent const& event);
1513
1514=== modified file 'src/server/graphics/nested/nested_platform.cpp'
1515--- src/server/graphics/nested/nested_platform.cpp 2014-11-18 09:59:21 +0000
1516+++ src/server/graphics/nested/nested_platform.cpp 2014-11-18 19:29:59 +0000
1517@@ -17,6 +17,7 @@
1518 */
1519
1520 #include "nested_platform.h"
1521+#include "nested_vsync_provider.h"
1522 #include "host_connection.h"
1523 #include "mir/graphics/nested_context.h"
1524
1525@@ -24,6 +25,7 @@
1526
1527 namespace mg = mir::graphics;
1528 namespace mgn = mir::graphics::nested;
1529+namespace mf = mir::frontend;
1530
1531 mgn::NestedPlatform::NestedPlatform(
1532 std::shared_ptr<HostConnection> const& connection,
1533
1534=== added file 'src/server/graphics/nested/nested_vsync_provider.cpp'
1535--- src/server/graphics/nested/nested_vsync_provider.cpp 1970-01-01 00:00:00 +0000
1536+++ src/server/graphics/nested/nested_vsync_provider.cpp 2014-11-18 19:29:59 +0000
1537@@ -0,0 +1,45 @@
1538+/*
1539+ * Copyright © 2014 Canonical Ltd.
1540+ *
1541+ * This program is free software: you can redistribute it and/or modify it
1542+ * under the terms of the GNU General Public License version 3,
1543+ * as published by the Free Software Foundation.
1544+ *
1545+ * This program is distributed in the hope that it will be useful,
1546+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1547+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1548+ * GNU General Public License for more details.
1549+ *
1550+ * You should have received a copy of the GNU General Public License
1551+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1552+ *
1553+ * Authored by: Robert Carr <robert.carr@canonical.com>
1554+ */
1555+
1556+#include "nested_vsync_provider.h"
1557+
1558+#include <boost/throw_exception.hpp>
1559+#include <stdexcept>
1560+
1561+namespace mg = mir::graphics;
1562+namespace mgn = mg::nested;
1563+
1564+void mgn::VsyncProvider::notify_of_vsync(mg::DisplayConfigurationOutputId id, std::chrono::nanoseconds vsync_time)
1565+{
1566+ std::lock_guard<std::mutex> lg(last_vsync_guard);
1567+ last_vsync[id] = vsync_time;
1568+}
1569+
1570+std::chrono::nanoseconds mgn::VsyncProvider::last_vsync_for(mg::DisplayConfigurationOutputId id)
1571+{
1572+ std::lock_guard<std::mutex> lg(last_vsync_guard);
1573+
1574+ // In this structure we see two flaws of the DisplayConfigurationOutputId mechanism
1575+ // 1. Failure to find id is not an exception, we may have just not seen a vsync time yet
1576+ // how do we differentiate without complex integration with display notification changes?
1577+ // 2. Similarly, how do we know when we are done with an ID?
1578+ if (last_vsync.find(id) == last_vsync.end())
1579+ return std::chrono::nanoseconds::zero();
1580+
1581+ return last_vsync[id];
1582+}
1583
1584=== added file 'src/server/graphics/nested/nested_vsync_provider.h'
1585--- src/server/graphics/nested/nested_vsync_provider.h 1970-01-01 00:00:00 +0000
1586+++ src/server/graphics/nested/nested_vsync_provider.h 2014-11-18 19:29:59 +0000
1587@@ -0,0 +1,49 @@
1588+/*
1589+ * Copyright © 2014 Canonical Ltd.
1590+ *
1591+ * This program is free software: you can redistribute it and/or modify it
1592+ * under the terms of the GNU General Public License version 3,
1593+ * as published by the Free Software Foundation.
1594+ *
1595+ * This program is distributed in the hope that it will be useful,
1596+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1597+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1598+ * GNU General Public License for more details.
1599+ *
1600+ * You should have received a copy of the GNU General Public License
1601+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1602+ *
1603+ * Authored by: Robert Carr <robert.carr@canonical.com>
1604+ */
1605+
1606+#ifndef MIR_GRAPHICS_NESTED_VSYNC_PROVIDER_H_
1607+#define MIR_GRAPHICS_NESTED_VSYNC_PROVIDER_H_
1608+
1609+#include "mir/frontend/vsync_provider.h"
1610+
1611+#include <mutex>
1612+#include <map>
1613+
1614+namespace mir
1615+{
1616+namespace graphics
1617+{
1618+namespace nested
1619+{
1620+
1621+struct VsyncProvider : public frontend::VsyncProvider
1622+{
1623+public:
1624+ void notify_of_vsync(DisplayConfigurationOutputId id, std::chrono::nanoseconds vsync_time);
1625+ std::chrono::nanoseconds last_vsync_for(DisplayConfigurationOutputId id);
1626+
1627+private:
1628+ std::mutex last_vsync_guard;
1629+ std::map<DisplayConfigurationOutputId, std::chrono::nanoseconds> last_vsync;
1630+};
1631+
1632+}
1633+}
1634+}
1635+
1636+#endif // MIR_GRAPHICS_NESTED_VSYNC_PROVIDER_H_
1637
1638=== modified file 'src/server/graphics/offscreen/display.cpp'
1639--- src/server/graphics/offscreen/display.cpp 2014-10-01 06:25:56 +0000
1640+++ src/server/graphics/offscreen/display.cpp 2014-11-18 19:29:59 +0000
1641@@ -20,12 +20,14 @@
1642 #include "display_buffer.h"
1643 #include "mir/graphics/basic_platform.h"
1644 #include "mir/graphics/display_configuration_policy.h"
1645+#include "mir/frontend/vsync_provider.h"
1646 #include "mir/geometry/size.h"
1647
1648 #include <boost/throw_exception.hpp>
1649 #include <stdexcept>
1650
1651 namespace mg = mir::graphics;
1652+namespace mf = mir::frontend;
1653 namespace mgo = mg::offscreen;
1654 namespace geom = mir::geometry;
1655
1656@@ -173,3 +175,17 @@
1657 return std::unique_ptr<GLContext>{
1658 new SurfacelessEGLContext{egl_display, egl_context_shared}};
1659 }
1660+
1661+// Not many examples of needing interactive touch resampling to offscreen outputs
1662+// so this may never have an implementation...perhaps leaving some code smell.
1663+std::shared_ptr<mf::VsyncProvider> mgo::Display::vsync_provider()
1664+{
1665+ struct NullVsyncProvider : public mf::VsyncProvider
1666+ {
1667+ std::chrono::nanoseconds last_vsync_for(graphics::DisplayConfigurationOutputId) override
1668+ {
1669+ return std::chrono::nanoseconds::zero();
1670+ }
1671+ };
1672+ return std::make_shared<NullVsyncProvider>();
1673+}
1674
1675=== modified file 'src/server/graphics/offscreen/display.h'
1676--- src/server/graphics/offscreen/display.h 2014-11-03 06:51:26 +0000
1677+++ src/server/graphics/offscreen/display.h 2014-11-18 19:29:59 +0000
1678@@ -88,6 +88,8 @@
1679
1680 std::shared_ptr<Cursor> create_hardware_cursor(std::shared_ptr<CursorImage> const& initial_image) override;
1681 std::unique_ptr<GLContext> create_gl_context() override;
1682+ std::shared_ptr<frontend::VsyncProvider> vsync_provider() override;
1683+
1684
1685 private:
1686 std::shared_ptr<BasicPlatform> const basic_platform;
1687
1688=== modified file 'src/server/symbols.map'
1689--- src/server/symbols.map 2014-11-18 17:26:29 +0000
1690+++ src/server/symbols.map 2014-11-18 19:29:59 +0000
1691@@ -103,6 +103,7 @@
1692 mir::DefaultServerConfiguration::the_scene*;
1693 mir::DefaultServerConfiguration::the_scene_report*;
1694 mir::DefaultServerConfiguration::the_screencast*;
1695+ mir::DefaultServerConfiguration::the_vsync_provider*;
1696 mir::DefaultServerConfiguration::the_server_action_queue*;
1697 mir::DefaultServerConfiguration::the_server_status_listener*;
1698 mir::DefaultServerConfiguration::the_session_authorizer*;
1699@@ -578,6 +579,7 @@
1700 non-virtual?thunk?to?mir::DefaultServerConfiguration::the_scene*;
1701 non-virtual?thunk?to?mir::DefaultServerConfiguration::the_scene_report*;
1702 non-virtual?thunk?to?mir::DefaultServerConfiguration::the_screencast*;
1703+ non-virtual?thunk?to?mir::DefaultServerConfiguration::the_vsync_provider*;
1704 non-virtual?thunk?to?mir::DefaultServerConfiguration::the_server_action_queue*;
1705 non-virtual?thunk?to?mir::DefaultServerConfiguration::the_server_status_listener*;
1706 non-virtual?thunk?to?mir::DefaultServerConfiguration::the_session_authorizer*;
1707
1708=== modified file 'tests/acceptance-tests/test_client_library.cpp'
1709--- tests/acceptance-tests/test_client_library.cpp 2014-11-11 17:46:49 +0000
1710+++ tests/acceptance-tests/test_client_library.cpp 2014-11-18 19:29:59 +0000
1711@@ -146,11 +146,16 @@
1712 }
1713 }
1714 };
1715+
1716+struct ClientLibraryStubbedPlatform : public ClientLibrary
1717+{
1718+ mtf::UsingStubClientPlatform using_stub_client_platform;
1719+};
1720 }
1721
1722 using namespace testing;
1723
1724-TEST_F(ClientLibrary, client_library_connects_and_disconnects)
1725+TEST_F(ClientLibraryStubbedPlatform, client_library_connects_and_disconnects)
1726 {
1727 MirWaitHandle* wh = mir_connect(new_connection().c_str(), __PRETTY_FUNCTION__, connection_callback, this);
1728 EXPECT_THAT(wh, NotNull());
1729@@ -163,7 +168,7 @@
1730 mir_connection_release(connection);
1731 }
1732
1733-TEST_F(ClientLibrary, synchronous_connection)
1734+TEST_F(ClientLibraryStubbedPlatform, synchronous_connection)
1735 {
1736 connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
1737
1738@@ -174,7 +179,7 @@
1739 mir_connection_release(connection);
1740 }
1741
1742-TEST_F(ClientLibrary, creates_surface)
1743+TEST_F(ClientLibraryStubbedPlatform, creates_surface)
1744 {
1745 mir_wait_for(mir_connect(new_connection().c_str(), __PRETTY_FUNCTION__, connection_callback, this));
1746
1747@@ -220,7 +225,7 @@
1748 mir_connection_release(connection);
1749 }
1750
1751-TEST_F(ClientLibrary, can_set_surface_types)
1752+TEST_F(ClientLibraryStubbedPlatform, can_set_surface_types)
1753 {
1754 mir_wait_for(mir_connect(new_connection().c_str(), __PRETTY_FUNCTION__, connection_callback, this));
1755
1756@@ -265,7 +270,7 @@
1757 mir_connection_release(connection);
1758 }
1759
1760-TEST_F(ClientLibrary, can_set_surface_state)
1761+TEST_F(ClientLibraryStubbedPlatform, can_set_surface_state)
1762 {
1763 connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
1764
1765@@ -307,7 +312,7 @@
1766 mir_connection_release(connection);
1767 }
1768
1769-TEST_F(ClientLibrary, receives_surface_dpi_value)
1770+TEST_F(ClientLibraryStubbedPlatform, receives_surface_dpi_value)
1771 {
1772 connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
1773
1774@@ -388,7 +393,7 @@
1775
1776 #ifdef ANDROID
1777 // Mir's Android test infrastructure isn't quite ready for this yet.
1778-TEST_F(ClientLibrary, DISABLED_gets_buffer_dimensions)
1779+TEST_F(ClientLibraryStubbedPlatform, DISABLED_gets_buffer_dimensions)
1780 #else
1781 TEST_F(ClientLibrary, gets_buffer_dimensions)
1782 #endif
1783@@ -436,7 +441,7 @@
1784 mir_connection_release(connection);
1785 }
1786
1787-TEST_F(ClientLibrary, creates_multiple_surfaces)
1788+TEST_F(ClientLibraryStubbedPlatform, creates_multiple_surfaces)
1789 {
1790 int const n_surfaces = 13;
1791 size_t old_surface_count = 0;
1792@@ -475,7 +480,7 @@
1793 mir_connection_release(connection);
1794 }
1795
1796-TEST_F(ClientLibrary, client_library_accesses_and_advances_buffers)
1797+TEST_F(ClientLibraryStubbedPlatform, client_library_accesses_and_advances_buffers)
1798 {
1799 mir_wait_for(mir_connect(new_connection().c_str(), __PRETTY_FUNCTION__, connection_callback, this));
1800
1801@@ -501,7 +506,7 @@
1802 mir_connection_release(connection);
1803 }
1804
1805-TEST_F(ClientLibrary, fully_synchronous_client)
1806+TEST_F(ClientLibraryStubbedPlatform, fully_synchronous_client)
1807 {
1808 connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
1809
1810@@ -527,7 +532,7 @@
1811 mir_connection_release(connection);
1812 }
1813
1814-TEST_F(ClientLibrary, highly_threaded_client)
1815+TEST_F(ClientLibraryStubbedPlatform, highly_threaded_client)
1816 {
1817 connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
1818
1819@@ -560,7 +565,7 @@
1820 mir_connection_release(connection);
1821 }
1822
1823-TEST_F(ClientLibrary, accesses_platform_package)
1824+TEST_F(ClientLibraryStubbedPlatform, accesses_platform_package)
1825 {
1826 mir_wait_for(mir_connect(new_connection().c_str(), __PRETTY_FUNCTION__, connection_callback, this));
1827
1828@@ -575,7 +580,7 @@
1829 mir_connection_release(connection);
1830 }
1831
1832-TEST_F(ClientLibrary, accesses_display_info)
1833+TEST_F(ClientLibraryStubbedPlatform, accesses_display_info)
1834 {
1835 mir_wait_for(mir_connect(new_connection().c_str(), __PRETTY_FUNCTION__, connection_callback, this));
1836
1837
1838=== modified file 'tests/include/mir_test_doubles/mock_display.h'
1839--- tests/include/mir_test_doubles/mock_display.h 2014-10-01 06:25:56 +0000
1840+++ tests/include/mir_test_doubles/mock_display.h 2014-11-18 19:29:59 +0000
1841@@ -48,6 +48,7 @@
1842 MOCK_METHOD0(resume, void());
1843 MOCK_METHOD1(create_hardware_cursor, std::shared_ptr<graphics::Cursor>(std::shared_ptr<graphics::CursorImage> const&));
1844 MOCK_METHOD0(create_gl_context, std::unique_ptr<graphics::GLContext>());
1845+ MOCK_METHOD0(vsync_provider, std::shared_ptr<frontend::VsyncProvider>());
1846 };
1847
1848 }
1849
1850=== modified file 'tests/include/mir_test_doubles/mock_hwc_vsync_coordinator.h'
1851--- tests/include/mir_test_doubles/mock_hwc_vsync_coordinator.h 2014-03-06 06:05:17 +0000
1852+++ tests/include/mir_test_doubles/mock_hwc_vsync_coordinator.h 2014-11-18 19:29:59 +0000
1853@@ -34,7 +34,9 @@
1854 {
1855 ~MockVsyncCoordinator() noexcept {}
1856 MOCK_METHOD0(wait_for_vsync, void());
1857- MOCK_METHOD0(notify_vsync, void());
1858+ MOCK_METHOD1(notify_vsync, void(std::chrono::nanoseconds));
1859+
1860+ MOCK_METHOD1(last_vsync_for, std::chrono::nanoseconds(graphics::DisplayConfigurationOutputId));
1861 };
1862
1863
1864
1865=== modified file 'tests/include/mir_test_doubles/null_display.h'
1866--- tests/include/mir_test_doubles/null_display.h 2014-11-03 06:51:26 +0000
1867+++ tests/include/mir_test_doubles/null_display.h 2014-11-18 19:29:59 +0000
1868@@ -66,6 +66,11 @@
1869 {
1870 return std::unique_ptr<NullGLContext>{new NullGLContext()};
1871 }
1872+
1873+ std::shared_ptr<frontend::VsyncProvider> vsync_provider()
1874+ {
1875+ return nullptr;
1876+ }
1877 };
1878
1879 }
1880
1881=== modified file 'tests/include/mir_test_doubles/stub_display.h'
1882--- tests/include/mir_test_doubles/stub_display.h 2014-06-17 11:21:31 +0000
1883+++ tests/include/mir_test_doubles/stub_display.h 2014-11-18 19:29:59 +0000
1884@@ -22,6 +22,7 @@
1885 #include "null_display.h"
1886 #include "stub_display_buffer.h"
1887 #include "stub_display_configuration.h"
1888+#include "stub_vsync_provider.h"
1889
1890 #include "mir/geometry/rectangle.h"
1891
1892@@ -56,6 +57,11 @@
1893 new StubDisplayConfig(output_rects)
1894 );
1895 }
1896+
1897+ std::shared_ptr<frontend::VsyncProvider> vsync_provider() override
1898+ {
1899+ return std::make_shared<StubVsyncProvider>();
1900+ }
1901
1902 private:
1903 std::vector<geometry::Rectangle> const output_rects;
1904
1905=== modified file 'tests/include/mir_test_doubles/stub_display_builder.h'
1906--- tests/include/mir_test_doubles/stub_display_builder.h 2014-10-01 06:25:56 +0000
1907+++ tests/include/mir_test_doubles/stub_display_builder.h 2014-11-18 19:29:59 +0000
1908@@ -84,6 +84,11 @@
1909 new StubConfigurableDisplayBuffer(geometry::Rectangle{{0,0},sz}));
1910 }
1911
1912+ std::shared_ptr<graphics::android::HWCVsyncCoordinator> vsync_coordinator() const
1913+ {
1914+ return nullptr;
1915+ }
1916+
1917 geometry::Size sz;
1918 };
1919 }
1920
1921=== modified file 'tests/include/mir_test_doubles/stub_host_connection.h'
1922--- tests/include/mir_test_doubles/stub_host_connection.h 2014-04-23 14:19:34 +0000
1923+++ tests/include/mir_test_doubles/stub_host_connection.h 2014-11-18 19:29:59 +0000
1924@@ -55,6 +55,7 @@
1925 public:
1926 EGLNativeWindowType egl_native_window() override { return {}; }
1927 void set_event_handler(MirEventDelegate const*) override {}
1928+ std::chrono::nanoseconds last_display_time() override { return std::chrono::nanoseconds::min(); }
1929 };
1930
1931 return std::make_shared<NullHostSurface>();
1932
1933=== added file 'tests/include/mir_test_doubles/stub_vsync_provider.h'
1934--- tests/include/mir_test_doubles/stub_vsync_provider.h 1970-01-01 00:00:00 +0000
1935+++ tests/include/mir_test_doubles/stub_vsync_provider.h 2014-11-18 19:29:59 +0000
1936@@ -0,0 +1,43 @@
1937+/*
1938+ * Copyright © 2014 Canonical Ltd.
1939+ *
1940+ * This program is free software: you can redistribute it and/or modify it
1941+ * under the terms of the GNU General Public License version 3,
1942+ * as published by the Free Software Foundation.
1943+ *
1944+ * This program is distributed in the hope that it will be useful,
1945+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1946+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1947+ * GNU General Public License for more details.
1948+ *
1949+ * You should have received a copy of the GNU General Public License
1950+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1951+ *
1952+ * Authored by: Robert Carr <robert.carr@canonical.com>
1953+ */
1954+
1955+#ifndef MIR_TEST_DOUBLES_STUB_VSYNC_PROVIDER_H_
1956+#define MIR_TEST_DOUBLES_STUB_VSYNC_PROVIDER_H_
1957+
1958+#include "mir/frontend/vsync_provider.h"
1959+
1960+namespace mir
1961+{
1962+namespace test
1963+{
1964+namespace doubles
1965+{
1966+
1967+struct StubVsyncProvider : public frontend::VsyncProvider
1968+{
1969+ std::chrono::nanoseconds last_vsync_for(graphics::DisplayConfigurationOutputId) override
1970+ {
1971+ return std::chrono::nanoseconds::zero();
1972+ }
1973+};
1974+
1975+}
1976+}
1977+}
1978+
1979+#endif // MIR_TEST_DOUBLES_STUB_VSYNC_PROVIDER_H_
1980
1981=== modified file 'tests/include/mir_test_framework/using_stub_client_platform.h'
1982--- tests/include/mir_test_framework/using_stub_client_platform.h 2014-11-11 15:50:11 +0000
1983+++ tests/include/mir_test_framework/using_stub_client_platform.h 2014-11-18 19:29:59 +0000
1984@@ -19,6 +19,8 @@
1985 #ifndef MIR_TEST_FRAMEWORK_USING_STUB_CLIENT_PLATFORM_H_
1986 #define MIR_TEST_FRAMEWORK_USING_STUB_CLIENT_PLATFORM_H_
1987
1988+#include "src/client/connection_configuration.h"
1989+
1990 #include <memory>
1991 #include <functional>
1992
1993
1994=== modified file 'tests/integration-tests/CMakeLists.txt'
1995--- tests/integration-tests/CMakeLists.txt 2014-11-18 03:21:20 +0000
1996+++ tests/integration-tests/CMakeLists.txt 2014-11-18 19:29:59 +0000
1997@@ -33,6 +33,7 @@
1998 test_server_shutdown.cpp
1999 test_session_manager.cpp
2000 test_session.cpp
2001+ test_vsync_to_client.cpp
2002 session_management.cpp
2003 surface_composition.cpp
2004 ${GENERATED_PROTOBUF_SRCS}
2005
2006=== modified file 'tests/integration-tests/graphics/android/test_display_integration.cpp'
2007--- tests/integration-tests/graphics/android/test_display_integration.cpp 2014-10-21 16:21:14 +0000
2008+++ tests/integration-tests/graphics/android/test_display_integration.cpp 2014-11-18 19:29:59 +0000
2009@@ -22,6 +22,7 @@
2010 #include "src/platform/graphics/android/resource_factory.h"
2011 #include "src/platform/graphics/android/android_graphic_buffer_allocator.h"
2012 #include "src/platform/graphics/android/output_builder.h"
2013+#include "src/platform/graphics/android/hwc_vsync.h"
2014 #include "src/server/graphics/program_factory.h"
2015 #include "src/server/report/null_report_factory.h"
2016
2017
2018=== modified file 'tests/integration-tests/test_surfaceloop.cpp'
2019--- tests/integration-tests/test_surfaceloop.cpp 2014-10-21 16:21:14 +0000
2020+++ tests/integration-tests/test_surfaceloop.cpp 2014-11-18 19:29:59 +0000
2021@@ -23,6 +23,7 @@
2022 #include "mir_test_doubles/null_platform.h"
2023 #include "mir_test_doubles/null_display.h"
2024 #include "mir_test_doubles/stub_display_buffer.h"
2025+#include "mir_test_doubles/stub_vsync_provider.h"
2026
2027 #include "mir_test_framework/stubbed_server_configuration.h"
2028 #include "mir_test_framework/basic_client_server_fixture.h"
2029@@ -85,6 +86,12 @@
2030 f(display_buffer);
2031 }
2032
2033+ std::shared_ptr<mf::VsyncProvider> vsync_provider() override
2034+ {
2035+ return std::make_shared<mtd::StubVsyncProvider>();
2036+ }
2037+
2038+
2039 private:
2040 mtd::StubDisplayBuffer display_buffer;
2041 };
2042
2043=== added file 'tests/integration-tests/test_vsync_to_client.cpp'
2044--- tests/integration-tests/test_vsync_to_client.cpp 1970-01-01 00:00:00 +0000
2045+++ tests/integration-tests/test_vsync_to_client.cpp 2014-11-18 19:29:59 +0000
2046@@ -0,0 +1,225 @@
2047+/*
2048+ * Copyright © 2014 Canonical Ltd.
2049+ *
2050+ * This program is free software: you can redistribute it and/or modify
2051+ * it under the terms of the GNU General Public License version 3 as
2052+ * published by the Free Software Foundation.
2053+ *
2054+ * This program is distributed in the hope that it will be useful,
2055+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2056+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2057+ * GNU General Public License for more details.
2058+ *
2059+ * You should have received a copy of the GNU General Public License
2060+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2061+ *
2062+ * Authored by: Robert Carr <robert.carr@canonical.com>
2063+ */
2064+
2065+#include "mir/frontend/vsync_provider.h"
2066+#include "mir/graphics/display_configuration.h"
2067+#include "mir/input/input_platform.h"
2068+#include "mir/input/input_receiver_thread.h"
2069+
2070+#include "mir_toolkit/mir_client_library.h"
2071+
2072+#include "mir_test/fake_shared.h"
2073+#include "mir_test_framework/in_process_server.h"
2074+#include "mir_test_framework/stubbed_server_configuration.h"
2075+#include "mir_test_framework/stub_client_connection_configuration.h"
2076+#include "mir_test_framework/using_stub_client_platform.h"
2077+
2078+namespace mg = mir::graphics;
2079+namespace mi = mir::input;
2080+namespace mf = mir::frontend;
2081+namespace mircv = mi::receiver;
2082+namespace mt = mir::test;
2083+namespace mtf = mir_test_framework;
2084+
2085+namespace
2086+{
2087+// Client mocks and configuration
2088+struct MockInputReceiverThread : public mircv::InputReceiverThread
2089+{
2090+ MOCK_METHOD1(notify_of_frame_time, void(std::chrono::nanoseconds));
2091+ // Stub of uninteresting methods
2092+ void start() override {}
2093+ void stop() override {}
2094+ void join() override {}
2095+};
2096+
2097+struct MockInputThreadInputPlatform : public mircv::InputPlatform
2098+{
2099+ MockInputThreadInputPlatform(std::shared_ptr<mircv::InputReceiverThread> const& receiver_thread)
2100+ : mock_receiver_thread(receiver_thread)
2101+ {
2102+ }
2103+ std::shared_ptr<mircv::InputReceiverThread> create_input_thread(int,
2104+ std::function<void(MirEvent *)> const&) override
2105+ {
2106+ return mock_receiver_thread;
2107+ }
2108+
2109+ std::shared_ptr<mircv::InputReceiverThread> const mock_receiver_thread;
2110+};
2111+
2112+struct InputMockInjectingClientConnectionConfiguration : public mtf::StubConnectionConfiguration
2113+{
2114+ InputMockInjectingClientConnectionConfiguration(std::string const& socket_file, std::shared_ptr<mircv::InputReceiverThread> const& receiver_thread)
2115+ : StubConnectionConfiguration(socket_file),
2116+ mock_input_platform(std::make_shared<MockInputThreadInputPlatform>(receiver_thread))
2117+ {
2118+ }
2119+
2120+ std::shared_ptr<mircv::InputPlatform> the_input_platform() override
2121+ {
2122+ return input_platform(
2123+ [this]
2124+ {
2125+ return mock_input_platform;
2126+ });
2127+ }
2128+ std::shared_ptr<MockInputThreadInputPlatform> const mock_input_platform;
2129+};
2130+
2131+// Server mocks and configuration
2132+struct StubVsyncProvider : public mf::VsyncProvider
2133+{
2134+ StubVsyncProvider()
2135+ : count(0)
2136+ {
2137+ }
2138+
2139+ std::chrono::nanoseconds last_vsync_for(mg::DisplayConfigurationOutputId) override
2140+ {
2141+ return std::chrono::nanoseconds(count++);
2142+ }
2143+ int count;
2144+};
2145+
2146+struct StubVsyncProviderServerConfiguration : mtf::StubbedServerConfiguration
2147+{
2148+ std::shared_ptr<mf::VsyncProvider>
2149+ the_vsync_provider() override
2150+ {
2151+ return vsync_provider([]()
2152+ {
2153+ return std::make_shared<StubVsyncProvider>();
2154+ });
2155+ }
2156+
2157+ std::shared_ptr<mi::InputManager> the_input_manager()
2158+ {
2159+ return DefaultServerConfiguration::the_input_manager();
2160+ }
2161+ std::shared_ptr<mi::InputSender> the_input_sender()
2162+ {
2163+ return DefaultServerConfiguration::the_input_sender();
2164+ }
2165+ std::shared_ptr<mi::InputDispatcher> the_input_dispatcher()
2166+ {
2167+ return DefaultServerConfiguration::the_input_dispatcher();
2168+ }
2169+};
2170+
2171+
2172+struct VsyncProviderTest : mtf::InProcessServer
2173+{
2174+ StubVsyncProviderServerConfiguration server_configuration;
2175+
2176+ mir::DefaultServerConfiguration& server_config() override { return server_configuration; }
2177+};
2178+
2179+}
2180+
2181+TEST_F(VsyncProviderTest, last_display_time)
2182+{
2183+ using namespace ::testing;
2184+
2185+ mtf::UsingStubClientPlatform using_stub_client_platform;
2186+
2187+ auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
2188+ MirSurfaceParameters const request_params =
2189+ {
2190+ __PRETTY_FUNCTION__,
2191+ 640, 480,
2192+ mir_pixel_format_abgr_8888,
2193+ mir_buffer_usage_hardware,
2194+ mir_display_output_id_invalid
2195+ };
2196+ auto surface = mir_connection_create_surface_sync(connection, &request_params);
2197+ EXPECT_EQ(true, mir_surface_is_valid(surface));
2198+
2199+ // The fake vsync provider on server just increments an integer
2200+ // for each vsync request.
2201+ mir_surface_swap_buffers_sync(surface);
2202+ EXPECT_EQ(1, mir_surface_get_last_display_time(surface));
2203+ mir_surface_swap_buffers_sync(surface);
2204+ EXPECT_EQ(2, mir_surface_get_last_display_time(surface));
2205+ mir_surface_swap_buffers_sync(surface);
2206+ EXPECT_EQ(3, mir_surface_get_last_display_time(surface));
2207+
2208+ mir_surface_release_sync(surface);
2209+ mir_connection_release(connection);
2210+}
2211+
2212+namespace
2213+{
2214+void ignore_event(MirSurface*, MirEvent const*, void*)
2215+{
2216+}
2217+struct StubConfiguration : public InputMockInjectingClientConnectionConfiguration
2218+{
2219+ StubConfiguration(std::string const& socket_file)
2220+ : InputMockInjectingClientConnectionConfiguration(socket_file, mock_input_receiver_thread)
2221+ {
2222+ }
2223+ ~StubConfiguration()
2224+ {
2225+ mock_input_receiver_thread.reset();
2226+ }
2227+
2228+ static std::shared_ptr<MockInputReceiverThread> mock_input_receiver_thread;
2229+};
2230+
2231+std::shared_ptr<MockInputReceiverThread> StubConfiguration::mock_input_receiver_thread;
2232+}
2233+
2234+TEST_F(VsyncProviderTest, client_input_thread_receives_information_from_server_vsync_provider_on_buffer_swap)
2235+{
2236+ using namespace ::testing;
2237+
2238+ StubConfiguration::mock_input_receiver_thread = std::make_shared<MockInputReceiverThread>();
2239+
2240+ mtf::UsingClientPlatform<StubConfiguration> using_stub_client_platform;
2241+ MirEventDelegate delegate{ignore_event, NULL};
2242+
2243+ {
2244+ InSequence seq;
2245+ // The fake vsync provider just uses increments for each vsync request.
2246+ EXPECT_CALL(*StubConfiguration::mock_input_receiver_thread, notify_of_frame_time(std::chrono::nanoseconds(1)));
2247+ EXPECT_CALL(*StubConfiguration::mock_input_receiver_thread, notify_of_frame_time(std::chrono::nanoseconds(2)));
2248+ EXPECT_CALL(*StubConfiguration::mock_input_receiver_thread, notify_of_frame_time(std::chrono::nanoseconds(3)));
2249+ }
2250+
2251+ auto connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
2252+ MirSurfaceParameters const request_params =
2253+ {
2254+ __PRETTY_FUNCTION__,
2255+ 640, 480,
2256+ mir_pixel_format_abgr_8888,
2257+ mir_buffer_usage_hardware,
2258+ mir_display_output_id_invalid
2259+ };
2260+ auto surface = mir_connection_create_surface_sync(connection, &request_params);
2261+
2262+ // Without a handler the client input thread will not be started.
2263+ mir_surface_set_event_handler(surface, &delegate);
2264+
2265+ mir_surface_swap_buffers_sync(surface);
2266+ mir_surface_swap_buffers_sync(surface);
2267+ mir_surface_swap_buffers_sync(surface);
2268+
2269+ mir_surface_release_sync(surface);
2270+ mir_connection_release(connection);
2271+}
2272
2273=== modified file 'tests/mir_test_framework/stubbed_graphics_platform.cpp'
2274--- tests/mir_test_framework/stubbed_graphics_platform.cpp 2014-11-13 16:41:26 +0000
2275+++ tests/mir_test_framework/stubbed_graphics_platform.cpp 2014-11-18 19:29:59 +0000
2276@@ -23,6 +23,7 @@
2277
2278 #include "mir_test_doubles/stub_buffer_allocator.h"
2279 #include "mir_test_doubles/stub_display.h"
2280+#include "mir_test_doubles/stub_vsync_provider.h"
2281
2282 #ifdef ANDROID
2283 #include "mir_test_doubles/stub_android_native_buffer.h"
2284@@ -37,6 +38,7 @@
2285 #include <boost/throw_exception.hpp>
2286
2287 namespace geom = mir::geometry;
2288+namespace mf = mir::frontend;
2289 namespace mg = mir::graphics;
2290 namespace mo = mir::options;
2291 namespace mtd = mir::test::doubles;
2292
2293=== modified file 'tests/unit-tests/client/input/test_android_input_receiver.cpp'
2294--- tests/unit-tests/client/input/test_android_input_receiver.cpp 2014-10-21 16:21:14 +0000
2295+++ tests/unit-tests/client/input/test_android_input_receiver.cpp 2014-11-18 19:29:59 +0000
2296@@ -204,102 +204,6 @@
2297 EXPECT_FALSE(receiver.next_event(std::chrono::milliseconds(1), ev)); // Minimal timeout needed for valgrind
2298 }
2299
2300-TEST_F(AndroidInputReceiverSetup, slow_raw_input_doesnt_cause_frameskipping)
2301-{ // Regression test for LP: #1372300
2302- using namespace testing;
2303- using namespace std::chrono;
2304-
2305- nsecs_t t = 0;
2306-
2307- mircva::InputReceiver receiver(
2308- client_fd, std::make_shared<mircv::NullInputReceiverReport>(),
2309- [&t](int) { return t; }
2310- );
2311- TestingInputProducer producer(server_fd);
2312-
2313- nsecs_t const one_millisecond = 1000000ULL;
2314- nsecs_t const one_second = 1000 * one_millisecond;
2315- nsecs_t const one_frame = one_second / 60;
2316-
2317- MirEvent ev;
2318-
2319- producer.produce_a_motion_event(123, 456, t);
2320- producer.produce_a_key_event();
2321- flush_channels();
2322-
2323- std::chrono::milliseconds const max_timeout(1000);
2324-
2325- // Key events don't get resampled. Will be reported first.
2326- ASSERT_TRUE(receiver.next_event(max_timeout, ev));
2327- ASSERT_EQ(mir_event_type_key, ev.type);
2328-
2329- // The motion is still too new. Won't be reported yet, but is batched.
2330- auto start = high_resolution_clock::now();
2331- ASSERT_FALSE(receiver.next_event(max_timeout, ev));
2332- auto end = high_resolution_clock::now();
2333- auto duration = end - start;
2334-
2335- // Verify we timed out in under a frame (LP: #1372300)
2336- // Sadly using real time as droidinput::Looper doesn't use a mocked clock.
2337- ASSERT_LT(duration_cast<nanoseconds>(duration).count(), one_frame);
2338-
2339- // Verify we don't use all the CPU by not sleeping (LP: #1373809)
2340- EXPECT_GT(duration_cast<nanoseconds>(duration).count(), one_millisecond);
2341-
2342- // But later in a frame or so, the motion will be reported:
2343- t += 2 * one_frame; // Account for the new slower 55Hz event rate
2344- ASSERT_TRUE(receiver.next_event(max_timeout, ev));
2345- ASSERT_EQ(mir_event_type_motion, ev.type);
2346-}
2347-
2348-TEST_F(AndroidInputReceiverSetup, rendering_does_not_lag_behind_input)
2349-{
2350- using namespace testing;
2351-
2352- nsecs_t t = 0;
2353-
2354- mircva::InputReceiver receiver(
2355- client_fd, std::make_shared<mircv::NullInputReceiverReport>(),
2356- [&t](int) { return t; }
2357- );
2358- TestingInputProducer producer(server_fd);
2359-
2360- nsecs_t const one_millisecond = 1000000ULL;
2361- nsecs_t const one_second = 1000 * one_millisecond;
2362- nsecs_t const device_sample_interval = one_second / 250;
2363- nsecs_t const frame_interval = one_second / 60;
2364- nsecs_t const gesture_duration = 1 * one_second;
2365-
2366- nsecs_t last_produced = 0;
2367- int frames_triggered = 0;
2368-
2369- for (t = 0; t < gesture_duration; t += one_millisecond)
2370- {
2371- if (!t || t >= (last_produced + device_sample_interval))
2372- {
2373- last_produced = t;
2374- float a = t * M_PI / 1000000.0f;
2375- float x = 500.0f * sinf(a);
2376- float y = 1000.0f * cosf(a);
2377- producer.produce_a_motion_event(x, y, t);
2378- flush_channels();
2379- }
2380-
2381- MirEvent ev;
2382- if (receiver.next_event(std::chrono::milliseconds(0), ev))
2383- ++frames_triggered;
2384- }
2385-
2386- // If the rendering time resulting from the gesture is longer than the
2387- // gesture itself then that's laggy...
2388- nsecs_t render_duration = frame_interval * frames_triggered;
2389- EXPECT_THAT(render_duration, Le(gesture_duration));
2390-
2391- int average_lag_milliseconds = (render_duration - gesture_duration) /
2392- (frames_triggered * one_millisecond);
2393- EXPECT_THAT(average_lag_milliseconds, Le(1));
2394-}
2395-
2396 TEST_F(AndroidInputReceiverSetup, input_comes_in_phase_with_rendering)
2397 {
2398 using namespace testing;
2399
2400=== modified file 'tests/unit-tests/client/test_client_mir_surface.cpp'
2401--- tests/unit-tests/client/test_client_mir_surface.cpp 2014-10-28 13:59:51 +0000
2402+++ tests/unit-tests/client/test_client_mir_surface.cpp 2014-11-18 19:29:59 +0000
2403@@ -289,6 +289,7 @@
2404 MOCK_METHOD0(start, void());
2405 MOCK_METHOD0(stop, void());
2406 MOCK_METHOD0(join, void());
2407+ MOCK_METHOD1(notify_of_frame_time, void(std::chrono::nanoseconds));
2408 };
2409
2410 class TestConnectionConfiguration : public mcl::DefaultConnectionConfiguration
2411
2412=== modified file 'tests/unit-tests/frontend/test_session_mediator.cpp'
2413--- tests/unit-tests/frontend/test_session_mediator.cpp 2014-11-13 16:41:26 +0000
2414+++ tests/unit-tests/frontend/test_session_mediator.cpp 2014-11-18 19:29:59 +0000
2415@@ -42,6 +42,7 @@
2416 #include "mir_test_doubles/mock_buffer.h"
2417 #include "mir_test_doubles/stub_session.h"
2418 #include "mir_test_doubles/stub_display_configuration.h"
2419+#include "mir_test_doubles/stub_vsync_provider.h"
2420 #include "mir_test_doubles/stub_buffer_allocator.h"
2421 #include "mir_test_doubles/null_screencast.h"
2422 #include "mir_test/display_config_matchers.h"
2423@@ -205,6 +206,39 @@
2424 MOCK_METHOD0(supported_pixel_formats, std::vector<MirPixelFormat>());
2425 };
2426
2427+
2428+class MockPlatform : public mg::Platform
2429+{
2430+ public:
2431+ MockPlatform(std::shared_ptr<mg::PlatformIpcOperations> const& ipc_ops)
2432+ {
2433+ using namespace testing;
2434+ ON_CALL(*this, create_buffer_allocator())
2435+ .WillByDefault(Return(std::shared_ptr<mg::GraphicBufferAllocator>()));
2436+ ON_CALL(*this, create_display(_,_,_))
2437+ .WillByDefault(Return(std::make_shared<mtd::NullDisplay>()));
2438+ ON_CALL(*this, make_vsync_provider())
2439+ .WillByDefault(Return(std::make_shared<mtd::StubVsyncProvider>()));
2440+ ON_CALL(*this, connection_ipc_package())
2441+ .WillByDefault(Return(std::make_shared<mg::PlatformIPCPackage>()));
2442+ ON_CALL(*this, make_ipc_operations())
2443+ .WillByDefault(Return(ipc_ops));
2444+ }
2445+
2446+ MOCK_METHOD0(create_buffer_allocator, std::shared_ptr<mg::GraphicBufferAllocator>());
2447+ MOCK_METHOD3(create_display,
2448+ std::shared_ptr<mg::Display>(
2449+ std::shared_ptr<mg::DisplayConfigurationPolicy> const&,
2450+ std::shared_ptr<mg::GLProgramFactory> const&,
2451+ std::shared_ptr<mg::GLConfig> const&));
2452+ MOCK_METHOD0(connection_ipc_package, std::shared_ptr<mg::PlatformIPCPackage>());
2453+ MOCK_METHOD0(create_internal_client, std::shared_ptr<mg::InternalClient>());
2454+ MOCK_CONST_METHOD0(make_ipc_operations, std::shared_ptr<mg::PlatformIpcOperations>());
2455+ MOCK_CONST_METHOD0(egl_native_display, EGLNativeDisplayType());
2456+ MOCK_METHOD0(make_buffer_writer, std::shared_ptr<mg::BufferWriter>());
2457+ MOCK_METHOD0(make_vsync_provider, std::shared_ptr<mf::VsyncProvider>());
2458+};
2459+
2460 struct StubScreencast : mtd::NullScreencast
2461 {
2462 std::shared_ptr<mg::Buffer> capture(mf::ScreencastSessionId)
2463@@ -230,7 +264,7 @@
2464 shell, mt::fake_shared(mock_ipc_operations), graphics_changer,
2465 surface_pixel_formats, report,
2466 std::make_shared<mtd::NullEventSink>(),
2467- resource_cache, stub_screencast, &connector, nullptr, nullptr}
2468+ resource_cache, stub_screencast, &connector, nullptr, std::make_shared<mtd::StubVsyncProvider>(), nullptr}
2469 {
2470 using namespace ::testing;
2471
2472@@ -286,7 +320,9 @@
2473 shell, mt::fake_shared(mock_ipc_operations), graphics_changer,
2474 surface_pixel_formats, report,
2475 std::make_shared<mtd::NullEventSink>(),
2476- resource_cache, stub_screencast, context, nullptr, nullptr};
2477+ resource_cache, stub_screencast, context, nullptr,
2478+ std::make_shared<mtd::StubVsyncProvider>(), nullptr
2479+ };
2480
2481 EXPECT_THAT(connects_handled_count, Eq(0));
2482
2483@@ -391,7 +427,10 @@
2484 surface_pixel_formats, report,
2485 std::make_shared<mtd::NullEventSink>(),
2486 resource_cache, std::make_shared<mtd::NullScreencast>(),
2487- nullptr, nullptr, nullptr);
2488+ nullptr, nullptr,
2489+ std::make_shared<mtd::StubVsyncProvider>(), nullptr
2490+ );
2491+
2492 mediator.connect(nullptr, &connect_parameters, &connection, null_callback.get());
2493
2494 EXPECT_THAT(connection.display_configuration(), mt::DisplayConfigMatches(std::cref(config)));
2495@@ -593,7 +632,9 @@
2496 surface_pixel_formats, report,
2497 std::make_shared<mtd::NullEventSink>(), resource_cache,
2498 std::make_shared<mtd::NullScreencast>(),
2499- nullptr, nullptr, nullptr};
2500+ nullptr, nullptr,
2501+ std::make_shared<mtd::StubVsyncProvider>(), nullptr
2502+ };
2503
2504 mediator.connect(nullptr, &connect_parameters, &connection, null_callback.get());
2505
2506@@ -846,7 +887,9 @@
2507 shell, mt::fake_shared(mock_ipc_operations), graphics_changer,
2508 surface_pixel_formats, report,
2509 std::make_shared<mtd::NullEventSink>(),
2510- mt::fake_shared(mock_cache), stub_screencast, &connector, nullptr, nullptr};
2511+ mt::fake_shared(mock_cache), stub_screencast, nullptr, nullptr,
2512+ std::make_shared<mtd::StubVsyncProvider>(), nullptr
2513+ };
2514
2515 mediator.connect(nullptr, &connect_parameters, &connection, null_callback.get());
2516 mediator.create_surface(nullptr, &surface_parameters, &surface_response, null_callback.get());
2517
2518=== modified file 'tests/unit-tests/graphics/android/CMakeLists.txt'
2519--- tests/unit-tests/graphics/android/CMakeLists.txt 2014-10-29 18:44:15 +0000
2520+++ tests/unit-tests/graphics/android/CMakeLists.txt 2014-11-18 19:29:59 +0000
2521@@ -29,6 +29,7 @@
2522 ${CMAKE_CURRENT_SOURCE_DIR}/test_device_detection.cpp
2523 ${CMAKE_CURRENT_SOURCE_DIR}/test_hwc_wrapper.cpp
2524 ${CMAKE_CURRENT_SOURCE_DIR}/test_hwc_fallback_gl_renderer.cpp
2525+ ${CMAKE_CURRENT_SOURCE_DIR}/test_hwc_vsync.cpp
2526 $<TARGET_OBJECTS:mirplatformgraphicsandroidobjects>
2527 )
2528
2529
2530=== modified file 'tests/unit-tests/graphics/android/test_hwc_common_device.cpp'
2531--- tests/unit-tests/graphics/android/test_hwc_common_device.cpp 2014-10-01 06:25:56 +0000
2532+++ tests/unit-tests/graphics/android/test_hwc_common_device.cpp 2014-11-18 19:29:59 +0000
2533@@ -195,14 +195,16 @@
2534 .WillOnce(SaveArg<0>(&callbacks));
2535
2536 auto device = make_hwc_device<TypeParam>(this->mock_device, this->mock_fbdev, this->mock_vsync);
2537+
2538+ int64_t const fake_vsync_timestamp = 17;
2539
2540- EXPECT_CALL(*this->mock_vsync, notify_vsync())
2541+ EXPECT_CALL(*this->mock_vsync, notify_vsync(std::chrono::nanoseconds(fake_vsync_timestamp)))
2542 .Times(1);
2543 ASSERT_THAT(callbacks, Ne(nullptr));
2544- callbacks->hooks.vsync(&callbacks->hooks, 0, 0);
2545+ callbacks->hooks.vsync(&callbacks->hooks, 0, fake_vsync_timestamp);
2546
2547 callbacks->self = nullptr;
2548- callbacks->hooks.vsync(&callbacks->hooks, 0, 0);
2549+ callbacks->hooks.vsync(&callbacks->hooks, 0, fake_vsync_timestamp);
2550 }
2551
2552 TYPED_TEST(HWCCommon, set_orientation)
2553
2554=== added file 'tests/unit-tests/graphics/android/test_hwc_vsync.cpp'
2555--- tests/unit-tests/graphics/android/test_hwc_vsync.cpp 1970-01-01 00:00:00 +0000
2556+++ tests/unit-tests/graphics/android/test_hwc_vsync.cpp 2014-11-18 19:29:59 +0000
2557@@ -0,0 +1,68 @@
2558+/*
2559+ * Copyright © 2014 Canonical Ltd.
2560+ *
2561+ * This program is free software: you can redistribute it and/or modify
2562+ * it under the terms of the GNU General Public License version 3 as
2563+ * published by the Free Software Foundation.
2564+ *
2565+ * This program is distributed in the hope that it will be useful,
2566+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2567+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2568+ * GNU General Public License for more details.
2569+ *
2570+ * You should have received a copy of the GNU General Public License
2571+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2572+ *
2573+ * Authored by: Robert Carr <robert.carr@canonical.com>
2574+ */
2575+
2576+#include "src/platform/graphics/android/hwc_vsync.h"
2577+
2578+#include "mir/graphics/display_configuration.h"
2579+
2580+#include <stdexcept>
2581+
2582+#include <gtest/gtest.h>
2583+#include <gmock/gmock.h>
2584+
2585+namespace mg = mir::graphics;
2586+namespace mga = mg::android;
2587+
2588+namespace
2589+{
2590+struct HWCVsyncTest : public testing::Test
2591+{
2592+ mga::HWCVsync syncer;
2593+
2594+ mg::DisplayConfigurationOutputId const output_id{0};
2595+ mg::DisplayConfigurationOutputId const invalid_output_id{1};
2596+};
2597+}
2598+
2599+TEST_F(HWCVsyncTest, initially_last_vsync_is_zero)
2600+{
2601+ EXPECT_EQ(std::chrono::nanoseconds::zero(), syncer.last_vsync_for(output_id));
2602+}
2603+
2604+// No multimonitor support on android drivers yet so non zero output ID is invalid.
2605+TEST_F(HWCVsyncTest, throws_exception_on_non_zero_output_id)
2606+{
2607+ EXPECT_THROW({
2608+ syncer.last_vsync_for(invalid_output_id);
2609+ }, std::runtime_error);
2610+}
2611+
2612+TEST_F(HWCVsyncTest, takes_time_from_last_vsync_notification)
2613+{
2614+ std::chrono::nanoseconds first_time{1}, second_time{2};
2615+
2616+ EXPECT_EQ(std::chrono::nanoseconds::zero(), syncer.last_vsync_for(output_id));
2617+
2618+ syncer.notify_vsync(first_time);
2619+ EXPECT_EQ(first_time, syncer.last_vsync_for(output_id));
2620+ EXPECT_EQ(first_time, syncer.last_vsync_for(output_id));
2621+
2622+ syncer.notify_vsync(second_time);
2623+ EXPECT_EQ(second_time, syncer.last_vsync_for(output_id));
2624+ EXPECT_EQ(second_time, syncer.last_vsync_for(output_id));
2625+}
2626
2627=== modified file 'tests/unit-tests/graphics/android/test_output_builder.cpp'
2628--- tests/unit-tests/graphics/android/test_output_builder.cpp 2014-10-27 13:06:48 +0000
2629+++ tests/unit-tests/graphics/android/test_output_builder.cpp 2014-11-18 19:29:59 +0000
2630@@ -68,6 +68,7 @@
2631 ON_CALL(*this, create_fb_device(_)).WillByDefault(Return(nullptr));
2632 ON_CALL(*this, create_hwc_device(_)).WillByDefault(Return(nullptr));
2633 ON_CALL(*this, create_hwc_fb_device(_,_)).WillByDefault(Return(nullptr));
2634+ ON_CALL(*this, create_vsync_coordinator()).WillByDefault(Return(nullptr));
2635 }
2636
2637 MOCK_CONST_METHOD0(create_hwc_native_device, std::shared_ptr<hwc_composer_device_1>());
2638@@ -83,6 +84,7 @@
2639 MOCK_CONST_METHOD2(create_hwc_fb_device,
2640 std::shared_ptr<mga::DisplayDevice>(
2641 std::shared_ptr<mga::HwcWrapper> const&, std::shared_ptr<framebuffer_device_t> const&));
2642+ MOCK_CONST_METHOD0(create_vsync_coordinator, std::shared_ptr<mga::HWCVsyncCoordinator>());
2643 };
2644
2645 class OutputBuilder : public ::testing::Test
2646
2647=== modified file 'tests/unit-tests/graphics/android/test_resource_factory.cpp'
2648--- tests/unit-tests/graphics/android/test_resource_factory.cpp 2014-10-01 06:25:56 +0000
2649+++ tests/unit-tests/graphics/android/test_resource_factory.cpp 2014-11-18 19:29:59 +0000
2650@@ -19,13 +19,16 @@
2651 #include "src/platform/graphics/android/resource_factory.h"
2652 #include "mir_test_doubles/mock_android_hw.h"
2653
2654+#include "mir_test/fake_shared.h"
2655+
2656 #include <stdexcept>
2657 #include <gmock/gmock.h>
2658 #include <gtest/gtest.h>
2659
2660-namespace mg=mir::graphics;
2661-namespace mga=mir::graphics::android;
2662-namespace mtd=mir::test::doubles;
2663+namespace mg = mir::graphics;
2664+namespace mga = mir::graphics::android;
2665+namespace mt = mir::test;
2666+namespace mtd = mt::doubles;
2667
2668 struct ResourceFactoryTest : public ::testing::Test
2669 {
2670
2671=== modified file 'tests/unit-tests/graphics/nested/test_nested_display.cpp'
2672--- tests/unit-tests/graphics/nested/test_nested_display.cpp 2014-10-01 06:25:56 +0000
2673+++ tests/unit-tests/graphics/nested/test_nested_display.cpp 2014-11-18 19:29:59 +0000
2674@@ -18,6 +18,7 @@
2675
2676 #include "src/server/graphics/nested/nested_display.h"
2677 #include "src/server/graphics/nested/host_connection.h"
2678+#include "src/server/graphics/nested/nested_vsync_provider.h"
2679 #include "src/server/report/null/display_report.h"
2680 #include "src/server/graphics/default_display_configuration_policy.h"
2681 #include "src/server/input/null_input_dispatcher.h"
2682
2683=== modified file 'tests/unit-tests/graphics/nested/test_nested_display_buffer.cpp'
2684--- tests/unit-tests/graphics/nested/test_nested_display_buffer.cpp 2014-06-04 22:09:06 +0000
2685+++ tests/unit-tests/graphics/nested/test_nested_display_buffer.cpp 2014-11-18 19:29:59 +0000
2686@@ -19,6 +19,7 @@
2687
2688 #include "src/server/graphics/nested/nested_output.h"
2689 #include "src/server/graphics/nested/host_connection.h"
2690+#include "src/server/graphics/nested/nested_vsync_provider.h"
2691 #include "src/server/input/null_input_dispatcher.h"
2692
2693 #include "mir_test_doubles/mock_egl.h"
2694@@ -29,8 +30,9 @@
2695 #include <gmock/gmock.h>
2696
2697 namespace geom = mir::geometry;
2698-namespace mgn = mir::graphics::nested;
2699-namespace mgnd = mir::graphics::nested::detail;
2700+namespace mg = mir::graphics;
2701+namespace mgn = mg::nested;
2702+namespace mgnd = mgn::detail;
2703 namespace mi = mir::input;
2704 namespace mt = mir::test;
2705 namespace mtd = mir::test::doubles;
2706@@ -40,6 +42,7 @@
2707 public:
2708 EGLNativeWindowType egl_native_window() override { return {}; }
2709 void set_event_handler(MirEventDelegate const*) override {}
2710+ std::chrono::nanoseconds last_display_time() override { return std::chrono::nanoseconds::min(); }
2711 };
2712
2713 struct NestedDisplayBufferTest : testing::Test
2714@@ -55,6 +58,8 @@
2715 mi::NullInputDispatcher null_input_dispatcher;
2716 mgnd::EGLDisplayHandle egl_disp_handle;
2717 geom::Rectangle const default_rect;
2718+ mgn::VsyncProvider vsync_provider;
2719+ mg::DisplayConfigurationOutputId id;
2720 };
2721
2722 TEST_F(NestedDisplayBufferTest, alpha_enabled_pixel_format_enables_destination_alpha)
2723@@ -64,7 +69,9 @@
2724 mt::fake_shared(null_host_surface),
2725 default_rect,
2726 mt::fake_shared(null_input_dispatcher),
2727- mir_pixel_format_abgr_8888};
2728+ mir_pixel_format_abgr_8888,
2729+ mt::fake_shared(vsync_provider),
2730+ id};
2731
2732 EXPECT_TRUE(db.uses_alpha());
2733 }
2734@@ -76,7 +83,9 @@
2735 mt::fake_shared(null_host_surface),
2736 default_rect,
2737 mt::fake_shared(null_input_dispatcher),
2738- mir_pixel_format_xbgr_8888};
2739+ mir_pixel_format_xbgr_8888,
2740+ mt::fake_shared(vsync_provider),
2741+ id};
2742
2743 EXPECT_FALSE(db.uses_alpha());
2744 }

Subscribers

People subscribed via source and target branches