1 /*
2 * Copyright © 2011 Benjamin Franzke
3 * Copyright © 2010 Intel Corporation
4 * Copyright © 2014,2018 Collabora Ltd.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 */
27
28 #include "config.h"
29
30 #include <assert.h>
31 #include <fcntl.h>
32 #include <getopt.h>
33 #include <signal.h>
34 #include <stdbool.h>
35 #include <stdint.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <sys/time.h>
41
42 #include <drm_fourcc.h>
43 // #include <xf86drm.h>
44
45 #include <wayland-client.h>
46 #include "shared/helpers.h"
47 #include "shared/platform.h"
48 #include "shared/simple_gbm.h"
49 #include <libweston/zalloc.h>
50 #include <wms-client-protocol.h>
51 #include "linux-dmabuf-unstable-v1-client-protocol.h"
52 #include "weston-direct-display-client-protocol.h"
53 #include "linux-explicit-synchronization-unstable-v1-client-protocol.h"
54
55 #include <EGL/egl.h>
56 #include <EGL/eglext.h>
57 #include <GLES2/gl2.h>
58 #include <GLES2/gl2ext.h>
59
60 #include "shared/weston-egl-ext.h"
61
62 #define LOG(fmt, ...) printf("dmabuf-egl: " fmt "\n", ##__VA_ARGS__)
63
64 #ifndef DRM_FORMAT_MOD_INVALID
65 #define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
66 #endif
67
68 /* Possible options that affect the displayed image */
69 #define OPT_IMMEDIATE (1 << 0) /* create wl_buffer immediately */
70 #define OPT_IMPLICIT_SYNC (1 << 1) /* force implicit sync */
71 #define OPT_MANDELBROT (1 << 2) /* render mandelbrot */
72 #define OPT_DIRECT_DISPLAY (1 << 3) /* direct-display */
73
74 #define BUFFER_FORMAT DRM_FORMAT_XRGB8888
75 #define MAX_BUFFER_PLANES 4
76
77 struct display {
78 struct wl_display *display;
79 struct wl_registry *registry;
80 struct wl_compositor *compositor;
81 struct wms *wms;
82 struct zwp_linux_dmabuf_v1 *dmabuf;
83 struct weston_direct_display_v1 *direct_display;
84 struct zwp_linux_explicit_synchronization_v1 *explicit_sync;
85 uint64_t *modifiers;
86 int modifiers_count;
87 int req_dmabuf_immediate;
88 bool use_explicit_sync;
89 struct {
90 EGLDisplay display;
91 EGLContext context;
92 EGLConfig conf;
93 bool has_dma_buf_import_modifiers;
94 bool has_no_config_context;
95 PFNEGLQUERYDMABUFMODIFIERSEXTPROC query_dma_buf_modifiers;
96 PFNEGLCREATEIMAGEKHRPROC create_image;
97 PFNEGLDESTROYIMAGEKHRPROC destroy_image;
98 PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
99 PFNEGLCREATESYNCKHRPROC create_sync;
100 PFNEGLDESTROYSYNCKHRPROC destroy_sync;
101 PFNEGLCLIENTWAITSYNCKHRPROC client_wait_sync;
102 PFNEGLDUPNATIVEFENCEFDANDROIDPROC dup_native_fence_fd;
103 PFNEGLWAITSYNCKHRPROC wait_sync;
104 } egl;
105 struct {
106 int drm_fd;
107 struct gbm_device *device;
108 } gbm;
109 struct window *window;
110 };
111
112 struct buffer {
113 struct display *display;
114 struct wl_buffer *buffer;
115 int busy;
116
117 struct gbm_bo *bo;
118
119 int width;
120 int height;
121 int format;
122 uint64_t modifier;
123 int plane_count;
124 int dmabuf_fds[MAX_BUFFER_PLANES];
125 uint32_t strides[MAX_BUFFER_PLANES];
126 uint32_t offsets[MAX_BUFFER_PLANES];
127
128 EGLImageKHR egl_image;
129 GLuint gl_texture;
130 GLuint gl_fbo;
131
132 struct zwp_linux_buffer_release_v1 *buffer_release;
133 /* The buffer owns the release_fence_fd, until it passes ownership
134 * to it to EGL (see wait_for_buffer_release_fence). */
135 int release_fence_fd;
136 };
137
138 #define NUM_BUFFERS 3
139
140 struct window {
141 struct display *display;
142 int width, height;
143 struct wl_surface *surface;
144 struct zwp_linux_surface_synchronization_v1 *surface_sync;
145 struct buffer buffers[NUM_BUFFERS];
146 struct wl_callback *callback;
147 bool initialized;
148 bool wait_for_configure;
149 struct {
150 GLuint program;
151 GLuint pos;
152 GLuint color;
153 GLuint offset_uniform;
154 } gl;
155 bool render_mandelbrot;
156 };
157
158 static sig_atomic_t running = 1;
159
160 static void
161 redraw(void *data, struct wl_callback *callback, uint32_t time);
162
163 static void
buffer_release(void * data,struct wl_buffer * buffer)164 buffer_release(void *data, struct wl_buffer *buffer)
165 {
166 struct buffer *mybuf = data;
167
168 mybuf->busy = 0;
169 }
170
171 static const struct wl_buffer_listener buffer_listener = {
172 buffer_release
173 };
174
175 static void
buffer_free(struct buffer * buf)176 buffer_free(struct buffer *buf)
177 {
178 int i;
179
180 if (buf->release_fence_fd >= 0)
181 close(buf->release_fence_fd);
182
183 if (buf->buffer_release)
184 zwp_linux_buffer_release_v1_destroy(buf->buffer_release);
185
186 if (buf->gl_fbo)
187 glDeleteFramebuffers(1, &buf->gl_fbo);
188
189 if (buf->gl_texture)
190 glDeleteTextures(1, &buf->gl_texture);
191
192 if (buf->egl_image) {
193 buf->display->egl.destroy_image(buf->display->egl.display,
194 buf->egl_image);
195 }
196
197 if (buf->buffer)
198 wl_buffer_destroy(buf->buffer);
199
200 if (buf->bo)
201 gbm_bo_destroy(buf->bo);
202
203 for (i = 0; i < buf->plane_count; ++i) {
204 if (buf->dmabuf_fds[i] >= 0)
205 close(buf->dmabuf_fds[i]);
206 }
207 }
208
209 static void
create_succeeded(void * data,struct zwp_linux_buffer_params_v1 * params,struct wl_buffer * new_buffer)210 create_succeeded(void *data,
211 struct zwp_linux_buffer_params_v1 *params,
212 struct wl_buffer *new_buffer)
213 {
214 struct buffer *buffer = data;
215
216 buffer->buffer = new_buffer;
217 /* When not using explicit synchronization listen to wl_buffer.release
218 * for release notifications, otherwise we are going to use
219 * zwp_linux_buffer_release_v1. */
220 if (!buffer->display->use_explicit_sync) {
221 wl_buffer_add_listener(buffer->buffer, &buffer_listener,
222 buffer);
223 }
224
225 zwp_linux_buffer_params_v1_destroy(params);
226 }
227
228 static void
create_failed(void * data,struct zwp_linux_buffer_params_v1 * params)229 create_failed(void *data, struct zwp_linux_buffer_params_v1 *params)
230 {
231 struct buffer *buffer = data;
232
233 buffer->buffer = NULL;
234 running = 0;
235
236 zwp_linux_buffer_params_v1_destroy(params);
237
238 fprintf(stderr, "Error: zwp_linux_buffer_params.create failed.\n");
239 }
240
241 static const struct zwp_linux_buffer_params_v1_listener params_listener = {
242 create_succeeded,
243 create_failed
244 };
245
246 static bool
create_fbo_for_buffer(struct display * display,struct buffer * buffer)247 create_fbo_for_buffer(struct display *display, struct buffer *buffer)
248 {
249 static const int general_attribs = 3;
250 static const int plane_attribs = 5;
251 static const int entries_per_attrib = 2;
252 EGLint attribs[(general_attribs + plane_attribs * MAX_BUFFER_PLANES) *
253 entries_per_attrib + 1];
254 unsigned int atti = 0;
255
256 attribs[atti++] = EGL_WIDTH;
257 attribs[atti++] = buffer->width;
258 attribs[atti++] = EGL_HEIGHT;
259 attribs[atti++] = buffer->height;
260 attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT;
261 attribs[atti++] = buffer->format;
262
263 #define ADD_PLANE_ATTRIBS(plane_idx) { \
264 attribs[atti++] = EGL_DMA_BUF_PLANE ## plane_idx ## _FD_EXT; \
265 attribs[atti++] = buffer->dmabuf_fds[plane_idx]; \
266 attribs[atti++] = EGL_DMA_BUF_PLANE ## plane_idx ## _OFFSET_EXT; \
267 attribs[atti++] = (int) buffer->offsets[plane_idx]; \
268 attribs[atti++] = EGL_DMA_BUF_PLANE ## plane_idx ## _PITCH_EXT; \
269 attribs[atti++] = (int) buffer->strides[plane_idx]; \
270 if (display->egl.has_dma_buf_import_modifiers) { \
271 attribs[atti++] = EGL_DMA_BUF_PLANE ## plane_idx ## _MODIFIER_LO_EXT; \
272 attribs[atti++] = buffer->modifier & 0xFFFFFFFF; \
273 attribs[atti++] = EGL_DMA_BUF_PLANE ## plane_idx ## _MODIFIER_HI_EXT; \
274 attribs[atti++] = buffer->modifier >> 32; \
275 } \
276 }
277
278 if (buffer->plane_count > 0)
279 ADD_PLANE_ATTRIBS(0);
280
281 if (buffer->plane_count > 1)
282 ADD_PLANE_ATTRIBS(1);
283
284 if (buffer->plane_count > 2)
285 ADD_PLANE_ATTRIBS(2);
286
287 if (buffer->plane_count > 3)
288 ADD_PLANE_ATTRIBS(3);
289
290 #undef ADD_PLANE_ATTRIBS
291
292 attribs[atti] = EGL_NONE;
293
294 assert(atti < ARRAY_LENGTH(attribs));
295
296 buffer->egl_image = display->egl.create_image(display->egl.display,
297 EGL_NO_CONTEXT,
298 EGL_LINUX_DMA_BUF_EXT,
299 NULL, attribs);
300 if (buffer->egl_image == EGL_NO_IMAGE_KHR) {
301 fprintf(stderr, "EGLImageKHR creation failed\n");
302 return false;
303 }
304
305 eglMakeCurrent(display->egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE,
306 display->egl.context);
307
308 glGenTextures(1, &buffer->gl_texture);
309 glBindTexture(GL_TEXTURE_2D, buffer->gl_texture);
310 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
311 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
312 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
313 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
314
315 display->egl.image_target_texture_2d(GL_TEXTURE_2D, buffer->egl_image);
316
317 glGenFramebuffers(1, &buffer->gl_fbo);
318 glBindFramebuffer(GL_FRAMEBUFFER, buffer->gl_fbo);
319 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
320 GL_TEXTURE_2D, buffer->gl_texture, 0);
321 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
322 fprintf(stderr, "FBO creation failed\n");
323 return false;
324 }
325
326 return true;
327 }
328
329
330 static int
create_dmabuf_buffer(struct display * display,struct buffer * buffer,int width,int height,uint32_t opts)331 create_dmabuf_buffer(struct display *display, struct buffer *buffer,
332 int width, int height, uint32_t opts)
333 {
334 /* Y-Invert the buffer image, since we are going to renderer to the
335 * buffer through a FBO. */
336 static uint32_t flags = ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT;
337 struct zwp_linux_buffer_params_v1 *params;
338 int i;
339
340 buffer->display = display;
341 buffer->width = width;
342 buffer->height = height;
343 buffer->format = BUFFER_FORMAT;
344 buffer->release_fence_fd = -1;
345
346 fprintf(stderr,"pss %s %d, %s, BUFFER_FORMAT 0x%08x\n",__func__,__LINE__,__FILE__,BUFFER_FORMAT);
347 #ifdef HAVE_GBM_MODIFIERS
348 if (display->modifiers_count > 0) {
349 buffer->bo = gbm_bo_create_with_modifiers(display->gbm.device,
350 buffer->width,
351 buffer->height,
352 buffer->format,
353 display->modifiers,
354 display->modifiers_count);
355 if (buffer->bo)
356 buffer->modifier = gbm_bo_get_modifier(buffer->bo);
357 }
358 #endif
359
360 if (!buffer->bo) {
361 buffer->bo = gbm_bo_create(display->gbm.device,
362 buffer->width,
363 buffer->height,
364 buffer->format,
365 GBM_BO_USE_RENDERING);
366 buffer->modifier = DRM_FORMAT_MOD_INVALID;
367 }
368
369 if (!buffer->bo) {
370 fprintf(stderr, "create_bo failed\n");
371 goto error;
372 }
373
374 #ifdef HAVE_GBM_MODIFIERS
375 buffer->plane_count = gbm_bo_get_plane_count(buffer->bo);
376 for (i = 0; i < buffer->plane_count; ++i) {
377 int ret;
378 union gbm_bo_handle handle;
379
380 handle = gbm_bo_get_handle_for_plane(buffer->bo, i);
381 if (handle.s32 == -1) {
382 fprintf(stderr, "error: failed to get gbm_bo_handle\n");
383 goto error;
384 }
385
386 ret = drmPrimeHandleToFD(display->gbm.drm_fd, handle.u32, 0,
387 &buffer->dmabuf_fds[i]);
388 if (ret < 0 || buffer->dmabuf_fds[i] < 0) {
389 fprintf(stderr, "error: failed to get dmabuf_fd\n");
390 goto error;
391 }
392 buffer->strides[i] = gbm_bo_get_stride_for_plane(buffer->bo, i);
393 buffer->offsets[i] = gbm_bo_get_offset(buffer->bo, i);
394 }
395 #else
396 buffer->plane_count = 1;
397 buffer->strides[0] = gbm_bo_get_stride(buffer->bo);
398 buffer->dmabuf_fds[0] = gbm_bo_get_fd(buffer->bo);
399 if (buffer->dmabuf_fds[0] < 0) {
400 fprintf(stderr, "error: failed to get dmabuf_fd\n");
401 goto error;
402 }
403 #endif
404
405 params = zwp_linux_dmabuf_v1_create_params(display->dmabuf);
406
407 if ((opts & OPT_DIRECT_DISPLAY) && display->direct_display) {
408 weston_direct_display_v1_enable(display->direct_display, params);
409 /* turn off Y_INVERT otherwise linux-dmabuf will reject it and
410 * we need all dmabuf flags turned off */
411 flags &= ~ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT;
412
413 fprintf(stdout, "image is y-inverted as direct-display flag was set, "
414 "dmabuf y-inverted attribute flag was removed\n");
415 }
416
417 for (i = 0; i < buffer->plane_count; ++i) {
418 zwp_linux_buffer_params_v1_add(params,
419 buffer->dmabuf_fds[i],
420 i,
421 buffer->offsets[i],
422 buffer->strides[i],
423 buffer->modifier >> 32,
424 buffer->modifier & 0xffffffff);
425 }
426
427 zwp_linux_buffer_params_v1_add_listener(params, ¶ms_listener, buffer);
428 if (display->req_dmabuf_immediate) {
429 buffer->buffer =
430 zwp_linux_buffer_params_v1_create_immed(params,
431 buffer->width,
432 buffer->height,
433 buffer->format,
434 flags);
435 /* When not using explicit synchronization listen to
436 * wl_buffer.release for release notifications, otherwise we
437 * are going to use zwp_linux_buffer_release_v1. */
438 if (!buffer->display->use_explicit_sync) {
439 wl_buffer_add_listener(buffer->buffer,
440 &buffer_listener,
441 buffer);
442 }
443 }
444 else {
445 zwp_linux_buffer_params_v1_create(params,
446 buffer->width,
447 buffer->height,
448 buffer->format,
449 flags);
450 }
451
452 if (!create_fbo_for_buffer(display, buffer))
453 goto error;
454
455 return 0;
456
457 error:
458 buffer_free(buffer);
459 return -1;
460 }
461
462 static const char *vert_shader_text =
463 "uniform float offset;\n"
464 "attribute vec4 pos;\n"
465 "attribute vec4 color;\n"
466 "varying vec4 v_color;\n"
467 "void main() {\n"
468 " gl_Position = pos + vec4(offset, offset, 0.0, 0.0);\n"
469 " v_color = color;\n"
470 "}\n";
471
472 static const char *frag_shader_text =
473 "precision mediump float;\n"
474 "varying vec4 v_color;\n"
475 "void main() {\n"
476 " gl_FragColor = v_color;\n"
477 "}\n";
478
479 static const char *vert_shader_mandelbrot_text =
480 "uniform float offset;\n"
481 "attribute vec4 pos;\n"
482 "varying vec2 v_pos;\n"
483 "void main() {\n"
484 " v_pos = pos.xy;\n"
485 " gl_Position = pos + vec4(offset, offset, 0.0, 0.0);\n"
486 "}\n";
487
488
489 /* Mandelbrot set shader using the escape time algorithm. */
490 static const char *frag_shader_mandelbrot_text =
491 "precision mediump float;\n"
492 "varying vec2 v_pos;\n"
493 "void main() {\n"
494 " const int max_iteration = 500;\n"
495 " // Scale and translate position to get a nice mandelbrot drawing for\n"
496 " // the used v_pos x and y range (-0.5 to 0.5).\n"
497 " float x0 = 3.0 * v_pos.x - 0.5;\n"
498 " float y0 = 3.0 * v_pos.y;\n"
499 " float x = 0.0;\n"
500 " float y = 0.0;\n"
501 " int iteration = 0;\n"
502 " while (x * x + y * y <= 4.0 && iteration < max_iteration) {\n"
503 " float xtemp = x * x - y * y + x0;\n"
504 " y = 2.0 * x * y + y0;\n"
505 " x = xtemp;\n"
506 " ++iteration;\n"
507 " }\n"
508 " float red = iteration == max_iteration ?\n"
509 " 0.0 : 1.0 - fract(float(iteration) / 20.0);\n"
510 " gl_FragColor = vec4(red, 0.0, 0.0, 1.0);\n"
511 "}\n";
512
513 static GLuint
create_shader(const char * source,GLenum shader_type)514 create_shader(const char *source, GLenum shader_type)
515 {
516 GLuint shader;
517 GLint status;
518
519 shader = glCreateShader(shader_type);
520 assert(shader != 0);
521
522 glShaderSource(shader, 1, (const char **) &source, NULL);
523 glCompileShader(shader);
524
525 glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
526 if (!status) {
527 char log[1000];
528 GLsizei len;
529 glGetShaderInfoLog(shader, 1000, &len, log);
530 fprintf(stderr, "Error: compiling %s: %.*s\n",
531 shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
532 len, log);
533 return 0;
534 }
535
536 return shader;
537 }
538
539 static GLuint
create_and_link_program(GLuint vert,GLuint frag)540 create_and_link_program(GLuint vert, GLuint frag)
541 {
542 GLint status;
543 GLuint program = glCreateProgram();
544
545 glAttachShader(program, vert);
546 glAttachShader(program, frag);
547 glLinkProgram(program);
548
549 glGetProgramiv(program, GL_LINK_STATUS, &status);
550 if (!status) {
551 char log[1000];
552 GLsizei len;
553 glGetProgramInfoLog(program, 1000, &len, log);
554 fprintf(stderr, "Error: linking:\n%.*s\n", len, log);
555 return 0;
556 }
557
558 return program;
559 }
560
561 static bool
window_set_up_gl(struct window * window)562 window_set_up_gl(struct window *window)
563 {
564 GLuint vert = create_shader(
565 window->render_mandelbrot ? vert_shader_mandelbrot_text :
566 vert_shader_text,
567 GL_VERTEX_SHADER);
568 GLuint frag = create_shader(
569 window->render_mandelbrot ? frag_shader_mandelbrot_text :
570 frag_shader_text,
571 GL_FRAGMENT_SHADER);
572
573 window->gl.program = create_and_link_program(vert, frag);
574
575 glDeleteShader(vert);
576 glDeleteShader(frag);
577
578 window->gl.pos = glGetAttribLocation(window->gl.program, "pos");
579 window->gl.color = glGetAttribLocation(window->gl.program, "color");
580
581 glUseProgram(window->gl.program);
582
583 window->gl.offset_uniform =
584 glGetUniformLocation(window->gl.program, "offset");
585
586 return window->gl.program != 0;
587 }
588
589 static void
destroy_window(struct window * window)590 destroy_window(struct window *window)
591 {
592 int i;
593
594 if (window->gl.program)
595 glDeleteProgram(window->gl.program);
596
597 if (window->callback)
598 wl_callback_destroy(window->callback);
599
600 for (i = 0; i < NUM_BUFFERS; i++) {
601 if (window->buffers[i].buffer)
602 buffer_free(&window->buffers[i]);
603 }
604
605 if (window->surface_sync)
606 zwp_linux_surface_synchronization_v1_destroy(window->surface_sync);
607 wl_surface_destroy(window->surface);
608 free(window);
609 }
610
611 static struct window *
create_window(struct display * display,int width,int height,int opts)612 create_window(struct display *display, int width, int height, int opts)
613 {
614 struct window *window;
615 int i;
616 int ret;
617
618 window = zalloc(sizeof *window);
619 if (!window)
620 return NULL;
621
622 window->callback = NULL;
623 window->display = display;
624 display->window = window;
625 window->width = width;
626 window->height = height;
627 window->surface = wl_compositor_create_surface(display->compositor);
628
629 if (display->wms) {
630 wms_create_window(display->wms, window->surface, 0, 0);
631 wl_display_flush(display->display);
632 wl_display_roundtrip(display->display);
633 wl_display_roundtrip(display->display);
634
635 window->wait_for_configure = false;
636 wl_surface_commit(window->surface);
637 } else {
638 assert(0);
639 }
640
641 if (display->explicit_sync) {
642 window->surface_sync =
643 zwp_linux_explicit_synchronization_v1_get_synchronization(
644 display->explicit_sync, window->surface);
645 assert(window->surface_sync);
646 }
647
648 for (i = 0; i < NUM_BUFFERS; ++i) {
649 int j;
650 for (j = 0; j < MAX_BUFFER_PLANES; ++j)
651 window->buffers[i].dmabuf_fds[j] = -1;
652
653 }
654
655 for (i = 0; i < NUM_BUFFERS; ++i) {
656 ret = create_dmabuf_buffer(display, &window->buffers[i],
657 window->width, window->height, opts);
658
659 if (ret < 0)
660 goto error;
661 }
662
663 window->render_mandelbrot = opts & OPT_MANDELBROT;
664
665 if (!window_set_up_gl(window))
666 goto error;
667
668 return window;
669
670 error:
671 if (window)
672 destroy_window(window);
673
674 return NULL;
675 }
676
677 static int
create_egl_fence_fd(struct window * window)678 create_egl_fence_fd(struct window *window)
679 {
680 struct display *d = window->display;
681 EGLSyncKHR sync = d->egl.create_sync(d->egl.display,
682 EGL_SYNC_NATIVE_FENCE_ANDROID,
683 NULL);
684 int fd;
685
686 assert(sync != EGL_NO_SYNC_KHR);
687 /* We need to flush before we can get the fence fd. */
688 glFlush();
689 fd = d->egl.dup_native_fence_fd(d->egl.display, sync);
690 assert(fd >= 0);
691
692 d->egl.destroy_sync(d->egl.display, sync);
693
694 return fd;
695 }
696
697 static struct buffer *
window_next_buffer(struct window * window)698 window_next_buffer(struct window *window)
699 {
700 int i;
701
702 for (i = 0; i < NUM_BUFFERS; i++)
703 if (!window->buffers[i].busy)
704 return &window->buffers[i];
705
706 return NULL;
707 }
708
709 static const struct wl_callback_listener frame_listener;
710
711 /* Renders a square moving from the lower left corner to the
712 * upper right corner of the window. The square's vertices have
713 * the following colors:
714 *
715 * green +-----+ yellow
716 * | |
717 * | |
718 * red +-----+ blue
719 */
720 static void
render(struct window * window,struct buffer * buffer)721 render(struct window *window, struct buffer *buffer)
722 {
723 /* Complete a movement iteration in 5000 ms. */
724 static const uint64_t iteration_ms = 5000;
725 static const GLfloat verts[4][2] = {
726 { -0.5, -0.5 },
727 { -0.5, 0.5 },
728 { 0.5, -0.5 },
729 { 0.5, 0.5 }
730 };
731 static const GLfloat colors[4][3] = {
732 { 1, 0, 0 },
733 { 0, 1, 0 },
734 { 0, 0, 1 },
735 { 1, 1, 0 }
736 };
737 GLfloat offset;
738 struct timeval tv;
739 uint64_t time_ms;
740
741 gettimeofday(&tv, NULL);
742 time_ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
743
744 /* Split time_ms in repeating windows of [0, iteration_ms) and map them
745 * to offsets in the [-0.5, 0.5) range. */
746 offset = (time_ms % iteration_ms) / (float) iteration_ms - 0.5;
747
748 /* Direct all GL draws to the buffer through the FBO */
749 glBindFramebuffer(GL_FRAMEBUFFER, buffer->gl_fbo);
750
751 glViewport(0, 0, window->width, window->height);
752
753 glUniform1f(window->gl.offset_uniform, offset);
754
755 glClearColor(0.0,0.0, 0.0, 1.0);
756 glClear(GL_COLOR_BUFFER_BIT);
757
758 glVertexAttribPointer(window->gl.pos, 2, GL_FLOAT, GL_FALSE, 0, verts);
759 glVertexAttribPointer(window->gl.color, 3, GL_FLOAT, GL_FALSE, 0, colors);
760 glEnableVertexAttribArray(window->gl.pos);
761 glEnableVertexAttribArray(window->gl.color);
762
763 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
764
765 glDisableVertexAttribArray(window->gl.pos);
766 glDisableVertexAttribArray(window->gl.color);
767 }
768
769 static void
render_mandelbrot(struct window * window,struct buffer * buffer)770 render_mandelbrot(struct window *window, struct buffer *buffer)
771 {
772 /* Complete a movement iteration in 5000 ms. */
773 static const uint64_t iteration_ms = 5000;
774 /* Split drawing in a square grid consisting of grid_side * grid_side
775 * cells. */
776 static const int grid_side = 4;
777 GLfloat norm_cell_side = 1.0 / grid_side;
778 int num_cells = grid_side * grid_side;
779 GLfloat offset;
780 struct timeval tv;
781 uint64_t time_ms;
782 int i;
783
784 gettimeofday(&tv, NULL);
785 time_ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
786
787 /* Split time_ms in repeating windows of [0, iteration_ms) and map them
788 * to offsets in the [-0.5, 0.5) range. */
789 offset = (time_ms % iteration_ms) / (float) iteration_ms - 0.5;
790
791 /* Direct all GL draws to the buffer through the FBO */
792 glBindFramebuffer(GL_FRAMEBUFFER, buffer->gl_fbo);
793
794 glViewport(0, 0, window->width, window->height);
795
796 glUniform1f(window->gl.offset_uniform, offset);
797
798 glClearColor(0.6, 0.6, 0.6, 1.0);
799 glClear(GL_COLOR_BUFFER_BIT);
800
801 for (i = 0; i < num_cells; ++i) {
802 /* Calculate the vertex coordinates of the current grid cell. */
803 int row = i / grid_side;
804 int col = i % grid_side;
805 GLfloat left = -0.5 + norm_cell_side * col;
806 GLfloat right = left + norm_cell_side;
807 GLfloat top = 0.5 - norm_cell_side * row;
808 GLfloat bottom = top - norm_cell_side;
809 GLfloat verts[4][2] = {
810 { left, bottom },
811 { left, top },
812 { right, bottom },
813 { right, top }
814 };
815
816 /* ... and draw it. */
817 glVertexAttribPointer(window->gl.pos, 2, GL_FLOAT, GL_FALSE, 0, verts);
818 glEnableVertexAttribArray(window->gl.pos);
819
820 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
821
822 glDisableVertexAttribArray(window->gl.pos);
823 }
824 }
825
826 static void
buffer_fenced_release(void * data,struct zwp_linux_buffer_release_v1 * release,int32_t fence)827 buffer_fenced_release(void *data,
828 struct zwp_linux_buffer_release_v1 *release,
829 int32_t fence)
830 {
831 struct buffer *buffer = data;
832
833 assert(release == buffer->buffer_release);
834 assert(buffer->release_fence_fd == -1);
835
836 buffer->busy = 0;
837 buffer->release_fence_fd = fence;
838 zwp_linux_buffer_release_v1_destroy(buffer->buffer_release);
839 buffer->buffer_release = NULL;
840 }
841
842 static void
buffer_immediate_release(void * data,struct zwp_linux_buffer_release_v1 * release)843 buffer_immediate_release(void *data,
844 struct zwp_linux_buffer_release_v1 *release)
845 {
846 struct buffer *buffer = data;
847
848 assert(release == buffer->buffer_release);
849 assert(buffer->release_fence_fd == -1);
850
851 buffer->busy = 0;
852 zwp_linux_buffer_release_v1_destroy(buffer->buffer_release);
853 buffer->buffer_release = NULL;
854 }
855
856 static const struct zwp_linux_buffer_release_v1_listener buffer_release_listener = {
857 buffer_fenced_release,
858 buffer_immediate_release,
859 };
860
861 static void
wait_for_buffer_release_fence(struct buffer * buffer)862 wait_for_buffer_release_fence(struct buffer *buffer)
863 {
864 struct display *d = buffer->display;
865 EGLint attrib_list[] = {
866 EGL_SYNC_NATIVE_FENCE_FD_ANDROID, buffer->release_fence_fd,
867 EGL_NONE,
868 };
869 EGLSyncKHR sync = d->egl.create_sync(d->egl.display,
870 EGL_SYNC_NATIVE_FENCE_ANDROID,
871 attrib_list);
872 int ret;
873
874 assert(sync);
875
876 /* EGLSyncKHR takes ownership of the fence fd. */
877 buffer->release_fence_fd = -1;
878
879 if (d->egl.wait_sync)
880 ret = d->egl.wait_sync(d->egl.display, sync, 0);
881 else
882 ret = d->egl.client_wait_sync(d->egl.display, sync, 0,
883 EGL_FOREVER_KHR);
884 assert(ret == EGL_TRUE);
885
886 ret = d->egl.destroy_sync(d->egl.display, sync);
887 assert(ret == EGL_TRUE);
888 }
889
890 static void
redraw(void * data,struct wl_callback * callback,uint32_t time)891 redraw(void *data, struct wl_callback *callback, uint32_t time)
892 {
893 struct window *window = data;
894 struct buffer *buffer;
895 fprintf(stderr,"pss %s %d, %s\n",__func__,__LINE__,__FILE__);
896 buffer = window_next_buffer(window);
897 if (!buffer) {
898 fprintf(stderr,
899 !callback ? "Failed to create the first buffer.\n" :
900 "All buffers busy at redraw(). Server bug?\n");
901 abort();
902 }
903
904 if (buffer->release_fence_fd >= 0)
905 wait_for_buffer_release_fence(buffer);
906
907 fprintf(stderr,"pss %s %d, %s\n",__func__,__LINE__,__FILE__);
908 if (window->render_mandelbrot)
909 render_mandelbrot(window, buffer);
910 else
911 render(window, buffer);
912 fprintf(stderr,"pss %s %d, %s\n",__func__,__LINE__,__FILE__);
913
914 fprintf(stderr,"pss %s %d, %s\n",__func__,__LINE__,__FILE__);
915 if (window->display->use_explicit_sync) {
916 int fence_fd = create_egl_fence_fd(window);
917 zwp_linux_surface_synchronization_v1_set_acquire_fence(
918 window->surface_sync, fence_fd);
919 close(fence_fd);
920
921 buffer->buffer_release =
922 zwp_linux_surface_synchronization_v1_get_release(window->surface_sync);
923 zwp_linux_buffer_release_v1_add_listener(
924 buffer->buffer_release, &buffer_release_listener, buffer);
925 } else {
926 glFinish();
927 }
928
929 fprintf(stderr,"pss %s %d, %s\n",__func__,__LINE__,__FILE__);
930 wl_surface_attach(window->surface, buffer->buffer, 0, 0);
931 wl_surface_damage(window->surface, 0, 0, window->width, window->height);
932
933 fprintf(stderr,"pss %s %d, %s\n",__func__,__LINE__,__FILE__);
934 if (callback)
935 wl_callback_destroy(callback);
936
937 fprintf(stderr,"pss %s %d, %s\n",__func__,__LINE__,__FILE__);
938 window->callback = wl_surface_frame(window->surface);
939 wl_callback_add_listener(window->callback, &frame_listener, window);
940 wl_surface_commit(window->surface);
941 buffer->busy = 1;
942 fprintf(stderr,"pss %s %d, %s\n",__func__,__LINE__,__FILE__);
943 }
944
945 static const struct wl_callback_listener frame_listener = {
946 redraw
947 };
948
949 static void
dmabuf_modifiers(void * data,struct zwp_linux_dmabuf_v1 * zwp_linux_dmabuf,uint32_t format,uint32_t modifier_hi,uint32_t modifier_lo)950 dmabuf_modifiers(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf,
951 uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo)
952 {
953 struct display *d = data;
954
955 switch (format) {
956 case BUFFER_FORMAT:
957 ++d->modifiers_count;
958 d->modifiers = realloc(d->modifiers,
959 d->modifiers_count * sizeof(*d->modifiers));
960 d->modifiers[d->modifiers_count - 1] =
961 ((uint64_t)modifier_hi << 32) | modifier_lo;
962 break;
963 default:
964 break;
965 }
966 }
967
968 static void
dmabuf_format(void * data,struct zwp_linux_dmabuf_v1 * zwp_linux_dmabuf,uint32_t format)969 dmabuf_format(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf, uint32_t format)
970 {
971 /* XXX: deprecated */
972 }
973
974 static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
975 dmabuf_format,
976 dmabuf_modifiers
977 };
978
WindowShotError(void * data,struct wms * wms,uint32_t error,uint32_t window_id)979 static void WindowShotError(void *data, struct wms *wms, uint32_t error, uint32_t window_id)
980 {
981 LOG("WindowShotError error: %d", error);
982 LOG("WindowShotError window_id: %d", window_id);
983 }
984
WindowShotDone(void * data,struct wms * wms,uint32_t window_id,int32_t fd,int32_t width,int32_t height,int32_t stride,uint32_t format,uint32_t seconds,uint32_t nanoseconds)985 static void WindowShotDone(void *data,
986 struct wms *wms,
987 uint32_t window_id, int32_t fd,
988 int32_t width, int32_t height, int32_t stride,
989 uint32_t format, uint32_t seconds, uint32_t nanoseconds)
990 {
991 LOG("WindowShotDone window_id: %d", window_id);
992 LOG("WindowShotDone fd: %d", fd);
993 LOG("WindowShotDone width: %d", width);
994 LOG("WindowShotDone height: %d", height);
995 LOG("WindowShotDone stride: %d", stride);
996 LOG("WindowShotDone format: %d", format);
997 LOG("WindowShotDone seconds: %d", seconds);
998 LOG("WindowShotDone nanoseconds: %d", nanoseconds);
999
1000 LOG("windowshot OK!!!");
1001
1002 close(fd);
1003 }
1004
ScreenShotError(void * data,struct wms * wms,uint32_t error,uint32_t screen_id)1005 static void ScreenShotError(void *data, struct wms *wms, uint32_t error, uint32_t screen_id)
1006 {
1007 LOG("ScreenShotError error: %d", error);
1008 LOG("ScreenShotError screen_id: %d", screen_id);
1009 }
1010
ScreenShotDone(void * data,struct wms * wms,uint32_t screen_id,int32_t fd,int32_t width,int32_t height,int32_t stride,uint32_t format,uint32_t seconds,uint32_t nanoseconds)1011 static void ScreenShotDone(void *data,
1012 struct wms *wms,
1013 uint32_t screen_id, int32_t fd,
1014 int32_t width, int32_t height, int32_t stride,
1015 uint32_t format, uint32_t seconds, uint32_t nanoseconds)
1016 {
1017 LOG("ScreenShotDone screen_id: %d", screen_id);
1018 LOG("ScreenShotDone fd: %d", fd);
1019 LOG("ScreenShotDone width: %d", width);
1020 LOG("ScreenShotDone height: %d", height);
1021 LOG("ScreenShotDone stride: %d", stride);
1022 LOG("ScreenShotDone format: %d", format);
1023 LOG("ScreenShotDone seconds: %d", seconds);
1024 LOG("ScreenShotDone nanoseconds: %d", nanoseconds);
1025
1026 LOG("screenshot OK!!!");
1027 close(fd);
1028 }
1029
ReplyStatus(void * data,struct wms * wms,uint32_t status)1030 static void ReplyStatus(void *data, struct wms *wms, uint32_t status)
1031 {
1032 LOG("ReplyStatus status: %d", status);
1033 }
1034
DisplayMode(void * data,struct wms * wms,uint32_t flag)1035 static void DisplayMode(void *data, struct wms *wms, uint32_t flag)
1036 {
1037 LOG("DisplayMode flag: %d", flag);
1038 }
1039
ScreenUpdate(void * data,struct wms * wms,uint32_t screen_id,const char * name,uint32_t update_state,int width,int height)1040 void ScreenUpdate(void *data,
1041 struct wms *wms,
1042 uint32_t screen_id,
1043 const char *name,
1044 uint32_t update_state,
1045 int width, int height)
1046 {
1047 LOG("screenUpdate screen_id: %d", screen_id);
1048 LOG("screenUpdate name: %s", name);
1049 LOG("screenUpdate update_state: %d", update_state);
1050 LOG("screenUpdate width: %d", width);
1051 LOG("screenUpdate height: %d", height);
1052
1053 if (update_state == WMS_SCREEN_STATUS_ADD) {
1054 LOG("screen add. ");
1055 }
1056 else {
1057 LOG("screen destroy.");
1058 }
1059 }
1060
WindowUpdate(void * data,struct wms * wms,uint32_t update_state,uint32_t window_id,int32_t x,int32_t y,int32_t width,int32_t height)1061 void WindowUpdate(void *data, struct wms *wms, uint32_t update_state, uint32_t window_id,
1062 int32_t x, int32_t y, int32_t width, int32_t height)
1063 {
1064 struct display *d = data;
1065 LOG("WindowUpdate window_id: %d", window_id);
1066 LOG("WindowUpdate update_state: %d", update_state);
1067 LOG("WindowUpdate x:%d, y:%d", x, y);
1068 LOG("WindowUpdate width:%d, height:%d", width, height);
1069
1070 if (update_state == WMS_WINDOW_STATUS_CREATED) {
1071 LOG("window %d create. ", window_id);
1072 d->window->width = width;
1073 d->window->height = height;
1074 }
1075 else if (update_state == WMS_WINDOW_STATUS_FAILED) {
1076 LOG("window create failed. ");
1077 }
1078 else {
1079 LOG("window %d destroy. ", window_id);
1080 }
1081 }
1082
1083 static void
registry_handle_global(void * data,struct wl_registry * registry,uint32_t id,const char * interface,uint32_t version)1084 registry_handle_global(void *data, struct wl_registry *registry,
1085 uint32_t id, const char *interface, uint32_t version)
1086 {
1087 struct display *d = data;
1088
1089 if (strcmp(interface, "wl_compositor") == 0) {
1090 d->compositor =
1091 wl_registry_bind(registry,
1092 id, &wl_compositor_interface, 1);
1093 } else if (strcmp(interface, "wms") == 0) {
1094 d->wms = (struct wms *)wl_registry_bind(registry, id, &wms_interface, 1);
1095
1096 static struct wms_listener wmsListener = {
1097 WindowUpdate,
1098 ScreenUpdate,
1099 DisplayMode,
1100 ReplyStatus,
1101 ScreenShotDone,
1102 ScreenShotError,
1103 WindowShotDone,
1104 WindowShotError
1105 };
1106 wms_add_listener(d->wms, &wmsListener, d);
1107 wl_display_flush(d->display);
1108 wl_display_roundtrip(d->display);
1109
1110 } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0) {
1111 if (version < 3)
1112 return;
1113 d->dmabuf = wl_registry_bind(registry,
1114 id, &zwp_linux_dmabuf_v1_interface, 3);
1115 zwp_linux_dmabuf_v1_add_listener(d->dmabuf, &dmabuf_listener, d);
1116 } else if (strcmp(interface, "zwp_linux_explicit_synchronization_v1") == 0) {
1117 d->explicit_sync = wl_registry_bind(
1118 registry, id,
1119 &zwp_linux_explicit_synchronization_v1_interface, 1);
1120 } else if (strcmp(interface, "weston_direct_display_v1") == 0) {
1121 d->direct_display = wl_registry_bind(registry,
1122 id, &weston_direct_display_v1_interface, 1);
1123 }
1124 }
1125
1126 static void
registry_handle_global_remove(void * data,struct wl_registry * registry,uint32_t name)1127 registry_handle_global_remove(void *data, struct wl_registry *registry,
1128 uint32_t name)
1129 {
1130 }
1131
1132 static const struct wl_registry_listener registry_listener = {
1133 registry_handle_global,
1134 registry_handle_global_remove
1135 };
1136
1137 static void
destroy_display(struct display * display)1138 destroy_display(struct display *display)
1139 {
1140 if (display->gbm.device)
1141 gbm_device_destroy(display->gbm.device);
1142
1143 if (display->gbm.drm_fd >= 0)
1144 close(display->gbm.drm_fd);
1145
1146 if (display->egl.context != EGL_NO_CONTEXT)
1147 eglDestroyContext(display->egl.display, display->egl.context);
1148
1149 if (display->egl.display != EGL_NO_DISPLAY)
1150 eglTerminate(display->egl.display);
1151
1152 free(display->modifiers);
1153
1154 if (display->dmabuf)
1155 zwp_linux_dmabuf_v1_destroy(display->dmabuf);
1156
1157 if (display->compositor)
1158 wl_compositor_destroy(display->compositor);
1159
1160 if (display->registry)
1161 wl_registry_destroy(display->registry);
1162
1163 if (display->display) {
1164 wl_display_flush(display->display);
1165 wl_display_disconnect(display->display);
1166 }
1167
1168 free(display);
1169 }
1170
1171 static bool
display_set_up_egl(struct display * display)1172 display_set_up_egl(struct display *display)
1173 {
1174 static const EGLint context_attribs[] = {
1175 EGL_CONTEXT_CLIENT_VERSION, 2,
1176 EGL_NONE
1177 };
1178 EGLint major, minor, ret, count;
1179 const char *egl_extensions = NULL;
1180 const char *gl_extensions = NULL;
1181
1182 EGLint config_attribs[] = {
1183 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1184 EGL_RED_SIZE, 1,
1185 EGL_GREEN_SIZE, 1,
1186 EGL_BLUE_SIZE, 1,
1187 EGL_ALPHA_SIZE, 1,
1188 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
1189 EGL_NONE
1190 };
1191
1192 display->egl.display =
1193 weston_platform_get_egl_display(EGL_PLATFORM_GBM_KHR,
1194 display->gbm.device, NULL);
1195
1196 if (display->egl.display == EGL_NO_DISPLAY) {
1197 fprintf(stderr, "Failed to create EGLDisplay\n");
1198 goto error;
1199 }
1200
1201 if (eglInitialize(display->egl.display, &major, &minor) == EGL_FALSE) {
1202 fprintf(stderr, "Failed to initialize EGLDisplay\n");
1203 goto error;
1204 }
1205
1206 if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) {
1207 fprintf(stderr, "Failed to bind OpenGL ES API\n");
1208 goto error;
1209 }
1210
1211 egl_extensions = eglQueryString(display->egl.display, EGL_EXTENSIONS);
1212 assert(egl_extensions != NULL);
1213
1214 if (!weston_check_egl_extension(egl_extensions,
1215 "EGL_EXT_image_dma_buf_import")) {
1216 fprintf(stderr, "EGL_EXT_image_dma_buf_import not supported\n");
1217 goto error;
1218 }
1219
1220 if (!weston_check_egl_extension(egl_extensions,
1221 "EGL_KHR_surfaceless_context")) {
1222 fprintf(stderr, "EGL_KHR_surfaceless_context not supported\n");
1223 goto error;
1224 }
1225
1226 if (weston_check_egl_extension(egl_extensions,
1227 "EGL_KHR_no_config_context")) {
1228 display->egl.has_no_config_context = true;
1229 }
1230
1231 if (display->egl.has_no_config_context) {
1232 display->egl.conf = EGL_NO_CONFIG_KHR;
1233 } else {
1234 fprintf(stderr,
1235 "Warning: EGL_KHR_no_config_context not supported\n");
1236 ret = eglChooseConfig(display->egl.display, config_attribs,
1237 &display->egl.conf, 1, &count);
1238 assert(ret && count >= 1);
1239 }
1240
1241 display->egl.context = eglCreateContext(display->egl.display,
1242 display->egl.conf,
1243 EGL_NO_CONTEXT,
1244 context_attribs);
1245 if (display->egl.context == EGL_NO_CONTEXT) {
1246 fprintf(stderr, "Failed to create EGLContext\n");
1247 goto error;
1248 }
1249
1250 eglMakeCurrent(display->egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE,
1251 display->egl.context);
1252
1253 gl_extensions = (const char *) glGetString(GL_EXTENSIONS);
1254 assert(gl_extensions != NULL);
1255
1256 if (!weston_check_egl_extension(gl_extensions,
1257 "GL_OES_EGL_image")) {
1258 fprintf(stderr, "GL_OES_EGL_image not supported\n");
1259 goto error;
1260 }
1261
1262 #if 0
1263 if (weston_check_egl_extension(egl_extensions,
1264 "EGL_EXT_image_dma_buf_import_modifiers")) {
1265 display->egl.has_dma_buf_import_modifiers = true;
1266 display->egl.query_dma_buf_modifiers =
1267 (void *) eglGetProcAddress("eglQueryDmaBufModifiersEXT");
1268 assert(display->egl.query_dma_buf_modifiers);
1269 }
1270 #endif
1271
1272 display->egl.create_image =
1273 (void *) eglGetProcAddress("eglCreateImageKHR");
1274 assert(display->egl.create_image);
1275
1276 display->egl.destroy_image =
1277 (void *) eglGetProcAddress("eglDestroyImageKHR");
1278 assert(display->egl.destroy_image);
1279
1280 display->egl.image_target_texture_2d =
1281 (void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
1282 assert(display->egl.image_target_texture_2d);
1283
1284 if (weston_check_egl_extension(egl_extensions, "EGL_KHR_fence_sync") &&
1285 weston_check_egl_extension(egl_extensions,
1286 "EGL_ANDROID_native_fence_sync")) {
1287 display->egl.create_sync =
1288 (void *) eglGetProcAddress("eglCreateSyncKHR");
1289 assert(display->egl.create_sync);
1290
1291 display->egl.destroy_sync =
1292 (void *) eglGetProcAddress("eglDestroySyncKHR");
1293 assert(display->egl.destroy_sync);
1294
1295 display->egl.client_wait_sync =
1296 (void *) eglGetProcAddress("eglClientWaitSyncKHR");
1297 assert(display->egl.client_wait_sync);
1298
1299 display->egl.dup_native_fence_fd =
1300 (void *) eglGetProcAddress("eglDupNativeFenceFDANDROID");
1301 assert(display->egl.dup_native_fence_fd);
1302 }
1303
1304 if (weston_check_egl_extension(egl_extensions,
1305 "EGL_KHR_wait_sync")) {
1306 display->egl.wait_sync =
1307 (void *) eglGetProcAddress("eglWaitSyncKHR");
1308 assert(display->egl.wait_sync);
1309 }
1310
1311 return true;
1312
1313 error:
1314 return false;
1315 }
1316
1317 static bool
display_update_supported_modifiers_for_egl(struct display * d)1318 display_update_supported_modifiers_for_egl(struct display *d)
1319 {
1320 uint64_t *egl_modifiers = NULL;
1321 int num_egl_modifiers = 0;
1322 EGLBoolean ret;
1323 int i;
1324 bool try_modifiers = d->egl.has_dma_buf_import_modifiers;
1325
1326 if (try_modifiers) {
1327 ret = d->egl.query_dma_buf_modifiers(d->egl.display,
1328 BUFFER_FORMAT,
1329 0, /* max_modifiers */
1330 NULL, /* modifiers */
1331 NULL, /* external_only */
1332 &num_egl_modifiers);
1333 if (ret == EGL_FALSE) {
1334 fprintf(stderr, "Failed to query num EGL modifiers for format\n");
1335 goto error;
1336 }
1337 }
1338
1339 if (!num_egl_modifiers)
1340 try_modifiers = false;
1341
1342 /* If EGL doesn't support modifiers, don't use them at all. */
1343 if (!try_modifiers) {
1344 d->modifiers_count = 0;
1345 free(d->modifiers);
1346 d->modifiers = NULL;
1347 return true;
1348 }
1349
1350 egl_modifiers = zalloc(num_egl_modifiers * sizeof(*egl_modifiers));
1351
1352 ret = d->egl.query_dma_buf_modifiers(d->egl.display,
1353 BUFFER_FORMAT,
1354 num_egl_modifiers,
1355 egl_modifiers,
1356 NULL, /* external_only */
1357 &num_egl_modifiers);
1358 if (ret == EGL_FALSE) {
1359 fprintf(stderr, "Failed to query EGL modifiers for format\n");
1360 goto error;
1361 }
1362
1363 /* Poor person's set intersection: d->modifiers INTERSECT
1364 * egl_modifiers. If a modifier is not supported, replace it with
1365 * DRM_FORMAT_MOD_INVALID in the d->modifiers array.
1366 */
1367 for (i = 0; i < d->modifiers_count; ++i) {
1368 uint64_t mod = d->modifiers[i];
1369 bool egl_supported = false;
1370 int j;
1371
1372 for (j = 0; j < num_egl_modifiers; ++j) {
1373 if (egl_modifiers[j] == mod) {
1374 egl_supported = true;
1375 break;
1376 }
1377 }
1378
1379 if (!egl_supported)
1380 d->modifiers[i] = DRM_FORMAT_MOD_INVALID;
1381 }
1382
1383 free(egl_modifiers);
1384
1385 return true;
1386
1387 error:
1388 free(egl_modifiers);
1389
1390 return false;
1391 }
1392
1393 static bool
display_set_up_gbm(struct display * display,char const * drm_render_node)1394 display_set_up_gbm(struct display *display, char const* drm_render_node)
1395 {
1396 display->gbm.drm_fd = open(drm_render_node, O_RDWR);
1397 if (display->gbm.drm_fd < 0) {
1398 fprintf(stderr, "Failed to open drm render node %s\n",
1399 drm_render_node);
1400 return false;
1401 }
1402
1403 display->gbm.device = gbm_create_device(display->gbm.drm_fd);
1404 if (display->gbm.device == NULL) {
1405 fprintf(stderr, "Failed to create gbm device\n");
1406 return false;
1407 }
1408
1409 return true;
1410 }
1411
1412 static struct display *
create_display(char const * drm_render_node,int opts)1413 create_display(char const *drm_render_node, int opts)
1414 {
1415 struct display *display = NULL;
1416
1417 display = zalloc(sizeof *display);
1418 if (display == NULL) {
1419 fprintf(stderr, "out of memory\n");
1420 goto error;
1421 }
1422
1423 display->gbm.drm_fd = -1;
1424
1425 display->display = wl_display_connect(NULL);
1426 assert(display->display);
1427
1428 display->req_dmabuf_immediate = opts & OPT_IMMEDIATE;
1429
1430 display->registry = wl_display_get_registry(display->display);
1431 wl_registry_add_listener(display->registry,
1432 ®istry_listener, display);
1433 wl_display_roundtrip(display->display);
1434 if (display->dmabuf == NULL) {
1435 fprintf(stderr, "No zwp_linux_dmabuf global\n");
1436 goto error;
1437 }
1438
1439 wl_display_roundtrip(display->display);
1440
1441 if (!display->modifiers_count) {
1442 fprintf(stderr, "format XRGB8888 is not available\n");
1443 goto error;
1444 }
1445
1446 /* GBM needs to be initialized before EGL, so that we have a valid
1447 * render node gbm_device to create the EGL display from. */
1448 if (!display_set_up_gbm(display, drm_render_node))
1449 goto error;
1450
1451 if (!display_set_up_egl(display))
1452 goto error;
1453
1454 if (!display_update_supported_modifiers_for_egl(display))
1455 goto error;
1456
1457 /* We use explicit synchronization only if the user hasn't disabled it,
1458 * the compositor supports it, we can handle fence fds. */
1459 display->use_explicit_sync =
1460 !(opts & OPT_IMPLICIT_SYNC) &&
1461 display->explicit_sync &&
1462 display->egl.dup_native_fence_fd;
1463
1464 if (opts & OPT_IMPLICIT_SYNC) {
1465 fprintf(stderr, "Warning: Not using explicit sync, disabled by user\n");
1466 } else if (!display->explicit_sync) {
1467 fprintf(stderr,
1468 "Warning: zwp_linux_explicit_synchronization_v1 not supported,\n"
1469 " will not use explicit synchronization\n");
1470 } else if (!display->egl.dup_native_fence_fd) {
1471 fprintf(stderr,
1472 "Warning: EGL_ANDROID_native_fence_sync not supported,\n"
1473 " will not use explicit synchronization\n");
1474 } else if (!display->egl.wait_sync) {
1475 fprintf(stderr,
1476 "Warning: EGL_KHR_wait_sync not supported,\n"
1477 " will not use server-side wait\n");
1478 }
1479
1480 return display;
1481
1482 error:
1483 if (display != NULL)
1484 destroy_display(display);
1485 return NULL;
1486 }
1487
1488 static void
signal_int(int signum)1489 signal_int(int signum)
1490 {
1491 running = 0;
1492 }
1493
1494 static void
print_usage_and_exit(void)1495 print_usage_and_exit(void)
1496 {
1497 printf("usage flags:\n"
1498 "\t'-i,--import-immediate=<>'"
1499 "\n\t\t0 to import dmabuf via roundtrip, "
1500 "\n\t\t1 to enable import without roundtrip\n"
1501 "\t'-d,--drm-render-node=<>'"
1502 "\n\t\tthe full path to the drm render node to use\n"
1503 "\t'-s,--size=<>'"
1504 "\n\t\tthe window size in pixels (default: 256)\n"
1505 "\t'-e,--explicit-sync=<>'"
1506 "\n\t\t0 to disable explicit sync, "
1507 "\n\t\t1 to enable explicit sync (default: 1)\n"
1508 "\t'-m,--mandelbrot'"
1509 "\n\t\trender a mandelbrot set with multiple draw calls\n"
1510 "\t'-g,--direct-display'"
1511 "\n\t\tenables weston-direct-display extension to attempt "
1512 "direct scan-out;\n\t\tnote this will cause the image to be "
1513 "displayed inverted as GL uses a\n\t\tdifferent texture "
1514 "coordinate system\n");
1515 exit(0);
1516 }
1517
1518 static int
is_true(const char * c)1519 is_true(const char* c)
1520 {
1521 if (!strcmp(c, "1"))
1522 return 1;
1523 else if (!strcmp(c, "0"))
1524 return 0;
1525 else
1526 print_usage_and_exit();
1527
1528 return 0;
1529 }
1530
1531 int
main(int argc,char ** argv)1532 main(int argc, char **argv)
1533 {
1534 struct sigaction sigint;
1535 struct display *display;
1536 struct window *window;
1537 int opts = 0;
1538 char const *drm_render_node = "/dev/dri/card0";
1539 int c, option_index, ret = 0;
1540 int window_size = 256;
1541
1542 static struct option long_options[] = {
1543 {"import-immediate", required_argument, 0, 'i' },
1544 {"drm-render-node", required_argument, 0, 'd' },
1545 {"size", required_argument, 0, 's' },
1546 {"explicit-sync", required_argument, 0, 'e' },
1547 {"mandelbrot", no_argument, 0, 'm' },
1548 {"direct-display", no_argument, 0, 'g' },
1549 {"help", no_argument , 0, 'h' },
1550 {0, 0, 0, 0}
1551 };
1552
1553 while ((c = getopt_long(argc, argv, "hi:d:s:e:mg",
1554 long_options, &option_index)) != -1) {
1555 switch (c) {
1556 case 'i':
1557 if (is_true(optarg))
1558 opts |= OPT_IMMEDIATE;
1559 break;
1560 case 'd':
1561 drm_render_node = optarg;
1562 break;
1563 case 's':
1564 window_size = strtol(optarg, NULL, 10);
1565 break;
1566 case 'e':
1567 if (!is_true(optarg))
1568 opts |= OPT_IMPLICIT_SYNC;
1569 break;
1570 case 'm':
1571 opts |= OPT_MANDELBROT;
1572 break;
1573 case 'g':
1574 opts |= OPT_DIRECT_DISPLAY;
1575 break;
1576 default:
1577 print_usage_and_exit();
1578 }
1579 }
1580
1581 display = create_display(drm_render_node, opts);
1582 if (!display)
1583 return 1;
1584 window = create_window(display, window_size, window_size, opts);
1585 if (!window)
1586 return 1;
1587
1588 sigint.sa_handler = signal_int;
1589 sigemptyset(&sigint.sa_mask);
1590 sigint.sa_flags = SA_RESETHAND;
1591 sigaction(SIGINT, &sigint, NULL);
1592
1593 /* Here we retrieve the linux-dmabuf objects if executed without immed,
1594 * or error */
1595 wl_display_roundtrip(display->display);
1596
1597 if (!running)
1598 return 1;
1599
1600 window->initialized = true;
1601
1602 if (!window->wait_for_configure)
1603 redraw(window, NULL, 0);
1604
1605 fprintf(stderr,"pss %s %d, %s\n",__func__,__LINE__,__FILE__);
1606 while (running && ret != -1) {
1607 fprintf(stderr,"pss %s %d, %s\n",__func__,__LINE__,__FILE__);
1608 ret = wl_display_dispatch(display->display);
1609 }
1610
1611 fprintf(stderr, "simple-dmabuf-egl exiting\n");
1612 destroy_window(window);
1613 destroy_display(display);
1614
1615 return 0;
1616 }
1617