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