Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/egl/drivers/dri2/platform_wayland.c
4570 views
1
/*
2
* Copyright Ā© 2011-2012 Intel Corporation
3
* Copyright Ā© 2012 Collabora, Ltd.
4
*
5
* Permission is hereby granted, free of charge, to any person obtaining a
6
* copy of this software and associated documentation files (the "Software"),
7
* to deal in the Software without restriction, including without limitation
8
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
9
* and/or sell copies of the Software, and to permit persons to whom the
10
* Software is furnished to do so, subject to the following conditions:
11
*
12
* The above copyright notice and this permission notice (including the next
13
* paragraph) shall be included in all copies or substantial portions of the
14
* Software.
15
*
16
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23
* DEALINGS IN THE SOFTWARE.
24
*
25
* Authors:
26
* Kristian HĆøgsberg <[email protected]>
27
* Benjamin Franzke <[email protected]>
28
*/
29
30
#include <stdint.h>
31
#include <stdlib.h>
32
#include <string.h>
33
#include <limits.h>
34
#include <dlfcn.h>
35
#include <errno.h>
36
#include <unistd.h>
37
#include <fcntl.h>
38
#include <xf86drm.h>
39
#include "drm-uapi/drm_fourcc.h"
40
#include <sys/mman.h>
41
42
#include "egl_dri2.h"
43
#include "loader_dri_helper.h"
44
#include "loader.h"
45
#include "util/u_vector.h"
46
#include "util/anon_file.h"
47
#include "eglglobals.h"
48
49
#include <wayland-egl-backend.h>
50
#include <wayland-client.h>
51
#include "wayland-drm-client-protocol.h"
52
#include "linux-dmabuf-unstable-v1-client-protocol.h"
53
54
/*
55
* The index of entries in this table is used as a bitmask in
56
* dri2_dpy->formats, which tracks the formats supported by our server.
57
*/
58
static const struct dri2_wl_visual {
59
const char *format_name;
60
uint32_t wl_drm_format;
61
uint32_t wl_shm_format;
62
int dri_image_format;
63
/* alt_dri_image_format is a substitute wl_buffer format to use for a
64
* wl-server unsupported dri_image_format, ie. some other dri_image_format in
65
* the table, of the same precision but with different channel ordering, or
66
* __DRI_IMAGE_FORMAT_NONE if an alternate format is not needed or supported.
67
* The code checks if alt_dri_image_format can be used as a fallback for a
68
* dri_image_format for a given wl-server implementation.
69
*/
70
int alt_dri_image_format;
71
int bpp;
72
int rgba_shifts[4];
73
unsigned int rgba_sizes[4];
74
} dri2_wl_visuals[] = {
75
{
76
"ABGR16F",
77
WL_DRM_FORMAT_ABGR16F, WL_SHM_FORMAT_ABGR16161616F,
78
__DRI_IMAGE_FORMAT_ABGR16161616F, 0, 64,
79
{ 0, 16, 32, 48 },
80
{ 16, 16, 16, 16 },
81
},
82
{
83
"XBGR16F",
84
WL_DRM_FORMAT_XBGR16F, WL_SHM_FORMAT_XBGR16161616F,
85
__DRI_IMAGE_FORMAT_XBGR16161616F, 0, 64,
86
{ 0, 16, 32, -1 },
87
{ 16, 16, 16, 0 },
88
},
89
{
90
"XRGB2101010",
91
WL_DRM_FORMAT_XRGB2101010, WL_SHM_FORMAT_XRGB2101010,
92
__DRI_IMAGE_FORMAT_XRGB2101010, __DRI_IMAGE_FORMAT_XBGR2101010, 32,
93
{ 20, 10, 0, -1 },
94
{ 10, 10, 10, 0 },
95
},
96
{
97
"ARGB2101010",
98
WL_DRM_FORMAT_ARGB2101010, WL_SHM_FORMAT_ARGB2101010,
99
__DRI_IMAGE_FORMAT_ARGB2101010, __DRI_IMAGE_FORMAT_ABGR2101010, 32,
100
{ 20, 10, 0, 30 },
101
{ 10, 10, 10, 2 },
102
},
103
{
104
"XBGR2101010",
105
WL_DRM_FORMAT_XBGR2101010, WL_SHM_FORMAT_XBGR2101010,
106
__DRI_IMAGE_FORMAT_XBGR2101010, __DRI_IMAGE_FORMAT_XRGB2101010, 32,
107
{ 0, 10, 20, -1 },
108
{ 10, 10, 10, 0 },
109
},
110
{
111
"ABGR2101010",
112
WL_DRM_FORMAT_ABGR2101010, WL_SHM_FORMAT_ABGR2101010,
113
__DRI_IMAGE_FORMAT_ABGR2101010, __DRI_IMAGE_FORMAT_ARGB2101010, 32,
114
{ 0, 10, 20, 30 },
115
{ 10, 10, 10, 2 },
116
},
117
{
118
"XRGB8888",
119
WL_DRM_FORMAT_XRGB8888, WL_SHM_FORMAT_XRGB8888,
120
__DRI_IMAGE_FORMAT_XRGB8888, __DRI_IMAGE_FORMAT_NONE, 32,
121
{ 16, 8, 0, -1 },
122
{ 8, 8, 8, 0 },
123
},
124
{
125
"ARGB8888",
126
WL_DRM_FORMAT_ARGB8888, WL_SHM_FORMAT_ARGB8888,
127
__DRI_IMAGE_FORMAT_ARGB8888, __DRI_IMAGE_FORMAT_NONE, 32,
128
{ 16, 8, 0, 24 },
129
{ 8, 8, 8, 8 },
130
},
131
{
132
"RGB565",
133
WL_DRM_FORMAT_RGB565, WL_SHM_FORMAT_RGB565,
134
__DRI_IMAGE_FORMAT_RGB565, __DRI_IMAGE_FORMAT_NONE, 16,
135
{ 11, 5, 0, -1 },
136
{ 5, 6, 5, 0 },
137
},
138
};
139
140
static_assert(ARRAY_SIZE(dri2_wl_visuals) <= EGL_DRI2_MAX_FORMATS,
141
"dri2_egl_display::formats is not large enough for "
142
"the formats in dri2_wl_visuals");
143
144
static int
145
dri2_wl_visual_idx_from_config(struct dri2_egl_display *dri2_dpy,
146
const __DRIconfig *config)
147
{
148
int shifts[4];
149
unsigned int sizes[4];
150
151
dri2_get_shifts_and_sizes(dri2_dpy->core, config, shifts, sizes);
152
153
for (unsigned int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {
154
const struct dri2_wl_visual *wl_visual = &dri2_wl_visuals[i];
155
156
if (shifts[0] == wl_visual->rgba_shifts[0] &&
157
shifts[1] == wl_visual->rgba_shifts[1] &&
158
shifts[2] == wl_visual->rgba_shifts[2] &&
159
shifts[3] == wl_visual->rgba_shifts[3] &&
160
sizes[0] == wl_visual->rgba_sizes[0] &&
161
sizes[1] == wl_visual->rgba_sizes[1] &&
162
sizes[2] == wl_visual->rgba_sizes[2] &&
163
sizes[3] == wl_visual->rgba_sizes[3]) {
164
return i;
165
}
166
}
167
168
return -1;
169
}
170
171
static int
172
dri2_wl_visual_idx_from_fourcc(uint32_t fourcc)
173
{
174
for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {
175
/* wl_drm format codes overlap with DRIImage FourCC codes for all formats
176
* we support. */
177
if (dri2_wl_visuals[i].wl_drm_format == fourcc)
178
return i;
179
}
180
181
return -1;
182
}
183
184
static int
185
dri2_wl_visual_idx_from_dri_image_format(uint32_t dri_image_format)
186
{
187
for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {
188
if (dri2_wl_visuals[i].dri_image_format == dri_image_format)
189
return i;
190
}
191
192
return -1;
193
}
194
195
static int
196
dri2_wl_visual_idx_from_shm_format(uint32_t shm_format)
197
{
198
for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {
199
if (dri2_wl_visuals[i].wl_shm_format == shm_format)
200
return i;
201
}
202
203
return -1;
204
}
205
206
bool
207
dri2_wl_is_format_supported(void* user_data, uint32_t format)
208
{
209
_EGLDisplay *disp = (_EGLDisplay *) user_data;
210
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
211
int j = dri2_wl_visual_idx_from_fourcc(format);
212
213
if (j == -1)
214
return false;
215
216
for (int i = 0; dri2_dpy->driver_configs[i]; i++)
217
if (j == dri2_wl_visual_idx_from_config(dri2_dpy,
218
dri2_dpy->driver_configs[i]))
219
return true;
220
221
return false;
222
}
223
224
static int
225
roundtrip(struct dri2_egl_display *dri2_dpy)
226
{
227
return wl_display_roundtrip_queue(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);
228
}
229
230
static void
231
wl_buffer_release(void *data, struct wl_buffer *buffer)
232
{
233
struct dri2_egl_surface *dri2_surf = data;
234
int i;
235
236
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); ++i)
237
if (dri2_surf->color_buffers[i].wl_buffer == buffer)
238
break;
239
240
assert (i < ARRAY_SIZE(dri2_surf->color_buffers));
241
242
if (dri2_surf->color_buffers[i].wl_release) {
243
wl_buffer_destroy(buffer);
244
dri2_surf->color_buffers[i].wl_release = false;
245
dri2_surf->color_buffers[i].wl_buffer = NULL;
246
}
247
248
dri2_surf->color_buffers[i].locked = false;
249
}
250
251
static const struct wl_buffer_listener wl_buffer_listener = {
252
.release = wl_buffer_release
253
};
254
255
static void
256
resize_callback(struct wl_egl_window *wl_win, void *data)
257
{
258
struct dri2_egl_surface *dri2_surf = data;
259
struct dri2_egl_display *dri2_dpy =
260
dri2_egl_display(dri2_surf->base.Resource.Display);
261
262
if (dri2_surf->base.Width == wl_win->width &&
263
dri2_surf->base.Height == wl_win->height)
264
return;
265
266
/* Update the surface size as soon as native window is resized; from user
267
* pov, this makes the effect that resize is done immediately after native
268
* window resize, without requiring to wait until the first draw.
269
*
270
* A more detailed and lengthy explanation can be found at
271
* https://lists.freedesktop.org/archives/mesa-dev/2018-June/196474.html
272
*/
273
if (!dri2_surf->back) {
274
dri2_surf->base.Width = wl_win->width;
275
dri2_surf->base.Height = wl_win->height;
276
}
277
dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
278
}
279
280
static void
281
destroy_window_callback(void *data)
282
{
283
struct dri2_egl_surface *dri2_surf = data;
284
dri2_surf->wl_win = NULL;
285
}
286
287
static struct wl_surface *
288
get_wl_surface_proxy(struct wl_egl_window *window)
289
{
290
/* Version 3 of wl_egl_window introduced a version field at the same
291
* location where a pointer to wl_surface was stored. Thus, if
292
* window->version is dereferenceable, we've been given an older version of
293
* wl_egl_window, and window->version points to wl_surface */
294
if (_eglPointerIsDereferencable((void *)(window->version))) {
295
return wl_proxy_create_wrapper((void *)(window->version));
296
}
297
return wl_proxy_create_wrapper(window->surface);
298
}
299
300
/**
301
* Called via eglCreateWindowSurface(), drv->CreateWindowSurface().
302
*/
303
static _EGLSurface *
304
dri2_wl_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
305
void *native_window, const EGLint *attrib_list)
306
{
307
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
308
struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
309
struct wl_egl_window *window = native_window;
310
struct dri2_egl_surface *dri2_surf;
311
int visual_idx;
312
const __DRIconfig *config;
313
314
if (!window) {
315
_eglError(EGL_BAD_NATIVE_WINDOW, "dri2_create_surface");
316
return NULL;
317
}
318
319
if (window->driver_private) {
320
_eglError(EGL_BAD_ALLOC, "dri2_create_surface");
321
return NULL;
322
}
323
324
dri2_surf = calloc(1, sizeof *dri2_surf);
325
if (!dri2_surf) {
326
_eglError(EGL_BAD_ALLOC, "dri2_create_surface");
327
return NULL;
328
}
329
330
if (!dri2_init_surface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf,
331
attrib_list, false, native_window))
332
goto cleanup_surf;
333
334
config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT,
335
dri2_surf->base.GLColorspace);
336
337
if (!config) {
338
_eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration");
339
goto cleanup_surf;
340
}
341
342
dri2_surf->base.Width = window->width;
343
dri2_surf->base.Height = window->height;
344
345
visual_idx = dri2_wl_visual_idx_from_config(dri2_dpy, config);
346
assert(visual_idx != -1);
347
348
if (dri2_dpy->wl_dmabuf || dri2_dpy->wl_drm) {
349
dri2_surf->format = dri2_wl_visuals[visual_idx].wl_drm_format;
350
} else {
351
assert(dri2_dpy->wl_shm);
352
dri2_surf->format = dri2_wl_visuals[visual_idx].wl_shm_format;
353
}
354
355
dri2_surf->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
356
if (!dri2_surf->wl_queue) {
357
_eglError(EGL_BAD_ALLOC, "dri2_create_surface");
358
goto cleanup_surf;
359
}
360
361
if (dri2_dpy->wl_drm) {
362
dri2_surf->wl_drm_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_drm);
363
if (!dri2_surf->wl_drm_wrapper) {
364
_eglError(EGL_BAD_ALLOC, "dri2_create_surface");
365
goto cleanup_queue;
366
}
367
wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_drm_wrapper,
368
dri2_surf->wl_queue);
369
}
370
371
dri2_surf->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy);
372
if (!dri2_surf->wl_dpy_wrapper) {
373
_eglError(EGL_BAD_ALLOC, "dri2_create_surface");
374
goto cleanup_drm;
375
}
376
wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_dpy_wrapper,
377
dri2_surf->wl_queue);
378
379
dri2_surf->wl_surface_wrapper = get_wl_surface_proxy(window);
380
if (!dri2_surf->wl_surface_wrapper) {
381
_eglError(EGL_BAD_ALLOC, "dri2_create_surface");
382
goto cleanup_dpy_wrapper;
383
}
384
wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_surface_wrapper,
385
dri2_surf->wl_queue);
386
387
dri2_surf->wl_win = window;
388
dri2_surf->wl_win->driver_private = dri2_surf;
389
dri2_surf->wl_win->destroy_window_callback = destroy_window_callback;
390
if (dri2_dpy->flush)
391
dri2_surf->wl_win->resize_callback = resize_callback;
392
393
if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf))
394
goto cleanup_surf_wrapper;
395
396
dri2_surf->base.SwapInterval = dri2_dpy->default_swap_interval;
397
398
return &dri2_surf->base;
399
400
cleanup_surf_wrapper:
401
wl_proxy_wrapper_destroy(dri2_surf->wl_surface_wrapper);
402
cleanup_dpy_wrapper:
403
wl_proxy_wrapper_destroy(dri2_surf->wl_dpy_wrapper);
404
cleanup_drm:
405
if (dri2_surf->wl_drm_wrapper)
406
wl_proxy_wrapper_destroy(dri2_surf->wl_drm_wrapper);
407
cleanup_queue:
408
wl_event_queue_destroy(dri2_surf->wl_queue);
409
cleanup_surf:
410
free(dri2_surf);
411
412
return NULL;
413
}
414
415
static _EGLSurface *
416
dri2_wl_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf,
417
void *native_window, const EGLint *attrib_list)
418
{
419
/* From the EGL_EXT_platform_wayland spec, version 3:
420
*
421
* It is not valid to call eglCreatePlatformPixmapSurfaceEXT with a <dpy>
422
* that belongs to Wayland. Any such call fails and generates
423
* EGL_BAD_PARAMETER.
424
*/
425
_eglError(EGL_BAD_PARAMETER, "cannot create EGL pixmap surfaces on "
426
"Wayland");
427
return NULL;
428
}
429
430
/**
431
* Called via eglDestroySurface(), drv->DestroySurface().
432
*/
433
static EGLBoolean
434
dri2_wl_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
435
{
436
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
437
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
438
439
dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
440
441
for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
442
if (dri2_surf->color_buffers[i].wl_buffer)
443
wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
444
if (dri2_surf->color_buffers[i].dri_image)
445
dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
446
if (dri2_surf->color_buffers[i].linear_copy)
447
dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);
448
if (dri2_surf->color_buffers[i].data)
449
munmap(dri2_surf->color_buffers[i].data,
450
dri2_surf->color_buffers[i].data_size);
451
}
452
453
if (dri2_dpy->dri2)
454
dri2_egl_surface_free_local_buffers(dri2_surf);
455
456
if (dri2_surf->throttle_callback)
457
wl_callback_destroy(dri2_surf->throttle_callback);
458
459
if (dri2_surf->wl_win) {
460
dri2_surf->wl_win->driver_private = NULL;
461
dri2_surf->wl_win->resize_callback = NULL;
462
dri2_surf->wl_win->destroy_window_callback = NULL;
463
}
464
465
wl_proxy_wrapper_destroy(dri2_surf->wl_surface_wrapper);
466
wl_proxy_wrapper_destroy(dri2_surf->wl_dpy_wrapper);
467
if (dri2_surf->wl_drm_wrapper)
468
wl_proxy_wrapper_destroy(dri2_surf->wl_drm_wrapper);
469
wl_event_queue_destroy(dri2_surf->wl_queue);
470
471
dri2_fini_surface(surf);
472
free(surf);
473
474
return EGL_TRUE;
475
}
476
477
static void
478
dri2_wl_release_buffers(struct dri2_egl_surface *dri2_surf)
479
{
480
struct dri2_egl_display *dri2_dpy =
481
dri2_egl_display(dri2_surf->base.Resource.Display);
482
483
for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
484
if (dri2_surf->color_buffers[i].wl_buffer) {
485
if (dri2_surf->color_buffers[i].locked) {
486
dri2_surf->color_buffers[i].wl_release = true;
487
} else {
488
wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
489
dri2_surf->color_buffers[i].wl_buffer = NULL;
490
}
491
}
492
if (dri2_surf->color_buffers[i].dri_image)
493
dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
494
if (dri2_surf->color_buffers[i].linear_copy)
495
dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);
496
if (dri2_surf->color_buffers[i].data)
497
munmap(dri2_surf->color_buffers[i].data,
498
dri2_surf->color_buffers[i].data_size);
499
500
dri2_surf->color_buffers[i].dri_image = NULL;
501
dri2_surf->color_buffers[i].linear_copy = NULL;
502
dri2_surf->color_buffers[i].data = NULL;
503
}
504
505
if (dri2_dpy->dri2)
506
dri2_egl_surface_free_local_buffers(dri2_surf);
507
}
508
509
static int
510
get_back_bo(struct dri2_egl_surface *dri2_surf)
511
{
512
struct dri2_egl_display *dri2_dpy =
513
dri2_egl_display(dri2_surf->base.Resource.Display);
514
int use_flags;
515
int visual_idx;
516
unsigned int dri_image_format;
517
unsigned int linear_dri_image_format;
518
uint64_t *modifiers;
519
int num_modifiers;
520
521
visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format);
522
assert(visual_idx != -1);
523
dri_image_format = dri2_wl_visuals[visual_idx].dri_image_format;
524
linear_dri_image_format = dri_image_format;
525
modifiers = u_vector_tail(&dri2_dpy->wl_modifiers[visual_idx]);
526
num_modifiers = u_vector_length(&dri2_dpy->wl_modifiers[visual_idx]);
527
528
if (num_modifiers == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) {
529
/* For the purposes of this function, an INVALID modifier on its own
530
* means the modifiers aren't supported.
531
*/
532
num_modifiers = 0;
533
}
534
535
/* Substitute dri image format if server does not support original format */
536
if (!BITSET_TEST(dri2_dpy->formats, visual_idx))
537
linear_dri_image_format = dri2_wl_visuals[visual_idx].alt_dri_image_format;
538
539
/* These asserts hold, as long as dri2_wl_visuals[] is self-consistent and
540
* the PRIME substitution logic in dri2_wl_add_configs_for_visuals() is free
541
* of bugs.
542
*/
543
assert(linear_dri_image_format != __DRI_IMAGE_FORMAT_NONE);
544
assert(BITSET_TEST(dri2_dpy->formats,
545
dri2_wl_visual_idx_from_dri_image_format(linear_dri_image_format)));
546
547
/* There might be a buffer release already queued that wasn't processed */
548
wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_surf->wl_queue);
549
550
while (dri2_surf->back == NULL) {
551
for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
552
/* Get an unlocked buffer, preferably one with a dri_buffer
553
* already allocated. */
554
if (dri2_surf->color_buffers[i].locked)
555
continue;
556
if (dri2_surf->back == NULL)
557
dri2_surf->back = &dri2_surf->color_buffers[i];
558
else if (dri2_surf->back->dri_image == NULL)
559
dri2_surf->back = &dri2_surf->color_buffers[i];
560
}
561
562
if (dri2_surf->back)
563
break;
564
565
/* If we don't have a buffer, then block on the server to release one for
566
* us, and try again. wl_display_dispatch_queue will process any pending
567
* events, however not all servers flush on issuing a buffer release
568
* event. So, we spam the server with roundtrips as they always cause a
569
* client flush.
570
*/
571
if (wl_display_roundtrip_queue(dri2_dpy->wl_dpy,
572
dri2_surf->wl_queue) < 0)
573
return -1;
574
}
575
576
if (dri2_surf->back == NULL)
577
return -1;
578
579
use_flags = __DRI_IMAGE_USE_SHARE | __DRI_IMAGE_USE_BACKBUFFER;
580
581
if (dri2_surf->base.ProtectedContent) {
582
/* Protected buffers can't be read from another GPU */
583
if (dri2_dpy->is_different_gpu)
584
return -1;
585
use_flags |= __DRI_IMAGE_USE_PROTECTED;
586
}
587
588
if (dri2_dpy->is_different_gpu &&
589
dri2_surf->back->linear_copy == NULL) {
590
/* The LINEAR modifier should be a perfect alias of the LINEAR use
591
* flag; try the new interface first before the old, then fall back. */
592
uint64_t linear_mod = DRM_FORMAT_MOD_LINEAR;
593
594
dri2_surf->back->linear_copy =
595
loader_dri_create_image(dri2_dpy->dri_screen, dri2_dpy->image,
596
dri2_surf->base.Width,
597
dri2_surf->base.Height,
598
linear_dri_image_format,
599
use_flags | __DRI_IMAGE_USE_LINEAR,
600
&linear_mod, 1, NULL);
601
602
if (dri2_surf->back->linear_copy == NULL)
603
return -1;
604
}
605
606
if (dri2_surf->back->dri_image == NULL) {
607
/* If our DRIImage implementation does not support
608
* createImageWithModifiers, then fall back to the old createImage,
609
* and hope it allocates an image which is acceptable to the winsys.
610
*/
611
dri2_surf->back->dri_image =
612
loader_dri_create_image(dri2_dpy->dri_screen, dri2_dpy->image,
613
dri2_surf->base.Width,
614
dri2_surf->base.Height,
615
dri_image_format,
616
dri2_dpy->is_different_gpu ? 0 : use_flags,
617
modifiers, num_modifiers, NULL);
618
619
dri2_surf->back->age = 0;
620
}
621
if (dri2_surf->back->dri_image == NULL)
622
return -1;
623
624
dri2_surf->back->locked = true;
625
626
return 0;
627
}
628
629
630
static void
631
back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer)
632
{
633
struct dri2_egl_display *dri2_dpy =
634
dri2_egl_display(dri2_surf->base.Resource.Display);
635
__DRIimage *image;
636
int name, pitch;
637
638
image = dri2_surf->back->dri_image;
639
640
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
641
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);
642
643
buffer->attachment = __DRI_BUFFER_BACK_LEFT;
644
buffer->name = name;
645
buffer->pitch = pitch;
646
buffer->cpp = 4;
647
buffer->flags = 0;
648
}
649
650
static int
651
update_buffers(struct dri2_egl_surface *dri2_surf)
652
{
653
struct dri2_egl_display *dri2_dpy =
654
dri2_egl_display(dri2_surf->base.Resource.Display);
655
656
if (dri2_surf->wl_win &&
657
(dri2_surf->base.Width != dri2_surf->wl_win->width ||
658
dri2_surf->base.Height != dri2_surf->wl_win->height)) {
659
660
dri2_surf->base.Width = dri2_surf->wl_win->width;
661
dri2_surf->base.Height = dri2_surf->wl_win->height;
662
dri2_surf->dx = dri2_surf->wl_win->dx;
663
dri2_surf->dy = dri2_surf->wl_win->dy;
664
}
665
666
if (dri2_surf->wl_win &&
667
(dri2_surf->base.Width != dri2_surf->wl_win->attached_width ||
668
dri2_surf->base.Height != dri2_surf->wl_win->attached_height)) {
669
dri2_wl_release_buffers(dri2_surf);
670
}
671
672
if (get_back_bo(dri2_surf) < 0) {
673
_eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");
674
return -1;
675
}
676
677
/* If we have an extra unlocked buffer at this point, we had to do triple
678
* buffering for a while, but now can go back to just double buffering.
679
* That means we can free any unlocked buffer now. */
680
for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
681
if (!dri2_surf->color_buffers[i].locked &&
682
dri2_surf->color_buffers[i].wl_buffer) {
683
wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
684
dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
685
if (dri2_dpy->is_different_gpu)
686
dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);
687
dri2_surf->color_buffers[i].wl_buffer = NULL;
688
dri2_surf->color_buffers[i].dri_image = NULL;
689
dri2_surf->color_buffers[i].linear_copy = NULL;
690
}
691
}
692
693
return 0;
694
}
695
696
static int
697
update_buffers_if_needed(struct dri2_egl_surface *dri2_surf)
698
{
699
if (dri2_surf->back != NULL)
700
return 0;
701
702
return update_buffers(dri2_surf);
703
}
704
705
static __DRIbuffer *
706
dri2_wl_get_buffers_with_format(__DRIdrawable * driDrawable,
707
int *width, int *height,
708
unsigned int *attachments, int count,
709
int *out_count, void *loaderPrivate)
710
{
711
struct dri2_egl_surface *dri2_surf = loaderPrivate;
712
int i, j;
713
714
if (update_buffers(dri2_surf) < 0)
715
return NULL;
716
717
for (i = 0, j = 0; i < 2 * count; i += 2, j++) {
718
__DRIbuffer *local;
719
720
switch (attachments[i]) {
721
case __DRI_BUFFER_BACK_LEFT:
722
back_bo_to_dri_buffer(dri2_surf, &dri2_surf->buffers[j]);
723
break;
724
default:
725
local = dri2_egl_surface_alloc_local_buffer(dri2_surf, attachments[i],
726
attachments[i + 1]);
727
728
if (!local) {
729
_eglError(EGL_BAD_ALLOC, "failed to allocate local buffer");
730
return NULL;
731
}
732
dri2_surf->buffers[j] = *local;
733
break;
734
}
735
}
736
737
*out_count = j;
738
if (j == 0)
739
return NULL;
740
741
*width = dri2_surf->base.Width;
742
*height = dri2_surf->base.Height;
743
744
return dri2_surf->buffers;
745
}
746
747
static __DRIbuffer *
748
dri2_wl_get_buffers(__DRIdrawable * driDrawable,
749
int *width, int *height,
750
unsigned int *attachments, int count,
751
int *out_count, void *loaderPrivate)
752
{
753
struct dri2_egl_surface *dri2_surf = loaderPrivate;
754
unsigned int *attachments_with_format;
755
__DRIbuffer *buffer;
756
int visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format);
757
758
if (visual_idx == -1)
759
return NULL;
760
761
attachments_with_format = calloc(count, 2 * sizeof(unsigned int));
762
if (!attachments_with_format) {
763
*out_count = 0;
764
return NULL;
765
}
766
767
for (int i = 0; i < count; ++i) {
768
attachments_with_format[2*i] = attachments[i];
769
attachments_with_format[2*i + 1] = dri2_wl_visuals[visual_idx].bpp;
770
}
771
772
buffer =
773
dri2_wl_get_buffers_with_format(driDrawable,
774
width, height,
775
attachments_with_format, count,
776
out_count, loaderPrivate);
777
778
free(attachments_with_format);
779
780
return buffer;
781
}
782
783
static int
784
image_get_buffers(__DRIdrawable *driDrawable,
785
unsigned int format,
786
uint32_t *stamp,
787
void *loaderPrivate,
788
uint32_t buffer_mask,
789
struct __DRIimageList *buffers)
790
{
791
struct dri2_egl_surface *dri2_surf = loaderPrivate;
792
793
if (update_buffers(dri2_surf) < 0)
794
return 0;
795
796
buffers->image_mask = __DRI_IMAGE_BUFFER_BACK;
797
buffers->back = dri2_surf->back->dri_image;
798
799
return 1;
800
}
801
802
static void
803
dri2_wl_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
804
{
805
(void) driDrawable;
806
(void) loaderPrivate;
807
}
808
809
static unsigned
810
dri2_wl_get_capability(void *loaderPrivate, enum dri_loader_cap cap)
811
{
812
switch (cap) {
813
case DRI_LOADER_CAP_FP16:
814
return 1;
815
default:
816
return 0;
817
}
818
}
819
820
static const __DRIdri2LoaderExtension dri2_loader_extension = {
821
.base = { __DRI_DRI2_LOADER, 4 },
822
823
.getBuffers = dri2_wl_get_buffers,
824
.flushFrontBuffer = dri2_wl_flush_front_buffer,
825
.getBuffersWithFormat = dri2_wl_get_buffers_with_format,
826
.getCapability = dri2_wl_get_capability,
827
};
828
829
static const __DRIimageLoaderExtension image_loader_extension = {
830
.base = { __DRI_IMAGE_LOADER, 2 },
831
832
.getBuffers = image_get_buffers,
833
.flushFrontBuffer = dri2_wl_flush_front_buffer,
834
.getCapability = dri2_wl_get_capability,
835
};
836
837
static void
838
wayland_throttle_callback(void *data,
839
struct wl_callback *callback,
840
uint32_t time)
841
{
842
struct dri2_egl_surface *dri2_surf = data;
843
844
dri2_surf->throttle_callback = NULL;
845
wl_callback_destroy(callback);
846
}
847
848
static const struct wl_callback_listener throttle_listener = {
849
.done = wayland_throttle_callback
850
};
851
852
static EGLBoolean
853
get_fourcc(struct dri2_egl_display *dri2_dpy,
854
__DRIimage *image, int *fourcc)
855
{
856
EGLBoolean query;
857
int dri_format;
858
int visual_idx;
859
860
query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FOURCC,
861
fourcc);
862
if (query)
863
return true;
864
865
query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT,
866
&dri_format);
867
if (!query)
868
return false;
869
870
visual_idx = dri2_wl_visual_idx_from_dri_image_format(dri_format);
871
if (visual_idx == -1)
872
return false;
873
874
*fourcc = dri2_wl_visuals[visual_idx].wl_drm_format;
875
return true;
876
}
877
878
static struct wl_buffer *
879
create_wl_buffer(struct dri2_egl_display *dri2_dpy,
880
struct dri2_egl_surface *dri2_surf,
881
__DRIimage *image)
882
{
883
struct wl_buffer *ret;
884
EGLBoolean query;
885
int width, height, fourcc, num_planes;
886
uint64_t modifier = DRM_FORMAT_MOD_INVALID;
887
888
query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_WIDTH, &width);
889
query &= dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HEIGHT,
890
&height);
891
query &= get_fourcc(dri2_dpy, image, &fourcc);
892
if (!query)
893
return NULL;
894
895
query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NUM_PLANES,
896
&num_planes);
897
if (!query)
898
num_planes = 1;
899
900
if (dri2_dpy->image->base.version >= 15) {
901
int mod_hi, mod_lo;
902
903
query = dri2_dpy->image->queryImage(image,
904
__DRI_IMAGE_ATTRIB_MODIFIER_UPPER,
905
&mod_hi);
906
query &= dri2_dpy->image->queryImage(image,
907
__DRI_IMAGE_ATTRIB_MODIFIER_LOWER,
908
&mod_lo);
909
if (query) {
910
modifier = combine_u32_into_u64(mod_hi, mod_lo);
911
}
912
}
913
914
bool supported_modifier = false;
915
bool mod_invalid_supported = false;
916
int visual_idx = dri2_wl_visual_idx_from_fourcc(fourcc);
917
assert(visual_idx != -1);
918
919
uint64_t *mod;
920
u_vector_foreach(mod, &dri2_dpy->wl_modifiers[visual_idx]) {
921
if (*mod == DRM_FORMAT_MOD_INVALID) {
922
mod_invalid_supported = true;
923
}
924
if (*mod == modifier) {
925
supported_modifier = true;
926
break;
927
}
928
}
929
if (!supported_modifier && mod_invalid_supported) {
930
/* If the server has advertised DRM_FORMAT_MOD_INVALID then we trust
931
* that the client has allocated the buffer with the right implicit
932
* modifier for the format, even though it's allocated a buffer the
933
* server hasn't explicitly claimed to support. */
934
modifier = DRM_FORMAT_MOD_INVALID;
935
supported_modifier = true;
936
}
937
938
if (dri2_dpy->wl_dmabuf && supported_modifier) {
939
struct zwp_linux_buffer_params_v1 *params;
940
int i;
941
942
/* We don't need a wrapper for wl_dmabuf objects, because we have to
943
* create the intermediate params object; we can set the queue on this,
944
* and the wl_buffer inherits it race-free. */
945
params = zwp_linux_dmabuf_v1_create_params(dri2_dpy->wl_dmabuf);
946
if (dri2_surf)
947
wl_proxy_set_queue((struct wl_proxy *) params, dri2_surf->wl_queue);
948
949
for (i = 0; i < num_planes; i++) {
950
__DRIimage *p_image;
951
int stride, offset;
952
int fd = -1;
953
954
p_image = dri2_dpy->image->fromPlanar(image, i, NULL);
955
if (!p_image) {
956
assert(i == 0);
957
p_image = image;
958
}
959
960
query = dri2_dpy->image->queryImage(p_image,
961
__DRI_IMAGE_ATTRIB_FD,
962
&fd);
963
query &= dri2_dpy->image->queryImage(p_image,
964
__DRI_IMAGE_ATTRIB_STRIDE,
965
&stride);
966
query &= dri2_dpy->image->queryImage(p_image,
967
__DRI_IMAGE_ATTRIB_OFFSET,
968
&offset);
969
if (image != p_image)
970
dri2_dpy->image->destroyImage(p_image);
971
972
if (!query) {
973
if (fd >= 0)
974
close(fd);
975
zwp_linux_buffer_params_v1_destroy(params);
976
return NULL;
977
}
978
979
zwp_linux_buffer_params_v1_add(params, fd, i, offset, stride,
980
modifier >> 32, modifier & 0xffffffff);
981
close(fd);
982
}
983
984
ret = zwp_linux_buffer_params_v1_create_immed(params, width, height,
985
fourcc, 0);
986
zwp_linux_buffer_params_v1_destroy(params);
987
} else if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) {
988
struct wl_drm *wl_drm =
989
dri2_surf ? dri2_surf->wl_drm_wrapper : dri2_dpy->wl_drm;
990
int fd, stride;
991
992
if (num_planes > 1)
993
return NULL;
994
995
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd);
996
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
997
ret = wl_drm_create_prime_buffer(wl_drm, fd, width, height, fourcc, 0,
998
stride, 0, 0, 0, 0);
999
close(fd);
1000
} else {
1001
struct wl_drm *wl_drm =
1002
dri2_surf ? dri2_surf->wl_drm_wrapper : dri2_dpy->wl_drm;
1003
int name, stride;
1004
1005
if (num_planes > 1)
1006
return NULL;
1007
1008
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
1009
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
1010
ret = wl_drm_create_buffer(wl_drm, name, width, height, stride, fourcc);
1011
}
1012
1013
return ret;
1014
}
1015
1016
static EGLBoolean
1017
try_damage_buffer(struct dri2_egl_surface *dri2_surf,
1018
const EGLint *rects,
1019
EGLint n_rects)
1020
{
1021
if (wl_proxy_get_version((struct wl_proxy *) dri2_surf->wl_surface_wrapper)
1022
< WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION)
1023
return EGL_FALSE;
1024
1025
for (int i = 0; i < n_rects; i++) {
1026
const int *rect = &rects[i * 4];
1027
1028
wl_surface_damage_buffer(dri2_surf->wl_surface_wrapper,
1029
rect[0],
1030
dri2_surf->base.Height - rect[1] - rect[3],
1031
rect[2], rect[3]);
1032
}
1033
return EGL_TRUE;
1034
}
1035
1036
/**
1037
* Called via eglSwapBuffers(), drv->SwapBuffers().
1038
*/
1039
static EGLBoolean
1040
dri2_wl_swap_buffers_with_damage(_EGLDisplay *disp,
1041
_EGLSurface *draw,
1042
const EGLint *rects,
1043
EGLint n_rects)
1044
{
1045
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1046
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
1047
1048
if (!dri2_surf->wl_win)
1049
return _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_swap_buffers");
1050
1051
while (dri2_surf->throttle_callback != NULL)
1052
if (wl_display_dispatch_queue(dri2_dpy->wl_dpy,
1053
dri2_surf->wl_queue) == -1)
1054
return -1;
1055
1056
for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
1057
if (dri2_surf->color_buffers[i].age > 0)
1058
dri2_surf->color_buffers[i].age++;
1059
1060
/* Make sure we have a back buffer in case we're swapping without ever
1061
* rendering. */
1062
if (update_buffers_if_needed(dri2_surf) < 0)
1063
return _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers");
1064
1065
if (draw->SwapInterval > 0) {
1066
dri2_surf->throttle_callback =
1067
wl_surface_frame(dri2_surf->wl_surface_wrapper);
1068
wl_callback_add_listener(dri2_surf->throttle_callback,
1069
&throttle_listener, dri2_surf);
1070
}
1071
1072
dri2_surf->back->age = 1;
1073
dri2_surf->current = dri2_surf->back;
1074
dri2_surf->back = NULL;
1075
1076
if (!dri2_surf->current->wl_buffer) {
1077
__DRIimage *image;
1078
1079
if (dri2_dpy->is_different_gpu)
1080
image = dri2_surf->current->linear_copy;
1081
else
1082
image = dri2_surf->current->dri_image;
1083
1084
dri2_surf->current->wl_buffer =
1085
create_wl_buffer(dri2_dpy, dri2_surf, image);
1086
1087
dri2_surf->current->wl_release = false;
1088
1089
wl_buffer_add_listener(dri2_surf->current->wl_buffer,
1090
&wl_buffer_listener, dri2_surf);
1091
}
1092
1093
wl_surface_attach(dri2_surf->wl_surface_wrapper,
1094
dri2_surf->current->wl_buffer,
1095
dri2_surf->dx, dri2_surf->dy);
1096
1097
dri2_surf->wl_win->attached_width = dri2_surf->base.Width;
1098
dri2_surf->wl_win->attached_height = dri2_surf->base.Height;
1099
/* reset resize growing parameters */
1100
dri2_surf->dx = 0;
1101
dri2_surf->dy = 0;
1102
1103
/* If the compositor doesn't support damage_buffer, we deliberately
1104
* ignore the damage region and post maximum damage, due to
1105
* https://bugs.freedesktop.org/78190 */
1106
if (!n_rects || !try_damage_buffer(dri2_surf, rects, n_rects))
1107
wl_surface_damage(dri2_surf->wl_surface_wrapper,
1108
0, 0, INT32_MAX, INT32_MAX);
1109
1110
if (dri2_dpy->is_different_gpu) {
1111
_EGLContext *ctx = _eglGetCurrentContext();
1112
struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
1113
dri2_dpy->image->blitImage(dri2_ctx->dri_context,
1114
dri2_surf->current->linear_copy,
1115
dri2_surf->current->dri_image,
1116
0, 0, dri2_surf->base.Width,
1117
dri2_surf->base.Height,
1118
0, 0, dri2_surf->base.Width,
1119
dri2_surf->base.Height, 0);
1120
}
1121
1122
dri2_flush_drawable_for_swapbuffers(disp, draw);
1123
dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
1124
1125
wl_surface_commit(dri2_surf->wl_surface_wrapper);
1126
1127
/* If we're not waiting for a frame callback then we'll at least throttle
1128
* to a sync callback so that we always give a chance for the compositor to
1129
* handle the commit and send a release event before checking for a free
1130
* buffer */
1131
if (dri2_surf->throttle_callback == NULL) {
1132
dri2_surf->throttle_callback = wl_display_sync(dri2_surf->wl_dpy_wrapper);
1133
wl_callback_add_listener(dri2_surf->throttle_callback,
1134
&throttle_listener, dri2_surf);
1135
}
1136
1137
wl_display_flush(dri2_dpy->wl_dpy);
1138
1139
return EGL_TRUE;
1140
}
1141
1142
static EGLint
1143
dri2_wl_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surface)
1144
{
1145
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
1146
1147
if (update_buffers_if_needed(dri2_surf) < 0) {
1148
_eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age");
1149
return -1;
1150
}
1151
1152
return dri2_surf->back->age;
1153
}
1154
1155
static EGLBoolean
1156
dri2_wl_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
1157
{
1158
return dri2_wl_swap_buffers_with_damage(disp, draw, NULL, 0);
1159
}
1160
1161
static struct wl_buffer *
1162
dri2_wl_create_wayland_buffer_from_image(_EGLDisplay *disp, _EGLImage *img)
1163
{
1164
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1165
struct dri2_egl_image *dri2_img = dri2_egl_image(img);
1166
__DRIimage *image = dri2_img->dri_image;
1167
struct wl_buffer *buffer;
1168
int format, visual_idx;
1169
1170
/* Check the upstream display supports this buffer's format. */
1171
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &format);
1172
visual_idx = dri2_wl_visual_idx_from_dri_image_format(format);
1173
if (visual_idx == -1)
1174
goto bad_format;
1175
1176
if (!BITSET_TEST(dri2_dpy->formats, visual_idx))
1177
goto bad_format;
1178
1179
buffer = create_wl_buffer(dri2_dpy, NULL, image);
1180
1181
/* The buffer object will have been created with our internal event queue
1182
* because it is using wl_dmabuf/wl_drm as a proxy factory. We want the
1183
* buffer to be used by the application so we'll reset it to the display's
1184
* default event queue. This isn't actually racy, as the only event the
1185
* buffer can get is a buffer release, which doesn't happen with an explicit
1186
* attach. */
1187
if (buffer)
1188
wl_proxy_set_queue((struct wl_proxy *) buffer, NULL);
1189
1190
return buffer;
1191
1192
bad_format:
1193
_eglError(EGL_BAD_MATCH, "unsupported image format");
1194
return NULL;
1195
}
1196
1197
static int
1198
dri2_wl_authenticate(_EGLDisplay *disp, uint32_t id)
1199
{
1200
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1201
int ret = 0;
1202
1203
if (dri2_dpy->is_render_node) {
1204
_eglLog(_EGL_WARNING, "wayland-egl: client asks server to "
1205
"authenticate for render-nodes");
1206
return 0;
1207
}
1208
dri2_dpy->authenticated = false;
1209
1210
wl_drm_authenticate(dri2_dpy->wl_drm, id);
1211
if (roundtrip(dri2_dpy) < 0)
1212
ret = -1;
1213
1214
if (!dri2_dpy->authenticated)
1215
ret = -1;
1216
1217
/* reset authenticated */
1218
dri2_dpy->authenticated = true;
1219
1220
return ret;
1221
}
1222
1223
static void
1224
drm_handle_device(void *data, struct wl_drm *drm, const char *device)
1225
{
1226
struct dri2_egl_display *dri2_dpy = data;
1227
drm_magic_t magic;
1228
1229
dri2_dpy->device_name = strdup(device);
1230
if (!dri2_dpy->device_name)
1231
return;
1232
1233
dri2_dpy->fd = loader_open_device(dri2_dpy->device_name);
1234
if (dri2_dpy->fd == -1) {
1235
_eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",
1236
dri2_dpy->device_name, strerror(errno));
1237
free(dri2_dpy->device_name);
1238
dri2_dpy->device_name = NULL;
1239
return;
1240
}
1241
1242
if (drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER) {
1243
dri2_dpy->authenticated = true;
1244
} else {
1245
if (drmGetMagic(dri2_dpy->fd, &magic)) {
1246
close(dri2_dpy->fd);
1247
dri2_dpy->fd = -1;
1248
free(dri2_dpy->device_name);
1249
dri2_dpy->device_name = NULL;
1250
_eglLog(_EGL_WARNING, "wayland-egl: drmGetMagic failed");
1251
return;
1252
}
1253
wl_drm_authenticate(dri2_dpy->wl_drm, magic);
1254
}
1255
}
1256
1257
static void
1258
drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
1259
{
1260
struct dri2_egl_display *dri2_dpy = data;
1261
int visual_idx = dri2_wl_visual_idx_from_fourcc(format);
1262
1263
if (visual_idx == -1)
1264
return;
1265
1266
BITSET_SET(dri2_dpy->formats, visual_idx);
1267
}
1268
1269
static void
1270
drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value)
1271
{
1272
struct dri2_egl_display *dri2_dpy = data;
1273
1274
dri2_dpy->capabilities = value;
1275
}
1276
1277
static void
1278
drm_handle_authenticated(void *data, struct wl_drm *drm)
1279
{
1280
struct dri2_egl_display *dri2_dpy = data;
1281
1282
dri2_dpy->authenticated = true;
1283
}
1284
1285
static const struct wl_drm_listener drm_listener = {
1286
.device = drm_handle_device,
1287
.format = drm_handle_format,
1288
.authenticated = drm_handle_authenticated,
1289
.capabilities = drm_handle_capabilities
1290
};
1291
1292
static void
1293
dmabuf_ignore_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
1294
uint32_t format)
1295
{
1296
/* formats are implicitly advertised by the 'modifier' event, so ignore */
1297
}
1298
1299
static void
1300
dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
1301
uint32_t format, uint32_t modifier_hi,
1302
uint32_t modifier_lo)
1303
{
1304
struct dri2_egl_display *dri2_dpy = data;
1305
int visual_idx = dri2_wl_visual_idx_from_fourcc(format);
1306
uint64_t *mod;
1307
1308
if (visual_idx == -1)
1309
return;
1310
1311
BITSET_SET(dri2_dpy->formats, visual_idx);
1312
1313
mod = u_vector_add(&dri2_dpy->wl_modifiers[visual_idx]);
1314
*mod = combine_u32_into_u64(modifier_hi, modifier_lo);
1315
}
1316
1317
static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
1318
.format = dmabuf_ignore_format,
1319
.modifier = dmabuf_handle_modifier,
1320
};
1321
1322
static void
1323
registry_handle_global_drm(void *data, struct wl_registry *registry,
1324
uint32_t name, const char *interface,
1325
uint32_t version)
1326
{
1327
struct dri2_egl_display *dri2_dpy = data;
1328
1329
if (strcmp(interface, "wl_drm") == 0) {
1330
dri2_dpy->wl_drm =
1331
wl_registry_bind(registry, name, &wl_drm_interface, MIN2(version, 2));
1332
wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy);
1333
} else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0 && version >= 3) {
1334
dri2_dpy->wl_dmabuf =
1335
wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface,
1336
MIN2(version, 3));
1337
zwp_linux_dmabuf_v1_add_listener(dri2_dpy->wl_dmabuf, &dmabuf_listener,
1338
dri2_dpy);
1339
}
1340
}
1341
1342
static void
1343
registry_handle_global_remove(void *data, struct wl_registry *registry,
1344
uint32_t name)
1345
{
1346
}
1347
1348
static const struct wl_registry_listener registry_listener_drm = {
1349
.global = registry_handle_global_drm,
1350
.global_remove = registry_handle_global_remove
1351
};
1352
1353
static void
1354
dri2_wl_setup_swap_interval(_EGLDisplay *disp)
1355
{
1356
/* We can't use values greater than 1 on Wayland because we are using the
1357
* frame callback to synchronise the frame and the only way we be sure to
1358
* get a frame callback is to attach a new buffer. Therefore we can't just
1359
* sit drawing nothing to wait until the next ā€˜n’ frame callbacks */
1360
1361
dri2_setup_swap_interval(disp, 1);
1362
}
1363
1364
static const struct dri2_egl_display_vtbl dri2_wl_display_vtbl = {
1365
.authenticate = dri2_wl_authenticate,
1366
.create_window_surface = dri2_wl_create_window_surface,
1367
.create_pixmap_surface = dri2_wl_create_pixmap_surface,
1368
.destroy_surface = dri2_wl_destroy_surface,
1369
.create_image = dri2_create_image_khr,
1370
.swap_buffers = dri2_wl_swap_buffers,
1371
.swap_buffers_with_damage = dri2_wl_swap_buffers_with_damage,
1372
.query_buffer_age = dri2_wl_query_buffer_age,
1373
.create_wayland_buffer_from_image = dri2_wl_create_wayland_buffer_from_image,
1374
.get_dri_drawable = dri2_surface_get_dri_drawable,
1375
};
1376
1377
static const __DRIextension *dri2_loader_extensions[] = {
1378
&dri2_loader_extension.base,
1379
&image_loader_extension.base,
1380
&image_lookup_extension.base,
1381
&use_invalidate.base,
1382
NULL,
1383
};
1384
1385
static const __DRIextension *image_loader_extensions[] = {
1386
&image_loader_extension.base,
1387
&image_lookup_extension.base,
1388
&use_invalidate.base,
1389
NULL,
1390
};
1391
1392
static EGLBoolean
1393
dri2_wl_add_configs_for_visuals(_EGLDisplay *disp)
1394
{
1395
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1396
unsigned int format_count[ARRAY_SIZE(dri2_wl_visuals)] = { 0 };
1397
unsigned int count = 0;
1398
bool assigned;
1399
1400
for (unsigned i = 0; dri2_dpy->driver_configs[i]; i++) {
1401
assigned = false;
1402
1403
for (unsigned j = 0; j < ARRAY_SIZE(dri2_wl_visuals); j++) {
1404
struct dri2_egl_config *dri2_conf;
1405
1406
if (!BITSET_TEST(dri2_dpy->formats, j))
1407
continue;
1408
1409
dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i],
1410
count + 1, EGL_WINDOW_BIT, NULL, dri2_wl_visuals[j].rgba_shifts, dri2_wl_visuals[j].rgba_sizes);
1411
if (dri2_conf) {
1412
if (dri2_conf->base.ConfigID == count + 1)
1413
count++;
1414
format_count[j]++;
1415
assigned = true;
1416
}
1417
}
1418
1419
if (!assigned && dri2_dpy->is_different_gpu) {
1420
struct dri2_egl_config *dri2_conf;
1421
int alt_dri_image_format, c, s;
1422
1423
/* No match for config. Try if we can blitImage convert to a visual */
1424
c = dri2_wl_visual_idx_from_config(dri2_dpy,
1425
dri2_dpy->driver_configs[i]);
1426
1427
if (c == -1)
1428
continue;
1429
1430
/* Find optimal target visual for blitImage conversion, if any. */
1431
alt_dri_image_format = dri2_wl_visuals[c].alt_dri_image_format;
1432
s = dri2_wl_visual_idx_from_dri_image_format(alt_dri_image_format);
1433
1434
if (s == -1 || !BITSET_TEST(dri2_dpy->formats, s))
1435
continue;
1436
1437
/* Visual s works for the Wayland server, and c can be converted into s
1438
* by our client gpu during PRIME blitImage conversion to a linear
1439
* wl_buffer, so add visual c as supported by the client renderer.
1440
*/
1441
dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i],
1442
count + 1, EGL_WINDOW_BIT, NULL,
1443
dri2_wl_visuals[c].rgba_shifts,
1444
dri2_wl_visuals[c].rgba_sizes);
1445
if (dri2_conf) {
1446
if (dri2_conf->base.ConfigID == count + 1)
1447
count++;
1448
format_count[c]++;
1449
if (format_count[c] == 1)
1450
_eglLog(_EGL_DEBUG, "Client format %s to server format %s via "
1451
"PRIME blitImage.", dri2_wl_visuals[c].format_name,
1452
dri2_wl_visuals[s].format_name);
1453
}
1454
}
1455
}
1456
1457
for (unsigned i = 0; i < ARRAY_SIZE(format_count); i++) {
1458
if (!format_count[i]) {
1459
_eglLog(_EGL_DEBUG, "No DRI config supports native format %s",
1460
dri2_wl_visuals[i].format_name);
1461
}
1462
}
1463
1464
return (count != 0);
1465
}
1466
1467
static EGLBoolean
1468
dri2_initialize_wayland_drm(_EGLDisplay *disp)
1469
{
1470
_EGLDevice *dev;
1471
struct dri2_egl_display *dri2_dpy;
1472
1473
dri2_dpy = calloc(1, sizeof *dri2_dpy);
1474
if (!dri2_dpy)
1475
return _eglError(EGL_BAD_ALLOC, "eglInitialize");
1476
1477
dri2_dpy->fd = -1;
1478
disp->DriverData = (void *) dri2_dpy;
1479
if (disp->PlatformDisplay == NULL) {
1480
dri2_dpy->wl_dpy = wl_display_connect(NULL);
1481
if (dri2_dpy->wl_dpy == NULL)
1482
goto cleanup;
1483
dri2_dpy->own_device = true;
1484
} else {
1485
dri2_dpy->wl_dpy = disp->PlatformDisplay;
1486
}
1487
1488
dri2_dpy->wl_modifiers =
1489
calloc(ARRAY_SIZE(dri2_wl_visuals), sizeof(*dri2_dpy->wl_modifiers));
1490
if (!dri2_dpy->wl_modifiers)
1491
goto cleanup;
1492
for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {
1493
if (!u_vector_init(&dri2_dpy->wl_modifiers[i], sizeof(uint64_t), 32))
1494
goto cleanup;
1495
}
1496
1497
dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
1498
1499
dri2_dpy->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy);
1500
if (dri2_dpy->wl_dpy_wrapper == NULL)
1501
goto cleanup;
1502
1503
wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_dpy_wrapper,
1504
dri2_dpy->wl_queue);
1505
1506
if (dri2_dpy->own_device)
1507
wl_display_dispatch_pending(dri2_dpy->wl_dpy);
1508
1509
dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy_wrapper);
1510
wl_registry_add_listener(dri2_dpy->wl_registry,
1511
&registry_listener_drm, dri2_dpy);
1512
if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_drm == NULL)
1513
goto cleanup;
1514
1515
if (roundtrip(dri2_dpy) < 0 || dri2_dpy->fd == -1)
1516
goto cleanup;
1517
1518
if (!dri2_dpy->authenticated &&
1519
(roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated))
1520
goto cleanup;
1521
1522
dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd,
1523
&dri2_dpy->is_different_gpu);
1524
dev = _eglAddDevice(dri2_dpy->fd, false);
1525
if (!dev) {
1526
_eglError(EGL_NOT_INITIALIZED, "DRI2: failed to find EGLDevice");
1527
goto cleanup;
1528
}
1529
1530
disp->Device = dev;
1531
1532
if (dri2_dpy->is_different_gpu) {
1533
free(dri2_dpy->device_name);
1534
dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd);
1535
if (!dri2_dpy->device_name) {
1536
_eglError(EGL_BAD_ALLOC, "wayland-egl: failed to get device name "
1537
"for requested GPU");
1538
goto cleanup;
1539
}
1540
}
1541
1542
/* we have to do the check now, because loader_get_user_preferred_fd
1543
* will return a render-node when the requested gpu is different
1544
* to the server, but also if the client asks for the same gpu than
1545
* the server by requesting its pci-id */
1546
dri2_dpy->is_render_node = drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER;
1547
1548
dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
1549
if (dri2_dpy->driver_name == NULL) {
1550
_eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name");
1551
goto cleanup;
1552
}
1553
1554
/* render nodes cannot use Gem names, and thus do not support
1555
* the __DRI_DRI2_LOADER extension */
1556
if (!dri2_dpy->is_render_node) {
1557
dri2_dpy->loader_extensions = dri2_loader_extensions;
1558
if (!dri2_load_driver(disp)) {
1559
_eglError(EGL_BAD_ALLOC, "DRI2: failed to load driver");
1560
goto cleanup;
1561
}
1562
} else {
1563
dri2_dpy->loader_extensions = image_loader_extensions;
1564
if (!dri2_load_driver_dri3(disp)) {
1565
_eglError(EGL_BAD_ALLOC, "DRI3: failed to load driver");
1566
goto cleanup;
1567
}
1568
}
1569
1570
if (!dri2_create_screen(disp))
1571
goto cleanup;
1572
1573
if (!dri2_setup_extensions(disp))
1574
goto cleanup;
1575
1576
dri2_setup_screen(disp);
1577
1578
dri2_wl_setup_swap_interval(disp);
1579
1580
/* To use Prime, we must have _DRI_IMAGE v7 at least.
1581
* createImageFromFds support indicates that Prime export/import
1582
* is supported by the driver. Fall back to
1583
* gem names if we don't have Prime support. */
1584
1585
if (dri2_dpy->image->base.version < 7 ||
1586
dri2_dpy->image->createImageFromFds == NULL)
1587
dri2_dpy->capabilities &= ~WL_DRM_CAPABILITY_PRIME;
1588
1589
/* We cannot use Gem names with render-nodes, only prime fds (dma-buf).
1590
* The server needs to accept them */
1591
if (dri2_dpy->is_render_node &&
1592
!(dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME)) {
1593
_eglLog(_EGL_WARNING, "wayland-egl: display is not render-node capable");
1594
goto cleanup;
1595
}
1596
1597
if (dri2_dpy->is_different_gpu &&
1598
(dri2_dpy->image->base.version < 9 ||
1599
dri2_dpy->image->blitImage == NULL)) {
1600
_eglLog(_EGL_WARNING, "wayland-egl: Different GPU selected, but the "
1601
"Image extension in the driver is not "
1602
"compatible. Version 9 or later and blitImage() "
1603
"are required");
1604
goto cleanup;
1605
}
1606
1607
if (!dri2_wl_add_configs_for_visuals(disp)) {
1608
_eglError(EGL_NOT_INITIALIZED, "DRI2: failed to add configs");
1609
goto cleanup;
1610
}
1611
1612
dri2_set_WL_bind_wayland_display(disp);
1613
/* When cannot convert EGLImage to wl_buffer when on a different gpu,
1614
* because the buffer of the EGLImage has likely a tiling mode the server
1615
* gpu won't support. These is no way to check for now. Thus do not support the
1616
* extension */
1617
if (!dri2_dpy->is_different_gpu)
1618
disp->Extensions.WL_create_wayland_buffer_from_image = EGL_TRUE;
1619
1620
disp->Extensions.EXT_buffer_age = EGL_TRUE;
1621
1622
disp->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE;
1623
1624
/* Fill vtbl last to prevent accidentally calling virtual function during
1625
* initialization.
1626
*/
1627
dri2_dpy->vtbl = &dri2_wl_display_vtbl;
1628
1629
return EGL_TRUE;
1630
1631
cleanup:
1632
dri2_display_destroy(disp);
1633
return EGL_FALSE;
1634
}
1635
1636
static int
1637
dri2_wl_swrast_get_stride_for_format(int format, int w)
1638
{
1639
int visual_idx = dri2_wl_visual_idx_from_shm_format(format);
1640
1641
assume(visual_idx != -1);
1642
1643
return w * (dri2_wl_visuals[visual_idx].bpp / 8);
1644
}
1645
1646
static EGLBoolean
1647
dri2_wl_swrast_allocate_buffer(struct dri2_egl_surface *dri2_surf,
1648
int format, int w, int h,
1649
void **data, int *size,
1650
struct wl_buffer **buffer)
1651
{
1652
struct dri2_egl_display *dri2_dpy =
1653
dri2_egl_display(dri2_surf->base.Resource.Display);
1654
struct wl_shm_pool *pool;
1655
int fd, stride, size_map;
1656
void *data_map;
1657
1658
stride = dri2_wl_swrast_get_stride_for_format(format, w);
1659
size_map = h * stride;
1660
1661
/* Create a shareable buffer */
1662
fd = os_create_anonymous_file(size_map, NULL);
1663
if (fd < 0)
1664
return EGL_FALSE;
1665
1666
data_map = mmap(NULL, size_map, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1667
if (data_map == MAP_FAILED) {
1668
close(fd);
1669
return EGL_FALSE;
1670
}
1671
1672
/* Share it in a wl_buffer */
1673
pool = wl_shm_create_pool(dri2_dpy->wl_shm, fd, size_map);
1674
wl_proxy_set_queue((struct wl_proxy *)pool, dri2_surf->wl_queue);
1675
*buffer = wl_shm_pool_create_buffer(pool, 0, w, h, stride, format);
1676
wl_shm_pool_destroy(pool);
1677
close(fd);
1678
1679
*data = data_map;
1680
*size = size_map;
1681
return EGL_TRUE;
1682
}
1683
1684
static int
1685
swrast_update_buffers(struct dri2_egl_surface *dri2_surf)
1686
{
1687
struct dri2_egl_display *dri2_dpy =
1688
dri2_egl_display(dri2_surf->base.Resource.Display);
1689
1690
/* we need to do the following operations only once per frame */
1691
if (dri2_surf->back)
1692
return 0;
1693
1694
if (dri2_surf->wl_win &&
1695
(dri2_surf->base.Width != dri2_surf->wl_win->width ||
1696
dri2_surf->base.Height != dri2_surf->wl_win->height)) {
1697
1698
dri2_wl_release_buffers(dri2_surf);
1699
1700
dri2_surf->base.Width = dri2_surf->wl_win->width;
1701
dri2_surf->base.Height = dri2_surf->wl_win->height;
1702
dri2_surf->dx = dri2_surf->wl_win->dx;
1703
dri2_surf->dy = dri2_surf->wl_win->dy;
1704
dri2_surf->current = NULL;
1705
}
1706
1707
/* find back buffer */
1708
1709
/* There might be a buffer release already queued that wasn't processed */
1710
wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_surf->wl_queue);
1711
1712
/* try get free buffer already created */
1713
for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
1714
if (!dri2_surf->color_buffers[i].locked &&
1715
dri2_surf->color_buffers[i].wl_buffer) {
1716
dri2_surf->back = &dri2_surf->color_buffers[i];
1717
break;
1718
}
1719
}
1720
1721
/* else choose any another free location */
1722
if (!dri2_surf->back) {
1723
for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
1724
if (!dri2_surf->color_buffers[i].locked) {
1725
dri2_surf->back = &dri2_surf->color_buffers[i];
1726
if (!dri2_wl_swrast_allocate_buffer(dri2_surf,
1727
dri2_surf->format,
1728
dri2_surf->base.Width,
1729
dri2_surf->base.Height,
1730
&dri2_surf->back->data,
1731
&dri2_surf->back->data_size,
1732
&dri2_surf->back->wl_buffer)) {
1733
_eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");
1734
return -1;
1735
}
1736
wl_buffer_add_listener(dri2_surf->back->wl_buffer,
1737
&wl_buffer_listener, dri2_surf);
1738
break;
1739
}
1740
}
1741
}
1742
1743
if (!dri2_surf->back) {
1744
_eglError(EGL_BAD_ALLOC, "failed to find free buffer");
1745
return -1;
1746
}
1747
1748
dri2_surf->back->locked = true;
1749
1750
/* If we have an extra unlocked buffer at this point, we had to do triple
1751
* buffering for a while, but now can go back to just double buffering.
1752
* That means we can free any unlocked buffer now. */
1753
for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
1754
if (!dri2_surf->color_buffers[i].locked &&
1755
dri2_surf->color_buffers[i].wl_buffer) {
1756
wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
1757
munmap(dri2_surf->color_buffers[i].data,
1758
dri2_surf->color_buffers[i].data_size);
1759
dri2_surf->color_buffers[i].wl_buffer = NULL;
1760
dri2_surf->color_buffers[i].data = NULL;
1761
}
1762
}
1763
1764
return 0;
1765
}
1766
1767
static void*
1768
dri2_wl_swrast_get_frontbuffer_data(struct dri2_egl_surface *dri2_surf)
1769
{
1770
/* if there has been a resize: */
1771
if (!dri2_surf->current)
1772
return NULL;
1773
1774
return dri2_surf->current->data;
1775
}
1776
1777
static void*
1778
dri2_wl_swrast_get_backbuffer_data(struct dri2_egl_surface *dri2_surf)
1779
{
1780
assert(dri2_surf->back);
1781
return dri2_surf->back->data;
1782
}
1783
1784
static void
1785
dri2_wl_swrast_commit_backbuffer(struct dri2_egl_surface *dri2_surf)
1786
{
1787
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
1788
1789
while (dri2_surf->throttle_callback != NULL)
1790
if (wl_display_dispatch_queue(dri2_dpy->wl_dpy,
1791
dri2_surf->wl_queue) == -1)
1792
return;
1793
1794
if (dri2_surf->base.SwapInterval > 0) {
1795
dri2_surf->throttle_callback =
1796
wl_surface_frame(dri2_surf->wl_surface_wrapper);
1797
wl_callback_add_listener(dri2_surf->throttle_callback,
1798
&throttle_listener, dri2_surf);
1799
}
1800
1801
dri2_surf->current = dri2_surf->back;
1802
dri2_surf->back = NULL;
1803
1804
wl_surface_attach(dri2_surf->wl_surface_wrapper,
1805
dri2_surf->current->wl_buffer,
1806
dri2_surf->dx, dri2_surf->dy);
1807
1808
dri2_surf->wl_win->attached_width = dri2_surf->base.Width;
1809
dri2_surf->wl_win->attached_height = dri2_surf->base.Height;
1810
/* reset resize growing parameters */
1811
dri2_surf->dx = 0;
1812
dri2_surf->dy = 0;
1813
1814
wl_surface_damage(dri2_surf->wl_surface_wrapper,
1815
0, 0, INT32_MAX, INT32_MAX);
1816
wl_surface_commit(dri2_surf->wl_surface_wrapper);
1817
1818
/* If we're not waiting for a frame callback then we'll at least throttle
1819
* to a sync callback so that we always give a chance for the compositor to
1820
* handle the commit and send a release event before checking for a free
1821
* buffer */
1822
if (dri2_surf->throttle_callback == NULL) {
1823
dri2_surf->throttle_callback = wl_display_sync(dri2_surf->wl_dpy_wrapper);
1824
wl_callback_add_listener(dri2_surf->throttle_callback,
1825
&throttle_listener, dri2_surf);
1826
}
1827
1828
wl_display_flush(dri2_dpy->wl_dpy);
1829
}
1830
1831
static void
1832
dri2_wl_swrast_get_drawable_info(__DRIdrawable * draw,
1833
int *x, int *y, int *w, int *h,
1834
void *loaderPrivate)
1835
{
1836
struct dri2_egl_surface *dri2_surf = loaderPrivate;
1837
1838
(void) swrast_update_buffers(dri2_surf);
1839
*x = 0;
1840
*y = 0;
1841
*w = dri2_surf->base.Width;
1842
*h = dri2_surf->base.Height;
1843
}
1844
1845
static void
1846
dri2_wl_swrast_get_image(__DRIdrawable * read,
1847
int x, int y, int w, int h,
1848
char *data, void *loaderPrivate)
1849
{
1850
struct dri2_egl_surface *dri2_surf = loaderPrivate;
1851
int copy_width = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w);
1852
int x_offset = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, x);
1853
int src_stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, dri2_surf->base.Width);
1854
int dst_stride = copy_width;
1855
char *src, *dst;
1856
1857
src = dri2_wl_swrast_get_frontbuffer_data(dri2_surf);
1858
if (!src) {
1859
memset(data, 0, copy_width * h);
1860
return;
1861
}
1862
1863
assert(data != src);
1864
assert(copy_width <= src_stride);
1865
1866
src += x_offset;
1867
src += y * src_stride;
1868
dst = data;
1869
1870
if (copy_width > src_stride-x_offset)
1871
copy_width = src_stride-x_offset;
1872
if (h > dri2_surf->base.Height-y)
1873
h = dri2_surf->base.Height-y;
1874
1875
for (; h>0; h--) {
1876
memcpy(dst, src, copy_width);
1877
src += src_stride;
1878
dst += dst_stride;
1879
}
1880
}
1881
1882
static void
1883
dri2_wl_swrast_put_image2(__DRIdrawable * draw, int op,
1884
int x, int y, int w, int h, int stride,
1885
char *data, void *loaderPrivate)
1886
{
1887
struct dri2_egl_surface *dri2_surf = loaderPrivate;
1888
int copy_width = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w);
1889
int dst_stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, dri2_surf->base.Width);
1890
int x_offset = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, x);
1891
char *src, *dst;
1892
1893
assert(copy_width <= stride);
1894
1895
(void) swrast_update_buffers(dri2_surf);
1896
dst = dri2_wl_swrast_get_backbuffer_data(dri2_surf);
1897
1898
/* partial copy, copy old content */
1899
if (copy_width < dst_stride)
1900
dri2_wl_swrast_get_image(draw, 0, 0,
1901
dri2_surf->base.Width, dri2_surf->base.Height,
1902
dst, loaderPrivate);
1903
1904
dst += x_offset;
1905
dst += y * dst_stride;
1906
1907
src = data;
1908
1909
/* drivers expect we do these checks (and some rely on it) */
1910
if (copy_width > dst_stride-x_offset)
1911
copy_width = dst_stride-x_offset;
1912
if (h > dri2_surf->base.Height-y)
1913
h = dri2_surf->base.Height-y;
1914
1915
for (; h>0; h--) {
1916
memcpy(dst, src, copy_width);
1917
src += stride;
1918
dst += dst_stride;
1919
}
1920
dri2_wl_swrast_commit_backbuffer(dri2_surf);
1921
}
1922
1923
static void
1924
dri2_wl_swrast_put_image(__DRIdrawable * draw, int op,
1925
int x, int y, int w, int h,
1926
char *data, void *loaderPrivate)
1927
{
1928
struct dri2_egl_surface *dri2_surf = loaderPrivate;
1929
int stride;
1930
1931
stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w);
1932
dri2_wl_swrast_put_image2(draw, op, x, y, w, h,
1933
stride, data, loaderPrivate);
1934
}
1935
1936
static EGLBoolean
1937
dri2_wl_swrast_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
1938
{
1939
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1940
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
1941
1942
if (!dri2_surf->wl_win)
1943
return _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_swap_buffers");
1944
1945
dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);
1946
return EGL_TRUE;
1947
}
1948
1949
static void
1950
shm_handle_format(void *data, struct wl_shm *shm, uint32_t format)
1951
{
1952
struct dri2_egl_display *dri2_dpy = data;
1953
int visual_idx = dri2_wl_visual_idx_from_shm_format(format);
1954
1955
if (visual_idx == -1)
1956
return;
1957
1958
BITSET_SET(dri2_dpy->formats, visual_idx);
1959
}
1960
1961
static const struct wl_shm_listener shm_listener = {
1962
.format = shm_handle_format
1963
};
1964
1965
static void
1966
registry_handle_global_swrast(void *data, struct wl_registry *registry,
1967
uint32_t name, const char *interface,
1968
uint32_t version)
1969
{
1970
struct dri2_egl_display *dri2_dpy = data;
1971
1972
if (strcmp(interface, "wl_shm") == 0) {
1973
dri2_dpy->wl_shm =
1974
wl_registry_bind(registry, name, &wl_shm_interface, 1);
1975
wl_shm_add_listener(dri2_dpy->wl_shm, &shm_listener, dri2_dpy);
1976
}
1977
}
1978
1979
static const struct wl_registry_listener registry_listener_swrast = {
1980
.global = registry_handle_global_swrast,
1981
.global_remove = registry_handle_global_remove
1982
};
1983
1984
static const struct dri2_egl_display_vtbl dri2_wl_swrast_display_vtbl = {
1985
.authenticate = NULL,
1986
.create_window_surface = dri2_wl_create_window_surface,
1987
.create_pixmap_surface = dri2_wl_create_pixmap_surface,
1988
.destroy_surface = dri2_wl_destroy_surface,
1989
.create_image = dri2_create_image_khr,
1990
.swap_buffers = dri2_wl_swrast_swap_buffers,
1991
.get_dri_drawable = dri2_surface_get_dri_drawable,
1992
};
1993
1994
static const __DRIswrastLoaderExtension swrast_loader_extension = {
1995
.base = { __DRI_SWRAST_LOADER, 2 },
1996
1997
.getDrawableInfo = dri2_wl_swrast_get_drawable_info,
1998
.putImage = dri2_wl_swrast_put_image,
1999
.getImage = dri2_wl_swrast_get_image,
2000
.putImage2 = dri2_wl_swrast_put_image2,
2001
};
2002
2003
static const __DRIextension *swrast_loader_extensions[] = {
2004
&swrast_loader_extension.base,
2005
&image_lookup_extension.base,
2006
NULL,
2007
};
2008
2009
static EGLBoolean
2010
dri2_initialize_wayland_swrast(_EGLDisplay *disp)
2011
{
2012
_EGLDevice *dev;
2013
struct dri2_egl_display *dri2_dpy;
2014
2015
dri2_dpy = calloc(1, sizeof *dri2_dpy);
2016
if (!dri2_dpy)
2017
return _eglError(EGL_BAD_ALLOC, "eglInitialize");
2018
2019
dri2_dpy->fd = -1;
2020
disp->DriverData = (void *) dri2_dpy;
2021
if (disp->PlatformDisplay == NULL) {
2022
dri2_dpy->wl_dpy = wl_display_connect(NULL);
2023
if (dri2_dpy->wl_dpy == NULL)
2024
goto cleanup;
2025
dri2_dpy->own_device = true;
2026
} else {
2027
dri2_dpy->wl_dpy = disp->PlatformDisplay;
2028
}
2029
2030
dev = _eglAddDevice(dri2_dpy->fd, true);
2031
if (!dev) {
2032
_eglError(EGL_NOT_INITIALIZED, "DRI2: failed to find EGLDevice");
2033
goto cleanup;
2034
}
2035
2036
disp->Device = dev;
2037
2038
dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
2039
2040
dri2_dpy->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy);
2041
if (dri2_dpy->wl_dpy_wrapper == NULL)
2042
goto cleanup;
2043
2044
wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_dpy_wrapper,
2045
dri2_dpy->wl_queue);
2046
2047
if (dri2_dpy->own_device)
2048
wl_display_dispatch_pending(dri2_dpy->wl_dpy);
2049
2050
dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy_wrapper);
2051
wl_registry_add_listener(dri2_dpy->wl_registry,
2052
&registry_listener_swrast, dri2_dpy);
2053
2054
if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_shm == NULL)
2055
goto cleanup;
2056
2057
if (roundtrip(dri2_dpy) < 0 || !BITSET_TEST_RANGE(dri2_dpy->formats,
2058
0, EGL_DRI2_MAX_FORMATS))
2059
goto cleanup;
2060
2061
dri2_dpy->driver_name = strdup("swrast");
2062
if (!dri2_load_driver_swrast(disp))
2063
goto cleanup;
2064
2065
dri2_dpy->loader_extensions = swrast_loader_extensions;
2066
2067
if (!dri2_create_screen(disp))
2068
goto cleanup;
2069
2070
if (!dri2_setup_extensions(disp))
2071
goto cleanup;
2072
2073
dri2_setup_screen(disp);
2074
2075
dri2_wl_setup_swap_interval(disp);
2076
2077
if (!dri2_wl_add_configs_for_visuals(disp)) {
2078
_eglError(EGL_NOT_INITIALIZED, "DRI2: failed to add configs");
2079
goto cleanup;
2080
}
2081
2082
/* Fill vtbl last to prevent accidentally calling virtual function during
2083
* initialization.
2084
*/
2085
dri2_dpy->vtbl = &dri2_wl_swrast_display_vtbl;
2086
2087
return EGL_TRUE;
2088
2089
cleanup:
2090
dri2_display_destroy(disp);
2091
return EGL_FALSE;
2092
}
2093
2094
EGLBoolean
2095
dri2_initialize_wayland(_EGLDisplay *disp)
2096
{
2097
if (disp->Options.ForceSoftware)
2098
return dri2_initialize_wayland_swrast(disp);
2099
else
2100
return dri2_initialize_wayland_drm(disp);
2101
}
2102
2103
void
2104
dri2_teardown_wayland(struct dri2_egl_display *dri2_dpy)
2105
{
2106
if (dri2_dpy->wl_drm)
2107
wl_drm_destroy(dri2_dpy->wl_drm);
2108
if (dri2_dpy->wl_dmabuf)
2109
zwp_linux_dmabuf_v1_destroy(dri2_dpy->wl_dmabuf);
2110
if (dri2_dpy->wl_shm)
2111
wl_shm_destroy(dri2_dpy->wl_shm);
2112
if (dri2_dpy->wl_registry)
2113
wl_registry_destroy(dri2_dpy->wl_registry);
2114
if (dri2_dpy->wl_queue)
2115
wl_event_queue_destroy(dri2_dpy->wl_queue);
2116
if (dri2_dpy->wl_dpy_wrapper)
2117
wl_proxy_wrapper_destroy(dri2_dpy->wl_dpy_wrapper);
2118
2119
for (int i = 0; dri2_dpy->wl_modifiers && i < ARRAY_SIZE(dri2_wl_visuals); i++)
2120
u_vector_finish(&dri2_dpy->wl_modifiers[i]);
2121
free(dri2_dpy->wl_modifiers);
2122
2123
if (dri2_dpy->own_device)
2124
wl_display_disconnect(dri2_dpy->wl_dpy);
2125
}
2126
2127