Merge lp:~vanvugt/mir/physical-frame into lp:mir
- physical-frame
- Merge into development-branch
Status: | Merged |
---|---|
Approved by: | Daniel van Vugt |
Approved revision: | no longer in the source branch. |
Merged at revision: | 3748 |
Proposed branch: | lp:~vanvugt/mir/physical-frame |
Merge into: | lp:mir |
Diff against target: |
1934 lines (+617/-124) 64 files modified
include/common/mir/time/posix_timestamp.h (+59/-0) include/platform/mir/graphics/atomic_frame.h (+43/-0) include/platform/mir/graphics/display.h (+17/-0) include/platform/mir/graphics/frame.h (+47/-0) include/test/mir/test/doubles/mock_egl.h (+4/-0) include/test/mir/test/doubles/null_display.h (+4/-0) src/include/platform/mir/graphics/display_report.h (+2/-1) src/platform/graphics/CMakeLists.txt (+1/-0) src/platform/graphics/atomic_frame.cpp (+50/-0) src/platform/symbols.map (+4/-0) src/platforms/android/server/device_quirks.cpp (+1/-1) src/platforms/android/server/display.cpp (+30/-4) src/platforms/android/server/display.h (+9/-1) src/platforms/android/server/fb_device.cpp (+1/-1) src/platforms/android/server/fb_device.h (+1/-1) src/platforms/android/server/hwc_blanking_control.cpp (+4/-4) src/platforms/android/server/hwc_configuration.h (+4/-3) src/platforms/android/server/hwc_fb_device.cpp (+1/-1) src/platforms/android/server/hwc_fb_device.h (+2/-1) src/platforms/android/server/hwc_wrapper.h (+2/-2) src/platforms/android/server/real_hwc_wrapper.cpp (+11/-3) src/platforms/android/server/real_hwc_wrapper.h (+3/-3) src/platforms/android/utils/render_overlays.cpp (+1/-1) src/platforms/eglstream-kms/server/display.cpp (+9/-0) src/platforms/eglstream-kms/server/display.h (+1/-0) src/platforms/mesa/server/kms/display.cpp (+6/-0) src/platforms/mesa/server/kms/display.h (+3/-1) src/platforms/mesa/server/kms/kms_output.h (+2/-0) src/platforms/mesa/server/kms/kms_page_flipper.cpp (+21/-7) src/platforms/mesa/server/kms/kms_page_flipper.h (+5/-3) src/platforms/mesa/server/kms/page_flipper.h (+2/-1) src/platforms/mesa/server/kms/real_kms_output.cpp (+7/-1) src/platforms/mesa/server/kms/real_kms_output.h (+5/-0) src/platforms/mesa/server/x11/graphics/display.cpp (+9/-1) src/platforms/mesa/server/x11/graphics/display.h (+6/-0) src/platforms/mesa/server/x11/graphics/display_buffer.cpp (+63/-2) src/platforms/mesa/server/x11/graphics/display_buffer.h (+8/-0) src/platforms/mesa/server/x11/graphics/egl_helper.h (+1/-0) src/server/graphics/nested/display.cpp (+5/-0) src/server/graphics/nested/display.h (+1/-0) src/server/report/logging/display_report.cpp (+29/-20) src/server/report/logging/display_report.h (+5/-7) src/server/report/logging/logging_report_factory.cpp (+1/-1) src/server/report/lttng/display_report.cpp (+2/-1) src/server/report/lttng/display_report.h (+1/-1) src/server/report/null/display_report.cpp (+1/-1) src/server/report/null/display_report.h (+1/-1) tests/include/mir/test/doubles/mock_display.h (+1/-0) tests/include/mir/test/doubles/mock_display_report.h (+2/-2) tests/include/mir/test/doubles/mock_hwc_device_wrapper.h (+1/-1) tests/include/mir/test/doubles/stub_display_builder.h (+5/-2) tests/mir_test_doubles/mock_egl.cpp (+14/-0) tests/mir_test_framework/stubbed_graphics_platform.cpp (+4/-1) tests/unit-tests/logging/test_display_report.cpp (+61/-20) tests/unit-tests/platforms/android/server/test_display.cpp (+3/-3) tests/unit-tests/platforms/android/server/test_display_hotplug.cpp (+2/-2) tests/unit-tests/platforms/android/server/test_hwc_configuration.cpp (+8/-6) tests/unit-tests/platforms/android/server/test_hwc_fb_device.cpp (+2/-2) tests/unit-tests/platforms/android/server/test_hwc_wrapper.cpp (+3/-2) tests/unit-tests/platforms/mesa/kms/mock_kms_output.h (+2/-0) tests/unit-tests/platforms/mesa/kms/test_display.cpp (+4/-5) tests/unit-tests/platforms/mesa/kms/test_kms_page_flipper.cpp (+1/-1) tests/unit-tests/platforms/mesa/kms/test_real_kms_output.cpp (+6/-2) tests/unit-tests/platforms/mesa/x11/test_display.cpp (+3/-0) |
To merge this branch: | bzr merge lp:~vanvugt/mir/physical-frame |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Cemil Azizoglu (community) | Approve | ||
Mir CI Bot | continuous-integration | Approve | |
Chris Halse Rogers | Needs Fixing | ||
Review via email: mp+306199@code.launchpad.net |
Commit message
Introducing backend plumbing for getting high precision frame timing.
Presently this is only complete for the android, kms and x11 graphics
platforms. Nested and eglstream will come later.
Description of the change
This is mostly just interface changes required to pass around timing
information so all the testing emphasis is on enhancing the display
report right now. I plan on automating that (as a
performance/
consistency but (a) that's not written yet, (b) this branch is already
too big and (c) that requires a real graphics head [since it's actually more about testing the graphics driver than Mir] so where to put
that test may become contentious. For the moment, just use
--display-
timing data.
Mir CI Bot (mir-ci-bot) wrote : | # |
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:3640
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:3641
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Chris Halse Rogers (raof) wrote : | # |
Hm. Do we actually need Display:
The platforms already call display_
Looking at GLX_OML_SYNC, we probably don't need an SBC-analogue in mg::Frame.
+ // long long to match printf format on all architectures
+ const long long msc = frame.msc,
You might be looking for the “PRIix” series of macros; in this case, PRIi64.
so that would be:
+ "vsync on %u: #" PRIi64 ", " PRIi64 ".%03" PRIi64 " ms %s, ...
It's a minor nit; long long is apparently guaranteed to be at least 64bits on any standard-compliant C++ compiler.
Otherwise looks good.
Chris Halse Rogers (raof) wrote : | # |
Oh, also:
+ auto extensions = eglQueryString(
+ eglGetSyncValues =
+ reinterpret_
+ strstr(extensions, "EGL_CHROMIUM_
+ eglGetProcAddre
+ );
is (probably not importantly) wrong (you can't naively use strstr to search through the extension string, because of substring matches).
We've already got a dependency on epoxy - why not use epoxy_has_
Daniel van Vugt (vanvugt) wrote : | # |
Excellent question. Yes we will need Display:
And yes I did think of PRIi64 too. However it is a bit ugly and has the additional disadvantage that the reporting code then has implied knowledge of the data type used in a distant header. This way using long long conversion that's not required, and is nicer to read.
Chris Halse Rogers (raof) wrote : | # |
So, the first point - provide on client request only - can be more easily handled further up the stack.
The second point - that there might be some future Display that can't provide vsync events information but *can* tell you frame timing - is already going to have a bad time in Mir. If we can't detect frames our compositor is going to spin at 100%, and if we provide a synthetic vsync then... we've got vsync events ☺.
Daniel van Vugt (vanvugt) wrote : | # |
OK, if it proves convenient and if we change DisplayReport to DisplayObserver then we could possibly use that. But it's easy to remove/replace and I would rather keep it until such time as that's proven to be equally convenient.
I also just remembered last_frame_on existed long before I started using DisplayReport here. And also long before the Report/Observer discussion. So it wasn't an option at the time.
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:3643
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:3644
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Daniel van Vugt (vanvugt) wrote : | # |
Also strstr is OK because as a prefix "EGL_CHROMIUM_
Chris Halse Rogers (raof) wrote : | # |
On Fri, Sep 23, 2016 at 12:51 PM, Daniel van Vugt
<email address hidden> wrote:
> Also strstr is OK because as a prefix "EGL_CHROMIUM_
> adequately unique.
At the moment, until someone introduces
EGL_CHROMIUM_
Chris Halse Rogers (raof) wrote : | # |
So, I'm a weak needs-fixing; I'd prefer Display:
If others are OK with this as-is I'm happy to be overruled on this.
Daniel van Vugt (vanvugt) wrote : | # |
Removing last_frame_on is definitely an option in future. But not an option right now because a nice alternative does not exist yet (morphing DisplayReport into DisplayObserver). And even if it did exist, I wouldn't remove the dead code until it was proven the next step (IPC) could use the alternative successfully.
Daniel van Vugt (vanvugt) wrote : | # |
It's worth noting that an event-driven solution all the way through is not what we want. Clients shouldn't be woken up on every frame -- they will only get timing information on demand and then sleep properly when idle. So the current design is based on that. It's possible even after the observer work is done this branch won't need changing.
Daniel van Vugt (vanvugt) wrote : | # |
Work in progress again.
Although I've resolved the conflicts, Cemil's recent rewrite of mesa-x11 has made this (just the Chromium extension) stop working.
Daniel van Vugt (vanvugt) wrote : | # |
All fixed.
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:3654
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Cemil Azizoglu (cemil-azizoglu) wrote : | # |
Looks good, we could also make the frequency at which frame data is obtained configurable. But I'm fine with this too.
Daniel van Vugt (vanvugt) wrote : | # |
I don't think that makes any sense. I think there is really only one answer...
The client will simply request information about the last frame from the server. So the server needs to know about every frame. But the client doesn't need to know unless it keeps asking (continuous rendering).
It's important to not deliver events or such to clients when they should be completely sleeping. But we also don't need to make it another on-demand RPC round trip either. One compromise might be to include the frame information in future buffer return messages. Because that's the only time the client will need fresh timing information. That way the client gets the information it needs without any extra roundtrips or wakeups.
Preview Diff
1 | === added file 'include/common/mir/time/posix_timestamp.h' |
2 | --- include/common/mir/time/posix_timestamp.h 1970-01-01 00:00:00 +0000 |
3 | +++ include/common/mir/time/posix_timestamp.h 2016-10-05 09:20:48 +0000 |
4 | @@ -0,0 +1,59 @@ |
5 | +/* |
6 | + * Copyright © 2016 Canonical Ltd. |
7 | + * |
8 | + * This program is free software: you can redistribute it and/or modify it |
9 | + * under the terms of the GNU Lesser General Public License version 3, |
10 | + * as published by the Free Software Foundation. |
11 | + * |
12 | + * This program is distributed in the hope that it will be useful, |
13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | + * GNU Lesser General Public License for more details. |
16 | + * |
17 | + * You should have received a copy of the GNU Lesser General Public License |
18 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | + * |
20 | + * Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com> |
21 | + */ |
22 | + |
23 | +#ifndef MIR_TIME_POSIX_TIMESTAMP_H_ |
24 | +#define MIR_TIME_POSIX_TIMESTAMP_H_ |
25 | + |
26 | +#include <chrono> |
27 | +#include <ctime> |
28 | + |
29 | +namespace mir { namespace time { |
30 | + |
31 | +/* |
32 | + * We need absolute precision here so sadly can't use high-level C++ clocks... |
33 | + * - Graphics frame timing needs support for at least the kernel clocks |
34 | + * CLOCK_REALTIME and CLOCK_MONOTONIC, to be selected at runtime, whereas |
35 | + * std::chrono does not support CLOCK_REALTIME or easily switching clocks. |
36 | + * - mir::time::Timestamp is relative to the (wrong) epoch of steady_clock, |
37 | + * so converting to/from mir::time::Timestamp would be dangerously |
38 | + * inaccurate at best. |
39 | + */ |
40 | + |
41 | +struct PosixTimestamp |
42 | +{ |
43 | + clockid_t clock_id; |
44 | + std::chrono::nanoseconds nanoseconds; |
45 | + |
46 | + PosixTimestamp() |
47 | + : clock_id{CLOCK_MONOTONIC}, nanoseconds{0} {} |
48 | + PosixTimestamp(clockid_t clk, std::chrono::nanoseconds ns) |
49 | + : clock_id{clk}, nanoseconds{ns} {} |
50 | + PosixTimestamp(clockid_t clk, struct timespec const& ts) |
51 | + : clock_id{clk}, nanoseconds{ts.tv_sec*1000000000LL + ts.tv_nsec} {} |
52 | + |
53 | + static PosixTimestamp now(clockid_t clock_id) |
54 | + { |
55 | + struct timespec ts; |
56 | + clock_gettime(clock_id, &ts); |
57 | + return PosixTimestamp(clock_id, ts); |
58 | + } |
59 | +}; |
60 | + |
61 | +}} // namespace mir::time |
62 | + |
63 | +#endif // MIR_TIME_POSIX_TIMESTAMP_H_ |
64 | |
65 | === added file 'include/platform/mir/graphics/atomic_frame.h' |
66 | --- include/platform/mir/graphics/atomic_frame.h 1970-01-01 00:00:00 +0000 |
67 | +++ include/platform/mir/graphics/atomic_frame.h 2016-10-05 09:20:48 +0000 |
68 | @@ -0,0 +1,43 @@ |
69 | +/* |
70 | + * Copyright © 2016 Canonical Ltd. |
71 | + * |
72 | + * This program is free software: you can redistribute it and/or modify it |
73 | + * under the terms of the GNU Lesser General Public License version 3, |
74 | + * as published by the Free Software Foundation. |
75 | + * |
76 | + * This program is distributed in the hope that it will be useful, |
77 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
78 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
79 | + * GNU Lesser General Public License for more details. |
80 | + * |
81 | + * You should have received a copy of the GNU Lesser General Public License |
82 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
83 | + * |
84 | + * Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com> |
85 | + */ |
86 | + |
87 | +#ifndef MIR_GRAPHICS_ATOMIC_FRAME_H_ |
88 | +#define MIR_GRAPHICS_ATOMIC_FRAME_H_ |
89 | + |
90 | +#include "mir/graphics/frame.h" |
91 | +#include <mutex> |
92 | + |
93 | +namespace mir { namespace graphics { |
94 | + |
95 | +class AtomicFrame |
96 | +{ |
97 | +public: |
98 | + Frame load() const; |
99 | + // Preferably use this and provide all fields from the driver: |
100 | + void store(Frame const&); |
101 | + // Or if your driver is limited these will suffice: |
102 | + void increment_now(); |
103 | + void increment_with_timestamp(Frame::Timestamp t); |
104 | +private: |
105 | + mutable std::mutex mutex; |
106 | + Frame frame; |
107 | +}; |
108 | + |
109 | +}} // namespace mir::graphics |
110 | + |
111 | +#endif // MIR_GRAPHICS_ATOMIC_FRAME_H_ |
112 | |
113 | === modified file 'include/platform/mir/graphics/display.h' |
114 | --- include/platform/mir/graphics/display.h 2016-09-15 00:57:29 +0000 |
115 | +++ include/platform/mir/graphics/display.h 2016-10-05 09:20:48 +0000 |
116 | @@ -19,6 +19,7 @@ |
117 | #ifndef MIR_GRAPHICS_DISPLAY_H_ |
118 | #define MIR_GRAPHICS_DISPLAY_H_ |
119 | |
120 | +#include "mir/graphics/frame.h" |
121 | #include <memory> |
122 | #include <functional> |
123 | #include <chrono> |
124 | @@ -188,6 +189,22 @@ |
125 | */ |
126 | virtual NativeDisplay* native_display() = 0; |
127 | |
128 | + /** |
129 | + * Returns timing information for the last frame displayed on a given |
130 | + * output. |
131 | + * |
132 | + * Frame timing will be provided to clients only when they request it. |
133 | + * This is to ensure idle clients never get woken by unwanted events. |
134 | + * It is also distinctly separate from the display configuration as this |
135 | + * timing information changes many times per second and should not interfere |
136 | + * with the more static display configuration. |
137 | + * |
138 | + * Note: Using unsigned here because DisplayConfigurationOutputId is |
139 | + * troublesome (can't be forward declared) and including |
140 | + * display_configuration.h to get it would be an overkill. |
141 | + */ |
142 | + virtual Frame last_frame_on(unsigned output_id) const = 0; |
143 | + |
144 | Display() = default; |
145 | virtual ~Display() = default; |
146 | private: |
147 | |
148 | === added file 'include/platform/mir/graphics/frame.h' |
149 | --- include/platform/mir/graphics/frame.h 1970-01-01 00:00:00 +0000 |
150 | +++ include/platform/mir/graphics/frame.h 2016-10-05 09:20:48 +0000 |
151 | @@ -0,0 +1,47 @@ |
152 | +/* |
153 | + * Copyright © 2016 Canonical Ltd. |
154 | + * |
155 | + * This program is free software: you can redistribute it and/or modify it |
156 | + * under the terms of the GNU Lesser General Public License version 3, |
157 | + * as published by the Free Software Foundation. |
158 | + * |
159 | + * This program is distributed in the hope that it will be useful, |
160 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
161 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
162 | + * GNU Lesser General Public License for more details. |
163 | + * |
164 | + * You should have received a copy of the GNU Lesser General Public License |
165 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
166 | + * |
167 | + * Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com> |
168 | + */ |
169 | + |
170 | +#ifndef MIR_GRAPHICS_FRAME_H_ |
171 | +#define MIR_GRAPHICS_FRAME_H_ |
172 | + |
173 | +#include "mir/time/posix_timestamp.h" |
174 | +#include <cstdint> |
175 | + |
176 | +namespace mir { namespace graphics { |
177 | + |
178 | +/** |
179 | + * Frame is a unique identifier for a frame displayed on an output. |
180 | + * |
181 | + * This MSC/UST terminology is used because that's what the rest of the |
182 | + * industry calls it: |
183 | + * GLX: https://www.opengl.org/registry/specs/OML/glx_sync_control.txt |
184 | + * WGL: https://www.opengl.org/registry/specs/OML/wgl_sync_control.txt |
185 | + * EGL: https://bugs.chromium.org/p/chromium/issues/attachmentText?aid=178027 |
186 | + * Mesa: "get_sync_values" functions |
187 | + */ |
188 | +struct Frame |
189 | +{ |
190 | + typedef mir::time::PosixTimestamp Timestamp; |
191 | + |
192 | + int64_t msc = 0; /**< Media Stream Counter */ |
193 | + Timestamp ust; /**< Unadjusted System Time */ |
194 | +}; |
195 | + |
196 | +}} // namespace mir::graphics |
197 | + |
198 | +#endif // MIR_GRAPHICS_FRAME_H_ |
199 | |
200 | === modified file 'include/test/mir/test/doubles/mock_egl.h' |
201 | --- include/test/mir/test/doubles/mock_egl.h 2016-07-15 09:37:28 +0000 |
202 | +++ include/test/mir/test/doubles/mock_egl.h 2016-10-05 09:20:48 +0000 |
203 | @@ -154,6 +154,10 @@ |
204 | MOCK_METHOD2(eglDestroySyncKHR, EGLBoolean(EGLDisplay, EGLSyncKHR)); |
205 | MOCK_METHOD4(eglClientWaitSyncKHR, EGLint(EGLDisplay, EGLSyncKHR, EGLint, EGLTimeKHR)); |
206 | |
207 | + MOCK_METHOD5(eglGetSyncValuesCHROMIUM, EGLBoolean(EGLDisplay, EGLSurface, |
208 | + int64_t*, int64_t*, |
209 | + int64_t*)); |
210 | + |
211 | EGLDisplay const fake_egl_display; |
212 | EGLConfig const* const fake_configs; |
213 | EGLint const fake_configs_num; |
214 | |
215 | === modified file 'include/test/mir/test/doubles/null_display.h' |
216 | --- include/test/mir/test/doubles/null_display.h 2016-09-15 00:57:28 +0000 |
217 | +++ include/test/mir/test/doubles/null_display.h 2016-10-05 09:20:48 +0000 |
218 | @@ -82,6 +82,10 @@ |
219 | { |
220 | return std::unique_ptr<NullGLContext>{new NullGLContext()}; |
221 | } |
222 | + graphics::Frame last_frame_on(unsigned) const override |
223 | + { |
224 | + return {}; |
225 | + } |
226 | NullDisplaySyncGroup group; |
227 | }; |
228 | |
229 | |
230 | === modified file 'src/include/platform/mir/graphics/display_report.h' |
231 | --- src/include/platform/mir/graphics/display_report.h 2016-09-09 07:10:01 +0000 |
232 | +++ src/include/platform/mir/graphics/display_report.h 2016-10-05 09:20:48 +0000 |
233 | @@ -25,6 +25,7 @@ |
234 | { |
235 | namespace graphics |
236 | { |
237 | +struct Frame; |
238 | |
239 | class DisplayReport |
240 | { |
241 | @@ -35,7 +36,7 @@ |
242 | virtual void report_successful_egl_buffer_swap_on_construction() = 0; |
243 | virtual void report_successful_display_construction() = 0; |
244 | virtual void report_egl_configuration(EGLDisplay disp, EGLConfig cfg) = 0; |
245 | - virtual void report_vsync(unsigned int output_id) = 0; |
246 | + virtual void report_vsync(unsigned int output_id, Frame const& f) = 0; |
247 | |
248 | /* gbm specific */ |
249 | virtual void report_successful_drm_mode_set_crtc_on_construction() = 0; |
250 | |
251 | === modified file 'src/platform/graphics/CMakeLists.txt' |
252 | --- src/platform/graphics/CMakeLists.txt 2016-09-01 17:02:56 +0000 |
253 | +++ src/platform/graphics/CMakeLists.txt 2016-10-05 09:20:48 +0000 |
254 | @@ -12,6 +12,7 @@ |
255 | pixel_format_utils.cpp |
256 | overlapping_output_grouping.cpp |
257 | platform_probe.cpp |
258 | + atomic_frame.cpp |
259 | ) |
260 | |
261 | add_library(mirplatformgraphicscommon OBJECT |
262 | |
263 | === added file 'src/platform/graphics/atomic_frame.cpp' |
264 | --- src/platform/graphics/atomic_frame.cpp 1970-01-01 00:00:00 +0000 |
265 | +++ src/platform/graphics/atomic_frame.cpp 2016-10-05 09:20:48 +0000 |
266 | @@ -0,0 +1,50 @@ |
267 | +/* |
268 | + * Copyright © 2016 Canonical Ltd. |
269 | + * |
270 | + * This program is free software: you can redistribute it and/or modify it |
271 | + * under the terms of the GNU Lesser General Public License version 3, |
272 | + * as published by the Free Software Foundation. |
273 | + * |
274 | + * This program is distributed in the hope that it will be useful, |
275 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
276 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
277 | + * GNU Lesser General Public License for more details. |
278 | + * |
279 | + * You should have received a copy of the GNU Lesser General Public License |
280 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
281 | + * |
282 | + * Authored by: Daniel van Vugt <daniel.van.vugt@canonical.com> |
283 | + */ |
284 | + |
285 | +#include "mir/graphics/atomic_frame.h" |
286 | +#include "mir/log.h" |
287 | + |
288 | +namespace mir { namespace graphics { |
289 | + |
290 | +Frame AtomicFrame::load() const |
291 | +{ |
292 | + std::lock_guard<decltype(mutex)> lock(mutex); |
293 | + return frame; |
294 | +} |
295 | + |
296 | +void AtomicFrame::store(Frame const& f) |
297 | +{ |
298 | + std::lock_guard<decltype(mutex)> lock(mutex); |
299 | + frame = f; |
300 | +} |
301 | + |
302 | +void AtomicFrame::increment_now() |
303 | +{ |
304 | + std::lock_guard<decltype(mutex)> lock(mutex); |
305 | + frame.ust = Frame::Timestamp::now(frame.ust.clock_id); |
306 | + frame.msc++; |
307 | +} |
308 | + |
309 | +void AtomicFrame::increment_with_timestamp(Frame::Timestamp t) |
310 | +{ |
311 | + std::lock_guard<decltype(mutex)> lock(mutex); |
312 | + frame.ust = t; |
313 | + frame.msc++; |
314 | +} |
315 | + |
316 | +}} // namespace mir::graphics |
317 | |
318 | === modified file 'src/platform/symbols.map' |
319 | --- src/platform/symbols.map 2016-09-19 06:09:48 +0000 |
320 | +++ src/platform/symbols.map 2016-10-05 09:20:48 +0000 |
321 | @@ -271,6 +271,10 @@ |
322 | android::isEligibleBuiltInKeyboard*; |
323 | __android_log_assert; |
324 | __android_log_print; |
325 | + |
326 | + mir::graphics::AtomicFrame::load*; |
327 | + mir::graphics::AtomicFrame::store*; |
328 | + mir::graphics::AtomicFrame::increment* |
329 | }; |
330 | local: *; |
331 | }; |
332 | |
333 | === modified file 'src/platforms/android/server/device_quirks.cpp' |
334 | --- src/platforms/android/server/device_quirks.cpp 2016-08-07 20:38:35 +0000 |
335 | +++ src/platforms/android/server/device_quirks.cpp 2016-10-05 09:20:48 +0000 |
336 | @@ -107,7 +107,7 @@ |
337 | void report_successful_egl_buffer_swap_on_construction() override {}; |
338 | void report_successful_display_construction() override {}; |
339 | void report_egl_configuration(EGLDisplay, EGLConfig) override {}; |
340 | - void report_vsync(unsigned int) override {}; |
341 | + void report_vsync(unsigned int, mg::Frame const&) override {}; |
342 | void report_successful_drm_mode_set_crtc_on_construction() override {}; |
343 | void report_drm_master_failure(int) override {}; |
344 | void report_vt_switch_away_failure() override {}; |
345 | |
346 | === modified file 'src/platforms/android/server/display.cpp' |
347 | --- src/platforms/android/server/display.cpp 2016-09-15 00:57:28 +0000 |
348 | +++ src/platforms/android/server/display.cpp 2016-10-05 09:20:48 +0000 |
349 | @@ -17,6 +17,7 @@ |
350 | */ |
351 | |
352 | #include "mir/graphics/platform.h" |
353 | +#include "mir/graphics/frame.h" |
354 | #include "display_configuration.h" |
355 | #include "mir/graphics/display_report.h" |
356 | #include "mir/graphics/display_buffer.h" |
357 | @@ -151,7 +152,9 @@ |
358 | hwc_config{display_buffer_builder->create_hwc_configuration()}, |
359 | hotplug_subscription{hwc_config->subscribe_to_config_changes( |
360 | std::bind(&mga::Display::on_hotplug, this), |
361 | - std::bind(&mga::Display::on_vsync, this, std::placeholders::_1))}, |
362 | + std::bind(&mga::Display::on_vsync, this, |
363 | + std::placeholders::_1, |
364 | + std::placeholders::_2))}, |
365 | config( |
366 | hwc_config->active_config_for(mga::DisplayName::primary), |
367 | mir_power_mode_off, |
368 | @@ -296,9 +299,32 @@ |
369 | display_change_pipe->notify_change(); |
370 | } |
371 | |
372 | -void mga::Display::on_vsync(DisplayName name) const |
373 | -{ |
374 | - display_report->report_vsync(as_output_id(name).as_value()); |
375 | +void mga::Display::on_vsync(DisplayName name, mg::Frame::Timestamp timestamp) |
376 | +{ |
377 | + std::lock_guard<decltype(vsync_mutex)> lock{vsync_mutex}; |
378 | + /* |
379 | + * XXX It's presently useful but idealistically inefficient that we |
380 | + * get a callback on every frame, even when the compositor is idle. |
381 | + * (LP: #1374318) |
382 | + * Although we possibly shouldn't fix that at all because the |
383 | + * call to increment_with_timestamp would produce incorrect MSC values |
384 | + * if it were to miss a physical frame. The X11 platform has that |
385 | + * problem already, but it's less important for production use than |
386 | + * Android. |
387 | + */ |
388 | + auto& f = last_frame[as_output_id(name).as_value()]; |
389 | + f.increment_with_timestamp(timestamp); |
390 | + display_report->report_vsync(as_output_id(name).as_value(), f.load()); |
391 | +} |
392 | + |
393 | +mg::Frame mga::Display::last_frame_on(unsigned output_id) const |
394 | +{ |
395 | + std::lock_guard<decltype(vsync_mutex)> lock{vsync_mutex}; |
396 | + auto last = last_frame.find(output_id); |
397 | + if (last == last_frame.end()) |
398 | + return {}; // Not an error. It might be a valid output_id pre-vsync |
399 | + else |
400 | + return last->second.load(); |
401 | } |
402 | |
403 | void mga::Display::register_configuration_change_handler( |
404 | |
405 | === modified file 'src/platforms/android/server/display.h' |
406 | --- src/platforms/android/server/display.h 2016-09-15 00:57:28 +0000 |
407 | +++ src/platforms/android/server/display.h 2016-10-05 09:20:48 +0000 |
408 | @@ -20,6 +20,8 @@ |
409 | #define MIR_GRAPHICS_ANDROID_DISPLAY_H_ |
410 | |
411 | #include "mir/graphics/display.h" |
412 | +#include "mir/graphics/frame.h" |
413 | +#include "mir/graphics/atomic_frame.h" |
414 | #include "mir/renderer/gl/context_source.h" |
415 | #include "gl_context.h" |
416 | #include "display_group.h" |
417 | @@ -30,6 +32,7 @@ |
418 | #include <memory> |
419 | #include <mutex> |
420 | #include <array> |
421 | +#include <unordered_map> |
422 | |
423 | namespace mir |
424 | { |
425 | @@ -88,9 +91,11 @@ |
426 | |
427 | std::unique_ptr<renderer::gl::Context> create_gl_context() override; |
428 | |
429 | + Frame last_frame_on(unsigned output_id) const override; |
430 | + |
431 | private: |
432 | void on_hotplug(); |
433 | - void on_vsync(DisplayName) const; |
434 | + void on_vsync(DisplayName, graphics::Frame::Timestamp); |
435 | |
436 | geometry::Point const origin{0,0}; |
437 | std::shared_ptr<DisplayReport> const display_report; |
438 | @@ -109,6 +114,9 @@ |
439 | OverlayOptimization const overlay_option; |
440 | |
441 | void update_configuration(std::lock_guard<decltype(configuration_mutex)> const&) const; |
442 | + |
443 | + std::mutex mutable vsync_mutex; |
444 | + std::unordered_map<unsigned,AtomicFrame> last_frame; |
445 | }; |
446 | |
447 | } |
448 | |
449 | === modified file 'src/platforms/android/server/fb_device.cpp' |
450 | --- src/platforms/android/server/fb_device.cpp 2016-09-22 16:27:13 +0000 |
451 | +++ src/platforms/android/server/fb_device.cpp 2016-10-05 09:20:48 +0000 |
452 | @@ -97,7 +97,7 @@ |
453 | |
454 | mga::ConfigChangeSubscription mga::FbControl::subscribe_to_config_changes( |
455 | std::function<void()> const&, |
456 | - std::function<void(DisplayName)> const&) |
457 | + std::function<void(DisplayName, mg::Frame::Timestamp)> const&) |
458 | { |
459 | return nullptr; |
460 | } |
461 | |
462 | === modified file 'src/platforms/android/server/fb_device.h' |
463 | --- src/platforms/android/server/fb_device.h 2016-05-03 06:55:25 +0000 |
464 | +++ src/platforms/android/server/fb_device.h 2016-10-05 09:20:48 +0000 |
465 | @@ -39,7 +39,7 @@ |
466 | DisplayConfigurationOutput active_config_for(DisplayName) override; |
467 | ConfigChangeSubscription subscribe_to_config_changes( |
468 | std::function<void()> const& hotplug_cb, |
469 | - std::function<void(DisplayName)> const& vsync_cb) override; |
470 | + std::function<void(DisplayName,graphics::Frame::Timestamp)> const& vsync_cb) override; |
471 | private: |
472 | std::shared_ptr<framebuffer_device_t> const fb_device; |
473 | }; |
474 | |
475 | === modified file 'src/platforms/android/server/hwc_blanking_control.cpp' |
476 | --- src/platforms/android/server/hwc_blanking_control.cpp 2016-09-19 04:16:15 +0000 |
477 | +++ src/platforms/android/server/hwc_blanking_control.cpp 2016-10-05 09:20:48 +0000 |
478 | @@ -227,13 +227,13 @@ |
479 | std::shared_ptr<mga::HwcWrapper> const& hwc_device, |
480 | void const* subscriber, |
481 | std::function<void()> const& hotplug, |
482 | - std::function<void(mga::DisplayName)> const& vsync) |
483 | + std::function<void(mga::DisplayName, mg::Frame::Timestamp)> const& vsync) |
484 | { |
485 | return std::make_shared< |
486 | mir::raii::PairedCalls<std::function<void()>, std::function<void()>>>( |
487 | [hotplug, vsync, subscriber, hwc_device]{ |
488 | hwc_device->subscribe_to_events(subscriber, |
489 | - [vsync](mga::DisplayName name, std::chrono::nanoseconds){ vsync(name); }, |
490 | + [vsync](mga::DisplayName name, mg::Frame::Timestamp ts){ vsync(name, ts); }, |
491 | [hotplug](mga::DisplayName, bool){ hotplug(); }, |
492 | []{}); |
493 | }, |
494 | @@ -259,7 +259,7 @@ |
495 | |
496 | mga::ConfigChangeSubscription mga::HwcBlankingControl::subscribe_to_config_changes( |
497 | std::function<void()> const& hotplug, |
498 | - std::function<void(DisplayName)> const& vsync) |
499 | + std::function<void(DisplayName, mg::Frame::Timestamp)> const& vsync) |
500 | { |
501 | return ::subscribe_to_config_changes(hwc_device, this, hotplug, vsync); |
502 | } |
503 | @@ -322,7 +322,7 @@ |
504 | |
505 | mga::ConfigChangeSubscription mga::HwcPowerModeControl::subscribe_to_config_changes( |
506 | std::function<void()> const& hotplug, |
507 | - std::function<void(DisplayName)> const& vsync) |
508 | + std::function<void(DisplayName, mg::Frame::Timestamp)> const& vsync) |
509 | { |
510 | return ::subscribe_to_config_changes(hwc_device, this, hotplug, vsync); |
511 | } |
512 | |
513 | === modified file 'src/platforms/android/server/hwc_configuration.h' |
514 | --- src/platforms/android/server/hwc_configuration.h 2016-08-24 02:09:08 +0000 |
515 | +++ src/platforms/android/server/hwc_configuration.h 2016-10-05 09:20:48 +0000 |
516 | @@ -20,6 +20,7 @@ |
517 | #define MIR_GRAPHICS_ANDROID_HWC_CONFIGURATION_H_ |
518 | |
519 | #include "mir/graphics/display_configuration.h" |
520 | +#include "mir/graphics/frame.h" |
521 | #include "mir/geometry/size.h" |
522 | #include "display_name.h" |
523 | #include <memory> |
524 | @@ -42,7 +43,7 @@ |
525 | virtual DisplayConfigurationOutput active_config_for(DisplayName) = 0; |
526 | virtual ConfigChangeSubscription subscribe_to_config_changes( |
527 | std::function<void()> const& hotplug_cb, |
528 | - std::function<void(DisplayName)> const& vsync_cb) = 0; |
529 | + std::function<void(DisplayName,graphics::Frame::Timestamp)> const& vsync_cb) = 0; |
530 | |
531 | protected: |
532 | HwcConfiguration() = default; |
533 | @@ -60,7 +61,7 @@ |
534 | DisplayConfigurationOutput active_config_for(DisplayName) override; |
535 | ConfigChangeSubscription subscribe_to_config_changes( |
536 | std::function<void()> const& hotplug_cb, |
537 | - std::function<void(DisplayName)> const& vsync_cb) override; |
538 | + std::function<void(DisplayName,graphics::Frame::Timestamp)> const& vsync_cb) override; |
539 | |
540 | private: |
541 | std::shared_ptr<HwcWrapper> const hwc_device; |
542 | @@ -77,7 +78,7 @@ |
543 | DisplayConfigurationOutput active_config_for(DisplayName) override; |
544 | ConfigChangeSubscription subscribe_to_config_changes( |
545 | std::function<void()> const& hotplug_cb, |
546 | - std::function<void(DisplayName)> const& vsync_cb) override; |
547 | + std::function<void(DisplayName,graphics::Frame::Timestamp)> const& vsync_cb) override; |
548 | |
549 | private: |
550 | std::shared_ptr<HwcWrapper> const hwc_device; |
551 | |
552 | === modified file 'src/platforms/android/server/hwc_fb_device.cpp' |
553 | --- src/platforms/android/server/hwc_fb_device.cpp 2016-09-19 04:16:15 +0000 |
554 | +++ src/platforms/android/server/hwc_fb_device.cpp 2016-10-05 09:20:48 +0000 |
555 | @@ -98,7 +98,7 @@ |
556 | vsync_trigger.wait(lk, [this]{return vsync_occurred;}); |
557 | } |
558 | |
559 | -void mga::HwcFbDevice::notify_vsync(mga::DisplayName, std::chrono::nanoseconds) |
560 | +void mga::HwcFbDevice::notify_vsync(mga::DisplayName, mg::Frame::Timestamp) |
561 | { |
562 | std::unique_lock<std::mutex> lk(vsync_wait_mutex); |
563 | vsync_occurred = true; |
564 | |
565 | === modified file 'src/platforms/android/server/hwc_fb_device.h' |
566 | --- src/platforms/android/server/hwc_fb_device.h 2016-05-03 06:55:25 +0000 |
567 | +++ src/platforms/android/server/hwc_fb_device.h 2016-10-05 09:20:48 +0000 |
568 | @@ -19,6 +19,7 @@ |
569 | #ifndef MIR_GRAPHICS_ANDROID_HWC_FB_DEVICE_H_ |
570 | #define MIR_GRAPHICS_ANDROID_HWC_FB_DEVICE_H_ |
571 | |
572 | +#include "mir/graphics/frame.h" |
573 | #include "display_device.h" |
574 | #include "hardware/gralloc.h" |
575 | #include "hardware/fb.h" |
576 | @@ -56,7 +57,7 @@ |
577 | std::mutex vsync_wait_mutex; |
578 | std::condition_variable vsync_trigger; |
579 | bool vsync_occurred; |
580 | - void notify_vsync(DisplayName, std::chrono::nanoseconds); |
581 | + void notify_vsync(DisplayName, graphics::Frame::Timestamp); |
582 | }; |
583 | |
584 | } |
585 | |
586 | === modified file 'src/platforms/android/server/hwc_wrapper.h' |
587 | --- src/platforms/android/server/hwc_wrapper.h 2015-06-17 05:20:42 +0000 |
588 | +++ src/platforms/android/server/hwc_wrapper.h 2016-10-05 09:20:48 +0000 |
589 | @@ -19,12 +19,12 @@ |
590 | #ifndef MIR_GRAPHICS_ANDROID_HWC_WRAPPER_H_ |
591 | #define MIR_GRAPHICS_ANDROID_HWC_WRAPPER_H_ |
592 | |
593 | +#include "mir/graphics/frame.h" |
594 | #include "mir/int_wrapper.h" |
595 | #include "display_name.h" |
596 | #include "power_mode.h" |
597 | #include <array> |
598 | #include <functional> |
599 | -#include <chrono> |
600 | #include <vector> |
601 | |
602 | struct hwc_display_contents_1; |
603 | @@ -51,7 +51,7 @@ |
604 | //As with the HWC api, these events MUST NOT call-back to the other functions in HwcWrapper. |
605 | virtual void subscribe_to_events( |
606 | void const* subscriber, |
607 | - std::function<void(DisplayName, std::chrono::nanoseconds)> const& vsync_callback, |
608 | + std::function<void(DisplayName, graphics::Frame::Timestamp)> const& vsync_callback, |
609 | std::function<void(DisplayName, bool)> const& hotplug_callback, |
610 | std::function<void()> const& invalidate_callback) = 0; |
611 | virtual void unsubscribe_from_events(void const* subscriber) noexcept = 0; |
612 | |
613 | === modified file 'src/platforms/android/server/real_hwc_wrapper.cpp' |
614 | --- src/platforms/android/server/real_hwc_wrapper.cpp 2016-05-03 06:55:25 +0000 |
615 | +++ src/platforms/android/server/real_hwc_wrapper.cpp 2016-10-05 09:20:48 +0000 |
616 | @@ -16,6 +16,7 @@ |
617 | * Authored by: Kevin DuBois <kevin.dubois@canonical.com> |
618 | */ |
619 | |
620 | +#include "mir/graphics/frame.h" |
621 | #include "real_hwc_wrapper.h" |
622 | #include "hwc_report.h" |
623 | #include "display_device_exceptions.h" |
624 | @@ -24,6 +25,7 @@ |
625 | #include <sstream> |
626 | #include <algorithm> |
627 | |
628 | +namespace mg = mir::graphics; |
629 | namespace mga=mir::graphics::android; |
630 | |
631 | namespace |
632 | @@ -66,7 +68,13 @@ |
633 | mga::HwcCallbacks const* callbacks{nullptr}; |
634 | std::unique_lock<std::mutex> lk(callback_lock); |
635 | if ((callbacks = reinterpret_cast<mga::HwcCallbacks const*>(procs)) && callbacks->self) |
636 | - callbacks->self->vsync(display_name(display), std::chrono::nanoseconds{timestamp}); |
637 | + { |
638 | + // hwcomposer.h says the clock used is CLOCK_MONOTONIC, and testing |
639 | + // on various devices confirms this is the case... |
640 | + mg::Frame::Timestamp hwc_time{CLOCK_MONOTONIC, |
641 | + std::chrono::nanoseconds{timestamp}}; |
642 | + callbacks->self->vsync(display_name(display), hwc_time); |
643 | + } |
644 | } |
645 | |
646 | static void hotplug_hook(const struct hwc_procs* procs, int display, int connected) |
647 | @@ -185,7 +193,7 @@ |
648 | |
649 | void mga::RealHwcWrapper::subscribe_to_events( |
650 | void const* subscriber, |
651 | - std::function<void(DisplayName, std::chrono::nanoseconds)> const& vsync, |
652 | + std::function<void(DisplayName, mg::Frame::Timestamp)> const& vsync, |
653 | std::function<void(DisplayName, bool)> const& hotplug, |
654 | std::function<void()> const& invalidate) |
655 | { |
656 | @@ -201,7 +209,7 @@ |
657 | callback_map.erase(it); |
658 | } |
659 | |
660 | -void mga::RealHwcWrapper::vsync(DisplayName name, std::chrono::nanoseconds timestamp) noexcept |
661 | +void mga::RealHwcWrapper::vsync(DisplayName name, mg::Frame::Timestamp timestamp) noexcept |
662 | { |
663 | std::unique_lock<std::mutex> lk(callback_map_lock); |
664 | for(auto const& callbacks : callback_map) |
665 | |
666 | === modified file 'src/platforms/android/server/real_hwc_wrapper.h' |
667 | --- src/platforms/android/server/real_hwc_wrapper.h 2016-05-03 06:55:25 +0000 |
668 | +++ src/platforms/android/server/real_hwc_wrapper.h 2016-10-05 09:20:48 +0000 |
669 | @@ -52,7 +52,7 @@ |
670 | |
671 | void subscribe_to_events( |
672 | void const* subscriber, |
673 | - std::function<void(DisplayName, std::chrono::nanoseconds)> const& vsync_callback, |
674 | + std::function<void(DisplayName, graphics::Frame::Timestamp)> const& vsync_callback, |
675 | std::function<void(DisplayName, bool)> const& hotplug_callback, |
676 | std::function<void()> const& invalidate_callback) override; |
677 | void unsubscribe_from_events(void const* subscriber) noexcept override; |
678 | @@ -71,7 +71,7 @@ |
679 | ConfigId active_config_for(DisplayName name) const override; |
680 | void set_active_config(DisplayName name, ConfigId id) const override; |
681 | |
682 | - void vsync(DisplayName, std::chrono::nanoseconds) noexcept; |
683 | + void vsync(DisplayName, graphics::Frame::Timestamp) noexcept; |
684 | void hotplug(DisplayName, bool) noexcept; |
685 | void invalidate() noexcept; |
686 | |
687 | @@ -82,7 +82,7 @@ |
688 | std::mutex callback_map_lock; |
689 | struct Callbacks |
690 | { |
691 | - std::function<void(DisplayName, std::chrono::nanoseconds)> vsync; |
692 | + std::function<void(DisplayName, graphics::Frame::Timestamp)> vsync; |
693 | std::function<void(DisplayName, bool)> hotplug; |
694 | std::function<void()> invalidate; |
695 | }; |
696 | |
697 | === modified file 'src/platforms/android/utils/render_overlays.cpp' |
698 | --- src/platforms/android/utils/render_overlays.cpp 2016-09-19 06:09:48 +0000 |
699 | +++ src/platforms/android/utils/render_overlays.cpp 2016-10-05 09:20:48 +0000 |
700 | @@ -233,7 +233,7 @@ |
701 | void report_successful_egl_buffer_swap_on_construction() override {} |
702 | void report_successful_display_construction() override {} |
703 | void report_egl_configuration(EGLDisplay, EGLConfig) override {} |
704 | - void report_vsync(unsigned int) override {} |
705 | + void report_vsync(unsigned int, mg::Frame const&) override {} |
706 | void report_successful_drm_mode_set_crtc_on_construction() override {} |
707 | void report_drm_master_failure(int) override {} |
708 | void report_vt_switch_away_failure() override {} |
709 | |
710 | === modified file 'src/platforms/eglstream-kms/server/display.cpp' |
711 | --- src/platforms/eglstream-kms/server/display.cpp 2016-09-21 06:15:45 +0000 |
712 | +++ src/platforms/eglstream-kms/server/display.cpp 2016-10-05 09:20:48 +0000 |
713 | @@ -373,3 +373,12 @@ |
714 | return false; |
715 | } |
716 | |
717 | +mg::Frame mge::Display::last_frame_on(unsigned) const |
718 | +{ |
719 | + /* |
720 | + * TODO: Implement this later when we have the hardware + driver to test on. |
721 | + * If no proper hardware counters are available, just call |
722 | + * AtomicFrame.increment_now() in post() above. |
723 | + */ |
724 | + return {}; |
725 | +} |
726 | |
727 | === modified file 'src/platforms/eglstream-kms/server/display.h' |
728 | --- src/platforms/eglstream-kms/server/display.h 2016-09-15 00:57:28 +0000 |
729 | +++ src/platforms/eglstream-kms/server/display.h 2016-10-05 09:20:48 +0000 |
730 | @@ -70,6 +70,7 @@ |
731 | NativeDisplay* native_display() override; |
732 | |
733 | std::unique_ptr<renderer::gl::Context> create_gl_context() override; |
734 | + Frame last_frame_on(unsigned output_id) const override; |
735 | |
736 | private: |
737 | mir::Fd const drm_node; |
738 | |
739 | === modified file 'src/platforms/mesa/server/kms/display.cpp' |
740 | --- src/platforms/mesa/server/kms/display.cpp 2016-09-15 00:57:28 +0000 |
741 | +++ src/platforms/mesa/server/kms/display.cpp 2016-10-05 09:20:48 +0000 |
742 | @@ -421,3 +421,9 @@ |
743 | { |
744 | return false; |
745 | } |
746 | + |
747 | +mg::Frame mgm::Display::last_frame_on(unsigned output_id) const |
748 | +{ |
749 | + auto output = output_container.get_kms_output_for(output_id); |
750 | + return output->last_frame(); |
751 | +} |
752 | |
753 | === modified file 'src/platforms/mesa/server/kms/display.h' |
754 | --- src/platforms/mesa/server/kms/display.h 2016-09-15 00:57:28 +0000 |
755 | +++ src/platforms/mesa/server/kms/display.h 2016-10-05 09:20:48 +0000 |
756 | @@ -99,6 +99,8 @@ |
757 | |
758 | std::unique_ptr<renderer::gl::Context> create_gl_context() override; |
759 | |
760 | + Frame last_frame_on(unsigned output_id) const override; |
761 | + |
762 | private: |
763 | void clear_connected_unused_outputs(); |
764 | |
765 | @@ -110,7 +112,7 @@ |
766 | mir::udev::Monitor monitor; |
767 | helpers::EGLHelper shared_egl; |
768 | std::vector<std::unique_ptr<DisplayBuffer>> display_buffers; |
769 | - RealKMSOutputContainer output_container; |
770 | + mutable RealKMSOutputContainer output_container; |
771 | mutable RealKMSDisplayConfiguration current_display_configuration; |
772 | mutable std::atomic<bool> dirty_configuration; |
773 | |
774 | |
775 | === modified file 'src/platforms/mesa/server/kms/kms_output.h' |
776 | --- src/platforms/mesa/server/kms/kms_output.h 2016-09-01 17:02:56 +0000 |
777 | +++ src/platforms/mesa/server/kms/kms_output.h 2016-10-05 09:20:48 +0000 |
778 | @@ -23,6 +23,7 @@ |
779 | #include "mir/geometry/point.h" |
780 | #include "mir/geometry/displacement.h" |
781 | #include "mir/graphics/display_configuration.h" |
782 | +#include "mir/graphics/frame.h" |
783 | #include "mir_toolkit/common.h" |
784 | |
785 | #include <gbm.h> |
786 | @@ -63,6 +64,7 @@ |
787 | |
788 | virtual void set_power_mode(MirPowerMode mode) = 0; |
789 | virtual void set_gamma(GammaCurves const& gamma) = 0; |
790 | + virtual Frame last_frame() const = 0; |
791 | |
792 | protected: |
793 | KMSOutput() = default; |
794 | |
795 | === modified file 'src/platforms/mesa/server/kms/kms_page_flipper.cpp' |
796 | --- src/platforms/mesa/server/kms/kms_page_flipper.cpp 2016-09-09 07:51:51 +0000 |
797 | +++ src/platforms/mesa/server/kms/kms_page_flipper.cpp 2016-10-05 09:20:48 +0000 |
798 | @@ -25,18 +25,22 @@ |
799 | |
800 | #include <xf86drm.h> |
801 | #include <xf86drmMode.h> |
802 | +#include <chrono> |
803 | |
804 | +namespace mg = mir::graphics; |
805 | namespace mgm = mir::graphics::mesa; |
806 | |
807 | namespace |
808 | { |
809 | |
810 | -void page_flip_handler(int /*fd*/, unsigned int /*frame*/, |
811 | - unsigned int /*sec*/, unsigned int /*usec*/, |
812 | +void page_flip_handler(int /*fd*/, unsigned int seq, |
813 | + unsigned int sec, unsigned int usec, |
814 | void* data) |
815 | { |
816 | auto page_flip_data = static_cast<mgm::PageFlipEventData*>(data); |
817 | - page_flip_data->flipper->notify_page_flip(page_flip_data->crtc_id); |
818 | + std::chrono::nanoseconds ns{sec*1000000000LL + usec*1000LL}; |
819 | + page_flip_data->flipper->notify_page_flip(page_flip_data->crtc_id, |
820 | + seq, ns); |
821 | } |
822 | |
823 | } |
824 | @@ -49,6 +53,11 @@ |
825 | pending_page_flips(), |
826 | worker_tid() |
827 | { |
828 | + uint64_t mono = 0; |
829 | + if (drmGetCap(drm_fd, DRM_CAP_TIMESTAMP_MONOTONIC, &mono) || !mono) |
830 | + clock_id = CLOCK_REALTIME; |
831 | + else |
832 | + clock_id = CLOCK_MONOTONIC; |
833 | } |
834 | |
835 | bool mgm::KMSPageFlipper::schedule_flip(uint32_t crtc_id, |
836 | @@ -72,7 +81,7 @@ |
837 | return (ret == 0); |
838 | } |
839 | |
840 | -void mgm::KMSPageFlipper::wait_for_flip(uint32_t crtc_id) |
841 | +mg::Frame mgm::KMSPageFlipper::wait_for_flip(uint32_t crtc_id) |
842 | { |
843 | static drmEventContext evctx = |
844 | { |
845 | @@ -94,7 +103,7 @@ |
846 | |
847 | /* If the page flip we are waiting for has arrived we are done. */ |
848 | if (page_flip_is_done(crtc_id)) |
849 | - return; |
850 | + return completed_page_flips[crtc_id]; |
851 | |
852 | /* ...otherwise we become the worker */ |
853 | worker_tid = std::this_thread::get_id(); |
854 | @@ -144,6 +153,7 @@ |
855 | */ |
856 | pf_cv.notify_all(); |
857 | } |
858 | + return completed_page_flips[crtc_id]; |
859 | } |
860 | |
861 | std::thread::id mgm::KMSPageFlipper::debug_get_worker_tid() |
862 | @@ -159,12 +169,16 @@ |
863 | return pending_page_flips.find(crtc_id) == pending_page_flips.end(); |
864 | } |
865 | |
866 | -void mgm::KMSPageFlipper::notify_page_flip(uint32_t crtc_id) |
867 | +void mgm::KMSPageFlipper::notify_page_flip(uint32_t crtc_id, int64_t msc, |
868 | + std::chrono::nanoseconds ust) |
869 | { |
870 | auto pending = pending_page_flips.find(crtc_id); |
871 | if (pending != pending_page_flips.end()) |
872 | { |
873 | - report->report_vsync(pending->second.connector_id); |
874 | + auto& frame = completed_page_flips[crtc_id]; |
875 | + frame.msc = msc; |
876 | + frame.ust = {clock_id, ust}; |
877 | + report->report_vsync(pending->second.connector_id, frame); |
878 | pending_page_flips.erase(pending); |
879 | } |
880 | } |
881 | |
882 | === modified file 'src/platforms/mesa/server/kms/kms_page_flipper.h' |
883 | --- src/platforms/mesa/server/kms/kms_page_flipper.h 2016-09-09 07:10:01 +0000 |
884 | +++ src/platforms/mesa/server/kms/kms_page_flipper.h 2016-10-05 09:20:48 +0000 |
885 | @@ -26,7 +26,7 @@ |
886 | #include <mutex> |
887 | #include <condition_variable> |
888 | #include <thread> |
889 | - |
890 | +#include <ctime> |
891 | #include <sys/time.h> |
892 | |
893 | namespace mir |
894 | @@ -53,20 +53,22 @@ |
895 | KMSPageFlipper(int drm_fd, std::shared_ptr<DisplayReport> const& report); |
896 | |
897 | bool schedule_flip(uint32_t crtc_id, uint32_t fb_id, uint32_t connector_id) override; |
898 | - void wait_for_flip(uint32_t crtc_id) override; |
899 | + Frame wait_for_flip(uint32_t crtc_id) override; |
900 | |
901 | std::thread::id debug_get_worker_tid(); |
902 | |
903 | - void notify_page_flip(uint32_t crtc_id); |
904 | + void notify_page_flip(uint32_t crtc_id, int64_t msc, std::chrono::nanoseconds ust); |
905 | private: |
906 | bool page_flip_is_done(uint32_t crtc_id); |
907 | |
908 | int const drm_fd; |
909 | std::shared_ptr<DisplayReport> const report; |
910 | std::unordered_map<uint32_t,PageFlipEventData> pending_page_flips; |
911 | + std::unordered_map<uint32_t,Frame> completed_page_flips; |
912 | std::mutex pf_mutex; |
913 | std::condition_variable pf_cv; |
914 | std::thread::id worker_tid; |
915 | + clockid_t clock_id; |
916 | }; |
917 | |
918 | } |
919 | |
920 | === modified file 'src/platforms/mesa/server/kms/page_flipper.h' |
921 | --- src/platforms/mesa/server/kms/page_flipper.h 2016-09-09 07:10:01 +0000 |
922 | +++ src/platforms/mesa/server/kms/page_flipper.h 2016-10-05 09:20:48 +0000 |
923 | @@ -19,6 +19,7 @@ |
924 | #ifndef MIR_GRAPHICS_MESA_PAGE_FLIPPER_H_ |
925 | #define MIR_GRAPHICS_MESA_PAGE_FLIPPER_H_ |
926 | |
927 | +#include "mir/graphics/frame.h" |
928 | #include <cstdint> |
929 | |
930 | namespace mir |
931 | @@ -34,7 +35,7 @@ |
932 | virtual ~PageFlipper() {} |
933 | |
934 | virtual bool schedule_flip(uint32_t crtc_id, uint32_t fb_id, uint32_t connector_id) = 0; |
935 | - virtual void wait_for_flip(uint32_t crtc_id) = 0; |
936 | + virtual Frame wait_for_flip(uint32_t crtc_id) = 0; |
937 | |
938 | protected: |
939 | PageFlipper() = default; |
940 | |
941 | === modified file 'src/platforms/mesa/server/kms/real_kms_output.cpp' |
942 | --- src/platforms/mesa/server/kms/real_kms_output.cpp 2016-09-09 07:10:01 +0000 |
943 | +++ src/platforms/mesa/server/kms/real_kms_output.cpp 2016-10-05 09:20:48 +0000 |
944 | @@ -181,7 +181,13 @@ |
945 | fatal_error("Output %s has no associated CRTC to wait on", |
946 | mgk::connector_name(connector).c_str()); |
947 | } |
948 | - page_flipper->wait_for_flip(current_crtc->crtc_id); |
949 | + |
950 | + last_frame_.store(page_flipper->wait_for_flip(current_crtc->crtc_id)); |
951 | +} |
952 | + |
953 | +mg::Frame mgm::RealKMSOutput::last_frame() const |
954 | +{ |
955 | + return last_frame_.load(); |
956 | } |
957 | |
958 | void mgm::RealKMSOutput::set_cursor(gbm_bo* buffer) |
959 | |
960 | === modified file 'src/platforms/mesa/server/kms/real_kms_output.h' |
961 | --- src/platforms/mesa/server/kms/real_kms_output.h 2016-09-01 17:02:56 +0000 |
962 | +++ src/platforms/mesa/server/kms/real_kms_output.h 2016-10-05 09:20:48 +0000 |
963 | @@ -19,6 +19,7 @@ |
964 | #ifndef MIR_GRAPHICS_MESA_REAL_KMS_OUTPUT_H_ |
965 | #define MIR_GRAPHICS_MESA_REAL_KMS_OUTPUT_H_ |
966 | |
967 | +#include "mir/graphics/atomic_frame.h" |
968 | #include "kms_output.h" |
969 | #include "kms-utils/drm_mode_resources.h" |
970 | |
971 | @@ -59,6 +60,8 @@ |
972 | void set_power_mode(MirPowerMode mode) override; |
973 | void set_gamma(GammaCurves const& gamma) override; |
974 | |
975 | + Frame last_frame() const override; |
976 | + |
977 | private: |
978 | bool ensure_crtc(); |
979 | void restore_saved_crtc(); |
980 | @@ -79,6 +82,8 @@ |
981 | int dpms_enum_id; |
982 | |
983 | std::mutex power_mutex; |
984 | + |
985 | + AtomicFrame last_frame_; |
986 | }; |
987 | |
988 | } |
989 | |
990 | === modified file 'src/platforms/mesa/server/x11/graphics/display.cpp' |
991 | --- src/platforms/mesa/server/x11/graphics/display.cpp 2016-10-04 08:15:29 +0000 |
992 | +++ src/platforms/mesa/server/x11/graphics/display.cpp 2016-10-05 09:20:48 +0000 |
993 | @@ -22,6 +22,7 @@ |
994 | #include "mir/graphics/virtual_output.h" |
995 | #include "mir/renderer/gl/context.h" |
996 | #include "mir/graphics/gl_config.h" |
997 | +#include "mir/graphics/atomic_frame.h" |
998 | #include "display_configuration.h" |
999 | #include "display.h" |
1000 | #include "display_buffer.h" |
1001 | @@ -235,7 +236,8 @@ |
1002 | pixel_width{get_pixel_width(x_dpy)}, |
1003 | pixel_height{get_pixel_height(x_dpy)}, |
1004 | report{report}, |
1005 | - orientation{mir_orientation_normal} |
1006 | + orientation{mir_orientation_normal}, |
1007 | + last_frame{std::make_shared<AtomicFrame>()} |
1008 | { |
1009 | shared_egl.setup(x_dpy); |
1010 | |
1011 | @@ -253,6 +255,7 @@ |
1012 | *win, |
1013 | actual_size, |
1014 | shared_egl.context(), |
1015 | + last_frame, |
1016 | report, |
1017 | orientation, |
1018 | *gl_config); |
1019 | @@ -344,3 +347,8 @@ |
1020 | { |
1021 | return false; |
1022 | } |
1023 | + |
1024 | +mg::Frame mgx::Display::last_frame_on(unsigned) const |
1025 | +{ |
1026 | + return last_frame->load(); |
1027 | +} |
1028 | |
1029 | === modified file 'src/platforms/mesa/server/x11/graphics/display.h' |
1030 | --- src/platforms/mesa/server/x11/graphics/display.h 2016-10-04 08:15:29 +0000 |
1031 | +++ src/platforms/mesa/server/x11/graphics/display.h 2016-10-05 09:20:48 +0000 |
1032 | @@ -29,11 +29,14 @@ |
1033 | #include <X11/Xutil.h> |
1034 | #include <EGL/egl.h> |
1035 | |
1036 | +#include <memory> |
1037 | + |
1038 | namespace mir |
1039 | { |
1040 | namespace graphics |
1041 | { |
1042 | |
1043 | +class AtomicFrame; |
1044 | class GLConfig; |
1045 | class DisplayReport; |
1046 | |
1047 | @@ -98,6 +101,8 @@ |
1048 | |
1049 | std::unique_ptr<renderer::gl::Context> create_gl_context() override; |
1050 | |
1051 | + Frame last_frame_on(unsigned output_id) const override; |
1052 | + |
1053 | private: |
1054 | helpers::EGLHelper shared_egl; |
1055 | ::Display* const x_dpy; |
1056 | @@ -109,6 +114,7 @@ |
1057 | MirPixelFormat pf; |
1058 | std::shared_ptr<DisplayReport> const report; |
1059 | MirOrientation orientation; //TODO: keep entire current display configuration |
1060 | + std::shared_ptr<AtomicFrame> last_frame; |
1061 | std::unique_ptr<DisplayBuffer> display_buffer; |
1062 | }; |
1063 | |
1064 | |
1065 | === modified file 'src/platforms/mesa/server/x11/graphics/display_buffer.cpp' |
1066 | --- src/platforms/mesa/server/x11/graphics/display_buffer.cpp 2016-10-04 08:15:29 +0000 |
1067 | +++ src/platforms/mesa/server/x11/graphics/display_buffer.cpp 2016-10-05 09:20:48 +0000 |
1068 | @@ -17,10 +17,12 @@ |
1069 | * |
1070 | */ |
1071 | |
1072 | +#include "mir/graphics/atomic_frame.h" |
1073 | #include "mir/fatal.h" |
1074 | #include "display_buffer.h" |
1075 | #include "display_configuration.h" |
1076 | #include "mir/graphics/display_report.h" |
1077 | +#include <cstring> |
1078 | |
1079 | namespace mg=mir::graphics; |
1080 | namespace mgx=mg::X; |
1081 | @@ -30,13 +32,16 @@ |
1082 | Window const win, |
1083 | geom::Size const sz, |
1084 | EGLContext const shared_context, |
1085 | + std::shared_ptr<AtomicFrame> const& f, |
1086 | std::shared_ptr<DisplayReport> const& r, |
1087 | MirOrientation const o, |
1088 | GLConfig const& gl_config) |
1089 | : size{sz}, |
1090 | report{r}, |
1091 | orientation_{o}, |
1092 | - egl{gl_config} |
1093 | + egl{gl_config}, |
1094 | + last_frame{f}, |
1095 | + eglGetSyncValues{nullptr} |
1096 | { |
1097 | egl.setup(x_dpy, win, shared_context); |
1098 | egl.report_egl_configuration( |
1099 | @@ -44,6 +49,36 @@ |
1100 | { |
1101 | r->report_egl_configuration(disp, cfg); |
1102 | }); |
1103 | + |
1104 | + /* |
1105 | + * EGL_CHROMIUM_sync_control is an EGL extension that Google invented/copied |
1106 | + * so they could switch Chrome(ium) from GLX to EGL: |
1107 | + * |
1108 | + * https://bugs.chromium.org/p/chromium/issues/detail?id=366935 |
1109 | + * https://www.opengl.org/registry/specs/OML/glx_sync_control.txt |
1110 | + * |
1111 | + * Most noteworthy is that the EGL extension only has one function, as |
1112 | + * Google realized that's all you need. You do not need wait functions or |
1113 | + * events if you already have accurate timestamps and the ability to sleep |
1114 | + * with high precision. In fact sync logic in clients will have higher |
1115 | + * precision if you implement the wait yourself relative to the correct |
1116 | + * kernel clock, than using IPC to implement the wait on the server. |
1117 | + * |
1118 | + * EGL_CHROMIUM_sync_control never got formally standardized and no longer |
1119 | + * needs to be since they switched ChromeOS over to Freon (native KMS). |
1120 | + * However this remains the correct and only way of doing it in EGL on X11. |
1121 | + * AFAIK the only existing implementation is Mesa. |
1122 | + */ |
1123 | + auto const extensions = eglQueryString(egl.display(), EGL_EXTENSIONS); |
1124 | + auto const extension = "EGL_CHROMIUM_sync_control"; |
1125 | + auto const found = strstr(extensions, extension); |
1126 | + if (found) |
1127 | + { |
1128 | + char end = found[strlen(extension)]; |
1129 | + if (end == '\0' || end == ' ') |
1130 | + eglGetSyncValues = reinterpret_cast<EglGetSyncValuesCHROMIUM*>( |
1131 | + eglGetProcAddress("eglGetSyncValuesCHROMIUM")); |
1132 | + } |
1133 | } |
1134 | |
1135 | geom::Rectangle mgx::DisplayBuffer::view_area() const |
1136 | @@ -80,11 +115,37 @@ |
1137 | fatal_error("Failed to perform buffer swap"); |
1138 | |
1139 | /* |
1140 | + * It would be nice to call this on demand as required. However the |
1141 | + * implementation requires an EGL context. So for simplicity we call it here |
1142 | + * on every frame. |
1143 | + * This does mean the current last_frame will be a bit out of date if |
1144 | + * the compositor missed a frame. But that doesn't actually matter because |
1145 | + * the consequence of that would be the client scheduling the next frame |
1146 | + * immediately without waiting, which is probably ideal anyway. |
1147 | + */ |
1148 | + int64_t ust_us, msc, sbc; |
1149 | + if (eglGetSyncValues && |
1150 | + eglGetSyncValues(egl.display(), egl.surface(), &ust_us, &msc, &sbc)) |
1151 | + { |
1152 | + std::chrono::nanoseconds const ust_ns{ust_us * 1000}; |
1153 | + mg::Frame frame; |
1154 | + frame.msc = msc; |
1155 | + frame.ust = {CLOCK_MONOTONIC, ust_ns}; |
1156 | + last_frame->store(frame); |
1157 | + (void)sbc; // unused |
1158 | + } |
1159 | + else // Extension not available? Fall back to a reasonable estimate: |
1160 | + { |
1161 | + last_frame->increment_now(); |
1162 | + } |
1163 | + |
1164 | + /* |
1165 | * Admittedly we are not a real display and will miss some real vsyncs |
1166 | * but this is best-effort. And besides, we don't want Mir reporting all |
1167 | * real vsyncs because that would mean the compositor never sleeps. |
1168 | */ |
1169 | - report->report_vsync(mgx::DisplayConfiguration::the_output_id.as_value()); |
1170 | + report->report_vsync(mgx::DisplayConfiguration::the_output_id.as_value(), |
1171 | + last_frame->load()); |
1172 | } |
1173 | |
1174 | void mgx::DisplayBuffer::bind() |
1175 | |
1176 | === modified file 'src/platforms/mesa/server/x11/graphics/display_buffer.h' |
1177 | --- src/platforms/mesa/server/x11/graphics/display_buffer.h 2016-10-04 08:15:29 +0000 |
1178 | +++ src/platforms/mesa/server/x11/graphics/display_buffer.h 2016-10-05 09:20:48 +0000 |
1179 | @@ -33,6 +33,7 @@ |
1180 | namespace graphics |
1181 | { |
1182 | |
1183 | +class AtomicFrame; |
1184 | class GLConfig; |
1185 | class DisplayReport; |
1186 | |
1187 | @@ -50,6 +51,7 @@ |
1188 | Window const win, |
1189 | geometry::Size const sz, |
1190 | EGLContext const shared_context, |
1191 | + std::shared_ptr<AtomicFrame> const& f, |
1192 | std::shared_ptr<DisplayReport> const& r, |
1193 | MirOrientation const o, |
1194 | GLConfig const& gl_config); |
1195 | @@ -76,6 +78,12 @@ |
1196 | std::shared_ptr<DisplayReport> const report; |
1197 | MirOrientation orientation_; |
1198 | helpers::EGLHelper egl; |
1199 | + std::shared_ptr<AtomicFrame> const last_frame; |
1200 | + |
1201 | + typedef EGLBoolean (EGLAPIENTRY EglGetSyncValuesCHROMIUM) |
1202 | + (EGLDisplay dpy, EGLSurface surface, int64_t *ust, |
1203 | + int64_t *msc, int64_t *sbc); |
1204 | + EglGetSyncValuesCHROMIUM* eglGetSyncValues; |
1205 | }; |
1206 | |
1207 | } |
1208 | |
1209 | === modified file 'src/platforms/mesa/server/x11/graphics/egl_helper.h' |
1210 | --- src/platforms/mesa/server/x11/graphics/egl_helper.h 2016-09-23 22:45:16 +0000 |
1211 | +++ src/platforms/mesa/server/x11/graphics/egl_helper.h 2016-10-05 09:20:48 +0000 |
1212 | @@ -57,6 +57,7 @@ |
1213 | EGLContext context() { return egl_context; } |
1214 | EGLDisplay display() { return egl_display; } |
1215 | EGLConfig config() { return egl_config; } |
1216 | + EGLSurface surface() const { return egl_surface; } |
1217 | |
1218 | void report_egl_configuration(std::function<void(EGLDisplay, EGLConfig)>); |
1219 | private: |
1220 | |
1221 | === modified file 'src/server/graphics/nested/display.cpp' |
1222 | --- src/server/graphics/nested/display.cpp 2016-09-15 00:57:28 +0000 |
1223 | +++ src/server/graphics/nested/display.cpp 2016-10-05 09:20:48 +0000 |
1224 | @@ -372,3 +372,8 @@ |
1225 | { |
1226 | return false; |
1227 | } |
1228 | + |
1229 | +mg::Frame mgn::Display::last_frame_on(unsigned) const |
1230 | +{ |
1231 | + return {}; // TODO after the client API exists for us to get it |
1232 | +} |
1233 | |
1234 | === modified file 'src/server/graphics/nested/display.h' |
1235 | --- src/server/graphics/nested/display.h 2016-09-15 00:57:28 +0000 |
1236 | +++ src/server/graphics/nested/display.h 2016-10-05 09:20:48 +0000 |
1237 | @@ -150,6 +150,7 @@ |
1238 | |
1239 | NativeDisplay* native_display() override; |
1240 | std::unique_ptr<renderer::gl::Context> create_gl_context() override; |
1241 | + Frame last_frame_on(unsigned output_id) const override; |
1242 | |
1243 | private: |
1244 | std::shared_ptr<graphics::Platform> const platform; |
1245 | |
1246 | === modified file 'src/server/report/logging/display_report.cpp' |
1247 | --- src/server/report/logging/display_report.cpp 2016-09-12 07:00:54 +0000 |
1248 | +++ src/server/report/logging/display_report.cpp 2016-10-05 09:20:48 +0000 |
1249 | @@ -21,16 +21,14 @@ |
1250 | #include <EGL/eglext.h> |
1251 | #include <sstream> |
1252 | #include <cstring> |
1253 | +#include <cstdlib> |
1254 | |
1255 | namespace ml=mir::logging; |
1256 | namespace mrl=mir::report::logging; |
1257 | |
1258 | mrl::DisplayReport::DisplayReport( |
1259 | - std::shared_ptr<ml::Logger> const& logger, |
1260 | - std::shared_ptr<time::Clock> const& clock) : |
1261 | - logger(logger), |
1262 | - clock(clock), |
1263 | - last_report(clock->now()) |
1264 | + std::shared_ptr<ml::Logger> const& logger) |
1265 | + : logger(logger) |
1266 | { |
1267 | } |
1268 | |
1269 | @@ -147,22 +145,33 @@ |
1270 | } |
1271 | } |
1272 | |
1273 | -void mrl::DisplayReport::report_vsync(unsigned int output_id) |
1274 | +void mrl::DisplayReport::report_vsync(unsigned int output_id, |
1275 | + graphics::Frame const& frame) |
1276 | { |
1277 | - using namespace std::chrono; |
1278 | - seconds const static report_interval{1}; |
1279 | - std::unique_lock<decltype(vsync_event_mutex)> lk(vsync_event_mutex); |
1280 | - auto now = clock->now(); |
1281 | - event_map[output_id]++; |
1282 | - if (now > last_report + report_interval) |
1283 | + std::lock_guard<decltype(vsync_event_mutex)> lk(vsync_event_mutex); |
1284 | + auto prev = prev_frame.find(output_id); |
1285 | + if (prev != prev_frame.end() && prev->second.msc < frame.msc) |
1286 | { |
1287 | - for(auto const& event : event_map) |
1288 | - logger->log(ml::Severity::informational, |
1289 | - std::to_string(event.second) + " vsync events on [" + |
1290 | - std::to_string(event.first) + "] over " + |
1291 | - std::to_string(duration_cast<milliseconds>(now - last_report).count()) + "ms", |
1292 | - component()); |
1293 | - event_map.clear(); |
1294 | - last_report = now; |
1295 | + auto const now = graphics::Frame::Timestamp::now(frame.ust.clock_id); |
1296 | + auto const age_ns = now.nanoseconds - frame.ust.nanoseconds; |
1297 | + auto const delta_ns = frame.ust.nanoseconds - |
1298 | + prev->second.ust.nanoseconds; |
1299 | + |
1300 | + // long long to match printf format on all architectures |
1301 | + const long long msc = frame.msc, |
1302 | + age_us = age_ns.count() / 1000, |
1303 | + interval_us = delta_ns.count() / |
1304 | + (1000*(frame.msc - prev->second.msc)), |
1305 | + hz100 = 100000000LL / interval_us; |
1306 | + |
1307 | + logger->log(component(), ml::Severity::informational, |
1308 | + "vsync on %u: #%lld, %lld.%03lldms %s, interval %lld.%03lldms (%lld.%02lldHz)", |
1309 | + output_id, |
1310 | + msc, |
1311 | + llabs(age_us/1000), llabs(age_us%1000), |
1312 | + age_us>=0 ? "ago" : "from now", |
1313 | + interval_us/1000, interval_us%1000, |
1314 | + hz100/100, hz100%100); |
1315 | } |
1316 | + prev_frame[output_id] = frame; |
1317 | } |
1318 | |
1319 | === modified file 'src/server/report/logging/display_report.h' |
1320 | --- src/server/report/logging/display_report.h 2016-09-12 07:00:54 +0000 |
1321 | +++ src/server/report/logging/display_report.h 2016-10-05 09:20:48 +0000 |
1322 | @@ -21,7 +21,7 @@ |
1323 | #define MIR_REPORT_LOGGING_DISPLAY_REPORTER_H_ |
1324 | |
1325 | #include "mir/graphics/display_report.h" |
1326 | -#include "mir/time/clock.h" |
1327 | +#include "mir/graphics/frame.h" |
1328 | |
1329 | #include <unordered_map> |
1330 | #include <memory> |
1331 | @@ -33,6 +33,7 @@ |
1332 | { |
1333 | class Logger; |
1334 | } |
1335 | +namespace graphics { struct Frame; } |
1336 | namespace report |
1337 | { |
1338 | namespace logging |
1339 | @@ -45,8 +46,7 @@ |
1340 | static const char* component(); |
1341 | |
1342 | DisplayReport( |
1343 | - std::shared_ptr<mir::logging::Logger> const& logger, |
1344 | - std::shared_ptr<time::Clock> const& clock); |
1345 | + std::shared_ptr<mir::logging::Logger> const& logger); |
1346 | |
1347 | virtual ~DisplayReport(); |
1348 | |
1349 | @@ -55,7 +55,7 @@ |
1350 | virtual void report_successful_egl_buffer_swap_on_construction() override; |
1351 | virtual void report_successful_drm_mode_set_crtc_on_construction() override; |
1352 | virtual void report_successful_display_construction() override; |
1353 | - virtual void report_vsync(unsigned int output_id) override; |
1354 | + virtual void report_vsync(unsigned int output_id, graphics::Frame const&) override; |
1355 | virtual void report_drm_master_failure(int error) override; |
1356 | virtual void report_vt_switch_away_failure() override; |
1357 | virtual void report_vt_switch_back_failure() override; |
1358 | @@ -67,10 +67,8 @@ |
1359 | |
1360 | private: |
1361 | std::shared_ptr<mir::logging::Logger> const logger; |
1362 | - std::shared_ptr<time::Clock> const clock; |
1363 | std::mutex vsync_event_mutex; |
1364 | - mir::time::Timestamp last_report; |
1365 | - std::unordered_map<unsigned int, unsigned int> event_map; |
1366 | + std::unordered_map<unsigned int, mir::graphics::Frame> prev_frame; |
1367 | }; |
1368 | } |
1369 | } |
1370 | |
1371 | === modified file 'src/server/report/logging/logging_report_factory.cpp' |
1372 | --- src/server/report/logging/logging_report_factory.cpp 2016-07-28 23:00:22 +0000 |
1373 | +++ src/server/report/logging/logging_report_factory.cpp 2016-10-05 09:20:48 +0000 |
1374 | @@ -47,7 +47,7 @@ |
1375 | |
1376 | std::shared_ptr<mir::graphics::DisplayReport> mr::LoggingReportFactory::create_display_report() |
1377 | { |
1378 | - return std::make_shared<logging::DisplayReport>(logger, clock); |
1379 | + return std::make_shared<logging::DisplayReport>(logger); |
1380 | } |
1381 | |
1382 | std::shared_ptr<mir::scene::SceneReport> mr::LoggingReportFactory::create_scene_report() |
1383 | |
1384 | === modified file 'src/server/report/lttng/display_report.cpp' |
1385 | --- src/server/report/lttng/display_report.cpp 2016-09-12 07:00:54 +0000 |
1386 | +++ src/server/report/lttng/display_report.cpp 2016-10-05 09:20:48 +0000 |
1387 | @@ -47,7 +47,8 @@ |
1388 | mir_tracepoint(mir_server_display, report_drm_master_failure, strerror(error)); |
1389 | } |
1390 | |
1391 | -void mir::report::lttng::DisplayReport::report_vsync(unsigned int output_id) |
1392 | +void mir::report::lttng::DisplayReport::report_vsync(unsigned int output_id, |
1393 | + mir::graphics::Frame const&) |
1394 | { |
1395 | mir_tracepoint(mir_server_display, report_vsync, output_id); |
1396 | } |
1397 | |
1398 | === modified file 'src/server/report/lttng/display_report.h' |
1399 | --- src/server/report/lttng/display_report.h 2016-09-12 07:00:54 +0000 |
1400 | +++ src/server/report/lttng/display_report.h 2016-10-05 09:20:48 +0000 |
1401 | @@ -45,7 +45,7 @@ |
1402 | virtual void report_drm_master_failure(int error) override; |
1403 | virtual void report_vt_switch_away_failure() override; |
1404 | virtual void report_vt_switch_back_failure() override; |
1405 | - virtual void report_vsync(unsigned int output_id) override; |
1406 | + virtual void report_vsync(unsigned int output_id, graphics::Frame const&) override; |
1407 | |
1408 | private: |
1409 | ServerTracepointProvider tp_provider; |
1410 | |
1411 | === modified file 'src/server/report/null/display_report.cpp' |
1412 | --- src/server/report/null/display_report.cpp 2015-04-28 07:54:10 +0000 |
1413 | +++ src/server/report/null/display_report.cpp 2016-10-05 09:20:48 +0000 |
1414 | @@ -29,4 +29,4 @@ |
1415 | void mrn::DisplayReport::report_vt_switch_away_failure() {} |
1416 | void mrn::DisplayReport::report_vt_switch_back_failure() {} |
1417 | void mrn::DisplayReport::report_egl_configuration(EGLDisplay, EGLConfig) {} |
1418 | -void mrn::DisplayReport::report_vsync(unsigned int) {} |
1419 | +void mrn::DisplayReport::report_vsync(unsigned int, mir::graphics::Frame const&) {} |
1420 | |
1421 | === modified file 'src/server/report/null/display_report.h' |
1422 | --- src/server/report/null/display_report.h 2016-09-12 07:00:54 +0000 |
1423 | +++ src/server/report/null/display_report.h 2016-10-05 09:20:48 +0000 |
1424 | @@ -43,7 +43,7 @@ |
1425 | void report_vt_switch_away_failure() override; |
1426 | void report_vt_switch_back_failure() override; |
1427 | void report_egl_configuration(EGLDisplay disp, EGLConfig cfg) override; |
1428 | - void report_vsync(unsigned int output_id) override; |
1429 | + void report_vsync(unsigned int output_id, graphics::Frame const&) override; |
1430 | }; |
1431 | } |
1432 | } |
1433 | |
1434 | === modified file 'tests/include/mir/test/doubles/mock_display.h' |
1435 | --- tests/include/mir/test/doubles/mock_display.h 2016-09-15 00:57:28 +0000 |
1436 | +++ tests/include/mir/test/doubles/mock_display.h 2016-10-05 09:20:48 +0000 |
1437 | @@ -51,6 +51,7 @@ |
1438 | MOCK_METHOD1(create_hardware_cursor, std::shared_ptr<graphics::Cursor>(std::shared_ptr<graphics::CursorImage> const&)); |
1439 | MOCK_METHOD2(create_virtual_output, std::unique_ptr<graphics::VirtualOutput>(int, int)); |
1440 | MOCK_METHOD0(native_display, graphics::NativeDisplay*()); |
1441 | + MOCK_CONST_METHOD1(last_frame_on, graphics::Frame(unsigned)); |
1442 | }; |
1443 | |
1444 | } |
1445 | |
1446 | === modified file 'tests/include/mir/test/doubles/mock_display_report.h' |
1447 | --- tests/include/mir/test/doubles/mock_display_report.h 2015-04-28 07:54:10 +0000 |
1448 | +++ tests/include/mir/test/doubles/mock_display_report.h 2016-10-05 09:20:48 +0000 |
1449 | @@ -20,7 +20,7 @@ |
1450 | #define MIR_TEST_DOUBLES_MOCK_DISPLAY_REPORT_H_ |
1451 | |
1452 | #include "mir/graphics/display_report.h" |
1453 | - |
1454 | +#include "mir/graphics/frame.h" // GMock can't live with just forward decls |
1455 | #include <gmock/gmock.h> |
1456 | |
1457 | namespace mir |
1458 | @@ -42,7 +42,7 @@ |
1459 | MOCK_METHOD0(report_vt_switch_away_failure, void()); |
1460 | MOCK_METHOD0(report_vt_switch_back_failure, void()); |
1461 | MOCK_METHOD2(report_egl_configuration, void(EGLDisplay,EGLConfig)); |
1462 | - MOCK_METHOD1(report_vsync, void(unsigned int)); |
1463 | + MOCK_METHOD2(report_vsync, void(unsigned int, graphics::Frame const&)); |
1464 | }; |
1465 | |
1466 | } |
1467 | |
1468 | === modified file 'tests/include/mir/test/doubles/mock_hwc_device_wrapper.h' |
1469 | --- tests/include/mir/test/doubles/mock_hwc_device_wrapper.h 2015-06-17 05:20:42 +0000 |
1470 | +++ tests/include/mir/test/doubles/mock_hwc_device_wrapper.h 2016-10-05 09:20:48 +0000 |
1471 | @@ -46,7 +46,7 @@ |
1472 | MOCK_CONST_METHOD1(display_on, void(graphics::android::DisplayName)); |
1473 | MOCK_CONST_METHOD1(display_off, void(graphics::android::DisplayName)); |
1474 | MOCK_METHOD4(subscribe_to_events, void(void const*, |
1475 | - std::function<void(graphics::android::DisplayName, std::chrono::nanoseconds)> const&, |
1476 | + std::function<void(graphics::android::DisplayName, mir::graphics::Frame::Timestamp)> const&, |
1477 | std::function<void(graphics::android::DisplayName, bool)> const&, |
1478 | std::function<void()> const&)); |
1479 | MOCK_METHOD1(unsubscribe_from_events_, void(void const*)); |
1480 | |
1481 | === modified file 'tests/include/mir/test/doubles/stub_display_builder.h' |
1482 | --- tests/include/mir/test/doubles/stub_display_builder.h 2016-08-24 02:09:08 +0000 |
1483 | +++ tests/include/mir/test/doubles/stub_display_builder.h 2016-10-05 09:20:48 +0000 |
1484 | @@ -57,7 +57,7 @@ |
1485 | MOCK_METHOD1(active_config_for, graphics::DisplayConfigurationOutput(graphics::android::DisplayName)); |
1486 | MOCK_METHOD2(subscribe_to_config_changes, |
1487 | graphics::android::ConfigChangeSubscription( |
1488 | - std::function<void()> const&, std::function<void(graphics::android::DisplayName)> const&)); |
1489 | + std::function<void()> const&, std::function<void(graphics::android::DisplayName, mir::graphics::Frame::Timestamp)> const&)); |
1490 | }; |
1491 | |
1492 | struct StubHwcConfiguration : public graphics::android::HwcConfiguration |
1493 | @@ -75,7 +75,10 @@ |
1494 | } |
1495 | |
1496 | graphics::android::ConfigChangeSubscription subscribe_to_config_changes( |
1497 | - std::function<void()> const&, std::function<void(graphics::android::DisplayName)> const&) override |
1498 | + std::function<void()> const&, |
1499 | + std::function<void(graphics::android::DisplayName, |
1500 | + graphics::Frame::Timestamp)> const& |
1501 | + ) override |
1502 | { |
1503 | return nullptr; |
1504 | } |
1505 | |
1506 | === modified file 'tests/mir_test_doubles/mock_egl.cpp' |
1507 | --- tests/mir_test_doubles/mock_egl.cpp 2016-07-15 09:37:28 +0000 |
1508 | +++ tests/mir_test_doubles/mock_egl.cpp 2016-10-05 09:20:48 +0000 |
1509 | @@ -49,6 +49,8 @@ |
1510 | EGLSyncKHR extension_eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list); |
1511 | EGLBoolean extension_eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync); |
1512 | EGLint extension_eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout); |
1513 | +EGLBoolean extension_eglGetSyncValuesCHROMIUM(EGLDisplay dpy, |
1514 | + EGLSurface surface, int64_t *ust, int64_t *msc, int64_t *sbc); |
1515 | |
1516 | /* EGL{Surface,Display,Config,Context} are all opaque types, so we can put whatever |
1517 | we want in them for testing */ |
1518 | @@ -144,6 +146,10 @@ |
1519 | .WillByDefault(Return(reinterpret_cast<func_ptr_t>(extension_eglDestroySyncKHR))); |
1520 | ON_CALL(*this, eglGetProcAddress(StrEq("eglClientWaitSyncKHR"))) |
1521 | .WillByDefault(Return(reinterpret_cast<func_ptr_t>(extension_eglClientWaitSyncKHR))); |
1522 | + ON_CALL(*this, eglGetProcAddress(StrEq("eglGetSyncValuesCHROMIUM"))) |
1523 | + .WillByDefault(Return( |
1524 | + reinterpret_cast<func_ptr_t>(extension_eglGetSyncValuesCHROMIUM) |
1525 | + )); |
1526 | } |
1527 | |
1528 | void mtd::MockEGL::provide_egl_extensions() |
1529 | @@ -416,3 +422,11 @@ |
1530 | CHECK_GLOBAL_MOCK(EGLint); |
1531 | return global_mock_egl->eglClientWaitSyncKHR(dpy, sync, flags, timeout); |
1532 | } |
1533 | + |
1534 | +EGLBoolean extension_eglGetSyncValuesCHROMIUM(EGLDisplay dpy, |
1535 | + EGLSurface surface, int64_t *ust, int64_t *msc, int64_t *sbc) |
1536 | +{ |
1537 | + CHECK_GLOBAL_MOCK(EGLBoolean); |
1538 | + return global_mock_egl->eglGetSyncValuesCHROMIUM(dpy, surface, |
1539 | + ust, msc, sbc); |
1540 | +} |
1541 | |
1542 | === modified file 'tests/mir_test_framework/stubbed_graphics_platform.cpp' |
1543 | --- tests/mir_test_framework/stubbed_graphics_platform.cpp 2016-09-22 16:27:13 +0000 |
1544 | +++ tests/mir_test_framework/stubbed_graphics_platform.cpp 2016-10-05 09:20:48 +0000 |
1545 | @@ -106,7 +106,10 @@ |
1546 | { |
1547 | return display->native_display(); |
1548 | } |
1549 | - |
1550 | + mg::Frame last_frame_on(unsigned output_id) const override |
1551 | + { |
1552 | + return display->last_frame_on(output_id); |
1553 | + } |
1554 | std::shared_ptr<Display> const display; |
1555 | }; |
1556 | |
1557 | |
1558 | === modified file 'tests/unit-tests/logging/test_display_report.cpp' |
1559 | --- tests/unit-tests/logging/test_display_report.cpp 2015-06-25 03:00:08 +0000 |
1560 | +++ tests/unit-tests/logging/test_display_report.cpp 2016-10-05 09:20:48 +0000 |
1561 | @@ -17,9 +17,9 @@ |
1562 | */ |
1563 | |
1564 | #include "src/server/report/logging/display_report.h" |
1565 | +#include "mir/graphics/frame.h" |
1566 | #include "mir/logging/logger.h" |
1567 | #include "mir/test/doubles/mock_egl.h" |
1568 | -#include "mir/test/doubles/advanceable_clock.h" |
1569 | |
1570 | #include <gtest/gtest.h> |
1571 | #include <gmock/gmock.h> |
1572 | @@ -40,7 +40,6 @@ |
1573 | |
1574 | struct DisplayReport : public testing::Test |
1575 | { |
1576 | - std::shared_ptr<mtd::AdvanceableClock> const clock{std::make_shared<mtd::AdvanceableClock>()}; |
1577 | std::shared_ptr<MockLogger> logger{std::make_shared<MockLogger>()}; |
1578 | mtd::MockEGL mock_egl; |
1579 | }; |
1580 | @@ -116,29 +115,71 @@ |
1581 | component)); |
1582 | } |
1583 | |
1584 | - mrl::DisplayReport report(logger, clock); |
1585 | + mrl::DisplayReport report(logger); |
1586 | report.report_egl_configuration(disp, config); |
1587 | } |
1588 | |
1589 | TEST_F(DisplayReport, reports_vsync) |
1590 | { |
1591 | - std::chrono::milliseconds interval(1500); |
1592 | + using namespace testing; |
1593 | + std::chrono::nanoseconds const nanos_per_frame{16666666}; |
1594 | + std::string const interval_str{"interval 16.666ms"}; |
1595 | unsigned int display1_id {1223}; |
1596 | unsigned int display2_id {4492}; |
1597 | - std::string display1_name(std::to_string(display1_id)); |
1598 | - std::string display2_name(std::to_string(display2_id)); |
1599 | - EXPECT_CALL(*logger, log( |
1600 | - ml::Severity::informational, |
1601 | - "2 vsync events on [" + display1_name + "] over " + std::to_string(interval.count()) + "ms", |
1602 | - component)); |
1603 | - EXPECT_CALL(*logger, log( |
1604 | - ml::Severity::informational, |
1605 | - "1 vsync events on [" + display2_name + "] over " + std::to_string(interval.count()) + "ms", |
1606 | - component)); |
1607 | - mrl::DisplayReport report(logger, clock); |
1608 | - |
1609 | - report.report_vsync(display1_id); |
1610 | - report.report_vsync(display2_id); |
1611 | - clock->advance_by(interval); |
1612 | - report.report_vsync(display1_id); |
1613 | + EXPECT_CALL(*logger, log( |
1614 | + ml::Severity::informational, |
1615 | + AllOf(StartsWith("vsync on "+std::to_string(display1_id)), |
1616 | + HasSubstr(interval_str)), |
1617 | + component)); |
1618 | + EXPECT_CALL(*logger, log( |
1619 | + ml::Severity::informational, |
1620 | + AllOf(StartsWith("vsync on "+std::to_string(display2_id)), |
1621 | + HasSubstr(interval_str)), |
1622 | + component)); |
1623 | + mrl::DisplayReport report(logger); |
1624 | + |
1625 | + mir::graphics::Frame frame; |
1626 | + report.report_vsync(display1_id, frame); |
1627 | + report.report_vsync(display2_id, frame); |
1628 | + frame.msc++; |
1629 | + frame.ust.nanoseconds += nanos_per_frame; |
1630 | + report.report_vsync(display1_id, frame); |
1631 | + report.report_vsync(display2_id, frame); |
1632 | +} |
1633 | + |
1634 | +TEST_F(DisplayReport, reports_vsync_steady_interval_despite_missed_frames) |
1635 | +{ |
1636 | + using namespace testing; |
1637 | + int const hz = 60; |
1638 | + std::string const interval_str{"interval 16.666ms (60.00Hz)"}; |
1639 | + unsigned const id{123}; |
1640 | + int const d1 = 456; |
1641 | + int const d2 = 789; |
1642 | + |
1643 | + InSequence seq; |
1644 | + |
1645 | + auto const id_str = std::to_string(id); |
1646 | + EXPECT_CALL(*logger, log( |
1647 | + ml::Severity::informational, |
1648 | + AllOf(StartsWith("vsync on "+id_str+": #"+std::to_string(d1)+","), |
1649 | + HasSubstr(interval_str)), |
1650 | + component)); |
1651 | + EXPECT_CALL(*logger, log( |
1652 | + ml::Severity::informational, |
1653 | + AllOf(StartsWith("vsync on "+id_str+": #"+std::to_string(d1+d2)+","), |
1654 | + HasSubstr(interval_str)), |
1655 | + component)); |
1656 | + |
1657 | + mrl::DisplayReport report(logger); |
1658 | + mir::graphics::Frame frame; |
1659 | + |
1660 | + std::chrono::nanoseconds const nanos_per_frame{1000000000LL/hz}; |
1661 | + |
1662 | + report.report_vsync(id, frame); |
1663 | + frame.msc += d1; |
1664 | + frame.ust.nanoseconds += d1 * nanos_per_frame; |
1665 | + report.report_vsync(id, frame); |
1666 | + frame.msc += d2; |
1667 | + frame.ust.nanoseconds += d2 * nanos_per_frame; |
1668 | + report.report_vsync(id, frame); |
1669 | } |
1670 | |
1671 | === modified file 'tests/unit-tests/platforms/android/server/test_display.cpp' |
1672 | --- tests/unit-tests/platforms/android/server/test_display.cpp 2016-09-19 06:09:48 +0000 |
1673 | +++ tests/unit-tests/platforms/android/server/test_display.cpp 2016-10-05 09:20:48 +0000 |
1674 | @@ -893,9 +893,9 @@ |
1675 | TEST_F(Display, reports_vsync) |
1676 | { |
1677 | using namespace testing; |
1678 | - std::function<void(mga::DisplayName)> vsync_fn = [](mga::DisplayName){}; |
1679 | + std::function<void(mga::DisplayName, mg::Frame::Timestamp)> vsync_fn = [](mga::DisplayName, mg::Frame::Timestamp){}; |
1680 | auto report = std::make_shared<NiceMock<mtd::MockDisplayReport>>(); |
1681 | - EXPECT_CALL(*report, report_vsync(_)); |
1682 | + EXPECT_CALL(*report, report_vsync(_, _)); |
1683 | stub_db_factory->with_next_config([&](mtd::MockHwcConfiguration& mock_config) |
1684 | { |
1685 | EXPECT_CALL(mock_config, subscribe_to_config_changes(_,_)) |
1686 | @@ -910,7 +910,7 @@ |
1687 | null_anw_report, |
1688 | mga::OverlayOptimization::enabled); |
1689 | |
1690 | - vsync_fn(mga::DisplayName::primary); |
1691 | + vsync_fn(mga::DisplayName::primary, {}); |
1692 | } |
1693 | |
1694 | TEST_F(Display, reports_correct_card_information) |
1695 | |
1696 | === modified file 'tests/unit-tests/platforms/android/server/test_display_hotplug.cpp' |
1697 | --- tests/unit-tests/platforms/android/server/test_display_hotplug.cpp 2016-07-20 04:54:07 +0000 |
1698 | +++ tests/unit-tests/platforms/android/server/test_display_hotplug.cpp 2016-10-05 09:20:48 +0000 |
1699 | @@ -49,7 +49,7 @@ |
1700 | return mtd::StubDisplayConfig({{true,true}}).outputs[0]; |
1701 | } |
1702 | mga::ConfigChangeSubscription subscribe_to_config_changes( |
1703 | - std::function<void()> const& cb, std::function<void(mga::DisplayName)> const&) override |
1704 | + std::function<void()> const& cb, std::function<void(mga::DisplayName, mg::Frame::Timestamp)> const&) override |
1705 | { |
1706 | hotplug_fn = cb; |
1707 | return {}; |
1708 | @@ -74,7 +74,7 @@ |
1709 | return wrapped.active_config_for(d); |
1710 | } |
1711 | mga::ConfigChangeSubscription subscribe_to_config_changes( |
1712 | - std::function<void()> const& hotplug, std::function<void(mga::DisplayName)> const& vsync) override |
1713 | + std::function<void()> const& hotplug, std::function<void(mga::DisplayName, mg::Frame::Timestamp)> const& vsync) override |
1714 | { |
1715 | return wrapped.subscribe_to_config_changes(hotplug, vsync); |
1716 | } |
1717 | |
1718 | === modified file 'tests/unit-tests/platforms/android/server/test_hwc_configuration.cpp' |
1719 | --- tests/unit-tests/platforms/android/server/test_hwc_configuration.cpp 2016-06-22 22:45:56 +0000 |
1720 | +++ tests/unit-tests/platforms/android/server/test_hwc_configuration.cpp 2016-10-05 09:20:48 +0000 |
1721 | @@ -23,6 +23,7 @@ |
1722 | #include <gtest/gtest.h> |
1723 | #include <chrono> |
1724 | |
1725 | +namespace mg = mir::graphics; |
1726 | namespace mga = mir::graphics::android; |
1727 | namespace mtd = mir::test::doubles; |
1728 | namespace geom = mir::geometry; |
1729 | @@ -271,8 +272,8 @@ |
1730 | { |
1731 | using namespace testing; |
1732 | std::function<void(mga::DisplayName, bool)> hotplug_fn([](mga::DisplayName, bool){}); |
1733 | - std::function<void(mga::DisplayName, std::chrono::nanoseconds)> vsync_fn( |
1734 | - [](mga::DisplayName, std::chrono::nanoseconds){}); |
1735 | + std::function<void(mga::DisplayName, mg::Frame::Timestamp)> vsync_fn( |
1736 | + [](mga::DisplayName, mg::Frame::Timestamp){}); |
1737 | EXPECT_CALL(*mock_hwc_wrapper, subscribe_to_events(_,_,_,_)) |
1738 | .WillOnce(DoAll(SaveArg<1>(&vsync_fn), SaveArg<2>(&hotplug_fn))); |
1739 | EXPECT_CALL(*mock_hwc_wrapper, unsubscribe_from_events_(_)); |
1740 | @@ -280,10 +281,11 @@ |
1741 | unsigned int hotplug_call_count{0}; |
1742 | unsigned int vsync_call_count{0}; |
1743 | auto subscription = config.subscribe_to_config_changes( |
1744 | - [&]{ hotplug_call_count++; }, [&](mga::DisplayName){ vsync_call_count++; }); |
1745 | - hotplug_fn(mga::DisplayName::primary, true); |
1746 | - hotplug_fn(mga::DisplayName::primary, true); |
1747 | - vsync_fn(mga::DisplayName::primary, std::chrono::nanoseconds(33)); |
1748 | + [&]{ hotplug_call_count++; }, [&](mga::DisplayName, mg::Frame::Timestamp){ vsync_call_count++; }); |
1749 | + hotplug_fn(mga::DisplayName::primary, true); |
1750 | + hotplug_fn(mga::DisplayName::primary, true); |
1751 | + using namespace std::literals::chrono_literals; |
1752 | + vsync_fn(mga::DisplayName::primary, mg::Frame::Timestamp{CLOCK_MONOTONIC,123ns}); |
1753 | EXPECT_THAT(hotplug_call_count, Eq(2)); |
1754 | EXPECT_THAT(vsync_call_count, Eq(1)); |
1755 | } |
1756 | |
1757 | === modified file 'tests/unit-tests/platforms/android/server/test_hwc_fb_device.cpp' |
1758 | --- tests/unit-tests/platforms/android/server/test_hwc_fb_device.cpp 2016-05-03 06:55:25 +0000 |
1759 | +++ tests/unit-tests/platforms/android/server/test_hwc_fb_device.cpp 2016-10-05 09:20:48 +0000 |
1760 | @@ -142,7 +142,7 @@ |
1761 | { |
1762 | using namespace testing; |
1763 | std::list<hwc_layer_1_t*> expected_list{&skip_layer}; |
1764 | - std::function<void(mga::DisplayName, std::chrono::nanoseconds)> vsync_cb; |
1765 | + std::function<void(mga::DisplayName, mg::Frame::Timestamp)> vsync_cb; |
1766 | EXPECT_CALL(*mock_hwc_device_wrapper, subscribe_to_events(_,_,_,_)) |
1767 | .WillOnce(SaveArg<1>(&vsync_cb)); |
1768 | mga::HwcFbDevice device(mock_hwc_device_wrapper, mock_fb_device); |
1769 | @@ -155,7 +155,7 @@ |
1770 | while(vsync_thread_on) |
1771 | { |
1772 | std::this_thread::sleep_for(std::chrono::microseconds(500)); |
1773 | - vsync_cb(mga::DisplayName::primary, std::chrono::nanoseconds(0)); |
1774 | + vsync_cb(mga::DisplayName::primary, mg::Frame::Timestamp{}); |
1775 | }}); |
1776 | |
1777 | Sequence seq; |
1778 | |
1779 | === modified file 'tests/unit-tests/platforms/android/server/test_hwc_wrapper.cpp' |
1780 | --- tests/unit-tests/platforms/android/server/test_hwc_wrapper.cpp 2016-08-24 02:09:08 +0000 |
1781 | +++ tests/unit-tests/platforms/android/server/test_hwc_wrapper.cpp 2016-10-05 09:20:48 +0000 |
1782 | @@ -23,6 +23,7 @@ |
1783 | #include <gmock/gmock.h> |
1784 | #include <gtest/gtest.h> |
1785 | |
1786 | +namespace mg = mir::graphics; |
1787 | namespace mga = mir::graphics::android; |
1788 | namespace mtd = mir::test::doubles; |
1789 | |
1790 | @@ -314,7 +315,7 @@ |
1791 | auto vsync_call_count = 0u; |
1792 | auto hotplug_call_count = 0u; |
1793 | wrapper.subscribe_to_events(this, |
1794 | - [&](mga::DisplayName, std::chrono::nanoseconds){vsync_call_count++;}, |
1795 | + [&](mga::DisplayName, mg::Frame::Timestamp){vsync_call_count++;}, |
1796 | [&](mga::DisplayName, bool){hotplug_call_count++;}, |
1797 | [&](){invalidate_call_count++;}); |
1798 | |
1799 | @@ -349,7 +350,7 @@ |
1800 | mga::RealHwcWrapper wrapper(mock_device, mock_report); |
1801 | wrapper.subscribe_to_events( |
1802 | this, |
1803 | - [&](mga::DisplayName, std::chrono::nanoseconds){ call_count++; }, |
1804 | + [&](mga::DisplayName, mg::Frame::Timestamp){ call_count++; }, |
1805 | [](mga::DisplayName, bool){}, |
1806 | []{}); |
1807 | |
1808 | |
1809 | === modified file 'tests/unit-tests/platforms/mesa/kms/mock_kms_output.h' |
1810 | --- tests/unit-tests/platforms/mesa/kms/mock_kms_output.h 2016-09-01 17:02:56 +0000 |
1811 | +++ tests/unit-tests/platforms/mesa/kms/mock_kms_output.h 2016-10-05 09:20:48 +0000 |
1812 | @@ -39,6 +39,8 @@ |
1813 | MOCK_METHOD1(schedule_page_flip, bool(uint32_t)); |
1814 | MOCK_METHOD0(wait_for_page_flip, void()); |
1815 | |
1816 | + MOCK_CONST_METHOD0(last_frame, graphics::Frame()); |
1817 | + |
1818 | MOCK_METHOD1(set_cursor, void(gbm_bo*)); |
1819 | MOCK_METHOD1(move_cursor, void(geometry::Point)); |
1820 | MOCK_METHOD0(clear_cursor, void()); |
1821 | |
1822 | === modified file 'tests/unit-tests/platforms/mesa/kms/test_display.cpp' |
1823 | --- tests/unit-tests/platforms/mesa/kms/test_display.cpp 2016-08-23 20:21:27 +0000 |
1824 | +++ tests/unit-tests/platforms/mesa/kms/test_display.cpp 2016-10-05 09:20:48 +0000 |
1825 | @@ -30,7 +30,6 @@ |
1826 | |
1827 | #include "mir/test/doubles/mock_egl.h" |
1828 | #include "mir/test/doubles/mock_gl.h" |
1829 | -#include "mir/test/doubles/advanceable_clock.h" |
1830 | #include "src/server/report/null_report_factory.h" |
1831 | #include "mir/test/doubles/mock_display_report.h" |
1832 | #include "mir/test/doubles/null_virtual_terminal.h" |
1833 | @@ -534,7 +533,7 @@ |
1834 | using namespace ::testing; |
1835 | |
1836 | auto logger = std::make_shared<MockLogger>(); |
1837 | - auto reporter = std::make_shared<mrl::DisplayReport>(logger, std::make_shared<mtd::AdvanceableClock>()); |
1838 | + auto reporter = std::make_shared<mrl::DisplayReport>(logger); |
1839 | |
1840 | EXPECT_CALL( |
1841 | *logger, |
1842 | @@ -550,7 +549,7 @@ |
1843 | using namespace ::testing; |
1844 | |
1845 | auto logger = std::make_shared<MockLogger>(); |
1846 | - auto reporter = std::make_shared<mrl::DisplayReport>(logger, std::make_shared<mtd::AdvanceableClock>()); |
1847 | + auto reporter = std::make_shared<mrl::DisplayReport>(logger); |
1848 | |
1849 | EXPECT_CALL( |
1850 | *logger, |
1851 | @@ -566,7 +565,7 @@ |
1852 | using namespace ::testing; |
1853 | |
1854 | auto logger = std::make_shared<MockLogger>(); |
1855 | - auto reporter = std::make_shared<mrl::DisplayReport>(logger, std::make_shared<mtd::AdvanceableClock>()); |
1856 | + auto reporter = std::make_shared<mrl::DisplayReport>(logger); |
1857 | |
1858 | EXPECT_CALL( |
1859 | *logger, |
1860 | @@ -582,7 +581,7 @@ |
1861 | using namespace ::testing; |
1862 | |
1863 | auto logger = std::make_shared<MockLogger>(); |
1864 | - auto reporter = std::make_shared<mrl::DisplayReport>(logger, std::make_shared<mtd::AdvanceableClock>()); |
1865 | + auto reporter = std::make_shared<mrl::DisplayReport>(logger); |
1866 | |
1867 | EXPECT_CALL( |
1868 | *logger, |
1869 | |
1870 | === modified file 'tests/unit-tests/platforms/mesa/kms/test_kms_page_flipper.cpp' |
1871 | --- tests/unit-tests/platforms/mesa/kms/test_kms_page_flipper.cpp 2016-09-13 07:24:11 +0000 |
1872 | +++ tests/unit-tests/platforms/mesa/kms/test_kms_page_flipper.cpp 2016-10-05 09:20:48 +0000 |
1873 | @@ -139,7 +139,7 @@ |
1874 | |
1875 | // Regression test for LP: #1621352 |
1876 | ASSERT_NE(crtc_id, connector_id); |
1877 | - EXPECT_CALL(report, report_vsync(connector_id)); |
1878 | + EXPECT_CALL(report, report_vsync(connector_id, _)); |
1879 | |
1880 | page_flipper.schedule_flip(crtc_id, fb_id, connector_id); |
1881 | EXPECT_EQ(1, write(mock_drm.fake_drm.write_fd(), "a", 1)); |
1882 | |
1883 | === modified file 'tests/unit-tests/platforms/mesa/kms/test_real_kms_output.cpp' |
1884 | --- tests/unit-tests/platforms/mesa/kms/test_real_kms_output.cpp 2016-09-09 07:47:18 +0000 |
1885 | +++ tests/unit-tests/platforms/mesa/kms/test_real_kms_output.cpp 2016-10-05 09:20:48 +0000 |
1886 | @@ -36,6 +36,8 @@ |
1887 | namespace mt = mir::test; |
1888 | namespace mtd = mir::test::doubles; |
1889 | |
1890 | +using namespace ::testing; |
1891 | + |
1892 | namespace |
1893 | { |
1894 | |
1895 | @@ -43,14 +45,14 @@ |
1896 | { |
1897 | public: |
1898 | bool schedule_flip(uint32_t,uint32_t,uint32_t) override { return true; } |
1899 | - void wait_for_flip(uint32_t) override { } |
1900 | + mg::Frame wait_for_flip(uint32_t) override { return {}; } |
1901 | }; |
1902 | |
1903 | class MockPageFlipper : public mgm::PageFlipper |
1904 | { |
1905 | public: |
1906 | MOCK_METHOD3(schedule_flip, bool(uint32_t,uint32_t,uint32_t)); |
1907 | - MOCK_METHOD1(wait_for_flip, void(uint32_t)); |
1908 | + MOCK_METHOD1(wait_for_flip, mg::Frame(uint32_t)); |
1909 | }; |
1910 | |
1911 | class RealKMSOutputTest : public ::testing::Test |
1912 | @@ -62,6 +64,8 @@ |
1913 | possible_encoder_ids1{encoder_ids[0]}, |
1914 | possible_encoder_ids2{encoder_ids[0], encoder_ids[1]} |
1915 | { |
1916 | + ON_CALL(mock_page_flipper, wait_for_flip(_)) |
1917 | + .WillByDefault(Return(mg::Frame{})); |
1918 | } |
1919 | |
1920 | void setup_outputs_connected_crtc() |
1921 | |
1922 | === modified file 'tests/unit-tests/platforms/mesa/x11/test_display.cpp' |
1923 | --- tests/unit-tests/platforms/mesa/x11/test_display.cpp 2016-10-04 08:15:29 +0000 |
1924 | +++ tests/unit-tests/platforms/mesa/x11/test_display.cpp 2016-10-05 09:20:48 +0000 |
1925 | @@ -52,6 +52,9 @@ |
1926 | using namespace testing; |
1927 | EGLint const client_version = 2; |
1928 | |
1929 | + ON_CALL(mock_egl, eglQueryString(_, EGL_EXTENSIONS)) |
1930 | + .WillByDefault(Return("other stuff and EGL_CHROMIUM_sync_control")); |
1931 | + |
1932 | ON_CALL(mock_egl, eglQueryContext(mock_egl.fake_egl_display, |
1933 | mock_egl.fake_egl_context, |
1934 | EGL_CONTEXT_CLIENT_VERSION, |
FAILED: Continuous integration, rev:3639 /mir-jenkins. ubuntu. com/job/ mir-ci/ 1772/ /mir-jenkins. ubuntu. com/job/ build-mir/ 2220/console /mir-jenkins. ubuntu. com/job/ build-0- fetch/2283 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= vivid+overlay/ 2274 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= xenial+ overlay/ 2274 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= yakkety/ 2274 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= yakkety/ 2248 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= yakkety/ 2248/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= xenial+ overlay/ 2248 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= xenial+ overlay/ 2248/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= yakkety/ 2248 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= yakkety/ 2248/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= android, release= vivid+overlay/ 2248/console /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= mesa,release= xenial+ overlay/ 2248 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= mesa,release= xenial+ overlay/ 2248/artifact/ output/ *zip*/output. zip
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild: /mir-jenkins. ubuntu. com/job/ mir-ci/ 1772/rebuild
https:/