[Piglit] [PATCH 3/7] egl-context-preemption: Add a high priority thread/context.
Tapani Pälli
tapani.palli at intel.com
Tue Oct 9 10:23:03 UTC 2018
On 10/4/18 6:35 PM, Rafael Antognolli wrote:
> Start a new thread right after dispatching the render commands from the
> main thread, after glFlush().
>
> This second thread creates a high priority EGL context, and uses it to
> render to a frame buffer multiple times. These draw calls are supposed
> to finish before the one in the main thread.
> ---
> tests/egl/egl-context-preemption.c | 243 +++++++++++++++++++++++++++++
> 1 file changed, 243 insertions(+)
>
> diff --git a/tests/egl/egl-context-preemption.c b/tests/egl/egl-context-preemption.c
> index 9d5aa42ee..566416312 100644
> --- a/tests/egl/egl-context-preemption.c
> +++ b/tests/egl/egl-context-preemption.c
> @@ -41,11 +41,16 @@
> */
>
> #define HIGH_PRIO_RUNS 50
> +static const int hp_width = 80, hp_height = 80;
>
> struct test_data {
> bool main_finished;
> int64_t main_tstarted, main_tfinished;
> + int64_t tstarted[HIGH_PRIO_RUNS];
> + int64_t tfinished[HIGH_PRIO_RUNS];
> + int nruns;
> EGLDisplay dpy;
> + EGLContext ctx;
> };
>
> struct test_profile {
> @@ -197,6 +202,224 @@ draw_objects(unsigned int shader_program, GLenum mode, GLfloat *vertices,
> glDisableVertexAttribArray(0);
> }
>
> +static enum piglit_result
> +init_display(EGLenum platform, EGLDisplay *out_dpy)
> +{
> + enum piglit_result result = PIGLIT_PASS;
> + EGLDisplay dpy;
> + EGLint egl_major, egl_minor;
> + bool ok;
> +
> + dpy = piglit_egl_get_default_display(platform);
> + if (!dpy) {
> + result = PIGLIT_SKIP;
> + goto error;
> + }
> +
> + ok = eglInitialize(dpy, &egl_major, &egl_minor);
> + if (!ok) {
> + result = PIGLIT_SKIP;
> + goto error;
> + }
> +
> + if (!piglit_is_egl_extension_supported(dpy, "EGL_IMG_context_priority")) {
> + piglit_loge("display does not support EGL_IMG_context_priority");
> + result = PIGLIT_SKIP;
> + goto error;
This seems unnecessary, we are already skipping the test if extension
was not supported in piglit_init?
> +
> + }
> +
> + *out_dpy = dpy;
> + return result;
> +
> +error:
> + if (dpy) {
> + eglTerminate(dpy);
> + }
> + return result;
> +}
> +
> +static enum piglit_result
> +init_other_display(EGLDisplay *out_other_dpy)
> +{
> + enum piglit_result result = PIGLIT_SKIP;
> + EGLDisplay other_dpy = 0;
> + int i;
> +
> + static const EGLint platforms[] = {
> + EGL_PLATFORM_GBM_MESA,
> + EGL_PLATFORM_SURFACELESS_MESA,
> + EGL_PLATFORM_X11_EXT,
> + EGL_PLATFORM_WAYLAND_EXT,
> + 0,
> + };
> +
> + for (i = 0; platforms[i] != 0; ++i) {
> + result = init_display(platforms[i], &other_dpy);
> + switch (result) {
> + case PIGLIT_SKIP:
> + break;
> + case PIGLIT_PASS:
> + *out_other_dpy = other_dpy;
> + return PIGLIT_PASS;
> + default:
> + break;
> + }
> + }
> +
> + return result;
> +}
> +
> +static enum piglit_result
> +setup_thread_context(struct test_data *d)
> +{
> + enum piglit_result result = PIGLIT_PASS;
> + bool ok = false;
> + EGLContext ctx2 = EGL_NO_CONTEXT;
> +
> + EGLDisplay dpy;
> + if (init_other_display(&dpy) == PIGLIT_SKIP) {
> + piglit_loge("failed to get display\n");
> + result = PIGLIT_FAIL;
> + return result;
> + }
> +
> + eglBindAPI(EGL_OPENGL_API);
> + if (!piglit_check_egl_error(EGL_SUCCESS)) {
> + piglit_loge("failed to set OpenGL API.\n");
> + result = PIGLIT_FAIL;
> + return result;
> + }
> +
> + EGLint attr[] = {
> + EGL_CONTEXT_CLIENT_VERSION, 3,
> + EGL_CONTEXT_MINOR_VERSION_KHR, 3,
> + EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG,
> + EGL_NONE };
> + ctx2 = eglCreateContext(dpy, EGL_NO_CONFIG_MESA, EGL_NO_CONTEXT, attr);
> + if (ctx2 == EGL_NO_CONTEXT) {
> + piglit_loge("failed to create context");
> + piglit_check_egl_error(EGL_SUCCESS);
> + result = PIGLIT_FAIL;
> + goto cleanup;
> + }
> +
> + ok = eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx2);
> + if (!ok) {
> + piglit_loge("failed to make context current without surface");
> + result = PIGLIT_FAIL;
> + goto cleanup;
> + }
> +
> + GLuint VertexArrayID;
> + glGenVertexArrays(1, &VertexArrayID);
> + glBindVertexArray(VertexArrayID);
> +
> + glEnable(GL_BLEND);
> + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
> +
> + glViewport(0, 0, hp_width, hp_height);
> +
> + d->ctx = ctx2;
> + d->dpy = dpy;
> +
> + return result;
> +
> +cleanup:
> + if (ctx2 != EGL_NO_CONTEXT)
> + eglDestroyContext(dpy, ctx2);
> + eglTerminate(dpy);
> +
> + return result;
> +}
> +
> +/* Allocate and attach textures and FBOs */
> +static void
> +setup_render_target(GLuint *fbos, GLuint *textures, unsigned n,
> + int width, int height)
> +{
> + glGenFramebuffers(n, fbos);
> + glGenTextures(n, textures);
> +
> + for (int i = 0; i < n; i++) {
> + glBindFramebuffer(GL_FRAMEBUFFER, fbos[i]);
> +
> + glBindTexture(GL_TEXTURE_2D, textures[i]);
> + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
> + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
> +
> + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, hp_width, hp_height, 0,
> + GL_RGB, GL_UNSIGNED_BYTE, NULL);
> + glBindTexture(GL_TEXTURE_2D, 0);
> +
> + // attach texture to the currently bound framebuffer
> + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
> + GL_TEXTURE_2D, textures[i], 0);
> +
> + if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
> + piglit_loge("Framebuffer is not complete!\n");
> +
> + if (!piglit_check_gl_error(GL_NO_ERROR)) {
> + piglit_report_result(PIGLIT_FAIL);
> + }
> + }
> +}
> +
> +static void
> +draw_high_priority(struct test_data *d, unsigned int shader_program, int iter)
> +{
> + GLint nbits;
> + glGetQueryiv(GL_TIMESTAMP, GL_QUERY_COUNTER_BITS, &nbits);
> + /* Ready to draw */
> + draw_objects(shader_program, GL_TRIANGLES, triangle_vertices,
> + sizeof(triangle_vertices), 1);
> + glFlush();
> +
> + GLuint query;
> + glGenQueries(1, &query);
> + glGetInteger64v(GL_TIMESTAMP, &d->tstarted[iter]);
> + glQueryCounter(query, GL_TIMESTAMP);
> +
> + glFinish();
> + glGetQueryObjecti64v(query, GL_QUERY_RESULT, &d->tfinished[iter]);
> + d->nruns++;
> +}
> +
> +static void*
> +thread2_create_high_priority_context(void *data)
> +{
> + enum piglit_result *result = malloc(sizeof(*result));
> + struct test_data *d = data;
> +
> + *result = setup_thread_context(d);
> + if (*result != PIGLIT_PASS)
> + return result;
> +
> + GLuint fbos[HIGH_PRIO_RUNS];
> + GLuint textures[HIGH_PRIO_RUNS];
> + setup_render_target(fbos, textures, HIGH_PRIO_RUNS,
> + hp_width, hp_height);
> +
> + unsigned int program = setup_shaders();
> +
> + for (int i = 0; i < HIGH_PRIO_RUNS; i++) {
> + /* It's fine to have a little race condition here, because we
> + * will discard results that finished after the main thread
> + * based on GL_TIMESTAMP anyway.
> + */
> + if (d->main_finished)
> + break;
> + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[i]);
> + draw_high_priority(d, program, i);
> + }
> +
> + if (d->ctx != EGL_NO_CONTEXT)
> + eglDestroyContext(d->dpy, d->ctx);
> + eglTerminate(d->dpy);
> +
> + return result;
> +}
> +
> static GLfloat *
> read_pixels_float(GLint x, GLint y, GLsizei width, GLsizei height,
> GLenum format, GLfloat *pixels)
> @@ -232,6 +455,7 @@ test_preemption(void *data)
> const struct test_profile *profile = data;
> struct test_data d = {
> .main_finished = false,
> + .nruns = 0,
> };
> d.dpy = eglGetCurrentDisplay();
>
> @@ -270,6 +494,18 @@ test_preemption(void *data)
> glGetInteger64v(GL_TIMESTAMP, &d.main_tstarted);
> glQueryCounter(query, GL_TIMESTAMP);
>
> + /* Start second thread with high priority */
> + pthread_t thread2;
> + int err = pthread_create(
> + &thread2, NULL,
> + thread2_create_high_priority_context,
> + &d);
> + if (err) {
> + piglit_loge("failed to create second thread");
> + result = PIGLIT_FAIL;
> + goto cleanup;
> + }
> +
> glFinish();
> glGetQueryObjecti64v(query, GL_QUERY_RESULT, &d.main_tfinished);
> d.main_finished = true;
> @@ -283,6 +519,13 @@ test_preemption(void *data)
>
> glBindFramebuffer(GL_FRAMEBUFFER, 0);
>
> + err = pthread_join(thread2, NULL);
> + if (err) {
> + piglit_loge("failed to join thread %"PRIuMAX, (uintmax_t) thread2);
> + result = PIGLIT_FAIL;
> + goto cleanup;
> + }
> +
> cleanup:
> free(ref_image);
> return result;
>
More information about the Piglit
mailing list