tests: Test whether a simple EGL main loop uses too many buffers

This adds a test that tries to simulate a simple game loop that would
be like this:

while (1) {
        draw_something();
        eglSwapBuffers();
}

In this case the test is relying on eglSwapBuffers to throttle to a
sensible frame rate.

The test then verifies that only 2 EGL buffers are used. This is done
via a new request and event in the wayland-test protocol.

Currently this causes 3 buffers to be created because the release
event generated by the swap buffers is not processed by Mesa until it
blocks for the frame complete event in the next swap buffers call, but
that is too late.

This can be fixed in Mesa by issuing a sync request after the swap
buffers and blocking on it before deciding whether to allocate a new
buffer.
dev
Neil Roberts 11 years ago committed by Kristian Høgsberg
parent 65a07f8aef
commit 40c0c3f91e
  1. 1
      configure.ac
  2. 7
      protocol/wayland-test.xml
  3. 12
      tests/Makefile.am
  4. 128
      tests/buffer-count-test.c
  5. 22
      tests/weston-test-client-helper.c
  6. 4
      tests/weston-test-client-helper.h
  7. 51
      tests/weston-test.c

@ -65,6 +65,7 @@ AM_CONDITIONAL(ENABLE_EGL, test x$enable_egl = xyes)
if test x$enable_egl = xyes; then if test x$enable_egl = xyes; then
AC_DEFINE([ENABLE_EGL], [1], [Build Weston with EGL support]) AC_DEFINE([ENABLE_EGL], [1], [Build Weston with EGL support])
PKG_CHECK_MODULES(EGL, [egl >= 7.10 glesv2]) PKG_CHECK_MODULES(EGL, [egl >= 7.10 glesv2])
PKG_CHECK_MODULES([EGL_TESTS], [egl >= 7.10 glesv2 wayland-client wayland-egl])
fi fi
AC_ARG_ENABLE(xkbcommon, AC_ARG_ENABLE(xkbcommon,

@ -51,5 +51,12 @@
<arg name="x" type="fixed"/> <arg name="x" type="fixed"/>
<arg name="y" type="fixed"/> <arg name="y" type="fixed"/>
</event> </event>
<request name="get_n_egl_buffers">
<!-- causes a n_egl_buffers event to be sent which reports how many
buffer objects are live for the client -->
</request>
<event name="n_egl_buffers">
<arg name="n" type="uint"/>
</event>
</interface> </interface>
</protocol> </protocol>

@ -17,6 +17,11 @@ weston_tests = \
subsurface.weston \ subsurface.weston \
$(xwayland_test) $(xwayland_test)
if ENABLE_EGL
weston_tests += \
buffer-count.weston
endif
AM_TESTS_ENVIRONMENT = \ AM_TESTS_ENVIRONMENT = \
abs_builddir='$(abs_builddir)'; export abs_builddir; abs_builddir='$(abs_builddir)'; export abs_builddir;
@ -63,6 +68,10 @@ weston_test_la_SOURCES = \
wayland-test-protocol.c \ wayland-test-protocol.c \
wayland-test-server-protocol.h wayland-test-server-protocol.h
if ENABLE_EGL
weston_test_la_LDFLAGS += $(EGL_TESTS_LIBS)
endif
libtest_runner_la_SOURCES = \ libtest_runner_la_SOURCES = \
weston-test-runner.c \ weston-test-runner.c \
weston-test-runner.h weston-test-runner.h
@ -111,6 +120,9 @@ text_weston_LDADD = libtest-client.la
subsurface_weston_SOURCES = subsurface-test.c subsurface_weston_SOURCES = subsurface-test.c
subsurface_weston_LDADD = libtest-client.la subsurface_weston_LDADD = libtest-client.la
buffer_count_weston_SOURCES = buffer-count-test.c
buffer_count_weston_LDADD = libtest-client.la $(EGL_TESTS_LIBS)
xwayland_weston_SOURCES = xwayland-test.c xwayland_weston_SOURCES = xwayland-test.c
xwayland_weston_CFLAGS = $(GCC_CFLAGS) $(XWAYLAND_TEST_CFLAGS) xwayland_weston_CFLAGS = $(GCC_CFLAGS) $(XWAYLAND_TEST_CFLAGS)
xwayland_weston_LDADD = libtest-client.la $(XWAYLAND_TEST_LIBS) xwayland_weston_LDADD = libtest-client.la $(XWAYLAND_TEST_LIBS)

@ -0,0 +1,128 @@
/*
* Copyright © 2013 Intel Corporation
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, provided
* that the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of the copyright holders not be used in
* advertising or publicity pertaining to distribution of the software
* without specific, written prior permission. The copyright holders make
* no representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <string.h>
#include "weston-test-client-helper.h"
#include <stdio.h>
#include <poll.h>
#include <time.h>
#include <EGL/egl.h>
#include <wayland-egl.h>
#include <GLES2/gl2.h>
struct test_data {
struct client *client;
EGLDisplay egl_dpy;
EGLContext egl_ctx;
EGLConfig egl_conf;
EGLSurface egl_surface;
};
static void
init_egl(struct test_data *test_data)
{
struct wl_egl_window *native_window;
struct surface *surface = test_data->client->surface;
static const EGLint context_attribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
EGLint config_attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, 1,
EGL_GREEN_SIZE, 1,
EGL_BLUE_SIZE, 1,
EGL_ALPHA_SIZE, 0,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE
};
EGLint major, minor, n;
EGLBoolean ret;
test_data->egl_dpy = eglGetDisplay((EGLNativeDisplayType)
test_data->client->wl_display);
assert(test_data->egl_dpy);
ret = eglInitialize(test_data->egl_dpy, &major, &minor);
assert(ret == EGL_TRUE);
ret = eglBindAPI(EGL_OPENGL_ES_API);
assert(ret == EGL_TRUE);
ret = eglChooseConfig(test_data->egl_dpy, config_attribs,
&test_data->egl_conf, 1, &n);
assert(ret && n == 1);
test_data->egl_ctx = eglCreateContext(test_data->egl_dpy,
test_data->egl_conf,
EGL_NO_CONTEXT, context_attribs);
assert(test_data->egl_ctx);
native_window =
wl_egl_window_create(surface->wl_surface,
surface->width,
surface->height);
test_data->egl_surface =
eglCreateWindowSurface(test_data->egl_dpy,
test_data->egl_conf,
(EGLNativeWindowType) native_window,
NULL);
ret = eglMakeCurrent(test_data->egl_dpy, test_data->egl_surface,
test_data->egl_surface, test_data->egl_ctx);
assert(ret == EGL_TRUE);
}
TEST(test_buffer_count)
{
struct test_data test_data;
uint32_t buffer_count;
int i;
test_data.client = client_create(10, 10, 10, 10);
init_egl(&test_data);
/* This is meant to represent a typical game loop which is
* expecting eglSwapBuffers to block and throttle the
* rendering to a sensible frame rate. Therefore it doesn't
* expect to have to install a frame callback itself. I'd
* imagine this is what a typical SDL game would end up
* doing */
for (i = 0; i < 10; i++) {
glClear(GL_COLOR_BUFFER_BIT);
eglSwapBuffers(test_data.egl_dpy, test_data.egl_surface);
}
buffer_count = get_n_egl_buffers(test_data.client);
printf("buffers used = %i\n", buffer_count);
/* The implementation should only end up creating two buffers
* and cycling between them */
assert(buffer_count == 2);
}

@ -111,6 +111,17 @@ move_client(struct client *client, int x, int y)
frame_callback_wait(client, &done); frame_callback_wait(client, &done);
} }
int
get_n_egl_buffers(struct client *client)
{
client->test->n_egl_buffers = -1;
wl_test_get_n_egl_buffers(client->test->wl_test);
wl_display_roundtrip(client->wl_display);
return client->test->n_egl_buffers;
}
static void static void
pointer_handle_enter(void *data, struct wl_pointer *wl_pointer, pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
uint32_t serial, struct wl_surface *wl_surface, uint32_t serial, struct wl_surface *wl_surface,
@ -340,8 +351,17 @@ test_handle_pointer_position(void *data, struct wl_test *wl_test,
test->pointer_x, test->pointer_y); test->pointer_x, test->pointer_y);
} }
static void
test_handle_n_egl_buffers(void *data, struct wl_test *wl_test, uint32_t n)
{
struct test *test = data;
test->n_egl_buffers = n;
}
static const struct wl_test_listener test_listener = { static const struct wl_test_listener test_listener = {
test_handle_pointer_position test_handle_pointer_position,
test_handle_n_egl_buffers,
}; };
static void static void

@ -51,6 +51,7 @@ struct test {
struct wl_test *wl_test; struct wl_test *wl_test;
int pointer_x; int pointer_x;
int pointer_y; int pointer_y;
uint32_t n_egl_buffers;
}; };
struct input { struct input {
@ -120,4 +121,7 @@ frame_callback_set(struct wl_surface *surface, int *done);
void void
frame_callback_wait(struct client *client, int *done); frame_callback_wait(struct client *client, int *done);
int
get_n_egl_buffers(struct client *client);
#endif #endif

@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "config.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
@ -28,6 +30,11 @@
#include "../src/compositor.h" #include "../src/compositor.h"
#include "wayland-test-server-protocol.h" #include "wayland-test-server-protocol.h"
#ifdef ENABLE_EGL
#include <EGL/egl.h>
#include <EGL/eglext.h>
#endif /* ENABLE_EGL */
struct weston_test { struct weston_test {
struct weston_compositor *compositor; struct weston_compositor *compositor;
struct weston_layer layer; struct weston_layer layer;
@ -181,12 +188,54 @@ send_key(struct wl_client *client, struct wl_resource *resource,
notify_key(seat, 100, key, state, STATE_UPDATE_AUTOMATIC); notify_key(seat, 100, key, state, STATE_UPDATE_AUTOMATIC);
} }
#ifdef ENABLE_EGL
static int
is_egl_buffer(struct wl_resource *resource)
{
PFNEGLQUERYWAYLANDBUFFERWL query_buffer =
(void *) eglGetProcAddress("eglQueryWaylandBufferWL");
EGLint format;
if (query_buffer(eglGetCurrentDisplay(),
resource,
EGL_TEXTURE_FORMAT,
&format))
return 1;
return 0;
}
#endif /* ENABLE_EGL */
static void
get_n_buffers(struct wl_client *client, struct wl_resource *resource)
{
int n_buffers = 0;
#ifdef ENABLE_EGL
struct wl_resource *buffer_resource;
int i;
for (i = 0; i < 1000; i++) {
buffer_resource = wl_client_get_object(client, i);
if (buffer_resource == NULL)
continue;
if (is_egl_buffer(buffer_resource))
n_buffers++;
}
#endif /* ENABLE_EGL */
wl_test_send_n_egl_buffers(resource, n_buffers);
}
static const struct wl_test_interface test_implementation = { static const struct wl_test_interface test_implementation = {
move_surface, move_surface,
move_pointer, move_pointer,
send_button, send_button,
activate_surface, activate_surface,
send_key send_key,
get_n_buffers,
}; };
static void static void

Loading…
Cancel
Save