Put vertex attribute data into a VBO.
[glsdk/kmscube.git] / kmscube.c
1 /*
2  * Copyright (c) 2012 Arvin Schnell <arvin.schnell@gmail.com>
3  * Copyright (c) 2012 Rob Clark <rob@ti.com>
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sub license,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial portions
14  * of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
25 /* Based on a egl cube test app originally written by Arvin Schnell */
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <errno.h>
35 #include <xf86drm.h>
36 #include <xf86drmMode.h>
37 #include <gbm.h>
39 #include "esUtil.h"
42 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
45 static struct {
46         EGLDisplay display;
47         EGLConfig config;
48         EGLContext context;
49         EGLSurface surface;
50         GLuint program;
51         GLint modelviewmatrix, modelviewprojectionmatrix, normalmatrix;
52         GLuint vbo;
53         GLuint positionsoffset, colorsoffset, normalsoffset;
54 } gl;
56 static struct {
57         struct gbm_device *dev;
58         struct gbm_surface *surface;
59 } gbm;
61 static struct {
62         int fd;
63         drmModeModeInfo *mode;
64         uint32_t crtc_id;
65         uint32_t connector_id;
66 } drm;
68 struct drm_fb {
69         struct gbm_bo *bo;
70         uint32_t fb_id;
71 };
73 static int init_drm(void)
74 {
75         static const char *modules[] = {
76                         "i915", "radeon", "nouveau", "vmwgfx", "omapdrm", "exynos"
77         };
78         drmModeRes *resources;
79         drmModeConnector *connector = NULL;
80         drmModeEncoder *encoder = NULL;
81         int i, area;
83         for (i = 0; i < ARRAY_SIZE(modules); i++) {
84                 printf("trying to load module %s...", modules[i]);
85                 drm.fd = drmOpen(modules[i], NULL);
86                 if (drm.fd < 0) {
87                         printf("failed.\n");
88                 } else {
89                         printf("success.\n");
90                         break;
91                 }
92         }
94         if (drm.fd < 0) {
95                 printf("could not open drm device\n");
96                 return -1;
97         }
99         resources = drmModeGetResources(drm.fd);
100         if (!resources) {
101                 printf("drmModeGetResources failed: %s\n", strerror(errno));
102                 return -1;
103         }
105         /* find a connected connector: */
106         for (i = 0; i < resources->count_connectors; i++) {
107                 connector = drmModeGetConnector(drm.fd, resources->connectors[i]);
108                 if (connector->connection == DRM_MODE_CONNECTED) {
109                         /* it's connected, let's use this! */
110                         break;
111                 }
112                 drmModeFreeConnector(connector);
113                 connector = NULL;
114         }
116         if (!connector) {
117                 /* we could be fancy and listen for hotplug events and wait for
118                  * a connector..
119                  */
120                 printf("no connected connector!\n");
121                 return -1;
122         }
124         /* find highest resolution mode: */
125         for (i = 0, area = 0; i < connector->count_modes; i++) {
126                 drmModeModeInfo *current_mode = &connector->modes[i];
127                 int current_area = current_mode->hdisplay * current_mode->vdisplay;
128                 if (current_area > area) {
129                         drm.mode = current_mode;
130                         area = current_area;
131                 }
132         }
134         if (!drm.mode) {
135                 printf("could not find mode!\n");
136                 return -1;
137         }
139         /* find encoder: */
140         for (i = 0; i < resources->count_encoders; i++) {
141                 encoder = drmModeGetEncoder(drm.fd, resources->encoders[i]);
142                 if (encoder->encoder_id == connector->encoder_id)
143                         break;
144                 drmModeFreeEncoder(encoder);
145                 encoder = NULL;
146         }
148         if (!encoder) {
149                 printf("no encoder!\n");
150                 return -1;
151         }
153         drm.crtc_id = encoder->crtc_id;
154         drm.connector_id = connector->connector_id;
156         return 0;
159 static int init_gbm(void)
161         gbm.dev = gbm_create_device(drm.fd);
163         gbm.surface = gbm_surface_create(gbm.dev,
164                         drm.mode->hdisplay, drm.mode->vdisplay,
165                         GBM_FORMAT_XRGB8888,
166                         GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
167         if (!gbm.surface) {
168                 printf("failed to create gbm surface\n");
169                 return -1;
170         }
172         return 0;
175 static int init_gl(void)
177         EGLint major, minor, n;
178         GLuint vertex_shader, fragment_shader;
179         GLint ret;
181         static const GLfloat vVertices[] = {
182                         // front
183                         -1.0f, -1.0f, +1.0f, // point blue
184                         +1.0f, -1.0f, +1.0f, // point magenta
185                         -1.0f, +1.0f, +1.0f, // point cyan
186                         +1.0f, +1.0f, +1.0f, // point white
187                         // back
188                         +1.0f, -1.0f, -1.0f, // point red
189                         -1.0f, -1.0f, -1.0f, // point black
190                         +1.0f, +1.0f, -1.0f, // point yellow
191                         -1.0f, +1.0f, -1.0f, // point green
192                         // right
193                         +1.0f, -1.0f, +1.0f, // point magenta
194                         +1.0f, -1.0f, -1.0f, // point red
195                         +1.0f, +1.0f, +1.0f, // point white
196                         +1.0f, +1.0f, -1.0f, // point yellow
197                         // left
198                         -1.0f, -1.0f, -1.0f, // point black
199                         -1.0f, -1.0f, +1.0f, // point blue
200                         -1.0f, +1.0f, -1.0f, // point green
201                         -1.0f, +1.0f, +1.0f, // point cyan
202                         // top
203                         -1.0f, +1.0f, +1.0f, // point cyan
204                         +1.0f, +1.0f, +1.0f, // point white
205                         -1.0f, +1.0f, -1.0f, // point green
206                         +1.0f, +1.0f, -1.0f, // point yellow
207                         // bottom
208                         -1.0f, -1.0f, -1.0f, // point black
209                         +1.0f, -1.0f, -1.0f, // point red
210                         -1.0f, -1.0f, +1.0f, // point blue
211                         +1.0f, -1.0f, +1.0f  // point magenta
212         };
214         static const GLfloat vColors[] = {
215                         // front
216                         0.0f,  0.0f,  1.0f, // blue
217                         1.0f,  0.0f,  1.0f, // magenta
218                         0.0f,  1.0f,  1.0f, // cyan
219                         1.0f,  1.0f,  1.0f, // white
220                         // back
221                         1.0f,  0.0f,  0.0f, // red
222                         0.0f,  0.0f,  0.0f, // black
223                         1.0f,  1.0f,  0.0f, // yellow
224                         0.0f,  1.0f,  0.0f, // green
225                         // right
226                         1.0f,  0.0f,  1.0f, // magenta
227                         1.0f,  0.0f,  0.0f, // red
228                         1.0f,  1.0f,  1.0f, // white
229                         1.0f,  1.0f,  0.0f, // yellow
230                         // left
231                         0.0f,  0.0f,  0.0f, // black
232                         0.0f,  0.0f,  1.0f, // blue
233                         0.0f,  1.0f,  0.0f, // green
234                         0.0f,  1.0f,  1.0f, // cyan
235                         // top
236                         0.0f,  1.0f,  1.0f, // cyan
237                         1.0f,  1.0f,  1.0f, // white
238                         0.0f,  1.0f,  0.0f, // green
239                         1.0f,  1.0f,  0.0f, // yellow
240                         // bottom
241                         0.0f,  0.0f,  0.0f, // black
242                         1.0f,  0.0f,  0.0f, // red
243                         0.0f,  0.0f,  1.0f, // blue
244                         1.0f,  0.0f,  1.0f  // magenta
245         };
247         static const GLfloat vNormals[] = {
248                         // front
249                         +0.0f, +0.0f, +1.0f, // forward
250                         +0.0f, +0.0f, +1.0f, // forward
251                         +0.0f, +0.0f, +1.0f, // forward
252                         +0.0f, +0.0f, +1.0f, // forward
253                         // back
254                         +0.0f, +0.0f, -1.0f, // backbard
255                         +0.0f, +0.0f, -1.0f, // backbard
256                         +0.0f, +0.0f, -1.0f, // backbard
257                         +0.0f, +0.0f, -1.0f, // backbard
258                         // right
259                         +1.0f, +0.0f, +0.0f, // right
260                         +1.0f, +0.0f, +0.0f, // right
261                         +1.0f, +0.0f, +0.0f, // right
262                         +1.0f, +0.0f, +0.0f, // right
263                         // left
264                         -1.0f, +0.0f, +0.0f, // left
265                         -1.0f, +0.0f, +0.0f, // left
266                         -1.0f, +0.0f, +0.0f, // left
267                         -1.0f, +0.0f, +0.0f, // left
268                         // top
269                         +0.0f, +1.0f, +0.0f, // up
270                         +0.0f, +1.0f, +0.0f, // up
271                         +0.0f, +1.0f, +0.0f, // up
272                         +0.0f, +1.0f, +0.0f, // up
273                         // bottom
274                         +0.0f, -1.0f, +0.0f, // down
275                         +0.0f, -1.0f, +0.0f, // down
276                         +0.0f, -1.0f, +0.0f, // down
277                         +0.0f, -1.0f, +0.0f  // down
278         };
280         static const EGLint context_attribs[] = {
281                 EGL_CONTEXT_CLIENT_VERSION, 2,
282                 EGL_NONE
283         };
285         static const EGLint config_attribs[] = {
286                 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
287                 EGL_RED_SIZE, 1,
288                 EGL_GREEN_SIZE, 1,
289                 EGL_BLUE_SIZE, 1,
290                 EGL_ALPHA_SIZE, 0,
291                 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
292                 EGL_NONE
293         };
295         static const char *vertex_shader_source =
296                         "uniform mat4 modelviewMatrix;      \n"
297                         "uniform mat4 modelviewprojectionMatrix;\n"
298                         "uniform mat3 normalMatrix;         \n"
299                         "                                   \n"
300                         "attribute vec4 in_position;        \n"
301                         "attribute vec3 in_normal;          \n"
302                         "attribute vec4 in_color;           \n"
303                         "\n"
304                         "vec4 lightSource = vec4(2.0, 2.0, 20.0, 0.0);\n"
305                         "                                   \n"
306                         "varying vec4 vVaryingColor;        \n"
307                         "                                   \n"
308                         "void main()                        \n"
309                         "{                                  \n"
310                         "    gl_Position = modelviewprojectionMatrix * in_position;\n"
311                         "    vec3 vEyeNormal = normalMatrix * in_normal;\n"
312                         "    vec4 vPosition4 = modelviewMatrix * in_position;\n"
313                         "    vec3 vPosition3 = vPosition4.xyz / vPosition4.w;\n"
314                         "    vec3 vLightDir = normalize(lightSource.xyz - vPosition3);\n"
315                         "    float diff = max(0.0, dot(vEyeNormal, vLightDir));\n"
316                         "    vVaryingColor = vec4(diff * in_color.rgb, 1.0);\n"
317                         "}                                  \n";
319         static const char *fragment_shader_source =
320                         "precision mediump float;           \n"
321                         "                                   \n"
322                         "varying vec4 vVaryingColor;        \n"
323                         "                                   \n"
324                         "void main()                        \n"
325                         "{                                  \n"
326                         "    gl_FragColor = vVaryingColor;  \n"
327                         "}                                  \n";
329         gl.display = eglGetDisplay(gbm.dev);
331         if (!eglInitialize(gl.display, &major, &minor)) {
332                 printf("failed to initialize\n");
333                 return -1;
334         }
336         printf("Using display %p with EGL version %d.%d\n",
337                         gl.display, major, minor);
339         printf("EGL Version \"%s\"\n", eglQueryString(gl.display, EGL_VERSION));
340         printf("EGL Vendor \"%s\"\n", eglQueryString(gl.display, EGL_VENDOR));
341         printf("EGL Extensions \"%s\"\n", eglQueryString(gl.display, EGL_EXTENSIONS));
343         if (!eglBindAPI(EGL_OPENGL_ES_API)) {
344                 printf("failed to bind api EGL_OPENGL_ES_API\n");
345                 return -1;
346         }
348         if (!eglChooseConfig(gl.display, config_attribs, &gl.config, 1, &n) || n != 1) {
349                 printf("failed to choose config: %d\n", n);
350                 return -1;
351         }
353         gl.context = eglCreateContext(gl.display, gl.config,
354                         EGL_NO_CONTEXT, context_attribs);
355         if (gl.context == NULL) {
356                 printf("failed to create context\n");
357                 return -1;
358         }
360         gl.surface = eglCreateWindowSurface(gl.display, gl.config, gbm.surface, NULL);
361         if (gl.surface == EGL_NO_SURFACE) {
362                 printf("failed to create egl surface\n");
363                 return -1;
364         }
366         /* connect the context to the surface */
367         eglMakeCurrent(gl.display, gl.surface, gl.surface, gl.context);
370         vertex_shader = glCreateShader(GL_VERTEX_SHADER);
372         glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
373         glCompileShader(vertex_shader);
375         glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &ret);
376         if (!ret) {
377                 char *log;
379                 printf("vertex shader compilation failed!:\n");
380                 glGetShaderiv(vertex_shader, GL_INFO_LOG_LENGTH, &ret);
381                 if (ret > 1) {
382                         log = malloc(ret);
383                         glGetShaderInfoLog(vertex_shader, ret, NULL, log);
384                         printf("%s", log);
385                 }
387                 return -1;
388         }
390         fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
392         glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
393         glCompileShader(fragment_shader);
395         glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &ret);
396         if (!ret) {
397                 char *log;
399                 printf("fragment shader compilation failed!:\n");
400                 glGetShaderiv(fragment_shader, GL_INFO_LOG_LENGTH, &ret);
402                 if (ret > 1) {
403                         log = malloc(ret);
404                         glGetShaderInfoLog(fragment_shader, ret, NULL, log);
405                         printf("%s", log);
406                 }
408                 return -1;
409         }
411         gl.program = glCreateProgram();
413         glAttachShader(gl.program, vertex_shader);
414         glAttachShader(gl.program, fragment_shader);
416         glBindAttribLocation(gl.program, 0, "in_position");
417         glBindAttribLocation(gl.program, 1, "in_normal");
418         glBindAttribLocation(gl.program, 2, "in_color");
420         glLinkProgram(gl.program);
422         glGetProgramiv(gl.program, GL_LINK_STATUS, &ret);
423         if (!ret) {
424                 char *log;
426                 printf("program linking failed!:\n");
427                 glGetProgramiv(gl.program, GL_INFO_LOG_LENGTH, &ret);
429                 if (ret > 1) {
430                         log = malloc(ret);
431                         glGetProgramInfoLog(gl.program, ret, NULL, log);
432                         printf("%s", log);
433                 }
435                 return -1;
436         }
438         glUseProgram(gl.program);
440         gl.modelviewmatrix = glGetUniformLocation(gl.program, "modelviewMatrix");
441         gl.modelviewprojectionmatrix = glGetUniformLocation(gl.program, "modelviewprojectionMatrix");
442         gl.normalmatrix = glGetUniformLocation(gl.program, "normalMatrix");
444         glViewport(0, 0, drm.mode->hdisplay, drm.mode->vdisplay);
445         glEnable(GL_CULL_FACE);
447         gl.positionsoffset = 0;
448         gl.colorsoffset = sizeof(vVertices);
449         gl.normalsoffset = sizeof(vVertices) + sizeof(vColors);
450         glGenBuffers(1, &gl.vbo);
451         glBindBuffer(GL_ARRAY_BUFFER, gl.vbo);
452         glBufferData(GL_ARRAY_BUFFER, sizeof(vVertices) + sizeof(vColors) + sizeof(vNormals), 0, GL_STATIC_DRAW);
453         glBufferSubData(GL_ARRAY_BUFFER, gl.positionsoffset, sizeof(vVertices), &vVertices[0]);
454         glBufferSubData(GL_ARRAY_BUFFER, gl.colorsoffset, sizeof(vColors), &vColors[0]);
455         glBufferSubData(GL_ARRAY_BUFFER, gl.normalsoffset, sizeof(vNormals), &vNormals[0]);
456         glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)gl.positionsoffset);
457         glEnableVertexAttribArray(0);
458         glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)gl.normalsoffset);
459         glEnableVertexAttribArray(1);
460         glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)gl.colorsoffset);
461         glEnableVertexAttribArray(2);
463         return 0;
466 static void draw(uint32_t i)
468         ESMatrix modelview;
470         /* clear the color buffer */
471         glClearColor(0.5, 0.5, 0.5, 1.0);
472         glClear(GL_COLOR_BUFFER_BIT);
474         esMatrixLoadIdentity(&modelview);
475         esTranslate(&modelview, 0.0f, 0.0f, -8.0f);
476         esRotate(&modelview, 45.0f + (0.25f * i), 1.0f, 0.0f, 0.0f);
477         esRotate(&modelview, 45.0f - (0.5f * i), 0.0f, 1.0f, 0.0f);
478         esRotate(&modelview, 10.0f + (0.15f * i), 0.0f, 0.0f, 1.0f);
480         GLfloat aspect = (GLfloat)(drm.mode->vdisplay) / (GLfloat)(drm.mode->hdisplay);
482         ESMatrix projection;
483         esMatrixLoadIdentity(&projection);
484         esFrustum(&projection, -2.8f, +2.8f, -2.8f * aspect, +2.8f * aspect, 6.0f, 10.0f);
486         ESMatrix modelviewprojection;
487         esMatrixLoadIdentity(&modelviewprojection);
488         esMatrixMultiply(&modelviewprojection, &modelview, &projection);
490         float normal[9];
491         normal[0] = modelview.m[0][0];
492         normal[1] = modelview.m[0][1];
493         normal[2] = modelview.m[0][2];
494         normal[3] = modelview.m[1][0];
495         normal[4] = modelview.m[1][1];
496         normal[5] = modelview.m[1][2];
497         normal[6] = modelview.m[2][0];
498         normal[7] = modelview.m[2][1];
499         normal[8] = modelview.m[2][2];
501         glUniformMatrix4fv(gl.modelviewmatrix, 1, GL_FALSE, &modelview.m[0][0]);
502         glUniformMatrix4fv(gl.modelviewprojectionmatrix, 1, GL_FALSE, &modelviewprojection.m[0][0]);
503         glUniformMatrix3fv(gl.normalmatrix, 1, GL_FALSE, normal);
505         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
506         glDrawArrays(GL_TRIANGLE_STRIP, 4, 4);
507         glDrawArrays(GL_TRIANGLE_STRIP, 8, 4);
508         glDrawArrays(GL_TRIANGLE_STRIP, 12, 4);
509         glDrawArrays(GL_TRIANGLE_STRIP, 16, 4);
510         glDrawArrays(GL_TRIANGLE_STRIP, 20, 4);
513 static void
514 drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
516         struct drm_fb *fb = data;
517         struct gbm_device *gbm = gbm_bo_get_device(bo);
519         if (fb->fb_id)
520                 drmModeRmFB(drm.fd, fb->fb_id);
522         free(fb);
525 static struct drm_fb * drm_fb_get_from_bo(struct gbm_bo *bo)
527         struct drm_fb *fb = gbm_bo_get_user_data(bo);
528         uint32_t width, height, stride, handle;
529         int ret;
531         if (fb)
532                 return fb;
534         fb = calloc(1, sizeof *fb);
535         fb->bo = bo;
537         width = gbm_bo_get_width(bo);
538         height = gbm_bo_get_height(bo);
539         stride = gbm_bo_get_stride(bo);
540         handle = gbm_bo_get_handle(bo).u32;
542         ret = drmModeAddFB(drm.fd, width, height, 24, 32, stride, handle, &fb->fb_id);
543         if (ret) {
544                 printf("failed to create fb: %s\n", strerror(errno));
545                 free(fb);
546                 return NULL;
547         }
549         gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
551         return fb;
554 static void page_flip_handler(int fd, unsigned int frame,
555                   unsigned int sec, unsigned int usec, void *data)
557         int *waiting_for_flip = data;
558         *waiting_for_flip = 0;
561 int main(int argc, char *argv[])
563         fd_set fds;
564         drmEventContext evctx = {
565                         .version = DRM_EVENT_CONTEXT_VERSION,
566                         .page_flip_handler = page_flip_handler,
567         };
568         struct gbm_bo *bo;
569         struct drm_fb *fb;
570         uint32_t i = 0;
571         int ret;
573         ret = init_drm();
574         if (ret) {
575                 printf("failed to initialize DRM\n");
576                 return ret;
577         }
579         FD_ZERO(&fds);
580         FD_SET(0, &fds);
581         FD_SET(drm.fd, &fds);
583         ret = init_gbm();
584         if (ret) {
585                 printf("failed to initialize GBM\n");
586                 return ret;
587         }
589         ret = init_gl();
590         if (ret) {
591                 printf("failed to initialize EGL\n");
592                 return ret;
593         }
595         /* clear the color buffer */
596         glClearColor(0.5, 0.5, 0.5, 1.0);
597         glClear(GL_COLOR_BUFFER_BIT);
598         eglSwapBuffers(gl.display, gl.surface);
599         bo = gbm_surface_lock_front_buffer(gbm.surface);
600         fb = drm_fb_get_from_bo(bo);
602         /* set mode: */
603         ret = drmModeSetCrtc(drm.fd, drm.crtc_id, fb->fb_id, 0, 0,
604                         &drm.connector_id, 1, drm.mode);
605         if (ret) {
606                 printf("failed to set mode: %s\n", strerror(errno));
607                 return ret;
608         }
610         while (1) {
611                 struct gbm_bo *next_bo;
612                 int waiting_for_flip = 1;
614                 draw(i++);
616                 eglSwapBuffers(gl.display, gl.surface);
617                 next_bo = gbm_surface_lock_front_buffer(gbm.surface);
618                 fb = drm_fb_get_from_bo(next_bo);
620                 /*
621                  * Here you could also update drm plane layers if you want
622                  * hw composition
623                  */
625                 ret = drmModePageFlip(drm.fd, drm.crtc_id, fb->fb_id,
626                                 DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);
627                 if (ret) {
628                         printf("failed to queue page flip: %s\n", strerror(errno));
629                         return -1;
630                 }
632                 while (waiting_for_flip) {
633                         ret = select(drm.fd + 1, &fds, NULL, NULL, NULL);
634                         if (ret < 0) {
635                                 printf("select err: %s\n", strerror(errno));
636                                 return ret;
637                         } else if (ret == 0) {
638                                 printf("select timeout!\n");
639                                 return -1;
640                         } else if (FD_ISSET(0, &fds)) {
641                                 printf("user interrupted!\n");
642                                 break;
643                         }
644                         drmHandleEvent(drm.fd, &evctx);
645                 }
647                 /* release last buffer to render on again: */
648                 gbm_surface_release_buffer(gbm.surface, bo);
649                 bo = next_bo;
650         }
652         return ret;