1 // Copyright 2018 The ChromiumOS Authors
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 <unistd.h>
21
22 #include "aura-shell.h"
23 #include "linux-dmabuf-unstable-v1.h"
24 #include "viewporter.h"
25 #include "xdg-shell.h"
26 #include "virtio-gpu-metadata-v1.h"
27 #include <wayland-client-core.h>
28 #include <wayland-client-protocol.h>
29 #include <wayland-client.h>
30
31 // BTN_LEFT is copied from linux/input-event-codes.h because the kernel headers
32 // aren't readily available in some downstream projects.
33 #define BTN_LEFT 0x110
34
35 #define DEFAULT_SCALE 2
36 #define MAX_BUFFER_COUNT 64
37 #define EVENT_BUF_SIZE 256
38
39 const int32_t DWL_KEYBOARD_KEY_STATE_RELEASED = WL_KEYBOARD_KEY_STATE_RELEASED;
40 const int32_t DWL_KEYBOARD_KEY_STATE_PRESSED = WL_KEYBOARD_KEY_STATE_PRESSED;
41
42 const uint32_t DWL_EVENT_TYPE_KEYBOARD_ENTER = 0x00;
43 const uint32_t DWL_EVENT_TYPE_KEYBOARD_LEAVE = 0x01;
44 const uint32_t DWL_EVENT_TYPE_KEYBOARD_KEY = 0x02;
45 const uint32_t DWL_EVENT_TYPE_POINTER_ENTER = 0x10;
46 const uint32_t DWL_EVENT_TYPE_POINTER_LEAVE = 0x11;
47 const uint32_t DWL_EVENT_TYPE_POINTER_MOVE = 0x12;
48 const uint32_t DWL_EVENT_TYPE_POINTER_BUTTON = 0x13;
49 const uint32_t DWL_EVENT_TYPE_TOUCH_DOWN = 0x20;
50 const uint32_t DWL_EVENT_TYPE_TOUCH_UP = 0x21;
51 const uint32_t DWL_EVENT_TYPE_TOUCH_MOTION = 0x22;
52
53 const uint32_t DWL_SURFACE_FLAG_RECEIVE_INPUT = 1 << 0;
54 const uint32_t DWL_SURFACE_FLAG_HAS_ALPHA = 1 << 1;
55
56 struct dwl_event {
57 const void *surface_descriptor;
58 uint32_t event_type;
59 int32_t params[3];
60 };
61
62 struct dwl_context;
63
64 struct interfaces {
65 struct dwl_context *context;
66 struct wl_compositor *compositor;
67 struct wl_subcompositor *subcompositor;
68 struct wl_shm *shm;
69 struct wl_seat *seat;
70 struct zaura_shell *aura; // optional
71 struct zwp_linux_dmabuf_v1 *linux_dmabuf;
72 struct xdg_wm_base *xdg_wm_base;
73 struct wp_viewporter *viewporter; // optional
74 struct wp_virtio_gpu_metadata_v1 *virtio_gpu_metadata; // optional
75 };
76
77 struct output {
78 struct wl_output *output;
79 struct zaura_output *aura_output;
80 struct dwl_context *context;
81 uint32_t id;
82 uint32_t current_scale;
83 uint32_t device_scale_factor;
84 bool internal;
85 };
86
87 struct input {
88 struct wl_keyboard *wl_keyboard;
89 struct wl_pointer *wl_pointer;
90 struct wl_surface *keyboard_input_surface;
91 struct wl_surface *pointer_input_surface;
92 int32_t pointer_x;
93 int32_t pointer_y;
94 bool pointer_lbutton_state;
95 };
96
97 typedef void (*dwl_error_callback_type)(const char *message);
98
99 struct dwl_context {
100 struct wl_display *display;
101 struct dwl_surface *surfaces[MAX_BUFFER_COUNT];
102 struct dwl_dmabuf *dmabufs[MAX_BUFFER_COUNT];
103 struct interfaces ifaces;
104 struct input input;
105 bool output_added;
106 struct output outputs[8];
107
108 struct dwl_event event_cbuf[EVENT_BUF_SIZE];
109 size_t event_read_pos;
110 size_t event_write_pos;
111
112 dwl_error_callback_type error_callback;
113 };
114
115 #define outputs_for_each(context, pos, output) \
116 for (pos = 0, output = &context->outputs[pos]; \
117 pos < (sizeof(context->outputs) / sizeof(context->outputs[0])); \
118 pos++, output = &context->outputs[pos])
119
120 struct dwl_dmabuf {
121 uint32_t width;
122 uint32_t height;
123 uint32_t import_id;
124 bool in_use;
125 struct wl_buffer *buffer;
126 struct dwl_context *context;
127 };
128
129 struct dwl_surface {
130 struct dwl_context *context;
131 struct wl_surface *wl_surface;
132 struct zaura_surface *aura;
133 struct xdg_surface *xdg_surface;
134 struct xdg_toplevel *xdg_toplevel;
135 struct wp_viewport *viewport;
136 struct wp_virtio_gpu_surface_metadata_v1 *virtio_gpu_surface_metadata;
137 struct wl_subsurface *subsurface;
138 uint32_t width;
139 uint32_t height;
140 uint32_t surface_id;
141 double scale;
142 bool close_requested;
143 size_t buffer_count;
144 uint64_t buffer_use_bit_mask;
145 struct wl_buffer *buffers[0];
146 };
147
148 static_assert(sizeof(((struct dwl_surface *)0)->buffer_use_bit_mask) * 8 >=
149 MAX_BUFFER_COUNT,
150 "not enough bits in buffer_use_bit_mask");
151
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)152 static void output_geometry(void *data, struct wl_output *output, int x, int y,
153 int physical_width, int physical_height,
154 int subpixel, const char *make, const char *model,
155 int transform)
156 {
157 (void)data;
158 (void)output;
159 (void)x;
160 (void)y;
161 (void)physical_width;
162 (void)physical_height;
163 (void)subpixel;
164 (void)make;
165 (void)model;
166 (void)transform;
167 }
168
output_mode(void * data,struct wl_output * output,uint32_t flags,int width,int height,int refresh)169 static void output_mode(void *data, struct wl_output *output, uint32_t flags,
170 int width, int height, int refresh)
171 {
172 (void)data;
173 (void)output;
174 (void)flags;
175 (void)width;
176 (void)height;
177 (void)refresh;
178 }
179
output_done(void * data,struct wl_output * output)180 static void output_done(void *data, struct wl_output *output)
181 {
182 (void)data;
183 (void)output;
184 }
185
output_scale(void * data,struct wl_output * wl_output,int32_t scale_factor)186 static void output_scale(void *data, struct wl_output *wl_output,
187 int32_t scale_factor)
188 {
189 (void)wl_output;
190 struct output *output = (struct output *)data;
191 struct dwl_context *context = output->context;
192
193 // If the aura interface is available, we prefer the scale factor
194 // reported by that.
195 if (context->ifaces.aura)
196 return;
197
198 output->current_scale = 1000 * scale_factor;
199 }
200
201 static const struct wl_output_listener output_listener = {
202 .geometry = output_geometry,
203 .mode = output_mode,
204 .done = output_done,
205 .scale = output_scale};
206
aura_output_scale(void * data,struct zaura_output * aura_output,uint32_t flags,uint32_t scale)207 static void aura_output_scale(void *data, struct zaura_output *aura_output,
208 uint32_t flags, uint32_t scale)
209 {
210 (void)aura_output;
211 struct output *output = (struct output *)data;
212 if (flags & ZAURA_OUTPUT_SCALE_PROPERTY_CURRENT) {
213 output->current_scale = scale;
214 }
215 }
216
aura_output_connection(void * data,struct zaura_output * aura_output,uint32_t connection)217 static void aura_output_connection(void *data, struct zaura_output *aura_output,
218 uint32_t connection)
219 {
220 (void)aura_output;
221 struct output *output = (struct output *)data;
222 output->internal = connection == ZAURA_OUTPUT_CONNECTION_TYPE_INTERNAL;
223 }
224
aura_output_device_scale_factor(void * data,struct zaura_output * aura_output,uint32_t device_scale_factor)225 static void aura_output_device_scale_factor(void *data,
226 struct zaura_output *aura_output,
227 uint32_t device_scale_factor)
228 {
229 (void)aura_output;
230 struct output *output = (struct output *)data;
231 output->device_scale_factor = device_scale_factor;
232 }
233
234 static const struct zaura_output_listener aura_output_listener = {
235 .scale = aura_output_scale,
236 .connection = aura_output_connection,
237 .device_scale_factor = aura_output_device_scale_factor};
238
xdg_wm_base_ping(void * data,struct xdg_wm_base * xdg_wm_base,uint32_t serial)239 static void xdg_wm_base_ping(void *data, struct xdg_wm_base *xdg_wm_base,
240 uint32_t serial)
241 {
242 (void)data;
243 xdg_wm_base_pong(xdg_wm_base, serial);
244 }
245
246 static const struct xdg_wm_base_listener xdg_wm_base_listener = {
247 .ping = xdg_wm_base_ping,
248 };
249
250
wl_keyboard_keymap(void * data,struct wl_keyboard * wl_keyboard,uint32_t format,int32_t fd,uint32_t size)251 static void wl_keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard,
252 uint32_t format, int32_t fd, uint32_t size)
253 {
254 struct dwl_context *context = (struct dwl_context*)data;
255 (void)wl_keyboard;
256 (void)fd;
257 (void)size;
258 if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
259 context->error_callback("wl_keyboard: invalid keymap format");
260 }
261 }
262
dwl_context_push_event(struct dwl_context * self,struct dwl_event * event)263 static void dwl_context_push_event(struct dwl_context *self,
264 struct dwl_event *event)
265 {
266 if (!self)
267 return;
268
269 memcpy(self->event_cbuf + self->event_write_pos, event,
270 sizeof(struct dwl_event));
271
272 if (++self->event_write_pos == EVENT_BUF_SIZE)
273 self->event_write_pos = 0;
274 }
275
wl_keyboard_enter(void * data,struct wl_keyboard * wl_keyboard,uint32_t serial,struct wl_surface * surface,struct wl_array * keys)276 static void wl_keyboard_enter(void *data, struct wl_keyboard *wl_keyboard,
277 uint32_t serial, struct wl_surface *surface,
278 struct wl_array *keys)
279 {
280 (void)wl_keyboard;
281 (void)serial;
282 (void)surface;
283 struct dwl_context *context = (struct dwl_context*)data;
284 struct input *input = &context->input;
285 uint32_t *key;
286 struct dwl_event event = {0};
287 input->keyboard_input_surface = surface;
288 wl_array_for_each(key, keys) {
289 event.surface_descriptor = input->keyboard_input_surface;
290 event.event_type = DWL_EVENT_TYPE_KEYBOARD_KEY;
291 event.params[0] = (int32_t)*key;
292 event.params[1] = DWL_KEYBOARD_KEY_STATE_PRESSED;
293 dwl_context_push_event(context, &event);
294 }
295 }
296
wl_keyboard_key(void * data,struct wl_keyboard * wl_keyboard,uint32_t serial,uint32_t time,uint32_t key,uint32_t state)297 static void wl_keyboard_key(void *data, struct wl_keyboard *wl_keyboard,
298 uint32_t serial, uint32_t time, uint32_t key,
299 uint32_t state)
300 {
301 struct dwl_context *context = (struct dwl_context*)data;
302 struct input *input = &context->input;
303 (void)wl_keyboard;
304 (void)serial;
305 (void)time;
306 struct dwl_event event = {0};
307 event.surface_descriptor = input->keyboard_input_surface;
308 event.event_type = DWL_EVENT_TYPE_KEYBOARD_KEY;
309 event.params[0] = (int32_t)key;
310 event.params[1] = state;
311 dwl_context_push_event(context, &event);
312 }
313
wl_keyboard_leave(void * data,struct wl_keyboard * wl_keyboard,uint32_t serial,struct wl_surface * surface)314 static void wl_keyboard_leave(void *data, struct wl_keyboard *wl_keyboard,
315 uint32_t serial, struct wl_surface *surface)
316 {
317 struct dwl_context *context = (struct dwl_context*)data;
318 struct input *input = &context->input;
319 struct dwl_event event = {0};
320 (void)wl_keyboard;
321 (void)serial;
322 (void)surface;
323
324 event.surface_descriptor = input->keyboard_input_surface;
325 event.event_type = DWL_EVENT_TYPE_KEYBOARD_LEAVE;
326 dwl_context_push_event(context, &event);
327
328 input->keyboard_input_surface = NULL;
329 }
330
wl_keyboard_modifiers(void * data,struct wl_keyboard * wl_keyboard,uint32_t serial,uint32_t mods_depressed,uint32_t mods_latched,uint32_t mods_locked,uint32_t group)331 static void wl_keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard,
332 uint32_t serial, uint32_t mods_depressed,
333 uint32_t mods_latched, uint32_t mods_locked,
334 uint32_t group)
335 {
336 (void)data;
337 (void)wl_keyboard;
338 (void)serial;
339 (void)mods_depressed;
340 (void)mods_latched;
341 (void)mods_locked;
342 (void)group;
343 }
344
wl_keyboard_repeat_info(void * data,struct wl_keyboard * wl_keyboard,int32_t rate,int32_t delay)345 static void wl_keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
346 int32_t rate, int32_t delay)
347 {
348 (void)data;
349 (void)wl_keyboard;
350 (void)rate;
351 (void)delay;
352 }
353
354 static const struct wl_keyboard_listener wl_keyboard_listener = {
355 .keymap = wl_keyboard_keymap,
356 .enter = wl_keyboard_enter,
357 .leave = wl_keyboard_leave,
358 .key = wl_keyboard_key,
359 .modifiers = wl_keyboard_modifiers,
360 .repeat_info = wl_keyboard_repeat_info,
361 };
362
pointer_enter_handler(void * data,struct wl_pointer * wl_pointer,uint32_t serial,struct wl_surface * surface,wl_fixed_t x,wl_fixed_t y)363 static void pointer_enter_handler(void *data, struct wl_pointer *wl_pointer,
364 uint32_t serial, struct wl_surface *surface,
365 wl_fixed_t x, wl_fixed_t y)
366 {
367 struct dwl_context *context = (struct dwl_context*)data;
368 struct input *input = &context->input;
369 (void)wl_pointer;
370 (void)serial;
371
372 input->pointer_input_surface = surface;
373 input->pointer_x = wl_fixed_to_int(x);
374 input->pointer_y = wl_fixed_to_int(y);
375 }
376
pointer_leave_handler(void * data,struct wl_pointer * wl_pointer,uint32_t serial,struct wl_surface * surface)377 static void pointer_leave_handler(void *data, struct wl_pointer *wl_pointer,
378 uint32_t serial, struct wl_surface *surface)
379 {
380 struct dwl_context *context = (struct dwl_context*)data;
381 struct input *input = &context->input;
382 (void)wl_pointer;
383 (void)serial;
384 (void)surface;
385
386 input->pointer_input_surface = NULL;
387 }
388
pointer_motion_handler(void * data,struct wl_pointer * wl_pointer,uint32_t time,wl_fixed_t x,wl_fixed_t y)389 static void pointer_motion_handler(void *data, struct wl_pointer *wl_pointer,
390 uint32_t time, wl_fixed_t x, wl_fixed_t y)
391 {
392 struct dwl_context *context = (struct dwl_context*)data;
393 struct input *input = &context->input;
394 struct dwl_event event = {0};
395 (void)wl_pointer;
396 (void)time;
397
398 input->pointer_x = wl_fixed_to_int(x);
399 input->pointer_y = wl_fixed_to_int(y);
400 if (input->pointer_lbutton_state) {
401 event.surface_descriptor = input->pointer_input_surface;
402 event.event_type = DWL_EVENT_TYPE_TOUCH_MOTION;
403 event.params[0] = input->pointer_x;
404 event.params[1] = input->pointer_y;
405 dwl_context_push_event(context, &event);
406 }
407 }
408
pointer_button_handler(void * data,struct wl_pointer * wl_pointer,uint32_t serial,uint32_t time,uint32_t button,uint32_t state)409 static void pointer_button_handler(void *data, struct wl_pointer *wl_pointer,
410 uint32_t serial, uint32_t time, uint32_t button,
411 uint32_t state)
412 {
413 struct dwl_context *context = (struct dwl_context*)data;
414 struct input *input = &context->input;
415 (void)wl_pointer;
416 (void)time;
417 (void)serial;
418
419 // we track only the left mouse button since we emulate a single touch device
420 if (button == BTN_LEFT) {
421 input->pointer_lbutton_state = state != 0;
422 struct dwl_event event = {0};
423 event.surface_descriptor = input->pointer_input_surface;
424 event.event_type = (state != 0)?
425 DWL_EVENT_TYPE_TOUCH_DOWN:DWL_EVENT_TYPE_TOUCH_UP;
426 event.params[0] = input->pointer_x;
427 event.params[1] = input->pointer_y;
428 dwl_context_push_event(context, &event);
429 }
430 }
431
wl_pointer_frame(void * data,struct wl_pointer * wl_pointer)432 static void wl_pointer_frame(void *data, struct wl_pointer *wl_pointer)
433 {
434 (void)data;
435 (void)wl_pointer;
436 }
437
pointer_axis_handler(void * data,struct wl_pointer * wl_pointer,uint32_t time,uint32_t axis,wl_fixed_t value)438 static void pointer_axis_handler(void *data, struct wl_pointer *wl_pointer,
439 uint32_t time, uint32_t axis, wl_fixed_t value)
440 {
441 (void)data;
442 (void)wl_pointer;
443 (void)time;
444 (void)axis;
445 (void)value;
446 }
447
wl_pointer_axis_source(void * data,struct wl_pointer * wl_pointer,uint32_t axis_source)448 static void wl_pointer_axis_source(void *data, struct wl_pointer *wl_pointer,
449 uint32_t axis_source)
450 {
451 (void)data;
452 (void)wl_pointer;
453 (void)axis_source;
454 }
455
wl_pointer_axis_stop(void * data,struct wl_pointer * wl_pointer,uint32_t time,uint32_t axis)456 static void wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer,
457 uint32_t time, uint32_t axis)
458 {
459 (void)data;
460 (void)wl_pointer;
461 (void)time;
462 (void)axis;
463 }
464
wl_pointer_axis_discrete(void * data,struct wl_pointer * wl_pointer,uint32_t axis,int32_t discrete)465 static void wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer,
466 uint32_t axis, int32_t discrete)
467 {
468 (void)data;
469 (void)wl_pointer;
470 (void)axis;
471 (void)discrete;
472 }
473
474 const struct wl_pointer_listener wl_pointer_listener = {
475 .enter = pointer_enter_handler,
476 .leave = pointer_leave_handler,
477 .motion = pointer_motion_handler,
478 .button = pointer_button_handler,
479 .axis = pointer_axis_handler,
480 .frame = wl_pointer_frame,
481 .axis_source = wl_pointer_axis_source,
482 .axis_stop = wl_pointer_axis_stop,
483 .axis_discrete = wl_pointer_axis_discrete,
484 };
485
wl_seat_capabilities(void * data,struct wl_seat * wl_seat,uint32_t capabilities)486 static void wl_seat_capabilities(void *data, struct wl_seat *wl_seat,
487 uint32_t capabilities)
488 {
489 struct dwl_context *context = (struct dwl_context*)data;
490 struct input *input = &context->input;
491 bool have_keyboard = capabilities & WL_SEAT_CAPABILITY_KEYBOARD;
492 bool have_pointer = capabilities & WL_SEAT_CAPABILITY_POINTER;
493
494 if (have_keyboard && input->wl_keyboard == NULL) {
495 input->wl_keyboard = wl_seat_get_keyboard(wl_seat);
496 wl_keyboard_add_listener(input->wl_keyboard, &wl_keyboard_listener, context);
497 } else if (!have_keyboard && input->wl_keyboard != NULL) {
498 wl_keyboard_release(input->wl_keyboard);
499 input->wl_keyboard = NULL;
500 }
501
502 if (have_pointer && input->wl_pointer == NULL) {
503 input->wl_pointer = wl_seat_get_pointer(wl_seat);
504 wl_pointer_add_listener(input->wl_pointer, &wl_pointer_listener, context);
505 } else if (!have_pointer && input->wl_pointer != NULL) {
506 wl_pointer_release(input->wl_pointer);
507 input->wl_pointer = NULL;
508 }
509 }
510
wl_seat_name(void * data,struct wl_seat * wl_seat,const char * name)511 static void wl_seat_name(void *data, struct wl_seat *wl_seat, const char *name)
512 {
513 (void)data;
514 (void)wl_seat;
515 (void)name;
516 }
517
518 static const struct wl_seat_listener wl_seat_listener = {
519 .capabilities = wl_seat_capabilities,
520 .name = wl_seat_name,
521 };
522
dwl_context_output_add(struct dwl_context * context,struct wl_output * wl_output,uint32_t id)523 static void dwl_context_output_add(struct dwl_context *context,
524 struct wl_output *wl_output, uint32_t id)
525 {
526 size_t i;
527 struct output *output;
528 outputs_for_each(context, i, output)
529 {
530 if (output->output == NULL) {
531 context->output_added = true;
532 output->id = id;
533 output->output = wl_output;
534 output->context = context;
535 output->current_scale = 1000;
536 output->device_scale_factor = 1000;
537 // This is a fun little hack from reveman. The idea is
538 // that the first display will be internal and never get
539 // removed.
540 output->internal = i == 0;
541 wl_output_add_listener(output->output, &output_listener,
542 output);
543 return;
544 }
545 }
546 }
547
dwl_context_output_remove_destroy(struct dwl_context * context,uint32_t id)548 static void dwl_context_output_remove_destroy(struct dwl_context *context,
549 uint32_t id)
550 {
551 size_t i;
552 struct output *output;
553 outputs_for_each(context, i, output)
554 {
555 if (output->id == id) {
556 if (output->aura_output)
557 zaura_output_destroy(output->aura_output);
558 wl_output_destroy(output->output);
559 memset(output, 0, sizeof(struct output));
560 return;
561 }
562 }
563 }
564
dwl_context_output_get_aura(struct dwl_context * context)565 static void dwl_context_output_get_aura(struct dwl_context *context)
566 {
567 if (!context->ifaces.aura)
568 return;
569
570 size_t i;
571 struct output *output;
572 outputs_for_each(context, i, output)
573 {
574 if (output->output != NULL && output->aura_output == NULL) {
575 output->aura_output = zaura_shell_get_aura_output(
576 context->ifaces.aura, output->output);
577 zaura_output_add_listener(
578 output->aura_output, &aura_output_listener, output);
579 }
580 }
581 }
582
registry_global(void * data,struct wl_registry * registry,uint32_t id,const char * interface,uint32_t version)583 static void registry_global(void *data, struct wl_registry *registry,
584 uint32_t id, const char *interface,
585 uint32_t version)
586 {
587 (void)version;
588 struct interfaces *ifaces = (struct interfaces *)data;
589 if (strcmp(interface, wl_compositor_interface.name) == 0) {
590 ifaces->compositor = (struct wl_compositor *)wl_registry_bind(
591 registry, id, &wl_compositor_interface, 3);
592 } else if (strcmp(interface, wl_subcompositor_interface.name) == 0) {
593 ifaces->subcompositor =
594 (struct wl_subcompositor *)wl_registry_bind(
595 registry, id, &wl_subcompositor_interface, 1);
596 } else if (strcmp(interface, wl_shm_interface.name) == 0) {
597 ifaces->shm = (struct wl_shm *)wl_registry_bind(
598 registry, id, &wl_shm_interface, 1);
599 } else if (strcmp(interface, wl_seat_interface.name) == 0) {
600 ifaces->seat = (struct wl_seat *)wl_registry_bind(
601 registry, id, &wl_seat_interface, 5);
602 wl_seat_add_listener(ifaces->seat, &wl_seat_listener, ifaces->context);
603 } else if (strcmp(interface, wl_output_interface.name) == 0) {
604 struct wl_output *output = (struct wl_output *)wl_registry_bind(
605 registry, id, &wl_output_interface, 2);
606 dwl_context_output_add(ifaces->context, output, id);
607 } else if (strcmp(interface, "zaura_shell") == 0 && version >= 6) {
608 ifaces->aura = (struct zaura_shell *)wl_registry_bind(
609 registry, id, &zaura_shell_interface, 6);
610 } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0) {
611 ifaces->linux_dmabuf =
612 (struct zwp_linux_dmabuf_v1 *)wl_registry_bind(
613 registry, id, &zwp_linux_dmabuf_v1_interface, 1);
614 } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
615 ifaces->xdg_wm_base = (struct xdg_wm_base *)wl_registry_bind(
616 registry, id, &xdg_wm_base_interface, 1);
617 xdg_wm_base_add_listener(ifaces->xdg_wm_base, &xdg_wm_base_listener,
618 NULL);
619 } else if (strcmp(interface, "wp_viewporter") == 0) {
620 ifaces->viewporter = (struct wp_viewporter *)wl_registry_bind(
621 registry, id, &wp_viewporter_interface, 1);
622 } else if (strcmp(interface, "wp_virtio_gpu_metadata_v1") == 0) {
623 ifaces->virtio_gpu_metadata =
624 (struct wp_virtio_gpu_metadata_v1 *)wl_registry_bind(
625 registry, id, &wp_virtio_gpu_metadata_v1_interface, 1);
626 }
627 }
628
global_remove(void * data,struct wl_registry * registry,uint32_t id)629 static void global_remove(void *data, struct wl_registry *registry, uint32_t id)
630 {
631 (void)registry;
632
633 struct interfaces *ifaces = (struct interfaces *)data;
634 // If the ID matches any output, this will remove it. Otherwise, this is
635 // a no-op.
636 dwl_context_output_remove_destroy(ifaces->context, id);
637
638 if (ifaces->aura &&
639 wl_proxy_get_id((struct wl_proxy *)ifaces->aura) == id) {
640 zaura_shell_destroy(ifaces->aura);
641 ifaces->aura = NULL;
642 }
643
644 // TODO(zachr): deal with the removal of some of the required
645 // interfaces.
646 }
647
648 static const struct wl_registry_listener registry_listener = {
649 .global = registry_global, .global_remove = global_remove};
650
toplevel_configure(void * data,struct xdg_toplevel * xdg_toplevel,int32_t width,int32_t height,struct wl_array * states)651 static void toplevel_configure(void *data,
652 struct xdg_toplevel *xdg_toplevel,
653 int32_t width, int32_t height,
654 struct wl_array *states)
655 {
656 (void)data;
657 (void)xdg_toplevel;
658 (void)width;
659 (void)height;
660 (void)states;
661 }
662
toplevel_close(void * data,struct xdg_toplevel * xdg_toplevel)663 static void toplevel_close(void *data,
664 struct xdg_toplevel *xdg_toplevel)
665 {
666 (void)xdg_toplevel;
667 struct dwl_surface *surface = (struct dwl_surface *)data;
668 surface->close_requested = true;
669 }
670
671 static const struct xdg_toplevel_listener toplevel_listener = {
672 .configure = toplevel_configure, .close = toplevel_close};
673
xdg_surface_configure_handler(void * data,struct xdg_surface * xdg_surface,uint32_t serial)674 static void xdg_surface_configure_handler(void *data,
675 struct xdg_surface *xdg_surface,
676 uint32_t serial)
677 {
678 (void)data;
679 xdg_surface_ack_configure(xdg_surface, serial);
680 }
681
682 static const struct xdg_surface_listener xdg_surface_listener = {
683 .configure = xdg_surface_configure_handler
684 };
685
surface_enter(void * data,struct wl_surface * wl_surface,struct wl_output * wl_output)686 static void surface_enter(void *data, struct wl_surface *wl_surface,
687 struct wl_output *wl_output)
688 {
689 struct dwl_surface *surface = (struct dwl_surface *)data;
690
691 struct output *output =
692 (struct output *)wl_output_get_user_data(wl_output);
693
694 surface->scale = (output->device_scale_factor / 1000.0) *
695 (output->current_scale / 1000.0);
696
697 if (surface->viewport) {
698 wp_viewport_set_destination(
699 surface->viewport, ceil(surface->width / surface->scale),
700 ceil(surface->height / surface->scale));
701 } else {
702 wl_surface_set_buffer_scale(wl_surface, surface->scale);
703 }
704
705 wl_surface_commit(wl_surface);
706 }
707
surface_leave(void * data,struct wl_surface * wl_surface,struct wl_output * output)708 static void surface_leave(void *data, struct wl_surface *wl_surface,
709 struct wl_output *output)
710 {
711 (void)data;
712 (void)wl_surface;
713 (void)output;
714 }
715
716 static const struct wl_surface_listener surface_listener = {
717 .enter = surface_enter, .leave = surface_leave};
718
error_callback_stub(const char * message)719 static void error_callback_stub(const char *message) {
720 (void)message;
721 }
722
dwl_context_new(dwl_error_callback_type error_callback)723 struct dwl_context *dwl_context_new(dwl_error_callback_type error_callback)
724 {
725 struct dwl_context *ctx = calloc(1, sizeof(struct dwl_context));
726 ctx->ifaces.context = ctx;
727 ctx->error_callback = error_callback ? error_callback : error_callback_stub;
728 return ctx;
729 }
730
dwl_context_destroy(struct dwl_context ** self)731 void dwl_context_destroy(struct dwl_context **self)
732 {
733 if ((*self)->display)
734 wl_display_disconnect((*self)->display);
735 free(*self);
736 *self = NULL;
737 }
738
dwl_context_setup(struct dwl_context * self,const char * socket_path)739 bool dwl_context_setup(struct dwl_context *self, const char *socket_path)
740 {
741 struct wl_display *display = wl_display_connect(socket_path);
742 if (!display) {
743 self->error_callback("failed to connect to display");
744 return false;
745 }
746 self->display = display;
747 wl_display_set_user_data(display, self);
748
749 struct wl_registry *registry = wl_display_get_registry(display);
750 if (!registry) {
751 self->error_callback("failed to get registry");
752 goto fail;
753 }
754
755 struct interfaces *ifaces = &self->ifaces;
756 wl_registry_add_listener(registry, ®istry_listener, ifaces);
757 wl_display_roundtrip(display);
758 dwl_context_output_get_aura(self);
759
760 if (!ifaces->shm) {
761 self->error_callback("missing interface shm");
762 goto fail;
763 }
764 if (!ifaces->compositor) {
765 self->error_callback("missing interface compositor");
766 goto fail;
767 }
768 if (!ifaces->subcompositor) {
769 self->error_callback("missing interface subcompositor");
770 goto fail;
771 }
772 if (!ifaces->seat) {
773 self->error_callback("missing interface seat");
774 goto fail;
775 }
776 if (!ifaces->linux_dmabuf) {
777 self->error_callback("missing interface linux_dmabuf");
778 goto fail;
779 }
780 if (!ifaces->xdg_wm_base) {
781 self->error_callback("missing interface xdg_wm_base");
782 goto fail;
783 }
784
785 return true;
786
787 fail:
788 wl_display_disconnect(display);
789 self->display = NULL;
790 return false;
791 }
792
dwl_context_fd(struct dwl_context * self)793 int dwl_context_fd(struct dwl_context *self)
794 {
795 return wl_display_get_fd(self->display);
796 }
797
dwl_context_dispatch(struct dwl_context * self)798 void dwl_context_dispatch(struct dwl_context *self)
799 {
800 wl_display_dispatch(self->display);
801 if (self->output_added) {
802 self->output_added = false;
803 dwl_context_output_get_aura(self);
804 wl_display_roundtrip(self->display);
805 }
806 }
807
linux_buffer_created(void * data,struct zwp_linux_buffer_params_v1 * zwp_linux_buffer_params_v1,struct wl_buffer * buffer)808 static void linux_buffer_created(
809 void *data, struct zwp_linux_buffer_params_v1 *zwp_linux_buffer_params_v1,
810 struct wl_buffer *buffer)
811 {
812 (void)zwp_linux_buffer_params_v1;
813 struct dwl_dmabuf *dmabuf = (struct dwl_dmabuf *)data;
814 dmabuf->buffer = buffer;
815 }
816
linux_buffer_failed(void * data,struct zwp_linux_buffer_params_v1 * zwp_linux_buffer_params_v1)817 static void linux_buffer_failed(
818 void *data, struct zwp_linux_buffer_params_v1 *zwp_linux_buffer_params_v1)
819 {
820 (void)data;
821 (void)zwp_linux_buffer_params_v1;
822 }
823
824 static const struct zwp_linux_buffer_params_v1_listener linux_buffer_listener =
825 {.created = linux_buffer_created, .failed = linux_buffer_failed};
826
dmabuf_buffer_release(void * data,struct wl_buffer * buffer)827 static void dmabuf_buffer_release(void *data, struct wl_buffer *buffer)
828 {
829 struct dwl_dmabuf *dmabuf = (struct dwl_dmabuf *)data;
830 (void)buffer;
831
832 dmabuf->in_use = false;
833 }
834
835 static const struct wl_buffer_listener dmabuf_buffer_listener = {
836 .release = dmabuf_buffer_release};
837
dwl_context_add_dmabuf(struct dwl_context * self,struct dwl_dmabuf * dmabuf)838 static bool dwl_context_add_dmabuf(struct dwl_context *self,
839 struct dwl_dmabuf *dmabuf)
840 {
841 size_t i;
842 for (i = 0; i < MAX_BUFFER_COUNT; i++) {
843 if (!self->dmabufs[i]) {
844 self->dmabufs[i] = dmabuf;
845 return true;
846 }
847 }
848
849 return false;
850 }
851
dwl_context_remove_dmabuf(struct dwl_context * self,uint32_t import_id)852 static void dwl_context_remove_dmabuf(struct dwl_context *self,
853 uint32_t import_id)
854 {
855 size_t i;
856 for (i = 0; i < MAX_BUFFER_COUNT; i++) {
857 if (self->dmabufs[i] &&
858 self->dmabufs[i]->import_id == import_id) {
859 self->dmabufs[i] = NULL;
860 }
861 }
862 }
863
dwl_context_get_dmabuf(struct dwl_context * self,uint32_t import_id)864 static struct dwl_dmabuf *dwl_context_get_dmabuf(struct dwl_context *self,
865 uint32_t import_id)
866 {
867 size_t i;
868 for (i = 0; i < MAX_BUFFER_COUNT; i++) {
869 if (self->dmabufs[i] &&
870 self->dmabufs[i]->import_id == import_id) {
871 return self->dmabufs[i];
872 }
873 }
874
875 return NULL;
876 }
877
dwl_context_dmabuf_new(struct dwl_context * self,uint32_t import_id,int fd,uint32_t offset,uint32_t stride,uint64_t modifier,uint32_t width,uint32_t height,uint32_t fourcc)878 struct dwl_dmabuf *dwl_context_dmabuf_new(struct dwl_context *self,
879 uint32_t import_id,
880 int fd, uint32_t offset,
881 uint32_t stride, uint64_t modifier,
882 uint32_t width, uint32_t height,
883 uint32_t fourcc)
884 {
885 struct dwl_dmabuf *dmabuf = calloc(1, sizeof(struct dwl_dmabuf));
886 if (!dmabuf) {
887 self->error_callback("failed to allocate dwl_dmabuf");
888 return NULL;
889 }
890 dmabuf->width = width;
891 dmabuf->height = height;
892
893 struct zwp_linux_buffer_params_v1 *params =
894 zwp_linux_dmabuf_v1_create_params(self->ifaces.linux_dmabuf);
895 if (!params) {
896 self->error_callback("failed to allocate zwp_linux_buffer_params_v1");
897 free(dmabuf);
898 return NULL;
899 }
900
901 zwp_linux_buffer_params_v1_add_listener(params, &linux_buffer_listener,
902 dmabuf);
903 zwp_linux_buffer_params_v1_add(params, fd, 0 /* plane_idx */, offset,
904 stride, modifier >> 32,
905 (uint32_t)modifier);
906 zwp_linux_buffer_params_v1_create(params, width, height, fourcc, 0);
907 wl_display_roundtrip(self->display);
908 zwp_linux_buffer_params_v1_destroy(params);
909
910 if (!dmabuf->buffer) {
911 self->error_callback("failed to get wl_buffer for dmabuf");
912 free(dmabuf);
913 return NULL;
914 }
915
916 wl_buffer_add_listener(dmabuf->buffer, &dmabuf_buffer_listener, dmabuf);
917
918 dmabuf->import_id = import_id;
919 dmabuf->context = self;
920 if (!dwl_context_add_dmabuf(self, dmabuf)) {
921 self->error_callback("failed to add dmabuf to context");
922 free(dmabuf);
923 return NULL;
924 }
925
926 return dmabuf;
927 }
928
dwl_dmabuf_destroy(struct dwl_dmabuf ** self)929 void dwl_dmabuf_destroy(struct dwl_dmabuf **self)
930 {
931 dwl_context_remove_dmabuf((*self)->context, (*self)->import_id);
932 wl_buffer_destroy((*self)->buffer);
933 free(*self);
934 *self = NULL;
935 }
936
surface_buffer_release(void * data,struct wl_buffer * buffer)937 static void surface_buffer_release(void *data, struct wl_buffer *buffer)
938 {
939 struct dwl_surface *surface = (struct dwl_surface *)data;
940 (void)buffer;
941
942 size_t i;
943 for (i = 0; i < surface->buffer_count; i++) {
944 if (buffer == surface->buffers[i]) {
945 surface->buffer_use_bit_mask &= ~(1 << i);
946 break;
947 }
948 }
949 }
950
951 static const struct wl_buffer_listener surface_buffer_listener = {
952 .release = surface_buffer_release};
953
dwl_context_get_surface(struct dwl_context * self,uint32_t surface_id)954 static struct dwl_surface *dwl_context_get_surface(struct dwl_context *self,
955 uint32_t surface_id)
956 {
957 size_t i;
958 for (i = 0; i < MAX_BUFFER_COUNT; i++) {
959 if (self->surfaces[i] &&
960 self->surfaces[i]->surface_id == surface_id) {
961 return self->surfaces[i];
962 }
963 }
964
965 return NULL;
966 }
967
dwl_context_add_surface(struct dwl_context * self,struct dwl_surface * surface)968 static bool dwl_context_add_surface(struct dwl_context *self,
969 struct dwl_surface *surface)
970 {
971 size_t i;
972 for (i = 0; i < MAX_BUFFER_COUNT; i++) {
973 if (!self->surfaces[i]) {
974 self->surfaces[i] = surface;
975 return true;
976 }
977 }
978
979 return false;
980 }
981
dwl_context_remove_surface(struct dwl_context * self,uint32_t surface_id)982 static void dwl_context_remove_surface(struct dwl_context *self,
983 uint32_t surface_id)
984 {
985 size_t i;
986 for (i = 0; i < MAX_BUFFER_COUNT; i++) {
987 if (self->surfaces[i] &&
988 self->surfaces[i]->surface_id == surface_id) {
989 self->surfaces[i] = NULL;
990 }
991 }
992 }
993
dwl_context_surface_new(struct dwl_context * self,uint32_t parent_id,uint32_t surface_id,int shm_fd,size_t shm_size,size_t buffer_size,uint32_t width,uint32_t height,uint32_t stride,uint32_t flags)994 struct dwl_surface *dwl_context_surface_new(struct dwl_context *self,
995 uint32_t parent_id,
996 uint32_t surface_id,
997 int shm_fd, size_t shm_size,
998 size_t buffer_size, uint32_t width,
999 uint32_t height, uint32_t stride,
1000 uint32_t flags)
1001 {
1002 if (buffer_size == 0)
1003 return NULL;
1004
1005 size_t buffer_count = shm_size / buffer_size;
1006 if (buffer_count == 0)
1007 return NULL;
1008 if (buffer_count > MAX_BUFFER_COUNT)
1009 return NULL;
1010
1011 struct dwl_surface *disp_surface =
1012 calloc(1, sizeof(struct dwl_surface) +
1013 sizeof(struct wl_buffer *) * buffer_count);
1014 if (!disp_surface)
1015 return NULL;
1016
1017 disp_surface->context = self;
1018 disp_surface->width = width;
1019 disp_surface->height = height;
1020 disp_surface->scale = DEFAULT_SCALE;
1021 disp_surface->buffer_count = buffer_count;
1022
1023 struct wl_shm_pool *shm_pool =
1024 wl_shm_create_pool(self->ifaces.shm, shm_fd, shm_size);
1025 if (!shm_pool) {
1026 self->error_callback("failed to make shm pool");
1027 goto fail;
1028 }
1029
1030 size_t i;
1031 uint32_t format = (flags & DWL_SURFACE_FLAG_HAS_ALPHA)?
1032 WL_SHM_FORMAT_ARGB8888:WL_SHM_FORMAT_XRGB8888;
1033
1034 for (i = 0; i < buffer_count; i++) {
1035 struct wl_buffer *buffer = wl_shm_pool_create_buffer(
1036 shm_pool, buffer_size * i, width, height, stride, format);
1037 if (!buffer) {
1038 self->error_callback("failed to create buffer");
1039 goto fail;
1040 }
1041 disp_surface->buffers[i] = buffer;
1042 }
1043
1044 for (i = 0; i < buffer_count; i++)
1045 wl_buffer_add_listener(disp_surface->buffers[i],
1046 &surface_buffer_listener, disp_surface);
1047
1048 disp_surface->wl_surface =
1049 wl_compositor_create_surface(self->ifaces.compositor);
1050 if (!disp_surface->wl_surface) {
1051 self->error_callback("failed to make surface");
1052 goto fail;
1053 }
1054
1055 wl_surface_add_listener(disp_surface->wl_surface, &surface_listener,
1056 disp_surface);
1057
1058 struct wl_region *region = wl_compositor_create_region(self->ifaces.compositor);
1059 if (!region) {
1060 self->error_callback("failed to make region");
1061 goto fail;
1062 }
1063
1064 bool receive_input = (flags & DWL_SURFACE_FLAG_RECEIVE_INPUT);
1065 if (receive_input) {
1066 wl_region_add(region, 0, 0, width, height);
1067 } else {
1068 // We have to add an empty region because NULL doesn't work
1069 wl_region_add(region, 0, 0, 0, 0);
1070 }
1071 wl_surface_set_input_region(disp_surface->wl_surface, region);
1072 wl_surface_set_opaque_region(disp_surface->wl_surface, region);
1073 wl_region_destroy(region);
1074
1075 if (!parent_id) {
1076 disp_surface->xdg_surface = xdg_wm_base_get_xdg_surface(
1077 self->ifaces.xdg_wm_base, disp_surface->wl_surface);
1078 if (!disp_surface->xdg_surface) {
1079 self->error_callback("failed to make xdg shell surface");
1080 goto fail;
1081 }
1082
1083 disp_surface->xdg_toplevel =
1084 xdg_surface_get_toplevel(disp_surface->xdg_surface);
1085 if (!disp_surface->xdg_toplevel) {
1086 self->error_callback("failed to make toplevel xdg shell surface");
1087 goto fail;
1088 }
1089 xdg_toplevel_set_title(disp_surface->xdg_toplevel, "crosvm");
1090 xdg_toplevel_add_listener(disp_surface->xdg_toplevel,
1091 &toplevel_listener, disp_surface);
1092
1093 xdg_surface_add_listener(disp_surface->xdg_surface,
1094 &xdg_surface_listener,
1095 NULL);
1096 if (self->ifaces.aura) {
1097 disp_surface->aura = zaura_shell_get_aura_surface(
1098 self->ifaces.aura, disp_surface->wl_surface);
1099 if (!disp_surface->aura) {
1100 self->error_callback("failed to make aura surface");
1101 goto fail;
1102 }
1103 zaura_surface_set_frame(
1104 disp_surface->aura,
1105 ZAURA_SURFACE_FRAME_TYPE_NORMAL);
1106 }
1107
1108 // signal that the surface is ready to be configured
1109 wl_surface_commit(disp_surface->wl_surface);
1110
1111 // wait for the surface to be configured
1112 wl_display_roundtrip(self->display);
1113 } else {
1114 struct dwl_surface *parent_surface =
1115 dwl_context_get_surface(self, parent_id);
1116
1117 if (!parent_surface) {
1118 self->error_callback("failed to find parent_surface");
1119 goto fail;
1120 }
1121
1122 disp_surface->subsurface = wl_subcompositor_get_subsurface(
1123 self->ifaces.subcompositor, disp_surface->wl_surface,
1124 parent_surface->wl_surface);
1125 if (!disp_surface->subsurface) {
1126 self->error_callback("failed to make subsurface");
1127 goto fail;
1128 }
1129 wl_subsurface_set_desync(disp_surface->subsurface);
1130 }
1131
1132 if (self->ifaces.viewporter) {
1133 disp_surface->viewport = wp_viewporter_get_viewport(
1134 self->ifaces.viewporter, disp_surface->wl_surface);
1135 if (!disp_surface->viewport) {
1136 self->error_callback("failed to make surface viewport");
1137 goto fail;
1138 }
1139 }
1140
1141 if (self->ifaces.virtio_gpu_metadata) {
1142 disp_surface->virtio_gpu_surface_metadata =
1143 wp_virtio_gpu_metadata_v1_get_surface_metadata(
1144 self->ifaces.virtio_gpu_metadata, disp_surface->wl_surface);
1145 if (!disp_surface->virtio_gpu_surface_metadata) {
1146 self->error_callback("failed to make surface virtio surface metadata");
1147 goto fail;
1148 }
1149 }
1150
1151 wl_surface_attach(disp_surface->wl_surface, disp_surface->buffers[0], 0,
1152 0);
1153 wl_surface_damage(disp_surface->wl_surface, 0, 0, width, height);
1154 wl_shm_pool_destroy(shm_pool);
1155
1156 // Needed to get outputs before iterating them.
1157 wl_display_roundtrip(self->display);
1158
1159 // Assuming that this surface will enter the internal output initially,
1160 // trigger a surface enter for that output before doing the first
1161 // surface commit. THis is to avoid unpleasant artifacts when the
1162 // surface first appears.
1163 struct output *output;
1164 outputs_for_each(self, i, output)
1165 {
1166 if (output->internal) {
1167 surface_enter(disp_surface, disp_surface->wl_surface,
1168 output->output);
1169 }
1170 }
1171
1172 wl_surface_commit(disp_surface->wl_surface);
1173 wl_display_flush(self->display);
1174
1175 disp_surface->surface_id = surface_id;
1176 if (!dwl_context_add_surface(self, disp_surface)) {
1177 self->error_callback("failed to add surface to context");
1178 goto fail;
1179 }
1180
1181 return disp_surface;
1182 fail:
1183 if (disp_surface->virtio_gpu_surface_metadata)
1184 wp_virtio_gpu_surface_metadata_v1_destroy(
1185 disp_surface->virtio_gpu_surface_metadata);
1186 if (disp_surface->viewport)
1187 wp_viewport_destroy(disp_surface->viewport);
1188 if (disp_surface->subsurface)
1189 wl_subsurface_destroy(disp_surface->subsurface);
1190 if (disp_surface->xdg_toplevel)
1191 xdg_toplevel_destroy(disp_surface->xdg_toplevel);
1192 if (disp_surface->xdg_surface)
1193 xdg_surface_destroy(disp_surface->xdg_surface);
1194 if (disp_surface->aura)
1195 zaura_surface_destroy(disp_surface->aura);
1196 if (disp_surface->wl_surface)
1197 wl_surface_destroy(disp_surface->wl_surface);
1198 for (i = 0; i < buffer_count; i++)
1199 if (disp_surface->buffers[i])
1200 wl_buffer_destroy(disp_surface->buffers[i]);
1201 if (shm_pool)
1202 wl_shm_pool_destroy(shm_pool);
1203 free(disp_surface);
1204 return NULL;
1205 }
1206
dwl_surface_destroy(struct dwl_surface ** self)1207 void dwl_surface_destroy(struct dwl_surface **self)
1208 {
1209 size_t i;
1210
1211 dwl_context_remove_surface((*self)->context, (*self)->surface_id);
1212 if ((*self)->virtio_gpu_surface_metadata)
1213 wp_virtio_gpu_surface_metadata_v1_destroy(
1214 (*self)->virtio_gpu_surface_metadata);
1215 if ((*self)->viewport)
1216 wp_viewport_destroy((*self)->viewport);
1217 if ((*self)->subsurface)
1218 wl_subsurface_destroy((*self)->subsurface);
1219 if ((*self)->xdg_toplevel)
1220 xdg_toplevel_destroy((*self)->xdg_toplevel);
1221 if ((*self)->xdg_surface)
1222 xdg_surface_destroy((*self)->xdg_surface);
1223 if ((*self)->aura)
1224 zaura_surface_destroy((*self)->aura);
1225 if ((*self)->wl_surface)
1226 wl_surface_destroy((*self)->wl_surface);
1227 for (i = 0; i < (*self)->buffer_count; i++)
1228 wl_buffer_destroy((*self)->buffers[i]);
1229 wl_display_flush((*self)->context->display);
1230 free(*self);
1231 *self = NULL;
1232 }
1233
dwl_surface_commit(struct dwl_surface * self)1234 void dwl_surface_commit(struct dwl_surface *self)
1235 {
1236 // It is possible that we are committing frames faster than the
1237 // compositor can put them on the screen. This may result in dropped
1238 // frames, but this is acceptable considering there is no good way to
1239 // apply back pressure to the guest gpu driver right now. The intention
1240 // of this module is to help bootstrap gpu support, so it does not have
1241 // to have artifact free rendering.
1242 wl_surface_commit(self->wl_surface);
1243 wl_display_flush(self->context->display);
1244 }
1245
dwl_surface_buffer_in_use(struct dwl_surface * self,size_t buffer_index)1246 bool dwl_surface_buffer_in_use(struct dwl_surface *self, size_t buffer_index)
1247 {
1248 return (self->buffer_use_bit_mask & (1 << buffer_index)) != 0;
1249 }
1250
dwl_surface_flip(struct dwl_surface * self,size_t buffer_index)1251 void dwl_surface_flip(struct dwl_surface *self, size_t buffer_index)
1252 {
1253 if (buffer_index >= self->buffer_count)
1254 return;
1255 wl_surface_attach(self->wl_surface, self->buffers[buffer_index], 0, 0);
1256 wl_surface_damage(self->wl_surface, 0, 0, self->width, self->height);
1257 dwl_surface_commit(self);
1258 self->buffer_use_bit_mask |= 1 << buffer_index;
1259 }
1260
dwl_surface_flip_to(struct dwl_surface * self,uint32_t import_id)1261 void dwl_surface_flip_to(struct dwl_surface *self, uint32_t import_id)
1262 {
1263 // Surface and dmabuf have to exist in same context.
1264 struct dwl_dmabuf *dmabuf = dwl_context_get_dmabuf(self->context,
1265 import_id);
1266 if (!dmabuf)
1267 return;
1268
1269 if (self->width != dmabuf->width || self->height != dmabuf->height)
1270 return;
1271 wl_surface_attach(self->wl_surface, dmabuf->buffer, 0, 0);
1272 wl_surface_damage(self->wl_surface, 0, 0, self->width, self->height);
1273 dwl_surface_commit(self);
1274 dmabuf->in_use = true;
1275 }
1276
dwl_surface_close_requested(const struct dwl_surface * self)1277 bool dwl_surface_close_requested(const struct dwl_surface *self)
1278 {
1279 return self->close_requested;
1280 }
1281
dwl_surface_set_position(struct dwl_surface * self,uint32_t x,uint32_t y)1282 void dwl_surface_set_position(struct dwl_surface *self, uint32_t x, uint32_t y)
1283 {
1284 if (self->subsurface) {
1285 wl_subsurface_set_position(self->subsurface, x / self->scale,
1286 y / self->scale);
1287 wl_surface_commit(self->wl_surface);
1288 wl_display_flush(self->context->display);
1289 }
1290 }
1291
dwl_surface_descriptor(const struct dwl_surface * self)1292 const void* dwl_surface_descriptor(const struct dwl_surface *self)
1293 {
1294 return self->wl_surface;
1295 }
1296
dwl_context_pending_events(const struct dwl_context * self)1297 bool dwl_context_pending_events(const struct dwl_context *self)
1298 {
1299 if (self->event_write_pos == self->event_read_pos)
1300 return false;
1301
1302 return true;
1303 }
1304
dwl_context_next_event(struct dwl_context * self,struct dwl_event * event)1305 void dwl_context_next_event(struct dwl_context *self, struct dwl_event *event)
1306 {
1307 memcpy(event, self->event_cbuf + self->event_read_pos,
1308 sizeof(struct dwl_event));
1309
1310 if (++self->event_read_pos == EVENT_BUF_SIZE)
1311 self->event_read_pos = 0;
1312 }
1313
dwl_surface_set_scanout_id(struct dwl_surface * self,uint32_t scanout_id)1314 void dwl_surface_set_scanout_id(struct dwl_surface *self, uint32_t scanout_id)
1315 {
1316 if (self->virtio_gpu_surface_metadata) {
1317 wp_virtio_gpu_surface_metadata_v1_set_scanout_id(
1318 self->virtio_gpu_surface_metadata, scanout_id);
1319 }
1320 }
1321