/************************************************************************** * * Copyright 2020 Google LLC * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * **************************************************************************/ /* * basic library initialisation, teardown, reset * and context creation tests. */ #include #include #include #include #include #include #include "testvirgl.h" START_TEST(virgl_fence_create) { int ret; ret = testvirgl_init_single_ctx(); ck_assert_int_eq(ret, 0); testvirgl_reset_fence(); ret = virgl_renderer_create_fence(1, 0); ck_assert_int_eq(ret, 0); testvirgl_fini_single_ctx(); } END_TEST START_TEST(virgl_fence_poll) { const int target_seqno = 50; int ret; ret = testvirgl_init_single_ctx(); ck_assert_int_eq(ret, 0); testvirgl_reset_fence(); ret = virgl_renderer_create_fence(target_seqno, 0); ck_assert_int_eq(ret, 0); do { int seqno; virgl_renderer_poll(); seqno = testvirgl_get_last_fence(); if (seqno == target_seqno) break; ck_assert_int_eq(seqno, 0); usleep(1000); } while(1); testvirgl_fini_single_ctx(); } END_TEST START_TEST(virgl_fence_poll_many) { const int fence_count = 100; const int base_seqno = 50; const int target_seqno = base_seqno + fence_count - 1; int last_seqno; int ret; int i; ret = testvirgl_init_single_ctx(); ck_assert_int_eq(ret, 0); testvirgl_reset_fence(); last_seqno = 0; for (i = 0; i < fence_count; i++) { ret = virgl_renderer_create_fence(base_seqno + i, 0); ck_assert_int_eq(ret, 0); } do { int seqno; virgl_renderer_poll(); seqno = testvirgl_get_last_fence(); if (seqno == target_seqno) break; ck_assert(seqno == 0 || (seqno >= base_seqno && seqno < target_seqno)); /* monotonic increasing */ ck_assert_int_ge(seqno, last_seqno); last_seqno = seqno; usleep(1000); } while(1); testvirgl_fini_single_ctx(); } END_TEST static int wait_sync_fd(int fd, int timeout) { struct pollfd pollfd = { .fd = fd, .events = POLLIN, }; int ret; do { ret = poll(&pollfd, 1, timeout); } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); if (ret < 0) return -errno; else if (ret > 0 && !(pollfd.revents & POLLIN)) return -EINVAL; return ret ? 0 : -ETIME; } START_TEST(virgl_fence_export) { const int target_seqno = 50; int fd; int ret; ret = testvirgl_init_single_ctx(); ck_assert_int_eq(ret, 0); testvirgl_reset_fence(); ret = virgl_renderer_create_fence(target_seqno, 0); ck_assert_int_eq(ret, 0); ret = virgl_renderer_export_fence(target_seqno, &fd); ck_assert_int_eq(ret, 0); ret = wait_sync_fd(fd, -1); ck_assert_int_eq(ret, 0); virgl_renderer_poll(); ck_assert_int_eq(testvirgl_get_last_fence(), target_seqno); close(fd); testvirgl_fini_single_ctx(); } END_TEST START_TEST(virgl_fence_export_signaled) { const int target_seqno = 50; const int test_range = 10; int fd; int ret; int i; ret = testvirgl_init_single_ctx(); ck_assert_int_eq(ret, 0); /* when there is no active fence, a signaled fd is always returned */ for (i = 0; i < test_range; i++) { ret = virgl_renderer_export_fence(target_seqno + 1 + i, &fd); ck_assert_int_eq(ret, 0); ret = wait_sync_fd(fd, 0); ck_assert_int_eq(ret, 0); close(fd); } ret = virgl_renderer_create_fence(target_seqno, 0); ck_assert_int_eq(ret, 0); /* when there is any active fence, a signaled fd is returned when the * requested seqno is smaller than the first active fence */ for (i = 0; i < test_range; i++) { ret = virgl_renderer_export_fence(target_seqno - 1 - i, &fd); ck_assert_int_eq(ret, 0); ret = wait_sync_fd(fd, 0); ck_assert_int_eq(ret, 0); close(fd); } testvirgl_fini_single_ctx(); } END_TEST START_TEST(virgl_fence_export_invalid) { const int target_seqno = 50; const int target_seqno2 = 55; int seqno; int fd; int ret; ret = testvirgl_init_single_ctx(); ck_assert_int_eq(ret, 0); ret = virgl_renderer_create_fence(target_seqno, 0); ck_assert_int_eq(ret, 0); ret = virgl_renderer_create_fence(target_seqno2, 0); ck_assert_int_eq(ret, 0); for (seqno = target_seqno; seqno <= target_seqno2 + 1; seqno++) { ret = virgl_renderer_export_fence(seqno, &fd); if (seqno == target_seqno || seqno == target_seqno2) { ck_assert_int_eq(ret, 0); close(fd); } else { ck_assert_int_eq(ret, -EINVAL); } } testvirgl_fini_single_ctx(); } END_TEST static Suite *virgl_init_suite(bool include_fence_export) { Suite *s; TCase *tc_core; s = suite_create("virgl_fence"); tc_core = tcase_create("fence"); tcase_add_test(tc_core, virgl_fence_create); tcase_add_test(tc_core, virgl_fence_poll); tcase_add_test(tc_core, virgl_fence_poll_many); if (include_fence_export) { tcase_add_test(tc_core, virgl_fence_export); tcase_add_test(tc_core, virgl_fence_export_signaled); tcase_add_test(tc_core, virgl_fence_export_invalid); } suite_add_tcase(s, tc_core); return s; } static bool detect_fence_export_support(void) { int dummy_cookie; struct virgl_renderer_callbacks dummy_cbs; int fd; int ret; memset(&dummy_cbs, 0, sizeof(dummy_cbs)); dummy_cbs.version = 1; ret = virgl_renderer_init(&dummy_cookie, context_flags, &dummy_cbs); if (ret) return false; ret = virgl_renderer_export_fence(0, &fd); if (ret) { virgl_renderer_cleanup(&dummy_cookie); return false; } close(fd); virgl_renderer_cleanup(&dummy_cookie); return true; } int main(void) { Suite *s; SRunner *sr; int number_failed; bool include_fence_export = false; if (getenv("VRENDTEST_USE_EGL_SURFACELESS")) context_flags |= VIRGL_RENDERER_USE_SURFACELESS; if (getenv("VRENDTEST_USE_EGL_GLES")) { context_flags |= VIRGL_RENDERER_USE_GLES; include_fence_export = detect_fence_export_support(); } s = virgl_init_suite(include_fence_export); sr = srunner_create(s); srunner_run_all(sr, CK_NORMAL); number_failed = srunner_ntests_failed(sr); srunner_free(sr); return number_failed == 0 ? EXIT_SUCCESS : EXIT_FAILURE; }