• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &params_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 				 &registry_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