Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/gpu_display/src/display_wl.c
5394 views
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
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
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
180
static void output_done(void *data, struct wl_output *output)
181
{
182
(void)data;
183
(void)output;
184
}
185
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
432
static void wl_pointer_frame(void *data, struct wl_pointer *wl_pointer)
433
{
434
(void)data;
435
(void)wl_pointer;
436
}
437
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
719
static void error_callback_stub(const char *message) {
720
(void)message;
721
}
722
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
if (!ctx)
727
return NULL;
728
ctx->ifaces.context = ctx;
729
ctx->error_callback = error_callback ? error_callback : error_callback_stub;
730
return ctx;
731
}
732
733
void dwl_context_destroy(struct dwl_context **self)
734
{
735
if ((*self)->display)
736
wl_display_disconnect((*self)->display);
737
free(*self);
738
*self = NULL;
739
}
740
741
bool dwl_context_setup(struct dwl_context *self, const char *socket_path)
742
{
743
struct wl_display *display = wl_display_connect(socket_path);
744
if (!display) {
745
self->error_callback("failed to connect to display");
746
return false;
747
}
748
self->display = display;
749
wl_display_set_user_data(display, self);
750
751
struct wl_registry *registry = wl_display_get_registry(display);
752
if (!registry) {
753
self->error_callback("failed to get registry");
754
goto fail;
755
}
756
757
struct interfaces *ifaces = &self->ifaces;
758
wl_registry_add_listener(registry, &registry_listener, ifaces);
759
wl_display_roundtrip(display);
760
dwl_context_output_get_aura(self);
761
762
if (!ifaces->shm) {
763
self->error_callback("missing interface shm");
764
goto fail;
765
}
766
if (!ifaces->compositor) {
767
self->error_callback("missing interface compositor");
768
goto fail;
769
}
770
if (!ifaces->subcompositor) {
771
self->error_callback("missing interface subcompositor");
772
goto fail;
773
}
774
if (!ifaces->seat) {
775
self->error_callback("missing interface seat");
776
goto fail;
777
}
778
if (!ifaces->linux_dmabuf) {
779
self->error_callback("missing interface linux_dmabuf");
780
goto fail;
781
}
782
if (!ifaces->xdg_wm_base) {
783
self->error_callback("missing interface xdg_wm_base");
784
goto fail;
785
}
786
787
return true;
788
789
fail:
790
wl_display_disconnect(display);
791
self->display = NULL;
792
return false;
793
}
794
795
int dwl_context_fd(struct dwl_context *self)
796
{
797
return wl_display_get_fd(self->display);
798
}
799
800
void dwl_context_dispatch(struct dwl_context *self)
801
{
802
wl_display_dispatch(self->display);
803
if (self->output_added) {
804
self->output_added = false;
805
dwl_context_output_get_aura(self);
806
wl_display_roundtrip(self->display);
807
}
808
}
809
810
static void linux_buffer_created(
811
void *data, struct zwp_linux_buffer_params_v1 *zwp_linux_buffer_params_v1,
812
struct wl_buffer *buffer)
813
{
814
(void)zwp_linux_buffer_params_v1;
815
struct dwl_dmabuf *dmabuf = (struct dwl_dmabuf *)data;
816
dmabuf->buffer = buffer;
817
}
818
819
static void linux_buffer_failed(
820
void *data, struct zwp_linux_buffer_params_v1 *zwp_linux_buffer_params_v1)
821
{
822
(void)data;
823
(void)zwp_linux_buffer_params_v1;
824
}
825
826
static const struct zwp_linux_buffer_params_v1_listener linux_buffer_listener =
827
{.created = linux_buffer_created, .failed = linux_buffer_failed};
828
829
static void dmabuf_buffer_release(void *data, struct wl_buffer *buffer)
830
{
831
struct dwl_dmabuf *dmabuf = (struct dwl_dmabuf *)data;
832
(void)buffer;
833
834
dmabuf->in_use = false;
835
}
836
837
static const struct wl_buffer_listener dmabuf_buffer_listener = {
838
.release = dmabuf_buffer_release};
839
840
static bool dwl_context_add_dmabuf(struct dwl_context *self,
841
struct dwl_dmabuf *dmabuf)
842
{
843
size_t i;
844
for (i = 0; i < MAX_BUFFER_COUNT; i++) {
845
if (!self->dmabufs[i]) {
846
self->dmabufs[i] = dmabuf;
847
return true;
848
}
849
}
850
851
return false;
852
}
853
854
static void dwl_context_remove_dmabuf(struct dwl_context *self,
855
uint32_t import_id)
856
{
857
size_t i;
858
for (i = 0; i < MAX_BUFFER_COUNT; i++) {
859
if (self->dmabufs[i] &&
860
self->dmabufs[i]->import_id == import_id) {
861
self->dmabufs[i] = NULL;
862
}
863
}
864
}
865
866
static struct dwl_dmabuf *dwl_context_get_dmabuf(struct dwl_context *self,
867
uint32_t import_id)
868
{
869
size_t i;
870
for (i = 0; i < MAX_BUFFER_COUNT; i++) {
871
if (self->dmabufs[i] &&
872
self->dmabufs[i]->import_id == import_id) {
873
return self->dmabufs[i];
874
}
875
}
876
877
return NULL;
878
}
879
880
struct dwl_dmabuf *dwl_context_dmabuf_new(struct dwl_context *self,
881
uint32_t import_id,
882
int fd, uint32_t offset,
883
uint32_t stride, uint64_t modifier,
884
uint32_t width, uint32_t height,
885
uint32_t fourcc)
886
{
887
struct dwl_dmabuf *dmabuf = calloc(1, sizeof(struct dwl_dmabuf));
888
if (!dmabuf) {
889
self->error_callback("failed to allocate dwl_dmabuf");
890
return NULL;
891
}
892
dmabuf->width = width;
893
dmabuf->height = height;
894
895
struct zwp_linux_buffer_params_v1 *params =
896
zwp_linux_dmabuf_v1_create_params(self->ifaces.linux_dmabuf);
897
if (!params) {
898
self->error_callback("failed to allocate zwp_linux_buffer_params_v1");
899
free(dmabuf);
900
return NULL;
901
}
902
903
zwp_linux_buffer_params_v1_add_listener(params, &linux_buffer_listener,
904
dmabuf);
905
zwp_linux_buffer_params_v1_add(params, fd, 0 /* plane_idx */, offset,
906
stride, modifier >> 32,
907
(uint32_t)modifier);
908
zwp_linux_buffer_params_v1_create(params, width, height, fourcc, 0);
909
wl_display_roundtrip(self->display);
910
zwp_linux_buffer_params_v1_destroy(params);
911
912
if (!dmabuf->buffer) {
913
self->error_callback("failed to get wl_buffer for dmabuf");
914
free(dmabuf);
915
return NULL;
916
}
917
918
wl_buffer_add_listener(dmabuf->buffer, &dmabuf_buffer_listener, dmabuf);
919
920
dmabuf->import_id = import_id;
921
dmabuf->context = self;
922
if (!dwl_context_add_dmabuf(self, dmabuf)) {
923
self->error_callback("failed to add dmabuf to context");
924
free(dmabuf);
925
return NULL;
926
}
927
928
return dmabuf;
929
}
930
931
void dwl_dmabuf_destroy(struct dwl_dmabuf **self)
932
{
933
dwl_context_remove_dmabuf((*self)->context, (*self)->import_id);
934
wl_buffer_destroy((*self)->buffer);
935
free(*self);
936
*self = NULL;
937
}
938
939
static void surface_buffer_release(void *data, struct wl_buffer *buffer)
940
{
941
struct dwl_surface *surface = (struct dwl_surface *)data;
942
(void)buffer;
943
944
size_t i;
945
for (i = 0; i < surface->buffer_count; i++) {
946
if (buffer == surface->buffers[i]) {
947
surface->buffer_use_bit_mask &= ~(1 << i);
948
break;
949
}
950
}
951
}
952
953
static const struct wl_buffer_listener surface_buffer_listener = {
954
.release = surface_buffer_release};
955
956
static struct dwl_surface *dwl_context_get_surface(struct dwl_context *self,
957
uint32_t surface_id)
958
{
959
size_t i;
960
for (i = 0; i < MAX_BUFFER_COUNT; i++) {
961
if (self->surfaces[i] &&
962
self->surfaces[i]->surface_id == surface_id) {
963
return self->surfaces[i];
964
}
965
}
966
967
return NULL;
968
}
969
970
static bool dwl_context_add_surface(struct dwl_context *self,
971
struct dwl_surface *surface)
972
{
973
size_t i;
974
for (i = 0; i < MAX_BUFFER_COUNT; i++) {
975
if (!self->surfaces[i]) {
976
self->surfaces[i] = surface;
977
return true;
978
}
979
}
980
981
return false;
982
}
983
984
static void dwl_context_remove_surface(struct dwl_context *self,
985
uint32_t surface_id)
986
{
987
size_t i;
988
for (i = 0; i < MAX_BUFFER_COUNT; i++) {
989
if (self->surfaces[i] &&
990
self->surfaces[i]->surface_id == surface_id) {
991
self->surfaces[i] = NULL;
992
}
993
}
994
}
995
996
struct dwl_surface *dwl_context_surface_new(struct dwl_context *self,
997
uint32_t parent_id,
998
uint32_t surface_id,
999
int shm_fd, size_t shm_size,
1000
size_t buffer_size, uint32_t width,
1001
uint32_t height, uint32_t stride,
1002
uint32_t flags)
1003
{
1004
if (buffer_size == 0)
1005
return NULL;
1006
1007
size_t buffer_count = shm_size / buffer_size;
1008
if (buffer_count == 0)
1009
return NULL;
1010
if (buffer_count > MAX_BUFFER_COUNT)
1011
return NULL;
1012
1013
struct dwl_surface *disp_surface =
1014
calloc(1, sizeof(struct dwl_surface) +
1015
sizeof(struct wl_buffer *) * buffer_count);
1016
if (!disp_surface)
1017
return NULL;
1018
1019
disp_surface->context = self;
1020
disp_surface->width = width;
1021
disp_surface->height = height;
1022
disp_surface->scale = DEFAULT_SCALE;
1023
disp_surface->buffer_count = buffer_count;
1024
1025
struct wl_shm_pool *shm_pool =
1026
wl_shm_create_pool(self->ifaces.shm, shm_fd, shm_size);
1027
if (!shm_pool) {
1028
self->error_callback("failed to make shm pool");
1029
goto fail;
1030
}
1031
1032
size_t i;
1033
uint32_t format = (flags & DWL_SURFACE_FLAG_HAS_ALPHA)?
1034
WL_SHM_FORMAT_ARGB8888:WL_SHM_FORMAT_XRGB8888;
1035
1036
for (i = 0; i < buffer_count; i++) {
1037
struct wl_buffer *buffer = wl_shm_pool_create_buffer(
1038
shm_pool, buffer_size * i, width, height, stride, format);
1039
if (!buffer) {
1040
self->error_callback("failed to create buffer");
1041
goto fail;
1042
}
1043
disp_surface->buffers[i] = buffer;
1044
}
1045
1046
for (i = 0; i < buffer_count; i++)
1047
wl_buffer_add_listener(disp_surface->buffers[i],
1048
&surface_buffer_listener, disp_surface);
1049
1050
disp_surface->wl_surface =
1051
wl_compositor_create_surface(self->ifaces.compositor);
1052
if (!disp_surface->wl_surface) {
1053
self->error_callback("failed to make surface");
1054
goto fail;
1055
}
1056
1057
wl_surface_add_listener(disp_surface->wl_surface, &surface_listener,
1058
disp_surface);
1059
1060
struct wl_region *region = wl_compositor_create_region(self->ifaces.compositor);
1061
if (!region) {
1062
self->error_callback("failed to make region");
1063
goto fail;
1064
}
1065
1066
bool receive_input = (flags & DWL_SURFACE_FLAG_RECEIVE_INPUT);
1067
if (receive_input) {
1068
wl_region_add(region, 0, 0, width, height);
1069
} else {
1070
// We have to add an empty region because NULL doesn't work
1071
wl_region_add(region, 0, 0, 0, 0);
1072
}
1073
wl_surface_set_input_region(disp_surface->wl_surface, region);
1074
wl_surface_set_opaque_region(disp_surface->wl_surface, region);
1075
wl_region_destroy(region);
1076
1077
if (!parent_id) {
1078
disp_surface->xdg_surface = xdg_wm_base_get_xdg_surface(
1079
self->ifaces.xdg_wm_base, disp_surface->wl_surface);
1080
if (!disp_surface->xdg_surface) {
1081
self->error_callback("failed to make xdg shell surface");
1082
goto fail;
1083
}
1084
1085
disp_surface->xdg_toplevel =
1086
xdg_surface_get_toplevel(disp_surface->xdg_surface);
1087
if (!disp_surface->xdg_toplevel) {
1088
self->error_callback("failed to make toplevel xdg shell surface");
1089
goto fail;
1090
}
1091
xdg_toplevel_set_title(disp_surface->xdg_toplevel, "crosvm");
1092
xdg_toplevel_add_listener(disp_surface->xdg_toplevel,
1093
&toplevel_listener, disp_surface);
1094
1095
xdg_surface_add_listener(disp_surface->xdg_surface,
1096
&xdg_surface_listener,
1097
NULL);
1098
if (self->ifaces.aura) {
1099
disp_surface->aura = zaura_shell_get_aura_surface(
1100
self->ifaces.aura, disp_surface->wl_surface);
1101
if (!disp_surface->aura) {
1102
self->error_callback("failed to make aura surface");
1103
goto fail;
1104
}
1105
zaura_surface_set_frame(
1106
disp_surface->aura,
1107
ZAURA_SURFACE_FRAME_TYPE_NORMAL);
1108
}
1109
1110
// signal that the surface is ready to be configured
1111
wl_surface_commit(disp_surface->wl_surface);
1112
1113
// wait for the surface to be configured
1114
wl_display_roundtrip(self->display);
1115
} else {
1116
struct dwl_surface *parent_surface =
1117
dwl_context_get_surface(self, parent_id);
1118
1119
if (!parent_surface) {
1120
self->error_callback("failed to find parent_surface");
1121
goto fail;
1122
}
1123
1124
disp_surface->subsurface = wl_subcompositor_get_subsurface(
1125
self->ifaces.subcompositor, disp_surface->wl_surface,
1126
parent_surface->wl_surface);
1127
if (!disp_surface->subsurface) {
1128
self->error_callback("failed to make subsurface");
1129
goto fail;
1130
}
1131
wl_subsurface_set_desync(disp_surface->subsurface);
1132
}
1133
1134
if (self->ifaces.viewporter) {
1135
disp_surface->viewport = wp_viewporter_get_viewport(
1136
self->ifaces.viewporter, disp_surface->wl_surface);
1137
if (!disp_surface->viewport) {
1138
self->error_callback("failed to make surface viewport");
1139
goto fail;
1140
}
1141
}
1142
1143
if (self->ifaces.virtio_gpu_metadata) {
1144
disp_surface->virtio_gpu_surface_metadata =
1145
wp_virtio_gpu_metadata_v1_get_surface_metadata(
1146
self->ifaces.virtio_gpu_metadata, disp_surface->wl_surface);
1147
if (!disp_surface->virtio_gpu_surface_metadata) {
1148
self->error_callback("failed to make surface virtio surface metadata");
1149
goto fail;
1150
}
1151
}
1152
1153
wl_surface_attach(disp_surface->wl_surface, disp_surface->buffers[0], 0,
1154
0);
1155
wl_surface_damage(disp_surface->wl_surface, 0, 0, width, height);
1156
wl_shm_pool_destroy(shm_pool);
1157
1158
// Needed to get outputs before iterating them.
1159
wl_display_roundtrip(self->display);
1160
1161
// Assuming that this surface will enter the internal output initially,
1162
// trigger a surface enter for that output before doing the first
1163
// surface commit. THis is to avoid unpleasant artifacts when the
1164
// surface first appears.
1165
struct output *output;
1166
outputs_for_each(self, i, output)
1167
{
1168
if (output->internal) {
1169
surface_enter(disp_surface, disp_surface->wl_surface,
1170
output->output);
1171
}
1172
}
1173
1174
wl_surface_commit(disp_surface->wl_surface);
1175
wl_display_flush(self->display);
1176
1177
disp_surface->surface_id = surface_id;
1178
if (!dwl_context_add_surface(self, disp_surface)) {
1179
self->error_callback("failed to add surface to context");
1180
goto fail;
1181
}
1182
1183
return disp_surface;
1184
fail:
1185
if (disp_surface->virtio_gpu_surface_metadata)
1186
wp_virtio_gpu_surface_metadata_v1_destroy(
1187
disp_surface->virtio_gpu_surface_metadata);
1188
if (disp_surface->viewport)
1189
wp_viewport_destroy(disp_surface->viewport);
1190
if (disp_surface->subsurface)
1191
wl_subsurface_destroy(disp_surface->subsurface);
1192
if (disp_surface->xdg_toplevel)
1193
xdg_toplevel_destroy(disp_surface->xdg_toplevel);
1194
if (disp_surface->xdg_surface)
1195
xdg_surface_destroy(disp_surface->xdg_surface);
1196
if (disp_surface->aura)
1197
zaura_surface_destroy(disp_surface->aura);
1198
if (disp_surface->wl_surface)
1199
wl_surface_destroy(disp_surface->wl_surface);
1200
for (i = 0; i < buffer_count; i++)
1201
if (disp_surface->buffers[i])
1202
wl_buffer_destroy(disp_surface->buffers[i]);
1203
if (shm_pool)
1204
wl_shm_pool_destroy(shm_pool);
1205
free(disp_surface);
1206
return NULL;
1207
}
1208
1209
void dwl_surface_destroy(struct dwl_surface **self)
1210
{
1211
size_t i;
1212
1213
dwl_context_remove_surface((*self)->context, (*self)->surface_id);
1214
if ((*self)->virtio_gpu_surface_metadata)
1215
wp_virtio_gpu_surface_metadata_v1_destroy(
1216
(*self)->virtio_gpu_surface_metadata);
1217
if ((*self)->viewport)
1218
wp_viewport_destroy((*self)->viewport);
1219
if ((*self)->subsurface)
1220
wl_subsurface_destroy((*self)->subsurface);
1221
if ((*self)->xdg_toplevel)
1222
xdg_toplevel_destroy((*self)->xdg_toplevel);
1223
if ((*self)->xdg_surface)
1224
xdg_surface_destroy((*self)->xdg_surface);
1225
if ((*self)->aura)
1226
zaura_surface_destroy((*self)->aura);
1227
if ((*self)->wl_surface)
1228
wl_surface_destroy((*self)->wl_surface);
1229
for (i = 0; i < (*self)->buffer_count; i++)
1230
wl_buffer_destroy((*self)->buffers[i]);
1231
wl_display_flush((*self)->context->display);
1232
free(*self);
1233
*self = NULL;
1234
}
1235
1236
void dwl_surface_commit(struct dwl_surface *self)
1237
{
1238
// It is possible that we are committing frames faster than the
1239
// compositor can put them on the screen. This may result in dropped
1240
// frames, but this is acceptable considering there is no good way to
1241
// apply back pressure to the guest gpu driver right now. The intention
1242
// of this module is to help bootstrap gpu support, so it does not have
1243
// to have artifact free rendering.
1244
wl_surface_commit(self->wl_surface);
1245
wl_display_flush(self->context->display);
1246
}
1247
1248
bool dwl_surface_buffer_in_use(struct dwl_surface *self, size_t buffer_index)
1249
{
1250
return (self->buffer_use_bit_mask & (1 << buffer_index)) != 0;
1251
}
1252
1253
void dwl_surface_flip(struct dwl_surface *self, size_t buffer_index)
1254
{
1255
if (buffer_index >= self->buffer_count)
1256
return;
1257
wl_surface_attach(self->wl_surface, self->buffers[buffer_index], 0, 0);
1258
wl_surface_damage(self->wl_surface, 0, 0, self->width, self->height);
1259
dwl_surface_commit(self);
1260
self->buffer_use_bit_mask |= 1 << buffer_index;
1261
}
1262
1263
void dwl_surface_flip_to(struct dwl_surface *self, uint32_t import_id)
1264
{
1265
// Surface and dmabuf have to exist in same context.
1266
struct dwl_dmabuf *dmabuf = dwl_context_get_dmabuf(self->context,
1267
import_id);
1268
if (!dmabuf)
1269
return;
1270
1271
if (self->width != dmabuf->width || self->height != dmabuf->height)
1272
return;
1273
wl_surface_attach(self->wl_surface, dmabuf->buffer, 0, 0);
1274
wl_surface_damage(self->wl_surface, 0, 0, self->width, self->height);
1275
dwl_surface_commit(self);
1276
dmabuf->in_use = true;
1277
}
1278
1279
bool dwl_surface_close_requested(const struct dwl_surface *self)
1280
{
1281
return self->close_requested;
1282
}
1283
1284
void dwl_surface_set_position(struct dwl_surface *self, uint32_t x, uint32_t y)
1285
{
1286
if (self->subsurface) {
1287
wl_subsurface_set_position(self->subsurface, x / self->scale,
1288
y / self->scale);
1289
wl_surface_commit(self->wl_surface);
1290
wl_display_flush(self->context->display);
1291
}
1292
}
1293
1294
const void* dwl_surface_descriptor(const struct dwl_surface *self)
1295
{
1296
return self->wl_surface;
1297
}
1298
1299
bool dwl_context_pending_events(const struct dwl_context *self)
1300
{
1301
if (self->event_write_pos == self->event_read_pos)
1302
return false;
1303
1304
return true;
1305
}
1306
1307
void dwl_context_next_event(struct dwl_context *self, struct dwl_event *event)
1308
{
1309
memcpy(event, self->event_cbuf + self->event_read_pos,
1310
sizeof(struct dwl_event));
1311
1312
if (++self->event_read_pos == EVENT_BUF_SIZE)
1313
self->event_read_pos = 0;
1314
}
1315
1316
void dwl_surface_set_scanout_id(struct dwl_surface *self, uint32_t scanout_id)
1317
{
1318
if (self->virtio_gpu_surface_metadata) {
1319
wp_virtio_gpu_surface_metadata_v1_set_scanout_id(
1320
self->virtio_gpu_surface_metadata, scanout_id);
1321
}
1322
}
1323
1324