enum piglit_result run_test(GLenum test_format, GLenum test_type, float *time_out) { bool pass = true; int64_t time; GLuint tex; int i, Bpp, channels; float *tmp, *expected, *observed; void *data; glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D, tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); channels = num_channels(test_format); Bpp = bytes_per_pixel(test_format, test_type); if (test_type == GL_FLOAT) { /* Sanatize so we don't get invalid floating point values */ tmp = malloc(texture_size * texture_size * channels * sizeof(float)); for (i = 0; i < texture_size * texture_size * channels; ++i) tmp[i] = sn_to_float(32, ((GLint *)rand_data)[i]); data = tmp; } else { tmp = NULL; data = rand_data; } expected = malloc(texture_size * texture_size * 4 * sizeof(float)); for (i = 0; i < texture_size * texture_size; ++i) to_expected(test_format, test_type, (GLubyte *)data + (i * Bpp), expected + 4 * i); if (benchmark) { time = piglit_get_microseconds(); for (i = 0; i < BENCHMARK_ITERATIONS; ++i) glTexImage2D(GL_TEXTURE_2D, 0, format->internal_format, texture_size, texture_size, 0, test_format, test_type, data); time = piglit_get_microseconds() - time; *time_out = (double)time / (double)BENCHMARK_ITERATIONS; } else { glTexImage2D(GL_TEXTURE_2D, 0, format->internal_format, texture_size, texture_size, 0, test_format, test_type, data); } pass &= piglit_check_gl_error(GL_NO_ERROR); if (is_format_signed(format->internal_format)) { glUseProgram(signed_prog); for (i = 0; i < texture_size * texture_size * 4; ++i) expected[i] = 0.5 + 0.5 * expected[i]; } else { glUseProgram(unsigned_prog); } piglit_draw_rect_tex(0, 0, texture_size, texture_size, 0, 0, 1, 1); observed = malloc(texture_size * texture_size * 4 * sizeof(float)); glReadPixels(0, 0, texture_size, texture_size, GL_RGBA, GL_FLOAT, observed); pass &= piglit_check_gl_error(GL_NO_ERROR); pass &= piglit_compare_images_color(0, 0, texture_size, texture_size, 4, tolerance, expected, observed); free(observed); free(expected); free(tmp); piglit_report_subtest_result(pass ? PIGLIT_PASS : PIGLIT_FAIL, "%s texture with %s and %s", piglit_get_gl_enum_name(format->internal_format), piglit_get_gl_enum_name(test_format), piglit_get_gl_enum_name(test_type)); glDeleteTextures(1, &tex); return pass; }
static enum piglit_result draw(Display *dpy) { enum piglit_result result = PIGLIT_PASS; int64_t last_ust = 0xd0, last_msc = 0xd0, last_sbc = 0xd0; int64_t last_timestamp = -1; struct stats msc_wallclock_duration_stats = {}; struct stats msc_ust_duration_stats = {}; double expected_msc_wallclock_duration = 0.0; int32_t rate_num, rate_den; unsigned int i; if (!glXGetSyncValuesOML(dpy, win, &last_ust, &last_msc, &last_sbc)) { fprintf(stderr, "Initial glXGetSyncValuesOML failed\n"); return PIGLIT_FAIL; } /* Check that the window is fresh */ if (last_sbc != 0) { fprintf(stderr, "Initial SBC for the window should be 0, was " "%" PRId64 "\n", last_sbc); piglit_merge_result(&result, PIGLIT_WARN); } if (!glXGetMscRateOML(dpy, win, &rate_num, &rate_den)) { fprintf(stderr, "glXGetMscRateOML failed, can't test MSC duration\n"); piglit_merge_result(&result, PIGLIT_WARN); } else { expected_msc_wallclock_duration = 1e6 * rate_den / rate_num; } piglit_set_timeout(5, PIGLIT_FAIL); for (i = 0; i < loops; i++) { int64_t new_ust = 0xd0, new_msc = 0xd0, new_sbc = 0xd0; int64_t check_ust = 0xd0, check_msc = 0xd0, check_sbc = 0xd0; int64_t new_timestamp; int64_t expected_msc, target_sbc; int64_t target_msc = 0; if (target_msc_delta) { target_msc = last_msc + target_msc_delta; } if (use_swapbuffers) { glClearColor(0.0, 1.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); target_sbc = glXSwapBuffersMscOML(dpy, win, target_msc, divisor, msc_remainder); if(target_sbc <= 0) { fprintf(stderr, "SwapBuffersMscOML failed\n"); return PIGLIT_FAIL; } if(target_sbc != last_sbc + 1) { fprintf(stderr, "glXSwapBuffersMscOML calculated the" " wrong target sbc: expected %"PRId64 " but got %"PRId64"\n", last_sbc + 1, target_sbc); result = PIGLIT_FAIL; } if(!glXWaitForSbcOML(dpy, win, target_sbc, &new_ust, &new_msc, &new_sbc)) { fprintf(stderr, "glXWaitForSbcOML failed\n"); result = PIGLIT_FAIL; } } else { target_sbc = last_sbc; if(!glXWaitForMscOML(dpy, win, target_msc, divisor, msc_remainder, &new_ust, &new_msc, &new_sbc)) { fprintf(stderr, "glXWaitForSbcOML failed\n"); result = PIGLIT_FAIL; } } new_timestamp = piglit_get_microseconds(); if (!glXGetSyncValuesOML(dpy, win, &check_ust, &check_msc, &check_sbc)) { fprintf(stderr, "Follow-up GetSyncValuesOML failed\n"); return PIGLIT_FAIL; } if (new_ust < last_ust) { fprintf(stderr, "iteration %u: non-monotonic UST went " "backward by %"PRId64" during Wait\n", i, last_ust - new_ust); result = PIGLIT_FAIL; /* Wait returned something bogus, but GetSyncValues * usually works, so try evaluating the rest of the * tests using the check values. */ new_ust = check_ust; } if (check_ust < new_ust) { fprintf(stderr, "iteration %u: non-monotonic UST went " "backward by %"PRId64" across GetSyncValues\n", i, last_ust - check_ust); result = PIGLIT_FAIL; } if (new_msc < last_msc) { fprintf(stderr, "iteration %u: non-monotonic MSC went " "backward by %"PRId64" during Wait\n", i, last_msc - new_msc); result = PIGLIT_FAIL; /* Wait returned something bogus, but GetSyncValues * usually works, so try evaluating the rest of the * tests using the check values. */ new_msc = check_msc; } if (check_msc < new_msc) { fprintf(stderr, "iteration %u: non-monotonic MSC went " "backward by %"PRId64" across GetSyncValues\n", i, last_msc - check_msc); result = PIGLIT_FAIL; } if (new_sbc != target_sbc) { fprintf(stderr, "iteration %u: Wait should have " "returned at SBC %"PRId64" but returned at " "%"PRId64"\n", i, target_sbc, new_sbc); result = PIGLIT_FAIL; } if (check_sbc != new_sbc) { fprintf(stderr, "iteration %u: GetSyncValues " "returned SBC %"PRId64" but Wait returned " "%"PRId64"\n", i, check_sbc, new_sbc); result = PIGLIT_FAIL; } if (new_msc > last_msc) { int64_t delta_msc = new_msc - last_msc; update_stats(&msc_ust_duration_stats, (new_ust - last_ust) / delta_msc); if (last_timestamp >= 0) { if (new_timestamp < 0) { fprintf(stderr, "no monotonic clock\n"); piglit_merge_result(&result, PIGLIT_WARN); } else { update_stats( &msc_wallclock_duration_stats, (new_timestamp - last_timestamp) / delta_msc); } } } expected_msc = target_msc; if (!target_msc) { /* If there is a divisor, the expected MSC is the * next MSC after last_msc such that * MSC % divisor == remainder */ int64_t last_remainder = last_msc % divisor; expected_msc = last_msc - last_remainder + msc_remainder; if (expected_msc <= last_msc) expected_msc += divisor; } if (new_msc < expected_msc) { fprintf(stderr, "iteration %u woke up %"PRId64 " MSCs early\n", i, expected_msc - new_msc); result = PIGLIT_FAIL; } if (new_msc > expected_msc) { fprintf(stderr, "iteration %u woke up %"PRId64 " MSCs later than expected\n", i, new_msc - expected_msc); piglit_merge_result(&result, PIGLIT_WARN); } if (new_msc % divisor != msc_remainder) { fprintf(stderr, "iteration %u woke up at wrong MSC" " remainder %"PRId64", not requested remainder" " %"PRId64"\n", i, new_msc % divisor, msc_remainder); result = PIGLIT_FAIL; } last_ust = new_ust; last_msc = new_msc; last_sbc = new_sbc; last_timestamp = new_timestamp; } if (msc_ust_duration_stats.n < 2) { fprintf(stderr, "Not enough UST timing samples\n"); piglit_merge_result(&result, PIGLIT_WARN); } else if (expected_msc_wallclock_duration > 0.0) { double apparent_ust_rate = msc_ust_duration_stats.mean / expected_msc_wallclock_duration; if (get_stddev(&msc_ust_duration_stats) / apparent_ust_rate > 100) { fprintf(stderr, "UST duration per MSC is surprisingly" " variable (stddev %f USTs), but then it only" " has to be monotonic\n", get_stddev(&msc_ust_duration_stats)); piglit_merge_result(&result, PIGLIT_WARN); } } if (msc_wallclock_duration_stats.n < 2) { fprintf(stderr, "Not enough wallclock timing samples\n"); piglit_merge_result(&result, PIGLIT_WARN); } else if (get_stddev(&msc_wallclock_duration_stats) > 1000) { fprintf(stderr, "Wallclock time between MSCs has stddev > 1ms" " (%fus), driver is probably not syncing to" " vblank\n", get_stddev(&msc_wallclock_duration_stats)); result = PIGLIT_FAIL; } else if (expected_msc_wallclock_duration > 0.0) { if (fabs(expected_msc_wallclock_duration - msc_wallclock_duration_stats.mean) > 50) { fprintf(stderr, "Wallclock time between MSCs %fus" " does not match glXGetMscRateOML %fus\n", msc_wallclock_duration_stats.mean, expected_msc_wallclock_duration); result = PIGLIT_FAIL; } } return result; }