On Tue, Oct 09, 2018 at 01:23:03PM +0300, Tapani Pälli wrote: > > > 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?
Agreed, I'll remove it. I think it was copy & pasted from another test, sorry for that. > > + > > + } > > + > > + *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; > > _______________________________________________ Piglit mailing list Piglit@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/piglit