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
surface_enter(void * data,struct wl_surface * wl_surface,struct wl_output * wl_output)330 static void surface_enter(void *data, struct wl_surface *wl_surface,
331 struct wl_output *wl_output)
332 {
333 struct dwl_surface *surface = (struct dwl_surface *)data;
334
335 struct output *output =
336 (struct output *)wl_output_get_user_data(wl_output);
337
338 surface->scale = (output->device_scale_factor / 1000.0) *
339 (output->current_scale / 1000.0);
340
341 if (surface->viewport) {
342 wp_viewport_set_destination(
343 surface->viewport, ceil(surface->width / surface->scale),
344 ceil(surface->height / surface->scale));
345 } else {
346 wl_surface_set_buffer_scale(wl_surface, surface->scale);
347 }
348
349 wl_surface_commit(wl_surface);
350 }
351
surface_leave(void * data,struct wl_surface * wl_surface,struct wl_output * output)352 static void surface_leave(void *data, struct wl_surface *wl_surface,
353 struct wl_output *output)
354 {
355 (void)data;
356 (void)wl_surface;
357 (void)output;
358 }
359
360 static const struct wl_surface_listener surface_listener = {
361 .enter = surface_enter, .leave = surface_leave};
362
dwl_context_new()363 struct dwl_context *dwl_context_new()
364 {
365 struct dwl_context *ctx = calloc(1, sizeof(struct dwl_context));
366 ctx->ifaces.context = ctx;
367 return ctx;
368 }
369
dwl_context_destroy(struct dwl_context ** self)370 void dwl_context_destroy(struct dwl_context **self)
371 {
372 if ((*self)->display)
373 wl_display_disconnect((*self)->display);
374 free(*self);
375 *self = NULL;
376 }
377
dwl_context_setup(struct dwl_context * self,const char * socket_path)378 bool dwl_context_setup(struct dwl_context *self, const char *socket_path)
379 {
380 struct wl_display *display = wl_display_connect(socket_path);
381 if (!display) {
382 syslog(LOG_ERR, "failed to connect to display");
383 return false;
384 }
385 self->display = display;
386 wl_display_set_user_data(display, self);
387
388 struct wl_registry *registry = wl_display_get_registry(display);
389 if (!registry) {
390 syslog(LOG_ERR, "failed to get registry");
391 goto fail;
392 }
393
394 struct interfaces *ifaces = &self->ifaces;
395 wl_registry_add_listener(registry, ®istry_listener, ifaces);
396 wl_display_roundtrip(display);
397 dwl_context_output_get_aura(self);
398
399 if (!ifaces->shm) {
400 syslog(LOG_ERR, "missing interface shm");
401 goto fail;
402 }
403 if (!ifaces->compositor) {
404 syslog(LOG_ERR, "missing interface compositor");
405 goto fail;
406 }
407 if (!ifaces->subcompositor) {
408 syslog(LOG_ERR, "missing interface subcompositor");
409 goto fail;
410 }
411 if (!ifaces->seat) {
412 syslog(LOG_ERR, "missing interface seat");
413 goto fail;
414 }
415 if (!ifaces->linux_dmabuf) {
416 syslog(LOG_ERR, "missing interface linux_dmabuf");
417 goto fail;
418 }
419 if (!ifaces->xdg_shell) {
420 syslog(LOG_ERR, "missing interface xdg_shell");
421 goto fail;
422 }
423
424 return true;
425
426 fail:
427 wl_display_disconnect(display);
428 return false;
429 }
430
dwl_context_fd(struct dwl_context * self)431 int dwl_context_fd(struct dwl_context *self)
432 {
433 return wl_display_get_fd(self->display);
434 }
435
dwl_context_dispatch(struct dwl_context * self)436 void dwl_context_dispatch(struct dwl_context *self)
437 {
438 wl_display_dispatch(self->display);
439 if (self->output_added) {
440 self->output_added = false;
441 dwl_context_output_get_aura(self);
442 wl_display_roundtrip(self->display);
443 }
444 }
445
linux_buffer_created(void * data,struct zwp_linux_buffer_params_v1 * zwp_linux_buffer_params_v1,struct wl_buffer * buffer)446 static void linux_buffer_created(
447 void *data, struct zwp_linux_buffer_params_v1 *zwp_linux_buffer_params_v1,
448 struct wl_buffer *buffer)
449 {
450 (void)zwp_linux_buffer_params_v1;
451 struct dwl_dmabuf *dmabuf = (struct dwl_dmabuf *)data;
452 dmabuf->buffer = buffer;
453 }
454
linux_buffer_failed(void * data,struct zwp_linux_buffer_params_v1 * zwp_linux_buffer_params_v1)455 static void linux_buffer_failed(
456 void *data, struct zwp_linux_buffer_params_v1 *zwp_linux_buffer_params_v1)
457 {
458 (void)data;
459 (void)zwp_linux_buffer_params_v1;
460 }
461
462 static const struct zwp_linux_buffer_params_v1_listener linux_buffer_listener =
463 {.created = linux_buffer_created, .failed = linux_buffer_failed};
464
dmabuf_buffer_release(void * data,struct wl_buffer * buffer)465 static void dmabuf_buffer_release(void *data, struct wl_buffer *buffer)
466 {
467 struct dwl_dmabuf *dmabuf = (struct dwl_dmabuf *)data;
468 (void)buffer;
469
470 dmabuf->in_use = false;
471 }
472
473 static const struct wl_buffer_listener dmabuf_buffer_listener = {
474 .release = dmabuf_buffer_release};
475
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)476 struct dwl_dmabuf *dwl_context_dmabuf_new(struct dwl_context *self, int fd,
477 uint32_t offset, uint32_t stride,
478 uint64_t modifiers, uint32_t width,
479 uint32_t height, uint32_t fourcc)
480 {
481 struct dwl_dmabuf *dmabuf = calloc(1, sizeof(struct dwl_dmabuf));
482 if (!dmabuf) {
483 syslog(LOG_ERR, "failed to allocate dwl_dmabuf");
484 return NULL;
485 }
486 dmabuf->width = width;
487 dmabuf->height = height;
488
489 struct zwp_linux_buffer_params_v1 *params =
490 zwp_linux_dmabuf_v1_create_params(self->ifaces.linux_dmabuf);
491 if (!params) {
492 syslog(LOG_ERR,
493 "failed to allocate zwp_linux_buffer_params_v1");
494 free(dmabuf);
495 return NULL;
496 }
497
498 zwp_linux_buffer_params_v1_add_listener(params, &linux_buffer_listener,
499 dmabuf);
500 zwp_linux_buffer_params_v1_add(params, fd, 0 /* plane_idx */, offset,
501 stride, modifiers >> 32,
502 (uint32_t)modifiers);
503 zwp_linux_buffer_params_v1_create(params, width, height, fourcc, 0);
504 wl_display_roundtrip(self->display);
505 zwp_linux_buffer_params_v1_destroy(params);
506
507 if (!dmabuf->buffer) {
508 syslog(LOG_ERR, "failed to get wl_buffer for dmabuf");
509 free(dmabuf);
510 return NULL;
511 }
512
513 wl_buffer_add_listener(dmabuf->buffer, &dmabuf_buffer_listener, dmabuf);
514
515 return dmabuf;
516 }
517
dwl_dmabuf_destroy(struct dwl_dmabuf ** self)518 void dwl_dmabuf_destroy(struct dwl_dmabuf **self)
519 {
520 wl_buffer_destroy((*self)->buffer);
521 free(*self);
522 *self = NULL;
523 }
524
surface_buffer_release(void * data,struct wl_buffer * buffer)525 static void surface_buffer_release(void *data, struct wl_buffer *buffer)
526 {
527 struct dwl_surface *surface = (struct dwl_surface *)data;
528 (void)buffer;
529
530 size_t i;
531 for (i = 0; i < surface->buffer_count; i++) {
532 if (buffer == surface->buffers[i]) {
533 surface->buffer_use_bit_mask &= ~(1 << i);
534 break;
535 }
536 }
537 }
538
539 static const struct wl_buffer_listener surface_buffer_listener = {
540 .release = surface_buffer_release};
541
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)542 struct dwl_surface *dwl_context_surface_new(struct dwl_context *self,
543 struct dwl_surface *parent,
544 int shm_fd, size_t shm_size,
545 size_t buffer_size, uint32_t width,
546 uint32_t height, uint32_t stride)
547 {
548 if (buffer_size == 0)
549 return NULL;
550 size_t buffer_count = shm_size / buffer_size;
551 if (buffer_count == 0)
552 return NULL;
553 if (buffer_count > MAX_BUFFER_COUNT)
554 return NULL;
555
556 struct dwl_surface *disp_surface =
557 calloc(1, sizeof(struct dwl_surface) +
558 sizeof(struct wl_buffer *) * buffer_count);
559 if (!disp_surface)
560 return NULL;
561 disp_surface->context = self;
562 disp_surface->width = width;
563 disp_surface->height = height;
564 disp_surface->scale = DEFAULT_SCALE;
565 disp_surface->buffer_count = buffer_count;
566
567 struct wl_region *region = NULL;
568 struct wl_shm_pool *shm_pool =
569 wl_shm_create_pool(self->ifaces.shm, shm_fd, shm_size);
570 if (!shm_pool) {
571 syslog(LOG_ERR, "failed to make shm pool");
572 goto fail;
573 }
574
575 size_t i;
576 for (i = 0; i < buffer_count; i++) {
577 struct wl_buffer *buffer = wl_shm_pool_create_buffer(
578 shm_pool, buffer_size * i, width, height, stride,
579 WL_SHM_FORMAT_ARGB8888);
580 if (!buffer) {
581 syslog(LOG_ERR, "failed to create buffer");
582 goto fail;
583 }
584 disp_surface->buffers[i] = buffer;
585 }
586
587 for (i = 0; i < buffer_count; i++)
588 wl_buffer_add_listener(disp_surface->buffers[i],
589 &surface_buffer_listener, disp_surface);
590
591 disp_surface->surface =
592 wl_compositor_create_surface(self->ifaces.compositor);
593 if (!disp_surface->surface) {
594 syslog(LOG_ERR, "failed to make surface");
595 goto fail;
596 }
597
598 wl_surface_add_listener(disp_surface->surface, &surface_listener,
599 disp_surface);
600
601 region = wl_compositor_create_region(self->ifaces.compositor);
602 if (!region) {
603 syslog(LOG_ERR, "failed to make region");
604 goto fail;
605 }
606 wl_region_add(region, 0, 0, width, height);
607 wl_surface_set_opaque_region(disp_surface->surface, region);
608
609 if (!parent) {
610 disp_surface->xdg = zxdg_shell_v6_get_xdg_surface(
611 self->ifaces.xdg_shell, disp_surface->surface);
612 if (!disp_surface->xdg) {
613 syslog(LOG_ERR, "failed to make xdg shell surface");
614 goto fail;
615 }
616
617 disp_surface->toplevel =
618 zxdg_surface_v6_get_toplevel(disp_surface->xdg);
619 if (!disp_surface->toplevel) {
620 syslog(LOG_ERR,
621 "failed to make toplevel xdg shell surface");
622 goto fail;
623 }
624 zxdg_toplevel_v6_set_title(disp_surface->toplevel, "crosvm");
625 zxdg_toplevel_v6_add_listener(disp_surface->toplevel,
626 &toplevel_listener, disp_surface);
627
628 if (self->ifaces.aura) {
629 disp_surface->aura = zaura_shell_get_aura_surface(
630 self->ifaces.aura, disp_surface->surface);
631 if (!disp_surface->aura) {
632 syslog(LOG_ERR, "failed to make aura surface");
633 goto fail;
634 }
635 zaura_surface_set_frame(
636 disp_surface->aura,
637 ZAURA_SURFACE_FRAME_TYPE_NORMAL);
638 }
639 } else {
640 disp_surface->subsurface = wl_subcompositor_get_subsurface(
641 self->ifaces.subcompositor, disp_surface->surface,
642 parent->surface);
643 if (!disp_surface->subsurface) {
644 syslog(LOG_ERR, "failed to make subsurface");
645 goto fail;
646 }
647 wl_subsurface_set_desync(disp_surface->subsurface);
648 }
649
650 if (self->ifaces.viewporter) {
651 disp_surface->viewport = wp_viewporter_get_viewport(
652 self->ifaces.viewporter, disp_surface->surface);
653 if (!disp_surface->viewport) {
654 syslog(LOG_ERR, "failed to make surface viewport");
655 goto fail;
656 }
657 }
658
659 wl_surface_attach(disp_surface->surface, disp_surface->buffers[0], 0,
660 0);
661 wl_surface_damage(disp_surface->surface, 0, 0, width, height);
662 wl_region_destroy(region);
663 wl_shm_pool_destroy(shm_pool);
664
665 // Needed to get outputs before iterating them.
666 wl_display_roundtrip(self->display);
667
668 // Assuming that this surface will enter the internal output initially,
669 // trigger a surface enter for that output before doing the first
670 // surface commit. THis is to avoid unpleasant artifacts when the
671 // surface first appears.
672 struct output *output;
673 outputs_for_each(self, i, output)
674 {
675 if (output->internal) {
676 surface_enter(disp_surface, disp_surface->surface,
677 output->output);
678 }
679 }
680
681 wl_surface_commit(disp_surface->surface);
682 wl_display_flush(self->display);
683
684 return disp_surface;
685 fail:
686 if (disp_surface->viewport)
687 wp_viewport_destroy(disp_surface->viewport);
688 if (disp_surface->subsurface)
689 wl_subsurface_destroy(disp_surface->subsurface);
690 if (disp_surface->toplevel)
691 zxdg_toplevel_v6_destroy(disp_surface->toplevel);
692 if (disp_surface->xdg)
693 zxdg_surface_v6_destroy(disp_surface->xdg);
694 if (disp_surface->aura)
695 zaura_surface_destroy(disp_surface->aura);
696 if (region)
697 wl_region_destroy(region);
698 if (disp_surface->surface)
699 wl_surface_destroy(disp_surface->surface);
700 for (i = 0; i < buffer_count; i++)
701 if (disp_surface->buffers[i])
702 wl_buffer_destroy(disp_surface->buffers[i]);
703 if (shm_pool)
704 wl_shm_pool_destroy(shm_pool);
705 free(disp_surface);
706 return NULL;
707 }
708
dwl_surface_destroy(struct dwl_surface ** self)709 void dwl_surface_destroy(struct dwl_surface **self)
710 {
711 size_t i;
712 if ((*self)->viewport)
713 wp_viewport_destroy((*self)->viewport);
714 if ((*self)->subsurface)
715 wl_subsurface_destroy((*self)->subsurface);
716 if ((*self)->toplevel)
717 zxdg_toplevel_v6_destroy((*self)->toplevel);
718 if ((*self)->xdg)
719 zxdg_surface_v6_destroy((*self)->xdg);
720 if ((*self)->aura)
721 zaura_surface_destroy((*self)->aura);
722 if ((*self)->surface)
723 wl_surface_destroy((*self)->surface);
724 for (i = 0; i < (*self)->buffer_count; i++)
725 wl_buffer_destroy((*self)->buffers[i]);
726 wl_display_flush((*self)->context->display);
727 free(*self);
728 *self = NULL;
729 }
730
dwl_surface_commit(struct dwl_surface * self)731 void dwl_surface_commit(struct dwl_surface *self)
732 {
733 // It is possible that we are committing frames faster than the
734 // compositor can put them on the screen. This may result in dropped
735 // frames, but this is acceptable considering there is no good way to
736 // apply back pressure to the guest gpu driver right now. The intention
737 // of this module is to help bootstrap gpu support, so it does not have
738 // to have artifact free rendering.
739 wl_surface_commit(self->surface);
740 wl_display_flush(self->context->display);
741 }
742
dwl_surface_buffer_in_use(struct dwl_surface * self,size_t buffer_index)743 bool dwl_surface_buffer_in_use(struct dwl_surface *self, size_t buffer_index)
744 {
745 return (self->buffer_use_bit_mask & (1 << buffer_index)) != 0;
746 }
747
dwl_surface_flip(struct dwl_surface * self,size_t buffer_index)748 void dwl_surface_flip(struct dwl_surface *self, size_t buffer_index)
749 {
750 if (buffer_index >= self->buffer_count)
751 return;
752 wl_surface_attach(self->surface, self->buffers[buffer_index], 0, 0);
753 wl_surface_damage(self->surface, 0, 0, self->width, self->height);
754 dwl_surface_commit(self);
755 self->buffer_use_bit_mask |= 1 << buffer_index;
756 }
757
dwl_surface_flip_to(struct dwl_surface * self,struct dwl_dmabuf * dmabuf)758 void dwl_surface_flip_to(struct dwl_surface *self, struct dwl_dmabuf *dmabuf)
759 {
760 if (self->width != dmabuf->width || self->height != dmabuf->height)
761 return;
762 wl_surface_attach(self->surface, dmabuf->buffer, 0, 0);
763 wl_surface_damage(self->surface, 0, 0, self->width, self->height);
764 dwl_surface_commit(self);
765 dmabuf->in_use = true;
766 }
767
dwl_surface_close_requested(const struct dwl_surface * self)768 bool dwl_surface_close_requested(const struct dwl_surface *self)
769 {
770 return self->close_requested;
771 }
772
dwl_surface_set_position(struct dwl_surface * self,uint32_t x,uint32_t y)773 void dwl_surface_set_position(struct dwl_surface *self, uint32_t x, uint32_t y)
774 {
775 if (self->subsurface) {
776 wl_subsurface_set_position(self->subsurface, x / self->scale,
777 y / self->scale);
778 wl_surface_commit(self->surface);
779 wl_display_flush(self->context->display);
780 }
781 }
782