[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