2 * Copyright © 2014 The TOVA Company
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
26 * Validates that OML Sync Control implementation actually syncs to vertical
30 #include "piglit-util-gl.h"
31 #include "piglit-glx-util.h"
34 * TODO: varying MSC deltas enumerated as arguments
35 * TODO: As a different test, create two drawables and verify they have
38 static bool fullscreen
;
39 static bool use_swapbuffers
= true;
40 static int64_t target_msc_delta
;
41 static int64_t divisor
;
42 static const int64_t msc_remainder
= 0;
43 static const unsigned int loops
= 10;
51 static void update_stats(struct stats
*stats
, double val
) {
52 double delta
= val
- stats
->mean
;
54 stats
->mean
+= delta
/ stats
->n
;
55 stats
->M2
+= delta
* (val
- stats
->mean
);
58 static double get_stddev(struct stats
*stats
) {
59 return sqrt(stats
->M2
/ (stats
->n
- 1));
63 swap_buffers_msc(Display
*dpy
, int64_t last_sbc
, int64_t *target_sbc
,
64 int64_t target_msc
, int64_t divisor
, int64_t remainder
,
65 int64_t *new_ust
, int64_t *new_msc
, int64_t *new_sbc
,
66 enum piglit_result
*result
)
68 glClearColor(0.0, 1.0, 0.0, 0.0);
69 glClear(GL_COLOR_BUFFER_BIT
);
71 *target_sbc
= glXSwapBuffersMscOML(dpy
, win
, target_msc
, divisor
,
73 if (*target_sbc
<= 0) {
74 fprintf(stderr
, "SwapBuffersMscOML failed\n");
78 if (*target_sbc
!= last_sbc
+ 1) {
80 "glXSwapBuffersMscOML calculated the wrong target sbc: "
81 "expected %"PRId64
" but got %"PRId64
"\n", last_sbc
+ 1,
83 *result
= PIGLIT_FAIL
;
86 if (!glXWaitForSbcOML(dpy
, win
, *target_sbc
, new_ust
, new_msc
,
88 fprintf(stderr
, "glXWaitForSbcOML failed\n");
89 *result
= PIGLIT_FAIL
;
96 wait_for_msc(Display
*dpy
, int64_t target_msc
, int64_t divisor
,
97 int64_t remainder
, int64_t *new_ust
, int64_t *new_msc
,
98 int64_t *new_sbc
, enum piglit_result
*result
)
100 if (!glXWaitForMscOML(dpy
, win
, target_msc
, divisor
, remainder
,
101 new_ust
, new_msc
, new_sbc
)) {
102 fprintf(stderr
, "glXWaitForMscOML failed\n");
103 *result
= PIGLIT_FAIL
;
107 static enum piglit_result
110 enum piglit_result result
= PIGLIT_PASS
;
111 int64_t last_ust
= 0xd0, last_msc
= 0xd0, last_sbc
= 0xd0;
112 int64_t last_timestamp
= -1; /* in nano seconds */
113 struct stats msc_wallclock_duration_stats
= {};
114 struct stats msc_ust_duration_stats
= {};
115 double expected_msc_wallclock_duration
= 0.0;
116 int32_t rate_num
, rate_den
;
119 if (!glXGetSyncValuesOML(dpy
, win
, &last_ust
, &last_msc
, &last_sbc
)) {
120 fprintf(stderr
, "Initial glXGetSyncValuesOML failed\n");
124 /* Check that the window is fresh */
126 fprintf(stderr
, "Initial SBC for the window should be 0, was "
129 piglit_merge_result(&result
, PIGLIT_WARN
);
132 if (!glXGetMscRateOML(dpy
, win
, &rate_num
, &rate_den
)) {
134 "glXGetMscRateOML failed, can't test MSC duration\n");
135 piglit_merge_result(&result
, PIGLIT_WARN
);
137 expected_msc_wallclock_duration
= 1e6
* rate_den
/ rate_num
;
140 piglit_set_timeout(5, PIGLIT_FAIL
);
143 for (i
= 0; i
< loops
; i
++) {
144 int64_t new_ust
= 0xd0, new_msc
= 0xd0, new_sbc
= 0xd0;
145 int64_t check_ust
= 0xd0, check_msc
= 0xd0, check_sbc
= 0xd0;
146 int64_t new_timestamp
; /* in nano seconds */
147 int64_t expected_msc
, target_sbc
;
148 int64_t target_msc
= 0;
150 if (target_msc_delta
) {
151 target_msc
= last_msc
+ target_msc_delta
;
154 if (use_swapbuffers
) {
155 if (!swap_buffers_msc(dpy
, last_sbc
, &target_sbc
,
157 msc_remainder
, &new_ust
, &new_msc
,
161 target_sbc
= last_sbc
;
162 wait_for_msc(dpy
, target_msc
, divisor
, msc_remainder
,
163 &new_ust
, &new_msc
, &new_sbc
, &result
);
165 new_timestamp
= piglit_time_get_nano();
167 if (!glXGetSyncValuesOML(dpy
, win
,
168 &check_ust
, &check_msc
, &check_sbc
))
170 fprintf(stderr
, "Follow-up GetSyncValuesOML failed\n");
174 if (new_ust
< last_ust
) {
175 fprintf(stderr
, "iteration %u: non-monotonic UST went "
176 "backward by %"PRId64
" during Wait\n",
177 i
, last_ust
- new_ust
);
178 result
= PIGLIT_FAIL
;
179 /* Wait returned something bogus, but GetSyncValues
180 * usually works, so try evaluating the rest of the
181 * tests using the check values. */
185 if (check_ust
< new_ust
) {
186 fprintf(stderr
, "iteration %u: non-monotonic UST went "
187 "backward by %"PRId64
" across GetSyncValues\n",
188 i
, last_ust
- check_ust
);
189 result
= PIGLIT_FAIL
;
192 if (new_msc
< last_msc
) {
193 fprintf(stderr
, "iteration %u: non-monotonic MSC went "
194 "backward by %"PRId64
" during Wait\n",
195 i
, last_msc
- new_msc
);
196 result
= PIGLIT_FAIL
;
197 /* Wait returned something bogus, but GetSyncValues
198 * usually works, so try evaluating the rest of the
199 * tests using the check values. */
203 if (check_msc
< new_msc
) {
204 fprintf(stderr
, "iteration %u: non-monotonic MSC went "
205 "backward by %"PRId64
" across GetSyncValues\n",
206 i
, last_msc
- check_msc
);
207 result
= PIGLIT_FAIL
;
210 if (new_sbc
!= target_sbc
) {
211 fprintf(stderr
, "iteration %u: Wait should have "
212 "returned at SBC %"PRId64
" but returned at "
214 i
, target_sbc
, new_sbc
);
215 result
= PIGLIT_FAIL
;
218 if (check_sbc
!= new_sbc
) {
219 fprintf(stderr
, "iteration %u: GetSyncValues "
220 "returned SBC %"PRId64
" but Wait returned "
222 i
, check_sbc
, new_sbc
);
223 result
= PIGLIT_FAIL
;
226 if (new_msc
> last_msc
) {
227 int64_t delta_msc
= new_msc
- last_msc
;
228 update_stats(&msc_ust_duration_stats
,
229 (new_ust
- last_ust
) / delta_msc
);
231 if (last_timestamp
>= 0) {
232 if (!piglit_time_is_monotonic()) {
234 "no monotonic clock\n");
235 piglit_merge_result(&result
,
239 &msc_wallclock_duration_stats
,
240 (new_timestamp
- last_timestamp
)
246 expected_msc
= target_msc
;
248 /* If there is a divisor, the expected MSC is the
249 * next MSC after last_msc such that
250 * MSC % divisor == remainder
252 int64_t last_remainder
= last_msc
% divisor
;
253 expected_msc
= last_msc
- last_remainder
+ msc_remainder
;
254 if (expected_msc
<= last_msc
)
255 expected_msc
+= divisor
;
258 if (new_msc
< expected_msc
) {
259 fprintf(stderr
, "iteration %u woke up %"PRId64
261 i
, expected_msc
- new_msc
);
262 result
= PIGLIT_FAIL
;
265 if (new_msc
> expected_msc
) {
266 fprintf(stderr
, "iteration %u woke up %"PRId64
267 " MSCs later than expected\n",
268 i
, new_msc
- expected_msc
);
269 piglit_merge_result(&result
, PIGLIT_WARN
);
272 if (new_msc
% divisor
!= msc_remainder
) {
273 fprintf(stderr
, "iteration %u woke up at wrong MSC"
274 " remainder %"PRId64
", not requested remainder"
276 i
, new_msc
% divisor
, msc_remainder
);
277 result
= PIGLIT_FAIL
;
283 last_timestamp
= new_timestamp
;
286 if (msc_ust_duration_stats
.n
< 2) {
287 fprintf(stderr
, "Not enough UST timing samples\n");
288 piglit_merge_result(&result
, PIGLIT_WARN
);
289 } else if (expected_msc_wallclock_duration
> 0.0) {
290 double apparent_ust_rate
= msc_ust_duration_stats
.mean
/
291 expected_msc_wallclock_duration
;
292 if (get_stddev(&msc_ust_duration_stats
) /
293 apparent_ust_rate
> 100)
295 fprintf(stderr
, "UST duration per MSC is surprisingly"
296 " variable (stddev %f USTs), but then it only"
297 " has to be monotonic\n",
298 get_stddev(&msc_ust_duration_stats
));
299 piglit_merge_result(&result
, PIGLIT_WARN
);
303 if (msc_wallclock_duration_stats
.n
< 2) {
304 fprintf(stderr
, "Not enough wallclock timing samples\n");
305 piglit_merge_result(&result
, PIGLIT_WARN
);
306 } else if (get_stddev(&msc_wallclock_duration_stats
) > 1000) {
307 fprintf(stderr
, "Wallclock time between MSCs has stddev > 1ms"
308 " (%fus), driver is probably not syncing to"
310 get_stddev(&msc_wallclock_duration_stats
));
311 result
= PIGLIT_FAIL
;
312 } else if (expected_msc_wallclock_duration
> 0.0) {
313 if (fabs(expected_msc_wallclock_duration
-
314 msc_wallclock_duration_stats
.mean
) > 50)
316 fprintf(stderr
, "Wallclock time between MSCs %fus"
317 " does not match glXGetMscRateOML %fus\n",
318 msc_wallclock_duration_stats
.mean
,
319 expected_msc_wallclock_duration
);
320 result
= PIGLIT_FAIL
;
328 parse_num_arg(int argc
, char **argv
, int j
)
334 fprintf(stderr
, "%s requires an argument\n", argv
[j
- 1]);
335 piglit_report_result(PIGLIT_FAIL
);
338 val
= strtoul(argv
[j
], &ptr
, 0);
339 if (!val
|| *ptr
!= '\0') {
340 fprintf(stderr
, "%s requires an argument\n", argv
[j
- 1]);
341 piglit_report_result(PIGLIT_FAIL
);
348 main(int argc
, char **argv
)
351 for (j
= 1; j
< argc
; j
++) {
352 if (!strcmp(argv
[j
], "-fullscreen")) {
354 } else if (!strcmp(argv
[j
], "-waitformsc")) {
355 use_swapbuffers
= false;
356 } else if (!strcmp(argv
[j
], "-divisor")) {
358 divisor
= parse_num_arg(argc
, argv
, j
);
359 } else if (!strcmp(argv
[j
], "-msc-delta")) {
361 target_msc_delta
= parse_num_arg(argc
, argv
, j
);
362 } else if (!strcmp(argv
[j
], "-auto")) {
363 piglit_automatic
= true;
365 fprintf(stderr
, "unsupported option %s\n", argv
[j
]);
366 piglit_report_result(PIGLIT_FAIL
);
370 if (divisor
&& target_msc_delta
) {
371 fprintf(stderr
, "this test doesn't support using both "
372 "-divisor and -msc-delta\n");
373 piglit_report_result(PIGLIT_FAIL
);
376 if (!use_swapbuffers
&& !divisor
&& !target_msc_delta
) {
377 fprintf(stderr
, "when using -waitformsc, this test requires "
378 "either -divisor or -msc-delta\n");
379 piglit_report_result(PIGLIT_FAIL
);
385 piglit_automatic
= true;
386 piglit_oml_sync_control_test_run(fullscreen
, draw
);