kmscube.c: init_drm(): handle usecase where display is disabled
[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 <unistd.h>
35 #include <errno.h>
36 #include <signal.h>
38 #include <xf86drm.h>
39 #include <xf86drmMode.h>
40 #include <gbm.h>
42 #include "esUtil.h"
44 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
46 #define MAX_DISPLAYS    (4)
47 uint8_t DISP_ID = 0;
48 uint8_t all_display = 0;
49 int8_t connector_id = -1;
51 static struct {
52         EGLDisplay display;
53         EGLConfig config;
54         EGLContext context;
55         EGLSurface surface;
56         GLuint program;
57         GLint modelviewmatrix, modelviewprojectionmatrix, normalmatrix;
58         GLuint vbo;
59         GLuint positionsoffset, colorsoffset, normalsoffset;
60         GLuint vertex_shader, fragment_shader;
61 } gl;
63 static struct {
64         struct gbm_device *dev;
65         struct gbm_surface *surface;
66 } gbm;
68 static struct {
69         int fd;
70         uint32_t ndisp;
71         uint32_t crtc_id[MAX_DISPLAYS];
72         uint32_t connector_id[MAX_DISPLAYS];
73         uint32_t resource_id;
74         uint32_t encoder[MAX_DISPLAYS];
75         drmModeModeInfo *mode[MAX_DISPLAYS];
76         drmModeConnector *connectors[MAX_DISPLAYS];
77 } drm;
79 struct drm_fb {
80         struct gbm_bo *bo;
81         uint32_t fb_id;
82 };
84 static int init_drm(void)
85 {
86         static const char *modules[] = {
87                         "omapdrm", "tilcdc", "i915", "radeon", "nouveau", "vmwgfx", "exynos"
88         };
89         drmModeRes *resources;
90         drmModeConnector *connector = NULL;
91         drmModeEncoder *encoder = NULL;
92         drmModeCrtc *crtc = NULL;
94         int i, j, k;
95         uint32_t maxRes, curRes;
97         for (i = 0; i < ARRAY_SIZE(modules); i++) {
98                 printf("trying to load module %s...", modules[i]);
99                 drm.fd = drmOpen(modules[i], NULL);
100                 if (drm.fd < 0) {
101                         printf("failed.\n");
102                 } else {
103                         printf("success.\n");
104                         break;
105                 }
106         }
108         if (drm.fd < 0) {
109                 printf("could not open drm device\n");
110                 return -1;
111         }
113         resources = drmModeGetResources(drm.fd);
114         if (!resources) {
115                 printf("drmModeGetResources failed: %s\n", strerror(errno));
116                 return -1;
117         }
118         drm.resource_id = (uint32_t) resources;
120         /* find a connected connector: */
121         for (i = 0; i < resources->count_connectors; i++) {
122                 connector = drmModeGetConnector(drm.fd, resources->connectors[i]);
123                 if (connector->connection == DRM_MODE_CONNECTED) {
125                         /* find the matched encoders */
126                         for (j=0; j<connector->count_encoders; j++) {
127                                 encoder = drmModeGetEncoder(drm.fd, connector->encoders[j]);
129                                 /* Take the fisrt one, if none is assigned */
130                                 if (!connector->encoder_id)
131                                 {
132                                         connector->encoder_id = encoder->encoder_id;
133                                 }
135                                 if (encoder->encoder_id == connector->encoder_id)
136                                 {
137                                         /* find the first valid CRTC if not assigned */
138                                         if (!encoder->crtc_id)
139                                         {
140                                                 for (k = 0; k < resources->count_crtcs; ++k) {
141                                                         /* check whether this CRTC works with the encoder */
142                                                         if (!(encoder->possible_crtcs & (1 << k)))
143                                                                 continue;
145                                                         encoder->crtc_id = resources->crtcs[k];
146                                                         break;
147                                                 }
149                                                 if (!encoder->crtc_id)
150                                                 {
151                                                         printf("Encoder(%d): no CRTC find!\n", encoder->encoder_id);
152                                                         drmModeFreeEncoder(encoder);
153                                                         encoder = NULL;
154                                                         continue;
155                                                 }
156                                         }
158                                         break;
159                                 }
161                                 drmModeFreeEncoder(encoder);
162                                 encoder = NULL;
163                         }
165                         if (!encoder) {
166                                 printf("Connector (%d): no encoder!\n", connector->connector_id);
167                                 drmModeFreeConnector(connector);
168                                 continue;
169                         }
171                         /* choose the current or first supported mode */
172                         crtc = drmModeGetCrtc(drm.fd, encoder->crtc_id);
173                         for (j = 0; j < connector->count_modes; j++)
174                         {
175                                 if (crtc->mode_valid)
176                                 {
177                                         if ((connector->modes[j].hdisplay == crtc->width) &&
178                                         (connector->modes[j].vdisplay == crtc->height))
179                                         {
180                                                 drm.mode[drm.ndisp] = &connector->modes[j];
181                                                 break;
182                                         }
183                                 }
184                                 else
185                                 {
186                                         if ((connector->modes[j].hdisplay == crtc->x) &&
187                                            (connector->modes[j].vdisplay == crtc->y))
188                                         {
189                                                 drm.mode[drm.ndisp] = &connector->modes[j];
190                                                 break;
191                                         }
192                                 }
193                         }
195                         if(j >= connector->count_modes)
196                                 drm.mode[drm.ndisp] = &connector->modes[0];
198                         drm.connector_id[drm.ndisp] = connector->connector_id;
200                         drm.encoder[drm.ndisp]  = (uint32_t) encoder;
201                         drm.crtc_id[drm.ndisp] = encoder->crtc_id;
202                         drm.connectors[drm.ndisp] = connector;
204                         printf("### Display [%d]: CRTC = %d, Connector = %d\n", drm.ndisp, drm.crtc_id[drm.ndisp], drm.connector_id[drm.ndisp]);
205                         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);
206                         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);
207                         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);
209                         /* If a connector_id is specified, use the corresponding display */
210                         if ((connector_id != -1) && (connector_id == drm.connector_id[drm.ndisp]))
211                                 DISP_ID = drm.ndisp;
213                         /* If all displays are enabled, choose the connector with maximum
214                         * resolution as the primary display */
215                         if (all_display) {
216                                 maxRes = drm.mode[DISP_ID]->vdisplay * drm.mode[DISP_ID]->hdisplay;
217                                 curRes = drm.mode[drm.ndisp]->vdisplay * drm.mode[drm.ndisp]->hdisplay;
219                                 if (curRes > maxRes)
220                                         DISP_ID = drm.ndisp;
221                         }
223                         drm.ndisp++;
224                 } else {
225                         drmModeFreeConnector(connector);
226                 }
227         }
229         if (drm.ndisp == 0) {
230                 /* we could be fancy and listen for hotplug events and wait for
231                  * a connector..
232                  */
233                 printf("no connected connector!\n");
234                 return -1;
235         }
237         return 0;
240 static int init_gbm(void)
242         gbm.dev = gbm_create_device(drm.fd);
244         gbm.surface = gbm_surface_create(gbm.dev,
245                         drm.mode[DISP_ID]->hdisplay, drm.mode[DISP_ID]->vdisplay,
246                         GBM_FORMAT_XRGB8888,
247                         GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
248         if (!gbm.surface) {
249                 printf("failed to create gbm surface\n");
250                 return -1;
251         }
253         return 0;
256 static int init_gl(void)
258         EGLint major, minor, n;
259         GLint ret;
261         static const GLfloat vVertices[] = {
262                         // front
263                         -1.0f, -1.0f, +1.0f, // point blue
264                         +1.0f, -1.0f, +1.0f, // point magenta
265                         -1.0f, +1.0f, +1.0f, // point cyan
266                         +1.0f, +1.0f, +1.0f, // point white
267                         // back
268                         +1.0f, -1.0f, -1.0f, // point red
269                         -1.0f, -1.0f, -1.0f, // point black
270                         +1.0f, +1.0f, -1.0f, // point yellow
271                         -1.0f, +1.0f, -1.0f, // point green
272                         // right
273                         +1.0f, -1.0f, +1.0f, // point magenta
274                         +1.0f, -1.0f, -1.0f, // point red
275                         +1.0f, +1.0f, +1.0f, // point white
276                         +1.0f, +1.0f, -1.0f, // point yellow
277                         // left
278                         -1.0f, -1.0f, -1.0f, // point black
279                         -1.0f, -1.0f, +1.0f, // point blue
280                         -1.0f, +1.0f, -1.0f, // point green
281                         -1.0f, +1.0f, +1.0f, // point cyan
282                         // top
283                         -1.0f, +1.0f, +1.0f, // point cyan
284                         +1.0f, +1.0f, +1.0f, // point white
285                         -1.0f, +1.0f, -1.0f, // point green
286                         +1.0f, +1.0f, -1.0f, // point yellow
287                         // bottom
288                         -1.0f, -1.0f, -1.0f, // point black
289                         +1.0f, -1.0f, -1.0f, // point red
290                         -1.0f, -1.0f, +1.0f, // point blue
291                         +1.0f, -1.0f, +1.0f  // point magenta
292         };
294         static const GLfloat vColors[] = {
295                         // front
296                         0.0f,  0.0f,  1.0f, // blue
297                         1.0f,  0.0f,  1.0f, // magenta
298                         0.0f,  1.0f,  1.0f, // cyan
299                         1.0f,  1.0f,  1.0f, // white
300                         // back
301                         1.0f,  0.0f,  0.0f, // red
302                         0.0f,  0.0f,  0.0f, // black
303                         1.0f,  1.0f,  0.0f, // yellow
304                         0.0f,  1.0f,  0.0f, // green
305                         // right
306                         1.0f,  0.0f,  1.0f, // magenta
307                         1.0f,  0.0f,  0.0f, // red
308                         1.0f,  1.0f,  1.0f, // white
309                         1.0f,  1.0f,  0.0f, // yellow
310                         // left
311                         0.0f,  0.0f,  0.0f, // black
312                         0.0f,  0.0f,  1.0f, // blue
313                         0.0f,  1.0f,  0.0f, // green
314                         0.0f,  1.0f,  1.0f, // cyan
315                         // top
316                         0.0f,  1.0f,  1.0f, // cyan
317                         1.0f,  1.0f,  1.0f, // white
318                         0.0f,  1.0f,  0.0f, // green
319                         1.0f,  1.0f,  0.0f, // yellow
320                         // bottom
321                         0.0f,  0.0f,  0.0f, // black
322                         1.0f,  0.0f,  0.0f, // red
323                         0.0f,  0.0f,  1.0f, // blue
324                         1.0f,  0.0f,  1.0f  // magenta
325         };
327         static const GLfloat vNormals[] = {
328                         // front
329                         +0.0f, +0.0f, +1.0f, // forward
330                         +0.0f, +0.0f, +1.0f, // forward
331                         +0.0f, +0.0f, +1.0f, // forward
332                         +0.0f, +0.0f, +1.0f, // forward
333                         // back
334                         +0.0f, +0.0f, -1.0f, // backbard
335                         +0.0f, +0.0f, -1.0f, // backbard
336                         +0.0f, +0.0f, -1.0f, // backbard
337                         +0.0f, +0.0f, -1.0f, // backbard
338                         // right
339                         +1.0f, +0.0f, +0.0f, // right
340                         +1.0f, +0.0f, +0.0f, // right
341                         +1.0f, +0.0f, +0.0f, // right
342                         +1.0f, +0.0f, +0.0f, // right
343                         // left
344                         -1.0f, +0.0f, +0.0f, // left
345                         -1.0f, +0.0f, +0.0f, // left
346                         -1.0f, +0.0f, +0.0f, // left
347                         -1.0f, +0.0f, +0.0f, // left
348                         // top
349                         +0.0f, +1.0f, +0.0f, // up
350                         +0.0f, +1.0f, +0.0f, // up
351                         +0.0f, +1.0f, +0.0f, // up
352                         +0.0f, +1.0f, +0.0f, // up
353                         // bottom
354                         +0.0f, -1.0f, +0.0f, // down
355                         +0.0f, -1.0f, +0.0f, // down
356                         +0.0f, -1.0f, +0.0f, // down
357                         +0.0f, -1.0f, +0.0f  // down
358         };
360         static const EGLint context_attribs[] = {
361                 EGL_CONTEXT_CLIENT_VERSION, 2,
362                 EGL_NONE
363         };
365         static const EGLint config_attribs[] = {
366                 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
367                 EGL_RED_SIZE, 1,
368                 EGL_GREEN_SIZE, 1,
369                 EGL_BLUE_SIZE, 1,
370                 EGL_ALPHA_SIZE, 0,
371                 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
372                 EGL_NONE
373         };
375         static const char *vertex_shader_source =
376                         "uniform mat4 modelviewMatrix;      \n"
377                         "uniform mat4 modelviewprojectionMatrix;\n"
378                         "uniform mat3 normalMatrix;         \n"
379                         "                                   \n"
380                         "attribute vec4 in_position;        \n"
381                         "attribute vec3 in_normal;          \n"
382                         "attribute vec4 in_color;           \n"
383                         "\n"
384                         "vec4 lightSource = vec4(2.0, 2.0, 20.0, 0.0);\n"
385                         "                                   \n"
386                         "varying vec4 vVaryingColor;        \n"
387                         "                                   \n"
388                         "void main()                        \n"
389                         "{                                  \n"
390                         "    gl_Position = modelviewprojectionMatrix * in_position;\n"
391                         "    vec3 vEyeNormal = normalMatrix * in_normal;\n"
392                         "    vec4 vPosition4 = modelviewMatrix * in_position;\n"
393                         "    vec3 vPosition3 = vPosition4.xyz / vPosition4.w;\n"
394                         "    vec3 vLightDir = normalize(lightSource.xyz - vPosition3);\n"
395                         "    float diff = max(0.0, dot(vEyeNormal, vLightDir));\n"
396                         "    vVaryingColor = vec4(diff * in_color.rgb, 1.0);\n"
397                         "}                                  \n";
399         static const char *fragment_shader_source =
400                         "precision mediump float;           \n"
401                         "                                   \n"
402                         "varying vec4 vVaryingColor;        \n"
403                         "                                   \n"
404                         "void main()                        \n"
405                         "{                                  \n"
406                         "    gl_FragColor = vVaryingColor;  \n"
407                         "}                                  \n";
409         gl.display = eglGetDisplay(gbm.dev);
411         if (!eglInitialize(gl.display, &major, &minor)) {
412                 printf("failed to initialize\n");
413                 return -1;
414         }
416         printf("Using display %p with EGL version %d.%d\n",
417                         gl.display, major, minor);
419         printf("EGL Version \"%s\"\n", eglQueryString(gl.display, EGL_VERSION));
420         printf("EGL Vendor \"%s\"\n", eglQueryString(gl.display, EGL_VENDOR));
421         printf("EGL Extensions \"%s\"\n", eglQueryString(gl.display, EGL_EXTENSIONS));
423         if (!eglBindAPI(EGL_OPENGL_ES_API)) {
424                 printf("failed to bind api EGL_OPENGL_ES_API\n");
425                 return -1;
426         }
428         if (!eglChooseConfig(gl.display, config_attribs, &gl.config, 1, &n) || n != 1) {
429                 printf("failed to choose config: %d\n", n);
430                 return -1;
431         }
433         gl.context = eglCreateContext(gl.display, gl.config,
434                         EGL_NO_CONTEXT, context_attribs);
435         if (gl.context == NULL) {
436                 printf("failed to create context\n");
437                 return -1;
438         }
440         gl.surface = eglCreateWindowSurface(gl.display, gl.config, gbm.surface, NULL);
441         if (gl.surface == EGL_NO_SURFACE) {
442                 printf("failed to create egl surface\n");
443                 return -1;
444         }
446         /* connect the context to the surface */
447         eglMakeCurrent(gl.display, gl.surface, gl.surface, gl.context);
450         gl.vertex_shader = glCreateShader(GL_VERTEX_SHADER);
452         glShaderSource(gl.vertex_shader, 1, &vertex_shader_source, NULL);
453         glCompileShader(gl.vertex_shader);
455         glGetShaderiv(gl.vertex_shader, GL_COMPILE_STATUS, &ret);
456         if (!ret) {
457                 char *log;
459                 printf("vertex shader compilation failed!:\n");
460                 glGetShaderiv(gl.vertex_shader, GL_INFO_LOG_LENGTH, &ret);
461                 if (ret > 1) {
462                         log = malloc(ret);
463                         glGetShaderInfoLog(gl.vertex_shader, ret, NULL, log);
464                         printf("%s", log);
465                 }
467                 return -1;
468         }
470         gl.fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
472         glShaderSource(gl.fragment_shader, 1, &fragment_shader_source, NULL);
473         glCompileShader(gl.fragment_shader);
475         glGetShaderiv(gl.fragment_shader, GL_COMPILE_STATUS, &ret);
476         if (!ret) {
477                 char *log;
479                 printf("fragment shader compilation failed!:\n");
480                 glGetShaderiv(gl.fragment_shader, GL_INFO_LOG_LENGTH, &ret);
482                 if (ret > 1) {
483                         log = malloc(ret);
484                         glGetShaderInfoLog(gl.fragment_shader, ret, NULL, log);
485                         printf("%s", log);
486                 }
488                 return -1;
489         }
491         gl.program = glCreateProgram();
493         glAttachShader(gl.program, gl.vertex_shader);
494         glAttachShader(gl.program, gl.fragment_shader);
496         glBindAttribLocation(gl.program, 0, "in_position");
497         glBindAttribLocation(gl.program, 1, "in_normal");
498         glBindAttribLocation(gl.program, 2, "in_color");
500         glLinkProgram(gl.program);
502         glGetProgramiv(gl.program, GL_LINK_STATUS, &ret);
503         if (!ret) {
504                 char *log;
506                 printf("program linking failed!:\n");
507                 glGetProgramiv(gl.program, GL_INFO_LOG_LENGTH, &ret);
509                 if (ret > 1) {
510                         log = malloc(ret);
511                         glGetProgramInfoLog(gl.program, ret, NULL, log);
512                         printf("%s", log);
513                 }
515                 return -1;
516         }
518         glUseProgram(gl.program);
520         gl.modelviewmatrix = glGetUniformLocation(gl.program, "modelviewMatrix");
521         gl.modelviewprojectionmatrix = glGetUniformLocation(gl.program, "modelviewprojectionMatrix");
522         gl.normalmatrix = glGetUniformLocation(gl.program, "normalMatrix");
524         glViewport(0, 0, drm.mode[DISP_ID]->hdisplay, drm.mode[DISP_ID]->vdisplay);
525         glEnable(GL_CULL_FACE);
527         gl.positionsoffset = 0;
528         gl.colorsoffset = sizeof(vVertices);
529         gl.normalsoffset = sizeof(vVertices) + sizeof(vColors);
530         glGenBuffers(1, &gl.vbo);
531         glBindBuffer(GL_ARRAY_BUFFER, gl.vbo);
532         glBufferData(GL_ARRAY_BUFFER, sizeof(vVertices) + sizeof(vColors) + sizeof(vNormals), 0, GL_STATIC_DRAW);
533         glBufferSubData(GL_ARRAY_BUFFER, gl.positionsoffset, sizeof(vVertices), &vVertices[0]);
534         glBufferSubData(GL_ARRAY_BUFFER, gl.colorsoffset, sizeof(vColors), &vColors[0]);
535         glBufferSubData(GL_ARRAY_BUFFER, gl.normalsoffset, sizeof(vNormals), &vNormals[0]);
536         glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)gl.positionsoffset);
537         glEnableVertexAttribArray(0);
538         glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)gl.normalsoffset);
539         glEnableVertexAttribArray(1);
540         glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)gl.colorsoffset);
541         glEnableVertexAttribArray(2);
543         return 0;
546 static void exit_gbm(void)
548         gbm_surface_destroy(gbm.surface);
549         gbm_device_destroy(gbm.dev);
550         return;
553 static void exit_gl(void)
555         glDeleteProgram(gl.program);
556         glDeleteBuffers(1, &gl.vbo);
557         glDeleteShader(gl.fragment_shader);
558         glDeleteShader(gl.vertex_shader);
559         eglDestroySurface(gl.display, gl.surface);
560         eglDestroyContext(gl.display, gl.context);
561         eglTerminate(gl.display);
562         return;
565 static void exit_drm(void)
568         drmModeRes *resources;
569         int i;
571         resources = (drmModeRes *)drm.resource_id;
572         for (i = 0; i < resources->count_connectors; i++) {
573                 drmModeFreeEncoder(drm.encoder[i]);
574                 drmModeFreeConnector(drm.connectors[i]);
575         }
576         drmModeFreeResources(drm.resource_id);
577         drmClose(drm.fd);
578         return;
581 void cleanup_kmscube(void)
583         exit_gl();
584         exit_gbm();
585         exit_drm();
586         printf("Cleanup of GL, GBM and DRM completed\n");
587         return;
590 static void draw(uint32_t i)
592         ESMatrix modelview;
594         /* clear the color buffer */
595         glClearColor(0.5, 0.5, 0.5, 1.0);
596         glClear(GL_COLOR_BUFFER_BIT);
598         esMatrixLoadIdentity(&modelview);
599         esTranslate(&modelview, 0.0f, 0.0f, -8.0f);
600         esRotate(&modelview, 45.0f + (0.25f * i), 1.0f, 0.0f, 0.0f);
601         esRotate(&modelview, 45.0f - (0.5f * i), 0.0f, 1.0f, 0.0f);
602         esRotate(&modelview, 10.0f + (0.15f * i), 0.0f, 0.0f, 1.0f);
604         GLfloat aspect = (GLfloat)(drm.mode[DISP_ID]->vdisplay) / (GLfloat)(drm.mode[DISP_ID]->hdisplay);
606         ESMatrix projection;
607         esMatrixLoadIdentity(&projection);
608         esFrustum(&projection, -2.8f, +2.8f, -2.8f * aspect, +2.8f * aspect, 6.0f, 10.0f);
610         ESMatrix modelviewprojection;
611         esMatrixLoadIdentity(&modelviewprojection);
612         esMatrixMultiply(&modelviewprojection, &modelview, &projection);
614         float normal[9];
615         normal[0] = modelview.m[0][0];
616         normal[1] = modelview.m[0][1];
617         normal[2] = modelview.m[0][2];
618         normal[3] = modelview.m[1][0];
619         normal[4] = modelview.m[1][1];
620         normal[5] = modelview.m[1][2];
621         normal[6] = modelview.m[2][0];
622         normal[7] = modelview.m[2][1];
623         normal[8] = modelview.m[2][2];
625         glUniformMatrix4fv(gl.modelviewmatrix, 1, GL_FALSE, &modelview.m[0][0]);
626         glUniformMatrix4fv(gl.modelviewprojectionmatrix, 1, GL_FALSE, &modelviewprojection.m[0][0]);
627         glUniformMatrix3fv(gl.normalmatrix, 1, GL_FALSE, normal);
629         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
630         glDrawArrays(GL_TRIANGLE_STRIP, 4, 4);
631         glDrawArrays(GL_TRIANGLE_STRIP, 8, 4);
632         glDrawArrays(GL_TRIANGLE_STRIP, 12, 4);
633         glDrawArrays(GL_TRIANGLE_STRIP, 16, 4);
634         glDrawArrays(GL_TRIANGLE_STRIP, 20, 4);
637 static void
638 drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
640         struct drm_fb *fb = data;
641         struct gbm_device *gbm = gbm_bo_get_device(bo);
643         if (fb->fb_id)
644                 drmModeRmFB(drm.fd, fb->fb_id);
646         free(fb);
649 static struct drm_fb * drm_fb_get_from_bo(struct gbm_bo *bo)
651         struct drm_fb *fb = gbm_bo_get_user_data(bo);
652         uint32_t width, height, stride, handle;
653         int ret;
655         if (fb)
656                 return fb;
658         fb = calloc(1, sizeof *fb);
659         fb->bo = bo;
661         width = gbm_bo_get_width(bo);
662         height = gbm_bo_get_height(bo);
663         stride = gbm_bo_get_stride(bo);
664         handle = gbm_bo_get_handle(bo).u32;
666         ret = drmModeAddFB(drm.fd, width, height, 24, 32, stride, handle, &fb->fb_id);
667         if (ret) {
668                 printf("failed to create fb: %s\n", strerror(errno));
669                 free(fb);
670                 return NULL;
671         }
673         gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
675         return fb;
678 static void page_flip_handler(int fd, unsigned int frame,
679                   unsigned int sec, unsigned int usec, void *data)
681         int *waiting_for_flip = data;
682         *waiting_for_flip = 0;
685 void print_usage()
687         printf("Usage : kmscube <options>\n");
688         printf("\t-h : Help\n");
689         printf("\t-a : Enable all displays\n");
690         printf("\t-c <id> : Display using connector_id [if not specified, use the first connected connector]\n");
691         printf("\t-n <number> (optional): Number of frames to render\n");
694 int kms_signalhandler(int signum)
696         switch(signum) {
697         case SIGINT:
698         case SIGTERM:
699                 /* Allow the pending page flip requests to be completed before
700                  * the teardown sequence */
701                 sleep(1);
702                 printf("Handling signal number = %d\n", signum);
703                 cleanup_kmscube();
704                 break;
705         default:
706                 printf("Unknown signal\n");
707                 break;
708         }
709         exit(1);
712 int main(int argc, char *argv[])
714         fd_set fds;
715         drmEventContext evctx = {
716                         .version = DRM_EVENT_CONTEXT_VERSION,
717                         .page_flip_handler = page_flip_handler,
718         };
719         struct gbm_bo *bo;
720         struct drm_fb *fb;
721         uint32_t i = 0;
722         int ret;
723         int opt;
724         int frame_count = -1;
726         signal(SIGINT, kms_signalhandler);
727         signal(SIGTERM, kms_signalhandler);
729         while ((opt = getopt(argc, argv, "ahc:n:")) != -1) {
730                 switch(opt) {
731                 case 'a':
732                         all_display = 1;
733                         break;
735                 case 'h':
736                         print_usage();
737                         return 0;
739                 case 'c':
740                         connector_id = atoi(optarg);
741                         break;
742                 case 'n':
743                         frame_count = atoi(optarg);
744                         break;
747                 default:
748                         printf("Undefined option %s\n", argv[optind]);
749                         print_usage();
750                         return -1;
751                 }
752         }
754         if (all_display) {
755                 printf("### Enabling all displays\n");
756                 connector_id = -1;
757         }
759         ret = init_drm();
760         if (ret) {
761                 printf("failed to initialize DRM\n");
762                 return ret;
763         }
764         printf("### Primary display => ConnectorId = %d, Resolution = %dx%d\n",
765                         drm.connector_id[DISP_ID], drm.mode[DISP_ID]->hdisplay,
766                         drm.mode[DISP_ID]->vdisplay);
768         FD_ZERO(&fds);
769         FD_SET(drm.fd, &fds);
771         ret = init_gbm();
772         if (ret) {
773                 printf("failed to initialize GBM\n");
774                 return ret;
775         }
777         ret = init_gl();
778         if (ret) {
779                 printf("failed to initialize EGL\n");
780                 return ret;
781         }
783         /* clear the color buffer */
784         glClearColor(0.5, 0.5, 0.5, 1.0);
785         glClear(GL_COLOR_BUFFER_BIT);
786         eglSwapBuffers(gl.display, gl.surface);
787         bo = gbm_surface_lock_front_buffer(gbm.surface);
788         fb = drm_fb_get_from_bo(bo);
790         /* set mode: */
791         if (all_display) {
792                 for (i=0; i<drm.ndisp; i++) {
793                         ret = drmModeSetCrtc(drm.fd, drm.crtc_id[i], fb->fb_id, 0, 0,
794                                         &drm.connector_id[i], 1, drm.mode[i]);
795                         if (ret) {
796                                 printf("display %d failed to set mode: %s\n", i, strerror(errno));
797                                 return ret;
798                         }
799                 }
800         } else {
801                 ret = drmModeSetCrtc(drm.fd, drm.crtc_id[DISP_ID], fb->fb_id,
802                                 0, 0, &drm.connector_id[DISP_ID], 1, drm.mode[DISP_ID]);
803                 if (ret) {
804                         printf("display %d failed to set mode: %s\n", DISP_ID, strerror(errno));
805                         return ret;
806                 }
807         }
809         while (frame_count != 0) {
810                 struct gbm_bo *next_bo;
811                 int waiting_for_flip = 1;
813                 draw(i++);
815                 eglSwapBuffers(gl.display, gl.surface);
816                 next_bo = gbm_surface_lock_front_buffer(gbm.surface);
817                 fb = drm_fb_get_from_bo(next_bo);
819                 /*
820                  * Here you could also update drm plane layers if you want
821                  * hw composition
822                  */
824                 ret = drmModePageFlip(drm.fd, drm.crtc_id[DISP_ID], fb->fb_id,
825                                 DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);
826                 if (ret) {
827                         printf("failed to queue page flip: %s\n", strerror(errno));
828                         return -1;
829                 }
831                 while (waiting_for_flip) {
832                         ret = select(drm.fd + 1, &fds, NULL, NULL, NULL);
833                         if (ret < 0) {
834                                 printf("select err: %s\n", strerror(errno));
835                                 return ret;
836                         } else if (ret == 0) {
837                                 printf("select timeout!\n");
838                                 return -1;
839                         } else if (FD_ISSET(0, &fds)) {
840                                 continue;
841                         }
842                         drmHandleEvent(drm.fd, &evctx);
843                 }
845                 /* release last buffer to render on again: */
846                 gbm_surface_release_buffer(gbm.surface, bo);
847                 bo = next_bo;
849                 if(frame_count >= 0)
850                         frame_count--;
851         }
853         cleanup_kmscube();
854         printf("\n Exiting kmscube \n");
856         return ret;