• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <assert.h>
6 #include <memory.h>
7 #include <stdbool.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <poll.h>
15 #include <sys/ioctl.h>
16 #include <sys/mman.h>
17 #include <sys/socket.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <syslog.h>
21 #include <unistd.h>
22 
23 #include "aura-shell.h"
24 #include "linux-dmabuf-unstable-v1.h"
25 #include "viewporter.h"
26 #include "xdg-shell-unstable-v6.h"
27 #include <wayland-client-core.h>
28 #include <wayland-client-protocol.h>
29 #include <wayland-client.h>
30 
31 #define DEFAULT_SCALE 2
32 #define MAX_BUFFER_COUNT 64
33 
34 struct dwl_context;
35 
36 struct interfaces {
37 	struct dwl_context *context;
38 	struct wl_compositor *compositor;
39 	struct wl_subcompositor *subcompositor;
40 	struct wl_shm *shm;
41 	struct wl_shell *shell;
42 	struct wl_seat *seat;
43 	struct zaura_shell *aura; // optional
44 	struct zwp_linux_dmabuf_v1 *linux_dmabuf;
45 	struct zxdg_shell_v6 *xdg_shell;
46 	struct wp_viewporter *viewporter; // optional
47 };
48 
49 struct output {
50 	struct wl_output *output;
51 	struct zaura_output *aura_output;
52 	struct dwl_context *context;
53 	uint32_t id;
54 	uint32_t current_scale;
55 	uint32_t device_scale_factor;
56 	bool internal;
57 };
58 
59 struct dwl_context {
60 	struct wl_display *display;
61 	struct interfaces ifaces;
62 	bool output_added;
63 	struct output outputs[8];
64 };
65 
66 #define outputs_for_each(context, pos, output)                                 \
67 	for (pos = 0, output = &context->outputs[pos];                         \
68 	     pos < (sizeof(context->outputs) / sizeof(context->outputs[0]));   \
69 	     pos++, output = &context->outputs[pos])
70 
71 struct dwl_dmabuf {
72 	uint32_t width;
73 	uint32_t height;
74 	bool in_use;
75 	struct wl_buffer *buffer;
76 };
77 
78 struct dwl_surface {
79 	struct dwl_context *context;
80 	struct wl_surface *surface;
81 	struct zaura_surface *aura;
82 	struct zxdg_surface_v6 *xdg;
83 	struct zxdg_toplevel_v6 *toplevel;
84 	struct wp_viewport *viewport;
85 	struct wl_subsurface *subsurface;
86 	uint32_t width;
87 	uint32_t height;
88 	double scale;
89 	bool close_requested;
90 	size_t buffer_count;
91 	uint64_t buffer_use_bit_mask;
92 	struct wl_buffer *buffers[0];
93 };
94 
95 static_assert(sizeof(((struct dwl_surface *)0)->buffer_use_bit_mask) * 8 >=
96 		  MAX_BUFFER_COUNT,
97 	      "not enough bits in buffer_use_bit_mask");
98 
output_geometry(void * data,struct wl_output * output,int x,int y,int physical_width,int physical_height,int subpixel,const char * make,const char * model,int transform)99 static void output_geometry(void *data, struct wl_output *output, int x, int y,
100 			    int physical_width, int physical_height,
101 			    int subpixel, const char *make, const char *model,
102 			    int transform)
103 {
104 	(void)data;
105 	(void)output;
106 	(void)x;
107 	(void)y;
108 	(void)physical_width;
109 	(void)physical_height;
110 	(void)subpixel;
111 	(void)make;
112 	(void)model;
113 	(void)transform;
114 }
115 
output_mode(void * data,struct wl_output * output,uint32_t flags,int width,int height,int refresh)116 static void output_mode(void *data, struct wl_output *output, uint32_t flags,
117 			int width, int height, int refresh)
118 {
119 	(void)data;
120 	(void)output;
121 	(void)flags;
122 	(void)width;
123 	(void)height;
124 	(void)refresh;
125 }
126 
output_done(void * data,struct wl_output * output)127 static void output_done(void *data, struct wl_output *output)
128 {
129 	(void)data;
130 	(void)output;
131 }
132 
output_scale(void * data,struct wl_output * wl_output,int32_t scale_factor)133 static void output_scale(void *data, struct wl_output *wl_output,
134 			 int32_t scale_factor)
135 {
136 	(void)wl_output;
137 	struct output *output = (struct output *)data;
138 	struct dwl_context *context = output->context;
139 
140 	// If the aura interface is available, we prefer the scale factor
141 	// reported by that.
142 	if (context->ifaces.aura)
143 		return;
144 
145 	output->current_scale = 1000 * scale_factor;
146 }
147 
148 static const struct wl_output_listener output_listener = {
149     .geometry = output_geometry,
150     .mode = output_mode,
151     .done = output_done,
152     .scale = output_scale};
153 
aura_output_scale(void * data,struct zaura_output * aura_output,uint32_t flags,uint32_t scale)154 static void aura_output_scale(void *data, struct zaura_output *aura_output,
155 			      uint32_t flags, uint32_t scale)
156 {
157 	(void)aura_output;
158 	struct output *output = (struct output *)data;
159 	if (flags & ZAURA_OUTPUT_SCALE_PROPERTY_CURRENT) {
160 		output->current_scale = scale;
161 	}
162 }
163 
aura_output_connection(void * data,struct zaura_output * aura_output,uint32_t connection)164 static void aura_output_connection(void *data, struct zaura_output *aura_output,
165 				   uint32_t connection)
166 {
167 	(void)aura_output;
168 	struct output *output = (struct output *)data;
169 	output->internal = connection == ZAURA_OUTPUT_CONNECTION_TYPE_INTERNAL;
170 }
171 
aura_output_device_scale_factor(void * data,struct zaura_output * aura_output,uint32_t device_scale_factor)172 static void aura_output_device_scale_factor(void *data,
173 					    struct zaura_output *aura_output,
174 					    uint32_t device_scale_factor)
175 {
176 	(void)aura_output;
177 	struct output *output = (struct output *)data;
178 	output->device_scale_factor = device_scale_factor;
179 }
180 
181 static const struct zaura_output_listener aura_output_listener = {
182     .scale = aura_output_scale,
183     .connection = aura_output_connection,
184     .device_scale_factor = aura_output_device_scale_factor};
185 
dwl_context_output_add(struct dwl_context * context,struct wl_output * wl_output,uint32_t id)186 static void dwl_context_output_add(struct dwl_context *context,
187 				   struct wl_output *wl_output, uint32_t id)
188 {
189 	size_t i;
190 	struct output *output;
191 	outputs_for_each(context, i, output)
192 	{
193 		if (output->output == NULL) {
194 			context->output_added = true;
195 			output->id = id;
196 			output->output = wl_output;
197 			output->context = context;
198 			output->current_scale = 1000;
199 			output->device_scale_factor = 1000;
200 			// This is a fun little hack from reveman. The idea is
201 			// that the first display will be internal and never get
202 			// removed.
203 			output->internal = i == 0;
204 			wl_output_add_listener(output->output, &output_listener,
205 					       output);
206 			return;
207 		}
208 	}
209 }
210 
dwl_context_output_remove_destroy(struct dwl_context * context,uint32_t id)211 static void dwl_context_output_remove_destroy(struct dwl_context *context,
212 					      uint32_t id)
213 {
214 	size_t i;
215 	struct output *output;
216 	outputs_for_each(context, i, output)
217 	{
218 		if (output->id == id) {
219 			if (output->aura_output)
220 				zaura_output_destroy(output->aura_output);
221 			wl_output_destroy(output->output);
222 			memset(output, 0, sizeof(struct output));
223 			return;
224 		}
225 	}
226 }
227 
dwl_context_output_get_aura(struct dwl_context * context)228 static void dwl_context_output_get_aura(struct dwl_context *context)
229 {
230 	if (!context->ifaces.aura)
231 		return;
232 
233 	size_t i;
234 	struct output *output;
235 	outputs_for_each(context, i, output)
236 	{
237 		if (output->output != NULL && output->aura_output == NULL) {
238 			output->aura_output = zaura_shell_get_aura_output(
239 			    context->ifaces.aura, output->output);
240 			zaura_output_add_listener(
241 			    output->aura_output, &aura_output_listener, output);
242 		}
243 	}
244 }
245 
registry_global(void * data,struct wl_registry * registry,uint32_t id,const char * interface,uint32_t version)246 static void registry_global(void *data, struct wl_registry *registry,
247 			    uint32_t id, const char *interface,
248 			    uint32_t version)
249 {
250 	(void)version;
251 	struct interfaces *ifaces = (struct interfaces *)data;
252 	if (strcmp(interface, "wl_compositor") == 0) {
253 		ifaces->compositor = (struct wl_compositor *)wl_registry_bind(
254 		    registry, id, &wl_compositor_interface, 3);
255 	} else if (strcmp(interface, "wl_subcompositor") == 0) {
256 		ifaces->subcompositor =
257 		    (struct wl_subcompositor *)wl_registry_bind(
258 			registry, id, &wl_subcompositor_interface, 1);
259 	} else if (strcmp(interface, "wl_shm") == 0) {
260 		ifaces->shm = (struct wl_shm *)wl_registry_bind(
261 		    registry, id, &wl_shm_interface, 1);
262 	} else if (strcmp(interface, "wl_seat") == 0) {
263 		ifaces->seat = (struct wl_seat *)wl_registry_bind(
264 		    registry, id, &wl_seat_interface, 5);
265 	} else if (strcmp(interface, "wl_output") == 0) {
266 		struct wl_output *output = (struct wl_output *)wl_registry_bind(
267 		    registry, id, &wl_output_interface, 2);
268 		dwl_context_output_add(ifaces->context, output, id);
269 	} else if (strcmp(interface, "zaura_shell") == 0 && version >= 6) {
270 		ifaces->aura = (struct zaura_shell *)wl_registry_bind(
271 		    registry, id, &zaura_shell_interface, 6);
272 	} else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0) {
273 		ifaces->linux_dmabuf =
274 		    (struct zwp_linux_dmabuf_v1 *)wl_registry_bind(
275 			registry, id, &zwp_linux_dmabuf_v1_interface, 1);
276 	} else if (strcmp(interface, "zxdg_shell_v6") == 0) {
277 		ifaces->xdg_shell = (struct zxdg_shell_v6 *)wl_registry_bind(
278 		    registry, id, &zxdg_shell_v6_interface, 1);
279 	} else if (strcmp(interface, "wp_viewporter") == 0) {
280 		ifaces->viewporter = (struct wp_viewporter *)wl_registry_bind(
281 		    registry, id, &wp_viewporter_interface, 1);
282 	}
283 }
284 
global_remove(void * data,struct wl_registry * registry,uint32_t id)285 static void global_remove(void *data, struct wl_registry *registry, uint32_t id)
286 {
287 	(void)registry;
288 
289 	struct interfaces *ifaces = (struct interfaces *)data;
290 	// If the ID matches any output, this will remove it. Otherwise, this is
291 	// a no-op.
292 	dwl_context_output_remove_destroy(ifaces->context, id);
293 
294 	if (ifaces->aura &&
295 	    wl_proxy_get_id((struct wl_proxy *)ifaces->aura) == id) {
296 		zaura_shell_destroy(ifaces->aura);
297 		ifaces->aura = NULL;
298 	}
299 
300 	// TODO(zachr): deal with the removal of some of the required
301 	// interfaces.
302 }
303 
304 static const struct wl_registry_listener registry_listener = {
305     .global = registry_global, .global_remove = global_remove};
306 
toplevel_configure(void * data,struct zxdg_toplevel_v6 * zxdg_toplevel_v6,int32_t width,int32_t height,struct wl_array * states)307 static void toplevel_configure(void *data,
308 			       struct zxdg_toplevel_v6 *zxdg_toplevel_v6,
309 			       int32_t width, int32_t height,
310 			       struct wl_array *states)
311 {
312 	(void)data;
313 	(void)zxdg_toplevel_v6;
314 	(void)width;
315 	(void)height;
316 	(void)states;
317 }
318 
toplevel_close(void * data,struct zxdg_toplevel_v6 * zxdg_toplevel_v6)319 static void toplevel_close(void *data,
320 			   struct zxdg_toplevel_v6 *zxdg_toplevel_v6)
321 {
322 	(void)zxdg_toplevel_v6;
323 	struct dwl_surface *surface = (struct dwl_surface *)data;
324 	surface->close_requested = true;
325 }
326 
327 static const struct zxdg_toplevel_v6_listener toplevel_listener = {
328     .configure = toplevel_configure, .close = toplevel_close};
329 
xdg_surface_configure_handler(void * data,struct zxdg_surface_v6 * xdg_surface,uint32_t serial)330 static void xdg_surface_configure_handler(void *data,
331 					  struct zxdg_surface_v6 *xdg_surface,
332 					  uint32_t serial)
333 {
334 	(void)data;
335 	zxdg_surface_v6_ack_configure(xdg_surface, serial);
336 }
337 
338 static const struct zxdg_surface_v6_listener xdg_surface_listener = {
339 	.configure = xdg_surface_configure_handler
340 };
341 
surface_enter(void * data,struct wl_surface * wl_surface,struct wl_output * wl_output)342 static void surface_enter(void *data, struct wl_surface *wl_surface,
343 			  struct wl_output *wl_output)
344 {
345 	struct dwl_surface *surface = (struct dwl_surface *)data;
346 
347 	struct output *output =
348 	    (struct output *)wl_output_get_user_data(wl_output);
349 
350 	surface->scale = (output->device_scale_factor / 1000.0) *
351 			 (output->current_scale / 1000.0);
352 
353 	if (surface->viewport) {
354 		wp_viewport_set_destination(
355 		    surface->viewport, ceil(surface->width / surface->scale),
356 		    ceil(surface->height / surface->scale));
357 	} else {
358 		wl_surface_set_buffer_scale(wl_surface, surface->scale);
359 	}
360 
361 	wl_surface_commit(wl_surface);
362 }
363 
surface_leave(void * data,struct wl_surface * wl_surface,struct wl_output * output)364 static void surface_leave(void *data, struct wl_surface *wl_surface,
365 			  struct wl_output *output)
366 {
367 	(void)data;
368 	(void)wl_surface;
369 	(void)output;
370 }
371 
372 static const struct wl_surface_listener surface_listener = {
373     .enter = surface_enter, .leave = surface_leave};
374 
dwl_context_new()375 struct dwl_context *dwl_context_new()
376 {
377 	struct dwl_context *ctx = calloc(1, sizeof(struct dwl_context));
378 	ctx->ifaces.context = ctx;
379 	return ctx;
380 }
381 
dwl_context_destroy(struct dwl_context ** self)382 void dwl_context_destroy(struct dwl_context **self)
383 {
384 	if ((*self)->display)
385 		wl_display_disconnect((*self)->display);
386 	free(*self);
387 	*self = NULL;
388 }
389 
dwl_context_setup(struct dwl_context * self,const char * socket_path)390 bool dwl_context_setup(struct dwl_context *self, const char *socket_path)
391 {
392 	struct wl_display *display = wl_display_connect(socket_path);
393 	if (!display) {
394 		syslog(LOG_ERR, "failed to connect to display");
395 		return false;
396 	}
397 	self->display = display;
398 	wl_display_set_user_data(display, self);
399 
400 	struct wl_registry *registry = wl_display_get_registry(display);
401 	if (!registry) {
402 		syslog(LOG_ERR, "failed to get registry");
403 		goto fail;
404 	}
405 
406 	struct interfaces *ifaces = &self->ifaces;
407 	wl_registry_add_listener(registry, &registry_listener, ifaces);
408 	wl_display_roundtrip(display);
409 	dwl_context_output_get_aura(self);
410 
411 	if (!ifaces->shm) {
412 		syslog(LOG_ERR, "missing interface shm");
413 		goto fail;
414 	}
415 	if (!ifaces->compositor) {
416 		syslog(LOG_ERR, "missing interface compositor");
417 		goto fail;
418 	}
419 	if (!ifaces->subcompositor) {
420 		syslog(LOG_ERR, "missing interface subcompositor");
421 		goto fail;
422 	}
423 	if (!ifaces->seat) {
424 		syslog(LOG_ERR, "missing interface seat");
425 		goto fail;
426 	}
427 	if (!ifaces->linux_dmabuf) {
428 		syslog(LOG_ERR, "missing interface linux_dmabuf");
429 		goto fail;
430 	}
431 	if (!ifaces->xdg_shell) {
432 		syslog(LOG_ERR, "missing interface xdg_shell");
433 		goto fail;
434 	}
435 
436 	return true;
437 
438 fail:
439 	wl_display_disconnect(display);
440 	self->display = NULL;
441 	return false;
442 }
443 
dwl_context_fd(struct dwl_context * self)444 int dwl_context_fd(struct dwl_context *self)
445 {
446 	return wl_display_get_fd(self->display);
447 }
448 
dwl_context_dispatch(struct dwl_context * self)449 void dwl_context_dispatch(struct dwl_context *self)
450 {
451 	wl_display_dispatch(self->display);
452 	if (self->output_added) {
453 		self->output_added = false;
454 		dwl_context_output_get_aura(self);
455 		wl_display_roundtrip(self->display);
456 	}
457 }
458 
linux_buffer_created(void * data,struct zwp_linux_buffer_params_v1 * zwp_linux_buffer_params_v1,struct wl_buffer * buffer)459 static void linux_buffer_created(
460     void *data, struct zwp_linux_buffer_params_v1 *zwp_linux_buffer_params_v1,
461     struct wl_buffer *buffer)
462 {
463 	(void)zwp_linux_buffer_params_v1;
464 	struct dwl_dmabuf *dmabuf = (struct dwl_dmabuf *)data;
465 	dmabuf->buffer = buffer;
466 }
467 
linux_buffer_failed(void * data,struct zwp_linux_buffer_params_v1 * zwp_linux_buffer_params_v1)468 static void linux_buffer_failed(
469     void *data, struct zwp_linux_buffer_params_v1 *zwp_linux_buffer_params_v1)
470 {
471 	(void)data;
472 	(void)zwp_linux_buffer_params_v1;
473 }
474 
475 static const struct zwp_linux_buffer_params_v1_listener linux_buffer_listener =
476     {.created = linux_buffer_created, .failed = linux_buffer_failed};
477 
dmabuf_buffer_release(void * data,struct wl_buffer * buffer)478 static void dmabuf_buffer_release(void *data, struct wl_buffer *buffer)
479 {
480 	struct dwl_dmabuf *dmabuf = (struct dwl_dmabuf *)data;
481 	(void)buffer;
482 
483 	dmabuf->in_use = false;
484 }
485 
486 static const struct wl_buffer_listener dmabuf_buffer_listener = {
487     .release = dmabuf_buffer_release};
488 
dwl_context_dmabuf_new(struct dwl_context * self,int fd,uint32_t offset,uint32_t stride,uint64_t modifiers,uint32_t width,uint32_t height,uint32_t fourcc)489 struct dwl_dmabuf *dwl_context_dmabuf_new(struct dwl_context *self, int fd,
490 					  uint32_t offset, uint32_t stride,
491 					  uint64_t modifiers, uint32_t width,
492 					  uint32_t height, uint32_t fourcc)
493 {
494 	struct dwl_dmabuf *dmabuf = calloc(1, sizeof(struct dwl_dmabuf));
495 	if (!dmabuf) {
496 		syslog(LOG_ERR, "failed to allocate dwl_dmabuf");
497 		return NULL;
498 	}
499 	dmabuf->width = width;
500 	dmabuf->height = height;
501 
502 	struct zwp_linux_buffer_params_v1 *params =
503 	    zwp_linux_dmabuf_v1_create_params(self->ifaces.linux_dmabuf);
504 	if (!params) {
505 		syslog(LOG_ERR,
506 		       "failed to allocate zwp_linux_buffer_params_v1");
507 		free(dmabuf);
508 		return NULL;
509 	}
510 
511 	zwp_linux_buffer_params_v1_add_listener(params, &linux_buffer_listener,
512 						dmabuf);
513 	zwp_linux_buffer_params_v1_add(params, fd, 0 /* plane_idx */, offset,
514 				       stride, modifiers >> 32,
515 				       (uint32_t)modifiers);
516 	zwp_linux_buffer_params_v1_create(params, width, height, fourcc, 0);
517 	wl_display_roundtrip(self->display);
518 	zwp_linux_buffer_params_v1_destroy(params);
519 
520 	if (!dmabuf->buffer) {
521 		syslog(LOG_ERR, "failed to get wl_buffer for dmabuf");
522 		free(dmabuf);
523 		return NULL;
524 	}
525 
526 	wl_buffer_add_listener(dmabuf->buffer, &dmabuf_buffer_listener, dmabuf);
527 
528 	return dmabuf;
529 }
530 
dwl_dmabuf_destroy(struct dwl_dmabuf ** self)531 void dwl_dmabuf_destroy(struct dwl_dmabuf **self)
532 {
533 	wl_buffer_destroy((*self)->buffer);
534 	free(*self);
535 	*self = NULL;
536 }
537 
surface_buffer_release(void * data,struct wl_buffer * buffer)538 static void surface_buffer_release(void *data, struct wl_buffer *buffer)
539 {
540 	struct dwl_surface *surface = (struct dwl_surface *)data;
541 	(void)buffer;
542 
543 	size_t i;
544 	for (i = 0; i < surface->buffer_count; i++) {
545 		if (buffer == surface->buffers[i]) {
546 			surface->buffer_use_bit_mask &= ~(1 << i);
547 			break;
548 		}
549 	}
550 }
551 
552 static const struct wl_buffer_listener surface_buffer_listener = {
553     .release = surface_buffer_release};
554 
dwl_context_surface_new(struct dwl_context * self,struct dwl_surface * parent,int shm_fd,size_t shm_size,size_t buffer_size,uint32_t width,uint32_t height,uint32_t stride)555 struct dwl_surface *dwl_context_surface_new(struct dwl_context *self,
556 					    struct dwl_surface *parent,
557 					    int shm_fd, size_t shm_size,
558 					    size_t buffer_size, uint32_t width,
559 					    uint32_t height, uint32_t stride)
560 {
561 	if (buffer_size == 0)
562 		return NULL;
563 	size_t buffer_count = shm_size / buffer_size;
564 	if (buffer_count == 0)
565 		return NULL;
566 	if (buffer_count > MAX_BUFFER_COUNT)
567 		return NULL;
568 
569 	struct dwl_surface *disp_surface =
570 	    calloc(1, sizeof(struct dwl_surface) +
571 			  sizeof(struct wl_buffer *) * buffer_count);
572 	if (!disp_surface)
573 		return NULL;
574 	disp_surface->context = self;
575 	disp_surface->width = width;
576 	disp_surface->height = height;
577 	disp_surface->scale = DEFAULT_SCALE;
578 	disp_surface->buffer_count = buffer_count;
579 
580 	struct wl_region *region = NULL;
581 	struct wl_shm_pool *shm_pool =
582 	    wl_shm_create_pool(self->ifaces.shm, shm_fd, shm_size);
583 	if (!shm_pool) {
584 		syslog(LOG_ERR, "failed to make shm pool");
585 		goto fail;
586 	}
587 
588 	size_t i;
589 	for (i = 0; i < buffer_count; i++) {
590 		struct wl_buffer *buffer = wl_shm_pool_create_buffer(
591 		    shm_pool, buffer_size * i, width, height, stride,
592 		    WL_SHM_FORMAT_ARGB8888);
593 		if (!buffer) {
594 			syslog(LOG_ERR, "failed to create buffer");
595 			goto fail;
596 		}
597 		disp_surface->buffers[i] = buffer;
598 	}
599 
600 	for (i = 0; i < buffer_count; i++)
601 		wl_buffer_add_listener(disp_surface->buffers[i],
602 				       &surface_buffer_listener, disp_surface);
603 
604 	disp_surface->surface =
605 	    wl_compositor_create_surface(self->ifaces.compositor);
606 	if (!disp_surface->surface) {
607 		syslog(LOG_ERR, "failed to make surface");
608 		goto fail;
609 	}
610 
611 	wl_surface_add_listener(disp_surface->surface, &surface_listener,
612 				disp_surface);
613 
614 	region = wl_compositor_create_region(self->ifaces.compositor);
615 	if (!region) {
616 		syslog(LOG_ERR, "failed to make region");
617 		goto fail;
618 	}
619 	wl_region_add(region, 0, 0, width, height);
620 	wl_surface_set_opaque_region(disp_surface->surface, region);
621 
622 	if (!parent) {
623 		disp_surface->xdg = zxdg_shell_v6_get_xdg_surface(
624 		    self->ifaces.xdg_shell, disp_surface->surface);
625 		if (!disp_surface->xdg) {
626 			syslog(LOG_ERR, "failed to make xdg shell surface");
627 			goto fail;
628 		}
629 
630 		disp_surface->toplevel =
631 		    zxdg_surface_v6_get_toplevel(disp_surface->xdg);
632 		if (!disp_surface->toplevel) {
633 			syslog(LOG_ERR,
634 			       "failed to make toplevel xdg shell surface");
635 			goto fail;
636 		}
637 		zxdg_toplevel_v6_set_title(disp_surface->toplevel, "crosvm");
638 		zxdg_toplevel_v6_add_listener(disp_surface->toplevel,
639 					      &toplevel_listener, disp_surface);
640 
641 		zxdg_surface_v6_add_listener(disp_surface->xdg,
642 					     &xdg_surface_listener,
643 					     NULL);
644 		if (self->ifaces.aura) {
645 			disp_surface->aura = zaura_shell_get_aura_surface(
646 			    self->ifaces.aura, disp_surface->surface);
647 			if (!disp_surface->aura) {
648 				syslog(LOG_ERR, "failed to make aura surface");
649 				goto fail;
650 			}
651 			zaura_surface_set_frame(
652 			    disp_surface->aura,
653 			    ZAURA_SURFACE_FRAME_TYPE_NORMAL);
654 		}
655 
656 		// signal that the surface is ready to be configured
657 		wl_surface_commit(disp_surface->surface);
658 
659 		// wait for the surface to be configured
660 		wl_display_roundtrip(self->display);
661 	} else {
662 		disp_surface->subsurface = wl_subcompositor_get_subsurface(
663 		    self->ifaces.subcompositor, disp_surface->surface,
664 		    parent->surface);
665 		if (!disp_surface->subsurface) {
666 			syslog(LOG_ERR, "failed to make subsurface");
667 			goto fail;
668 		}
669 		wl_subsurface_set_desync(disp_surface->subsurface);
670 	}
671 
672 	if (self->ifaces.viewporter) {
673 		disp_surface->viewport = wp_viewporter_get_viewport(
674 		    self->ifaces.viewporter, disp_surface->surface);
675 		if (!disp_surface->viewport) {
676 			syslog(LOG_ERR, "failed to make surface viewport");
677 			goto fail;
678 		}
679 	}
680 
681 	wl_surface_attach(disp_surface->surface, disp_surface->buffers[0], 0,
682 			  0);
683 	wl_surface_damage(disp_surface->surface, 0, 0, width, height);
684 	wl_region_destroy(region);
685 	wl_shm_pool_destroy(shm_pool);
686 
687 	// Needed to get outputs before iterating them.
688 	wl_display_roundtrip(self->display);
689 
690 	// Assuming that this surface will enter the internal output initially,
691 	// trigger a surface enter for that output before doing the first
692 	// surface commit. THis is to avoid unpleasant artifacts when the
693 	// surface first appears.
694 	struct output *output;
695 	outputs_for_each(self, i, output)
696 	{
697 		if (output->internal) {
698 			surface_enter(disp_surface, disp_surface->surface,
699 				      output->output);
700 		}
701 	}
702 
703 	wl_surface_commit(disp_surface->surface);
704 	wl_display_flush(self->display);
705 
706 	return disp_surface;
707 fail:
708 	if (disp_surface->viewport)
709 		wp_viewport_destroy(disp_surface->viewport);
710 	if (disp_surface->subsurface)
711 		wl_subsurface_destroy(disp_surface->subsurface);
712 	if (disp_surface->toplevel)
713 		zxdg_toplevel_v6_destroy(disp_surface->toplevel);
714 	if (disp_surface->xdg)
715 		zxdg_surface_v6_destroy(disp_surface->xdg);
716 	if (disp_surface->aura)
717 		zaura_surface_destroy(disp_surface->aura);
718 	if (region)
719 		wl_region_destroy(region);
720 	if (disp_surface->surface)
721 		wl_surface_destroy(disp_surface->surface);
722 	for (i = 0; i < buffer_count; i++)
723 		if (disp_surface->buffers[i])
724 			wl_buffer_destroy(disp_surface->buffers[i]);
725 	if (shm_pool)
726 		wl_shm_pool_destroy(shm_pool);
727 	free(disp_surface);
728 	return NULL;
729 }
730 
dwl_surface_destroy(struct dwl_surface ** self)731 void dwl_surface_destroy(struct dwl_surface **self)
732 {
733 	size_t i;
734 	if ((*self)->viewport)
735 		wp_viewport_destroy((*self)->viewport);
736 	if ((*self)->subsurface)
737 		wl_subsurface_destroy((*self)->subsurface);
738 	if ((*self)->toplevel)
739 		zxdg_toplevel_v6_destroy((*self)->toplevel);
740 	if ((*self)->xdg)
741 		zxdg_surface_v6_destroy((*self)->xdg);
742 	if ((*self)->aura)
743 		zaura_surface_destroy((*self)->aura);
744 	if ((*self)->surface)
745 		wl_surface_destroy((*self)->surface);
746 	for (i = 0; i < (*self)->buffer_count; i++)
747 		wl_buffer_destroy((*self)->buffers[i]);
748 	wl_display_flush((*self)->context->display);
749 	free(*self);
750 	*self = NULL;
751 }
752 
dwl_surface_commit(struct dwl_surface * self)753 void dwl_surface_commit(struct dwl_surface *self)
754 {
755 	// It is possible that we are committing frames faster than the
756 	// compositor can put them on the screen. This may result in dropped
757 	// frames, but this is acceptable considering there is no good way to
758 	// apply back pressure to the guest gpu driver right now. The intention
759 	// of this module is to help bootstrap gpu support, so it does not have
760 	// to have artifact free rendering.
761 	wl_surface_commit(self->surface);
762 	wl_display_flush(self->context->display);
763 }
764 
dwl_surface_buffer_in_use(struct dwl_surface * self,size_t buffer_index)765 bool dwl_surface_buffer_in_use(struct dwl_surface *self, size_t buffer_index)
766 {
767 	return (self->buffer_use_bit_mask & (1 << buffer_index)) != 0;
768 }
769 
dwl_surface_flip(struct dwl_surface * self,size_t buffer_index)770 void dwl_surface_flip(struct dwl_surface *self, size_t buffer_index)
771 {
772 	if (buffer_index >= self->buffer_count)
773 		return;
774 	wl_surface_attach(self->surface, self->buffers[buffer_index], 0, 0);
775 	wl_surface_damage(self->surface, 0, 0, self->width, self->height);
776 	dwl_surface_commit(self);
777 	self->buffer_use_bit_mask |= 1 << buffer_index;
778 }
779 
dwl_surface_flip_to(struct dwl_surface * self,struct dwl_dmabuf * dmabuf)780 void dwl_surface_flip_to(struct dwl_surface *self, struct dwl_dmabuf *dmabuf)
781 {
782 	if (self->width != dmabuf->width || self->height != dmabuf->height)
783 		return;
784 	wl_surface_attach(self->surface, dmabuf->buffer, 0, 0);
785 	wl_surface_damage(self->surface, 0, 0, self->width, self->height);
786 	dwl_surface_commit(self);
787 	dmabuf->in_use = true;
788 }
789 
dwl_surface_close_requested(const struct dwl_surface * self)790 bool dwl_surface_close_requested(const struct dwl_surface *self)
791 {
792 	return self->close_requested;
793 }
794 
dwl_surface_set_position(struct dwl_surface * self,uint32_t x,uint32_t y)795 void dwl_surface_set_position(struct dwl_surface *self, uint32_t x, uint32_t y)
796 {
797 	if (self->subsurface) {
798 		wl_subsurface_set_position(self->subsurface, x / self->scale,
799 					   y / self->scale);
800 		wl_surface_commit(self->surface);
801 		wl_display_flush(self->context->display);
802 	}
803 }
804