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>
37 #include <xf86drm.h>
38 #include <xf86drmMode.h>
39 #include <gbm.h>
41 #include "esUtil.h"
43 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
45 #define MAX_DISPLAYS (4)
46 uint8_t DISP_ID = 0;
47 uint8_t all_display = 0;
48 int8_t connector_id = -1;
50 static struct {
51 EGLDisplay display;
52 EGLConfig config;
53 EGLContext context;
54 EGLSurface surface;
55 GLuint program;
56 GLint modelviewmatrix, modelviewprojectionmatrix, normalmatrix;
57 GLuint vbo;
58 GLuint positionsoffset, colorsoffset, normalsoffset;
59 } gl;
61 static struct {
62 struct gbm_device *dev;
63 struct gbm_surface *surface;
64 } gbm;
66 static struct {
67 int fd;
68 uint32_t ndisp;
69 uint32_t crtc_id[MAX_DISPLAYS];
70 uint32_t connector_id[MAX_DISPLAYS];
71 drmModeModeInfo *mode[MAX_DISPLAYS];
72 drmModeConnector *connectors[MAX_DISPLAYS];
73 } drm;
75 struct drm_fb {
76 struct gbm_bo *bo;
77 uint32_t fb_id;
78 };
80 static int init_drm(void)
81 {
82 static const char *modules[] = {
83 "omapdrm", "i915", "radeon", "nouveau", "vmwgfx", "exynos"
84 };
85 drmModeRes *resources;
86 drmModeConnector *connector = NULL;
87 drmModeEncoder *encoder = NULL;
88 int i, j;
89 uint32_t maxRes, curRes;
91 for (i = 0; i < ARRAY_SIZE(modules); i++) {
92 printf("trying to load module %s...", modules[i]);
93 drm.fd = drmOpen(modules[i], NULL);
94 if (drm.fd < 0) {
95 printf("failed.\n");
96 } else {
97 printf("success.\n");
98 break;
99 }
100 }
102 if (drm.fd < 0) {
103 printf("could not open drm device\n");
104 return -1;
105 }
107 resources = drmModeGetResources(drm.fd);
108 if (!resources) {
109 printf("drmModeGetResources failed: %s\n", strerror(errno));
110 return -1;
111 }
113 /* find a connected connector: */
114 for (i = 0; i < resources->count_connectors; i++) {
115 connector = drmModeGetConnector(drm.fd, resources->connectors[i]);
116 if (connector->connection == DRM_MODE_CONNECTED) {
117 /* choose the first supported mode */
118 drm.mode[drm.ndisp] = &connector->modes[0];
119 drm.connector_id[drm.ndisp] = connector->connector_id;
121 for (j=0; j<resources->count_encoders; j++) {
122 encoder = drmModeGetEncoder(drm.fd, resources->encoders[j]);
123 if (encoder->encoder_id == connector->encoder_id)
124 break;
126 drmModeFreeEncoder(encoder);
127 encoder = NULL;
128 }
130 if (!encoder) {
131 printf("no encoder!\n");
132 return -1;
133 }
135 drm.crtc_id[drm.ndisp] = encoder->crtc_id;
136 drm.connectors[drm.ndisp] = connector;
138 printf("### Display [%d]: CRTC = %d, Connector = %d\n", drm.ndisp, drm.crtc_id[drm.ndisp], drm.connector_id[drm.ndisp]);
139 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);
140 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);
141 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);
143 /* If a connector_id is specified, use the corresponding display */
144 if ((connector_id != -1) && (connector_id == drm.connector_id[drm.ndisp]))
145 DISP_ID = drm.ndisp;
147 /* If all displays are enabled, choose the connector with maximum
148 * resolution as the primary display */
149 if (all_display) {
150 maxRes = drm.mode[DISP_ID]->vdisplay * drm.mode[DISP_ID]->hdisplay;
151 curRes = drm.mode[drm.ndisp]->vdisplay * drm.mode[drm.ndisp]->hdisplay;
153 if (curRes > maxRes)
154 DISP_ID = drm.ndisp;
155 }
157 drm.ndisp++;
158 } else {
159 drmModeFreeConnector(connector);
160 }
161 }
163 if (drm.ndisp == 0) {
164 /* we could be fancy and listen for hotplug events and wait for
165 * a connector..
166 */
167 printf("no connected connector!\n");
168 return -1;
169 }
171 return 0;
172 }
174 static int init_gbm(void)
175 {
176 gbm.dev = gbm_create_device(drm.fd);
178 gbm.surface = gbm_surface_create(gbm.dev,
179 drm.mode[DISP_ID]->hdisplay, drm.mode[DISP_ID]->vdisplay,
180 GBM_FORMAT_XRGB8888,
181 GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
182 if (!gbm.surface) {
183 printf("failed to create gbm surface\n");
184 return -1;
185 }
187 return 0;
188 }
190 static int init_gl(void)
191 {
192 EGLint major, minor, n;
193 GLuint vertex_shader, fragment_shader;
194 GLint ret;
196 static const GLfloat vVertices[] = {
197 // front
198 -1.0f, -1.0f, +1.0f, // point blue
199 +1.0f, -1.0f, +1.0f, // point magenta
200 -1.0f, +1.0f, +1.0f, // point cyan
201 +1.0f, +1.0f, +1.0f, // point white
202 // back
203 +1.0f, -1.0f, -1.0f, // point red
204 -1.0f, -1.0f, -1.0f, // point black
205 +1.0f, +1.0f, -1.0f, // point yellow
206 -1.0f, +1.0f, -1.0f, // point green
207 // right
208 +1.0f, -1.0f, +1.0f, // point magenta
209 +1.0f, -1.0f, -1.0f, // point red
210 +1.0f, +1.0f, +1.0f, // point white
211 +1.0f, +1.0f, -1.0f, // point yellow
212 // left
213 -1.0f, -1.0f, -1.0f, // point black
214 -1.0f, -1.0f, +1.0f, // point blue
215 -1.0f, +1.0f, -1.0f, // point green
216 -1.0f, +1.0f, +1.0f, // point cyan
217 // top
218 -1.0f, +1.0f, +1.0f, // point cyan
219 +1.0f, +1.0f, +1.0f, // point white
220 -1.0f, +1.0f, -1.0f, // point green
221 +1.0f, +1.0f, -1.0f, // point yellow
222 // bottom
223 -1.0f, -1.0f, -1.0f, // point black
224 +1.0f, -1.0f, -1.0f, // point red
225 -1.0f, -1.0f, +1.0f, // point blue
226 +1.0f, -1.0f, +1.0f // point magenta
227 };
229 static const GLfloat vColors[] = {
230 // front
231 0.0f, 0.0f, 1.0f, // blue
232 1.0f, 0.0f, 1.0f, // magenta
233 0.0f, 1.0f, 1.0f, // cyan
234 1.0f, 1.0f, 1.0f, // white
235 // back
236 1.0f, 0.0f, 0.0f, // red
237 0.0f, 0.0f, 0.0f, // black
238 1.0f, 1.0f, 0.0f, // yellow
239 0.0f, 1.0f, 0.0f, // green
240 // right
241 1.0f, 0.0f, 1.0f, // magenta
242 1.0f, 0.0f, 0.0f, // red
243 1.0f, 1.0f, 1.0f, // white
244 1.0f, 1.0f, 0.0f, // yellow
245 // left
246 0.0f, 0.0f, 0.0f, // black
247 0.0f, 0.0f, 1.0f, // blue
248 0.0f, 1.0f, 0.0f, // green
249 0.0f, 1.0f, 1.0f, // cyan
250 // top
251 0.0f, 1.0f, 1.0f, // cyan
252 1.0f, 1.0f, 1.0f, // white
253 0.0f, 1.0f, 0.0f, // green
254 1.0f, 1.0f, 0.0f, // yellow
255 // bottom
256 0.0f, 0.0f, 0.0f, // black
257 1.0f, 0.0f, 0.0f, // red
258 0.0f, 0.0f, 1.0f, // blue
259 1.0f, 0.0f, 1.0f // magenta
260 };
262 static const GLfloat vNormals[] = {
263 // front
264 +0.0f, +0.0f, +1.0f, // forward
265 +0.0f, +0.0f, +1.0f, // forward
266 +0.0f, +0.0f, +1.0f, // forward
267 +0.0f, +0.0f, +1.0f, // forward
268 // back
269 +0.0f, +0.0f, -1.0f, // backbard
270 +0.0f, +0.0f, -1.0f, // backbard
271 +0.0f, +0.0f, -1.0f, // backbard
272 +0.0f, +0.0f, -1.0f, // backbard
273 // right
274 +1.0f, +0.0f, +0.0f, // right
275 +1.0f, +0.0f, +0.0f, // right
276 +1.0f, +0.0f, +0.0f, // right
277 +1.0f, +0.0f, +0.0f, // right
278 // left
279 -1.0f, +0.0f, +0.0f, // left
280 -1.0f, +0.0f, +0.0f, // left
281 -1.0f, +0.0f, +0.0f, // left
282 -1.0f, +0.0f, +0.0f, // left
283 // top
284 +0.0f, +1.0f, +0.0f, // up
285 +0.0f, +1.0f, +0.0f, // up
286 +0.0f, +1.0f, +0.0f, // up
287 +0.0f, +1.0f, +0.0f, // up
288 // bottom
289 +0.0f, -1.0f, +0.0f, // down
290 +0.0f, -1.0f, +0.0f, // down
291 +0.0f, -1.0f, +0.0f, // down
292 +0.0f, -1.0f, +0.0f // down
293 };
295 static const EGLint context_attribs[] = {
296 EGL_CONTEXT_CLIENT_VERSION, 2,
297 EGL_NONE
298 };
300 static const EGLint config_attribs[] = {
301 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
302 EGL_RED_SIZE, 1,
303 EGL_GREEN_SIZE, 1,
304 EGL_BLUE_SIZE, 1,
305 EGL_ALPHA_SIZE, 0,
306 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
307 EGL_NONE
308 };
310 static const char *vertex_shader_source =
311 "uniform mat4 modelviewMatrix; \n"
312 "uniform mat4 modelviewprojectionMatrix;\n"
313 "uniform mat3 normalMatrix; \n"
314 " \n"
315 "attribute vec4 in_position; \n"
316 "attribute vec3 in_normal; \n"
317 "attribute vec4 in_color; \n"
318 "\n"
319 "vec4 lightSource = vec4(2.0, 2.0, 20.0, 0.0);\n"
320 " \n"
321 "varying vec4 vVaryingColor; \n"
322 " \n"
323 "void main() \n"
324 "{ \n"
325 " gl_Position = modelviewprojectionMatrix * in_position;\n"
326 " vec3 vEyeNormal = normalMatrix * in_normal;\n"
327 " vec4 vPosition4 = modelviewMatrix * in_position;\n"
328 " vec3 vPosition3 = vPosition4.xyz / vPosition4.w;\n"
329 " vec3 vLightDir = normalize(lightSource.xyz - vPosition3);\n"
330 " float diff = max(0.0, dot(vEyeNormal, vLightDir));\n"
331 " vVaryingColor = vec4(diff * in_color.rgb, 1.0);\n"
332 "} \n";
334 static const char *fragment_shader_source =
335 "precision mediump float; \n"
336 " \n"
337 "varying vec4 vVaryingColor; \n"
338 " \n"
339 "void main() \n"
340 "{ \n"
341 " gl_FragColor = vVaryingColor; \n"
342 "} \n";
344 gl.display = eglGetDisplay(gbm.dev);
346 if (!eglInitialize(gl.display, &major, &minor)) {
347 printf("failed to initialize\n");
348 return -1;
349 }
351 printf("Using display %p with EGL version %d.%d\n",
352 gl.display, major, minor);
354 printf("EGL Version \"%s\"\n", eglQueryString(gl.display, EGL_VERSION));
355 printf("EGL Vendor \"%s\"\n", eglQueryString(gl.display, EGL_VENDOR));
356 printf("EGL Extensions \"%s\"\n", eglQueryString(gl.display, EGL_EXTENSIONS));
358 if (!eglBindAPI(EGL_OPENGL_ES_API)) {
359 printf("failed to bind api EGL_OPENGL_ES_API\n");
360 return -1;
361 }
363 if (!eglChooseConfig(gl.display, config_attribs, &gl.config, 1, &n) || n != 1) {
364 printf("failed to choose config: %d\n", n);
365 return -1;
366 }
368 gl.context = eglCreateContext(gl.display, gl.config,
369 EGL_NO_CONTEXT, context_attribs);
370 if (gl.context == NULL) {
371 printf("failed to create context\n");
372 return -1;
373 }
375 gl.surface = eglCreateWindowSurface(gl.display, gl.config, gbm.surface, NULL);
376 if (gl.surface == EGL_NO_SURFACE) {
377 printf("failed to create egl surface\n");
378 return -1;
379 }
381 /* connect the context to the surface */
382 eglMakeCurrent(gl.display, gl.surface, gl.surface, gl.context);
385 vertex_shader = glCreateShader(GL_VERTEX_SHADER);
387 glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
388 glCompileShader(vertex_shader);
390 glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &ret);
391 if (!ret) {
392 char *log;
394 printf("vertex shader compilation failed!:\n");
395 glGetShaderiv(vertex_shader, GL_INFO_LOG_LENGTH, &ret);
396 if (ret > 1) {
397 log = malloc(ret);
398 glGetShaderInfoLog(vertex_shader, ret, NULL, log);
399 printf("%s", log);
400 }
402 return -1;
403 }
405 fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
407 glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
408 glCompileShader(fragment_shader);
410 glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &ret);
411 if (!ret) {
412 char *log;
414 printf("fragment shader compilation failed!:\n");
415 glGetShaderiv(fragment_shader, GL_INFO_LOG_LENGTH, &ret);
417 if (ret > 1) {
418 log = malloc(ret);
419 glGetShaderInfoLog(fragment_shader, ret, NULL, log);
420 printf("%s", log);
421 }
423 return -1;
424 }
426 gl.program = glCreateProgram();
428 glAttachShader(gl.program, vertex_shader);
429 glAttachShader(gl.program, fragment_shader);
431 glBindAttribLocation(gl.program, 0, "in_position");
432 glBindAttribLocation(gl.program, 1, "in_normal");
433 glBindAttribLocation(gl.program, 2, "in_color");
435 glLinkProgram(gl.program);
437 glGetProgramiv(gl.program, GL_LINK_STATUS, &ret);
438 if (!ret) {
439 char *log;
441 printf("program linking failed!:\n");
442 glGetProgramiv(gl.program, GL_INFO_LOG_LENGTH, &ret);
444 if (ret > 1) {
445 log = malloc(ret);
446 glGetProgramInfoLog(gl.program, ret, NULL, log);
447 printf("%s", log);
448 }
450 return -1;
451 }
453 glUseProgram(gl.program);
455 gl.modelviewmatrix = glGetUniformLocation(gl.program, "modelviewMatrix");
456 gl.modelviewprojectionmatrix = glGetUniformLocation(gl.program, "modelviewprojectionMatrix");
457 gl.normalmatrix = glGetUniformLocation(gl.program, "normalMatrix");
459 glViewport(0, 0, drm.mode[DISP_ID]->hdisplay, drm.mode[DISP_ID]->vdisplay);
460 glEnable(GL_CULL_FACE);
462 gl.positionsoffset = 0;
463 gl.colorsoffset = sizeof(vVertices);
464 gl.normalsoffset = sizeof(vVertices) + sizeof(vColors);
465 glGenBuffers(1, &gl.vbo);
466 glBindBuffer(GL_ARRAY_BUFFER, gl.vbo);
467 glBufferData(GL_ARRAY_BUFFER, sizeof(vVertices) + sizeof(vColors) + sizeof(vNormals), 0, GL_STATIC_DRAW);
468 glBufferSubData(GL_ARRAY_BUFFER, gl.positionsoffset, sizeof(vVertices), &vVertices[0]);
469 glBufferSubData(GL_ARRAY_BUFFER, gl.colorsoffset, sizeof(vColors), &vColors[0]);
470 glBufferSubData(GL_ARRAY_BUFFER, gl.normalsoffset, sizeof(vNormals), &vNormals[0]);
471 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)gl.positionsoffset);
472 glEnableVertexAttribArray(0);
473 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)gl.normalsoffset);
474 glEnableVertexAttribArray(1);
475 glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)gl.colorsoffset);
476 glEnableVertexAttribArray(2);
478 return 0;
479 }
481 static void draw(uint32_t i)
482 {
483 ESMatrix modelview;
485 /* clear the color buffer */
486 glClearColor(0.5, 0.5, 0.5, 1.0);
487 glClear(GL_COLOR_BUFFER_BIT);
489 esMatrixLoadIdentity(&modelview);
490 esTranslate(&modelview, 0.0f, 0.0f, -8.0f);
491 esRotate(&modelview, 45.0f + (0.25f * i), 1.0f, 0.0f, 0.0f);
492 esRotate(&modelview, 45.0f - (0.5f * i), 0.0f, 1.0f, 0.0f);
493 esRotate(&modelview, 10.0f + (0.15f * i), 0.0f, 0.0f, 1.0f);
495 GLfloat aspect = (GLfloat)(drm.mode[DISP_ID]->vdisplay) / (GLfloat)(drm.mode[DISP_ID]->hdisplay);
497 ESMatrix projection;
498 esMatrixLoadIdentity(&projection);
499 esFrustum(&projection, -2.8f, +2.8f, -2.8f * aspect, +2.8f * aspect, 6.0f, 10.0f);
501 ESMatrix modelviewprojection;
502 esMatrixLoadIdentity(&modelviewprojection);
503 esMatrixMultiply(&modelviewprojection, &modelview, &projection);
505 float normal[9];
506 normal[0] = modelview.m[0][0];
507 normal[1] = modelview.m[0][1];
508 normal[2] = modelview.m[0][2];
509 normal[3] = modelview.m[1][0];
510 normal[4] = modelview.m[1][1];
511 normal[5] = modelview.m[1][2];
512 normal[6] = modelview.m[2][0];
513 normal[7] = modelview.m[2][1];
514 normal[8] = modelview.m[2][2];
516 glUniformMatrix4fv(gl.modelviewmatrix, 1, GL_FALSE, &modelview.m[0][0]);
517 glUniformMatrix4fv(gl.modelviewprojectionmatrix, 1, GL_FALSE, &modelviewprojection.m[0][0]);
518 glUniformMatrix3fv(gl.normalmatrix, 1, GL_FALSE, normal);
520 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
521 glDrawArrays(GL_TRIANGLE_STRIP, 4, 4);
522 glDrawArrays(GL_TRIANGLE_STRIP, 8, 4);
523 glDrawArrays(GL_TRIANGLE_STRIP, 12, 4);
524 glDrawArrays(GL_TRIANGLE_STRIP, 16, 4);
525 glDrawArrays(GL_TRIANGLE_STRIP, 20, 4);
526 }
528 static void
529 drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
530 {
531 struct drm_fb *fb = data;
532 struct gbm_device *gbm = gbm_bo_get_device(bo);
534 if (fb->fb_id)
535 drmModeRmFB(drm.fd, fb->fb_id);
537 free(fb);
538 }
540 static struct drm_fb * drm_fb_get_from_bo(struct gbm_bo *bo)
541 {
542 struct drm_fb *fb = gbm_bo_get_user_data(bo);
543 uint32_t width, height, stride, handle;
544 int ret;
546 if (fb)
547 return fb;
549 fb = calloc(1, sizeof *fb);
550 fb->bo = bo;
552 width = gbm_bo_get_width(bo);
553 height = gbm_bo_get_height(bo);
554 stride = gbm_bo_get_stride(bo);
555 handle = gbm_bo_get_handle(bo).u32;
557 ret = drmModeAddFB(drm.fd, width, height, 24, 32, stride, handle, &fb->fb_id);
558 if (ret) {
559 printf("failed to create fb: %s\n", strerror(errno));
560 free(fb);
561 return NULL;
562 }
564 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
566 return fb;
567 }
569 static void page_flip_handler(int fd, unsigned int frame,
570 unsigned int sec, unsigned int usec, void *data)
571 {
572 int *waiting_for_flip = data;
573 *waiting_for_flip = 0;
574 }
576 void print_usage()
577 {
578 printf("Usage : kmscube <options>\n");
579 printf("\t-h : Help\n");
580 printf("\t-a : Enable all displays\n");
581 printf("\t-c <id> : Display using connector_id [if not specified, use the first connected connector]\n");
582 }
584 int main(int argc, char *argv[])
585 {
586 fd_set fds;
587 drmEventContext evctx = {
588 .version = DRM_EVENT_CONTEXT_VERSION,
589 .page_flip_handler = page_flip_handler,
590 };
591 struct gbm_bo *bo;
592 struct drm_fb *fb;
593 uint32_t i = 0;
594 int ret;
595 int opt;
597 while ((opt = getopt(argc, argv, "ahc:")) != -1) {
598 switch(opt) {
599 case 'a':
600 all_display = 1;
601 break;
603 case 'h':
604 print_usage();
605 return 0;
607 case 'c':
608 connector_id = atoi(optarg);
609 break;
611 default:
612 printf("Undefined option %s\n", argv[optind]);
613 print_usage();
614 return -1;
615 }
616 }
618 if (all_display) {
619 printf("### Enabling all displays\n");
620 connector_id = -1;
621 }
623 ret = init_drm();
624 if (ret) {
625 printf("failed to initialize DRM\n");
626 return ret;
627 }
628 printf("### Primary display => ConnectorId = %d, Resolution = %dx%d\n",
629 drm.connector_id[DISP_ID], drm.mode[DISP_ID]->hdisplay,
630 drm.mode[DISP_ID]->vdisplay);
632 FD_ZERO(&fds);
633 FD_SET(drm.fd, &fds);
635 ret = init_gbm();
636 if (ret) {
637 printf("failed to initialize GBM\n");
638 return ret;
639 }
641 ret = init_gl();
642 if (ret) {
643 printf("failed to initialize EGL\n");
644 return ret;
645 }
647 /* clear the color buffer */
648 glClearColor(0.5, 0.5, 0.5, 1.0);
649 glClear(GL_COLOR_BUFFER_BIT);
650 eglSwapBuffers(gl.display, gl.surface);
651 bo = gbm_surface_lock_front_buffer(gbm.surface);
652 fb = drm_fb_get_from_bo(bo);
654 /* set mode: */
655 if (all_display) {
656 for (i=0; i<drm.ndisp; i++) {
657 ret = drmModeSetCrtc(drm.fd, drm.crtc_id[i], fb->fb_id, 0, 0,
658 &drm.connector_id[i], 1, drm.mode[i]);
659 if (ret) {
660 printf("display %d failed to set mode: %s\n", i, strerror(errno));
661 return ret;
662 }
663 }
664 } else {
665 ret = drmModeSetCrtc(drm.fd, drm.crtc_id[DISP_ID], fb->fb_id,
666 0, 0, &drm.connector_id[DISP_ID], 1, drm.mode[DISP_ID]);
667 if (ret) {
668 printf("display %d failed to set mode: %s\n", DISP_ID, strerror(errno));
669 return ret;
670 }
671 }
673 while (1) {
674 struct gbm_bo *next_bo;
675 int waiting_for_flip = 1;
677 draw(i++);
679 eglSwapBuffers(gl.display, gl.surface);
680 next_bo = gbm_surface_lock_front_buffer(gbm.surface);
681 fb = drm_fb_get_from_bo(next_bo);
683 /*
684 * Here you could also update drm plane layers if you want
685 * hw composition
686 */
688 ret = drmModePageFlip(drm.fd, drm.crtc_id[DISP_ID], fb->fb_id,
689 DRM_MODE_PAGE_FLIP_EVENT, &waiting_for_flip);
690 if (ret) {
691 printf("failed to queue page flip: %s\n", strerror(errno));
692 return -1;
693 }
695 while (waiting_for_flip) {
696 ret = select(drm.fd + 1, &fds, NULL, NULL, NULL);
697 if (ret < 0) {
698 printf("select err: %s\n", strerror(errno));
699 return ret;
700 } else if (ret == 0) {
701 printf("select timeout!\n");
702 return -1;
703 } else if (FD_ISSET(0, &fds)) {
704 continue;
705 }
706 drmHandleEvent(drm.fd, &evctx);
707 }
709 /* release last buffer to render on again: */
710 gbm_surface_release_buffer(gbm.surface, bo);
711 bo = next_bo;
712 }
714 return ret;
715 }