dmabuf: Add gdk_dmabuf_sanitize()

Tries to sanitize the dmabuf to conform to the values expected
by Vulkan/EGL which should also be the values expected by
Wayland compositors

We put these sanitized values into the GdkDmabufTexture, by
sanitizing the input from GdkDmabufTextureBuilder, which are
controlled by the callers.

Things we do here:

1. Disallow any dmabuf format that we do not know.

1. Treat the INVALID modifier the same as LINEAR.

2. Ignore all other modifiers.

3. Try and fix various inconsistencies between V4L and Mesa,
   like NV12.

*** WARNING ***

This function is not absolutely perfect, you do not have a
perfect dmabuf afterwards.

In particular, it doesn't check sizes.
This commit is contained in:
Benjamin Otte 2023-10-20 12:08:18 +02:00
parent f4a67ebcbb
commit dd8c6e9f51
3 changed files with 95 additions and 6 deletions

View File

@ -206,4 +206,77 @@ gdk_dmabuf_get_direct_downloader (void)
return &downloader; return &downloader;
} }
/*
* Tries to sanitize the dmabuf to conform to the values expected
* by Vulkan/EGL which should also be the values expected by
* Wayland compositors
*
* We put these sanitized values into the GdkDmabufTexture, by
* sanitizing the input from GdkDmabufTextureBuilder, which are
* controlled by the callers.
*
* Things we do here:
*
* 1. Disallow any dmabuf format that we do not know.
*
* 1. Treat the INVALID modifier the same as LINEAR.
*
* 2. Ignore all other modifiers.
*
* 3. Try and fix various inconsistencies between V4L and Mesa,
* like NV12.
*
* *** WARNING ***
*
* This function is not absolutely perfect, you do not have a
* perfect dmabuf afterwards.
*
* In particular, it doesn't check sizes.
*
* *** WARNING ***
*/
gboolean
gdk_dmabuf_sanitize (GdkDmabuf *dest,
gsize width,
gsize height,
const GdkDmabuf *src,
GError **error)
{
const GdkDrmFormatInfo *info;
info = get_drm_format_info (src->fourcc);
if (info == NULL)
{
g_set_error (error,
GDK_DMABUF_ERROR, GDK_DMABUF_ERROR_UNSUPPORTED_FORMAT,
"Unsupported dmabuf format %.4s",
(char *) &src->fourcc);
return FALSE;
}
*dest = *src;
if (src->modifier && src->modifier != DRM_FORMAT_MOD_INVALID)
return TRUE;
switch (dest->fourcc)
{
case DRM_FORMAT_NV12:
if (dest->n_planes == 1)
{
dest->n_planes = 2;
dest->planes[1].fd = dest->planes[0].fd;
dest->planes[1].stride = dest->planes[0].stride;
dest->planes[1].offset = dest->planes[0].offset + dest->planes[0].stride * height;
}
break;
default:
break;
}
return TRUE;
}
#endif /* HAVE_LINUX_DMA_BUF_H */ #endif /* HAVE_LINUX_DMA_BUF_H */

View File

@ -41,4 +41,10 @@ struct _GdkDmabufDownloader
#ifdef HAVE_LINUX_DMA_BUF_H #ifdef HAVE_LINUX_DMA_BUF_H
const GdkDmabufDownloader * const GdkDmabufDownloader *
gdk_dmabuf_get_direct_downloader (void) G_GNUC_CONST; gdk_dmabuf_get_direct_downloader (void) G_GNUC_CONST;
gboolean gdk_dmabuf_sanitize (GdkDmabuf *dest,
gsize width,
gsize height,
const GdkDmabuf *src,
GError **error);
#endif #endif

View File

@ -22,6 +22,7 @@
#include "gdkdisplayprivate.h" #include "gdkdisplayprivate.h"
#include "gdkdmabufformatsbuilderprivate.h" #include "gdkdmabufformatsbuilderprivate.h"
#include "gdkdmabufprivate.h"
#include "gdktextureprivate.h" #include "gdktextureprivate.h"
#include <gdk/gdkglcontext.h> #include <gdk/gdkglcontext.h>
#include <gdk/gdkgltexturebuilder.h> #include <gdk/gdkgltexturebuilder.h>
@ -132,13 +133,22 @@ gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
GdkDmabufTexture *self; GdkDmabufTexture *self;
GdkTexture *update_texture; GdkTexture *update_texture;
GdkDisplay *display; GdkDisplay *display;
const GdkDmabuf *dmabuf; GdkDmabuf dmabuf;
GdkMemoryFormat format; GdkMemoryFormat format;
GError *local_error = NULL; GError *local_error = NULL;
int width, height;
gsize i; gsize i;
display = gdk_dmabuf_texture_builder_get_display (builder); display = gdk_dmabuf_texture_builder_get_display (builder);
dmabuf = gdk_dmabuf_texture_builder_get_dmabuf (builder); width = gdk_dmabuf_texture_builder_get_width (builder);
height = gdk_dmabuf_texture_builder_get_height (builder);
if (!gdk_dmabuf_sanitize (&dmabuf,
width,
height,
gdk_dmabuf_texture_builder_get_dmabuf (builder),
error))
return NULL;
gdk_display_init_dmabuf (display); gdk_display_init_dmabuf (display);
@ -149,7 +159,7 @@ gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
if (display->dmabuf_downloaders[i]->supports (display->dmabuf_downloaders[i], if (display->dmabuf_downloaders[i]->supports (display->dmabuf_downloaders[i],
display, display,
dmabuf, &dmabuf,
gdk_dmabuf_texture_builder_get_premultiplied (builder), gdk_dmabuf_texture_builder_get_premultiplied (builder),
&format, &format,
local_error ? NULL : &local_error)) local_error ? NULL : &local_error))
@ -163,14 +173,14 @@ gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
} }
self = g_object_new (GDK_TYPE_DMABUF_TEXTURE, self = g_object_new (GDK_TYPE_DMABUF_TEXTURE,
"width", gdk_dmabuf_texture_builder_get_width (builder), "width", width,
"height", gdk_dmabuf_texture_builder_get_height (builder), "height", height,
NULL); NULL);
GDK_TEXTURE (self)->format = format; GDK_TEXTURE (self)->format = format;
g_set_object (&self->display, display); g_set_object (&self->display, display);
self->downloader = display->dmabuf_downloaders[i]; self->downloader = display->dmabuf_downloaders[i];
self->dmabuf = *dmabuf; self->dmabuf = dmabuf;
self->destroy = destroy; self->destroy = destroy;
self->data = data; self->data = data;