]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/kmscube.git/blob - kmscube.c
find the desired pixel format from the format list of the primary plane
[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 <stdbool.h>
35 #include <unistd.h>
36 #include <errno.h>
37 #include <signal.h>
39 #include <xf86drm.h>
40 #include <xf86drmMode.h>
41 #include <drm_fourcc.h>
42 #include <gbm.h>
44 #include "esUtil.h"
46 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
48 #define MAX_DISPLAYS    (4)
49 uint8_t DISP_ID = 0;
50 uint8_t all_display = 0;
51 int8_t connector_id = -1;
53 static struct {
54         EGLDisplay display;
55         EGLConfig config;
56         EGLContext context;
57         EGLSurface surface;
58         GLuint program;
59         GLint modelviewmatrix, modelviewprojectionmatrix, normalmatrix;
60         GLuint vbo;
61         GLuint positionsoffset, colorsoffset, normalsoffset;
62         GLuint vertex_shader, fragment_shader;
63 } gl;
65 static struct {
66         struct gbm_device *dev;
67         struct gbm_surface *surface;
68 } gbm;
70 static struct {
71         int fd;
72         uint32_t ndisp;
73         uint32_t crtc_id[MAX_DISPLAYS];
74         uint32_t connector_id[MAX_DISPLAYS];
75         uint32_t resource_id;
76         uint32_t encoder[MAX_DISPLAYS];
77         uint32_t format[MAX_DISPLAYS];
78         drmModeModeInfo *mode[MAX_DISPLAYS];
79         drmModeConnector *connectors[MAX_DISPLAYS];
80 } drm;
82 struct drm_fb {
83         struct gbm_bo *bo;
84         uint32_t fb_id;
85 };
87 static uint32_t drm_fmt_to_gbm_fmt(uint32_t fmt)
88 {
89         switch (fmt) {
90                 case DRM_FORMAT_XRGB8888:
91                         return GBM_FORMAT_XRGB8888;
92                 case DRM_FORMAT_ARGB8888:
93                         return GBM_FORMAT_ARGB8888;
94                 case DRM_FORMAT_RGB565:
95                         return GBM_FORMAT_RGB565;
96                 default:
97                         printf("Unsupported DRM format: 0x%x", fmt);
98                         return GBM_FORMAT_XRGB8888;
99         }
102 static bool search_plane_format(uint32_t desired_format, int formats_count, uint32_t* formats)
104         int i;
106         for ( i = 0; i < formats_count; i++)
107         {
108                 if (desired_format == formats[i])
109                         return true;
110         }
112         return false;
115 int get_drm_prop_val(int fd, drmModeObjectPropertiesPtr props,
116                          const char *name, unsigned int *p_val) {
117         drmModePropertyPtr p;
118         unsigned int i, prop_id = 0; /* Property ID should always be > 0 */
120         for (i = 0; !prop_id && i < props->count_props; i++) {
121                 p = drmModeGetProperty(fd, props->props[i]);
122                 if (!strcmp(p->name, name)){
123                         prop_id = p->prop_id;
124                         break;
125                 }
126                 drmModeFreeProperty(p);
127         }
129         if (!prop_id) {
130                 printf("Could not find %s property\n", name);
131                 return(-1);
132         }
134         drmModeFreeProperty(p);
135         *p_val = props->prop_values[i];
136         return 0;
139 static bool set_drm_format(void)
141         /* desired DRM format in order */
142         static const uint32_t drm_formats[] = {DRM_FORMAT_XRGB8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_RGB565};
143         drmModePlaneRes *plane_res;
144         bool found = false;
145         int i,k;
147         drmSetClientCap(drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
149         plane_res  = drmModeGetPlaneResources(drm.fd);
151         if (!plane_res) {
152                 printf("drmModeGetPlaneResources failed: %s\n", strerror(errno));
153                 drmSetClientCap(drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 0);
154                 return false;
155         }
157         /*
158          * find the plane connected to crtc_id (the primary plane) and then find the desired pixel format
159          * from the plane format list
160          */
161         for (i = 0; i < plane_res->count_planes; i++)
162         {
163                 drmModePlane *plane = drmModeGetPlane(drm.fd, plane_res->planes[i]);
164                 drmModeObjectProperties *props;
165                 unsigned int plane_type;
167                 if(plane == NULL)
168                         continue;
170                 props = drmModeObjectGetProperties(drm.fd, plane->plane_id, DRM_MODE_OBJECT_PLANE);
172                 if(props == NULL){
173                         printf("plane (%d) properties not found\n",  plane->plane_id);
174                         drmModeFreePlane(plane);
175                         continue;
176                 }
178                 if(get_drm_prop_val(drm.fd, props, "type",  &plane_type) < 0)
179                 {
180                         printf("plane (%d) type value not found\n",  plane->plane_id);
181                         drmModeFreeObjectProperties(props);
182                         drmModeFreePlane(plane);
183                         continue;
184                 }
186                 if (plane_type != DRM_PLANE_TYPE_PRIMARY)
187                 {
188                         drmModeFreeObjectProperties(props);
189                         drmModeFreePlane(plane);
190                         continue;
191                 }
192                 else if (!plane->crtc_id)
193                 {
194                         plane->crtc_id = drm.crtc_id[drm.ndisp];
195                 }
197                 drmModeFreeObjectProperties(props);
199                 if (plane->crtc_id == drm.crtc_id[drm.ndisp])
200                 {
201                         for (k = 0; k < ARRAY_SIZE(drm_formats); k++)
202                         {
203                                 if (search_plane_format(drm_formats[k], plane->count_formats, plane->formats))
204                                 {
205                                         drm.format[drm.ndisp] = drm_formats[k];
206                                         drmModeFreePlane(plane);
207                                         drmModeFreePlaneResources(plane_res);
208                                         drmSetClientCap(drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 0);
209                                         return true;
210                                 }
211                         }
212                 }
214                 drmModeFreePlane(plane);
215         }
217         drmModeFreePlaneResources(plane_res);
218         drmSetClientCap(drm.fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 0);
219         return false;
222 static int init_drm(void)
224         static const char *modules[] = {
225                         "omapdrm", "tilcdc", "i915", "radeon", "nouveau", "vmwgfx", "exynos"
226         };
227         drmModeRes *resources;
228         drmModeConnector *connector = NULL;
229         drmModeEncoder *encoder = NULL;
230         drmModeCrtc *crtc = NULL;
232         int i, j, k;
233         uint32_t maxRes, curRes;
235         for (i = 0; i < ARRAY_SIZE(modules); i++) {
236                 printf("trying to load module %s...", modules[i]);
237                 drm.fd = drmOpen(modules[i], NULL);
238                 if (drm.fd < 0) {
239                         printf("failed.\n");
240                 } else {
241                         printf("success.\n");
242                         break;
243                 }
244         }
246         if (drm.fd < 0) {
247                 printf("could not open drm device\n");
248                 return -1;
249         }
251         resources = drmModeGetResources(drm.fd);
252         if (!resources) {
253                 printf("drmModeGetResources failed: %s\n", strerror(errno));
254                 return -1;
255         }
256         drm.resource_id = (uint32_t) resources;
258         /* find a connected connector: */
259         for (i = 0; i < resources->count_connectors; i++) {
260                 connector = drmModeGetConnector(drm.fd, resources->connectors[i]);
261                 if (connector->connection == DRM_MODE_CONNECTED) {
263                         /* find the matched encoders */
264                         for (j=0; j<connector->count_encoders; j++) {
265                                 encoder = drmModeGetEncoder(drm.fd, connector->encoders[j]);
267                                 /* Take the fisrt one, if none is assigned */
268                                 if (!connector->encoder_id)
269                                 {
270                                         connector->encoder_id = encoder->encoder_id;
271                                 }
273                                 if (encoder->encoder_id == connector->encoder_id)
274                                 {
275                                         /* find the first valid CRTC if not assigned */
276                                         if (!encoder->crtc_id)
277                                         {
278                                                 for (k = 0; k < resources->count_crtcs; ++k) {
279                                                         /* check whether this CRTC works with the encoder */
280                                                         if (!(encoder->possible_crtcs & (1 << k)))
281                                                                 continue;
283                                                         encoder->crtc_id = resources->crtcs[k];
284                                                         break;
285                                                 }
287                                                 if (!encoder->crtc_id)
288                                                 {
289                                                         printf("Encoder(%d): no CRTC find!\n", encoder->encoder_id);
290                                                         drmModeFreeEncoder(encoder);
291                                                         encoder = NULL;
292                                                         continue;
293                                                 }
294                                         }
296                                         break;
297                                 }
299                                 drmModeFreeEncoder(encoder);
300                                 encoder = NULL;
301                         }
303                         if (!encoder) {
304                                 printf("Connector (%d): no encoder!\n", connector->connector_id);
305                                 drmModeFreeConnector(connector);
306                                 continue;
307                         }
309                         /* choose the current or first supported mode */
310                         crtc = drmModeGetCrtc(drm.fd, encoder->crtc_id);
311                         for (j = 0; j < connector->count_modes; j++)
312                         {
313                                 if (crtc->mode_valid)
314                                 {
315                                         if ((connector->modes[j].hdisplay == crtc->width) &&
316                                         (connector->modes[j].vdisplay == crtc->height))
317                                         {
318                                                 drm.mode[drm.ndisp] = &connector->modes[j];
319                                                 break;
320                                         }
321                                 }
322                                 else
323                                 {
324                                         if ((connector->modes[j].hdisplay == crtc->x) &&
325                                            (connector->modes[j].vdisplay == crtc->y))
326                                         {
327                                                 drm.mode[drm.ndisp] = &connector->modes[j];
328                                                 break;
329                                         }
330                                 }
331                         }
333                         if(j >= connector->count_modes)
334                                 drm.mode[drm.ndisp] = &connector->modes[0];
336                         drm.connector_id[drm.ndisp] = connector->connector_id;
338                         drm.encoder[drm.ndisp]  = (uint32_t) encoder;
339                         drm.crtc_id[drm.ndisp] = encoder->crtc_id;
340                         drm.connectors[drm.ndisp] = connector;
342                         if (!set_drm_format())
343                         {
344                                 // Error handling
345                                 printf("No desired pixel format found!\n");
346                                 return -1;
347                         }
349                         printf("### Display [%d]: CRTC = %d, Connector = %d, format = 0x%x\n", drm.ndisp, drm.crtc_id[drm.ndisp], drm.connector_id[drm.ndisp], drm.format[drm.ndisp]);
350                         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);
351                         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);
352                         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);
354                         /* If a connector_id is specified, use the corresponding display */
355                         if ((connector_id != -1) && (connector_id == drm.connector_id[drm.ndisp]))
356                                 DISP_ID = drm.ndisp;
358                         /* If all displays are enabled, choose the connector with maximum
359                         * resolution as the primary display */
360                         if (all_display) {
361                                 maxRes = drm.mode[DISP_ID]->vdisplay * drm.mode[DISP_ID]->hdisplay;
362                                 curRes = drm.mode[drm.ndisp]->vdisplay * drm.mode[drm.ndisp]->hdisplay;
364                                 if (curRes > maxRes)
365                                         DISP_ID = drm.ndisp;
366                         }
368                         drm.ndisp++;
369                 } else {
370                         drmModeFreeConnector(connector);
371                 }
372         }
374         if (drm.ndisp == 0) {
375                 /* we could be fancy and listen for hotplug events and wait for
376                  * a connector..
377                  */
378                 printf("no connected connector!\n");
379                 return -1;
380         }
382         return 0;
385 static int init_gbm(void)
387         gbm.dev = gbm_create_device(drm.fd);
389         gbm.surface = gbm_surface_create(gbm.dev,
390                         drm.mode[DISP_ID]->hdisplay, drm.mode[DISP_ID]->vdisplay,
391                         drm_fmt_to_gbm_fmt(drm.format[DISP_ID]),
392                         GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
393         if (!gbm.surface) {
394                 printf("failed to create gbm surface\n");
395                 return -1;
396         }
398         return 0;
401 static int init_gl(void)
403         EGLint major, minor, n;
404         GLint ret;
406         static const GLfloat vVertices[] = {
407                         // front
408                         -1.0f, -1.0f, +1.0f, // point blue
409                         +1.0f, -1.0f, +1.0f, // point magenta
410                         -1.0f, +1.0f, +1.0f, // point cyan
411                         +1.0f, +1.0f, +1.0f, // point white
412                         // back
413                         +1.0f, -1.0f, -1.0f, // point red
414                         -1.0f, -1.0f, -1.0f, // point black
415                         +1.0f, +1.0f, -1.0f, // point yellow
416                         -1.0f, +1.0f, -1.0f, // point green
417                         // right
418                         +1.0f, -1.0f, +1.0f, // point magenta
419                         +1.0f, -1.0f, -1.0f, // point red
420                         +1.0f, +1.0f, +1.0f, // point white
421                         +1.0f, +1.0f, -1.0f, // point yellow
422                         // left
423                         -1.0f, -1.0f, -1.0f, // point black
424                         -1.0f, -1.0f, +1.0f, // point blue
425                         -1.0f, +1.0f, -1.0f, // point green
426                         -1.0f, +1.0f, +1.0f, // point cyan
427                         // top
428                         -1.0f, +1.0f, +1.0f, // point cyan
429                         +1.0f, +1.0f, +1.0f, // point white
430                         -1.0f, +1.0f, -1.0f, // point green
431                         +1.0f, +1.0f, -1.0f, // point yellow
432                         // bottom
433                         -1.0f, -1.0f, -1.0f, // point black
434                         +1.0f, -1.0f, -1.0f, // point red
435                         -1.0f, -1.0f, +1.0f, // point blue
436                         +1.0f, -1.0f, +1.0f  // point magenta
437         };
439         static const GLfloat vColors[] = {
440                         // front
441                         0.0f,  0.0f,  1.0f, // blue
442                         1.0f,  0.0f,  1.0f, // magenta
443                         0.0f,  1.0f,  1.0f, // cyan
444                         1.0f,  1.0f,  1.0f, // white
445                         // back
446                         1.0f,  0.0f,  0.0f, // red
447                         0.0f,  0.0f,  0.0f, // black
448                         1.0f,  1.0f,  0.0f, // yellow
449                         0.0f,  1.0f,  0.0f, // green
450                         // right
451                         1.0f,  0.0f,  1.0f, // magenta
452                         1.0f,  0.0f,  0.0f, // red
453                         1.0f,  1.0f,  1.0f, // white
454                         1.0f,  1.0f,  0.0f, // yellow
455                         // left
456                         0.0f,  0.0f,  0.0f, // black
457                         0.0f,  0.0f,  1.0f, // blue
458                         0.0f,  1.0f,  0.0f, // green
459                         0.0f,  1.0f,  1.0f, // cyan
460                         // top
461                         0.0f,  1.0f,  1.0f, // cyan
462                         1.0f,  1.0f,  1.0f, // white
463                         0.0f,  1.0f,  0.0f, // green
464                         1.0f,  1.0f,  0.0f, // yellow
465                         // bottom
466                         0.0f,  0.0f,  0.0f, // black
467                         1.0f,  0.0f,  0.0f, // red
468                         0.0f,  0.0f,  1.0f, // blue
469                         1.0f,  0.0f,  1.0f  // magenta
470         };
472         static const GLfloat vNormals[] = {
473                         // front
474                         +0.0f, +0.0f, +1.0f, // forward
475                         +0.0f, +0.0f, +1.0f, // forward
476                         +0.0f, +0.0f, +1.0f, // forward
477                         +0.0f, +0.0f, +1.0f, // forward
478                         // back
479                         +0.0f, +0.0f, -1.0f, // backbard
480                         +0.0f, +0.0f, -1.0f, // backbard
481                         +0.0f, +0.0f, -1.0f, // backbard
482                         +0.0f, +0.0f, -1.0f, // backbard
483                         // right
484                         +1.0f, +0.0f, +0.0f, // right
485                         +1.0f, +0.0f, +0.0f, // right
486                         +1.0f, +0.0f, +0.0f, // right
487                         +1.0f, +0.0f, +0.0f, // right
488                         // left
489                         -1.0f, +0.0f, +0.0f, // left
490                         -1.0f, +0.0f, +0.0f, // left
491                         -1.0f, +0.0f, +0.0f, // left
492                         -1.0f, +0.0f, +0.0f, // left
493                         // top
494                         +0.0f, +1.0f, +0.0f, // up
495                         +0.0f, +1.0f, +0.0f, // up
496                         +0.0f, +1.0f, +0.0f, // up
497                         +0.0f, +1.0f, +0.0f, // up
498                         // bottom
499                         +0.0f, -1.0f, +0.0f, // down
500                         +0.0f, -1.0f, +0.0f, // down
501                         +0.0f, -1.0f, +0.0f, // down
502                         +0.0f, -1.0f, +0.0f  // down
503         };
505         static const EGLint context_attribs[] = {
506                 EGL_CONTEXT_CLIENT_VERSION, 2,
507                 EGL_NONE
508         };
510         static const EGLint config_attribs[] = {
511                 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
512                 EGL_RED_SIZE, 1,
513                 EGL_GREEN_SIZE, 1,
514                 EGL_BLUE_SIZE, 1,
515                 EGL_ALPHA_SIZE, 0,
516                 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
517                 EGL_NONE
518         };
520         static const char *vertex_shader_source =
521                         "uniform mat4 modelviewMatrix;      \n"
522                         "uniform mat4 modelviewprojectionMatrix;\n"
523                         "uniform mat3 normalMatrix;         \n"
524                         "                                   \n"
525                         "attribute vec4 in_position;        \n"
526                         "attribute vec3 in_normal;          \n"
527                         "attribute vec4 in_color;           \n"
528                         "\n"
529                         "vec4 lightSource = vec4(2.0, 2.0, 20.0, 0.0);\n"
530                         "                                   \n"
531                         "varying vec4 vVaryingColor;        \n"
532                         "                                   \n"
533                         "void main()                        \n"
534                         "{                                  \n"
535                         "    gl_Position = modelviewprojectionMatrix * in_position;\n"
536                         "    vec3 vEyeNormal = normalMatrix * in_normal;\n"
537                         "    vec4 vPosition4 = modelviewMatrix * in_position;\n"
538                         "    vec3 vPosition3 = vPosition4.xyz / vPosition4.w;\n"
539                         "    vec3 vLightDir = normalize(lightSource.xyz - vPosition3);\n"
540                         "    float diff = max(0.0, dot(vEyeNormal, vLightDir));\n"
541                         "    vVaryingColor = vec4(diff * in_color.rgb, 1.0);\n"
542                         "}                                  \n";
544         static const char *fragment_shader_source =
545                         "precision mediump float;           \n"
546                         "                                   \n"
547                         "varying vec4 vVaryingColor;        \n"
548                         "                                   \n"
549                         "void main()                        \n"
550                         "{                                  \n"
551                         "    gl_FragColor = vVaryingColor;  \n"
552                         "}                                  \n";
554         gl.display = eglGetDisplay(gbm.dev);
556         if (!eglInitialize(gl.display, &major, &minor)) {
557                 printf("failed to initialize\n");
558                 return -1;
559         }
561         printf("Using display %p with EGL version %d.%d\n",
562                         gl.display, major, minor);
564         printf("EGL Version \"%s\"\n", eglQueryString(gl.display, EGL_VERSION));
565         printf("EGL Vendor \"%s\"\n", eglQueryString(gl.display, EGL_VENDOR));
566         printf("EGL Extensions \"%s\"\n", eglQueryString(gl.display, EGL_EXTENSIONS));
568         if (!eglBindAPI(EGL_OPENGL_ES_API)) {
569                 printf("failed to bind api EGL_OPENGL_ES_API\n");
570                 return -1;
571         }
573         if (!eglChooseConfig(gl.display, config_attribs, &gl.config, 1, &n) || n != 1) {
574                 printf("failed to choose config: %d\n", n);
575                 return -1;
576         }
578         gl.context = eglCreateContext(gl.display, gl.config,
579                         EGL_NO_CONTEXT, context_attribs);
580         if (gl.context == NULL) {
581                 printf("failed to create context\n");
582                 return -1;
583         }
585         gl.surface = eglCreateWindowSurface(gl.display, gl.config, gbm.surface, NULL);
586         if (gl.surface == EGL_NO_SURFACE) {
587                 printf("failed to create egl surface\n");
588                 return -1;
589         }
591         /* connect the context to the surface */
592         eglMakeCurrent(gl.display, gl.surface, gl.surface, gl.context);
595         gl.vertex_shader = glCreateShader(GL_VERTEX_SHADER);
597         glShaderSource(gl.vertex_shader, 1, &vertex_shader_source, NULL);
598         glCompileShader(gl.vertex_shader);
600         glGetShaderiv(gl.vertex_shader, GL_COMPILE_STATUS, &ret);
601         if (!ret) {
602                 char *log;
604                 printf("vertex shader compilation failed!:\n");
605                 glGetShaderiv(gl.vertex_shader, GL_INFO_LOG_LENGTH, &ret);
606                 if (ret > 1) {
607                         log = malloc(ret);
608                         glGetShaderInfoLog(gl.vertex_shader, ret, NULL, log);
609                         printf("%s", log);
610                 }
612                 return -1;
613         }
615         gl.fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
617         glShaderSource(gl.fragment_shader, 1, &fragment_shader_source, NULL);
618         glCompileShader(gl.fragment_shader);
620         glGetShaderiv(gl.fragment_shader, GL_COMPILE_STATUS, &ret);
621         if (!ret) {
622                 char *log;
624                 printf("fragment shader compilation failed!:\n");
625                 glGetShaderiv(gl.fragment_shader, GL_INFO_LOG_LENGTH, &ret);
627                 if (ret > 1) {
628                         log = malloc(ret);
629                         glGetShaderInfoLog(gl.fragment_shader, ret, NULL, log);
630                         printf("%s", log);
631                 }
633                 return -1;
634         }
636         gl.program = glCreateProgram();
638         glAttachShader(gl.program, gl.vertex_shader);
639         glAttachShader(gl.program, gl.fragment_shader);
641         glBindAttribLocation(gl.program, 0, "in_position");
642         glBindAttribLocation(gl.program, 1, "in_normal");
643         glBindAttribLocation(gl.program, 2, "in_color");
645         glLinkProgram(gl.program);
647         glGetProgramiv(gl.program, GL_LINK_STATUS, &ret);
648         if (!ret) {
649                 char *log;
651                 printf("program linking failed!:\n");
652                 glGetProgramiv(gl.program, GL_INFO_LOG_LENGTH, &ret);
654                 if (ret > 1) {
655                         log = malloc(ret);
656                         glGetProgramInfoLog(gl.program, ret, NULL, log);
657                         printf("%s", log);
658                 }
660                 return -1;
661         }
663         glUseProgram(gl.program);
665         gl.modelviewmatrix = glGetUniformLocation(gl.program, "modelviewMatrix");
666         gl.modelviewprojectionmatrix = glGetUniformLocation(gl.program, "modelviewprojectionMatrix");
667         gl.normalmatrix = glGetUniformLocation(gl.program, "normalMatrix");
669         glViewport(0, 0, drm.mode[DISP_ID]->hdisplay, drm.mode[DISP_ID]->vdisplay);
670         glEnable(GL_CULL_FACE);
672         gl.positionsoffset = 0;
673         gl.colorsoffset = sizeof(vVertices);
674         gl.normalsoffset = sizeof(vVertices) + sizeof(vColors);
675         glGenBuffers(1, &gl.vbo);
676         glBindBuffer(GL_ARRAY_BUFFER, gl.vbo);
677         glBufferData(GL_ARRAY_BUFFER, sizeof(vVertices) + sizeof(vColors) + sizeof(vNormals), 0, GL_STATIC_DRAW);
678         glBufferSubData(GL_ARRAY_BUFFER, gl.positionsoffset, sizeof(vVertices), &vVertices[0]);
679         glBufferSubData(GL_ARRAY_BUFFER, gl.colorsoffset, sizeof(vColors), &vColors[0]);
680         glBufferSubData(GL_ARRAY_BUFFER, gl.normalsoffset, sizeof(vNormals), &vNormals[0]);
681         glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)gl.positionsoffset);
682         glEnableVertexAttribArray(0);
683         glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)gl.normalsoffset);
684         glEnableVertexAttribArray(1);
685         glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)gl.colorsoffset);
686         glEnableVertexAttribArray(2);
688         return 0;
691 static void exit_gbm(void)
693         gbm_surface_destroy(gbm.surface);
694         gbm_device_destroy(gbm.dev);
695         return;
698 static void exit_gl(void)
700         glDeleteProgram(gl.program);
701         glDeleteBuffers(1, &gl.vbo);
702         glDeleteShader(gl.fragment_shader);
703         glDeleteShader(gl.vertex_shader);
704         eglDestroySurface(gl.display, gl.surface);
705         eglDestroyContext(gl.display, gl.context);
706         eglTerminate(gl.display);
707         return;
710 static void exit_drm(void)
713         drmModeRes *resources;
714         int i;
716         resources = (drmModeRes *)drm.resource_id;
717         for (i = 0; i < resources->count_connectors; i++) {
718                 drmModeFreeEncoder(drm.encoder[i]);
719                 drmModeFreeConnector(drm.connectors[i]);
720         }
721         drmModeFreeResources(drm.resource_id);
722         drmClose(drm.fd);
723         return;
726 void cleanup_kmscube(void)
728         exit_gl();
729         exit_gbm();
730         exit_drm();
731         printf("Cleanup of GL, GBM and DRM completed\n");
732         return;
735 static void draw(uint32_t i)
737         ESMatrix modelview;
739         /* clear the color buffer */
740         glClearColor(0.5, 0.5, 0.5, 1.0);
741         glClear(GL_COLOR_BUFFER_BIT);
743         esMatrixLoadIdentity(&modelview);
744         esTranslate(&modelview, 0.0f, 0.0f, -8.0f);
745         esRotate(&modelview, 45.0f + (0.25f * i), 1.0f, 0.0f, 0.0f);
746         esRotate(&modelview, 45.0f - (0.5f * i), 0.0f, 1.0f, 0.0f);
747         esRotate(&modelview, 10.0f + (0.15f * i), 0.0f, 0.0f, 1.0f);
749         GLfloat aspect = (GLfloat)(drm.mode[DISP_ID]->vdisplay) / (GLfloat)(drm.mode[DISP_ID]->hdisplay);
751         ESMatrix projection;
752         esMatrixLoadIdentity(&projection);
753         esFrustum(&projection, -2.8f, +2.8f, -2.8f * aspect, +2.8f * aspect, 6.0f, 10.0f);
755         ESMatrix modelviewprojection;
756         esMatrixLoadIdentity(&modelviewprojection);
757         esMatrixMultiply(&modelviewprojection, &modelview, &projection);
759         float normal[9];
760         normal[0] = modelview.m[0][0];
761         normal[1] = modelview.m[0][1];
762         normal[2] = modelview.m[0][2];
763         normal[3] = modelview.m[1][0];
764         normal[4] = modelview.m[1][1];
765         normal[5] = modelview.m[1][2];
766         normal[6] = modelview.m[2][0];
767         normal[7] = modelview.m[2][1];
768         normal[8] = modelview.m[2][2];
770         glUniformMatrix4fv(gl.modelviewmatrix, 1, GL_FALSE, &modelview.m[0][0]);
771         glUniformMatrix4fv(gl.modelviewprojectionmatrix, 1, GL_FALSE, &modelviewprojection.m[0][0]);
772         glUniformMatrix3fv(gl.normalmatrix, 1, GL_FALSE, normal);
774         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
775         glDrawArrays(GL_TRIANGLE_STRIP, 4, 4);
776         glDrawArrays(GL_TRIANGLE_STRIP, 8, 4);
777         glDrawArrays(GL_TRIANGLE_STRIP, 12, 4);
778         glDrawArrays(GL_TRIANGLE_STRIP, 16, 4);
779         glDrawArrays(GL_TRIANGLE_STRIP, 20, 4);
782 static void
783 drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
785         struct drm_fb *fb = data;
786         struct gbm_device *gbm = gbm_bo_get_device(bo);
788         if (fb->fb_id)
789                 drmModeRmFB(drm.fd, fb->fb_id);
791         free(fb);
794 static struct drm_fb * drm_fb_get_from_bo(struct gbm_bo *bo)
796         struct drm_fb *fb = gbm_bo_get_user_data(bo);
797         uint32_t width, height, format;
798         uint32_t bo_handles[4] = {0}, offsets[4] = {0}, pitches[4] = {0};
799         int ret;
801         if (fb)
802                 return fb;
804         fb = calloc(1, sizeof *fb);
805         fb->bo = bo;
807         width = gbm_bo_get_width(bo);
808         height = gbm_bo_get_height(bo);
809         pitches[0] = gbm_bo_get_stride(bo);
810         bo_handles[0] = gbm_bo_get_handle(bo).u32;
811         format = gbm_bo_get_format(bo);
813         ret = drmModeAddFB2(drm.fd, width, height, format, bo_handles, pitches, offsets, &fb->fb_id, 0);
814         if (ret) {
815                 printf("failed to create fb: %s\n", strerror(errno));
816                 free(fb);
817                 return NULL;
818         }
820         gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
822         return fb;
825 static void page_flip_handler(int fd, unsigned int frame,
826                   unsigned int sec, unsigned int usec, void *data)
828         int *waiting_for_flip = data;
829         *waiting_for_flip = 0;
832 void print_usage()
834         printf("Usage : kmscube <options>\n");
835         printf("\t-h : Help\n");
836         printf("\t-a : Enable all displays\n");
837         printf("\t-c <id> : Display using connector_id [if not specified, use the first connected connector]\n");
838         printf("\t-n <number> (optional): Number of frames to render\n");
841 int kms_signalhandler(int signum)
843         switch(signum) {
844         case SIGINT:
845         case SIGTERM:
846                 /* Allow the pending page flip requests to be completed before
847                  * the teardown sequence */
848                 sleep(1);
849                 printf("Handling signal number = %d\n", signum);
850                 cleanup_kmscube();
851                 break;
852         default:
853                 printf("Unknown signal\n");
854                 break;
855         }
856         exit(1);
859 int main(int argc, char *argv[])
861         fd_set fds;
862         drmEventContext evctx = {
863                         .version = DRM_EVENT_CONTEXT_VERSION,
864                         .page_flip_handler = page_flip_handler,
865         };
866         struct gbm_bo *bo;
867         struct drm_fb *fb;
868         uint32_t i = 0;
869         int ret;
870         int opt;
871         int frame_count = -1;
873         signal(SIGINT, kms_signalhandler);
874         signal(SIGTERM, kms_signalhandler);
876         while ((opt = getopt(argc, argv, "ahc:n:")) != -1) {
877                 switch(opt) {
878                 case 'a':
879                         all_display = 1;
880                         break;
882                 case 'h':
883                         print_usage();
884                         return 0;
886                 case 'c':
887                         connector_id = atoi(optarg);
888                         break;
889                 case 'n':
890                         frame_count = atoi(optarg);
891                         break;
894                 default:
895                         printf("Undefined option %s\n", argv[optind]);
896                         print_usage();
897                         return -1;
898                 }
899         }
901         if (all_display) {
902                 printf("### Enabling all displays\n");
903                 connector_id = -1;
904         }
906         ret = init_drm();
907         if (ret) {
908                 printf("failed to initialize DRM\n");
909                 return ret;
910         }
911         printf("### Primary display => ConnectorId = %d, Resolution = %dx%d\n",
912                         drm.connector_id[DISP_ID], drm.mode[DISP_ID]->hdisplay,
913                         drm.mode[DISP_ID]->vdisplay);
915         FD_ZERO(&fds);
916         FD_SET(drm.fd, &fds);
918         ret = init_gbm();
919         if (ret) {
920                 printf("failed to initialize GBM\n");
921                 return ret;
922         }
924         ret = init_gl();
925         if (ret) {
926                 printf("failed to initialize EGL\n");
927                 return ret;
928         }
930         /* clear the color buffer */
931         glClearColor(0.5, 0.5, 0.5, 1.0);
932         glClear(GL_COLOR_BUFFER_BIT);
933         eglSwapBuffers(gl.display, gl.surface);
934         bo = gbm_surface_lock_front_buffer(gbm.surface);
935         fb = drm_fb_get_from_bo(bo);
937         /* set mode: */
938         if (all_display) {
939                 for (i=0; i<drm.ndisp; i++) {
940                         ret = drmModeSetCrtc(drm.fd, drm.crtc_id[i], fb->fb_id, 0, 0,
941                                         &drm.connector_id[i], 1, drm.mode[i]);
942                         if (ret) {
943                                 printf("display %d failed to set mode: %s\n", i, strerror(errno));
944                                 return ret;
945                         }
946                 }
947         } else {
948                 ret = drmModeSetCrtc(drm.fd, drm.crtc_id[DISP_ID], fb->fb_id,
949                                 0, 0, &drm.connector_id[DISP_ID], 1, drm.mode[DISP_ID]);
950                 if (ret) {
951                         printf("display %d failed to set mode: %s\n", DISP_ID, strerror(errno));
952                         return ret;
953                 }
954         }
956         while (frame_count != 0) {
957                 struct gbm_bo *next_bo;
958                 int waiting_for_flip = 1;
960                 draw(i++);
962                 eglSwapBuffers(gl.display, gl.surface);
963                 next_bo = gbm_surface_lock_front_buffer(gbm.surface);
964                 fb = drm_fb_get_from_bo(next_bo);
966                 /*
967                  * Here you could also update drm plane layers if you want
968                  * hw composition
969                  */
971                 ret = drmModePageFlip(drm.fd, drm.crtc_id[DISP_ID], fb->fb_id,
972                                 DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);
973                 if (ret) {
974                         printf("failed to queue page flip: %s\n", strerror(errno));
975                         return -1;
976                 }
978                 while (waiting_for_flip) {
979                         ret = select(drm.fd + 1, &fds, NULL, NULL, NULL);
980                         if (ret < 0) {
981                                 printf("select err: %s\n", strerror(errno));
982                                 return ret;
983                         } else if (ret == 0) {
984                                 printf("select timeout!\n");
985                                 return -1;
986                         } else if (FD_ISSET(0, &fds)) {
987                                 continue;
988                         }
989                         drmHandleEvent(drm.fd, &evctx);
990                 }
992                 /* release last buffer to render on again: */
993                 gbm_surface_release_buffer(gbm.surface, bo);
994                 bo = next_bo;
996                 if(frame_count >= 0)
997                         frame_count--;
998         }
1000         cleanup_kmscube();
1001         printf("\n Exiting kmscube \n");
1003         return ret;