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

Reply via email to