<div dir="ltr">Andreas, Adam, could you review?<div><br></div><div>Br, DS</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Apr 29, 2016 at 7:54 AM, Dongseong Hwang <span dir="ltr"><<a href="mailto:dongseong.hwang@intel.com" target="_blank">dongseong.hwang@intel.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">This demo shows how ChromeOS renders OpenGL ES2 via kms, drm and gbm.<br>
This demo consists of<br>
1. kms modesetting and vsync<br>
2. EGL and GLES2 context creation<br>
3. gbm bo creation and EGL Image binding<br>
<br>
drm connection code is copied from eglkms.<br>
ES2 rendering code is copied from es2tri.<br>
<br>
Signed-off-by: Dongseong Hwang <<a href="mailto:dongseong.hwang@intel.com">dongseong.hwang@intel.com</a>><br>
---<br>
 src/egl/opengles2/Makefile.am |   9 +<br>
 src/egl/opengles2/es2eglkms.c | 608 ++++++++++++++++++++++++++++++++++++++++++<br>
 2 files changed, 617 insertions(+)<br>
 create mode 100644 src/egl/opengles2/es2eglkms.c<br>
<br>
diff --git a/src/egl/opengles2/Makefile.am b/src/egl/opengles2/Makefile.am<br>
index b80ba50..2564a74 100644<br>
--- a/src/egl/opengles2/Makefile.am<br>
+++ b/src/egl/opengles2/Makefile.am<br>
@@ -45,6 +45,11 @@ endif<br>
 if HAVE_WAYLAND<br>
 bin_PROGRAMS += es2gears_wayland<br>
 endif<br>
+if HAVE_DRM<br>
+if HAVE_GBM<br>
+bin_PROGRAMS += es2eglkms<br>
+endif<br>
+endif<br>
 endif<br>
 endif<br>
<br>
@@ -57,3 +62,7 @@ es2gears_x11_LDADD = ../eglut/<a href="http://libeglut_x11.la" rel="noreferrer" target="_blank">libeglut_x11.la</a><br>
<br>
 es2gears_wayland_SOURCES = es2gears.c<br>
 es2gears_wayland_LDADD = ../eglut/<a href="http://libeglut_wayland.la" rel="noreferrer" target="_blank">libeglut_wayland.la</a><br>
+<br>
+es2eglkms_SOURCES = es2eglkms.c<br>
+es2eglkms_CFLAGS = $(AM_CFLAGS) $(DRM_CFLAGS) $(GBM_CFLAGS)<br>
+es2eglkms_LDADD = $(AM_LDFLAGS) $(DRM_LIBS) $(GBM_LIBS)<br>
\ No newline at end of file<br>
diff --git a/src/egl/opengles2/es2eglkms.c b/src/egl/opengles2/es2eglkms.c<br>
new file mode 100644<br>
index 0000000..95b3ade<br>
--- /dev/null<br>
+++ b/src/egl/opengles2/es2eglkms.c<br>
@@ -0,0 +1,608 @@<br>
+/*<br>
+ * Copyright © 2016 Dongseong Hwang<br>
+ *<br>
+ * Permission to use, copy, modify, distribute, and sell this software and its<br>
+ * documentation for any purpose is hereby granted without fee, provided that<br>
+ * the above copyright notice appear in all copies and that both that copyright<br>
+ * notice and this permission notice appear in supporting documentation, and<br>
+ * that the name of the copyright holders not be used in advertising or<br>
+ * publicity pertaining to distribution of the software without specific,<br>
+ * written prior permission.  The copyright holders make no representations<br>
+ * about the suitability of this software for any purpose.  It is provided "as<br>
+ * is" without express or implied warranty.<br>
+ *<br>
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,<br>
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO<br>
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR<br>
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,<br>
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER<br>
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE<br>
+ * OF THIS SOFTWARE.<br>
+ */<br>
+<br>
+#include <math.h><br>
+#include <stdio.h><br>
+#include <stdlib.h><br>
+#include <errno.h><br>
+<br>
+#define EGL_EGLEXT_PROTOTYPES<br>
+#define GL_GLEXT_PROTOTYPES<br>
+<br>
+#include <gbm.h><br>
+#include <GLES2/gl2.h><br>
+#include <GLES2/gl2ext.h><br>
+#include <EGL/egl.h><br>
+#include <EGL/eglext.h><br>
+#include <drm.h><br>
+#include <xf86drm.h><br>
+#include <xf86drmMode.h><br>
+#include <fcntl.h><br>
+#include <unistd.h><br>
+#include <string.h><br>
+<br>
+// double buffering<br>
+#define NUM_BUFFERS 2<br>
+<br>
+struct framebuffer {<br>
+   struct gbm_bo *bo;<br>
+   int fd;<br>
+   uint32_t fb_id;<br>
+   EGLImageKHR image;<br>
+   GLuint gl_tex;<br>
+   GLuint gl_fb;<br>
+};<br>
+<br>
+struct kms {<br>
+   drmModeConnector *connector;<br>
+   drmModeEncoder *encoder;<br>
+   drmModeModeInfo mode;<br>
+};<br>
+<br>
+struct gl {<br>
+   GLuint program;<br>
+   GLfloat view_rotz;<br>
+   GLint u_matrix;<br>
+   GLint attr_pos;<br>
+   GLint attr_color;<br>
+<br>
+   PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR;<br>
+   PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR;<br>
+};<br>
+<br>
+static void make_z_rot_matrix(GLfloat angle, GLfloat *m)<br>
+{<br>
+   float c = cos(angle * M_PI / 180.0);<br>
+   float s = sin(angle * M_PI / 180.0);<br>
+   int i;<br>
+   for (i = 0; i < 16; i++)<br>
+      m[i] = 0.0;<br>
+   m[0] = m[5] = m[10] = m[15] = 1.0;<br>
+<br>
+   m[0] = c;<br>
+   m[1] = s;<br>
+   m[4] = -s;<br>
+   m[5] = c;<br>
+}<br>
+<br>
+static void make_scale_matrix(GLfloat xs, GLfloat ys, GLfloat zs, GLfloat *m)<br>
+{<br>
+   int i;<br>
+   for (i = 0; i < 16; i++)<br>
+      m[i] = 0.0;<br>
+   m[0] = xs;<br>
+   m[5] = ys;<br>
+   m[10] = zs;<br>
+   m[15] = 1.0;<br>
+}<br>
+<br>
+static void mul_matrix(GLfloat *prod, const GLfloat *a, const GLfloat *b)<br>
+{<br>
+#define A(row, col) a[(col << 2) + row]<br>
+#define B(row, col) b[(col << 2) + row]<br>
+#define P(row, col) p[(col << 2) + row]<br>
+   GLfloat p[16];<br>
+   GLint i;<br>
+   for (i = 0; i < 4; i++) {<br>
+      const GLfloat ai0 = A(i, 0), ai1 = A(i, 1), ai2 = A(i, 2), ai3 = A(i, 3);<br>
+      P(i, 0) = ai0 * B(0, 0) + ai1 * B(1, 0) + ai2 * B(2, 0) + ai3 * B(3, 0);<br>
+      P(i, 1) = ai0 * B(0, 1) + ai1 * B(1, 1) + ai2 * B(2, 1) + ai3 * B(3, 1);<br>
+      P(i, 2) = ai0 * B(0, 2) + ai1 * B(1, 2) + ai2 * B(2, 2) + ai3 * B(3, 2);<br>
+      P(i, 3) = ai0 * B(0, 3) + ai1 * B(1, 3) + ai2 * B(2, 3) + ai3 * B(3, 3);<br>
+   }<br>
+   memcpy(prod, p, sizeof(p));<br>
+#undef A<br>
+#undef B<br>
+#undef PROD<br>
+}<br>
+<br>
+static EGLBoolean setup_kms(int fd, struct kms *kms)<br>
+{<br>
+   drmModeRes *resources;<br>
+   drmModeConnector *connector;<br>
+   drmModeEncoder *encoder;<br>
+   int i;<br>
+<br>
+   resources = drmModeGetResources(fd);<br>
+   if (!resources) {<br>
+      fprintf(stderr, "drmModeGetResources failed\n");<br>
+      return EGL_FALSE;<br>
+   }<br>
+<br>
+   for (i = 0; i < resources->count_connectors; i++) {<br>
+      connector = drmModeGetConnector(fd, resources->connectors[i]);<br>
+      if (connector == NULL)<br>
+         continue;<br>
+<br>
+      if (connector->connection == DRM_MODE_CONNECTED &&<br>
+          connector->count_modes > 0)<br>
+         break;<br>
+<br>
+      drmModeFreeConnector(connector);<br>
+   }<br>
+<br>
+   if (i == resources->count_connectors) {<br>
+      fprintf(stderr, "No currently active connector found.\n");<br>
+      return EGL_FALSE;<br>
+   }<br>
+<br>
+   for (i = 0; i < resources->count_encoders; i++) {<br>
+      encoder = drmModeGetEncoder(fd, resources->encoders[i]);<br>
+<br>
+      if (encoder == NULL)<br>
+         continue;<br>
+<br>
+      if (encoder->encoder_id == connector->encoder_id)<br>
+         break;<br>
+<br>
+      drmModeFreeEncoder(encoder);<br>
+   }<br>
+<br>
+   kms->connector = connector;<br>
+   kms->encoder = encoder;<br>
+   kms->mode = connector->modes[0];<br>
+<br>
+   return EGL_TRUE;<br>
+}<br>
+<br>
+static void gl_init(struct gl *gl, int width, int height)<br>
+{<br>
+   glClearColor(0.4, 0.4, 0.4, 0.0);<br>
+<br>
+   static const char *fragShaderText =<br>
+       "precision mediump float;\n"<br>
+       "varying vec4 v_color;\n"<br>
+       "void main() {\n"<br>
+       "   gl_FragColor = v_color;\n"<br>
+       "}\n";<br>
+   static const char *vertShaderText =<br>
+       "uniform mat4 modelviewProjection;\n"<br>
+       "attribute vec4 pos;\n"<br>
+       "attribute vec4 color;\n"<br>
+       "varying vec4 v_color;\n"<br>
+       "void main() {\n"<br>
+       "   gl_Position = modelviewProjection * pos;\n"<br>
+       "   v_color = color;\n"<br>
+       "}\n";<br>
+<br>
+   GLuint fragShader, vertShader;<br>
+   GLint stat;<br>
+<br>
+   fragShader = glCreateShader(GL_FRAGMENT_SHADER);<br>
+   glShaderSource(fragShader, 1, (const char **)&fragShaderText, NULL);<br>
+   glCompileShader(fragShader);<br>
+   glGetShaderiv(fragShader, GL_COMPILE_STATUS, &stat);<br>
+   if (!stat) {<br>
+      printf("Error: fragment shader did not compile!\n");<br>
+      exit(1);<br>
+   }<br>
+<br>
+   vertShader = glCreateShader(GL_VERTEX_SHADER);<br>
+   glShaderSource(vertShader, 1, (const char **)&vertShaderText, NULL);<br>
+   glCompileShader(vertShader);<br>
+   glGetShaderiv(vertShader, GL_COMPILE_STATUS, &stat);<br>
+   if (!stat) {<br>
+      printf("Error: vertex shader did not compile!\n");<br>
+      exit(1);<br>
+   }<br>
+<br>
+   gl->program = glCreateProgram();<br>
+   glAttachShader(gl->program, fragShader);<br>
+   glAttachShader(gl->program, vertShader);<br>
+<br>
+   gl->attr_pos = 0;<br>
+   gl->attr_color = 1;<br>
+   glBindAttribLocation(gl->program, gl->attr_pos, "pos");<br>
+   glBindAttribLocation(gl->program, gl->attr_color, "color");<br>
+   glLinkProgram(gl->program);<br>
+   glGetProgramiv(gl->program, GL_LINK_STATUS, &stat);<br>
+   if (!stat) {<br>
+      char log[1000];<br>
+      GLsizei len;<br>
+      glGetProgramInfoLog(gl->program, 1000, &len, log);<br>
+      printf("Error: linking:\n%s\n", log);<br>
+      exit(1);<br>
+   }<br>
+<br>
+   glUseProgram(gl->program);<br>
+<br>
+   gl->u_matrix = glGetUniformLocation(gl->program, "modelviewProjection");<br>
+   printf("Uniform modelviewProjection at %d\n", gl->u_matrix);<br>
+   printf("Attrib pos at %d\n", gl->attr_pos);<br>
+   printf("Attrib color at %d\n", gl->attr_color);<br>
+<br>
+   gl->view_rotz = 0;<br>
+<br>
+   glViewport(0, 0, (GLint)width, (GLint)height);<br>
+}<br>
+<br>
+static void render_stuff(struct gl *gl)<br>
+{<br>
+   static const GLfloat verts[3][2] = { { -1, -1 }, { 1, -1 }, { 0, 1 } };<br>
+   static const GLfloat colors[3][3] = {<br>
+      { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 }<br>
+   };<br>
+   GLfloat mat[16], rot[16], scale[16];<br>
+<br>
+   gl->view_rotz += 1.0;<br>
+<br>
+   glClear(GL_COLOR_BUFFER_BIT);<br>
+<br>
+   /* Set modelview/projection matrix */<br>
+   make_z_rot_matrix(gl->view_rotz, rot);<br>
+   make_scale_matrix(0.5, 0.5, 0.5, scale);<br>
+   mul_matrix(mat, rot, scale);<br>
+   glUniformMatrix4fv(gl->u_matrix, 1, GL_FALSE, mat);<br>
+<br>
+   glVertexAttribPointer(gl->attr_pos, 2, GL_FLOAT, GL_FALSE, 0, verts);<br>
+   glVertexAttribPointer(gl->attr_color, 3, GL_FLOAT, GL_FALSE, 0, colors);<br>
+   glEnableVertexAttribArray(gl->attr_pos);<br>
+   glEnableVertexAttribArray(gl->attr_color);<br>
+<br>
+   glDrawArrays(GL_TRIANGLES, 0, 3);<br>
+}<br>
+<br>
+static void egl_sync_fence(EGLDisplay dpy, struct gl *gl)<br>
+{<br>
+   EGLSyncKHR sync = gl->eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);<br>
+   glFlush();<br>
+   gl->eglClientWaitSyncKHR(dpy, sync, 0, EGL_FOREVER_KHR);<br>
+}<br>
+<br>
+static int has_extension(const char *extension, const char *extensions)<br>
+{<br>
+   const char *start, *where, *terminator;<br>
+   start = extensions;<br>
+   for (;;) {<br>
+      where = (char *)strstr((const char *)start, extension);<br>
+      if (!where)<br>
+         break;<br>
+      terminator = where + strlen(extension);<br>
+      if (where == start || *(where - 1) == ' ')<br>
+         if (*terminator == ' ' || *terminator == '\0')<br>
+            return 0;<br>
+      start = terminator;<br>
+   }<br>
+   return -1;<br>
+}<br>
+<br>
+static void page_flip_handler(int fd, unsigned int frame, unsigned int sec,<br>
+                              unsigned int usec, void *data)<br>
+{<br>
+   int *waiting_for_flip = data;<br>
+   *waiting_for_flip = 0;<br>
+}<br>
+<br>
+static const char device_name[] = "/dev/dri/card0";<br>
+<br>
+int main(int argc, char *argv[])<br>
+{<br>
+   EGLDisplay dpy;<br>
+   EGLContext ctx;<br>
+   EGLConfig config;<br>
+   EGLint major, minor, n;<br>
+   // Names are the original gl/egl function names with the prefix chopped off.<br>
+   PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;<br>
+   PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;<br>
+   PFNGLEGLIMAGETARGETTEXTURE2DOESPROC eglImageTargetTexture2DOES;<br>
+   int egl_sync_supported = 0;<br>
+   struct gl gl;<br>
+   const char *ver;<br>
+   uint32_t handle, stride;<br>
+   struct kms kms;<br>
+   int ret, fd;<br>
+   struct gbm_device *gbm;<br>
+   struct gbm_bo *bo;<br>
+   drmModeCrtcPtr saved_crtc;<br>
+   struct framebuffer fbs[NUM_BUFFERS];<br>
+   int front_buffer;<br>
+   drmEventContext evctx = {<br>
+      .version = DRM_EVENT_CONTEXT_VERSION,<br>
+      .page_flip_handler = page_flip_handler,<br>
+   };<br>
+   fd_set fds;<br>
+<br>
+   fd = open(device_name, O_RDWR);<br>
+   if (fd < 0) {<br>
+      /* Probably permissions error */<br>
+      fprintf(stderr, "couldn't open %s, skipping\n", device_name);<br>
+      return -1;<br>
+   }<br>
+<br>
+   gbm = gbm_create_device(fd);<br>
+   if (gbm == NULL) {<br>
+      fprintf(stderr, "couldn't create gbm device\n");<br>
+      ret = -1;<br>
+      goto close_fd;<br>
+   }<br>
+<br>
+   eglCreateImageKHR =<br>
+       (PFNEGLCREATEIMAGEKHRPROC)eglGetProcAddress("eglCreateImageKHR");<br>
+   eglDestroyImageKHR =<br>
+       (PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress("eglDestroyImageKHR");<br>
+   eglImageTargetTexture2DOES =<br>
+       (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)eglGetProcAddress(<br>
+           "glEGLImageTargetTexture2DOES");<br>
+   gl.eglCreateSyncKHR =<br>
+       (PFNEGLCREATESYNCKHRPROC)eglGetProcAddress("eglCreateSyncKHR");<br>
+   gl.eglClientWaitSyncKHR =<br>
+       (PFNEGLCLIENTWAITSYNCKHRPROC)eglGetProcAddress("eglClientWaitSyncKHR");<br>
+   if (!eglCreateImageKHR || !eglDestroyImageKHR ||<br>
+       !eglImageTargetTexture2DOES) {<br>
+      fprintf(stderr,<br>
+              "eglGetProcAddress returned NULL for a required extension entry "<br>
+              "point.\n");<br>
+      ret = -1;<br>
+      goto destroy_gbm_device;<br>
+   }<br>
+   if (gl.eglCreateSyncKHR && gl.eglClientWaitSyncKHR) {<br>
+      egl_sync_supported = 1;<br>
+   }<br>
+<br>
+   dpy = eglGetDisplay(gbm);<br>
+   if (dpy == EGL_NO_DISPLAY) {<br>
+      fprintf(stderr, "eglGetDisplay() failed\n");<br>
+      ret = -1;<br>
+      goto destroy_gbm_device;<br>
+   }<br>
+<br>
+   if (!eglInitialize(dpy, &major, &minor)) {<br>
+      fprintf(stderr, "eglInitialize() failed\n");<br>
+      ret = -1;<br>
+      goto egl_terminate;<br>
+   }<br>
+<br>
+   ver = eglQueryString(dpy, EGL_VERSION);<br>
+   printf("EGL_VERSION = %s\n", ver);<br>
+<br>
+   if (!setup_kms(fd, &kms)) {<br>
+      ret = -1;<br>
+      goto egl_terminate;<br>
+   }<br>
+<br>
+   if (!eglBindAPI(EGL_OPENGL_ES_API)) {<br>
+      fprintf(stderr, "failed to bind api EGL_OPENGL_ES_API\n");<br>
+      ret = -1;<br>
+      goto egl_terminate;<br>
+   }<br>
+<br>
+   static const EGLint attribs[] = { EGL_SURFACE_TYPE, EGL_DONT_CARE,<br>
+                                     EGL_NONE };<br>
+<br>
+   if (!eglChooseConfig(dpy, attribs, &config, 1, &n) || n != 1) {<br>
+      fprintf(stderr, "failed to choose argb config\n");<br>
+      goto egl_terminate;<br>
+   }<br>
+<br>
+   static const EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2,<br>
+                                             EGL_NONE };<br>
+<br>
+   ctx = eglCreateContext(dpy, config, EGL_NO_CONTEXT, context_attribs);<br>
+   if (ctx == NULL) {<br>
+      fprintf(stderr, "failed to create context\n");<br>
+      ret = -1;<br>
+      goto egl_terminate;<br>
+   }<br>
+<br>
+   if (!eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx)) {<br>
+      fprintf(stderr, "failed to make context current\n");<br>
+      ret = -1;<br>
+      goto destroy_context;<br>
+   }<br>
+<br>
+   const char *egl_extensions = eglQueryString(dpy, EGL_EXTENSIONS);<br>
+   printf("EGL Extensions \"%s\"\n", egl_extensions);<br>
+   if (has_extension("EGL_KHR_image_base", egl_extensions)) {<br>
+      fprintf(stderr, "EGL_KHR_image_base extension not supported\n");<br>
+      ret = -1;<br>
+      goto destroy_context;<br>
+   }<br>
+   if (has_extension("EGL_EXT_image_dma_buf_import", egl_extensions)) {<br>
+      fprintf(stderr, "EGL_EXT_image_dma_buf_import extension not supported\n");<br>
+      ret = -1;<br>
+      goto destroy_context;<br>
+   }<br>
+<br>
+   const char *gl_extensions = (const char *)glGetString(GL_EXTENSIONS);<br>
+   if (has_extension("GL_OES_EGL_image", gl_extensions)) {<br>
+      fprintf(stderr, "GL_OES_EGL_image extension not supported\n");<br>
+      ret = -1;<br>
+      goto destroy_context;<br>
+   }<br>
+<br>
+   uint32_t width = kms.mode.hdisplay;<br>
+   uint32_t height = kms.mode.vdisplay;<br>
+<br>
+   for (size_t i = 0; i < NUM_BUFFERS; i++) {<br>
+      fbs[i].bo = gbm_bo_create(gbm, width, height, GBM_FORMAT_XRGB8888,<br>
+                                GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);<br>
+      if (!fbs[i].bo) {<br>
+         fprintf(stderr, "failed to create a gbm buffer.\n");<br>
+         ret = -1;<br>
+         goto rm_fb;<br>
+      }<br>
+<br>
+      fbs[i].fd = gbm_bo_get_fd(fbs[i].bo);<br>
+      if (fbs[i].fd < 0) {<br>
+         fprintf(stderr, "failed to get fb for bo: %d", fbs[i].fd);<br>
+         ret = -1;<br>
+         goto rm_fb;<br>
+      }<br>
+<br>
+      uint32_t handle = gbm_bo_get_handle(fbs[i].bo).u32;<br>
+      uint32_t stride = gbm_bo_get_stride(fbs[i].bo);<br>
+      uint32_t offset = 0;<br>
+      drmModeAddFB2(fd, width, height, GBM_FORMAT_XRGB8888, &handle, &stride,<br>
+                    &offset, &fbs[i].fb_id, 0);<br>
+      if (!fbs[i].fb_id) {<br>
+         fprintf(stderr, "failed to create framebuffer from buffer object.\n");<br>
+         ret = -1;<br>
+         goto rm_fb;<br>
+      }<br>
+<br>
+      const EGLint khr_image_attrs[] = { EGL_DMA_BUF_PLANE0_FD_EXT,<br>
+                                         fbs[i].fd,<br>
+                                         EGL_WIDTH,<br>
+                                         width,<br>
+                                         EGL_HEIGHT,<br>
+                                         height,<br>
+                                         EGL_LINUX_DRM_FOURCC_EXT,<br>
+                                         GBM_FORMAT_XRGB8888,<br>
+                                         EGL_DMA_BUF_PLANE0_PITCH_EXT,<br>
+                                         stride,<br>
+                                         EGL_DMA_BUF_PLANE0_OFFSET_EXT,<br>
+                                         offset,<br>
+                                         EGL_NONE };<br>
+<br>
+      fbs[i].image =<br>
+          eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT,<br>
+                            NULL /* no client buffer */, khr_image_attrs);<br>
+      if (fbs[i].image == EGL_NO_IMAGE_KHR) {<br>
+         fprintf(stderr, "failed to make image from buffer object: %x\n",<br>
+                 eglGetError());<br>
+         ret = -1;<br>
+         goto rm_fb;<br>
+      }<br>
+<br>
+      glGenTextures(1, &fbs[i].gl_tex);<br>
+      glBindTexture(GL_TEXTURE_2D, fbs[i].gl_tex);<br>
+      eglImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)fbs[i].image);<br>
+      glBindTexture(GL_TEXTURE_2D, 0);<br>
+<br>
+      glGenFramebuffers(1, &fbs[i].gl_fb);<br>
+      glBindFramebuffer(GL_FRAMEBUFFER, fbs[i].gl_fb);<br>
+      glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,<br>
+                             GL_TEXTURE_2D, fbs[i].gl_tex, 0);<br>
+<br>
+      if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {<br>
+         fprintf(stderr,<br>
+                 "failed framebuffer check for created target buffer: %x\n",<br>
+                 glCheckFramebufferStatus(GL_FRAMEBUFFER));<br>
+         ret = -1;<br>
+         goto rm_gl_fb;<br>
+      }<br>
+   }<br>
+<br>
+   gl_init(&gl, width, height);<br>
+   glClear(GL_COLOR_BUFFER_BIT);<br>
+   if (egl_sync_supported) {<br>
+      egl_sync_fence(dpy, &gl);<br>
+   } else {<br>
+      glFinish();<br>
+   }<br>
+<br>
+   front_buffer = 0;<br>
+   const struct framebuffer *back_fb = &fbs[front_buffer ^ 1];<br>
+<br>
+   saved_crtc = drmModeGetCrtc(fd, kms.encoder->crtc_id);<br>
+   if (saved_crtc == NULL)<br>
+      goto rm_gl_fb;<br>
+<br>
+   ret = drmModeSetCrtc(fd, kms.encoder->crtc_id, back_fb->fb_id, 0, 0,<br>
+                        &kms.connector->connector_id, 1, &kms.mode);<br>
+   if (ret) {<br>
+      fprintf(stderr, "failed to set mode: %m\n");<br>
+      goto free_saved_crtc;<br>
+   }<br>
+<br>
+   front_buffer ^= 1;<br>
+   int got_user_input = 0;<br>
+   FD_ZERO(&fds);<br>
+   FD_SET(0, &fds);<br>
+   FD_SET(fd, &fds);<br>
+   while (1) {<br>
+      int waiting_for_flip = 1;<br>
+<br>
+      const struct framebuffer *back_fb = &fbs[front_buffer ^ 1];<br>
+      glBindFramebuffer(GL_FRAMEBUFFER, back_fb->gl_fb);<br>
+      render_stuff(&gl);<br>
+      if (egl_sync_supported) {<br>
+         egl_sync_fence(dpy, &gl);<br>
+      } else {<br>
+         glFinish();<br>
+      }<br>
+<br>
+      ret = drmModePageFlip(fd, kms.encoder->crtc_id, back_fb->fb_id,<br>
+                            DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);<br>
+      if (ret) {<br>
+         fprintf(stderr, "failed to queue page flip: %s\n", strerror(errno));<br>
+         goto free_saved_crtc;<br>
+      }<br>
+<br>
+      while (waiting_for_flip) {<br>
+         ret = select(fd + 1, &fds, NULL, NULL, NULL);<br>
+         if (ret < 0) {<br>
+            fprintf(stderr, "select err: %s\n", strerror(errno));<br>
+            goto free_saved_crtc;<br>
+         } else if (ret == 0) {<br>
+            fprintf(stderr, "select timeout!\n");<br>
+            goto free_saved_crtc;<br>
+         } else if (FD_ISSET(0, &fds)) {<br>
+            printf("exit due to user-input\n");<br>
+            got_user_input = 1;<br>
+            break;<br>
+         } else if (FD_ISSET(fd, &fds)) {<br>
+            drmHandleEvent(fd, &evctx);<br>
+         }<br>
+      }<br>
+<br>
+      if (got_user_input) {<br>
+         break;<br>
+      }<br>
+      front_buffer ^= 1;<br>
+   }<br>
+<br>
+   getchar();<br>
+<br>
+   ret = drmModeSetCrtc(fd, saved_crtc->crtc_id, saved_crtc->buffer_id,<br>
+                        saved_crtc->x, saved_crtc->y,<br>
+                        &kms.connector->connector_id, 1, &saved_crtc->mode);<br>
+   if (ret) {<br>
+      fprintf(stderr, "failed to restore crtc: %m\n");<br>
+   }<br>
+<br>
+free_saved_crtc:<br>
+   drmModeFreeCrtc(saved_crtc);<br>
+rm_gl_fb:<br>
+   for (size_t i = 0; i < NUM_BUFFERS; i++) {<br>
+      glDeleteFramebuffers(1, &fbs[i].gl_fb);<br>
+      glDeleteTextures(1, &fbs[i].gl_tex);<br>
+   }<br>
+rm_fb:<br>
+   for (size_t i = 0; i < NUM_BUFFERS; i++) {<br>
+      eglDestroyImageKHR(dpy, fbs[i].image);<br>
+      drmModeRmFB(fd, fbs[i].fb_id);<br>
+      close(fbs[i].fd);<br>
+      gbm_bo_destroy(fbs[i].bo);<br>
+   }<br>
+   eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);<br>
+destroy_context:<br>
+   eglDestroyContext(dpy, ctx);<br>
+egl_terminate:<br>
+   eglTerminate(dpy);<br>
+destroy_gbm_device:<br>
+   gbm_device_destroy(gbm);<br>
+close_fd:<br>
+   close(fd);<br>
+<br>
+   return ret;<br>
+}<br>
<span class="HOEnZb"><font color="#888888">--<br>
2.5.0<br>
<br>
</font></span></blockquote></div><br></div>