2b01b6b4368a3c54db159a8a9f00ef3409f5049f
1 /*
2 * Copyright (c) 2012 Arvin Schnell <arvin.schnell@gmail.com>
3 * Copyright (c) 2012 Rob Clark <rob@ti.com>
4 * Copyright (c) 2015 Tomi Valkeinen <tomi.valkeinen@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 <chrono>
29 #include <cstdio>
30 #include <vector>
31 #include <memory>
32 #include <algorithm>
33 #include <poll.h>
35 #include <xf86drm.h>
36 #include <xf86drmMode.h>
37 #include <gbm.h>
39 #include "esUtil.h"
41 #include <kms++.h>
42 #include "test.h"
43 #include "opts.h"
45 using namespace kms;
46 using namespace std;
48 static bool s_verbose;
49 static int s_flip_pending;
50 static bool s_need_exit;
52 class GbmDevice
53 {
54 public:
55 GbmDevice(Card& card)
56 {
57 m_dev = gbm_create_device(card.fd());
58 FAIL_IF(!m_dev, "failed to create gbm device");
59 }
61 ~GbmDevice()
62 {
63 gbm_device_destroy(m_dev);
64 }
66 GbmDevice(const GbmDevice& other) = delete;
67 GbmDevice& operator=(const GbmDevice& other) = delete;
69 struct gbm_device* handle() const { return m_dev; }
71 private:
72 struct gbm_device* m_dev;
73 };
75 class GbmSurface
76 {
77 public:
78 GbmSurface(GbmDevice& gdev, int width, int height)
79 {
80 m_surface = gbm_surface_create(gdev.handle(), width, height,
81 GBM_FORMAT_XRGB8888,
82 GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
83 FAIL_IF(!m_surface, "failed to create gbm surface");
84 }
86 ~GbmSurface()
87 {
88 gbm_surface_destroy(m_surface);
89 }
91 GbmSurface(const GbmSurface& other) = delete;
92 GbmSurface& operator=(const GbmSurface& other) = delete;
94 bool has_free()
95 {
96 return gbm_surface_has_free_buffers(m_surface);
97 }
99 gbm_bo* lock_front_buffer()
100 {
101 return gbm_surface_lock_front_buffer(m_surface);
102 }
104 void release_buffer(gbm_bo *bo)
105 {
106 gbm_surface_release_buffer(m_surface, bo);
107 }
109 struct gbm_surface* handle() const { return m_surface; }
111 private:
112 struct gbm_surface* m_surface;
113 };
115 class EglState
116 {
117 public:
118 EglState(EGLNativeDisplayType display_id)
119 {
120 EGLBoolean b;
121 EGLint major, minor, n;
123 static const EGLint context_attribs[] = {
124 EGL_CONTEXT_CLIENT_VERSION, 2,
125 EGL_NONE
126 };
128 static const EGLint config_attribs[] = {
129 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
130 EGL_RED_SIZE, 8,
131 EGL_GREEN_SIZE, 8,
132 EGL_BLUE_SIZE, 8,
133 EGL_ALPHA_SIZE, 0,
134 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
135 EGL_NONE
136 };
138 m_display = eglGetDisplay(display_id);
139 FAIL_IF(!m_display, "failed to get egl display");
141 b = eglInitialize(m_display, &major, &minor);
142 FAIL_IF(!b, "failed to initialize");
144 if (s_verbose) {
145 printf("Using display %p with EGL version %d.%d\n", m_display, major, minor);
147 printf("EGL_VENDOR: %s\n", eglQueryString(m_display, EGL_VENDOR));
148 printf("EGL_VERSION: %s\n", eglQueryString(m_display, EGL_VERSION));
149 printf("EGL_EXTENSIONS: %s\n", eglQueryString(m_display, EGL_EXTENSIONS));
150 printf("EGL_CLIENT_APIS: %s\n", eglQueryString(m_display, EGL_CLIENT_APIS));
151 }
153 b = eglBindAPI(EGL_OPENGL_ES_API);
154 FAIL_IF(!b, "failed to bind api EGL_OPENGL_ES_API");
156 b = eglChooseConfig(m_display, config_attribs, &m_config, 1, &n);
157 FAIL_IF(!b || n != 1, "failed to choose config");
159 auto getconf = [this](EGLint a) { EGLint v = -1; eglGetConfigAttrib(m_display, m_config, a, &v); return v; };
161 if (s_verbose) {
162 printf("EGL Config %d: color buf %d/%d/%d/%d = %d, depth %d, stencil %d\n",
163 getconf(EGL_CONFIG_ID),
164 getconf(EGL_ALPHA_SIZE),
165 getconf(EGL_RED_SIZE),
166 getconf(EGL_GREEN_SIZE),
167 getconf(EGL_BLUE_SIZE),
168 getconf(EGL_BUFFER_SIZE),
169 getconf(EGL_DEPTH_SIZE),
170 getconf(EGL_STENCIL_SIZE));
171 }
173 m_context = eglCreateContext(m_display, m_config, EGL_NO_CONTEXT, context_attribs);
174 FAIL_IF(!m_context, "failed to create context");
176 eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, m_context);
177 }
179 ~EglState()
180 {
181 eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
182 eglTerminate(m_display);
183 }
185 EGLDisplay display() const { return m_display; }
186 EGLConfig config() const { return m_config; }
187 EGLContext context() const { return m_context; }
189 private:
190 EGLDisplay m_display;
191 EGLConfig m_config;
192 EGLContext m_context;
193 };
195 class GlScene
196 {
197 public:
198 GlScene()
199 {
200 GLuint vertex_shader, fragment_shader;
201 GLint ret;
203 #include "cube.h"
205 static const char *vertex_shader_source =
206 "uniform mat4 modelviewMatrix; \n"
207 "uniform mat4 modelviewprojectionMatrix;\n"
208 "uniform mat3 normalMatrix; \n"
209 " \n"
210 "attribute vec4 in_position; \n"
211 "attribute vec3 in_normal; \n"
212 "attribute vec4 in_color; \n"
213 "\n"
214 "vec4 lightSource = vec4(2.0, 2.0, 20.0, 0.0);\n"
215 " \n"
216 "varying vec4 vVaryingColor; \n"
217 " \n"
218 "void main() \n"
219 "{ \n"
220 " gl_Position = modelviewprojectionMatrix * in_position;\n"
221 " vec3 vEyeNormal = normalMatrix * in_normal;\n"
222 " vec4 vPosition4 = modelviewMatrix * in_position;\n"
223 " vec3 vPosition3 = vPosition4.xyz / vPosition4.w;\n"
224 " vec3 vLightDir = normalize(lightSource.xyz - vPosition3);\n"
225 " float diff = max(0.0, dot(vEyeNormal, vLightDir));\n"
226 " vVaryingColor = vec4(diff * in_color.rgb, 1.0);\n"
227 "} \n";
229 static const char *fragment_shader_source =
230 "precision mediump float; \n"
231 " \n"
232 "varying vec4 vVaryingColor; \n"
233 " \n"
234 "void main() \n"
235 "{ \n"
236 " gl_FragColor = vVaryingColor; \n"
237 "} \n";
240 if (s_verbose) {
241 printf("GL_VENDOR: %s\n", glGetString(GL_VENDOR));
242 printf("GL_VERSION: %s\n", glGetString(GL_VERSION));
243 printf("GL_RENDERER: %s\n", glGetString(GL_RENDERER));
244 printf("GL_EXTENSIONS: %s\n", glGetString(GL_EXTENSIONS));
245 }
247 vertex_shader = glCreateShader(GL_VERTEX_SHADER);
249 glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
250 glCompileShader(vertex_shader);
252 glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &ret);
253 FAIL_IF(!ret, "vertex shader compilation failed!");
255 fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
257 glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
258 glCompileShader(fragment_shader);
260 glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &ret);
261 FAIL_IF(!ret, "fragment shader compilation failed!");
263 GLuint program = glCreateProgram();
265 glAttachShader(program, vertex_shader);
266 glAttachShader(program, fragment_shader);
268 glBindAttribLocation(program, 0, "in_position");
269 glBindAttribLocation(program, 1, "in_normal");
270 glBindAttribLocation(program, 2, "in_color");
272 glLinkProgram(program);
274 glGetProgramiv(program, GL_LINK_STATUS, &ret);
275 FAIL_IF(!ret, "program linking failed!");
277 glUseProgram(program);
279 m_modelviewmatrix = glGetUniformLocation(program, "modelviewMatrix");
280 m_modelviewprojectionmatrix = glGetUniformLocation(program, "modelviewprojectionMatrix");
281 m_normalmatrix = glGetUniformLocation(program, "normalMatrix");
283 glEnable(GL_CULL_FACE);
285 GLintptr positionsoffset = 0;
286 GLintptr colorsoffset = sizeof(vVertices);
287 GLintptr normalsoffset = sizeof(vVertices) + sizeof(vColors);
288 GLuint vbo;
290 glGenBuffers(1, &vbo);
291 glBindBuffer(GL_ARRAY_BUFFER, vbo);
292 glBufferData(GL_ARRAY_BUFFER, sizeof(vVertices) + sizeof(vColors) + sizeof(vNormals), 0, GL_STATIC_DRAW);
293 glBufferSubData(GL_ARRAY_BUFFER, positionsoffset, sizeof(vVertices), &vVertices[0]);
294 glBufferSubData(GL_ARRAY_BUFFER, colorsoffset, sizeof(vColors), &vColors[0]);
295 glBufferSubData(GL_ARRAY_BUFFER, normalsoffset, sizeof(vNormals), &vNormals[0]);
296 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)positionsoffset);
297 glEnableVertexAttribArray(0);
298 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)normalsoffset);
299 glEnableVertexAttribArray(1);
300 glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)colorsoffset);
301 glEnableVertexAttribArray(2);
302 }
304 GlScene(const GlScene& other) = delete;
305 GlScene& operator=(const GlScene& other) = delete;
307 void set_viewport(uint32_t width, uint32_t height)
308 {
309 m_width = width;
310 m_height = height;
311 }
313 void draw(uint32_t framenum)
314 {
315 glViewport(0, 0, m_width, m_height);
317 glClearColor(0.5, 0.5, 0.5, 1.0);
318 glClear(GL_COLOR_BUFFER_BIT);
320 ESMatrix modelview;
322 esMatrixLoadIdentity(&modelview);
323 esTranslate(&modelview, 0.0f, 0.0f, -8.0f);
324 esRotate(&modelview, 45.0f + (0.75f * framenum), 1.0f, 0.0f, 0.0f);
325 esRotate(&modelview, 45.0f - (0.5f * framenum), 0.0f, 1.0f, 0.0f);
326 esRotate(&modelview, 10.0f + (0.45f * framenum), 0.0f, 0.0f, 1.0f);
328 GLfloat aspect = (float)m_height / m_width;
330 ESMatrix projection;
331 esMatrixLoadIdentity(&projection);
332 esFrustum(&projection, -2.8f, +2.8f, -2.8f * aspect, +2.8f * aspect, 6.0f, 10.0f);
334 ESMatrix modelviewprojection;
335 esMatrixLoadIdentity(&modelviewprojection);
336 esMatrixMultiply(&modelviewprojection, &modelview, &projection);
338 float normal[9];
339 normal[0] = modelview.m[0][0];
340 normal[1] = modelview.m[0][1];
341 normal[2] = modelview.m[0][2];
342 normal[3] = modelview.m[1][0];
343 normal[4] = modelview.m[1][1];
344 normal[5] = modelview.m[1][2];
345 normal[6] = modelview.m[2][0];
346 normal[7] = modelview.m[2][1];
347 normal[8] = modelview.m[2][2];
349 glUniformMatrix4fv(m_modelviewmatrix, 1, GL_FALSE, &modelview.m[0][0]);
350 glUniformMatrix4fv(m_modelviewprojectionmatrix, 1, GL_FALSE, &modelviewprojection.m[0][0]);
351 glUniformMatrix3fv(m_normalmatrix, 1, GL_FALSE, normal);
353 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
354 glDrawArrays(GL_TRIANGLE_STRIP, 4, 4);
355 glDrawArrays(GL_TRIANGLE_STRIP, 8, 4);
356 glDrawArrays(GL_TRIANGLE_STRIP, 12, 4);
357 glDrawArrays(GL_TRIANGLE_STRIP, 16, 4);
358 glDrawArrays(GL_TRIANGLE_STRIP, 20, 4);
359 }
361 private:
362 GLint m_modelviewmatrix, m_modelviewprojectionmatrix, m_normalmatrix;
364 uint32_t m_width;
365 uint32_t m_height;
366 };
368 class GbmEglSurface
369 {
370 public:
371 GbmEglSurface(Card& card, GbmDevice& gdev, const EglState& egl, int width, int height)
372 : card(card), gdev(gdev), egl(egl), m_width(width), m_height(height),
373 bo_prev(0), bo_next(0)
374 {
375 gsurface = unique_ptr<GbmSurface>(new GbmSurface(gdev, width, height));
376 esurface = eglCreateWindowSurface(egl.display(), egl.config(), gsurface->handle(), NULL);
377 FAIL_IF(esurface == EGL_NO_SURFACE, "failed to create egl surface");
378 }
380 ~GbmEglSurface()
381 {
382 if (bo_next)
383 gsurface->release_buffer(bo_next);
384 eglDestroySurface(egl.display(), esurface);
385 }
387 void make_current()
388 {
389 FAIL_IF(!gsurface->has_free(), "No free buffers");
391 eglMakeCurrent(egl.display(), esurface, esurface, egl.context());
392 }
394 void swap_buffers()
395 {
396 eglSwapBuffers(egl.display(), esurface);
397 }
399 static void drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
400 {
401 auto fb = reinterpret_cast<Framebuffer*>(data);
402 delete fb;
403 }
405 static Framebuffer* drm_fb_get_from_bo(struct gbm_bo *bo, Card& card)
406 {
407 auto fb = reinterpret_cast<Framebuffer*>(gbm_bo_get_user_data(bo));
408 if (fb)
409 return fb;
411 uint32_t width = gbm_bo_get_width(bo);
412 uint32_t height = gbm_bo_get_height(bo);
413 uint32_t stride = gbm_bo_get_stride(bo);
414 uint32_t handle = gbm_bo_get_handle(bo).u32;
416 fb = new ExtFramebuffer(card, width, height, 24, 32, stride, handle);
418 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
420 return fb;
421 }
423 struct Framebuffer* lock_next()
424 {
425 bo_prev = bo_next;
426 bo_next = gsurface->lock_front_buffer();
427 FAIL_IF(!bo_next, "could not lock gbm buffer");
428 return drm_fb_get_from_bo(bo_next, card);
429 }
431 void free_prev()
432 {
433 if (bo_prev) {
434 gsurface->release_buffer(bo_prev);
435 bo_prev = 0;
436 }
437 }
439 uint32_t width() const { return m_width; }
440 uint32_t height() const { return m_height; }
442 private:
443 Card& card;
444 GbmDevice& gdev;
445 const EglState& egl;
447 unique_ptr<GbmSurface> gsurface;
448 EGLSurface esurface;
450 int m_width;
451 int m_height;
453 struct gbm_bo* bo_prev;
454 struct gbm_bo* bo_next;
455 };
457 class NullEglSurface
458 {
459 public:
460 NullEglSurface(const EglState& egl)
461 : egl(egl)
462 {
463 esurface = eglCreateWindowSurface(egl.display(), egl.config(), 0, NULL);
464 FAIL_IF(esurface == EGL_NO_SURFACE, "failed to create egl surface");
465 }
467 ~NullEglSurface()
468 {
469 eglDestroySurface(egl.display(), esurface);
470 }
472 void make_current()
473 {
474 eglMakeCurrent(egl.display(), esurface, esurface, egl.context());
475 }
477 void swap_buffers()
478 {
479 eglSwapBuffers(egl.display(), esurface);
480 }
482 private:
483 const EglState& egl;
485 EGLSurface esurface;
486 };
488 class OutputHandler : private PageFlipHandlerBase
489 {
490 public:
491 OutputHandler(Card& card, GbmDevice& gdev, const EglState& egl, Connector* connector, Crtc* crtc, Videomode& mode, Plane* plane, float rotation_mult)
492 : m_frame_num(0), m_connector(connector), m_crtc(crtc), m_plane(plane), m_mode(mode),
493 m_rotation_mult(rotation_mult)
494 {
495 m_surface1 = unique_ptr<GbmEglSurface>(new GbmEglSurface(card, gdev, egl, mode.hdisplay, mode.vdisplay));
496 m_scene1 = unique_ptr<GlScene>(new GlScene());
497 m_scene1->set_viewport(m_surface1->width(), m_surface1->height());
499 if (m_plane) {
500 m_surface2 = unique_ptr<GbmEglSurface>(new GbmEglSurface(card, gdev, egl, 400, 400));
501 m_scene2 = unique_ptr<GlScene>(new GlScene());
502 m_scene2->set_viewport(m_surface2->width(), m_surface2->height());
503 }
504 }
506 OutputHandler(const OutputHandler& other) = delete;
507 OutputHandler& operator=(const OutputHandler& other) = delete;
509 void setup()
510 {
511 int ret;
513 m_surface1->make_current();
514 m_surface1->swap_buffers();
515 struct Framebuffer* fb = m_surface1->lock_next();
517 struct Framebuffer* planefb = 0;
519 if (m_plane) {
520 m_surface2->make_current();
521 m_surface2->swap_buffers();
522 planefb = m_surface2->lock_next();
523 }
526 ret = m_crtc->set_mode(m_connector, *fb, m_mode);
527 FAIL_IF(ret, "failed to set mode");
529 if (m_crtc->card().has_atomic()) {
530 Plane* root_plane = 0;
531 for (Plane* p : m_crtc->get_possible_planes()) {
532 if (p->crtc_id() == m_crtc->id()) {
533 root_plane = p;
534 break;
535 }
536 }
538 FAIL_IF(!root_plane, "No primary plane for crtc %d", m_crtc->id());
540 m_root_plane = root_plane;
541 }
543 if (m_plane) {
544 ret = m_crtc->set_plane(m_plane, *planefb,
545 0, 0, planefb->width(), planefb->height(),
546 0, 0, planefb->width(), planefb->height());
547 FAIL_IF(ret, "failed to set plane");
548 }
549 }
551 void start_flipping()
552 {
553 m_t1 = chrono::steady_clock::now();
554 queue_next();
555 }
557 private:
558 void handle_page_flip(uint32_t frame, double time)
559 {
560 ++m_frame_num;
562 if (m_frame_num % 100 == 0) {
563 auto t2 = chrono::steady_clock::now();
564 chrono::duration<float> fsec = t2 - m_t1;
565 printf("fps: %f\n", 100.0 / fsec.count());
566 m_t1 = t2;
567 }
569 s_flip_pending--;
571 m_surface1->free_prev();
572 if (m_plane)
573 m_surface2->free_prev();
575 if (s_need_exit)
576 return;
578 queue_next();
579 }
581 void queue_next()
582 {
583 m_surface1->make_current();
584 m_scene1->draw(m_frame_num * m_rotation_mult);
585 m_surface1->swap_buffers();
586 struct Framebuffer* fb = m_surface1->lock_next();
588 struct Framebuffer* planefb = 0;
590 if (m_plane) {
591 m_surface2->make_current();
592 m_scene2->draw(m_frame_num * m_rotation_mult * 2);
593 m_surface2->swap_buffers();
594 planefb = m_surface2->lock_next();
595 }
597 if (m_crtc->card().has_atomic()) {
598 int r;
600 AtomicReq req(m_crtc->card());
602 req.add(m_root_plane, "FB_ID", fb->id());
603 if (m_plane)
604 req.add(m_plane, "FB_ID", planefb->id());
606 r = req.test();
607 FAIL_IF(r, "atomic test failed");
609 r = req.commit(this);
610 FAIL_IF(r, "atomic commit failed");
611 } else {
612 int ret;
614 ret = m_crtc->page_flip(*fb, this);
615 FAIL_IF(ret, "failed to queue page flip");
617 if (m_plane) {
618 ret = m_crtc->set_plane(m_plane, *planefb,
619 0, 0, planefb->width(), planefb->height(),
620 0, 0, planefb->width(), planefb->height());
621 FAIL_IF(ret, "failed to set plane");
622 }
623 }
625 s_flip_pending++;
626 }
628 int m_frame_num;
629 chrono::steady_clock::time_point m_t1;
631 Connector* m_connector;
632 Crtc* m_crtc;
633 Plane* m_plane;
634 Videomode m_mode;
635 Plane* m_root_plane;
637 unique_ptr<GbmEglSurface> m_surface1;
638 unique_ptr<GbmEglSurface> m_surface2;
640 unique_ptr<GlScene> m_scene1;
641 unique_ptr<GlScene> m_scene2;
643 float m_rotation_mult;
644 };
646 static void main_gbm()
647 {
648 Card card;
650 GbmDevice gdev(card);
651 EglState egl(gdev.handle());
653 vector<unique_ptr<OutputHandler>> outputs;
654 vector<Plane*> used_planes;
656 float rot_mult = 1;
658 for (auto pipe : card.get_connected_pipelines()) {
659 auto connector = pipe.connector;
660 auto crtc = pipe.crtc;
661 auto mode = connector->get_default_mode();
663 Plane* plane = 0;
665 for (Plane* p : crtc->get_possible_planes()) {
666 if (find(used_planes.begin(), used_planes.end(), p) != used_planes.end())
667 continue;
669 if (p->plane_type() != PlaneType::Overlay)
670 continue;
672 plane = p;
673 break;
674 }
676 if (plane)
677 used_planes.push_back(plane);
679 auto out = new OutputHandler(card, gdev, egl, connector, crtc, mode, plane, rot_mult);
680 outputs.emplace_back(out);
682 rot_mult *= 1.33;
683 }
685 for (auto& out : outputs)
686 out->setup();
688 for (auto& out : outputs)
689 out->start_flipping();
691 struct pollfd fds[2] = { 0 };
692 fds[0].fd = 0;
693 fds[0].events = POLLIN;
694 fds[1].fd = card.fd();
695 fds[1].events = POLLIN;
697 while (!s_need_exit || s_flip_pending) {
698 int r = poll(fds, ARRAY_SIZE(fds), -1);
699 FAIL_IF(r < 0, "poll error %d", r);
701 if (fds[0].revents)
702 s_need_exit = true;
704 if (fds[1].revents)
705 card.call_page_flip_handlers();
706 }
707 }
709 static void main_egl()
710 {
711 EglState egl(EGL_DEFAULT_DISPLAY);
712 NullEglSurface surface(egl);
713 GlScene scene;
715 scene.set_viewport(600, 600);
717 int framenum = 0;
719 struct pollfd fds[1] = { 0 };
720 fds[0].fd = 0;
721 fds[0].events = POLLIN;
723 while (true) {
724 int r = poll(fds, ARRAY_SIZE(fds), 0);
725 ASSERT(r >= 0);
727 if (fds[0].revents)
728 break;
730 surface.make_current();
731 scene.draw(framenum++);
732 surface.swap_buffers();
733 }
734 }
736 int main(int argc, char *argv[])
737 {
738 OptionSet optionset = {
739 Option("v|verbose",
740 [&]()
741 {
742 s_verbose = true;
743 }),
744 };
746 optionset.parse(argc, argv);
748 int mode;
750 if (optionset.params().size() == 0) {
751 mode = 0;
752 } else {
753 const string m = optionset.params().front();
755 if (m == "gbm")
756 mode = 0;
757 else if (m == "null")
758 mode = 1;
759 else {
760 printf("Unknown mode %s\n", m.c_str());
761 return -1;
762 }
763 }
765 switch (mode) {
766 case 0:
767 main_gbm();
768 break;
770 case 1:
771 main_egl();
772 break;
773 }
775 return 0;
776 }