You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

312 lines
7.3 KiB

/**************************************************************************
*
* 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 <check.h>
#include <errno.h>
#include <poll.h>
#include <stdlib.h>
#include <unistd.h>
#include <virglrenderer.h>
#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;
}