[Mesa-dev] [PATCH demos] egl: Add es2eglkms demo

Hwang, Dongseong dongseong.hwang at intel.com
Fri May 6 12:25:22 UTC 2016


Andreas, Adam, could you review?

Br, DS

On Fri, Apr 29, 2016 at 7:54 AM, Dongseong Hwang <dongseong.hwang at intel.com>
wrote:

> This demo shows how ChromeOS renders OpenGL ES2 via kms, drm and gbm.
> This demo consists of
> 1. kms modesetting and vsync
> 2. EGL and GLES2 context creation
> 3. gbm bo creation and EGL Image binding
>
> drm connection code is copied from eglkms.
> ES2 rendering code is copied from es2tri.
>
> Signed-off-by: Dongseong Hwang <dongseong.hwang at intel.com>
> ---
>  src/egl/opengles2/Makefile.am |   9 +
>  src/egl/opengles2/es2eglkms.c | 608
> ++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 617 insertions(+)
>  create mode 100644 src/egl/opengles2/es2eglkms.c
>
> diff --git a/src/egl/opengles2/Makefile.am b/src/egl/opengles2/Makefile.am
> index b80ba50..2564a74 100644
> --- a/src/egl/opengles2/Makefile.am
> +++ b/src/egl/opengles2/Makefile.am
> @@ -45,6 +45,11 @@ endif
>  if HAVE_WAYLAND
>  bin_PROGRAMS += es2gears_wayland
>  endif
> +if HAVE_DRM
> +if HAVE_GBM
> +bin_PROGRAMS += es2eglkms
> +endif
> +endif
>  endif
>  endif
>
> @@ -57,3 +62,7 @@ es2gears_x11_LDADD = ../eglut/libeglut_x11.la
>
>  es2gears_wayland_SOURCES = es2gears.c
>  es2gears_wayland_LDADD = ../eglut/libeglut_wayland.la
> +
> +es2eglkms_SOURCES = es2eglkms.c
> +es2eglkms_CFLAGS = $(AM_CFLAGS) $(DRM_CFLAGS) $(GBM_CFLAGS)
> +es2eglkms_LDADD = $(AM_LDFLAGS) $(DRM_LIBS) $(GBM_LIBS)
> \ No newline at end of file
> diff --git a/src/egl/opengles2/es2eglkms.c b/src/egl/opengles2/es2eglkms.c
> new file mode 100644
> index 0000000..95b3ade
> --- /dev/null
> +++ b/src/egl/opengles2/es2eglkms.c
> @@ -0,0 +1,608 @@
> +/*
> + * Copyright © 2016 Dongseong Hwang
> + *
> + * 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 <math.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <errno.h>
> +
> +#define EGL_EGLEXT_PROTOTYPES
> +#define GL_GLEXT_PROTOTYPES
> +
> +#include <gbm.h>
> +#include <GLES2/gl2.h>
> +#include <GLES2/gl2ext.h>
> +#include <EGL/egl.h>
> +#include <EGL/eglext.h>
> +#include <drm.h>
> +#include <xf86drm.h>
> +#include <xf86drmMode.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <string.h>
> +
> +// double buffering
> +#define NUM_BUFFERS 2
> +
> +struct framebuffer {
> +   struct gbm_bo *bo;
> +   int fd;
> +   uint32_t fb_id;
> +   EGLImageKHR image;
> +   GLuint gl_tex;
> +   GLuint gl_fb;
> +};
> +
> +struct kms {
> +   drmModeConnector *connector;
> +   drmModeEncoder *encoder;
> +   drmModeModeInfo mode;
> +};
> +
> +struct gl {
> +   GLuint program;
> +   GLfloat view_rotz;
> +   GLint u_matrix;
> +   GLint attr_pos;
> +   GLint attr_color;
> +
> +   PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR;
> +   PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR;
> +};
> +
> +static void make_z_rot_matrix(GLfloat angle, GLfloat *m)
> +{
> +   float c = cos(angle * M_PI / 180.0);
> +   float s = sin(angle * M_PI / 180.0);
> +   int i;
> +   for (i = 0; i < 16; i++)
> +      m[i] = 0.0;
> +   m[0] = m[5] = m[10] = m[15] = 1.0;
> +
> +   m[0] = c;
> +   m[1] = s;
> +   m[4] = -s;
> +   m[5] = c;
> +}
> +
> +static void make_scale_matrix(GLfloat xs, GLfloat ys, GLfloat zs, GLfloat
> *m)
> +{
> +   int i;
> +   for (i = 0; i < 16; i++)
> +      m[i] = 0.0;
> +   m[0] = xs;
> +   m[5] = ys;
> +   m[10] = zs;
> +   m[15] = 1.0;
> +}
> +
> +static void mul_matrix(GLfloat *prod, const GLfloat *a, const GLfloat *b)
> +{
> +#define A(row, col) a[(col << 2) + row]
> +#define B(row, col) b[(col << 2) + row]
> +#define P(row, col) p[(col << 2) + row]
> +   GLfloat p[16];
> +   GLint i;
> +   for (i = 0; i < 4; i++) {
> +      const GLfloat ai0 = A(i, 0), ai1 = A(i, 1), ai2 = A(i, 2), ai3 =
> A(i, 3);
> +      P(i, 0) = ai0 * B(0, 0) + ai1 * B(1, 0) + ai2 * B(2, 0) + ai3 *
> B(3, 0);
> +      P(i, 1) = ai0 * B(0, 1) + ai1 * B(1, 1) + ai2 * B(2, 1) + ai3 *
> B(3, 1);
> +      P(i, 2) = ai0 * B(0, 2) + ai1 * B(1, 2) + ai2 * B(2, 2) + ai3 *
> B(3, 2);
> +      P(i, 3) = ai0 * B(0, 3) + ai1 * B(1, 3) + ai2 * B(2, 3) + ai3 *
> B(3, 3);
> +   }
> +   memcpy(prod, p, sizeof(p));
> +#undef A
> +#undef B
> +#undef PROD
> +}
> +
> +static EGLBoolean setup_kms(int fd, struct kms *kms)
> +{
> +   drmModeRes *resources;
> +   drmModeConnector *connector;
> +   drmModeEncoder *encoder;
> +   int i;
> +
> +   resources = drmModeGetResources(fd);
> +   if (!resources) {
> +      fprintf(stderr, "drmModeGetResources failed\n");
> +      return EGL_FALSE;
> +   }
> +
> +   for (i = 0; i < resources->count_connectors; i++) {
> +      connector = drmModeGetConnector(fd, resources->connectors[i]);
> +      if (connector == NULL)
> +         continue;
> +
> +      if (connector->connection == DRM_MODE_CONNECTED &&
> +          connector->count_modes > 0)
> +         break;
> +
> +      drmModeFreeConnector(connector);
> +   }
> +
> +   if (i == resources->count_connectors) {
> +      fprintf(stderr, "No currently active connector found.\n");
> +      return EGL_FALSE;
> +   }
> +
> +   for (i = 0; i < resources->count_encoders; i++) {
> +      encoder = drmModeGetEncoder(fd, resources->encoders[i]);
> +
> +      if (encoder == NULL)
> +         continue;
> +
> +      if (encoder->encoder_id == connector->encoder_id)
> +         break;
> +
> +      drmModeFreeEncoder(encoder);
> +   }
> +
> +   kms->connector = connector;
> +   kms->encoder = encoder;
> +   kms->mode = connector->modes[0];
> +
> +   return EGL_TRUE;
> +}
> +
> +static void gl_init(struct gl *gl, int width, int height)
> +{
> +   glClearColor(0.4, 0.4, 0.4, 0.0);
> +
> +   static const char *fragShaderText =
> +       "precision mediump float;\n"
> +       "varying vec4 v_color;\n"
> +       "void main() {\n"
> +       "   gl_FragColor = v_color;\n"
> +       "}\n";
> +   static const char *vertShaderText =
> +       "uniform mat4 modelviewProjection;\n"
> +       "attribute vec4 pos;\n"
> +       "attribute vec4 color;\n"
> +       "varying vec4 v_color;\n"
> +       "void main() {\n"
> +       "   gl_Position = modelviewProjection * pos;\n"
> +       "   v_color = color;\n"
> +       "}\n";
> +
> +   GLuint fragShader, vertShader;
> +   GLint stat;
> +
> +   fragShader = glCreateShader(GL_FRAGMENT_SHADER);
> +   glShaderSource(fragShader, 1, (const char **)&fragShaderText, NULL);
> +   glCompileShader(fragShader);
> +   glGetShaderiv(fragShader, GL_COMPILE_STATUS, &stat);
> +   if (!stat) {
> +      printf("Error: fragment shader did not compile!\n");
> +      exit(1);
> +   }
> +
> +   vertShader = glCreateShader(GL_VERTEX_SHADER);
> +   glShaderSource(vertShader, 1, (const char **)&vertShaderText, NULL);
> +   glCompileShader(vertShader);
> +   glGetShaderiv(vertShader, GL_COMPILE_STATUS, &stat);
> +   if (!stat) {
> +      printf("Error: vertex shader did not compile!\n");
> +      exit(1);
> +   }
> +
> +   gl->program = glCreateProgram();
> +   glAttachShader(gl->program, fragShader);
> +   glAttachShader(gl->program, vertShader);
> +
> +   gl->attr_pos = 0;
> +   gl->attr_color = 1;
> +   glBindAttribLocation(gl->program, gl->attr_pos, "pos");
> +   glBindAttribLocation(gl->program, gl->attr_color, "color");
> +   glLinkProgram(gl->program);
> +   glGetProgramiv(gl->program, GL_LINK_STATUS, &stat);
> +   if (!stat) {
> +      char log[1000];
> +      GLsizei len;
> +      glGetProgramInfoLog(gl->program, 1000, &len, log);
> +      printf("Error: linking:\n%s\n", log);
> +      exit(1);
> +   }
> +
> +   glUseProgram(gl->program);
> +
> +   gl->u_matrix = glGetUniformLocation(gl->program,
> "modelviewProjection");
> +   printf("Uniform modelviewProjection at %d\n", gl->u_matrix);
> +   printf("Attrib pos at %d\n", gl->attr_pos);
> +   printf("Attrib color at %d\n", gl->attr_color);
> +
> +   gl->view_rotz = 0;
> +
> +   glViewport(0, 0, (GLint)width, (GLint)height);
> +}
> +
> +static void render_stuff(struct gl *gl)
> +{
> +   static const GLfloat verts[3][2] = { { -1, -1 }, { 1, -1 }, { 0, 1 } };
> +   static const GLfloat colors[3][3] = {
> +      { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 }
> +   };
> +   GLfloat mat[16], rot[16], scale[16];
> +
> +   gl->view_rotz += 1.0;
> +
> +   glClear(GL_COLOR_BUFFER_BIT);
> +
> +   /* Set modelview/projection matrix */
> +   make_z_rot_matrix(gl->view_rotz, rot);
> +   make_scale_matrix(0.5, 0.5, 0.5, scale);
> +   mul_matrix(mat, rot, scale);
> +   glUniformMatrix4fv(gl->u_matrix, 1, GL_FALSE, mat);
> +
> +   glVertexAttribPointer(gl->attr_pos, 2, GL_FLOAT, GL_FALSE, 0, verts);
> +   glVertexAttribPointer(gl->attr_color, 3, GL_FLOAT, GL_FALSE, 0,
> colors);
> +   glEnableVertexAttribArray(gl->attr_pos);
> +   glEnableVertexAttribArray(gl->attr_color);
> +
> +   glDrawArrays(GL_TRIANGLES, 0, 3);
> +}
> +
> +static void egl_sync_fence(EGLDisplay dpy, struct gl *gl)
> +{
> +   EGLSyncKHR sync = gl->eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
> +   glFlush();
> +   gl->eglClientWaitSyncKHR(dpy, sync, 0, EGL_FOREVER_KHR);
> +}
> +
> +static int has_extension(const char *extension, const char *extensions)
> +{
> +   const char *start, *where, *terminator;
> +   start = extensions;
> +   for (;;) {
> +      where = (char *)strstr((const char *)start, extension);
> +      if (!where)
> +         break;
> +      terminator = where + strlen(extension);
> +      if (where == start || *(where - 1) == ' ')
> +         if (*terminator == ' ' || *terminator == '\0')
> +            return 0;
> +      start = terminator;
> +   }
> +   return -1;
> +}
> +
> +static void page_flip_handler(int fd, unsigned int frame, unsigned int
> sec,
> +                              unsigned int usec, void *data)
> +{
> +   int *waiting_for_flip = data;
> +   *waiting_for_flip = 0;
> +}
> +
> +static const char device_name[] = "/dev/dri/card0";
> +
> +int main(int argc, char *argv[])
> +{
> +   EGLDisplay dpy;
> +   EGLContext ctx;
> +   EGLConfig config;
> +   EGLint major, minor, n;
> +   // Names are the original gl/egl function names with the prefix
> chopped off.
> +   PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
> +   PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
> +   PFNGLEGLIMAGETARGETTEXTURE2DOESPROC eglImageTargetTexture2DOES;
> +   int egl_sync_supported = 0;
> +   struct gl gl;
> +   const char *ver;
> +   uint32_t handle, stride;
> +   struct kms kms;
> +   int ret, fd;
> +   struct gbm_device *gbm;
> +   struct gbm_bo *bo;
> +   drmModeCrtcPtr saved_crtc;
> +   struct framebuffer fbs[NUM_BUFFERS];
> +   int front_buffer;
> +   drmEventContext evctx = {
> +      .version = DRM_EVENT_CONTEXT_VERSION,
> +      .page_flip_handler = page_flip_handler,
> +   };
> +   fd_set fds;
> +
> +   fd = open(device_name, O_RDWR);
> +   if (fd < 0) {
> +      /* Probably permissions error */
> +      fprintf(stderr, "couldn't open %s, skipping\n", device_name);
> +      return -1;
> +   }
> +
> +   gbm = gbm_create_device(fd);
> +   if (gbm == NULL) {
> +      fprintf(stderr, "couldn't create gbm device\n");
> +      ret = -1;
> +      goto close_fd;
> +   }
> +
> +   eglCreateImageKHR =
> +       (PFNEGLCREATEIMAGEKHRPROC)eglGetProcAddress("eglCreateImageKHR");
> +   eglDestroyImageKHR =
> +       (PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress("eglDestroyImageKHR");
> +   eglImageTargetTexture2DOES =
> +       (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress(
> +           "glEGLImageTargetTexture2DOES");
> +   gl.eglCreateSyncKHR =
> +       (PFNEGLCREATESYNCKHRPROC)eglGetProcAddress("eglCreateSyncKHR");
> +   gl.eglClientWaitSyncKHR =
> +
>  (PFNEGLCLIENTWAITSYNCKHRPROC)eglGetProcAddress("eglClientWaitSyncKHR");
> +   if (!eglCreateImageKHR || !eglDestroyImageKHR ||
> +       !eglImageTargetTexture2DOES) {
> +      fprintf(stderr,
> +              "eglGetProcAddress returned NULL for a required extension
> entry "
> +              "point.\n");
> +      ret = -1;
> +      goto destroy_gbm_device;
> +   }
> +   if (gl.eglCreateSyncKHR && gl.eglClientWaitSyncKHR) {
> +      egl_sync_supported = 1;
> +   }
> +
> +   dpy = eglGetDisplay(gbm);
> +   if (dpy == EGL_NO_DISPLAY) {
> +      fprintf(stderr, "eglGetDisplay() failed\n");
> +      ret = -1;
> +      goto destroy_gbm_device;
> +   }
> +
> +   if (!eglInitialize(dpy, &major, &minor)) {
> +      fprintf(stderr, "eglInitialize() failed\n");
> +      ret = -1;
> +      goto egl_terminate;
> +   }
> +
> +   ver = eglQueryString(dpy, EGL_VERSION);
> +   printf("EGL_VERSION = %s\n", ver);
> +
> +   if (!setup_kms(fd, &kms)) {
> +      ret = -1;
> +      goto egl_terminate;
> +   }
> +
> +   if (!eglBindAPI(EGL_OPENGL_ES_API)) {
> +      fprintf(stderr, "failed to bind api EGL_OPENGL_ES_API\n");
> +      ret = -1;
> +      goto egl_terminate;
> +   }
> +
> +   static const EGLint attribs[] = { EGL_SURFACE_TYPE, EGL_DONT_CARE,
> +                                     EGL_NONE };
> +
> +   if (!eglChooseConfig(dpy, attribs, &config, 1, &n) || n != 1) {
> +      fprintf(stderr, "failed to choose argb config\n");
> +      goto egl_terminate;
> +   }
> +
> +   static const EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION,
> 2,
> +                                             EGL_NONE };
> +
> +   ctx = eglCreateContext(dpy, config, EGL_NO_CONTEXT, context_attribs);
> +   if (ctx == NULL) {
> +      fprintf(stderr, "failed to create context\n");
> +      ret = -1;
> +      goto egl_terminate;
> +   }
> +
> +   if (!eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx)) {
> +      fprintf(stderr, "failed to make context current\n");
> +      ret = -1;
> +      goto destroy_context;
> +   }
> +
> +   const char *egl_extensions = eglQueryString(dpy, EGL_EXTENSIONS);
> +   printf("EGL Extensions \"%s\"\n", egl_extensions);
> +   if (has_extension("EGL_KHR_image_base", egl_extensions)) {
> +      fprintf(stderr, "EGL_KHR_image_base extension not supported\n");
> +      ret = -1;
> +      goto destroy_context;
> +   }
> +   if (has_extension("EGL_EXT_image_dma_buf_import", egl_extensions)) {
> +      fprintf(stderr, "EGL_EXT_image_dma_buf_import extension not
> supported\n");
> +      ret = -1;
> +      goto destroy_context;
> +   }
> +
> +   const char *gl_extensions = (const char *)glGetString(GL_EXTENSIONS);
> +   if (has_extension("GL_OES_EGL_image", gl_extensions)) {
> +      fprintf(stderr, "GL_OES_EGL_image extension not supported\n");
> +      ret = -1;
> +      goto destroy_context;
> +   }
> +
> +   uint32_t width = kms.mode.hdisplay;
> +   uint32_t height = kms.mode.vdisplay;
> +
> +   for (size_t i = 0; i < NUM_BUFFERS; i++) {
> +      fbs[i].bo = gbm_bo_create(gbm, width, height, GBM_FORMAT_XRGB8888,
> +                                GBM_BO_USE_SCANOUT |
> GBM_BO_USE_RENDERING);
> +      if (!fbs[i].bo) {
> +         fprintf(stderr, "failed to create a gbm buffer.\n");
> +         ret = -1;
> +         goto rm_fb;
> +      }
> +
> +      fbs[i].fd = gbm_bo_get_fd(fbs[i].bo);
> +      if (fbs[i].fd < 0) {
> +         fprintf(stderr, "failed to get fb for bo: %d", fbs[i].fd);
> +         ret = -1;
> +         goto rm_fb;
> +      }
> +
> +      uint32_t handle = gbm_bo_get_handle(fbs[i].bo).u32;
> +      uint32_t stride = gbm_bo_get_stride(fbs[i].bo);
> +      uint32_t offset = 0;
> +      drmModeAddFB2(fd, width, height, GBM_FORMAT_XRGB8888, &handle,
> &stride,
> +                    &offset, &fbs[i].fb_id, 0);
> +      if (!fbs[i].fb_id) {
> +         fprintf(stderr, "failed to create framebuffer from buffer
> object.\n");
> +         ret = -1;
> +         goto rm_fb;
> +      }
> +
> +      const EGLint khr_image_attrs[] = { EGL_DMA_BUF_PLANE0_FD_EXT,
> +                                         fbs[i].fd,
> +                                         EGL_WIDTH,
> +                                         width,
> +                                         EGL_HEIGHT,
> +                                         height,
> +                                         EGL_LINUX_DRM_FOURCC_EXT,
> +                                         GBM_FORMAT_XRGB8888,
> +                                         EGL_DMA_BUF_PLANE0_PITCH_EXT,
> +                                         stride,
> +                                         EGL_DMA_BUF_PLANE0_OFFSET_EXT,
> +                                         offset,
> +                                         EGL_NONE };
> +
> +      fbs[i].image =
> +          eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT,
> +                            NULL /* no client buffer */, khr_image_attrs);
> +      if (fbs[i].image == EGL_NO_IMAGE_KHR) {
> +         fprintf(stderr, "failed to make image from buffer object: %x\n",
> +                 eglGetError());
> +         ret = -1;
> +         goto rm_fb;
> +      }
> +
> +      glGenTextures(1, &fbs[i].gl_tex);
> +      glBindTexture(GL_TEXTURE_2D, fbs[i].gl_tex);
> +      eglImageTargetTexture2DOES(GL_TEXTURE_2D,
> (GLeglImageOES)fbs[i].image);
> +      glBindTexture(GL_TEXTURE_2D, 0);
> +
> +      glGenFramebuffers(1, &fbs[i].gl_fb);
> +      glBindFramebuffer(GL_FRAMEBUFFER, fbs[i].gl_fb);
> +      glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
> +                             GL_TEXTURE_2D, fbs[i].gl_tex, 0);
> +
> +      if (glCheckFramebufferStatus(GL_FRAMEBUFFER) !=
> GL_FRAMEBUFFER_COMPLETE) {
> +         fprintf(stderr,
> +                 "failed framebuffer check for created target buffer:
> %x\n",
> +                 glCheckFramebufferStatus(GL_FRAMEBUFFER));
> +         ret = -1;
> +         goto rm_gl_fb;
> +      }
> +   }
> +
> +   gl_init(&gl, width, height);
> +   glClear(GL_COLOR_BUFFER_BIT);
> +   if (egl_sync_supported) {
> +      egl_sync_fence(dpy, &gl);
> +   } else {
> +      glFinish();
> +   }
> +
> +   front_buffer = 0;
> +   const struct framebuffer *back_fb = &fbs[front_buffer ^ 1];
> +
> +   saved_crtc = drmModeGetCrtc(fd, kms.encoder->crtc_id);
> +   if (saved_crtc == NULL)
> +      goto rm_gl_fb;
> +
> +   ret = drmModeSetCrtc(fd, kms.encoder->crtc_id, back_fb->fb_id, 0, 0,
> +                        &kms.connector->connector_id, 1, &kms.mode);
> +   if (ret) {
> +      fprintf(stderr, "failed to set mode: %m\n");
> +      goto free_saved_crtc;
> +   }
> +
> +   front_buffer ^= 1;
> +   int got_user_input = 0;
> +   FD_ZERO(&fds);
> +   FD_SET(0, &fds);
> +   FD_SET(fd, &fds);
> +   while (1) {
> +      int waiting_for_flip = 1;
> +
> +      const struct framebuffer *back_fb = &fbs[front_buffer ^ 1];
> +      glBindFramebuffer(GL_FRAMEBUFFER, back_fb->gl_fb);
> +      render_stuff(&gl);
> +      if (egl_sync_supported) {
> +         egl_sync_fence(dpy, &gl);
> +      } else {
> +         glFinish();
> +      }
> +
> +      ret = drmModePageFlip(fd, kms.encoder->crtc_id, back_fb->fb_id,
> +                            DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);
> +      if (ret) {
> +         fprintf(stderr, "failed to queue page flip: %s\n",
> strerror(errno));
> +         goto free_saved_crtc;
> +      }
> +
> +      while (waiting_for_flip) {
> +         ret = select(fd + 1, &fds, NULL, NULL, NULL);
> +         if (ret < 0) {
> +            fprintf(stderr, "select err: %s\n", strerror(errno));
> +            goto free_saved_crtc;
> +         } else if (ret == 0) {
> +            fprintf(stderr, "select timeout!\n");
> +            goto free_saved_crtc;
> +         } else if (FD_ISSET(0, &fds)) {
> +            printf("exit due to user-input\n");
> +            got_user_input = 1;
> +            break;
> +         } else if (FD_ISSET(fd, &fds)) {
> +            drmHandleEvent(fd, &evctx);
> +         }
> +      }
> +
> +      if (got_user_input) {
> +         break;
> +      }
> +      front_buffer ^= 1;
> +   }
> +
> +   getchar();
> +
> +   ret = drmModeSetCrtc(fd, saved_crtc->crtc_id, saved_crtc->buffer_id,
> +                        saved_crtc->x, saved_crtc->y,
> +                        &kms.connector->connector_id, 1,
> &saved_crtc->mode);
> +   if (ret) {
> +      fprintf(stderr, "failed to restore crtc: %m\n");
> +   }
> +
> +free_saved_crtc:
> +   drmModeFreeCrtc(saved_crtc);
> +rm_gl_fb:
> +   for (size_t i = 0; i < NUM_BUFFERS; i++) {
> +      glDeleteFramebuffers(1, &fbs[i].gl_fb);
> +      glDeleteTextures(1, &fbs[i].gl_tex);
> +   }
> +rm_fb:
> +   for (size_t i = 0; i < NUM_BUFFERS; i++) {
> +      eglDestroyImageKHR(dpy, fbs[i].image);
> +      drmModeRmFB(fd, fbs[i].fb_id);
> +      close(fbs[i].fd);
> +      gbm_bo_destroy(fbs[i].bo);
> +   }
> +   eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
> +destroy_context:
> +   eglDestroyContext(dpy, ctx);
> +egl_terminate:
> +   eglTerminate(dpy);
> +destroy_gbm_device:
> +   gbm_device_destroy(gbm);
> +close_fd:
> +   close(fd);
> +
> +   return ret;
> +}
> --
> 2.5.0
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/mesa-dev/attachments/20160506/bac3aaa1/attachment-0001.html>


More information about the mesa-dev mailing list