1902970a52bbaa9e46a6db8473bb1f0c0179f43f
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 static bool s_support_planes;
54 class GbmDevice
55 {
56 public:
57 GbmDevice(Card& card)
58 {
59 m_dev = gbm_create_device(card.fd());
60 FAIL_IF(!m_dev, "failed to create gbm device");
61 }
63 ~GbmDevice()
64 {
65 gbm_device_destroy(m_dev);
66 }
68 GbmDevice(const GbmDevice& other) = delete;
69 GbmDevice& operator=(const GbmDevice& other) = delete;
71 struct gbm_device* handle() const { return m_dev; }
73 private:
74 struct gbm_device* m_dev;
75 };
77 class GbmSurface
78 {
79 public:
80 GbmSurface(GbmDevice& gdev, int width, int height)
81 {
82 m_surface = gbm_surface_create(gdev.handle(), width, height,
83 GBM_FORMAT_XRGB8888,
84 GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
85 FAIL_IF(!m_surface, "failed to create gbm surface");
86 }
88 ~GbmSurface()
89 {
90 gbm_surface_destroy(m_surface);
91 }
93 GbmSurface(const GbmSurface& other) = delete;
94 GbmSurface& operator=(const GbmSurface& other) = delete;
96 bool has_free()
97 {
98 return gbm_surface_has_free_buffers(m_surface);
99 }
101 gbm_bo* lock_front_buffer()
102 {
103 return gbm_surface_lock_front_buffer(m_surface);
104 }
106 void release_buffer(gbm_bo *bo)
107 {
108 gbm_surface_release_buffer(m_surface, bo);
109 }
111 struct gbm_surface* handle() const { return m_surface; }
113 private:
114 struct gbm_surface* m_surface;
115 };
117 class EglState
118 {
119 public:
120 EglState(EGLNativeDisplayType display_id)
121 {
122 EGLBoolean b;
123 EGLint major, minor, n;
125 static const EGLint context_attribs[] = {
126 EGL_CONTEXT_CLIENT_VERSION, 2,
127 EGL_NONE
128 };
130 static const EGLint config_attribs[] = {
131 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
132 EGL_RED_SIZE, 8,
133 EGL_GREEN_SIZE, 8,
134 EGL_BLUE_SIZE, 8,
135 EGL_ALPHA_SIZE, 0,
136 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
137 EGL_NONE
138 };
140 m_display = eglGetDisplay(display_id);
141 FAIL_IF(!m_display, "failed to get egl display");
143 b = eglInitialize(m_display, &major, &minor);
144 FAIL_IF(!b, "failed to initialize");
146 if (s_verbose) {
147 printf("Using display %p with EGL version %d.%d\n", m_display, major, minor);
149 printf("EGL_VENDOR: %s\n", eglQueryString(m_display, EGL_VENDOR));
150 printf("EGL_VERSION: %s\n", eglQueryString(m_display, EGL_VERSION));
151 printf("EGL_EXTENSIONS: %s\n", eglQueryString(m_display, EGL_EXTENSIONS));
152 printf("EGL_CLIENT_APIS: %s\n", eglQueryString(m_display, EGL_CLIENT_APIS));
153 }
155 b = eglBindAPI(EGL_OPENGL_ES_API);
156 FAIL_IF(!b, "failed to bind api EGL_OPENGL_ES_API");
158 b = eglChooseConfig(m_display, config_attribs, &m_config, 1, &n);
159 FAIL_IF(!b || n != 1, "failed to choose config");
161 auto getconf = [this](EGLint a) { EGLint v = -1; eglGetConfigAttrib(m_display, m_config, a, &v); return v; };
163 if (s_verbose) {
164 printf("EGL Config %d: color buf %d/%d/%d/%d = %d, depth %d, stencil %d\n",
165 getconf(EGL_CONFIG_ID),
166 getconf(EGL_ALPHA_SIZE),
167 getconf(EGL_RED_SIZE),
168 getconf(EGL_GREEN_SIZE),
169 getconf(EGL_BLUE_SIZE),
170 getconf(EGL_BUFFER_SIZE),
171 getconf(EGL_DEPTH_SIZE),
172 getconf(EGL_STENCIL_SIZE));
173 }
175 m_context = eglCreateContext(m_display, m_config, EGL_NO_CONTEXT, context_attribs);
176 FAIL_IF(!m_context, "failed to create context");
178 eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, m_context);
179 }
181 ~EglState()
182 {
183 eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
184 eglTerminate(m_display);
185 }
187 EGLDisplay display() const { return m_display; }
188 EGLConfig config() const { return m_config; }
189 EGLContext context() const { return m_context; }
191 private:
192 EGLDisplay m_display;
193 EGLConfig m_config;
194 EGLContext m_context;
195 };
197 class GlScene
198 {
199 public:
200 GlScene()
201 {
202 GLuint vertex_shader, fragment_shader;
203 GLint ret;
205 #include "cube.h"
207 static const char *vertex_shader_source =
208 "uniform mat4 modelviewMatrix; \n"
209 "uniform mat4 modelviewprojectionMatrix;\n"
210 "uniform mat3 normalMatrix; \n"
211 " \n"
212 "attribute vec4 in_position; \n"
213 "attribute vec3 in_normal; \n"
214 "attribute vec4 in_color; \n"
215 "\n"
216 "vec4 lightSource = vec4(2.0, 2.0, 20.0, 0.0);\n"
217 " \n"
218 "varying vec4 vVaryingColor; \n"
219 " \n"
220 "void main() \n"
221 "{ \n"
222 " gl_Position = modelviewprojectionMatrix * in_position;\n"
223 " vec3 vEyeNormal = normalMatrix * in_normal;\n"
224 " vec4 vPosition4 = modelviewMatrix * in_position;\n"
225 " vec3 vPosition3 = vPosition4.xyz / vPosition4.w;\n"
226 " vec3 vLightDir = normalize(lightSource.xyz - vPosition3);\n"
227 " float diff = max(0.0, dot(vEyeNormal, vLightDir));\n"
228 " vVaryingColor = vec4(diff * in_color.rgb, 1.0);\n"
229 "} \n";
231 static const char *fragment_shader_source =
232 "precision mediump float; \n"
233 " \n"
234 "varying vec4 vVaryingColor; \n"
235 " \n"
236 "void main() \n"
237 "{ \n"
238 " gl_FragColor = vVaryingColor; \n"
239 "} \n";
242 if (s_verbose) {
243 printf("GL_VENDOR: %s\n", glGetString(GL_VENDOR));
244 printf("GL_VERSION: %s\n", glGetString(GL_VERSION));
245 printf("GL_RENDERER: %s\n", glGetString(GL_RENDERER));
246 printf("GL_EXTENSIONS: %s\n", glGetString(GL_EXTENSIONS));
247 }
249 vertex_shader = glCreateShader(GL_VERTEX_SHADER);
251 glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
252 glCompileShader(vertex_shader);
254 glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &ret);
255 FAIL_IF(!ret, "vertex shader compilation failed!");
257 fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
259 glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
260 glCompileShader(fragment_shader);
262 glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &ret);
263 FAIL_IF(!ret, "fragment shader compilation failed!");
265 GLuint program = glCreateProgram();
267 glAttachShader(program, vertex_shader);
268 glAttachShader(program, fragment_shader);
270 glBindAttribLocation(program, 0, "in_position");
271 glBindAttribLocation(program, 1, "in_normal");
272 glBindAttribLocation(program, 2, "in_color");
274 glLinkProgram(program);
276 glGetProgramiv(program, GL_LINK_STATUS, &ret);
277 FAIL_IF(!ret, "program linking failed!");
279 glUseProgram(program);
281 m_modelviewmatrix = glGetUniformLocation(program, "modelviewMatrix");
282 m_modelviewprojectionmatrix = glGetUniformLocation(program, "modelviewprojectionMatrix");
283 m_normalmatrix = glGetUniformLocation(program, "normalMatrix");
285 glEnable(GL_CULL_FACE);
287 GLintptr positionsoffset = 0;
288 GLintptr colorsoffset = sizeof(vVertices);
289 GLintptr normalsoffset = sizeof(vVertices) + sizeof(vColors);
290 GLuint vbo;
292 glGenBuffers(1, &vbo);
293 glBindBuffer(GL_ARRAY_BUFFER, vbo);
294 glBufferData(GL_ARRAY_BUFFER, sizeof(vVertices) + sizeof(vColors) + sizeof(vNormals), 0, GL_STATIC_DRAW);
295 glBufferSubData(GL_ARRAY_BUFFER, positionsoffset, sizeof(vVertices), &vVertices[0]);
296 glBufferSubData(GL_ARRAY_BUFFER, colorsoffset, sizeof(vColors), &vColors[0]);
297 glBufferSubData(GL_ARRAY_BUFFER, normalsoffset, sizeof(vNormals), &vNormals[0]);
298 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)positionsoffset);
299 glEnableVertexAttribArray(0);
300 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)normalsoffset);
301 glEnableVertexAttribArray(1);
302 glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)colorsoffset);
303 glEnableVertexAttribArray(2);
304 }
306 GlScene(const GlScene& other) = delete;
307 GlScene& operator=(const GlScene& other) = delete;
309 void set_viewport(uint32_t width, uint32_t height)
310 {
311 m_width = width;
312 m_height = height;
313 }
315 void draw(uint32_t framenum)
316 {
317 glViewport(0, 0, m_width, m_height);
319 glClearColor(0.5, 0.5, 0.5, 1.0);
320 glClear(GL_COLOR_BUFFER_BIT);
322 ESMatrix modelview;
324 esMatrixLoadIdentity(&modelview);
325 esTranslate(&modelview, 0.0f, 0.0f, -8.0f);
326 esRotate(&modelview, 45.0f + (0.75f * framenum), 1.0f, 0.0f, 0.0f);
327 esRotate(&modelview, 45.0f - (0.5f * framenum), 0.0f, 1.0f, 0.0f);
328 esRotate(&modelview, 10.0f + (0.45f * framenum), 0.0f, 0.0f, 1.0f);
330 GLfloat aspect = (float)m_height / m_width;
332 ESMatrix projection;
333 esMatrixLoadIdentity(&projection);
334 esFrustum(&projection, -2.8f, +2.8f, -2.8f * aspect, +2.8f * aspect, 6.0f, 10.0f);
336 ESMatrix modelviewprojection;
337 esMatrixLoadIdentity(&modelviewprojection);
338 esMatrixMultiply(&modelviewprojection, &modelview, &projection);
340 float normal[9];
341 normal[0] = modelview.m[0][0];
342 normal[1] = modelview.m[0][1];
343 normal[2] = modelview.m[0][2];
344 normal[3] = modelview.m[1][0];
345 normal[4] = modelview.m[1][1];
346 normal[5] = modelview.m[1][2];
347 normal[6] = modelview.m[2][0];
348 normal[7] = modelview.m[2][1];
349 normal[8] = modelview.m[2][2];
351 glUniformMatrix4fv(m_modelviewmatrix, 1, GL_FALSE, &modelview.m[0][0]);
352 glUniformMatrix4fv(m_modelviewprojectionmatrix, 1, GL_FALSE, &modelviewprojection.m[0][0]);
353 glUniformMatrix3fv(m_normalmatrix, 1, GL_FALSE, normal);
355 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
356 glDrawArrays(GL_TRIANGLE_STRIP, 4, 4);
357 glDrawArrays(GL_TRIANGLE_STRIP, 8, 4);
358 glDrawArrays(GL_TRIANGLE_STRIP, 12, 4);
359 glDrawArrays(GL_TRIANGLE_STRIP, 16, 4);
360 glDrawArrays(GL_TRIANGLE_STRIP, 20, 4);
361 }
363 private:
364 GLint m_modelviewmatrix, m_modelviewprojectionmatrix, m_normalmatrix;
366 uint32_t m_width;
367 uint32_t m_height;
368 };
370 class GbmEglSurface
371 {
372 public:
373 GbmEglSurface(Card& card, GbmDevice& gdev, const EglState& egl, int width, int height)
374 : card(card), gdev(gdev), egl(egl), m_width(width), m_height(height),
375 bo_prev(0), bo_next(0)
376 {
377 gsurface = unique_ptr<GbmSurface>(new GbmSurface(gdev, width, height));
378 esurface = eglCreateWindowSurface(egl.display(), egl.config(), gsurface->handle(), NULL);
379 FAIL_IF(esurface == EGL_NO_SURFACE, "failed to create egl surface");
380 }
382 ~GbmEglSurface()
383 {
384 if (bo_next)
385 gsurface->release_buffer(bo_next);
386 eglDestroySurface(egl.display(), esurface);
387 }
389 void make_current()
390 {
391 FAIL_IF(!gsurface->has_free(), "No free buffers");
393 eglMakeCurrent(egl.display(), esurface, esurface, egl.context());
394 }
396 void swap_buffers()
397 {
398 eglSwapBuffers(egl.display(), esurface);
399 }
401 static void drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
402 {
403 auto fb = reinterpret_cast<Framebuffer*>(data);
404 delete fb;
405 }
407 static Framebuffer* drm_fb_get_from_bo(struct gbm_bo *bo, Card& card)
408 {
409 auto fb = reinterpret_cast<Framebuffer*>(gbm_bo_get_user_data(bo));
410 if (fb)
411 return fb;
413 uint32_t width = gbm_bo_get_width(bo);
414 uint32_t height = gbm_bo_get_height(bo);
415 uint32_t stride = gbm_bo_get_stride(bo);
416 uint32_t handle = gbm_bo_get_handle(bo).u32;
418 fb = new ExtFramebuffer(card, width, height, 24, 32, stride, handle);
420 gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
422 return fb;
423 }
425 struct Framebuffer* lock_next()
426 {
427 bo_prev = bo_next;
428 bo_next = gsurface->lock_front_buffer();
429 FAIL_IF(!bo_next, "could not lock gbm buffer");
430 return drm_fb_get_from_bo(bo_next, card);
431 }
433 void free_prev()
434 {
435 if (bo_prev) {
436 gsurface->release_buffer(bo_prev);
437 bo_prev = 0;
438 }
439 }
441 uint32_t width() const { return m_width; }
442 uint32_t height() const { return m_height; }
444 private:
445 Card& card;
446 GbmDevice& gdev;
447 const EglState& egl;
449 unique_ptr<GbmSurface> gsurface;
450 EGLSurface esurface;
452 int m_width;
453 int m_height;
455 struct gbm_bo* bo_prev;
456 struct gbm_bo* bo_next;
457 };
459 class NullEglSurface
460 {
461 public:
462 NullEglSurface(const EglState& egl)
463 : egl(egl)
464 {
465 esurface = eglCreateWindowSurface(egl.display(), egl.config(), 0, NULL);
466 FAIL_IF(esurface == EGL_NO_SURFACE, "failed to create egl surface");
467 }
469 ~NullEglSurface()
470 {
471 eglDestroySurface(egl.display(), esurface);
472 }
474 void make_current()
475 {
476 eglMakeCurrent(egl.display(), esurface, esurface, egl.context());
477 }
479 void swap_buffers()
480 {
481 eglSwapBuffers(egl.display(), esurface);
482 }
484 private:
485 const EglState& egl;
487 EGLSurface esurface;
488 };
490 class OutputHandler : private PageFlipHandlerBase
491 {
492 public:
493 OutputHandler(Card& card, GbmDevice& gdev, const EglState& egl, Connector* connector, Crtc* crtc, Videomode& mode, Plane* plane, float rotation_mult)
494 : m_frame_num(0), m_connector(connector), m_crtc(crtc), m_plane(plane), m_mode(mode),
495 m_rotation_mult(rotation_mult)
496 {
497 m_surface1 = unique_ptr<GbmEglSurface>(new GbmEglSurface(card, gdev, egl, mode.hdisplay, mode.vdisplay));
498 m_scene1 = unique_ptr<GlScene>(new GlScene());
499 m_scene1->set_viewport(m_surface1->width(), m_surface1->height());
501 if (m_plane) {
502 m_surface2 = unique_ptr<GbmEglSurface>(new GbmEglSurface(card, gdev, egl, 400, 400));
503 m_scene2 = unique_ptr<GlScene>(new GlScene());
504 m_scene2->set_viewport(m_surface2->width(), m_surface2->height());
505 }
506 }
508 OutputHandler(const OutputHandler& other) = delete;
509 OutputHandler& operator=(const OutputHandler& other) = delete;
511 void setup()
512 {
513 int ret;
515 m_surface1->make_current();
516 m_surface1->swap_buffers();
517 struct Framebuffer* fb = m_surface1->lock_next();
519 struct Framebuffer* planefb = 0;
521 if (m_plane) {
522 m_surface2->make_current();
523 m_surface2->swap_buffers();
524 planefb = m_surface2->lock_next();
525 }
528 ret = m_crtc->set_mode(m_connector, *fb, m_mode);
529 FAIL_IF(ret, "failed to set mode");
531 if (m_crtc->card().has_atomic()) {
532 Plane* root_plane = 0;
533 for (Plane* p : m_crtc->get_possible_planes()) {
534 if (p->crtc_id() == m_crtc->id()) {
535 root_plane = p;
536 break;
537 }
538 }
540 FAIL_IF(!root_plane, "No primary plane for crtc %d", m_crtc->id());
542 m_root_plane = root_plane;
543 }
545 if (m_plane) {
546 ret = m_crtc->set_plane(m_plane, *planefb,
547 0, 0, planefb->width(), planefb->height(),
548 0, 0, planefb->width(), planefb->height());
549 FAIL_IF(ret, "failed to set plane");
550 }
551 }
553 void start_flipping()
554 {
555 m_t1 = chrono::steady_clock::now();
556 queue_next();
557 }
559 private:
560 void handle_page_flip(uint32_t frame, double time)
561 {
562 ++m_frame_num;
564 if (m_frame_num % 100 == 0) {
565 auto t2 = chrono::steady_clock::now();
566 chrono::duration<float> fsec = t2 - m_t1;
567 printf("fps: %f\n", 100.0 / fsec.count());
568 m_t1 = t2;
569 }
571 s_flip_pending--;
573 m_surface1->free_prev();
574 if (m_plane)
575 m_surface2->free_prev();
577 if (s_need_exit)
578 return;
580 queue_next();
581 }
583 void queue_next()
584 {
585 m_surface1->make_current();
586 m_scene1->draw(m_frame_num * m_rotation_mult);
587 m_surface1->swap_buffers();
588 struct Framebuffer* fb = m_surface1->lock_next();
590 struct Framebuffer* planefb = 0;
592 if (m_plane) {
593 m_surface2->make_current();
594 m_scene2->draw(m_frame_num * m_rotation_mult * 2);
595 m_surface2->swap_buffers();
596 planefb = m_surface2->lock_next();
597 }
599 if (m_crtc->card().has_atomic()) {
600 int r;
602 AtomicReq req(m_crtc->card());
604 req.add(m_root_plane, "FB_ID", fb->id());
605 if (m_plane)
606 req.add(m_plane, "FB_ID", planefb->id());
608 r = req.test();
609 FAIL_IF(r, "atomic test failed");
611 r = req.commit(this);
612 FAIL_IF(r, "atomic commit failed");
613 } else {
614 int ret;
616 ret = m_crtc->page_flip(*fb, this);
617 FAIL_IF(ret, "failed to queue page flip");
619 if (m_plane) {
620 ret = m_crtc->set_plane(m_plane, *planefb,
621 0, 0, planefb->width(), planefb->height(),
622 0, 0, planefb->width(), planefb->height());
623 FAIL_IF(ret, "failed to set plane");
624 }
625 }
627 s_flip_pending++;
628 }
630 int m_frame_num;
631 chrono::steady_clock::time_point m_t1;
633 Connector* m_connector;
634 Crtc* m_crtc;
635 Plane* m_plane;
636 Videomode m_mode;
637 Plane* m_root_plane;
639 unique_ptr<GbmEglSurface> m_surface1;
640 unique_ptr<GbmEglSurface> m_surface2;
642 unique_ptr<GlScene> m_scene1;
643 unique_ptr<GlScene> m_scene2;
645 float m_rotation_mult;
646 };
648 static void main_gbm()
649 {
650 Card card;
652 GbmDevice gdev(card);
653 EglState egl(gdev.handle());
655 vector<unique_ptr<OutputHandler>> outputs;
656 vector<Plane*> used_planes;
658 float rot_mult = 1;
660 for (auto pipe : card.get_connected_pipelines()) {
661 auto connector = pipe.connector;
662 auto crtc = pipe.crtc;
663 auto mode = connector->get_default_mode();
665 Plane* plane = 0;
667 if (s_support_planes) {
668 for (Plane* p : crtc->get_possible_planes()) {
669 if (find(used_planes.begin(), used_planes.end(), p) != used_planes.end())
670 continue;
672 if (p->plane_type() != PlaneType::Overlay)
673 continue;
675 plane = p;
676 break;
677 }
678 }
680 if (plane)
681 used_planes.push_back(plane);
683 auto out = new OutputHandler(card, gdev, egl, connector, crtc, mode, plane, rot_mult);
684 outputs.emplace_back(out);
686 rot_mult *= 1.33;
687 }
689 for (auto& out : outputs)
690 out->setup();
692 for (auto& out : outputs)
693 out->start_flipping();
695 struct pollfd fds[2] = { 0 };
696 fds[0].fd = 0;
697 fds[0].events = POLLIN;
698 fds[1].fd = card.fd();
699 fds[1].events = POLLIN;
701 while (!s_need_exit || s_flip_pending) {
702 int r = poll(fds, ARRAY_SIZE(fds), -1);
703 FAIL_IF(r < 0, "poll error %d", r);
705 if (fds[0].revents)
706 s_need_exit = true;
708 if (fds[1].revents)
709 card.call_page_flip_handlers();
710 }
711 }
713 static void main_egl()
714 {
715 EglState egl(EGL_DEFAULT_DISPLAY);
716 NullEglSurface surface(egl);
717 GlScene scene;
719 scene.set_viewport(600, 600);
721 int framenum = 0;
723 struct pollfd fds[1] = { 0 };
724 fds[0].fd = 0;
725 fds[0].events = POLLIN;
727 while (true) {
728 int r = poll(fds, ARRAY_SIZE(fds), 0);
729 ASSERT(r >= 0);
731 if (fds[0].revents)
732 break;
734 surface.make_current();
735 scene.draw(framenum++);
736 surface.swap_buffers();
737 }
738 }
740 int main(int argc, char *argv[])
741 {
742 OptionSet optionset = {
743 Option("v|verbose",
744 [&]()
745 {
746 s_verbose = true;
747 }),
748 };
750 optionset.parse(argc, argv);
752 int mode;
754 if (optionset.params().size() == 0) {
755 mode = 0;
756 } else {
757 const string m = optionset.params().front();
759 if (m == "gbm")
760 mode = 0;
761 else if (m == "null")
762 mode = 1;
763 else {
764 printf("Unknown mode %s\n", m.c_str());
765 return -1;
766 }
767 }
769 switch (mode) {
770 case 0:
771 main_gbm();
772 break;
774 case 1:
775 main_egl();
776 break;
777 }
779 return 0;
780 }