Merge lp:~mir-team/mir/vsync-timings-from-server into lp:mir
- vsync-timings-from-server
- Merge into development-branch
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 |
Related bugs: |
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.
- 2024. By Robert Carr
-
Cleanup
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:/
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Robert Carr (robertcarr) wrote : | # |
When testing you may notice that shell elements, i.e. indicator bar seem more responsive than client elements.
I believe
https:/
presents some improvement though
- 2025. By Robert Carr
-
Update ABI sha1sums
- 2026. By Robert Carr
-
Fix lgpl license on vsync provideR
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2024
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2026
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
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.
Daniel van Vugt (vanvugt) wrote : | # |
Perhaps just a rename "VsyncSource". *shrug*
- 2027. By Robert Carr
-
Merge lp:mir
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-
2488 -TEST_F(
2536 -TEST_F(
Daniel van Vugt (vanvugt) wrote : | # |
(3) Spurious line appears in a few files:
+e1be9faee8b844
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2027
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 2028. By Robert Carr
-
Fix swap files in sha1sums
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2028
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 2029. By Robert Carr
-
Remove backup file from sha1sums
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2029
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
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-
2488 -TEST_F(
2536 -TEST_F(
(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.
Daniel van Vugt (vanvugt) wrote : | # |
(5) This looks like a bug and will cause resampling/
480 + has_new_frame_time = false;
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).
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2029
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 2030. By Robert Carr
-
Merge lp:mir
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2030
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 2031. By Robert Carr
-
Forjenkins
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2031
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 2032. By Robert Carr
-
Jenkins
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:2032
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alan Griffiths (alan-griffiths) wrote : | # |
CI failures logged as lp:1391488 (new) and lp:1391261 (confirmed)
Alan Griffiths (alan-griffiths) wrote : | # |
71 + last_sync = std::chrono:
72 + vsync_provider.
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.
Kevin DuBois (kdub) wrote : | # |
First pass:
Could VsyncProvider be in mir::graphics instead of mir::frontend?
new whitespace
324 +
int64_t mir_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:
and
204 + virtual std::shared_
and
184 + virtual std::shared_
Seems like a lot of rigging where we could just have
mg::Display:
and the server code could just use the existing the_display() function.
Kevin DuBois (kdub) wrote : | # |
int64_t mir_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(
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)
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)
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.
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.
Alberto Aguirre (albaguirre) wrote : | # |
Text conflict in src/client/
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.
Alberto Aguirre (albaguirre) wrote : | # |
These are some videos I took.
I don't notice any significant difference
Vivid #19 in mako:
https:/
Vivid #19 in mako + this branch:
https:/
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.
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.
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.
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:/
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_
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?
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:/
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
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2033
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 2034. By Robert Carr
-
Update sha1sums
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2034
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
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.
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
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:2035
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
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
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 | } |
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.