<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>