Compare commits
9 Commits
dmabuf-tex
...
ebassi/fix
Author | SHA1 | Date | |
---|---|---|---|
|
2d370768db | ||
|
7325121c63 | ||
|
31abe56b7a | ||
|
ca3fd16039 | ||
|
4417509515 | ||
|
9dc2e554e5 | ||
|
bfb01f5a4b | ||
|
570e80a9ff | ||
|
6d90d25a74 |
@@ -2,8 +2,9 @@
|
||||
# a merge request for files listed here, please add the following people to
|
||||
# the list of reviewers
|
||||
|
||||
# The syntax of this file is similar to the GitHub CODEOWNERS file:
|
||||
# https://help.github.com/articles/about-codeowners/
|
||||
# The syntax of this file is defined in the GitLab documentation:
|
||||
# https://docs.gitlab.com/ee/user/project/codeowners/reference.html
|
||||
#
|
||||
# Which, in turn, is similar to the .gitignore and .gitattributes files:
|
||||
#
|
||||
# - comments start with `#`
|
||||
@@ -14,64 +15,61 @@
|
||||
# If you want to be responsible for code reviews in specific sections of
|
||||
# the GTK code base, add yourself here.
|
||||
|
||||
# Maintainer
|
||||
* @matthiasc
|
||||
[Maintainer]
|
||||
* @matthiasc
|
||||
|
||||
# Build system
|
||||
meson.build @ebassi @nirbheek
|
||||
*.py @ebassi
|
||||
[Build system]
|
||||
meson.build @ebassi @nirbheek @xclaesse
|
||||
*.py @ebassi
|
||||
|
||||
# CSS
|
||||
gtk/gtkcss*.[ch] @otte @baedert
|
||||
gtk/gtkstyle*.[ch] @otte @baedert
|
||||
[CSS]
|
||||
/gtk/gtkcss*.[ch] @otte @matthiasc
|
||||
/gtk/gtkstyle*.[ch] @otte @matthiasc
|
||||
|
||||
# Gestures
|
||||
gtk/gtkeventcontroller* @carlosg
|
||||
gtk/gtkgesture*.[ch] @carlosg
|
||||
[Gestures]
|
||||
/gtk/gtkeventcontroller* @carlosg
|
||||
/gtk/gtkgesture*.[ch] @carlosg
|
||||
|
||||
# GtkFileChooser
|
||||
gtk/gtkfilechooser* @federico @ebassi
|
||||
gtk/gtkfilesystem* @federico @ebassi
|
||||
gtk/gtkfilefilter* @federico @ebassi
|
||||
[Input methods]
|
||||
/gtk/gtkimcontext* @carlosg
|
||||
|
||||
# GtkFontChooser
|
||||
gtk/gtkfontchooser* @matthiasc
|
||||
[Media]
|
||||
/gtk/gtkmedia* @otte
|
||||
|
||||
# Input methods
|
||||
gtk/gtkimcontext* @carlosg
|
||||
[GSK]
|
||||
/gsk/ @otte @chergert @ebassi
|
||||
|
||||
# Media
|
||||
gtk/gtkmedia* @otte
|
||||
[GL rendering]
|
||||
/gsk/gl/ @otte @chergert
|
||||
|
||||
# GSK
|
||||
gsk @otte @baedert @ebassi
|
||||
[Vulkan rendering]
|
||||
/gsk/vulkan @otte
|
||||
|
||||
# GL rendering
|
||||
gsk/gl @baedert @ebassi
|
||||
[Documentation]
|
||||
/docs/ @ebassi @dboles
|
||||
README.md @ebassi
|
||||
CONTRIBUTING.md @ebassi @matthiasc
|
||||
|
||||
# Vulkan rendering
|
||||
gsk/vulkan
|
||||
[Wayland]
|
||||
/gdk/wayland @jadahl
|
||||
|
||||
# Documentation
|
||||
docs/ @ebassi @dboles
|
||||
[X11]
|
||||
/gdk/x11 @ofourdan @matthiasc @carlosg
|
||||
|
||||
# Wayland
|
||||
gdk/wayland @jadahl
|
||||
[macOS]
|
||||
/gdk/macos @chergert
|
||||
|
||||
# X11
|
||||
gdk/x11 @ofourdan @matthiasc
|
||||
[Themes]
|
||||
/gtk/themes @lapoc @jimmac
|
||||
|
||||
# Themes
|
||||
gtk/themes @lapoc @jimmac
|
||||
[Inspector]
|
||||
/gtk/inspector @otte @matthiasc
|
||||
|
||||
# Inspector
|
||||
gtk/inspector @otte @matthiasc
|
||||
[Layout managers]
|
||||
/gtk/gtklayout* @ebassi
|
||||
/gtk/gtkconstraint* @ebassi
|
||||
|
||||
# Layout managers
|
||||
gtk/gtklayout* @ebassi
|
||||
gtk/gtkconstraint* @ebassi
|
||||
|
||||
# Accessibility
|
||||
gtk/gtkaccessible*.[ch] @ebassi
|
||||
gtk/gtkatcontext*.[ch] @ebassi
|
||||
gtk/a11y @ebassi
|
||||
[Accessibility]
|
||||
/gtk/gtkaccessible*.[ch] @ebassi @tyrylu @matthiasc
|
||||
/gtk/gtkatcontext*.[ch] @ebassi @tyrylu @matthiasc
|
||||
/gtk/a11y @ebassi @tyrylu
|
||||
|
@@ -1770,10 +1770,6 @@ gdk_display_init_egl (GdkDisplay *self,
|
||||
epoxy_has_egl_extension (priv->egl_display, "EGL_KHR_no_config_context");
|
||||
self->have_egl_pixel_format_float =
|
||||
epoxy_has_egl_extension (priv->egl_display, "EGL_EXT_pixel_format_float");
|
||||
self->have_egl_dma_buf_import =
|
||||
epoxy_has_egl_extension (priv->egl_display, "EGL_EXT_image_dma_buf_import_modifiers");
|
||||
self->have_egl_dma_buf_export =
|
||||
epoxy_has_egl_extension (priv->egl_display, "EGL_MESA_image_dma_buf_export");
|
||||
|
||||
if (self->have_egl_no_config_context)
|
||||
priv->egl_config_high_depth = gdk_display_create_egl_config (self,
|
||||
@@ -1843,6 +1839,29 @@ gdk_display_get_egl_display (GdkDisplay *self)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
static void
|
||||
gdk_display_add_dmabuf_downloader (GdkDisplay *display,
|
||||
const GdkDmabufDownloader *downloader,
|
||||
GdkDmabufFormatsBuilder *builder)
|
||||
{
|
||||
gsize i;
|
||||
|
||||
downloader->add_formats (downloader, display, builder);
|
||||
|
||||
/* dmabuf_downloaders is NULL-terminated */
|
||||
for (i = 0; i < G_N_ELEMENTS (display->dmabuf_downloaders) - 1; i++)
|
||||
{
|
||||
if (display->dmabuf_downloaders[i] == NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
g_assert (i < G_N_ELEMENTS (display->dmabuf_downloaders));
|
||||
|
||||
display->dmabuf_downloaders[i] = downloader;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* To support a drm format, we must be able to import it into GL
|
||||
* using the relevant EGL extensions, and download it into a memory
|
||||
* texture, possibly doing format conversion with shaders (in GSK).
|
||||
@@ -1850,7 +1869,6 @@ gdk_display_get_egl_display (GdkDisplay *self)
|
||||
static void
|
||||
init_dmabuf_formats (GdkDisplay *display)
|
||||
{
|
||||
GdkDisplayPrivate *priv = gdk_display_get_instance_private (display);
|
||||
GdkDmabufFormatsBuilder *builder;
|
||||
|
||||
if (display->dmabuf_formats != NULL)
|
||||
@@ -1858,18 +1876,17 @@ init_dmabuf_formats (GdkDisplay *display)
|
||||
|
||||
builder = gdk_dmabuf_formats_builder_new ();
|
||||
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
if (!GDK_DEBUG_CHECK (DMABUF_DISABLE))
|
||||
{
|
||||
gdk_display_prepare_gl (display, NULL);
|
||||
|
||||
gdk_dmabuf_texture_add_supported_formats (builder);
|
||||
|
||||
if (priv->gl_context)
|
||||
gdk_gl_context_add_dmabuf_formats (priv->gl_context, builder);
|
||||
gdk_display_add_dmabuf_downloader (display, gdk_dmabuf_get_direct_downloader (), builder);
|
||||
}
|
||||
#endif
|
||||
|
||||
display->dmabuf_formats = gdk_dmabuf_formats_builder_free_to_formats (builder);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_display_get_dmabuf_formats:
|
||||
|
@@ -25,7 +25,7 @@
|
||||
#include "gdksurfaceprivate.h"
|
||||
#include "gdkkeysprivate.h"
|
||||
#include "gdkdeviceprivate.h"
|
||||
#include "gdkdmabufformats.h"
|
||||
#include "gdkdmabufprivate.h"
|
||||
|
||||
#ifdef GDK_RENDERING_VULKAN
|
||||
#include <vulkan/vulkan.h>
|
||||
@@ -114,10 +114,9 @@ struct _GdkDisplay
|
||||
guint have_egl_buffer_age : 1;
|
||||
guint have_egl_no_config_context : 1;
|
||||
guint have_egl_pixel_format_float : 1;
|
||||
guint have_egl_dma_buf_import : 1;
|
||||
guint have_egl_dma_buf_export : 1;
|
||||
|
||||
GdkDmabufFormats *dmabuf_formats;
|
||||
const GdkDmabufDownloader *dmabuf_downloaders[4];
|
||||
};
|
||||
|
||||
struct _GdkDisplayClass
|
||||
|
209
gdk/gdkdmabuf.c
Normal file
209
gdk/gdkdmabuf.c
Normal file
@@ -0,0 +1,209 @@
|
||||
/* gdkdmabuf.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 "gdkdmabufprivate.h"
|
||||
|
||||
#include "gdkdebugprivate.h"
|
||||
#include "gdkdmabuftextureprivate.h"
|
||||
#include "gdkmemoryformatprivate.h"
|
||||
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <epoxy/egl.h>
|
||||
|
||||
typedef struct _GdkDrmFormatInfo GdkDrmFormatInfo;
|
||||
struct _GdkDrmFormatInfo
|
||||
{
|
||||
guint32 fourcc;
|
||||
GdkMemoryFormat premultiplied_memory_format;
|
||||
GdkMemoryFormat unpremultiplied_memory_format;
|
||||
};
|
||||
|
||||
static GdkDrmFormatInfo supported_formats[] = {
|
||||
{ DRM_FORMAT_ARGB8888, GDK_MEMORY_A8R8G8B8_PREMULTIPLIED, GDK_MEMORY_A8R8G8B8 },
|
||||
{ DRM_FORMAT_RGBA8888, GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, GDK_MEMORY_R8G8B8A8 },
|
||||
{ DRM_FORMAT_BGRA8888, GDK_MEMORY_B8G8R8A8_PREMULTIPLIED, GDK_MEMORY_B8G8R8A8 },
|
||||
{ DRM_FORMAT_ABGR16161616F, GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED, GDK_MEMORY_R16G16B16A16_FLOAT },
|
||||
{ DRM_FORMAT_RGB888, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8 },
|
||||
{ DRM_FORMAT_BGR888, GDK_MEMORY_B8G8R8, GDK_MEMORY_B8G8R8 },
|
||||
};
|
||||
|
||||
static GdkDrmFormatInfo *
|
||||
get_drm_format_info (guint32 fourcc)
|
||||
{
|
||||
for (int i = 0; i < G_N_ELEMENTS (supported_formats); i++)
|
||||
{
|
||||
if (supported_formats[i].fourcc == fourcc)
|
||||
return &supported_formats[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_dmabuf_direct_downloader_add_formats (const GdkDmabufDownloader *downloader,
|
||||
GdkDisplay *display,
|
||||
GdkDmabufFormatsBuilder *builder)
|
||||
{
|
||||
gsize i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (supported_formats); i++)
|
||||
{
|
||||
gdk_dmabuf_formats_builder_add_format (builder,
|
||||
supported_formats[i].fourcc,
|
||||
DRM_FORMAT_MOD_LINEAR);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_dmabuf_direct_downloader_supports (const GdkDmabufDownloader *downloader,
|
||||
GdkDisplay *display,
|
||||
const GdkDmabuf *dmabuf,
|
||||
gboolean premultiplied,
|
||||
GdkMemoryFormat *out_format,
|
||||
GError **error)
|
||||
{
|
||||
GdkDrmFormatInfo *info;
|
||||
|
||||
info = get_drm_format_info (dmabuf->fourcc);
|
||||
|
||||
if (!info)
|
||||
{
|
||||
g_set_error (error,
|
||||
GDK_DMABUF_ERROR, GDK_DMABUF_ERROR_UNSUPPORTED_FORMAT,
|
||||
"Unsupported dmabuf format %.4s",
|
||||
(char *) &dmabuf->fourcc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (dmabuf->modifier != DRM_FORMAT_MOD_LINEAR)
|
||||
{
|
||||
g_set_error (error,
|
||||
GDK_DMABUF_ERROR, GDK_DMABUF_ERROR_UNSUPPORTED_FORMAT,
|
||||
"Unsupported dmabuf modifier %#lx (only linear buffers are supported)",
|
||||
dmabuf->modifier);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (dmabuf->n_planes > 1)
|
||||
{
|
||||
g_set_error_literal (error,
|
||||
GDK_DMABUF_ERROR, GDK_DMABUF_ERROR_CREATION_FAILED,
|
||||
"Multiplanar dmabufs are not supported");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*out_format = premultiplied ? info->premultiplied_memory_format
|
||||
: info->unpremultiplied_memory_format;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_dmabuf_direct_downloader_do_download (GdkTexture *texture,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
const GdkDmabuf *dmabuf;
|
||||
gsize size;
|
||||
unsigned int height;
|
||||
gsize src_stride;
|
||||
guchar *src_data;
|
||||
int bpp;
|
||||
|
||||
GDK_DEBUG (DMABUF, "Using mmap() and memcpy() for downloading a dmabuf");
|
||||
|
||||
dmabuf = gdk_dmabuf_texture_get_dmabuf (GDK_DMABUF_TEXTURE (texture));
|
||||
height = gdk_texture_get_height (texture);
|
||||
bpp = gdk_memory_format_bytes_per_pixel (gdk_texture_get_format (texture));
|
||||
|
||||
src_stride = dmabuf->planes[0].stride;
|
||||
size = dmabuf->planes[0].stride * height;
|
||||
|
||||
if (ioctl (dmabuf->planes[0].fd, 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, dmabuf->planes[0].fd, dmabuf->planes[0].offset);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
munmap (src_data, size);
|
||||
|
||||
if (ioctl (dmabuf->planes[0].fd, 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));
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_dmabuf_direct_downloader_download (const GdkDmabufDownloader *downloader,
|
||||
GdkTexture *texture,
|
||||
GdkMemoryFormat format,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
GdkMemoryFormat src_format = gdk_texture_get_format (texture);
|
||||
|
||||
if (format == src_format)
|
||||
gdk_dmabuf_direct_downloader_do_download (texture, data, stride);
|
||||
else
|
||||
{
|
||||
const GdkDmabuf *dmabuf;
|
||||
unsigned int width, height;
|
||||
guchar *src_data;
|
||||
gsize src_stride;
|
||||
|
||||
dmabuf = gdk_dmabuf_texture_get_dmabuf (GDK_DMABUF_TEXTURE (texture));
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
|
||||
src_stride = dmabuf->planes[0].stride;
|
||||
src_data = g_new (guchar, src_stride * height);
|
||||
|
||||
gdk_dmabuf_direct_downloader_do_download (texture, src_data, src_stride);
|
||||
|
||||
gdk_memory_convert (data, stride, format,
|
||||
src_data, src_stride, src_format,
|
||||
width, height);
|
||||
|
||||
g_free (src_data);
|
||||
}
|
||||
}
|
||||
|
||||
const GdkDmabufDownloader *
|
||||
gdk_dmabuf_get_direct_downloader (void)
|
||||
{
|
||||
static const GdkDmabufDownloader downloader = {
|
||||
gdk_dmabuf_direct_downloader_add_formats,
|
||||
gdk_dmabuf_direct_downloader_supports,
|
||||
gdk_dmabuf_direct_downloader_download,
|
||||
};
|
||||
|
||||
return &downloader;
|
||||
}
|
||||
|
||||
#endif /* HAVE_LINUX_DMA_BUF_H */
|
44
gdk/gdkdmabufprivate.h
Normal file
44
gdk/gdkdmabufprivate.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include "gdkdmabufformatsbuilderprivate.h"
|
||||
|
||||
#define GDK_DMABUF_MAX_PLANES 4
|
||||
|
||||
typedef struct _GdkDmabuf GdkDmabuf;
|
||||
typedef struct _GdkDmabufDownloader GdkDmabufDownloader;
|
||||
|
||||
struct _GdkDmabuf
|
||||
{
|
||||
guint32 fourcc;
|
||||
guint64 modifier;
|
||||
unsigned int n_planes;
|
||||
struct {
|
||||
int fd;
|
||||
unsigned int stride;
|
||||
unsigned int offset;
|
||||
} planes[GDK_DMABUF_MAX_PLANES];
|
||||
};
|
||||
|
||||
struct _GdkDmabufDownloader
|
||||
{
|
||||
void (* add_formats) (const GdkDmabufDownloader *downloader,
|
||||
GdkDisplay *display,
|
||||
GdkDmabufFormatsBuilder *builder);
|
||||
|
||||
gboolean (* supports) (const GdkDmabufDownloader *downloader,
|
||||
GdkDisplay *display,
|
||||
const GdkDmabuf *dmabuf,
|
||||
gboolean premultiplied,
|
||||
GdkMemoryFormat *out_format,
|
||||
GError **error);
|
||||
void (* download) (const GdkDmabufDownloader *downloader,
|
||||
GdkTexture *texture,
|
||||
GdkMemoryFormat format,
|
||||
guchar *data,
|
||||
gsize stride);
|
||||
};
|
||||
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
const GdkDmabufDownloader *
|
||||
gdk_dmabuf_get_direct_downloader (void) G_GNUC_CONST;
|
||||
#endif
|
@@ -22,9 +22,8 @@
|
||||
|
||||
#include "gdkdisplayprivate.h"
|
||||
#include "gdkdmabufformatsbuilderprivate.h"
|
||||
#include "gdkmemoryformatprivate.h"
|
||||
#include "gdkmemorytextureprivate.h"
|
||||
#include <gdk/gdkglcontextprivate.h>
|
||||
#include "gdktextureprivate.h"
|
||||
#include <gdk/gdkglcontext.h>
|
||||
#include <gdk/gdkgltexturebuilder.h>
|
||||
#include <gdk/gdktexturedownloader.h>
|
||||
|
||||
@@ -36,8 +35,6 @@
|
||||
#include <epoxy/egl.h>
|
||||
#endif
|
||||
|
||||
#include <graphene.h>
|
||||
|
||||
/**
|
||||
* GdkDmabufTexture:
|
||||
*
|
||||
@@ -54,16 +51,9 @@ struct _GdkDmabufTexture
|
||||
GdkTexture parent_instance;
|
||||
|
||||
GdkDisplay *display;
|
||||
const GdkDmabufDownloader *downloader;
|
||||
|
||||
guint32 fourcc;
|
||||
guint64 modifier;
|
||||
|
||||
unsigned int n_planes;
|
||||
|
||||
/* Per-plane properties */
|
||||
int fds[MAX_DMABUF_PLANES];
|
||||
unsigned int strides[MAX_DMABUF_PLANES];
|
||||
unsigned int offsets[MAX_DMABUF_PLANES];
|
||||
GdkDmabuf dmabuf;
|
||||
|
||||
GDestroyNotify destroy;
|
||||
gpointer data;
|
||||
@@ -81,7 +71,6 @@ G_DEFINE_TYPE (GdkDmabufTexture, gdk_dmabuf_texture, GDK_TYPE_TEXTURE)
|
||||
static void
|
||||
gdk_dmabuf_texture_init (GdkDmabufTexture *self)
|
||||
{
|
||||
self->fds[0] = self->fds[1] = self->fds[2] = self->fds[3] = -1;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -95,10 +84,20 @@ gdk_dmabuf_texture_dispose (GObject *object)
|
||||
G_OBJECT_CLASS (gdk_dmabuf_texture_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void gdk_dmabuf_texture_download (GdkTexture *texture,
|
||||
GdkMemoryFormat format,
|
||||
guchar *data,
|
||||
gsize stride);
|
||||
static void
|
||||
gdk_dmabuf_texture_download (GdkTexture *texture,
|
||||
GdkMemoryFormat format,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
GdkDmabufTexture *self = GDK_DMABUF_TEXTURE (texture);
|
||||
|
||||
self->downloader->download (self->downloader,
|
||||
texture,
|
||||
format,
|
||||
data,
|
||||
stride);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_dmabuf_texture_class_init (GdkDmabufTextureClass *klass)
|
||||
@@ -111,672 +110,16 @@ gdk_dmabuf_texture_class_init (GdkDmabufTextureClass *klass)
|
||||
gobject_class->dispose = gdk_dmabuf_texture_dispose;
|
||||
}
|
||||
|
||||
guint32
|
||||
gdk_dmabuf_texture_get_fourcc (GdkDmabufTexture *texture)
|
||||
GdkDisplay *
|
||||
gdk_dmabuf_texture_get_display (GdkDmabufTexture *self)
|
||||
{
|
||||
return texture->fourcc;
|
||||
return self->display;
|
||||
}
|
||||
|
||||
guint64
|
||||
gdk_dmabuf_texture_get_modifier (GdkDmabufTexture *texture)
|
||||
const GdkDmabuf *
|
||||
gdk_dmabuf_texture_get_dmabuf (GdkDmabufTexture *self)
|
||||
{
|
||||
return texture->modifier;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
gdk_dmabuf_texture_get_n_planes (GdkDmabufTexture *texture)
|
||||
{
|
||||
return texture->n_planes;
|
||||
}
|
||||
|
||||
int *
|
||||
gdk_dmabuf_texture_get_fds (GdkDmabufTexture *texture)
|
||||
{
|
||||
return texture->fds;
|
||||
}
|
||||
|
||||
unsigned int *
|
||||
gdk_dmabuf_texture_get_strides (GdkDmabufTexture *texture)
|
||||
{
|
||||
return texture->strides;
|
||||
}
|
||||
|
||||
unsigned int *
|
||||
gdk_dmabuf_texture_get_offsets (GdkDmabufTexture *texture)
|
||||
{
|
||||
return texture->offsets;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
|
||||
typedef struct _GdkDrmFormatInfo GdkDrmFormatInfo;
|
||||
struct _GdkDrmFormatInfo
|
||||
{
|
||||
guint32 fourcc;
|
||||
GdkMemoryFormat premultiplied_memory_format;
|
||||
GdkMemoryFormat unpremultiplied_memory_format;
|
||||
};
|
||||
|
||||
/* These are the dma-buf formats that we can support just with memcpy,
|
||||
* as long as they are combined with DRM_FORMAT_MOD_LINEAR
|
||||
*/
|
||||
static GdkDrmFormatInfo supported_formats[] = {
|
||||
{ DRM_FORMAT_ARGB8888, GDK_MEMORY_A8R8G8B8_PREMULTIPLIED, GDK_MEMORY_A8R8G8B8 },
|
||||
{ DRM_FORMAT_RGBA8888, GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, GDK_MEMORY_R8G8B8A8 },
|
||||
{ DRM_FORMAT_BGRA8888, GDK_MEMORY_B8G8R8A8_PREMULTIPLIED, GDK_MEMORY_B8G8R8A8 },
|
||||
{ DRM_FORMAT_ABGR16161616F, GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED, GDK_MEMORY_R16G16B16A16_FLOAT },
|
||||
{ DRM_FORMAT_RGB888, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8 },
|
||||
{ DRM_FORMAT_BGR888, GDK_MEMORY_B8G8R8, GDK_MEMORY_B8G8R8 },
|
||||
};
|
||||
|
||||
static GdkDrmFormatInfo *
|
||||
get_drm_format_info (guint32 fourcc)
|
||||
{
|
||||
for (int i = 0; i < G_N_ELEMENTS (supported_formats); i++)
|
||||
{
|
||||
if (supported_formats[i].fourcc == fourcc)
|
||||
return &supported_formats[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Hack. We don't include gsk/gsk.h here to avoid a build order problem
|
||||
* with the generated header gskenumtypes.h, so we need to hack around
|
||||
* a bit to access the gsk api we need.
|
||||
*/
|
||||
|
||||
typedef gpointer GskRenderer;
|
||||
typedef gpointer GskRenderNode;
|
||||
|
||||
extern GskRenderer * gsk_gl_renderer_new (void);
|
||||
extern gboolean gsk_renderer_realize (GskRenderer *renderer,
|
||||
GdkSurface *surface,
|
||||
GError **error);
|
||||
extern void gsk_renderer_unrealize (GskRenderer *renderer);
|
||||
extern GdkTexture * gsk_renderer_render_texture (GskRenderer *renderer,
|
||||
GskRenderNode *node,
|
||||
const graphene_rect_t *bounds);
|
||||
extern GskRenderNode * gsk_texture_node_new (GdkTexture *texture,
|
||||
const graphene_rect_t *viewport);
|
||||
extern void gsk_render_node_unref (GskRenderNode *node);
|
||||
|
||||
static int
|
||||
gl_format_for_memory_format (GdkMemoryFormat format)
|
||||
{
|
||||
switch (gdk_memory_format_get_depth (format))
|
||||
{
|
||||
case GDK_MEMORY_U8:
|
||||
return GL_RGBA8;
|
||||
case GDK_MEMORY_U16:
|
||||
return GL_RGBA16;
|
||||
case GDK_MEMORY_FLOAT16:
|
||||
return GL_RGBA16F;
|
||||
case GDK_MEMORY_FLOAT32:
|
||||
return GL_RGBA32F;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
gl_type_for_gl_format (int format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case GL_RGBA8:
|
||||
return GL_UNSIGNED_BYTE;
|
||||
case GL_RGBA16:
|
||||
return GL_UNSIGNED_SHORT;
|
||||
case GL_RGBA16F:
|
||||
return GL_HALF_FLOAT;
|
||||
case GL_RGBA32F:
|
||||
return GL_FLOAT;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
create_render_target (int width,
|
||||
int height,
|
||||
int format,
|
||||
unsigned int *fbo_id,
|
||||
unsigned int *texture_id)
|
||||
{
|
||||
int type;
|
||||
unsigned int texture, fbo;
|
||||
|
||||
type = gl_type_for_gl_format (format);
|
||||
|
||||
glGenTextures (1, &texture);
|
||||
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
glBindTexture (GL_TEXTURE_2D, texture);
|
||||
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
glTexImage2D (GL_TEXTURE_2D, 0, format, width, height, 0, GL_RGBA, type, NULL);
|
||||
|
||||
glGenFramebuffers (1, &fbo);
|
||||
glBindFramebuffer (GL_FRAMEBUFFER, fbo);
|
||||
glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
|
||||
g_assert (glCheckFramebufferStatus (GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
|
||||
|
||||
*fbo_id = fbo;
|
||||
*texture_id = texture;
|
||||
}
|
||||
|
||||
static const char vertex_shader_source[] = ""
|
||||
"#version 150\n"
|
||||
"in vec2 in_position;\n"
|
||||
"void main() {\n"
|
||||
" gl_Position = vec4(in_position, 0.0, 1.0);\n"
|
||||
"}";
|
||||
|
||||
static const char fragment_shader_source[] = ""
|
||||
"#version 150\n"
|
||||
"uniform sampler2D source;\n"
|
||||
"uniform vec2 size;\n"
|
||||
"out vec4 out_color;\n"
|
||||
"void main() {\n"
|
||||
" vec4 in_color = texture(source, gl_FragCoord.xy / size);\n"
|
||||
" out_color = in_color;\n"
|
||||
"}";
|
||||
|
||||
static unsigned int
|
||||
create_shader (int type,
|
||||
const char *src)
|
||||
{
|
||||
unsigned int shader;
|
||||
int status;
|
||||
|
||||
shader = glCreateShader (type);
|
||||
glShaderSource (shader, 1, &src, NULL);
|
||||
glCompileShader (shader);
|
||||
|
||||
glGetShaderiv (shader, GL_COMPILE_STATUS, &status);
|
||||
if (status == GL_FALSE)
|
||||
{
|
||||
int log_len;
|
||||
char *buffer;
|
||||
|
||||
glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &log_len);
|
||||
|
||||
buffer = g_malloc (log_len + 1);
|
||||
glGetShaderInfoLog (shader, log_len, NULL, buffer);
|
||||
|
||||
g_warning ("Compile failure in %s shader:\n%s",
|
||||
type == GL_VERTEX_SHADER ? "vertex" : "fragment",
|
||||
buffer);
|
||||
|
||||
g_free (buffer);
|
||||
|
||||
glDeleteShader (shader);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
compile_program (const char *vs,
|
||||
const char *fs,
|
||||
unsigned int *source_location,
|
||||
unsigned int *size_location)
|
||||
{
|
||||
unsigned int vertex, fragment, program;
|
||||
int status;
|
||||
|
||||
vertex = create_shader (GL_VERTEX_SHADER, vs);
|
||||
if (vertex == 0)
|
||||
return 0;
|
||||
|
||||
fragment = create_shader (GL_FRAGMENT_SHADER, fs);
|
||||
if (fragment == 0)
|
||||
{
|
||||
glDeleteShader (vertex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
program = glCreateProgram ();
|
||||
|
||||
glAttachShader (program, vertex);
|
||||
glAttachShader (program, fragment);
|
||||
|
||||
glLinkProgram (program);
|
||||
|
||||
glGetProgramiv (program, GL_LINK_STATUS, &status);
|
||||
if (status == GL_FALSE)
|
||||
{
|
||||
int log_len;
|
||||
char *buffer;
|
||||
|
||||
glGetProgramiv (program, GL_INFO_LOG_LENGTH, &log_len);
|
||||
|
||||
buffer = g_malloc (log_len + 1);
|
||||
glGetProgramInfoLog (program, log_len, NULL, buffer);
|
||||
|
||||
g_warning ("Linking failure:\n%s", buffer);
|
||||
|
||||
g_free (buffer);
|
||||
|
||||
glDeleteProgram (program);
|
||||
program = 0;
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
*source_location = glGetUniformLocation (program, "source");
|
||||
*size_location = glGetUniformLocation (program, "size");
|
||||
|
||||
glDetachShader (program, vertex);
|
||||
glDetachShader (program, fragment);
|
||||
|
||||
out:
|
||||
glDeleteShader (vertex);
|
||||
glDeleteShader (fragment);
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
unsigned int program;
|
||||
unsigned int source_location;
|
||||
unsigned int size_location;
|
||||
} ProgramData;
|
||||
|
||||
static unsigned int
|
||||
get_blit_program (GdkGLContext *context,
|
||||
unsigned int *source_location,
|
||||
unsigned int *size_location)
|
||||
{
|
||||
ProgramData *data;
|
||||
|
||||
data = g_object_get_data (G_OBJECT (context), "dmabuf-blit-program-data");
|
||||
if (!data)
|
||||
{
|
||||
data = g_new0 (ProgramData, 1);
|
||||
data->program = compile_program (vertex_shader_source,
|
||||
fragment_shader_source,
|
||||
&data->source_location,
|
||||
&data->size_location);
|
||||
g_object_set_data (G_OBJECT (context), "dmabuf-blit-program-data", data);
|
||||
}
|
||||
|
||||
*source_location = data->source_location;
|
||||
*size_location = data->size_location;
|
||||
|
||||
return data->program;
|
||||
}
|
||||
|
||||
static void
|
||||
blit_texture (GdkGLContext *context,
|
||||
int width,
|
||||
int height,
|
||||
unsigned int texture,
|
||||
unsigned int fbo)
|
||||
{
|
||||
unsigned int program;
|
||||
unsigned int source_location;
|
||||
unsigned int size_location;
|
||||
unsigned int vao;
|
||||
unsigned int buffer;
|
||||
const float vertices[] = {
|
||||
-1.0f, 1.0f,
|
||||
-1.0f, -1.0f,
|
||||
1.0f, 1.0f,
|
||||
1.0f, -1.0f
|
||||
};
|
||||
|
||||
program = get_blit_program (context, &source_location, &size_location);
|
||||
|
||||
glGenVertexArrays (1, &vao);
|
||||
glBindVertexArray (vao);
|
||||
|
||||
glGenBuffers (1, &buffer);
|
||||
glBindBuffer (GL_ARRAY_BUFFER, buffer);
|
||||
glBufferData (GL_ARRAY_BUFFER, sizeof (vertices), vertices, GL_STATIC_DRAW);
|
||||
|
||||
glVertexAttribPointer (0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
|
||||
glEnableVertexAttribArray (0);
|
||||
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
glBindTexture (GL_TEXTURE_2D, texture);
|
||||
glBindFramebuffer (GL_FRAMEBUFFER, fbo);
|
||||
|
||||
glUseProgram (program);
|
||||
glUniform1i (source_location, texture);
|
||||
glUniform2f (size_location, width, height);
|
||||
|
||||
glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
glUseProgram (0);
|
||||
glDisableVertexAttribArray (0);
|
||||
glBindBuffer (GL_ARRAY_BUFFER, 0);
|
||||
|
||||
glDeleteBuffers (1, &buffer);
|
||||
glDeleteVertexArrays (1, &vao);
|
||||
}
|
||||
|
||||
static void
|
||||
do_indirect_download_gl (GdkDmabufTexture *self,
|
||||
GdkMemoryFormat format,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
GdkGLContext *context;
|
||||
unsigned int texture_id;
|
||||
unsigned int texture_id2;
|
||||
unsigned int fbo;
|
||||
int width, height;
|
||||
int gl_format;
|
||||
GdkGLTextureBuilder *builder;
|
||||
GdkTexture *gl_texture;
|
||||
gpointer sync;
|
||||
GdkTextureDownloader *downloader;
|
||||
|
||||
GDK_DEBUG (DMABUF, "Using gl for downloading a dmabuf");
|
||||
|
||||
context = gdk_display_get_gl_context (self->display);
|
||||
|
||||
gdk_gl_context_make_current (context);
|
||||
|
||||
gl_format = gl_format_for_memory_format (format),
|
||||
|
||||
width = gdk_texture_get_width (GDK_TEXTURE (self));
|
||||
height = gdk_texture_get_height (GDK_TEXTURE (self));
|
||||
|
||||
/* 1. import the dmabuf as GL texture */
|
||||
texture_id = gdk_gl_context_import_dmabuf (context, width, height,
|
||||
self->fourcc,
|
||||
self->modifier,
|
||||
self->n_planes,
|
||||
self->fds,
|
||||
self->strides,
|
||||
self->offsets);
|
||||
|
||||
/* 2. create a texture to render into */
|
||||
create_render_target (width, height, gl_format, &fbo, &texture_id2);
|
||||
|
||||
/* 3. copy from texture_id1 to texture_id2, using a blit shader */
|
||||
glClear (GL_COLOR_BUFFER_BIT);
|
||||
blit_texture (context, width, height, texture_id, fbo);
|
||||
sync = glFenceSync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
|
||||
/* 4. create a GdkGLTexture from the rendered texture */
|
||||
builder = gdk_gl_texture_builder_new ();
|
||||
gdk_gl_texture_builder_set_context (builder, context);
|
||||
gdk_gl_texture_builder_set_id (builder, texture_id2);
|
||||
gdk_gl_texture_builder_set_width (builder, width);
|
||||
gdk_gl_texture_builder_set_height (builder, height);
|
||||
gdk_gl_texture_builder_set_format (builder, format);
|
||||
gdk_gl_texture_builder_set_sync (builder, sync);
|
||||
gl_texture = gdk_gl_texture_builder_build (builder, NULL, NULL);
|
||||
|
||||
/* 5. download it */
|
||||
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);
|
||||
|
||||
/* 6. cleanup */
|
||||
glDeleteFramebuffers (1, &fbo);
|
||||
glDeleteTextures (1, &texture_id);
|
||||
glDeleteTextures (1, &texture_id2);
|
||||
}
|
||||
|
||||
static void
|
||||
do_indirect_download_gsk (GdkDmabufTexture *self,
|
||||
GdkMemoryFormat format,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
GskRenderer *renderer;
|
||||
int width, height;
|
||||
GskRenderNode *node;
|
||||
GdkTexture *gl_texture;
|
||||
GdkTextureDownloader *downloader;
|
||||
GError *error = NULL;
|
||||
|
||||
GDK_DEBUG (DMABUF, "Using gsk for downloading a dmabuf");
|
||||
|
||||
g_assert (GDK_IS_DISPLAY (self->display));
|
||||
g_assert (GDK_IS_GL_CONTEXT (gdk_display_get_gl_context (self->display)));
|
||||
|
||||
renderer = g_object_get_data (G_OBJECT (self->display), "dmabuf-gl-renderer");
|
||||
if (!renderer)
|
||||
{
|
||||
renderer = gsk_gl_renderer_new ();
|
||||
if (!gsk_renderer_realize (renderer, NULL, &error))
|
||||
{
|
||||
g_warning ("Failed to realize GL renderer: %s", error->message);
|
||||
g_error_free (error);
|
||||
g_object_unref (renderer);
|
||||
return;
|
||||
}
|
||||
|
||||
g_object_set_data_full (G_OBJECT (self->display), "dmabuf-gl-renderer",
|
||||
renderer, g_object_unref);
|
||||
}
|
||||
|
||||
width = gdk_texture_get_width (GDK_TEXTURE (self));
|
||||
height = gdk_texture_get_height (GDK_TEXTURE (self));
|
||||
|
||||
node = gsk_texture_node_new (GDK_TEXTURE (self), &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gl_texture = gsk_renderer_render_texture (renderer, node, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gsk_render_node_unref (node);
|
||||
|
||||
gsk_renderer_unrealize (renderer);
|
||||
g_object_unref (renderer);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 (DMABUF, "Using mmap 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->strides[0];
|
||||
size = self->strides[0] * height;
|
||||
|
||||
if (ioctl (self->fds[0], DMA_BUF_IOCTL_SYNC, &(struct dma_buf_sync) { DMA_BUF_SYNC_START|DMA_BUF_SYNC_READ }) < 0)
|
||||
g_warning ("Failed to sync dmabuf: %s", g_strerror (errno));
|
||||
|
||||
src_data = mmap (NULL, size, PROT_READ, MAP_SHARED, self->fds[0], self->offsets[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);
|
||||
}
|
||||
|
||||
munmap (src_data, size);
|
||||
|
||||
if (ioctl (self->fds[0], DMA_BUF_IOCTL_SYNC, &(struct dma_buf_sync) { DMA_BUF_SYNC_END|DMA_BUF_SYNC_READ }) < 0)
|
||||
g_warning ("Failed to sync dmabuf: %s", g_strerror (errno));
|
||||
}
|
||||
|
||||
/* A helper to determine suitable download memory formats for drm formats */
|
||||
static GdkMemoryFormat
|
||||
compute_memory_format (guint32 fourcc,
|
||||
gboolean premultiplied)
|
||||
{
|
||||
switch (fourcc)
|
||||
{
|
||||
case DRM_FORMAT_ARGB8888:
|
||||
case DRM_FORMAT_ABGR8888:
|
||||
case DRM_FORMAT_XRGB8888_A8:
|
||||
case DRM_FORMAT_XBGR8888_A8:
|
||||
return premultiplied ? GDK_MEMORY_A8R8G8B8_PREMULTIPLIED : GDK_MEMORY_A8R8G8B8;
|
||||
|
||||
case DRM_FORMAT_RGBA8888:
|
||||
case DRM_FORMAT_RGBX8888_A8:
|
||||
return premultiplied ? GDK_MEMORY_R8G8B8A8_PREMULTIPLIED : GDK_MEMORY_R8G8B8A8;
|
||||
|
||||
case DRM_FORMAT_BGRA8888:
|
||||
return premultiplied ? GDK_MEMORY_B8G8R8A8_PREMULTIPLIED : GDK_MEMORY_B8G8R8A8;
|
||||
|
||||
case DRM_FORMAT_RGB888:
|
||||
case DRM_FORMAT_XRGB8888:
|
||||
case DRM_FORMAT_XBGR8888:
|
||||
case DRM_FORMAT_RGBX8888:
|
||||
case DRM_FORMAT_BGRX8888:
|
||||
return GDK_MEMORY_R8G8B8;
|
||||
|
||||
case DRM_FORMAT_BGR888:
|
||||
return GDK_MEMORY_B8G8R8;
|
||||
|
||||
case DRM_FORMAT_XRGB2101010:
|
||||
case DRM_FORMAT_XBGR2101010:
|
||||
case DRM_FORMAT_RGBX1010102:
|
||||
case DRM_FORMAT_BGRX1010102:
|
||||
case DRM_FORMAT_XRGB16161616:
|
||||
case DRM_FORMAT_XBGR16161616:
|
||||
return GDK_MEMORY_R16G16B16;
|
||||
|
||||
case DRM_FORMAT_ARGB2101010:
|
||||
case DRM_FORMAT_ABGR2101010:
|
||||
case DRM_FORMAT_RGBA1010102:
|
||||
case DRM_FORMAT_BGRA1010102:
|
||||
case DRM_FORMAT_ARGB16161616:
|
||||
case DRM_FORMAT_ABGR16161616:
|
||||
return premultiplied ? GDK_MEMORY_R16G16B16A16_PREMULTIPLIED : GDK_MEMORY_R16G16B16A16;
|
||||
|
||||
case DRM_FORMAT_ARGB16161616F:
|
||||
case DRM_FORMAT_ABGR16161616F:
|
||||
return premultiplied ? GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED : GDK_MEMORY_R16G16B16A16_FLOAT;
|
||||
|
||||
case DRM_FORMAT_XRGB16161616F:
|
||||
case DRM_FORMAT_XBGR16161616F:
|
||||
return GDK_MEMORY_R16G16B16_FLOAT;
|
||||
|
||||
case DRM_FORMAT_YUYV:
|
||||
case DRM_FORMAT_YVYU:
|
||||
case DRM_FORMAT_UYVY:
|
||||
case DRM_FORMAT_VYUY:
|
||||
case DRM_FORMAT_XYUV8888:
|
||||
case DRM_FORMAT_XVUY8888:
|
||||
case DRM_FORMAT_VUY888:
|
||||
return GDK_MEMORY_R8G8B8;
|
||||
|
||||
/* Add more formats here */
|
||||
default:
|
||||
return premultiplied ? GDK_MEMORY_A8R8G8B8_PREMULTIPLIED : GDK_MEMORY_A8R8G8B8;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_LINUX_DMA_BUF_H */
|
||||
|
||||
void
|
||||
gdk_dmabuf_texture_add_supported_formats (GdkDmabufFormatsBuilder *builder)
|
||||
{
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
gsize i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (supported_formats); i++)
|
||||
{
|
||||
gdk_dmabuf_formats_builder_add_format (builder,
|
||||
supported_formats[i].fourcc,
|
||||
DRM_FORMAT_MOD_LINEAR);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
do_indirect_download (GdkDmabufTexture *self,
|
||||
GdkMemoryFormat format,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
const char *method = g_getenv ("DMABUF_DOWNLOAD_METHOD");
|
||||
|
||||
if (g_strcmp0 (method, "gl") == 0)
|
||||
do_indirect_download_gl (self, format, data, stride);
|
||||
else
|
||||
do_indirect_download_gsk (self, format, data, stride);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_dmabuf_texture_download (GdkTexture *texture,
|
||||
GdkMemoryFormat format,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
GdkDmabufTexture *self = GDK_DMABUF_TEXTURE (texture);
|
||||
GdkMemoryFormat src_format = gdk_texture_get_format (texture);
|
||||
GdkDrmFormatInfo *info;
|
||||
|
||||
info = get_drm_format_info (self->fourcc);
|
||||
|
||||
if (!info || self->n_planes > 1 || self->modifier != DRM_FORMAT_MOD_LINEAR ||
|
||||
g_getenv ("DMABUF_DOWNLOAD_METHOD") != NULL)
|
||||
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->strides[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);
|
||||
}
|
||||
#endif /* HAVE_LINUX_DMA_BUF_H */
|
||||
}
|
||||
|
||||
static gboolean
|
||||
display_supports_format (GdkDisplay *display,
|
||||
guint32 fourcc,
|
||||
guint64 modifier)
|
||||
{
|
||||
GdkDmabufFormats *formats;
|
||||
|
||||
if (!display)
|
||||
return FALSE;
|
||||
|
||||
formats = gdk_display_get_dmabuf_formats (display);
|
||||
|
||||
return gdk_dmabuf_formats_contains (formats, fourcc, modifier);
|
||||
return &self->dmabuf;
|
||||
}
|
||||
|
||||
GdkTexture *
|
||||
@@ -788,56 +131,47 @@ gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
GdkDmabufTexture *self;
|
||||
GdkTexture *update_texture;
|
||||
GdkDisplay *display = gdk_dmabuf_texture_builder_get_display (builder);
|
||||
guint32 fourcc = gdk_dmabuf_texture_builder_get_fourcc (builder);
|
||||
guint64 modifier = gdk_dmabuf_texture_builder_get_modifier (builder);
|
||||
gboolean premultiplied = gdk_dmabuf_texture_builder_get_premultiplied (builder);
|
||||
unsigned int n_planes = gdk_dmabuf_texture_builder_get_n_planes (builder);
|
||||
GdkDrmFormatInfo *info;
|
||||
gboolean can_download_directly;
|
||||
gboolean can_download_indirectly;
|
||||
GdkDisplay *display;
|
||||
const GdkDmabuf *dmabuf;
|
||||
GdkMemoryFormat format;
|
||||
GError *local_error = NULL;
|
||||
gsize i;
|
||||
|
||||
info = get_drm_format_info (fourcc);
|
||||
display = gdk_dmabuf_texture_builder_get_display (builder);
|
||||
dmabuf = gdk_dmabuf_texture_builder_get_dmabuf (builder);
|
||||
|
||||
can_download_directly = info != NULL && n_planes == 1 && modifier == DRM_FORMAT_MOD_LINEAR;
|
||||
can_download_indirectly = display_supports_format (display, fourcc, modifier);
|
||||
|
||||
if (!can_download_directly && !can_download_indirectly)
|
||||
for (i = 0; display->dmabuf_downloaders[i] != NULL; i++)
|
||||
{
|
||||
g_set_error (error, GDK_DMABUF_ERROR, GDK_DMABUF_ERROR_UNSUPPORTED_FORMAT,
|
||||
"Unsupported dmabuf format: %.4s:%#lx, planes: %u",
|
||||
(char *) &fourcc, modifier, n_planes);
|
||||
return NULL;
|
||||
if (local_error && g_error_matches (local_error, GDK_DMABUF_ERROR, GDK_DMABUF_ERROR_UNSUPPORTED_FORMAT))
|
||||
g_clear_error (&local_error);
|
||||
|
||||
if (display->dmabuf_downloaders[i]->supports (display->dmabuf_downloaders[i],
|
||||
display,
|
||||
dmabuf,
|
||||
gdk_dmabuf_texture_builder_get_premultiplied (builder),
|
||||
&format,
|
||||
local_error ? NULL : &local_error))
|
||||
break;
|
||||
}
|
||||
|
||||
GDK_DEBUG (DMABUF,
|
||||
"Create dmabuf texture (format: %.4s:%#lx, planes: %u)",
|
||||
(char *) &fourcc, modifier, n_planes);
|
||||
if (display->dmabuf_downloaders[i] == NULL)
|
||||
{
|
||||
g_propagate_error (error, local_error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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, display);
|
||||
self->downloader = display->dmabuf_downloaders[i];
|
||||
self->dmabuf = *dmabuf;
|
||||
self->destroy = destroy;
|
||||
self->data = data;
|
||||
|
||||
if (can_download_directly)
|
||||
GDK_TEXTURE (self)->format = premultiplied ? info->premultiplied_memory_format
|
||||
: info->unpremultiplied_memory_format;
|
||||
else
|
||||
GDK_TEXTURE (self)->format = compute_memory_format (fourcc, premultiplied);
|
||||
|
||||
g_set_object (&self->display, display);
|
||||
|
||||
self->fourcc = fourcc;
|
||||
self->modifier = modifier;
|
||||
self->n_planes = n_planes;
|
||||
|
||||
memcpy (self->fds, gdk_dmabuf_texture_builder_get_fds (builder), sizeof (int) * MAX_DMABUF_PLANES);
|
||||
memcpy (self->strides, gdk_dmabuf_texture_builder_get_strides (builder), sizeof (unsigned int) * MAX_DMABUF_PLANES);
|
||||
memcpy (self->offsets, gdk_dmabuf_texture_builder_get_offsets (builder), sizeof (unsigned int) * MAX_DMABUF_PLANES);
|
||||
|
||||
update_texture = gdk_dmabuf_texture_builder_get_update_texture (builder);
|
||||
if (update_texture)
|
||||
{
|
||||
@@ -862,3 +196,4 @@ gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@@ -36,16 +36,9 @@ struct _GdkDmabufTextureBuilder
|
||||
GdkDisplay *display;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
guint32 fourcc;
|
||||
guint64 modifier;
|
||||
gboolean premultiplied;
|
||||
|
||||
unsigned int n_planes;
|
||||
|
||||
/* per-plane properties */
|
||||
int fds[MAX_DMABUF_PLANES];
|
||||
unsigned int strides[MAX_DMABUF_PLANES];
|
||||
unsigned int offsets[MAX_DMABUF_PLANES];
|
||||
GdkDmabuf dmabuf;
|
||||
|
||||
GdkTexture *update_texture;
|
||||
cairo_region_t *update_region;
|
||||
@@ -162,11 +155,11 @@ gdk_dmabuf_texture_builder_get_property (GObject *object,
|
||||
break;
|
||||
|
||||
case PROP_FOURCC:
|
||||
g_value_set_uint (value, self->fourcc);
|
||||
g_value_set_uint (value, self->dmabuf.fourcc);
|
||||
break;
|
||||
|
||||
case PROP_MODIFIER:
|
||||
g_value_set_uint64 (value, self->modifier);
|
||||
g_value_set_uint64 (value, self->dmabuf.modifier);
|
||||
break;
|
||||
|
||||
case PROP_PREMULTIPLIED:
|
||||
@@ -174,7 +167,7 @@ gdk_dmabuf_texture_builder_get_property (GObject *object,
|
||||
break;
|
||||
|
||||
case PROP_N_PLANES:
|
||||
g_value_set_uint (value, self->n_planes);
|
||||
g_value_set_uint (value, self->dmabuf.n_planes);
|
||||
break;
|
||||
|
||||
case PROP_UPDATE_REGION:
|
||||
@@ -371,8 +364,9 @@ gdk_dmabuf_texture_builder_class_init (GdkDmabufTextureBuilderClass *klass)
|
||||
static void
|
||||
gdk_dmabuf_texture_builder_init (GdkDmabufTextureBuilder *self)
|
||||
{
|
||||
self->fds[0] = self->fds[1] = self->fds[2] = self->fds[3] = -1;
|
||||
self->premultiplied = TRUE;
|
||||
for (int i = 0; i < GDK_DMABUF_MAX_PLANES; i++)
|
||||
self->dmabuf.planes[i].fd = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -538,7 +532,7 @@ gdk_dmabuf_texture_builder_get_fourcc (GdkDmabufTextureBuilder *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), 0);
|
||||
|
||||
return self->fourcc;
|
||||
return self->dmabuf.fourcc;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -560,10 +554,10 @@ gdk_dmabuf_texture_builder_set_fourcc (GdkDmabufTextureBuilder *self,
|
||||
{
|
||||
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
|
||||
|
||||
if (self->fourcc == fourcc)
|
||||
if (self->dmabuf.fourcc == fourcc)
|
||||
return;
|
||||
|
||||
self->fourcc = fourcc;
|
||||
self->dmabuf.fourcc = fourcc;
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FOURCC]);
|
||||
}
|
||||
@@ -583,7 +577,7 @@ gdk_dmabuf_texture_builder_get_modifier (GdkDmabufTextureBuilder *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), 0);
|
||||
|
||||
return self->modifier;
|
||||
return self->dmabuf.modifier;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -601,10 +595,10 @@ gdk_dmabuf_texture_builder_set_modifier (GdkDmabufTextureBuilder *self,
|
||||
{
|
||||
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
|
||||
|
||||
if (self->modifier == modifier)
|
||||
if (self->dmabuf.modifier == modifier)
|
||||
return;
|
||||
|
||||
self->modifier = modifier;
|
||||
self->dmabuf.modifier = modifier;
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODIFIER]);
|
||||
}
|
||||
@@ -624,7 +618,7 @@ gdk_dmabuf_texture_builder_get_n_planes (GdkDmabufTextureBuilder *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), 0);
|
||||
|
||||
return self->n_planes;
|
||||
return self->dmabuf.n_planes;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -686,10 +680,10 @@ gdk_dmabuf_texture_builder_set_n_planes (GdkDmabufTextureBuilder *self,
|
||||
{
|
||||
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
|
||||
|
||||
if (self->n_planes == n_planes)
|
||||
if (self->dmabuf.n_planes == n_planes)
|
||||
return;
|
||||
|
||||
self->n_planes = n_planes;
|
||||
self->dmabuf.n_planes = n_planes;
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_N_PLANES]);
|
||||
}
|
||||
@@ -710,9 +704,9 @@ gdk_dmabuf_texture_builder_get_fd (GdkDmabufTextureBuilder *self,
|
||||
unsigned int plane)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), 0);
|
||||
g_return_val_if_fail (0 <= plane && plane < MAX_DMABUF_PLANES, 0);
|
||||
g_return_val_if_fail (0 <= plane && plane < GDK_DMABUF_MAX_PLANES, 0);
|
||||
|
||||
return self->fds[plane];
|
||||
return self->dmabuf.planes[plane].fd;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -731,12 +725,12 @@ gdk_dmabuf_texture_builder_set_fd (GdkDmabufTextureBuilder *self,
|
||||
int fd)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
|
||||
g_return_if_fail (0 <= plane && plane < MAX_DMABUF_PLANES);
|
||||
g_return_if_fail (0 <= plane && plane < GDK_DMABUF_MAX_PLANES);
|
||||
|
||||
if (self->fds[plane] == fd)
|
||||
if (self->dmabuf.planes[plane].fd == fd)
|
||||
return;
|
||||
|
||||
self->fds[plane] = fd;
|
||||
self->dmabuf.planes[plane].fd = fd;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -755,9 +749,9 @@ gdk_dmabuf_texture_builder_get_stride (GdkDmabufTextureBuilder *self,
|
||||
unsigned int plane)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), 0);
|
||||
g_return_val_if_fail (0 <= plane && plane < MAX_DMABUF_PLANES, 0);
|
||||
g_return_val_if_fail (0 <= plane && plane < GDK_DMABUF_MAX_PLANES, 0);
|
||||
|
||||
return self->strides[plane];
|
||||
return self->dmabuf.planes[plane].stride;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -778,12 +772,12 @@ gdk_dmabuf_texture_builder_set_stride (GdkDmabufTextureBuilder *self,
|
||||
unsigned int stride)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
|
||||
g_return_if_fail (0 <= plane && plane < MAX_DMABUF_PLANES);
|
||||
g_return_if_fail (0 <= plane && plane < GDK_DMABUF_MAX_PLANES);
|
||||
|
||||
if (self->strides[plane] == stride)
|
||||
if (self->dmabuf.planes[plane].stride == stride)
|
||||
return;
|
||||
|
||||
self->strides[plane] = stride;
|
||||
self->dmabuf.planes[plane].stride = stride;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -802,9 +796,9 @@ gdk_dmabuf_texture_builder_get_offset (GdkDmabufTextureBuilder *self,
|
||||
unsigned int plane)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), 0);
|
||||
g_return_val_if_fail (0 <= plane && plane < MAX_DMABUF_PLANES, 0);
|
||||
g_return_val_if_fail (0 <= plane && plane < GDK_DMABUF_MAX_PLANES, 0);
|
||||
|
||||
return self->offsets[plane];
|
||||
return self->dmabuf.planes[plane].offset;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -823,12 +817,12 @@ gdk_dmabuf_texture_builder_set_offset (GdkDmabufTextureBuilder *self,
|
||||
unsigned int offset)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
|
||||
g_return_if_fail (0 <= plane && plane < MAX_DMABUF_PLANES);
|
||||
g_return_if_fail (0 <= plane && plane < GDK_DMABUF_MAX_PLANES);
|
||||
|
||||
if (self->offsets[plane] == offset)
|
||||
if (self->dmabuf.planes[plane].offset == offset)
|
||||
return;
|
||||
|
||||
self->offsets[plane] = offset;
|
||||
self->dmabuf.planes[plane].offset = offset;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -970,11 +964,11 @@ gdk_dmabuf_texture_builder_build (GdkDmabufTextureBuilder *self,
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
g_return_val_if_fail (self->width > 0, NULL);
|
||||
g_return_val_if_fail (self->height > 0, NULL);
|
||||
g_return_val_if_fail (self->fourcc != 0, NULL);
|
||||
g_return_val_if_fail (self->n_planes > 0, NULL);
|
||||
g_return_val_if_fail (self->dmabuf.fourcc != 0, NULL);
|
||||
g_return_val_if_fail (self->dmabuf.n_planes > 0, NULL);
|
||||
|
||||
for (int i = 0; i < self->n_planes; i++)
|
||||
g_return_val_if_fail (self->fds[i] != -1 || self->offsets[i] != 0, NULL);
|
||||
for (int i = 0; i < self->dmabuf.n_planes; i++)
|
||||
g_return_val_if_fail (self->dmabuf.planes[i].fd != -1 || self->dmabuf.planes[i].offset != 0, NULL);
|
||||
|
||||
if (GDK_DEBUG_CHECK (DMABUF_DISABLE))
|
||||
{
|
||||
@@ -986,20 +980,8 @@ gdk_dmabuf_texture_builder_build (GdkDmabufTextureBuilder *self,
|
||||
return gdk_dmabuf_texture_new_from_builder (self, destroy, data, error);
|
||||
}
|
||||
|
||||
int *
|
||||
gdk_dmabuf_texture_builder_get_fds (GdkDmabufTextureBuilder *self)
|
||||
const GdkDmabuf *
|
||||
gdk_dmabuf_texture_builder_get_dmabuf (GdkDmabufTextureBuilder *self)
|
||||
{
|
||||
return self->fds;
|
||||
}
|
||||
|
||||
unsigned int *
|
||||
gdk_dmabuf_texture_builder_get_strides (GdkDmabufTextureBuilder *self)
|
||||
{
|
||||
return self->strides;
|
||||
}
|
||||
|
||||
unsigned int *
|
||||
gdk_dmabuf_texture_builder_get_offsets (GdkDmabufTextureBuilder *self)
|
||||
{
|
||||
return self->offsets;
|
||||
return &self->dmabuf;
|
||||
}
|
||||
|
@@ -3,33 +3,19 @@
|
||||
#include "gdkdmabuftexture.h"
|
||||
|
||||
#include "gdkdmabuftexturebuilder.h"
|
||||
#include "gdkdmabufformatsbuilderprivate.h"
|
||||
#include "gdkdmabufformatsprivate.h"
|
||||
#include "gdktextureprivate.h"
|
||||
#include "gdkdisplay.h"
|
||||
#include "gdkdmabufprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define MAX_DMABUF_PLANES 4
|
||||
|
||||
int * gdk_dmabuf_texture_builder_get_fds (GdkDmabufTextureBuilder *builder);
|
||||
unsigned int * gdk_dmabuf_texture_builder_get_offsets (GdkDmabufTextureBuilder *builder);
|
||||
unsigned int * gdk_dmabuf_texture_builder_get_strides (GdkDmabufTextureBuilder *builder);
|
||||
const GdkDmabuf * gdk_dmabuf_texture_builder_get_dmabuf (GdkDmabufTextureBuilder *builder);
|
||||
|
||||
GdkTexture * gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
|
||||
GDestroyNotify destroy,
|
||||
gpointer data,
|
||||
GError **error);
|
||||
|
||||
guint32 gdk_dmabuf_texture_get_fourcc (GdkDmabufTexture *texture);
|
||||
guint64 gdk_dmabuf_texture_get_modifier (GdkDmabufTexture *texture);
|
||||
unsigned int gdk_dmabuf_texture_get_n_planes (GdkDmabufTexture *texture);
|
||||
int * gdk_dmabuf_texture_get_fds (GdkDmabufTexture *texture);
|
||||
unsigned int * gdk_dmabuf_texture_get_offsets (GdkDmabufTexture *texture);
|
||||
unsigned int * gdk_dmabuf_texture_get_strides (GdkDmabufTexture *texture);
|
||||
|
||||
void gdk_dmabuf_texture_add_supported_formats (GdkDmabufFormatsBuilder *builder);
|
||||
|
||||
GdkDisplay * gdk_dmabuf_texture_get_display (GdkDmabufTexture *self);
|
||||
const GdkDmabuf * gdk_dmabuf_texture_get_dmabuf (GdkDmabufTexture *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@@ -83,7 +83,6 @@
|
||||
#include "gdkmemorytextureprivate.h"
|
||||
#include "gdkprofilerprivate.h"
|
||||
#include "gdkglversionprivate.h"
|
||||
#include "gdkdmabufformatsprivate.h"
|
||||
|
||||
#include "gdkprivate.h"
|
||||
|
||||
@@ -96,10 +95,6 @@
|
||||
#include <epoxy/egl.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
#include <drm/drm_fourcc.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#define DEFAULT_ALLOWED_APIS GDK_GL_API_GL | GDK_GL_API_GLES
|
||||
@@ -114,7 +109,6 @@ typedef struct {
|
||||
guint has_sync : 1;
|
||||
guint has_unpack_subimage : 1;
|
||||
guint has_debug_output : 1;
|
||||
guint has_image_storage : 1;
|
||||
guint extensions_checked : 1;
|
||||
guint debug_enabled : 1;
|
||||
guint forward_compatible : 1;
|
||||
@@ -1561,8 +1555,6 @@ gdk_gl_context_check_extensions (GdkGLContext *context)
|
||||
epoxy_has_gl_extension ("GL_ARB_sync") ||
|
||||
epoxy_has_gl_extension ("GL_APPLE_sync");
|
||||
|
||||
priv->has_image_storage = epoxy_has_gl_extension ("GL_EXT_EGL_image_storage");
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
{
|
||||
int max_texture_size;
|
||||
@@ -1950,226 +1942,3 @@ gdk_gl_backend_use (GdkGLBackend backend_type)
|
||||
|
||||
g_assert (the_gl_backend_type == backend_type);
|
||||
}
|
||||
|
||||
void
|
||||
gdk_gl_context_add_dmabuf_formats (GdkGLContext *self,
|
||||
GdkDmabufFormatsBuilder *builder)
|
||||
{
|
||||
#if defined(HAVE_EGL) && defined(HAVE_LINUX_DMA_BUF_H)
|
||||
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (self);
|
||||
GdkDisplay *display = gdk_gl_context_get_display (self);
|
||||
EGLDisplay egl_display = gdk_display_get_egl_display (display);
|
||||
|
||||
gdk_gl_context_make_current (self);
|
||||
|
||||
if (egl_display != EGL_NO_DISPLAY &&
|
||||
display->have_egl_dma_buf_import &&
|
||||
priv->has_image_storage)
|
||||
{
|
||||
int num_fourccs;
|
||||
int *fourccs;
|
||||
|
||||
eglQueryDmaBufFormatsEXT (egl_display, 0, NULL, &num_fourccs);
|
||||
fourccs = g_new (int, num_fourccs);
|
||||
eglQueryDmaBufFormatsEXT (egl_display, num_fourccs, fourccs, &num_fourccs);
|
||||
|
||||
for (int i = 0; i < num_fourccs; i++)
|
||||
{
|
||||
int num_modifiers;
|
||||
uint64_t *modifiers;
|
||||
unsigned int *external_only;
|
||||
|
||||
eglQueryDmaBufModifiersEXT (egl_display, fourccs[i], 0, NULL, NULL, &num_modifiers);
|
||||
modifiers = g_new (uint64_t, num_modifiers);
|
||||
external_only = g_new (unsigned int, num_modifiers);
|
||||
eglQueryDmaBufModifiersEXT (egl_display, fourccs[i], num_modifiers, modifiers, external_only, &num_modifiers);
|
||||
|
||||
for (int j = 0; j < num_modifiers; j++)
|
||||
{
|
||||
GDK_DEBUG (DMABUF, "%ssupported EGL dmabuf format %.4s:%#lx %s",
|
||||
external_only[j] ? "un" : "",
|
||||
(char *) &fourccs[i],
|
||||
modifiers[j],
|
||||
external_only[j] ? "EXT" : "");
|
||||
if (!external_only[j])
|
||||
gdk_dmabuf_formats_builder_add_format (builder, fourccs[i], modifiers[j]);
|
||||
}
|
||||
|
||||
g_free (modifiers);
|
||||
}
|
||||
|
||||
g_free (fourccs);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
guint
|
||||
gdk_gl_context_import_dmabuf (GdkGLContext *self,
|
||||
int width,
|
||||
int height,
|
||||
unsigned int fourcc,
|
||||
guint64 modifier,
|
||||
unsigned int n_planes,
|
||||
int *fds,
|
||||
unsigned int *strides,
|
||||
unsigned int *offsets)
|
||||
{
|
||||
#if defined(HAVE_EGL) && defined(HAVE_LINUX_DMA_BUF_H)
|
||||
GdkDisplay *display = gdk_gl_context_get_display (self);
|
||||
EGLDisplay egl_display = gdk_display_get_egl_display (display);
|
||||
EGLint attribs[64];
|
||||
int i;
|
||||
EGLImage image;
|
||||
guint texture_id;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_GL_CONTEXT (self), 0);
|
||||
g_return_val_if_fail (width > 0, 0);
|
||||
g_return_val_if_fail (height > 0, 0);
|
||||
g_return_val_if_fail (1 <= n_planes && n_planes <= 4, 0);
|
||||
g_return_val_if_fail (fds != NULL, 0);
|
||||
g_return_val_if_fail (strides != NULL, 0);
|
||||
g_return_val_if_fail (offsets != NULL, 0);
|
||||
|
||||
if (egl_display == EGL_NO_DISPLAY || !display->have_egl_dma_buf_import)
|
||||
return 0;
|
||||
|
||||
GDK_DEBUG (DMABUF,
|
||||
"Importing dmabuf (format: %.4s:%#lx, planes: %u) into GL",
|
||||
(char *) &fourcc, modifier, n_planes);
|
||||
|
||||
i = 0;
|
||||
attribs[i++] = EGL_WIDTH;
|
||||
attribs[i++] = width;
|
||||
attribs[i++] = EGL_HEIGHT;
|
||||
attribs[i++] = height;
|
||||
attribs[i++] = EGL_LINUX_DRM_FOURCC_EXT;
|
||||
attribs[i++] = fourcc;
|
||||
|
||||
#define ADD_PLANE(plane) \
|
||||
{ \
|
||||
if (modifier != DRM_FORMAT_MOD_INVALID) \
|
||||
{ \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE## plane ##_MODIFIER_LO_EXT; \
|
||||
attribs[i++] = modifier & 0xFFFFFFFF; \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE## plane ## _MODIFIER_HI_EXT; \
|
||||
attribs[i++] = modifier >> 32; \
|
||||
} \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE## plane ##_FD_EXT; \
|
||||
attribs[i++] = fds[plane]; \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE## plane ##_PITCH_EXT; \
|
||||
attribs[i++] = strides[plane]; \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE## plane ##_OFFSET_EXT; \
|
||||
attribs[i++] = offsets[plane]; \
|
||||
}
|
||||
|
||||
ADD_PLANE (0);
|
||||
|
||||
if (n_planes > 1) ADD_PLANE (1);
|
||||
if (n_planes > 2) ADD_PLANE (2);
|
||||
if (n_planes > 3) ADD_PLANE (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 ("Creating EGLImage for dmabuf failed: %#x", eglGetError ());
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_gl_context_export_dmabuf (GdkGLContext *self,
|
||||
unsigned int texture_id,
|
||||
int *fourcc,
|
||||
int *n_planes,
|
||||
guint64 *modifier,
|
||||
int *fds,
|
||||
int *strides,
|
||||
int *offsets)
|
||||
{
|
||||
#if defined(HAVE_EGL) && defined(HAVE_LINUX_DMA_BUF_H)
|
||||
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (self);
|
||||
GdkDisplay *display = gdk_gl_context_get_display (self);
|
||||
EGLDisplay egl_display = gdk_display_get_egl_display (display);
|
||||
EGLContext egl_context = priv->egl_context;
|
||||
EGLint attribs[10];
|
||||
int i;
|
||||
EGLImage image;
|
||||
gboolean result = FALSE;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_GL_CONTEXT (self), FALSE);
|
||||
g_return_val_if_fail (texture_id > 0, FALSE);
|
||||
g_return_val_if_fail (fourcc != NULL, FALSE);
|
||||
g_return_val_if_fail (n_planes != NULL, FALSE);
|
||||
g_return_val_if_fail (modifier != NULL, FALSE);
|
||||
g_return_val_if_fail (fds != NULL, FALSE);
|
||||
g_return_val_if_fail (strides != NULL, FALSE);
|
||||
g_return_val_if_fail (offsets != NULL, FALSE);
|
||||
|
||||
if (egl_display == EGL_NO_DISPLAY || !display->have_egl_dma_buf_export)
|
||||
return 0;
|
||||
|
||||
GDK_DEBUG (DMABUF, "Exporting GL texture to dmabuf");
|
||||
|
||||
i = 0;
|
||||
attribs[i++] = EGL_IMAGE_PRESERVED_KHR;
|
||||
attribs[i++] = EGL_TRUE;
|
||||
|
||||
attribs[i++] = EGL_NONE;
|
||||
|
||||
image = eglCreateImageKHR (egl_display,
|
||||
egl_context,
|
||||
EGL_GL_TEXTURE_2D_KHR,
|
||||
(EGLClientBuffer)GUINT_TO_POINTER (texture_id),
|
||||
attribs);
|
||||
|
||||
if (image == EGL_NO_IMAGE)
|
||||
return FALSE;
|
||||
|
||||
if (!eglExportDMABUFImageQueryMESA (egl_display,
|
||||
image,
|
||||
fourcc,
|
||||
n_planes,
|
||||
modifier))
|
||||
goto out;
|
||||
|
||||
if (!eglExportDMABUFImageMESA (egl_display,
|
||||
image,
|
||||
fds,
|
||||
strides,
|
||||
offsets))
|
||||
goto out;
|
||||
|
||||
GDK_DEBUG (DMABUF,
|
||||
"Exported GL texture to dmabuf (format: %.4s:%#lx, planes: %d)",
|
||||
(char *)fourcc, *modifier, *n_planes);
|
||||
|
||||
result = TRUE;
|
||||
|
||||
out:
|
||||
eglDestroyImageKHR (egl_display, image);
|
||||
|
||||
return result;
|
||||
#else
|
||||
return FALSE:
|
||||
#endif
|
||||
}
|
||||
|
@@ -23,7 +23,6 @@
|
||||
#include "gdkglcontext.h"
|
||||
#include "gdkdrawcontextprivate.h"
|
||||
#include "gdkglversionprivate.h"
|
||||
#include "gdkdmabufformatsbuilderprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@@ -160,28 +159,5 @@ gboolean gdk_gl_context_has_sync (GdkGLContext
|
||||
|
||||
double gdk_gl_context_get_scale (GdkGLContext *self);
|
||||
|
||||
void gdk_gl_context_add_dmabuf_formats (GdkGLContext *self,
|
||||
GdkDmabufFormatsBuilder *builder);
|
||||
|
||||
guint gdk_gl_context_import_dmabuf (GdkGLContext *self,
|
||||
int width,
|
||||
int height,
|
||||
unsigned int fourcc,
|
||||
guint64 modifier,
|
||||
unsigned int n_planes,
|
||||
int *fds,
|
||||
unsigned int *strides,
|
||||
unsigned int *offsets);
|
||||
|
||||
gboolean gdk_gl_context_export_dmabuf (GdkGLContext *self,
|
||||
unsigned int texture_id,
|
||||
int *fourcc,
|
||||
int *n_planes,
|
||||
guint64 *modifier,
|
||||
int *fds,
|
||||
int *strides,
|
||||
int *offsets);
|
||||
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@@ -17,6 +17,7 @@ gdk_public_sources = files([
|
||||
'gdkdevicetool.c',
|
||||
'gdkdisplay.c',
|
||||
'gdkdisplaymanager.c',
|
||||
'gdkdmabuf.c',
|
||||
'gdkdmabufformats.c',
|
||||
'gdkdmabufformatsbuilder.c',
|
||||
'gdkdmabuftexture.c',
|
||||
|
@@ -44,8 +44,6 @@
|
||||
#include <gdk/gdktextureprivate.h>
|
||||
|
||||
#include <gdk/gdkmemoryformatprivate.h>
|
||||
#include <gdk/gdkdmabuftextureprivate.h>
|
||||
|
||||
|
||||
G_DEFINE_TYPE (GskGLDriver, gsk_gl_driver, G_TYPE_OBJECT)
|
||||
|
||||
@@ -760,19 +758,7 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
|
||||
return t->texture_id;
|
||||
}
|
||||
|
||||
if (GDK_IS_DMABUF_TEXTURE (texture))
|
||||
{
|
||||
texture_id = gdk_gl_context_import_dmabuf (context,
|
||||
gdk_texture_get_width (texture),
|
||||
gdk_texture_get_height (texture),
|
||||
gdk_dmabuf_texture_get_fourcc (GDK_DMABUF_TEXTURE (texture)),
|
||||
gdk_dmabuf_texture_get_modifier (GDK_DMABUF_TEXTURE (texture)),
|
||||
gdk_dmabuf_texture_get_n_planes (GDK_DMABUF_TEXTURE (texture)),
|
||||
gdk_dmabuf_texture_get_fds (GDK_DMABUF_TEXTURE (texture)),
|
||||
gdk_dmabuf_texture_get_strides (GDK_DMABUF_TEXTURE (texture)),
|
||||
gdk_dmabuf_texture_get_offsets (GDK_DMABUF_TEXTURE (texture)));
|
||||
}
|
||||
else if (GDK_IS_GL_TEXTURE (texture))
|
||||
if (GDK_IS_GL_TEXTURE (texture))
|
||||
{
|
||||
GdkGLTexture *gl_texture = (GdkGLTexture *) texture;
|
||||
GdkGLContext *texture_context = gdk_gl_texture_get_context (gl_texture);
|
||||
|
@@ -30,7 +30,6 @@
|
||||
#include <gsk/gskglshaderprivate.h>
|
||||
#include <gdk/gdktextureprivate.h>
|
||||
#include <gdk/gdkmemorytextureprivate.h>
|
||||
#include <gdk/gdkdmabuftexture.h>
|
||||
#include <gsk/gsktransformprivate.h>
|
||||
#include <gsk/gskroundedrectprivate.h>
|
||||
#include <gsk/gskrectprivate.h>
|
||||
@@ -48,7 +47,6 @@
|
||||
#include "ninesliceprivate.h"
|
||||
#include "fp16private.h"
|
||||
|
||||
|
||||
#define ORTHO_NEAR_PLANE -10000
|
||||
#define ORTHO_FAR_PLANE 10000
|
||||
#define MAX_GRADIENT_STOPS 6
|
||||
@@ -3632,12 +3630,16 @@ gsk_gl_render_job_upload_texture (GskGLRenderJob *job,
|
||||
gboolean ensure_mipmap,
|
||||
GskGLRenderOffscreen *offscreen)
|
||||
{
|
||||
/* Don't put GL or dma-buf textures into icon caches, they are already on the GPU side */
|
||||
GdkGLTexture *gl_texture = NULL;
|
||||
|
||||
if (GDK_IS_GL_TEXTURE (texture))
|
||||
gl_texture = GDK_GL_TEXTURE (texture);
|
||||
|
||||
if (!ensure_mipmap &&
|
||||
gsk_gl_texture_library_can_cache ((GskGLTextureLibrary *)job->driver->icons_library,
|
||||
texture->width,
|
||||
texture->height) &&
|
||||
!(GDK_IS_GL_TEXTURE (texture) || GDK_IS_DMABUF_TEXTURE (texture)))
|
||||
!gl_texture)
|
||||
{
|
||||
const GskGLIconData *icon_data;
|
||||
|
||||
@@ -3651,18 +3653,16 @@ gsk_gl_render_job_upload_texture (GskGLRenderJob *job,
|
||||
/* Only generate a mipmap if it does not make use reupload
|
||||
* a GL texture which we could otherwise use directly.
|
||||
*/
|
||||
if (GDK_IS_GL_TEXTURE (texture) &&
|
||||
gdk_gl_context_is_shared (gdk_gl_texture_get_context (GDK_GL_TEXTURE (texture)),
|
||||
job->command_queue->context))
|
||||
ensure_mipmap = gdk_gl_texture_has_mipmap (GDK_GL_TEXTURE (texture));
|
||||
if (gl_texture &&
|
||||
gdk_gl_context_is_shared (gdk_gl_texture_get_context (gl_texture), job->command_queue->context))
|
||||
ensure_mipmap = gdk_gl_texture_has_mipmap (gl_texture);
|
||||
|
||||
offscreen->texture_id = gsk_gl_driver_load_texture (job->driver, texture, ensure_mipmap);
|
||||
init_full_texture_region (offscreen);
|
||||
offscreen->has_mipmap = ensure_mipmap;
|
||||
|
||||
if (GDK_IS_GL_TEXTURE (texture) &&
|
||||
offscreen->texture_id == gdk_gl_texture_get_id (GDK_GL_TEXTURE (texture)))
|
||||
offscreen->sync = gdk_gl_texture_get_sync (GDK_GL_TEXTURE (texture));
|
||||
if (gl_texture && offscreen->texture_id == gdk_gl_texture_get_id (gl_texture))
|
||||
offscreen->sync = gdk_gl_texture_get_sync (gl_texture);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,5 @@
|
||||
gtk_tests = [
|
||||
# testname, optional extra sources
|
||||
['testdmabuf'],
|
||||
['testsections'],
|
||||
['testfilelauncher'],
|
||||
['input'],
|
||||
|
@@ -1,442 +0,0 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/dma-heap.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
|
||||
/* For this to work, you may need to give /dev/dma_heap/system
|
||||
* lax permissions.
|
||||
*/
|
||||
|
||||
static int
|
||||
allocate_dma_buf (gsize size)
|
||||
{
|
||||
static int fd = -1;
|
||||
struct dma_heap_allocation_data heap_data;
|
||||
int ret;
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
fd = open ("/dev/dma_heap/system", O_RDONLY | O_CLOEXEC);
|
||||
if (fd == -1)
|
||||
g_error ("Failed to open /dev/dma_heap/system");
|
||||
}
|
||||
|
||||
heap_data.len = size;
|
||||
heap_data.fd = 0;
|
||||
heap_data.fd_flags = O_RDWR | O_CLOEXEC;
|
||||
heap_data.heap_flags = 0;
|
||||
|
||||
ret = ioctl (fd, DMA_HEAP_IOCTL_ALLOC, &heap_data);
|
||||
if (ret)
|
||||
g_error ("dma-buf allocation failed");
|
||||
|
||||
return heap_data.fd;
|
||||
}
|
||||
|
||||
static void
|
||||
populate_dma_buf (int fd,
|
||||
guchar *data,
|
||||
gsize size)
|
||||
{
|
||||
guchar *buf;
|
||||
|
||||
buf = mmap (NULL, size, PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
memcpy (buf, data, size);
|
||||
munmap (buf, size);
|
||||
}
|
||||
|
||||
|
||||
/* The YUV conversion code is adapted from weston/tests/yuv-buffer-test.c */
|
||||
|
||||
/*
|
||||
* Based on Rec. ITU-R BT.601-7
|
||||
*
|
||||
* This is intended to be obvious and accurate, not fast.
|
||||
*/
|
||||
static void
|
||||
x8r8g8b8_to_ycbcr8_bt601 (guint32 xrgb,
|
||||
guchar *y_out,
|
||||
guchar *cb_out,
|
||||
guchar *cr_out)
|
||||
{
|
||||
double y, cb, cr;
|
||||
double r = (xrgb >> 16) & 0xff;
|
||||
double g = (xrgb >> 8) & 0xff;
|
||||
double b = (xrgb >> 0) & 0xff;
|
||||
|
||||
/* normalize to [0.0, 1.0] */
|
||||
r /= 255.0;
|
||||
g /= 255.0;
|
||||
b /= 255.0;
|
||||
|
||||
/* Y normalized to [0.0, 1.0], Cb and Cr [-0.5, 0.5] */
|
||||
y = 0.299 * r + 0.587 * g + 0.114 * b;
|
||||
cr = (r - y) / 1.402;
|
||||
cb = (b - y) / 1.772;
|
||||
|
||||
/* limited range quantization to 8 bit */
|
||||
*y_out = round(219.0 * y + 16.0);
|
||||
if (cr_out)
|
||||
*cr_out = round(224.0 * cr + 128.0);
|
||||
if (cb_out)
|
||||
*cb_out = round(224.0 * cb + 128.0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 3 plane YCbCr
|
||||
* plane 0: Y plane, [7:0] Y
|
||||
* plane 1: Cb plane, [7:0] Cb
|
||||
* plane 2: Cr plane, [7:0] Cr
|
||||
* YUV420: 2x2 subsampled Cb (1) and Cr (2) planes
|
||||
* YUV444: no subsampling
|
||||
*/
|
||||
static guchar *
|
||||
y_u_v_create_buffer (uint32_t drm_format,
|
||||
guchar *rgb_data,
|
||||
int rgb_width,
|
||||
int rgb_height,
|
||||
int *size,
|
||||
int *u_offset,
|
||||
int *v_offset)
|
||||
{
|
||||
gsize bytes;
|
||||
int x, y;
|
||||
guint32 *rgb_row;
|
||||
guchar *y_base;
|
||||
guchar *u_base;
|
||||
guchar *v_base;
|
||||
guchar *y_row;
|
||||
guchar *u_row;
|
||||
guchar *v_row;
|
||||
guint32 argb;
|
||||
int sub = (drm_format == DRM_FORMAT_YUV420) ? 2 : 1;
|
||||
guchar *buf;
|
||||
|
||||
g_assert (drm_format == DRM_FORMAT_YUV420 ||
|
||||
drm_format == DRM_FORMAT_YUV444);
|
||||
|
||||
/* Full size Y plus quarter U and V */
|
||||
bytes = rgb_width * rgb_height +
|
||||
(rgb_width / sub) * (rgb_height / sub) * 2;
|
||||
|
||||
buf = g_new (guchar, bytes);
|
||||
|
||||
*size = bytes;
|
||||
*u_offset = rgb_width * rgb_height;
|
||||
*v_offset = *u_offset + (rgb_width / sub) * (rgb_height / sub);
|
||||
|
||||
y_base = buf;
|
||||
u_base = y_base + rgb_width * rgb_height;
|
||||
v_base = u_base + (rgb_width / sub) * (rgb_height / sub);
|
||||
|
||||
for (y = 0; y < rgb_height; y++)
|
||||
{
|
||||
rgb_row = (guint32 *) (rgb_data + y * 4 * rgb_width);
|
||||
y_row = y_base + y * rgb_width;
|
||||
u_row = u_base + (y / sub) * (rgb_width / sub);
|
||||
v_row = v_base + (y / sub) * (rgb_width / sub);
|
||||
|
||||
for (x = 0; x < rgb_width; x++)
|
||||
{
|
||||
/*
|
||||
* Sub-sample the source image instead, so that U and V
|
||||
* sub-sampling does not require proper
|
||||
* filtering/averaging/siting.
|
||||
*/
|
||||
argb = *(rgb_row + x / 2 * 2);
|
||||
|
||||
/*
|
||||
* A stupid way of "sub-sampling" chroma. This does not
|
||||
* do the necessary filtering/averaging/siting or
|
||||
* alternate Cb/Cr rows.
|
||||
*/
|
||||
if ((y & (sub - 1)) == 0 && (x & (sub - 1)) == 0)
|
||||
x8r8g8b8_to_ycbcr8_bt601 (argb, y_row + x, u_row + x / sub, v_row + x / sub);
|
||||
else
|
||||
x8r8g8b8_to_ycbcr8_bt601 (argb, y_row + x, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* 2 plane YCbCr
|
||||
* plane 0 = Y plane, [7:0] Y
|
||||
* plane 1 = Cr:Cb plane, [15:0] Cr:Cb little endian
|
||||
* 2x2 subsampled Cr:Cb plane
|
||||
*/
|
||||
static guchar *
|
||||
nv12_create_buffer (uint32_t drm_format,
|
||||
guchar *rgb_data,
|
||||
int rgb_width,
|
||||
int rgb_height,
|
||||
int *size,
|
||||
int *uv_offset)
|
||||
{
|
||||
size_t bytes;
|
||||
int x, y;
|
||||
uint32_t *rgb_row;
|
||||
uint8_t *y_base;
|
||||
uint16_t *uv_base;
|
||||
uint8_t *y_row;
|
||||
uint16_t *uv_row;
|
||||
uint32_t argb;
|
||||
uint8_t cr;
|
||||
uint8_t cb;
|
||||
guchar *buf;
|
||||
|
||||
g_assert (drm_format == DRM_FORMAT_NV12);
|
||||
|
||||
/* Full size Y, quarter UV */
|
||||
bytes = rgb_width * rgb_height +
|
||||
(rgb_width / 2) * (rgb_height / 2) * sizeof (uint16_t);
|
||||
|
||||
buf = g_new0 (guchar, bytes);
|
||||
|
||||
*uv_offset = rgb_width * rgb_height;
|
||||
y_base = buf;
|
||||
uv_base = (uint16_t *)(y_base + rgb_width * rgb_height);
|
||||
|
||||
for (y = 0; y < rgb_height; y++)
|
||||
{
|
||||
rgb_row = (uint32_t *) (rgb_data + y * 4 * rgb_width);
|
||||
y_row = y_base + y * rgb_width;
|
||||
uv_row = (uint16_t *) (uv_base + (y / 2) * (rgb_width / 2));
|
||||
|
||||
for (x = 0; x < rgb_width; x++)
|
||||
{
|
||||
/*
|
||||
* Sub-sample the source image instead, so that U and V
|
||||
* sub-sampling does not require proper
|
||||
* filtering/averaging/siting.
|
||||
*/
|
||||
argb = *(rgb_row + x / 2 * 2);
|
||||
|
||||
/*
|
||||
* A stupid way of "sub-sampling" chroma. This does not
|
||||
* do the necessary filtering/averaging/siting.
|
||||
*/
|
||||
if ((y & 1) == 0 && (x & 1) == 0)
|
||||
{
|
||||
x8r8g8b8_to_ycbcr8_bt601(argb, y_row + x, &cb, &cr);
|
||||
*(uv_row + x / 2) = ((uint16_t)cr << 8) | cb;
|
||||
}
|
||||
else
|
||||
{
|
||||
x8r8g8b8_to_ycbcr8_bt601(argb, y_row + x, NULL, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static GdkTexture *
|
||||
make_dmabuf_texture (const char *filename,
|
||||
guint32 format)
|
||||
{
|
||||
GdkTexture *texture;
|
||||
int width, height;
|
||||
gsize rgb_stride, rgb_size;
|
||||
guchar *rgb_data;
|
||||
int fd;
|
||||
GdkDmabufTextureBuilder *builder;
|
||||
GError *error = NULL;
|
||||
|
||||
texture = gdk_texture_new_from_filename (filename, NULL);
|
||||
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
rgb_stride = 4 * width;
|
||||
rgb_size = rgb_stride * height;
|
||||
|
||||
rgb_data = g_new0 (guchar, rgb_size);
|
||||
|
||||
gdk_texture_download (texture, rgb_data, rgb_stride);
|
||||
|
||||
g_object_unref (texture);
|
||||
|
||||
builder = gdk_dmabuf_texture_builder_new ();
|
||||
|
||||
gdk_dmabuf_texture_builder_set_display (builder, gdk_display_get_default ());
|
||||
gdk_dmabuf_texture_builder_set_width (builder, width);
|
||||
gdk_dmabuf_texture_builder_set_height (builder, height);
|
||||
gdk_dmabuf_texture_builder_set_fourcc (builder, format);
|
||||
gdk_dmabuf_texture_builder_set_modifier (builder, DRM_FORMAT_MOD_LINEAR);
|
||||
|
||||
if (format == DRM_FORMAT_XRGB8888)
|
||||
{
|
||||
gdk_dmabuf_texture_builder_set_n_planes (builder, 1);
|
||||
|
||||
fd = allocate_dma_buf (rgb_size);
|
||||
populate_dma_buf (fd, rgb_data, rgb_size);
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 0, fd);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 0, rgb_stride);
|
||||
}
|
||||
else if (format == DRM_FORMAT_YUV420)
|
||||
{
|
||||
guchar *buf;
|
||||
int size, u_offset, v_offset;
|
||||
|
||||
gdk_dmabuf_texture_builder_set_n_planes (builder, 3);
|
||||
|
||||
buf = y_u_v_create_buffer (format, rgb_data, width, height, &size, &u_offset, &v_offset);
|
||||
|
||||
fd = allocate_dma_buf (width * height);
|
||||
populate_dma_buf (fd, buf, width * height);
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 0, fd);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 0, width);
|
||||
gdk_dmabuf_texture_builder_set_offset (builder, 0, 0);
|
||||
|
||||
fd = allocate_dma_buf ((width / 2) * (height / 2));
|
||||
populate_dma_buf (fd, buf + u_offset, (width / 2) * (height / 2));
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 1, fd);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 1, width / 2);
|
||||
gdk_dmabuf_texture_builder_set_offset (builder, 1, 0);
|
||||
|
||||
fd = allocate_dma_buf ((width / 2) * (height / 2));
|
||||
populate_dma_buf (fd, buf + v_offset, (width / 2) * (height / 2));
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 2, fd);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 2, width / 2);
|
||||
gdk_dmabuf_texture_builder_set_offset (builder, 2, 0);
|
||||
|
||||
g_free (buf);
|
||||
}
|
||||
else if (format == DRM_FORMAT_NV12)
|
||||
{
|
||||
guchar *buf;
|
||||
int size, uv_offset;
|
||||
|
||||
gdk_dmabuf_texture_builder_set_n_planes (builder, 2);
|
||||
|
||||
buf = nv12_create_buffer (format, rgb_data, width, height, &size, &uv_offset);
|
||||
|
||||
fd = allocate_dma_buf (width * height);
|
||||
populate_dma_buf (fd, buf, width * height);
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 0, fd);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 0, width);
|
||||
gdk_dmabuf_texture_builder_set_offset (builder, 0, 0);
|
||||
|
||||
fd = allocate_dma_buf ((width / 2) * (height / 2) * sizeof (uint16_t));
|
||||
populate_dma_buf (fd, buf + uv_offset, (width / 2) * (height / 2) * sizeof (uint16_t));
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 1, fd);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 1, width);
|
||||
gdk_dmabuf_texture_builder_set_offset (builder, 1, 0);
|
||||
|
||||
g_free (buf);
|
||||
}
|
||||
|
||||
g_free (rgb_data);
|
||||
|
||||
texture = gdk_dmabuf_texture_builder_build (builder, NULL, NULL, &error);
|
||||
if (!texture)
|
||||
g_error ("Failed to create dmabuf texture: %s", error->message);
|
||||
|
||||
g_object_unref (builder);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
static guint32 supported_formats[] = {
|
||||
DRM_FORMAT_XRGB8888,
|
||||
DRM_FORMAT_YUV420,
|
||||
DRM_FORMAT_NV12,
|
||||
};
|
||||
|
||||
static gboolean
|
||||
format_is_supported (guint32 fmt)
|
||||
{
|
||||
for (int i = 0; i < G_N_ELEMENTS (supported_formats); i++)
|
||||
{
|
||||
if (supported_formats[i] == fmt)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static char *
|
||||
supported_formats_to_string (void)
|
||||
{
|
||||
GString *s;
|
||||
|
||||
s = g_string_new ("");
|
||||
for (int i = 0; i < G_N_ELEMENTS (supported_formats); i++)
|
||||
{
|
||||
if (s->len)
|
||||
g_string_append (s, ", ");
|
||||
g_string_append_printf (s, "%.4s", (char *)&supported_formats[i]);
|
||||
}
|
||||
|
||||
return g_string_free (s, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
usage (void)
|
||||
{
|
||||
char *formats = supported_formats_to_string ();
|
||||
g_print ("Usage: testdmabuf FORMAT FILE\n"
|
||||
"Supported formats: %s\n", formats);
|
||||
g_free (formats);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
static guint32
|
||||
parse_format (const char *a)
|
||||
{
|
||||
if (strlen (a) == 4)
|
||||
{
|
||||
guint32 format = fourcc_code (a[0], a[1], a[2], a[3]);
|
||||
if (format_is_supported (format))
|
||||
return format;
|
||||
}
|
||||
|
||||
usage ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
GdkTexture *texture;
|
||||
GtkWidget *window, *picture;
|
||||
char *filename;
|
||||
guint32 format;
|
||||
|
||||
if (argc != 3)
|
||||
g_assert (argc == 3);
|
||||
|
||||
format = parse_format (argv[1]);
|
||||
filename = argv[2];
|
||||
|
||||
gtk_init ();
|
||||
|
||||
/* Get the list of supported formats with GDK_DEBUG=opengl */
|
||||
gdk_display_get_dmabuf_formats (gdk_display_get_default ());
|
||||
|
||||
texture = make_dmabuf_texture (filename, format);
|
||||
|
||||
gdk_texture_save_to_png (texture, "testdmabuf.out.png");
|
||||
|
||||
window = gtk_window_new ();
|
||||
|
||||
picture = gtk_picture_new_for_paintable (GDK_PAINTABLE (texture));
|
||||
|
||||
gtk_window_set_child (GTK_WINDOW (window), picture);
|
||||
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
|
||||
while (g_list_model_get_n_items (gtk_window_get_toplevels ()) > 0)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user