Compare commits
8 Commits
wip/matthi
...
dmabuf-tex
Author | SHA1 | Date | |
---|---|---|---|
|
451f7ba2e4 | ||
|
636202aac0 | ||
|
66551f3032 | ||
|
b9a4d8b54d | ||
|
e58570a4ee | ||
|
431597bc7a | ||
|
7a11bc9442 | ||
|
0d27813b42 |
@@ -42,6 +42,8 @@
|
||||
#include <gdk/gdkdevicetool.h>
|
||||
#include <gdk/gdkdisplay.h>
|
||||
#include <gdk/gdkdisplaymanager.h>
|
||||
#include <gdk/gdkdmabuftexture.h>
|
||||
#include <gdk/gdkdmabuftexturebuilder.h>
|
||||
#include <gdk/gdkdrag.h>
|
||||
#include <gdk/gdkdragsurface.h>
|
||||
#include <gdk/gdkdragsurfacesize.h>
|
||||
|
@@ -404,6 +404,8 @@ gdk_display_finalize (GObject *object)
|
||||
|
||||
g_list_free_full (display->seats, g_object_unref);
|
||||
|
||||
g_free (display->egl_dmabuf_formats);
|
||||
|
||||
G_OBJECT_CLASS (gdk_display_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@@ -1259,6 +1261,61 @@ gdk_display_create_vulkan_context (GdkDisplay *self,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
init_dmabuf_formats (GdkDisplay *self)
|
||||
{
|
||||
GdkDisplayPrivate *priv = gdk_display_get_instance_private (self);
|
||||
|
||||
if (priv->egl_display != EGL_NO_DISPLAY)
|
||||
{
|
||||
int num_formats;
|
||||
int *formats;
|
||||
GArray *array;
|
||||
|
||||
eglQueryDmaBufFormatsEXT (priv->egl_display, 0, NULL, &num_formats);
|
||||
formats = g_new (int, num_formats);
|
||||
eglQueryDmaBufFormatsEXT (priv->egl_display, num_formats, formats, &num_formats);
|
||||
|
||||
array = g_array_new (FALSE, FALSE, sizeof (GdkDmabufFormat));
|
||||
|
||||
for (int i = 0; i < num_formats; i++)
|
||||
{
|
||||
int num_modifiers;
|
||||
uint64_t *modifiers;
|
||||
unsigned int *external_only;
|
||||
|
||||
eglQueryDmaBufModifiersEXT (priv->egl_display, formats[i], 0, NULL, NULL, &num_modifiers);
|
||||
modifiers = g_new (uint64_t, num_modifiers);
|
||||
external_only = g_new (unsigned int, num_modifiers);
|
||||
eglQueryDmaBufModifiersEXT (priv->egl_display, formats[i], num_modifiers, modifiers, external_only, &num_modifiers);
|
||||
|
||||
if (num_modifiers == 0)
|
||||
g_array_append_val (array, ((GdkDmabufFormat){ formats[i], 0 }));
|
||||
else
|
||||
{
|
||||
for (int j = 0; j < num_modifiers; j++)
|
||||
g_array_append_val (array, ((GdkDmabufFormat){ formats[i], modifiers[j] }));
|
||||
}
|
||||
|
||||
g_free (modifiers);
|
||||
}
|
||||
|
||||
g_free (formats);
|
||||
|
||||
self->egl_dmabuf_n_formats = array->len;
|
||||
self->egl_dmabuf_formats = (GdkDmabufFormat *) g_array_free (array, FALSE);
|
||||
}
|
||||
|
||||
GDK_DEBUG (MISC, "EGL dmabuf formats: (%lu)", self->egl_dmabuf_n_formats);
|
||||
for (gsize i = 0; i < self->egl_dmabuf_n_formats; i++)
|
||||
{
|
||||
uint32_t f = self->egl_dmabuf_formats[i].fourcc;
|
||||
uint64_t m = self->egl_dmabuf_formats[i].modifier;
|
||||
|
||||
GDK_DEBUG (MISC, " %c%c%c%c:%#lx", f & 0xff, (f >> 8) & 0xff, (f >> 16) & 0xff, (f >> 24) & 0xff, m);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_display_init_gl (GdkDisplay *self)
|
||||
{
|
||||
@@ -1300,6 +1357,10 @@ gdk_display_init_gl (GdkDisplay *self)
|
||||
gdk_gl_backend_use (GDK_GL_CONTEXT_GET_CLASS (context)->backend_type);
|
||||
|
||||
gdk_profiler_end_mark (before, "initialize OpenGL", NULL);
|
||||
|
||||
gdk_gl_context_make_current (context);
|
||||
|
||||
init_dmabuf_formats (self);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1824,6 +1885,40 @@ gdk_display_get_egl_display (GdkDisplay *self)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* GdkDmabufFormat:
|
||||
* @fourcc: the format code
|
||||
* @modifiers: the format modifier
|
||||
*
|
||||
* The `GdkDmabufFormat` struct represents a dma-buf format
|
||||
* as defined in the `drm_fourcc.h` header.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
|
||||
/**
|
||||
* gdk_display_get_dmabuf_formats:
|
||||
* @display: a `GdkDisplay`
|
||||
* @n_formats: return location for the number of formats
|
||||
*
|
||||
* Returns the dma-buf formats that are supported for
|
||||
* this display.
|
||||
*
|
||||
* Returns: (transfer none): an array of `GdkDmabufFormat` structs.
|
||||
* The length of the array is returned in @n_formats
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
const GdkDmabufFormat *
|
||||
gdk_display_get_dmabuf_formats (GdkDisplay *display,
|
||||
gsize *n_formats)
|
||||
{
|
||||
gdk_display_prepare_gl (display, NULL);
|
||||
|
||||
*n_formats = display->egl_dmabuf_n_formats;
|
||||
return display->egl_dmabuf_formats;
|
||||
}
|
||||
|
||||
GdkDebugFlags
|
||||
gdk_display_get_debug_flags (GdkDisplay *display)
|
||||
{
|
||||
|
@@ -134,6 +134,17 @@ gboolean gdk_display_get_setting (GdkDisplay *display,
|
||||
const char *name,
|
||||
GValue *value);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t fourcc;
|
||||
uint64_t modifier;
|
||||
} GdkDmabufFormat;
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
const GdkDmabufFormat *
|
||||
gdk_display_get_dmabuf_formats (GdkDisplay *display,
|
||||
gsize *n_formats);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkDisplay, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
@@ -113,6 +113,9 @@ struct _GdkDisplay
|
||||
guint have_egl_buffer_age : 1;
|
||||
guint have_egl_no_config_context : 1;
|
||||
guint have_egl_pixel_format_float : 1;
|
||||
|
||||
GdkDmabufFormat *egl_dmabuf_formats;
|
||||
gsize egl_dmabuf_n_formats;
|
||||
};
|
||||
|
||||
struct _GdkDisplayClass
|
||||
|
451
gdk/gdkdmabuftexture.c
Normal file
451
gdk/gdkdmabuftexture.c
Normal file
@@ -0,0 +1,451 @@
|
||||
/* gdkdmabuftexture.c
|
||||
*
|
||||
* Copyright 2023 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gdkdmabuftextureprivate.h"
|
||||
|
||||
#ifndef __linux__
|
||||
|
||||
GType
|
||||
gdk_dmabuf_texture_get_type (void)
|
||||
{
|
||||
return G_TYPE_INVALID;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include "gdkdisplayprivate.h"
|
||||
#include "gdkmemoryformatprivate.h"
|
||||
#include "gdkmemorytextureprivate.h"
|
||||
#include <gdk/gdkglcontext.h>
|
||||
#include <gdk/gdkgltexturebuilder.h>
|
||||
#include <gdk/gdktexturedownloader.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <epoxy/egl.h>
|
||||
|
||||
/**
|
||||
* GdkDmabufTexture:
|
||||
*
|
||||
* A `GdkTexture` representing a dma-buf object.
|
||||
*
|
||||
* To create a `GdkDmabufTexture`, use the auxiliary
|
||||
* [class@Gdk.DmabufTextureBuilder] object.
|
||||
*
|
||||
* Dma-buf textures can only be created on Linux.
|
||||
*/
|
||||
|
||||
struct _GdkDmabufTexture
|
||||
{
|
||||
GdkTexture parent_instance;
|
||||
|
||||
GdkDisplay *display;
|
||||
|
||||
unsigned int fourcc;
|
||||
guint64 modifier;
|
||||
|
||||
/* Per-plane properties */
|
||||
int fd[4];
|
||||
unsigned int stride[4];
|
||||
unsigned int offset[4];
|
||||
|
||||
GDestroyNotify destroy;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
struct _GdkDmabufTextureClass
|
||||
{
|
||||
GdkTextureClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GdkDmabufTexture, gdk_dmabuf_texture, GDK_TYPE_TEXTURE)
|
||||
|
||||
static void
|
||||
gdk_dmabuf_texture_dispose (GObject *object)
|
||||
{
|
||||
GdkDmabufTexture *self = GDK_DMABUF_TEXTURE (object);
|
||||
|
||||
if (self->destroy)
|
||||
self->destroy (self->data);
|
||||
|
||||
G_OBJECT_CLASS (gdk_dmabuf_texture_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static struct {
|
||||
unsigned int fourcc;
|
||||
guint64 modifier;
|
||||
GdkMemoryFormat memory;
|
||||
int planes;
|
||||
} supported_formats[] = {
|
||||
{ DRM_FORMAT_RGB888, DRM_FORMAT_MOD_LINEAR, GDK_MEMORY_R8G8B8, 1 },
|
||||
{ DRM_FORMAT_BGR888, DRM_FORMAT_MOD_LINEAR, GDK_MEMORY_B8G8R8, 1 },
|
||||
{ DRM_FORMAT_ARGB8888, DRM_FORMAT_MOD_LINEAR, GDK_MEMORY_A8R8G8B8, 1 },
|
||||
{ DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_LINEAR, GDK_MEMORY_A8B8G8R8, 1 },
|
||||
{ DRM_FORMAT_RGBA8888, DRM_FORMAT_MOD_LINEAR, GDK_MEMORY_R8G8B8A8, 1 },
|
||||
{ DRM_FORMAT_BGRA8888, DRM_FORMAT_MOD_LINEAR, GDK_MEMORY_B8G8R8A8, 1 },
|
||||
};
|
||||
|
||||
static gboolean
|
||||
get_memory_format (GdkDisplay *display,
|
||||
unsigned int fourcc,
|
||||
guint64 modifier,
|
||||
GdkMemoryFormat *format,
|
||||
int *n_planes)
|
||||
{
|
||||
/* We can always support simple linear formats */
|
||||
for (int i = 0; i < G_N_ELEMENTS (supported_formats); i++)
|
||||
{
|
||||
if (supported_formats[i].fourcc == fourcc &&
|
||||
supported_formats[i].modifier == modifier)
|
||||
{
|
||||
*format = supported_formats[i].memory;
|
||||
*n_planes = supported_formats[i].planes;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (display)
|
||||
{
|
||||
const GdkDmabufFormat *formats;
|
||||
gsize n_formats;
|
||||
|
||||
/* For others, we rely on a detour though GL */
|
||||
formats = gdk_display_get_dmabuf_formats (display, &n_formats);
|
||||
for (gsize i = 0; i < n_formats; i++)
|
||||
{
|
||||
if (formats[i].fourcc == fourcc &&
|
||||
formats[i].modifier == modifier)
|
||||
{
|
||||
*format = GDK_MEMORY_A8R8G8B8; // FIXME
|
||||
*n_planes = 1; // FIXME
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int
|
||||
import_dmabuf_into_gl (GdkDmabufTexture *self)
|
||||
{
|
||||
GdkGLContext *context;
|
||||
EGLDisplay egl_display;
|
||||
EGLint attribs[64];
|
||||
EGLImage image;
|
||||
guint texture_id;
|
||||
int i;
|
||||
|
||||
egl_display = gdk_display_get_egl_display (self->display);
|
||||
|
||||
if (egl_display == EGL_NO_DISPLAY)
|
||||
{
|
||||
g_warning ("Can't import dmabufs when not using EGL");
|
||||
return 0;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
attribs[i++] = EGL_WIDTH;
|
||||
attribs[i++] = gdk_texture_get_width (GDK_TEXTURE (self));
|
||||
attribs[i++] = EGL_HEIGHT;
|
||||
attribs[i++] = gdk_texture_get_height (GDK_TEXTURE (self));
|
||||
attribs[i++] = EGL_LINUX_DRM_FOURCC_EXT;
|
||||
attribs[i++] = self->fourcc;
|
||||
|
||||
#define ADD_PLANE_ATTRIBUTES(plane) \
|
||||
if (self->fd[plane] != -1 || self->offset[plane] != 0) \
|
||||
{ \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE ## plane ## _FD_EXT; \
|
||||
attribs[i++] = self->fd[plane]; \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE ## plane ## _MODIFIER_LO_EXT; \
|
||||
attribs[i++] = self->modifier & 0xFFFFFFFF; \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE ## plane ## _MODIFIER_HI_EXT; \
|
||||
attribs[i++] = self->modifier >> 32; \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE ## plane ## _PITCH_EXT; \
|
||||
attribs[i++] = self->stride[plane]; \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE ## plane ## _OFFSET_EXT; \
|
||||
attribs[i++] = self->offset[plane]; \
|
||||
}
|
||||
|
||||
ADD_PLANE_ATTRIBUTES (0)
|
||||
ADD_PLANE_ATTRIBUTES (1)
|
||||
ADD_PLANE_ATTRIBUTES (2)
|
||||
ADD_PLANE_ATTRIBUTES (3)
|
||||
|
||||
attribs[i++] = EGL_NONE;
|
||||
|
||||
image = eglCreateImageKHR (egl_display,
|
||||
EGL_NO_CONTEXT,
|
||||
EGL_LINUX_DMA_BUF_EXT,
|
||||
(EGLClientBuffer)NULL,
|
||||
attribs);
|
||||
if (image == EGL_NO_IMAGE)
|
||||
{
|
||||
g_warning ("Failed to create EGL image: %d", eglGetError ());
|
||||
return 0;
|
||||
}
|
||||
|
||||
context = gdk_display_get_gl_context (self->display);
|
||||
gdk_gl_context_make_current (context);
|
||||
|
||||
glGenTextures (1, &texture_id);
|
||||
glBindTexture (GL_TEXTURE_2D, texture_id);
|
||||
glEGLImageTargetTexture2DOES (GL_TEXTURE_2D, image);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
eglDestroyImageKHR (egl_display, image);
|
||||
|
||||
return texture_id;
|
||||
}
|
||||
|
||||
static void
|
||||
do_indirect_download (GdkDmabufTexture *self,
|
||||
GdkMemoryFormat format,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
GdkGLTextureBuilder *builder;
|
||||
int id;
|
||||
GdkTexture *gl_texture;
|
||||
GdkTextureDownloader *downloader;
|
||||
|
||||
GDK_DEBUG (MISC, "Using EGLImage and GL import for downloading a dmabuf");
|
||||
|
||||
g_assert (GDK_IS_DISPLAY (self->display));
|
||||
g_assert (GDK_IS_GL_CONTEXT (gdk_display_get_gl_context (self->display)));
|
||||
|
||||
id = import_dmabuf_into_gl (self);
|
||||
if (id == 0)
|
||||
return;
|
||||
|
||||
builder = gdk_gl_texture_builder_new ();
|
||||
|
||||
gdk_gl_texture_builder_set_context (builder, gdk_display_get_gl_context (self->display));
|
||||
gdk_gl_texture_builder_set_id (builder, id);
|
||||
gdk_gl_texture_builder_set_width (builder, gdk_texture_get_width (GDK_TEXTURE (self)));
|
||||
gdk_gl_texture_builder_set_height (builder, gdk_texture_get_height (GDK_TEXTURE (self)));
|
||||
gdk_gl_texture_builder_set_format (builder, gdk_texture_get_format (GDK_TEXTURE (self)));
|
||||
|
||||
gl_texture = gdk_gl_texture_builder_build (builder, NULL, NULL);
|
||||
|
||||
downloader = gdk_texture_downloader_new (gl_texture);
|
||||
|
||||
gdk_texture_downloader_set_format (downloader, format);
|
||||
|
||||
gdk_texture_downloader_download_into (downloader, data, stride);
|
||||
|
||||
gdk_texture_downloader_free (downloader);
|
||||
g_object_unref (gl_texture);
|
||||
g_object_unref (builder);
|
||||
}
|
||||
|
||||
static void
|
||||
do_direct_download (GdkDmabufTexture *self,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
gsize size;
|
||||
unsigned int height;
|
||||
gsize src_stride;
|
||||
guchar *src_data;
|
||||
int bpp;
|
||||
|
||||
GDK_DEBUG (MISC, "Using mmap() and memcpy() for downloading a dmabuf");
|
||||
|
||||
height = gdk_texture_get_height (GDK_TEXTURE (self));
|
||||
bpp = gdk_memory_format_bytes_per_pixel (gdk_texture_get_format (GDK_TEXTURE (self)));
|
||||
|
||||
src_stride = self->stride[0];
|
||||
size = self->stride[0] * height;
|
||||
|
||||
if (ioctl (self->fd[0], DMA_BUF_IOCTL_SYNC, &(struct dma_buf_sync) { DMA_BUF_SYNC_START|DMA_BUF_SYNC_READ }) < 0)
|
||||
g_warning ("Failed to sync dma-buf: %s", g_strerror (errno));
|
||||
|
||||
src_data = mmap (NULL, size, PROT_READ, MAP_SHARED, self->fd[0], self->offset[0]);
|
||||
|
||||
if (stride == src_stride)
|
||||
memcpy (data, src_data, size);
|
||||
else
|
||||
{
|
||||
for (unsigned int i = 0; i < height; i++)
|
||||
memcpy (data + i * stride, src_data + i * src_stride, height * bpp);
|
||||
}
|
||||
|
||||
if (ioctl (self->fd[0], DMA_BUF_IOCTL_SYNC, &(struct dma_buf_sync) { DMA_BUF_SYNC_END|DMA_BUF_SYNC_READ }) < 0)
|
||||
g_warning ("Failed to sync dma-buf: %s", g_strerror (errno));
|
||||
|
||||
munmap (src_data, size);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_dmabuf_texture_download (GdkTexture *texture,
|
||||
GdkMemoryFormat format,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
GdkDmabufTexture *self = GDK_DMABUF_TEXTURE (texture);
|
||||
GdkMemoryFormat fmt;
|
||||
int planes;
|
||||
GdkMemoryFormat src_format = gdk_texture_get_format (texture);
|
||||
|
||||
if (!get_memory_format (NULL, self->fourcc, self->modifier, &fmt, &planes))
|
||||
do_indirect_download (self, format, data, stride);
|
||||
else if (format == src_format)
|
||||
do_direct_download (self, data, stride);
|
||||
else
|
||||
{
|
||||
unsigned int width, height;
|
||||
guchar *src_data;
|
||||
gsize src_stride;
|
||||
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
|
||||
src_stride = self->stride[0];
|
||||
src_data = g_new (guchar, src_stride * height);
|
||||
|
||||
do_direct_download (self, src_data, src_stride);
|
||||
|
||||
gdk_memory_convert (data, stride, format,
|
||||
src_data, src_stride, src_format,
|
||||
width, height);
|
||||
|
||||
g_free (src_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_dmabuf_texture_class_init (GdkDmabufTextureClass *klass)
|
||||
{
|
||||
GdkTextureClass *texture_class = GDK_TEXTURE_CLASS (klass);
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
texture_class->download = gdk_dmabuf_texture_download;
|
||||
|
||||
gobject_class->dispose = gdk_dmabuf_texture_dispose;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_dmabuf_texture_init (GdkDmabufTexture *self)
|
||||
{
|
||||
self->fd[0] = self->fd[1] = self->fd[2] = self->fd[3] = -1;
|
||||
}
|
||||
|
||||
GdkTexture *
|
||||
gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
|
||||
GDestroyNotify destroy,
|
||||
gpointer data)
|
||||
{
|
||||
GdkDmabufTexture *self;
|
||||
GdkTexture *update_texture;
|
||||
GdkMemoryFormat format;
|
||||
int n_planes;
|
||||
uint32_t f = gdk_dmabuf_texture_builder_get_fourcc (builder);
|
||||
uint64_t m = gdk_dmabuf_texture_builder_get_modifier(builder);
|
||||
|
||||
if (!get_memory_format (gdk_dmabuf_texture_builder_get_display (builder),
|
||||
gdk_dmabuf_texture_builder_get_fourcc (builder),
|
||||
gdk_dmabuf_texture_builder_get_modifier (builder),
|
||||
&format, &n_planes))
|
||||
{
|
||||
g_warning ("Unsupported dmabuf format %c%c%c%c:%#lx", f & 0xff, (f >> 8) & 0xff, (f >> 16) & 0xff, (f >> 24) & 0xff, m);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GDK_DEBUG (MISC, "Dmabuf texture in format %c%c%c%c:%#lx", f & 0xff, (f >> 8) & 0xff, (f >> 16) & 0xff, (f >> 24) & 0xff, m);
|
||||
|
||||
self = g_object_new (GDK_TYPE_DMABUF_TEXTURE,
|
||||
"width", gdk_dmabuf_texture_builder_get_width (builder),
|
||||
"height", gdk_dmabuf_texture_builder_get_height (builder),
|
||||
NULL);
|
||||
|
||||
GDK_TEXTURE (self)->format = format;
|
||||
|
||||
g_set_object (&self->display, gdk_dmabuf_texture_builder_get_display (builder));
|
||||
|
||||
self->fourcc = gdk_dmabuf_texture_builder_get_fourcc (builder);
|
||||
self->modifier = gdk_dmabuf_texture_builder_get_modifier (builder);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
self->fd[i] = gdk_dmabuf_texture_builder_get_fd (builder, i);
|
||||
self->stride[i] = gdk_dmabuf_texture_builder_get_stride (builder, i);
|
||||
if (self->stride[i] == 0)
|
||||
self->stride[i] = gdk_dmabuf_texture_builder_get_width (builder) *
|
||||
gdk_memory_format_bytes_per_pixel (format);
|
||||
self->offset[i] = gdk_dmabuf_texture_builder_get_offset (builder, i);
|
||||
}
|
||||
|
||||
update_texture = gdk_dmabuf_texture_builder_get_update_texture (builder);
|
||||
if (update_texture)
|
||||
{
|
||||
cairo_region_t *update_region = gdk_dmabuf_texture_builder_get_update_region (builder);
|
||||
if (update_region)
|
||||
{
|
||||
update_region = cairo_region_copy (update_region);
|
||||
cairo_region_intersect_rectangle (update_region,
|
||||
&(cairo_rectangle_int_t) {
|
||||
0, 0,
|
||||
update_texture->width, update_texture->height
|
||||
});
|
||||
gdk_texture_set_diff (GDK_TEXTURE (self), update_texture, update_region);
|
||||
}
|
||||
}
|
||||
|
||||
return GDK_TEXTURE (self);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
gdk_dmabuf_texture_get_fourcc (GdkDmabufTexture *texture)
|
||||
{
|
||||
return texture->fourcc;
|
||||
}
|
||||
|
||||
guint64
|
||||
gdk_dmabuf_texture_get_modifier (GdkDmabufTexture *texture)
|
||||
{
|
||||
return texture->modifier;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
gdk_dmabuf_texture_get_offset (GdkDmabufTexture *texture,
|
||||
int plane)
|
||||
{
|
||||
return texture->offset[plane];
|
||||
}
|
||||
|
||||
unsigned int
|
||||
gdk_dmabuf_texture_get_stride (GdkDmabufTexture *texture,
|
||||
int plane)
|
||||
{
|
||||
return texture->stride[plane];
|
||||
}
|
||||
|
||||
int
|
||||
gdk_dmabuf_texture_get_fd (GdkDmabufTexture *texture,
|
||||
int plane)
|
||||
{
|
||||
return texture->fd[plane];
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
43
gdk/gdkdmabuftexture.h
Normal file
43
gdk/gdkdmabuftexture.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/* gdkdmabuftexture.h
|
||||
*
|
||||
* Copyright 2023 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gdk/gdk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gdk/gdktypes.h>
|
||||
#include <gdk/gdktexture.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GDK_TYPE_DMABUF_TEXTURE (gdk_dmabuf_texture_get_type ())
|
||||
|
||||
#define GDK_DMABUF_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_DMABUF_TEXTURE, GdkDmabufTexture))
|
||||
#define GDK_IS_DMABUF_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_DMABUF_TEXTURE))
|
||||
|
||||
typedef struct _GdkDmabufTexture GdkDmabufTexture;
|
||||
typedef struct _GdkDmabufTextureClass GdkDmabufTextureClass;
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
GType gdk_dmabuf_texture_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkDmabufTexture, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
1063
gdk/gdkdmabuftexturebuilder.c
Normal file
1063
gdk/gdkdmabuftexturebuilder.c
Normal file
File diff suppressed because it is too large
Load Diff
109
gdk/gdkdmabuftexturebuilder.h
Normal file
109
gdk/gdkdmabuftexturebuilder.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright © 2023 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gdk/gdk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gdk/gdktypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GDK_TYPE_DMABUF_TEXTURE_BUILDER (gdk_dmabuf_texture_builder_get_type ())
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
GDK_DECLARE_INTERNAL_TYPE (GdkDmabufTextureBuilder, gdk_dmabuf_texture_builder, GDK, DMABUF_TEXTURE_BUILDER, GObject)
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
GdkDmabufTextureBuilder *gdk_dmabuf_texture_builder_new (void);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
GdkDisplay * gdk_dmabuf_texture_builder_get_display (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gdk_dmabuf_texture_builder_set_display (GdkDmabufTextureBuilder *self,
|
||||
GdkDisplay *display);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
unsigned int gdk_dmabuf_texture_builder_get_width (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gdk_dmabuf_texture_builder_set_width (GdkDmabufTextureBuilder *self,
|
||||
unsigned int width);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
unsigned int gdk_dmabuf_texture_builder_get_height (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gdk_dmabuf_texture_builder_set_height (GdkDmabufTextureBuilder *self,
|
||||
unsigned int height);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
unsigned int gdk_dmabuf_texture_builder_get_fourcc (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gdk_dmabuf_texture_builder_set_fourcc (GdkDmabufTextureBuilder *self,
|
||||
unsigned int fourcc);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
guint64 gdk_dmabuf_texture_builder_get_modifier (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gdk_dmabuf_texture_builder_set_modifier (GdkDmabufTextureBuilder *self,
|
||||
guint64 modifier);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
int gdk_dmabuf_texture_builder_get_fd (GdkDmabufTextureBuilder *self,
|
||||
int plane) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gdk_dmabuf_texture_builder_set_fd (GdkDmabufTextureBuilder *self,
|
||||
int plane,
|
||||
int fd);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
unsigned int gdk_dmabuf_texture_builder_get_stride (GdkDmabufTextureBuilder *self,
|
||||
int plane) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gdk_dmabuf_texture_builder_set_stride (GdkDmabufTextureBuilder *self,
|
||||
int plane,
|
||||
unsigned int stride);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
unsigned int gdk_dmabuf_texture_builder_get_offset (GdkDmabufTextureBuilder *self,
|
||||
int plane) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gdk_dmabuf_texture_builder_set_offset (GdkDmabufTextureBuilder *self,
|
||||
int plane,
|
||||
unsigned int offset);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
GdkTexture * gdk_dmabuf_texture_builder_get_update_texture (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gdk_dmabuf_texture_builder_set_update_texture (GdkDmabufTextureBuilder *self,
|
||||
GdkTexture *texture);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
cairo_region_t * gdk_dmabuf_texture_builder_get_update_region (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gdk_dmabuf_texture_builder_set_update_region (GdkDmabufTextureBuilder *self,
|
||||
cairo_region_t *region);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
GdkTexture * gdk_dmabuf_texture_builder_build (GdkDmabufTextureBuilder *self,
|
||||
GDestroyNotify destroy,
|
||||
gpointer data);
|
||||
|
||||
G_END_DECLS
|
||||
|
24
gdk/gdkdmabuftextureprivate.h
Normal file
24
gdk/gdkdmabuftextureprivate.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "gdkdmabuftexture.h"
|
||||
|
||||
#include "gdkdmabuftexturebuilder.h"
|
||||
#include "gdktextureprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GdkTexture * gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
|
||||
GDestroyNotify destroy,
|
||||
gpointer data);
|
||||
|
||||
unsigned int gdk_dmabuf_texture_get_fourcc (GdkDmabufTexture *texture);
|
||||
guint64 gdk_dmabuf_texture_get_modifier (GdkDmabufTexture *texture);
|
||||
int gdk_dmabuf_texture_get_fd (GdkDmabufTexture *texture,
|
||||
int plane);
|
||||
unsigned int gdk_dmabuf_texture_get_offset (GdkDmabufTexture *texture,
|
||||
int plane);
|
||||
unsigned int gdk_dmabuf_texture_get_stride (GdkDmabufTexture *texture,
|
||||
int plane);
|
||||
|
||||
G_END_DECLS
|
||||
|
@@ -17,6 +17,8 @@ gdk_public_sources = files([
|
||||
'gdkdevicetool.c',
|
||||
'gdkdisplay.c',
|
||||
'gdkdisplaymanager.c',
|
||||
'gdkdmabuftexture.c',
|
||||
'gdkdmabuftexturebuilder.c',
|
||||
'gdkdrag.c',
|
||||
'gdkdragsurface.c',
|
||||
'gdkdragsurfacesize.c',
|
||||
@@ -79,6 +81,8 @@ gdk_public_headers = files([
|
||||
'gdkdisplay.h',
|
||||
'gdkdisplaymanager.h',
|
||||
'gdkdrag.h',
|
||||
'gdkdmabuftexture.h',
|
||||
'gdkdmabuftexturebuilder.h',
|
||||
'gdkdragsurfacesize.h',
|
||||
'gdkdrawcontext.h',
|
||||
'gdkdrop.h',
|
||||
|
@@ -24,6 +24,7 @@
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
#ifdef HAVE_LINUX_MEMFD_H
|
||||
#include <linux/memfd.h>
|
||||
@@ -56,6 +57,7 @@
|
||||
#include <wayland/xdg-foreign-unstable-v1-client-protocol.h>
|
||||
#include <wayland/xdg-foreign-unstable-v2-client-protocol.h>
|
||||
#include <wayland/server-decoration-client-protocol.h>
|
||||
#include "linux-dmabuf-unstable-v1-client-protocol.h"
|
||||
|
||||
#include "wm-button-layout-translation.h"
|
||||
|
||||
@@ -298,7 +300,7 @@ wl_shm_format (void *data,
|
||||
char buf[10];
|
||||
#endif
|
||||
|
||||
GDK_DEBUG (MISC, "supported pixel format %s (0x%X)",
|
||||
GDK_DEBUG (MISC, "supported shm pixel format %s (0x%X)",
|
||||
get_format_name (format, buf), (guint) format);
|
||||
}
|
||||
|
||||
@@ -306,6 +308,93 @@ static const struct wl_shm_listener wl_shm_listener = {
|
||||
wl_shm_format
|
||||
};
|
||||
|
||||
static void
|
||||
linux_dmabuf_done (void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1)
|
||||
{
|
||||
GDK_DEBUG (MISC, "dmabuf feedback done");
|
||||
}
|
||||
|
||||
static void
|
||||
linux_dmabuf_format_table (void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1,
|
||||
int32_t fd,
|
||||
uint32_t size)
|
||||
{
|
||||
GdkWaylandDisplay *display_wayland = data;
|
||||
|
||||
display_wayland->linux_dmabuf_n_formats = size / 16;
|
||||
display_wayland->linux_dmabuf_formats = mmap (NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
|
||||
GDK_DEBUG (MISC, "got dmabuf format table (%lu entries)", display_wayland->linux_dmabuf_n_formats);
|
||||
}
|
||||
|
||||
static void
|
||||
linux_dmabuf_main_device (void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1,
|
||||
struct wl_array *device)
|
||||
{
|
||||
dev_t dev = *(dev_t *)device->data;
|
||||
|
||||
GDK_DEBUG (MISC, "got dmabuf main device: %u %u", major (dev), minor (dev));
|
||||
}
|
||||
|
||||
static void
|
||||
linux_dmabuf_tranche_done (void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1)
|
||||
{
|
||||
GDK_DEBUG (MISC, "dmabuf feedback tranche done");
|
||||
}
|
||||
|
||||
static void
|
||||
linux_dmabuf_tranche_target_device (void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1,
|
||||
struct wl_array *device)
|
||||
{
|
||||
dev_t dev = *(dev_t *)device->data;
|
||||
|
||||
GDK_DEBUG (MISC, "got dmabuf tranche target device: %u %u", major (dev), minor (dev));
|
||||
}
|
||||
|
||||
static void
|
||||
linux_dmabuf_tranche_formats (void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1,
|
||||
struct wl_array *indices)
|
||||
{
|
||||
GdkWaylandDisplay *display_wayland = data;
|
||||
|
||||
GDK_DEBUG (MISC, "got dmabuf tranche formats (%lu entries):", indices->size / sizeof (guint16));
|
||||
guint16 *pos;
|
||||
|
||||
wl_array_for_each (pos, indices)
|
||||
{
|
||||
LinuxDmabufFormat *fmt = &display_wayland->linux_dmabuf_formats[*pos];
|
||||
uint32_t f = fmt->fourcc;
|
||||
uint64_t m = fmt->modifier;
|
||||
GDK_DEBUG (MISC, " %c%c%c%c:%#lx", f & 0xff, (f >> 8) & 0xff, (f >> 16) & 0xff, (f >> 24) & 0xff, m);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
linux_dmabuf_tranche_flags (void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1,
|
||||
uint32_t flags)
|
||||
{
|
||||
GDK_DEBUG (MISC,
|
||||
"got dmabuf tranche flags: %s",
|
||||
flags & ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT ? "scanout" : "");
|
||||
}
|
||||
|
||||
static const struct zwp_linux_dmabuf_feedback_v1_listener linux_dmabuf_feedback_listener = {
|
||||
linux_dmabuf_done,
|
||||
linux_dmabuf_format_table,
|
||||
linux_dmabuf_main_device,
|
||||
linux_dmabuf_tranche_done,
|
||||
linux_dmabuf_tranche_target_device,
|
||||
linux_dmabuf_tranche_formats,
|
||||
linux_dmabuf_tranche_flags,
|
||||
};
|
||||
|
||||
static void
|
||||
server_decoration_manager_default_mode (void *data,
|
||||
struct org_kde_kwin_server_decoration_manager *manager,
|
||||
@@ -382,6 +471,18 @@ gdk_registry_handle_global (void *data,
|
||||
wl_registry_bind (display_wayland->wl_registry, id, &wl_shm_interface, 1);
|
||||
wl_shm_add_listener (display_wayland->shm, &wl_shm_listener, display_wayland);
|
||||
}
|
||||
else if (strcmp (interface, "zwp_linux_dmabuf_v1") == 0)
|
||||
{
|
||||
display_wayland->linux_dmabuf =
|
||||
wl_registry_bind (display_wayland->wl_registry, id,
|
||||
&zwp_linux_dmabuf_v1_interface,
|
||||
MIN (version, 4));
|
||||
display_wayland->linux_dmabuf_feedback =
|
||||
zwp_linux_dmabuf_v1_get_default_feedback (display_wayland->linux_dmabuf);
|
||||
zwp_linux_dmabuf_feedback_v1_add_listener (display_wayland->linux_dmabuf_feedback,
|
||||
&linux_dmabuf_feedback_listener, display_wayland);
|
||||
_gdk_wayland_display_async_roundtrip (display_wayland);
|
||||
}
|
||||
else if (strcmp (interface, "xdg_wm_base") == 0)
|
||||
{
|
||||
display_wayland->xdg_wm_base_id = id;
|
||||
@@ -726,6 +827,10 @@ gdk_wayland_display_dispose (GObject *object)
|
||||
g_clear_pointer (&display_wayland->xdg_activation, xdg_activation_v1_destroy);
|
||||
g_clear_pointer (&display_wayland->fractional_scale, wp_fractional_scale_manager_v1_destroy);
|
||||
g_clear_pointer (&display_wayland->viewporter, wp_viewporter_destroy);
|
||||
g_clear_pointer (&display_wayland->linux_dmabuf, zwp_linux_dmabuf_v1_destroy);
|
||||
g_clear_pointer (&display_wayland->linux_dmabuf_feedback, zwp_linux_dmabuf_feedback_v1_destroy);
|
||||
if (display_wayland->linux_dmabuf_formats)
|
||||
munmap (display_wayland->linux_dmabuf_formats, display_wayland->linux_dmabuf_n_formats * 16);
|
||||
|
||||
g_clear_pointer (&display_wayland->shm, wl_shm_destroy);
|
||||
g_clear_pointer (&display_wayland->wl_registry, wl_registry_destroy);
|
||||
|
@@ -71,6 +71,13 @@ typedef enum _GdkWaylandShellVariant
|
||||
GDK_WAYLAND_SHELL_VARIANT_ZXDG_SHELL_V6
|
||||
} GdkWaylandShellVariant;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t fourcc;
|
||||
uint32_t padding;
|
||||
uint64_t modifier;
|
||||
} LinuxDmabufFormat;
|
||||
|
||||
struct _GdkWaylandDisplay
|
||||
{
|
||||
GdkDisplay parent_instance;
|
||||
@@ -95,6 +102,10 @@ struct _GdkWaylandDisplay
|
||||
struct wl_registry *wl_registry;
|
||||
struct wl_compositor *compositor;
|
||||
struct wl_shm *shm;
|
||||
struct zwp_linux_dmabuf_v1 *linux_dmabuf;
|
||||
struct zwp_linux_dmabuf_feedback_v1 *linux_dmabuf_feedback;
|
||||
gsize linux_dmabuf_n_formats;
|
||||
LinuxDmabufFormat *linux_dmabuf_formats;
|
||||
struct xdg_wm_base *xdg_wm_base;
|
||||
struct zxdg_shell_v6 *zxdg_shell_v6;
|
||||
struct gtk_shell1 *gtk_shell;
|
||||
|
@@ -67,6 +67,7 @@ proto_sources = [
|
||||
['idle-inhibit', 'unstable', 'v1', ],
|
||||
['xdg-activation', 'staging', 'v1', ],
|
||||
['fractional-scale', 'staging', 'v1', ],
|
||||
['linux-dmabuf', 'unstable', 'v1', ],
|
||||
]
|
||||
|
||||
gdk_wayland_gen_headers = []
|
||||
|
@@ -1136,7 +1136,12 @@ gsk_gl_driver_lookup_shader (GskGLDriver *self,
|
||||
return program;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void
|
||||
gsk_gl_driver_save_texture_to_png (GskGLDriver *driver,
|
||||
int texture_id,
|
||||
int width,
|
||||
int height,
|
||||
const char *filename);
|
||||
void
|
||||
gsk_gl_driver_save_texture_to_png (GskGLDriver *driver,
|
||||
int texture_id,
|
||||
@@ -1160,6 +1165,7 @@ gsk_gl_driver_save_texture_to_png (GskGLDriver *driver,
|
||||
g_object_unref (builder);
|
||||
}
|
||||
|
||||
#if 0
|
||||
void
|
||||
gsk_gl_driver_save_atlases_to_png (GskGLDriver *self,
|
||||
const char *directory)
|
||||
|
@@ -42,6 +42,10 @@ GSK_GL_DEFINE_PROGRAM (cross_fade,
|
||||
GSK_GL_ADD_UNIFORM (1, CROSS_FADE_PROGRESS, u_progress)
|
||||
GSK_GL_ADD_UNIFORM (2, CROSS_FADE_SOURCE2, u_source2))
|
||||
|
||||
GSK_GL_DEFINE_PROGRAM (dmabuf,
|
||||
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("dmabuf.glsl")),
|
||||
GSK_GL_ADD_UNIFORM (1, DMABUF_SOURCE, u_source_dmabuf))
|
||||
|
||||
GSK_GL_DEFINE_PROGRAM (filled_border,
|
||||
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("filled_border.glsl")),
|
||||
GSK_GL_ADD_UNIFORM (1, FILLED_BORDER_WIDTHS, u_widths)
|
||||
|
@@ -30,6 +30,8 @@
|
||||
#include <gsk/gskglshaderprivate.h>
|
||||
#include <gdk/gdktextureprivate.h>
|
||||
#include <gdk/gdkmemorytextureprivate.h>
|
||||
#include <gdk/gdkdmabuftextureprivate.h>
|
||||
#include <gdk/gdkdisplayprivate.h>
|
||||
#include <gsk/gsktransformprivate.h>
|
||||
#include <gsk/gskroundedrectprivate.h>
|
||||
#include <gsk/gskrectprivate.h>
|
||||
@@ -43,10 +45,13 @@
|
||||
#include "gskglprogramprivate.h"
|
||||
#include "gskglrenderjobprivate.h"
|
||||
#include "gskglshadowlibraryprivate.h"
|
||||
#include "gskdebugprivate.h"
|
||||
|
||||
#include "ninesliceprivate.h"
|
||||
#include "fp16private.h"
|
||||
|
||||
#include <epoxy/egl.h>
|
||||
|
||||
#define ORTHO_NEAR_PLANE -10000
|
||||
#define ORTHO_FAR_PLANE 10000
|
||||
#define MAX_GRADIENT_STOPS 6
|
||||
@@ -3562,6 +3567,164 @@ gsk_gl_render_job_visit_gl_shader_node (GskGLRenderJob *job,
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
import_dmabuf_texture (GskGLRenderJob *job,
|
||||
GdkTexture *texture)
|
||||
{
|
||||
GdkDmabufTexture *dmabuf_texture = GDK_DMABUF_TEXTURE (texture);
|
||||
GdkGLContext *context = job->command_queue->context;
|
||||
GdkDisplay *display = gdk_gl_context_get_display (context);
|
||||
EGLDisplay egl_display;
|
||||
EGLint attribs[64];
|
||||
EGLImage image;
|
||||
guint texture_id;
|
||||
int i;
|
||||
|
||||
GSK_DEBUG (OPENGL, "Importing dma-buf into GL via EGLImage");
|
||||
|
||||
egl_display = gdk_display_get_egl_display (display);
|
||||
if (egl_display == NULL)
|
||||
{
|
||||
g_warning ("Can't import dmabufs when not using EGL");
|
||||
return 0;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
attribs[i++] = EGL_WIDTH;
|
||||
attribs[i++] = gdk_texture_get_width (texture);
|
||||
attribs[i++] = EGL_HEIGHT;
|
||||
attribs[i++] = gdk_texture_get_height (texture);
|
||||
attribs[i++] = EGL_LINUX_DRM_FOURCC_EXT;
|
||||
attribs[i++] = gdk_dmabuf_texture_get_fourcc (dmabuf_texture);
|
||||
|
||||
#define ADD_PLANE_ATTRIBUTES(plane) \
|
||||
if (gdk_dmabuf_texture_get_fd (dmabuf_texture, plane) != -1 || gdk_dmabuf_texture_get_offset (dmabuf_texture, plane) != 0) \
|
||||
{ \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE ## plane ## _FD_EXT; \
|
||||
attribs[i++] = gdk_dmabuf_texture_get_fd (dmabuf_texture, plane); \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE ## plane ## _MODIFIER_LO_EXT; \
|
||||
attribs[i++] = gdk_dmabuf_texture_get_modifier (dmabuf_texture) & 0xFFFFFFFF; \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE ## plane ## _MODIFIER_HI_EXT; \
|
||||
attribs[i++] = gdk_dmabuf_texture_get_modifier (dmabuf_texture) >> 32; \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE ## plane ## _PITCH_EXT; \
|
||||
attribs[i++] = gdk_dmabuf_texture_get_stride (dmabuf_texture, plane); \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE ## plane ## _OFFSET_EXT; \
|
||||
attribs[i++] = gdk_dmabuf_texture_get_offset (dmabuf_texture, plane); \
|
||||
}
|
||||
|
||||
ADD_PLANE_ATTRIBUTES (0)
|
||||
ADD_PLANE_ATTRIBUTES (1)
|
||||
ADD_PLANE_ATTRIBUTES (2)
|
||||
ADD_PLANE_ATTRIBUTES (3)
|
||||
|
||||
attribs[i++] = EGL_NONE;
|
||||
|
||||
image = eglCreateImageKHR (egl_display,
|
||||
EGL_NO_CONTEXT,
|
||||
EGL_LINUX_DMA_BUF_EXT,
|
||||
(EGLClientBuffer)NULL,
|
||||
attribs);
|
||||
|
||||
if (image == EGL_NO_IMAGE)
|
||||
{
|
||||
g_warning ("Failed to create EGL image: %#x\n", eglGetError ());
|
||||
return 0;
|
||||
}
|
||||
|
||||
gdk_gl_context_make_current (context);
|
||||
|
||||
glGenTextures (1, &texture_id);
|
||||
glBindTexture (GL_TEXTURE_EXTERNAL_OES, texture_id);
|
||||
glEGLImageTargetTexture2DOES (GL_TEXTURE_EXTERNAL_OES, image);
|
||||
glTexParameteri (GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri (GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
eglDestroyImageKHR (egl_display, image);
|
||||
|
||||
return texture_id;
|
||||
}
|
||||
|
||||
static void
|
||||
set_viewport_for_size (GskGLDriver *self,
|
||||
GskGLProgram *program,
|
||||
float width,
|
||||
float height)
|
||||
{
|
||||
float viewport[4] = { 0, 0, width, height };
|
||||
|
||||
gsk_gl_uniform_state_set4fv (program->uniforms,
|
||||
program->program_info,
|
||||
UNIFORM_SHARED_VIEWPORT, 0,
|
||||
1,
|
||||
(const float *)&viewport);
|
||||
self->stamps[UNIFORM_SHARED_VIEWPORT]++;
|
||||
}
|
||||
|
||||
#define ORTHO_NEAR_PLANE -10000
|
||||
#define ORTHO_FAR_PLANE 10000
|
||||
|
||||
static void
|
||||
set_projection_for_size (GskGLDriver *self,
|
||||
GskGLProgram *program,
|
||||
float width,
|
||||
float height)
|
||||
{
|
||||
graphene_matrix_t projection;
|
||||
|
||||
graphene_matrix_init_ortho (&projection, 0, width, 0, height, ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE);
|
||||
graphene_matrix_scale (&projection, 1, -1, 1);
|
||||
|
||||
gsk_gl_uniform_state_set_matrix (program->uniforms,
|
||||
program->program_info,
|
||||
UNIFORM_SHARED_PROJECTION, 0,
|
||||
&projection);
|
||||
self->stamps[UNIFORM_SHARED_PROJECTION]++;
|
||||
}
|
||||
|
||||
static void
|
||||
reset_modelview (GskGLDriver *self,
|
||||
GskGLProgram *program)
|
||||
{
|
||||
graphene_matrix_t modelview;
|
||||
|
||||
graphene_matrix_init_identity (&modelview);
|
||||
|
||||
gsk_gl_uniform_state_set_matrix (program->uniforms,
|
||||
program->program_info,
|
||||
UNIFORM_SHARED_MODELVIEW, 0,
|
||||
&modelview);
|
||||
self->stamps[UNIFORM_SHARED_MODELVIEW]++;
|
||||
}
|
||||
|
||||
static void
|
||||
draw_rect (GskGLCommandQueue *command_queue,
|
||||
float min_x,
|
||||
float min_y,
|
||||
float max_x,
|
||||
float max_y)
|
||||
{
|
||||
GskGLDrawVertex *vertices = gsk_gl_command_queue_add_vertices (command_queue);
|
||||
float min_u = 0;
|
||||
float max_u = 1;
|
||||
float min_v = 1;
|
||||
float max_v = 0;
|
||||
guint16 c = FP16_ZERO;
|
||||
|
||||
vertices[0] = (GskGLDrawVertex) { .position = { min_x, min_y }, .uv = { min_u, min_v }, .color = { c, c, c, c } };
|
||||
vertices[1] = (GskGLDrawVertex) { .position = { min_x, max_y }, .uv = { min_u, max_v }, .color = { c, c, c, c } };
|
||||
vertices[2] = (GskGLDrawVertex) { .position = { max_x, min_y }, .uv = { max_u, min_v }, .color = { c, c, c, c } };
|
||||
vertices[3] = (GskGLDrawVertex) { .position = { max_x, max_y }, .uv = { max_u, max_v }, .color = { c, c, c, c } };
|
||||
vertices[4] = (GskGLDrawVertex) { .position = { min_x, max_y }, .uv = { min_u, max_v }, .color = { c, c, c, c } };
|
||||
vertices[5] = (GskGLDrawVertex) { .position = { max_x, min_y }, .uv = { max_u, min_v }, .color = { c, c, c, c } };
|
||||
}
|
||||
|
||||
extern void
|
||||
gsk_gl_driver_save_texture_to_png (GskGLDriver *driver,
|
||||
int texture_id,
|
||||
int width,
|
||||
int height,
|
||||
const char *filename);
|
||||
|
||||
static void
|
||||
gsk_gl_render_job_upload_texture (GskGLRenderJob *job,
|
||||
GdkTexture *texture,
|
||||
@@ -3570,6 +3733,56 @@ gsk_gl_render_job_upload_texture (GskGLRenderJob *job,
|
||||
{
|
||||
GdkGLTexture *gl_texture = NULL;
|
||||
|
||||
if (GDK_IS_DMABUF_TEXTURE (texture))
|
||||
{
|
||||
unsigned int texture_id;
|
||||
GskGLRenderTarget *render_target;
|
||||
int width, height;
|
||||
int prev_fbo;
|
||||
GskGLProgram *program;
|
||||
|
||||
g_print ("importing YUYV\n");
|
||||
width = gdk_texture_get_width (GDK_TEXTURE (texture));
|
||||
height = gdk_texture_get_height (GDK_TEXTURE (texture));
|
||||
|
||||
texture_id = import_dmabuf_texture (job, texture);
|
||||
|
||||
gsk_gl_driver_save_texture_to_png (job->driver, texture_id, width, height, "tex.png");
|
||||
|
||||
gsk_gl_driver_create_render_target (job->driver, width, height, GL_RGBA8, &render_target);
|
||||
|
||||
prev_fbo = gsk_gl_command_queue_bind_framebuffer (job->driver->command_queue, render_target->framebuffer_id);
|
||||
gsk_gl_command_queue_clear (job->driver->command_queue, 0, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
|
||||
program = job->driver->dmabuf_no_clip;
|
||||
|
||||
gsk_gl_command_queue_begin_draw (job->driver->command_queue,
|
||||
program->program_info,
|
||||
width, height);
|
||||
|
||||
set_projection_for_size (job->driver, program, width, height);
|
||||
set_viewport_for_size (job->driver, program, width, height);
|
||||
reset_modelview (job->driver, program);
|
||||
|
||||
gsk_gl_program_set_uniform_texture (program,
|
||||
UNIFORM_DMABUF_SOURCE, 0,
|
||||
GL_TEXTURE_2D, GL_TEXTURE0, texture_id);
|
||||
|
||||
draw_rect (job->driver->command_queue, 0, 0, width, height);
|
||||
|
||||
gsk_gl_command_queue_end_draw (job->driver->command_queue);
|
||||
|
||||
gsk_gl_command_queue_bind_framebuffer (job->driver->command_queue, prev_fbo);
|
||||
|
||||
offscreen->texture_id = gsk_gl_driver_release_render_target (job->driver, render_target, FALSE);
|
||||
init_full_texture_region (offscreen);
|
||||
offscreen->has_mipmap = FALSE;
|
||||
|
||||
glDeleteTextures (1, &texture_id);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (GDK_IS_GL_TEXTURE (texture))
|
||||
gl_texture = GDK_GL_TEXTURE (texture);
|
||||
|
||||
|
19
gsk/gl/resources/dmabuf.glsl
Normal file
19
gsk/gl/resources/dmabuf.glsl
Normal file
@@ -0,0 +1,19 @@
|
||||
// VERTEX_SHADER:
|
||||
// dmabuf.glsl
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
// dmabuf.glsl
|
||||
|
||||
uniform samplerExternalOES u_source_dmabuf;
|
||||
|
||||
void main() {
|
||||
vec4 rgb = texture2D(u_source_dmabuf, vUv);
|
||||
|
||||
gskSetOutputColor(rgb);
|
||||
}
|
@@ -1,3 +1,5 @@
|
||||
#extension GL_OES_EGL_image_external : require
|
||||
|
||||
#ifndef GSK_LEGACY
|
||||
precision highp float;
|
||||
#endif
|
||||
|
@@ -20,6 +20,7 @@ gsk_private_gl_shaders = [
|
||||
'gl/resources/custom.glsl',
|
||||
'gl/resources/filled_border.glsl',
|
||||
'gl/resources/mask.glsl',
|
||||
'gl/resources/dmabuf.glsl',
|
||||
]
|
||||
|
||||
gsk_public_sources = files([
|
||||
|
Reference in New Issue
Block a user