6b1dd8b8c0da57e040ad74a71ed6fded180d67e2
[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  * Copyright (c) 2013 Anand Balagopalakrishnan <anandb@ti.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sub license,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial portions
15  * of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  */
26 /* Based on a egl cube test app originally written by Arvin Schnell */
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <string.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <errno.h>
36 #include <xf86drm.h>
37 #include <xf86drmMode.h>
38 #include <gbm.h>
40 #include "esUtil.h"
42 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
44 #define MAX_DISPLAYS    (4)
45 uint8_t DISP_ID = 0;
46 uint8_t all_display = 0;
48 static struct {
49         EGLDisplay display;
50         EGLConfig config;
51         EGLContext context;
52         EGLSurface surface;
53         GLuint program;
54         GLint modelviewmatrix, modelviewprojectionmatrix, normalmatrix;
55         GLuint vbo;
56         GLuint positionsoffset, colorsoffset, normalsoffset;
57 } gl;
59 static struct {
60         struct gbm_device *dev;
61         struct gbm_surface *surface;
62 } gbm;
64 static struct {
65         int fd;
66         uint32_t ndisp;
67         uint32_t crtc_id[MAX_DISPLAYS];
68         uint32_t connector_id[MAX_DISPLAYS];
69         drmModeModeInfo *mode[MAX_DISPLAYS];
70         drmModeConnector *connectors[MAX_DISPLAYS];
71 } drm;
73 struct drm_fb {
74         struct gbm_bo *bo;
75         uint32_t fb_id;
76 };
78 static int init_drm(void)
79 {
80         static const char *modules[] = {
81                         "omapdrm", "i915", "radeon", "nouveau", "vmwgfx", "exynos"
82         };
83         drmModeRes *resources;
84         drmModeConnector *connector = NULL;
85         drmModeEncoder *encoder = NULL;
86         int i, j;
88         for (i = 0; i < ARRAY_SIZE(modules); i++) {
89                 printf("trying to load module %s...", modules[i]);
90                 drm.fd = drmOpen(modules[i], NULL);
91                 if (drm.fd < 0) {
92                         printf("failed.\n");
93                 } else {
94                         printf("success.\n");
95                         break;
96                 }
97         }
99         if (drm.fd < 0) {
100                 printf("could not open drm device\n");
101                 return -1;
102         }
104         resources = drmModeGetResources(drm.fd);
105         if (!resources) {
106                 printf("drmModeGetResources failed: %s\n", strerror(errno));
107                 return -1;
108         }
110         /* find a connected connector: */
111         for (i = 0; i < resources->count_connectors; i++) {
112                 connector = drmModeGetConnector(drm.fd, resources->connectors[i]);
113                 if (connector->connection == DRM_MODE_CONNECTED) {
114                         /* choose the last supported mode */
115                         drm.mode[drm.ndisp] = &connector->modes[connector->count_modes-1];
116                         drm.connector_id[drm.ndisp] = connector->connector_id;
118                         for (j=0; j<resources->count_encoders; j++) {
119                                 encoder = drmModeGetEncoder(drm.fd, resources->encoders[j]);
120                                 if (encoder->encoder_id == connector->encoder_id)
121                                         break;
123                                 drmModeFreeEncoder(encoder);
124                                 encoder = NULL;
125                         }
127                         if (!encoder) {
128                                 printf("no encoder!\n");
129                                 return -1;
130                         }
132                         drm.crtc_id[drm.ndisp] = encoder->crtc_id;
133                         drm.connectors[drm.ndisp] = connector;
135                         printf("### Display [%d]: CRTC = %d, Connector = %d\n", drm.ndisp, drm.crtc_id[drm.ndisp], drm.connector_id[drm.ndisp]);
136                         printf("\tMode chosen [%s] : Clock => %d, Vertical refresh => %d, Type => %d\n", drm.mode[drm.ndisp]->name, drm.mode[drm.ndisp]->clock, drm.mode[drm.ndisp]->vrefresh, drm.mode[drm.ndisp]->type);
137                         printf("\tHorizontal => %d, %d, %d, %d, %d\n", drm.mode[drm.ndisp]->hdisplay, drm.mode[drm.ndisp]->hsync_start, drm.mode[drm.ndisp]->hsync_end, drm.mode[drm.ndisp]->htotal, drm.mode[drm.ndisp]->hskew);
138                         printf("\tVertical => %d, %d, %d, %d, %d\n", drm.mode[drm.ndisp]->vdisplay, drm.mode[drm.ndisp]->vsync_start, drm.mode[drm.ndisp]->vsync_end, drm.mode[drm.ndisp]->vtotal, drm.mode[drm.ndisp]->vscan);
140                         drm.ndisp++;
141                 } else {
142                         drmModeFreeConnector(connector);
143                 }
144         }
146         if (drm.ndisp == 0) {
147                 /* we could be fancy and listen for hotplug events and wait for
148                  * a connector..
149                  */
150                 printf("no connected connector!\n");
151                 return -1;
152         }
154         return 0;
157 static int init_gbm(void)
159         gbm.dev = gbm_create_device(drm.fd);
161         gbm.surface = gbm_surface_create(gbm.dev,
162                         drm.mode[DISP_ID]->hdisplay, drm.mode[DISP_ID]->vdisplay,
163                         GBM_FORMAT_XRGB8888,
164                         GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
165         if (!gbm.surface) {
166                 printf("failed to create gbm surface\n");
167                 return -1;
168         }
170         return 0;
173 static int init_gl(void)
175         EGLint major, minor, n;
176         GLuint vertex_shader, fragment_shader;
177         GLint ret;
179         static const GLfloat vVertices[] = {
180                         // front
181                         -1.0f, -1.0f, +1.0f, // point blue
182                         +1.0f, -1.0f, +1.0f, // point magenta
183                         -1.0f, +1.0f, +1.0f, // point cyan
184                         +1.0f, +1.0f, +1.0f, // point white
185                         // back
186                         +1.0f, -1.0f, -1.0f, // point red
187                         -1.0f, -1.0f, -1.0f, // point black
188                         +1.0f, +1.0f, -1.0f, // point yellow
189                         -1.0f, +1.0f, -1.0f, // point green
190                         // right
191                         +1.0f, -1.0f, +1.0f, // point magenta
192                         +1.0f, -1.0f, -1.0f, // point red
193                         +1.0f, +1.0f, +1.0f, // point white
194                         +1.0f, +1.0f, -1.0f, // point yellow
195                         // left
196                         -1.0f, -1.0f, -1.0f, // point black
197                         -1.0f, -1.0f, +1.0f, // point blue
198                         -1.0f, +1.0f, -1.0f, // point green
199                         -1.0f, +1.0f, +1.0f, // point cyan
200                         // top
201                         -1.0f, +1.0f, +1.0f, // point cyan
202                         +1.0f, +1.0f, +1.0f, // point white
203                         -1.0f, +1.0f, -1.0f, // point green
204                         +1.0f, +1.0f, -1.0f, // point yellow
205                         // bottom
206                         -1.0f, -1.0f, -1.0f, // point black
207                         +1.0f, -1.0f, -1.0f, // point red
208                         -1.0f, -1.0f, +1.0f, // point blue
209                         +1.0f, -1.0f, +1.0f  // point magenta
210         };
212         static const GLfloat vColors[] = {
213                         // front
214                         0.0f,  0.0f,  1.0f, // blue
215                         1.0f,  0.0f,  1.0f, // magenta
216                         0.0f,  1.0f,  1.0f, // cyan
217                         1.0f,  1.0f,  1.0f, // white
218                         // back
219                         1.0f,  0.0f,  0.0f, // red
220                         0.0f,  0.0f,  0.0f, // black
221                         1.0f,  1.0f,  0.0f, // yellow
222                         0.0f,  1.0f,  0.0f, // green
223                         // right
224                         1.0f,  0.0f,  1.0f, // magenta
225                         1.0f,  0.0f,  0.0f, // red
226                         1.0f,  1.0f,  1.0f, // white
227                         1.0f,  1.0f,  0.0f, // yellow
228                         // left
229                         0.0f,  0.0f,  0.0f, // black
230                         0.0f,  0.0f,  1.0f, // blue
231                         0.0f,  1.0f,  0.0f, // green
232                         0.0f,  1.0f,  1.0f, // cyan
233                         // top
234                         0.0f,  1.0f,  1.0f, // cyan
235                         1.0f,  1.0f,  1.0f, // white
236                         0.0f,  1.0f,  0.0f, // green
237                         1.0f,  1.0f,  0.0f, // yellow
238                         // bottom
239                         0.0f,  0.0f,  0.0f, // black
240                         1.0f,  0.0f,  0.0f, // red
241                         0.0f,  0.0f,  1.0f, // blue
242                         1.0f,  0.0f,  1.0f  // magenta
243         };
245         static const GLfloat vNormals[] = {
246                         // front
247                         +0.0f, +0.0f, +1.0f, // forward
248                         +0.0f, +0.0f, +1.0f, // forward
249                         +0.0f, +0.0f, +1.0f, // forward
250                         +0.0f, +0.0f, +1.0f, // forward
251                         // back
252                         +0.0f, +0.0f, -1.0f, // backbard
253                         +0.0f, +0.0f, -1.0f, // backbard
254                         +0.0f, +0.0f, -1.0f, // backbard
255                         +0.0f, +0.0f, -1.0f, // backbard
256                         // right
257                         +1.0f, +0.0f, +0.0f, // right
258                         +1.0f, +0.0f, +0.0f, // right
259                         +1.0f, +0.0f, +0.0f, // right
260                         +1.0f, +0.0f, +0.0f, // right
261                         // left
262                         -1.0f, +0.0f, +0.0f, // left
263                         -1.0f, +0.0f, +0.0f, // left
264                         -1.0f, +0.0f, +0.0f, // left
265                         -1.0f, +0.0f, +0.0f, // left
266                         // top
267                         +0.0f, +1.0f, +0.0f, // up
268                         +0.0f, +1.0f, +0.0f, // up
269                         +0.0f, +1.0f, +0.0f, // up
270                         +0.0f, +1.0f, +0.0f, // up
271                         // bottom
272                         +0.0f, -1.0f, +0.0f, // down
273                         +0.0f, -1.0f, +0.0f, // down
274                         +0.0f, -1.0f, +0.0f, // down
275                         +0.0f, -1.0f, +0.0f  // down
276         };
278         static const EGLint context_attribs[] = {
279                 EGL_CONTEXT_CLIENT_VERSION, 2,
280                 EGL_NONE
281         };
283         static const EGLint config_attribs[] = {
284                 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
285                 EGL_RED_SIZE, 1,
286                 EGL_GREEN_SIZE, 1,
287                 EGL_BLUE_SIZE, 1,
288                 EGL_ALPHA_SIZE, 0,
289                 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
290                 EGL_NONE
291         };
293         static const char *vertex_shader_source =
294                         "uniform mat4 modelviewMatrix;      \n"
295                         "uniform mat4 modelviewprojectionMatrix;\n"
296                         "uniform mat3 normalMatrix;         \n"
297                         "                                   \n"
298                         "attribute vec4 in_position;        \n"
299                         "attribute vec3 in_normal;          \n"
300                         "attribute vec4 in_color;           \n"
301                         "\n"
302                         "vec4 lightSource = vec4(2.0, 2.0, 20.0, 0.0);\n"
303                         "                                   \n"
304                         "varying vec4 vVaryingColor;        \n"
305                         "                                   \n"
306                         "void main()                        \n"
307                         "{                                  \n"
308                         "    gl_Position = modelviewprojectionMatrix * in_position;\n"
309                         "    vec3 vEyeNormal = normalMatrix * in_normal;\n"
310                         "    vec4 vPosition4 = modelviewMatrix * in_position;\n"
311                         "    vec3 vPosition3 = vPosition4.xyz / vPosition4.w;\n"
312                         "    vec3 vLightDir = normalize(lightSource.xyz - vPosition3);\n"
313                         "    float diff = max(0.0, dot(vEyeNormal, vLightDir));\n"
314                         "    vVaryingColor = vec4(diff * in_color.rgb, 1.0);\n"
315                         "}                                  \n";
317         static const char *fragment_shader_source =
318                         "precision mediump float;           \n"
319                         "                                   \n"
320                         "varying vec4 vVaryingColor;        \n"
321                         "                                   \n"
322                         "void main()                        \n"
323                         "{                                  \n"
324                         "    gl_FragColor = vVaryingColor;  \n"
325                         "}                                  \n";
327         gl.display = eglGetDisplay(gbm.dev);
329         if (!eglInitialize(gl.display, &major, &minor)) {
330                 printf("failed to initialize\n");
331                 return -1;
332         }
334         printf("Using display %p with EGL version %d.%d\n",
335                         gl.display, major, minor);
337         printf("EGL Version \"%s\"\n", eglQueryString(gl.display, EGL_VERSION));
338         printf("EGL Vendor \"%s\"\n", eglQueryString(gl.display, EGL_VENDOR));
339         printf("EGL Extensions \"%s\"\n", eglQueryString(gl.display, EGL_EXTENSIONS));
341         if (!eglBindAPI(EGL_OPENGL_ES_API)) {
342                 printf("failed to bind api EGL_OPENGL_ES_API\n");
343                 return -1;
344         }
346         if (!eglChooseConfig(gl.display, config_attribs, &gl.config, 1, &n) || n != 1) {
347                 printf("failed to choose config: %d\n", n);
348                 return -1;
349         }
351         gl.context = eglCreateContext(gl.display, gl.config,
352                         EGL_NO_CONTEXT, context_attribs);
353         if (gl.context == NULL) {
354                 printf("failed to create context\n");
355                 return -1;
356         }
358         gl.surface = eglCreateWindowSurface(gl.display, gl.config, gbm.surface, NULL);
359         if (gl.surface == EGL_NO_SURFACE) {
360                 printf("failed to create egl surface\n");
361                 return -1;
362         }
364         /* connect the context to the surface */
365         eglMakeCurrent(gl.display, gl.surface, gl.surface, gl.context);
368         vertex_shader = glCreateShader(GL_VERTEX_SHADER);
370         glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
371         glCompileShader(vertex_shader);
373         glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &ret);
374         if (!ret) {
375                 char *log;
377                 printf("vertex shader compilation failed!:\n");
378                 glGetShaderiv(vertex_shader, GL_INFO_LOG_LENGTH, &ret);
379                 if (ret > 1) {
380                         log = malloc(ret);
381                         glGetShaderInfoLog(vertex_shader, ret, NULL, log);
382                         printf("%s", log);
383                 }
385                 return -1;
386         }
388         fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
390         glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
391         glCompileShader(fragment_shader);
393         glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &ret);
394         if (!ret) {
395                 char *log;
397                 printf("fragment shader compilation failed!:\n");
398                 glGetShaderiv(fragment_shader, GL_INFO_LOG_LENGTH, &ret);
400                 if (ret > 1) {
401                         log = malloc(ret);
402                         glGetShaderInfoLog(fragment_shader, ret, NULL, log);
403                         printf("%s", log);
404                 }
406                 return -1;
407         }
409         gl.program = glCreateProgram();
411         glAttachShader(gl.program, vertex_shader);
412         glAttachShader(gl.program, fragment_shader);
414         glBindAttribLocation(gl.program, 0, "in_position");
415         glBindAttribLocation(gl.program, 1, "in_normal");
416         glBindAttribLocation(gl.program, 2, "in_color");
418         glLinkProgram(gl.program);
420         glGetProgramiv(gl.program, GL_LINK_STATUS, &ret);
421         if (!ret) {
422                 char *log;
424                 printf("program linking failed!:\n");
425                 glGetProgramiv(gl.program, GL_INFO_LOG_LENGTH, &ret);
427                 if (ret > 1) {
428                         log = malloc(ret);
429                         glGetProgramInfoLog(gl.program, ret, NULL, log);
430                         printf("%s", log);
431                 }
433                 return -1;
434         }
436         glUseProgram(gl.program);
438         gl.modelviewmatrix = glGetUniformLocation(gl.program, "modelviewMatrix");
439         gl.modelviewprojectionmatrix = glGetUniformLocation(gl.program, "modelviewprojectionMatrix");
440         gl.normalmatrix = glGetUniformLocation(gl.program, "normalMatrix");
442         glViewport(0, 0, drm.mode[DISP_ID]->hdisplay, drm.mode[DISP_ID]->vdisplay);
443         glEnable(GL_CULL_FACE);
445         gl.positionsoffset = 0;
446         gl.colorsoffset = sizeof(vVertices);
447         gl.normalsoffset = sizeof(vVertices) + sizeof(vColors);
448         glGenBuffers(1, &gl.vbo);
449         glBindBuffer(GL_ARRAY_BUFFER, gl.vbo);
450         glBufferData(GL_ARRAY_BUFFER, sizeof(vVertices) + sizeof(vColors) + sizeof(vNormals), 0, GL_STATIC_DRAW);
451         glBufferSubData(GL_ARRAY_BUFFER, gl.positionsoffset, sizeof(vVertices), &vVertices[0]);
452         glBufferSubData(GL_ARRAY_BUFFER, gl.colorsoffset, sizeof(vColors), &vColors[0]);
453         glBufferSubData(GL_ARRAY_BUFFER, gl.normalsoffset, sizeof(vNormals), &vNormals[0]);
454         glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)gl.positionsoffset);
455         glEnableVertexAttribArray(0);
456         glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)gl.normalsoffset);
457         glEnableVertexAttribArray(1);
458         glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)gl.colorsoffset);
459         glEnableVertexAttribArray(2);
461         return 0;
464 static void draw(uint32_t i)
466         ESMatrix modelview;
468         /* clear the color buffer */
469         glClearColor(0.5, 0.5, 0.5, 1.0);
470         glClear(GL_COLOR_BUFFER_BIT);
472         esMatrixLoadIdentity(&modelview);
473         esTranslate(&modelview, 0.0f, 0.0f, -8.0f);
474         esRotate(&modelview, 45.0f + (0.25f * i), 1.0f, 0.0f, 0.0f);
475         esRotate(&modelview, 45.0f - (0.5f * i), 0.0f, 1.0f, 0.0f);
476         esRotate(&modelview, 10.0f + (0.15f * i), 0.0f, 0.0f, 1.0f);
478         GLfloat aspect = (GLfloat)(drm.mode[DISP_ID]->vdisplay) / (GLfloat)(drm.mode[DISP_ID]->hdisplay);
480         ESMatrix projection;
481         esMatrixLoadIdentity(&projection);
482         esFrustum(&projection, -2.8f, +2.8f, -2.8f * aspect, +2.8f * aspect, 6.0f, 10.0f);
484         ESMatrix modelviewprojection;
485         esMatrixLoadIdentity(&modelviewprojection);
486         esMatrixMultiply(&modelviewprojection, &modelview, &projection);
488         float normal[9];
489         normal[0] = modelview.m[0][0];
490         normal[1] = modelview.m[0][1];
491         normal[2] = modelview.m[0][2];
492         normal[3] = modelview.m[1][0];
493         normal[4] = modelview.m[1][1];
494         normal[5] = modelview.m[1][2];
495         normal[6] = modelview.m[2][0];
496         normal[7] = modelview.m[2][1];
497         normal[8] = modelview.m[2][2];
499         glUniformMatrix4fv(gl.modelviewmatrix, 1, GL_FALSE, &modelview.m[0][0]);
500         glUniformMatrix4fv(gl.modelviewprojectionmatrix, 1, GL_FALSE, &modelviewprojection.m[0][0]);
501         glUniformMatrix3fv(gl.normalmatrix, 1, GL_FALSE, normal);
503         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
504         glDrawArrays(GL_TRIANGLE_STRIP, 4, 4);
505         glDrawArrays(GL_TRIANGLE_STRIP, 8, 4);
506         glDrawArrays(GL_TRIANGLE_STRIP, 12, 4);
507         glDrawArrays(GL_TRIANGLE_STRIP, 16, 4);
508         glDrawArrays(GL_TRIANGLE_STRIP, 20, 4);
511 static void
512 drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
514         struct drm_fb *fb = data;
515         struct gbm_device *gbm = gbm_bo_get_device(bo);
517         if (fb->fb_id)
518                 drmModeRmFB(drm.fd, fb->fb_id);
520         free(fb);
523 static struct drm_fb * drm_fb_get_from_bo(struct gbm_bo *bo)
525         struct drm_fb *fb = gbm_bo_get_user_data(bo);
526         uint32_t width, height, stride, handle;
527         int ret;
529         if (fb)
530                 return fb;
532         fb = calloc(1, sizeof *fb);
533         fb->bo = bo;
535         width = gbm_bo_get_width(bo);
536         height = gbm_bo_get_height(bo);
537         stride = gbm_bo_get_stride(bo);
538         handle = gbm_bo_get_handle(bo).u32;
540         ret = drmModeAddFB(drm.fd, width, height, 24, 32, stride, handle, &fb->fb_id);
541         if (ret) {
542                 printf("failed to create fb: %s\n", strerror(errno));
543                 free(fb);
544                 return NULL;
545         }
547         gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
549         return fb;
552 static void page_flip_handler(int fd, unsigned int frame,
553                   unsigned int sec, unsigned int usec, void *data)
555         int *waiting_for_flip = data;
556         *waiting_for_flip = 0;
559 int main(int argc, char *argv[])
561         fd_set fds;
562         drmEventContext evctx = {
563                         .version = DRM_EVENT_CONTEXT_VERSION,
564                         .page_flip_handler = page_flip_handler,
565         };
566         struct gbm_bo *bo;
567         struct drm_fb *fb;
568         uint32_t i = 0;
569         int ret;
571         if (argc > 1) {
572                 if (strcmp(argv[1], "--all") == 0) 
573                         all_display = 1;
574                 else if (strcmp(argv[1], "-h") == 0)
575                         printf("Usage: %s [ --all | <0|1|..> ] \n", argv[0]);
576                 else
577                         DISP_ID = atoi(argv[1]);
578         }
580         if (all_display) 
581                 printf("### Enabling all displays\n");
583         ret = init_drm();
584         if (ret) {
585                 printf("failed to initialize DRM\n");
586                 return ret;
587         }
589         FD_ZERO(&fds);
590         FD_SET(0, &fds);
591         FD_SET(drm.fd, &fds);
593         ret = init_gbm();
594         if (ret) {
595                 printf("failed to initialize GBM\n");
596                 return ret;
597         }
599         ret = init_gl();
600         if (ret) {
601                 printf("failed to initialize EGL\n");
602                 return ret;
603         }
605         /* clear the color buffer */
606         glClearColor(0.5, 0.5, 0.5, 1.0);
607         glClear(GL_COLOR_BUFFER_BIT);
608         eglSwapBuffers(gl.display, gl.surface);
609         bo = gbm_surface_lock_front_buffer(gbm.surface);
610         fb = drm_fb_get_from_bo(bo);
612         /* set mode: */
613         if (all_display) {
614                 for (i=0; i<drm.ndisp; i++) {
615                         ret = drmModeSetCrtc(drm.fd, drm.crtc_id[i], fb->fb_id, 0, 0,
616                                         &drm.connector_id[i], 1, drm.mode[i]);
617                         if (ret) {
618                                 printf("display %d failed to set mode: %s\n", i, strerror(errno));
619                                 return ret;
620                         }
621                 }
622         } else {
623                 ret = drmModeSetCrtc(drm.fd, drm.crtc_id[DISP_ID], fb->fb_id,
624                                 0, 0, &drm.connector_id[DISP_ID], 1, drm.mode[DISP_ID]);
625                 if (ret) {
626                         printf("display %d failed to set mode: %s\n", DISP_ID, strerror(errno));
627                         return ret;
628                 }
629         }
631         while (1) {
632                 struct gbm_bo *next_bo;
633                 int waiting_for_flip = 1;
635                 draw(i++);
637                 eglSwapBuffers(gl.display, gl.surface);
638                 next_bo = gbm_surface_lock_front_buffer(gbm.surface);
639                 fb = drm_fb_get_from_bo(next_bo);
641                 /*
642                  * Here you could also update drm plane layers if you want
643                  * hw composition
644                  */
646                 ret = drmModePageFlip(drm.fd, drm.crtc_id[DISP_ID], fb->fb_id,
647                                 DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);
648                 if (ret) {
649                         printf("failed to queue page flip: %s\n", strerror(errno));
650                         return -1;
651                 }
653                 while (waiting_for_flip) {
654                         ret = select(drm.fd + 1, &fds, NULL, NULL, NULL);
655                         if (ret < 0) {
656                                 printf("select err: %s\n", strerror(errno));
657                                 return ret;
658                         } else if (ret == 0) {
659                                 printf("select timeout!\n");
660                                 return -1;
661                         } else if (FD_ISSET(0, &fds)) {
662                                 printf("user interrupted!\n");
663                                 break;
664                         }
665                         drmHandleEvent(drm.fd, &evctx);
666                 }
668                 /* release last buffer to render on again: */
669                 gbm_surface_release_buffer(gbm.surface, bo);
670                 bo = next_bo;
671         }
673         return ret;