Skip to content

Commit a537e38

Browse files
committed
wayland: Add API to acquire a CoglScanout from a surface
This will check whether the current backing buffer is compatible with the primary plane of the passed CoglOnscreen. Since this will extend the time before a buffer is released, the MetaWaylandBufferRef is swapped and orphaned if a new buffer is committed before the previous one was released. It'll eventually be released, usually by the next page flip callback. Currently implemented for EGLImage and DMA-BUF buffer types. Original Mutter commit: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/798/diffs?commit_id=ff7a42b8bc25c24d3e0fc0a277b1d628f5ea599a
1 parent fed926d commit a537e38

File tree

6 files changed

+266
-0
lines changed

6 files changed

+266
-0
lines changed

src/wayland/meta-wayland-buffer.c

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@
5858
#include "meta/util.h"
5959
#include "wayland/meta-wayland-dma-buf.h"
6060

61+
#ifdef HAVE_NATIVE_BACKEND
62+
#include "backends/native/meta-drm-buffer-gbm.h"
63+
#include "backends/native/meta-renderer-native.h"
64+
#endif
65+
6166
#ifndef DRM_FORMAT_MOD_INVALID
6267
#define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
6368
#endif
@@ -577,6 +582,93 @@ meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
577582
}
578583
}
579584

585+
static CoglScanout *
586+
try_acquire_egl_image_scanout (MetaWaylandBuffer *buffer,
587+
CoglOnscreen *onscreen)
588+
{
589+
#ifdef HAVE_NATIVE_BACKEND
590+
MetaBackend *backend = meta_get_backend ();
591+
MetaRenderer *renderer = meta_backend_get_renderer (backend);
592+
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
593+
MetaGpuKms *gpu_kms;
594+
struct gbm_device *gbm_device;
595+
struct gbm_bo *gbm_bo;
596+
uint32_t drm_format;
597+
uint64_t drm_modifier;
598+
uint32_t stride;
599+
MetaDrmBufferGbm *fb;
600+
g_autoptr (GError) error = NULL;
601+
602+
gpu_kms = meta_renderer_native_get_primary_gpu (renderer_native);
603+
gbm_device = meta_gbm_device_from_gpu (gpu_kms);
604+
605+
gbm_bo = gbm_bo_import (gbm_device,
606+
GBM_BO_IMPORT_WL_BUFFER, buffer->resource,
607+
GBM_BO_USE_SCANOUT);
608+
if (!gbm_bo)
609+
return NULL;
610+
611+
drm_format = gbm_bo_get_format (gbm_bo);
612+
drm_modifier = gbm_bo_get_modifier (gbm_bo);
613+
stride = gbm_bo_get_stride (gbm_bo);
614+
if (!meta_onscreen_native_is_buffer_scanout_compatible (onscreen,
615+
drm_format,
616+
drm_modifier,
617+
stride))
618+
{
619+
gbm_bo_destroy (gbm_bo);
620+
return NULL;
621+
}
622+
623+
fb = meta_drm_buffer_gbm_new_take (gpu_kms, gbm_bo,
624+
drm_modifier != DRM_FORMAT_MOD_INVALID,
625+
&error);
626+
if (!fb)
627+
{
628+
g_debug ("Failed to create scanout buffer: %s", error->message);
629+
gbm_bo_destroy (gbm_bo);
630+
return NULL;
631+
}
632+
633+
return COGL_SCANOUT (fb);
634+
#else
635+
return NULL;
636+
#endif
637+
}
638+
639+
CoglScanout *
640+
meta_wayland_buffer_try_acquire_scanout (MetaWaylandBuffer *buffer,
641+
CoglOnscreen *onscreen)
642+
{
643+
switch (buffer->type)
644+
{
645+
case META_WAYLAND_BUFFER_TYPE_SHM:
646+
return NULL;
647+
case META_WAYLAND_BUFFER_TYPE_EGL_IMAGE:
648+
return try_acquire_egl_image_scanout (buffer, onscreen);
649+
#ifdef HAVE_WAYLAND_EGLSTREAM
650+
case META_WAYLAND_BUFFER_TYPE_EGL_STREAM:
651+
return NULL;
652+
#endif
653+
case META_WAYLAND_BUFFER_TYPE_DMA_BUF:
654+
{
655+
MetaWaylandDmaBufBuffer *dma_buf;
656+
657+
dma_buf = meta_wayland_dma_buf_from_buffer (buffer);
658+
if (!dma_buf)
659+
return NULL;
660+
661+
return meta_wayland_dma_buf_try_acquire_scanout (dma_buf, onscreen);
662+
}
663+
case META_WAYLAND_BUFFER_TYPE_UNKNOWN:
664+
g_warn_if_reached ();
665+
return NULL;
666+
}
667+
668+
g_assert_not_reached ();
669+
return NULL;
670+
}
671+
580672
static void
581673
meta_wayland_buffer_finalize (GObject *object)
582674
{

src/wayland/meta-wayland-buffer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,7 @@ void meta_wayland_buffer_process_damage (MetaWaylandBuff
8989
CoglTexture *texture,
9090
cairo_region_t *region);
9191

92+
CoglScanout * meta_wayland_buffer_try_acquire_scanout (MetaWaylandBuffer *buffer,
93+
CoglOnscreen *onscreen);
94+
9295
#endif /* META_WAYLAND_BUFFER_H */

src/wayland/meta-wayland-dma-buf.c

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@
5151
#include "wayland/meta-wayland-private.h"
5252
#include "wayland/meta-wayland-versions.h"
5353

54+
#ifdef HAVE_NATIVE_BACKEND
55+
#include "backends/native/meta-drm-buffer-gbm.h"
56+
#include "backends/native/meta-renderer-native.h"
57+
#endif
58+
5459
#include "linux-dmabuf-unstable-v1-server-protocol.h"
5560

5661
#ifndef DRM_FORMAT_MOD_INVALID
@@ -184,6 +189,117 @@ meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer,
184189
return TRUE;
185190
}
186191

192+
#ifdef HAVE_NATIVE_BACKEND
193+
static struct gbm_bo *
194+
create_gbm_bo (MetaWaylandDmaBufBuffer *dma_buf,
195+
MetaGpuKms *gpu_kms,
196+
int n_planes,
197+
gboolean *use_modifier)
198+
{
199+
struct gbm_device *gbm_device;
200+
201+
gbm_device = meta_gbm_device_from_gpu (gpu_kms);
202+
203+
if (dma_buf->drm_modifier != DRM_FORMAT_MOD_INVALID ||
204+
n_planes > 1 ||
205+
dma_buf->offsets[0] > 0)
206+
{
207+
struct gbm_import_fd_modifier_data import_with_modifier;
208+
209+
import_with_modifier = (struct gbm_import_fd_modifier_data) {
210+
.width = dma_buf->width,
211+
.height = dma_buf->height,
212+
.format = dma_buf->drm_format,
213+
.num_fds = n_planes,
214+
.modifier = dma_buf->drm_modifier,
215+
};
216+
memcpy (import_with_modifier.fds,
217+
dma_buf->fds,
218+
sizeof (dma_buf->fds));
219+
memcpy (import_with_modifier.strides,
220+
dma_buf->strides,
221+
sizeof (import_with_modifier.strides));
222+
memcpy (import_with_modifier.offsets,
223+
dma_buf->offsets,
224+
sizeof (import_with_modifier.offsets));
225+
226+
*use_modifier = TRUE;
227+
return gbm_bo_import (gbm_device, GBM_BO_IMPORT_FD_MODIFIER,
228+
&import_with_modifier,
229+
GBM_BO_USE_SCANOUT);
230+
}
231+
else
232+
{
233+
struct gbm_import_fd_data import_legacy;
234+
235+
import_legacy = (struct gbm_import_fd_data) {
236+
.width = dma_buf->width,
237+
.height = dma_buf->height,
238+
.format = dma_buf->drm_format,
239+
.stride = dma_buf->strides[0],
240+
.fd = dma_buf->fds[0],
241+
};
242+
243+
*use_modifier = FALSE;
244+
return gbm_bo_import (gbm_device, GBM_BO_IMPORT_FD,
245+
&import_legacy,
246+
GBM_BO_USE_SCANOUT);
247+
}
248+
}
249+
#endif
250+
251+
CoglScanout *
252+
meta_wayland_dma_buf_try_acquire_scanout (MetaWaylandDmaBufBuffer *dma_buf,
253+
CoglOnscreen *onscreen)
254+
{
255+
#ifdef HAVE_NATIVE_BACKEND
256+
MetaBackend *backend = meta_get_backend ();
257+
MetaRenderer *renderer = meta_backend_get_renderer (backend);
258+
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer);
259+
MetaGpuKms *gpu_kms;
260+
int n_planes;
261+
uint32_t drm_format;
262+
uint64_t drm_modifier;
263+
uint32_t stride;
264+
struct gbm_bo *gbm_bo;
265+
gboolean use_modifier;
266+
g_autoptr (GError) error = NULL;
267+
MetaDrmBufferGbm *fb;
268+
269+
for (n_planes = 0; n_planes < META_WAYLAND_DMA_BUF_MAX_FDS; n_planes++)
270+
{
271+
if (dma_buf->fds[n_planes] < 0)
272+
break;
273+
}
274+
275+
drm_format = dma_buf->drm_format;
276+
drm_modifier = dma_buf->drm_modifier;
277+
stride = dma_buf->strides[0];
278+
if (!meta_onscreen_native_is_buffer_scanout_compatible (onscreen,
279+
drm_format,
280+
drm_modifier,
281+
stride))
282+
return NULL;
283+
284+
gpu_kms = meta_renderer_native_get_primary_gpu (renderer_native);
285+
gbm_bo = create_gbm_bo (dma_buf, gpu_kms, n_planes, &use_modifier);
286+
287+
fb = meta_drm_buffer_gbm_new_take (gpu_kms, gbm_bo,
288+
use_modifier,
289+
&error);
290+
if (!fb)
291+
{
292+
g_debug ("Failed to create scanout buffer: %s", error->message);
293+
gbm_bo_destroy (gbm_bo);
294+
return NULL;
295+
}
296+
297+
return COGL_SCANOUT (fb);
298+
#else
299+
return NULL;
300+
#endif
301+
}
302+
187303
static void
188304
buffer_params_add (struct wl_client *client,
189305
struct wl_resource *resource,

src/wayland/meta-wayland-dma-buf.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,8 @@ meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer,
4949
MetaWaylandDmaBufBuffer *
5050
meta_wayland_dma_buf_from_buffer (MetaWaylandBuffer *buffer);
5151

52+
CoglScanout *
53+
meta_wayland_dma_buf_try_acquire_scanout (MetaWaylandDmaBufBuffer *dma_buf,
54+
CoglOnscreen *onscreen);
55+
5256
#endif /* META_WAYLAND_DMA_BUF_H */

src/wayland/meta-wayland-surface.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,13 @@ meta_wayland_buffer_ref_new (void)
133133
return buffer_ref;
134134
}
135135

136+
static MetaWaylandBufferRef *
137+
meta_wayland_buffer_ref_ref (MetaWaylandBufferRef *buffer_ref)
138+
{
139+
g_ref_count_inc (&buffer_ref->ref_count);
140+
return buffer_ref;
141+
}
142+
136143
static void
137144
meta_wayland_buffer_ref_unref (MetaWaylandBufferRef *buffer_ref)
138145
{
@@ -677,6 +684,12 @@ meta_wayland_surface_apply_state (MetaWaylandSurface *surface,
677684
if (surface->buffer_held)
678685
meta_wayland_surface_unref_buffer_use_count (surface);
679686

687+
if (surface->buffer_ref->use_count > 0)
688+
{
689+
meta_wayland_buffer_ref_unref (surface->buffer_ref);
690+
surface->buffer_ref = meta_wayland_buffer_ref_new ();
691+
}
692+
680693
g_set_object (&surface->buffer_ref->buffer, state->buffer);
681694

682695
if (state->buffer)
@@ -2042,3 +2055,38 @@ meta_wayland_surface_get_height (MetaWaylandSurface *surface)
20422055
return height / surface->scale;
20432056
}
20442057
}
2058+
2059+
static void
2060+
scanout_destroyed (gpointer data,
2061+
GObject *where_the_object_was)
2062+
{
2063+
MetaWaylandBufferRef *buffer_ref = data;
2064+
2065+
meta_wayland_buffer_ref_dec_use_count (buffer_ref);
2066+
meta_wayland_buffer_ref_unref (buffer_ref);
2067+
}
2068+
2069+
CoglScanout *
2070+
meta_wayland_surface_try_acquire_scanout (MetaWaylandSurface *surface,
2071+
CoglOnscreen *onscreen)
2072+
{
2073+
CoglScanout *scanout;
2074+
MetaWaylandBufferRef *buffer_ref;
2075+
2076+
if (!surface->buffer_ref->buffer)
2077+
return NULL;
2078+
2079+
if (surface->buffer_ref->use_count == 0)
2080+
return NULL;
2081+
2082+
scanout = meta_wayland_buffer_try_acquire_scanout (surface->buffer_ref->buffer,
2083+
onscreen);
2084+
if (!scanout)
2085+
return NULL;
2086+
2087+
buffer_ref = meta_wayland_buffer_ref_ref (surface->buffer_ref);
2088+
meta_wayland_buffer_ref_inc_use_count (buffer_ref);
2089+
g_object_weak_ref (G_OBJECT (scanout), scanout_destroyed, buffer_ref);
2090+
2091+
return scanout;
2092+
}

src/wayland/meta-wayland-surface.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,9 @@ void meta_wayland_surface_update_outputs_recursively (MetaWayland
341341
int meta_wayland_surface_get_width (MetaWaylandSurface *surface);
342342
int meta_wayland_surface_get_height (MetaWaylandSurface *surface);
343343

344+
CoglScanout * meta_wayland_surface_try_acquire_scanout (MetaWaylandSurface *surface,
345+
CoglOnscreen *onscreen);
346+
344347
static inline GNode *
345348
meta_get_next_subsurface_sibling (GNode *n)
346349
{

0 commit comments

Comments
 (0)