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