Compare commits
57 Commits
dmabuf-deb
...
subsurface
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a77fde155d | ||
|
|
004c2b8cc2 | ||
|
|
0605888ac6 | ||
|
|
ef5b1ba044 | ||
|
|
5fa7457171 | ||
|
|
f50edb6910 | ||
|
|
2d874e601c | ||
|
|
c9b83dfa1d | ||
|
|
dd7a38069f | ||
|
|
51a181af7a | ||
|
|
8fcd9bc0c4 | ||
|
|
e2edf693f5 | ||
|
|
323300e92a | ||
|
|
e688be1cff | ||
|
|
611d5cf844 | ||
|
|
51cb1aeb4e | ||
|
|
625eb508e8 | ||
|
|
2718e1715d | ||
|
|
6ddcad6b33 | ||
|
|
0c23997f70 | ||
|
|
4d1ef63009 | ||
|
|
30e14f73fa | ||
|
|
39e205aa78 | ||
|
|
f0ec1660c1 | ||
|
|
79f98f3a13 | ||
|
|
5f0557027d | ||
|
|
a579e3bc6d | ||
|
|
8f70f4b85e | ||
|
|
911198cddd | ||
|
|
ca5247a995 | ||
|
|
004a881521 | ||
|
|
65993ed0e0 | ||
|
|
a4d0a5bda5 | ||
|
|
33bc276639 | ||
|
|
06822581f7 | ||
|
|
976143fbe9 | ||
|
|
9fd4feef0c | ||
|
|
5eed13bd07 | ||
|
|
d02d45dd8d | ||
|
|
13d0e311b7 | ||
|
|
52254f755f | ||
|
|
494154beb6 | ||
|
|
adde188eca | ||
|
|
8fb0ab2b43 | ||
|
|
b8b5835fc6 | ||
|
|
463307655c | ||
|
|
d17d8e04a6 | ||
|
|
d8d1dfd8f3 | ||
|
|
f581280811 | ||
|
|
3a9aea44df | ||
|
|
e05764806a | ||
|
|
5ca65f04fe | ||
|
|
32ba1e389c | ||
|
|
beb9e0c906 | ||
|
|
98f02f6221 | ||
|
|
13848969f4 | ||
|
|
0817dfe67f |
30
NEWS
30
NEWS
@@ -1,6 +1,34 @@
|
||||
Overview of Changes in 4.13.2, xx-xx-xxxx
|
||||
Overview of Changes in 4.13.3, xx-xx-xxxx
|
||||
=========================================
|
||||
|
||||
Overview of Changes in 4.13.2, 22-10-2023
|
||||
=========================================
|
||||
|
||||
* GtkPrintdialog:
|
||||
- New async-style api to replace GtkPrintOperation
|
||||
|
||||
* GtkEmojiChooser:
|
||||
- Add more languages: Bengali, Hindi, Japanese, Finnish,
|
||||
Thai and Norwegian bokmål
|
||||
|
||||
* Accessibility:
|
||||
- Fix some utf8 handling issues
|
||||
|
||||
* GDK:
|
||||
- Add support for dmabuf textures, with GdkDmabufTextureBuilder
|
||||
- Add a few more supported memory formats for textures
|
||||
|
||||
* GSK:
|
||||
- Add a fast-path for masking color
|
||||
- Add support for importing dmabuf textures
|
||||
- Handle GLES better by using some extensions
|
||||
|
||||
* Translation updates:
|
||||
Catalan
|
||||
Russian
|
||||
Turkish
|
||||
|
||||
|
||||
Overview of Changes in 4.13.1, 28-09-2023
|
||||
=========================================
|
||||
|
||||
|
||||
@@ -391,6 +391,9 @@ gdk_display_dispose (GObject *object)
|
||||
|
||||
g_queue_clear (&display->queued_events);
|
||||
|
||||
g_clear_object (&display->egl_gsk_renderer);
|
||||
g_clear_pointer (&display->egl_external_formats, gdk_dmabuf_formats_unref);
|
||||
|
||||
g_clear_object (&priv->gl_context);
|
||||
#ifdef HAVE_EGL
|
||||
g_clear_pointer (&priv->egl_display, eglTerminate);
|
||||
@@ -1770,6 +1773,10 @@ 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,
|
||||
@@ -1839,7 +1846,7 @@ gdk_display_get_egl_display (GdkDisplay *self)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
#ifdef HAVE_DMABUF
|
||||
static void
|
||||
gdk_display_add_dmabuf_downloader (GdkDisplay *display,
|
||||
const GdkDmabufDownloader *downloader,
|
||||
@@ -1847,7 +1854,8 @@ gdk_display_add_dmabuf_downloader (GdkDisplay *display,
|
||||
{
|
||||
gsize i;
|
||||
|
||||
downloader->add_formats (downloader, display, builder);
|
||||
if (!downloader->add_formats (downloader, display, builder))
|
||||
return;
|
||||
|
||||
/* dmabuf_downloaders is NULL-terminated */
|
||||
for (i = 0; i < G_N_ELEMENTS (display->dmabuf_downloaders) - 1; i++)
|
||||
@@ -1874,19 +1882,31 @@ gdk_display_init_dmabuf (GdkDisplay *self)
|
||||
if (self->dmabuf_formats != NULL)
|
||||
return;
|
||||
|
||||
GDK_DISPLAY_DEBUG (self, DMABUF,
|
||||
"Beginning initialization of dmabuf support");
|
||||
|
||||
builder = gdk_dmabuf_formats_builder_new ();
|
||||
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
#ifdef HAVE_DMABUF
|
||||
if (!GDK_DEBUG_CHECK (DMABUF_DISABLE))
|
||||
{
|
||||
gdk_display_prepare_gl (self, NULL);
|
||||
|
||||
gdk_display_add_dmabuf_downloader (self, gdk_dmabuf_get_direct_downloader (), builder);
|
||||
|
||||
#ifdef HAVE_EGL
|
||||
if (gdk_display_prepare_gl (self, NULL))
|
||||
gdk_display_add_dmabuf_downloader (self, gdk_dmabuf_get_egl_downloader (), builder);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
self->dmabuf_formats = gdk_dmabuf_formats_builder_free_to_formats (builder);
|
||||
}
|
||||
|
||||
GDK_DISPLAY_DEBUG (self, DMABUF,
|
||||
"Initialized support for %zu dmabuf formats",
|
||||
gdk_dmabuf_formats_get_n_formats (self->dmabuf_formats));
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_display_get_dmabuf_formats:
|
||||
@@ -1897,6 +1917,9 @@ gdk_display_init_dmabuf (GdkDisplay *self)
|
||||
* GTK may use OpenGL or Vulkan to support some formats.
|
||||
* Calling this function will then initialize them if they aren't yet.
|
||||
*
|
||||
* The formats returned by this function can be used for negotiating
|
||||
* buffer formats with producers such as v4l, pipewire or GStreamer.
|
||||
*
|
||||
* Returns: (transfer none): a `GdkDmabufFormats` object
|
||||
*
|
||||
* Since: 4.14
|
||||
|
||||
@@ -114,9 +114,15 @@ 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];
|
||||
|
||||
/* Cached data the EGL dmabuf downloader */
|
||||
gpointer egl_gsk_renderer;
|
||||
GdkDmabufFormats *egl_external_formats;
|
||||
};
|
||||
|
||||
struct _GdkDisplayClass
|
||||
|
||||
373
gdk/gdkdmabuf.c
373
gdk/gdkdmabuf.c
@@ -24,11 +24,11 @@
|
||||
#include "gdkdmabuftextureprivate.h"
|
||||
#include "gdkmemoryformatprivate.h"
|
||||
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
#ifdef HAVE_DMABUF
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm_fourcc.h>
|
||||
#include <epoxy/egl.h>
|
||||
|
||||
typedef struct _GdkDrmFormatInfo GdkDrmFormatInfo;
|
||||
@@ -133,15 +133,31 @@ download_nv12 (guchar *dst_data,
|
||||
{
|
||||
const guchar *y_data, *uv_data;
|
||||
gsize x, y, y_stride, uv_stride;
|
||||
gsize U, V;
|
||||
gsize U, V, X_SUB, Y_SUB;
|
||||
|
||||
if (dmabuf->fourcc == DRM_FORMAT_NV21)
|
||||
switch (dmabuf->fourcc)
|
||||
{
|
||||
U = 1; V = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
U = 0; V = 1;
|
||||
case DRM_FORMAT_NV12:
|
||||
U = 0; V = 1; X_SUB = 2; Y_SUB = 2;
|
||||
break;
|
||||
case DRM_FORMAT_NV21:
|
||||
U = 1; V = 0; X_SUB = 2; Y_SUB = 2;
|
||||
break;
|
||||
case DRM_FORMAT_NV16:
|
||||
U = 0; V = 1; X_SUB = 2; Y_SUB = 1;
|
||||
break;
|
||||
case DRM_FORMAT_NV61:
|
||||
U = 1; V = 0; X_SUB = 2; Y_SUB = 1;
|
||||
break;
|
||||
case DRM_FORMAT_NV24:
|
||||
U = 0; V = 1; X_SUB = 1; Y_SUB = 1;
|
||||
break;
|
||||
case DRM_FORMAT_NV42:
|
||||
U = 1; V = 0; X_SUB = 1; Y_SUB = 1;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return;
|
||||
}
|
||||
|
||||
y_stride = dmabuf->planes[0].stride;
|
||||
@@ -149,35 +165,108 @@ download_nv12 (guchar *dst_data,
|
||||
g_return_if_fail (sizes[0] >= dmabuf->planes[0].offset + height * y_stride);
|
||||
uv_stride = dmabuf->planes[1].stride;
|
||||
uv_data = src_data[1] + dmabuf->planes[1].offset;
|
||||
g_return_if_fail (sizes[1] >= dmabuf->planes[1].offset + (height + 1) / 2 * uv_stride);
|
||||
g_return_if_fail (sizes[1] >= dmabuf->planes[1].offset + (height + Y_SUB - 1) / Y_SUB * uv_stride);
|
||||
|
||||
for (y = 0; y < height; y += 2)
|
||||
for (y = 0; y < height; y += Y_SUB)
|
||||
{
|
||||
guchar *dst2_data = dst_data + dst_stride;
|
||||
const guchar *y2_data = y_data + y_stride;
|
||||
|
||||
for (x = 0; x < width; x += 2)
|
||||
for (x = 0; x < width; x += X_SUB)
|
||||
{
|
||||
int r, g, b;
|
||||
gsize xs, ys;
|
||||
|
||||
get_uv_values (&itu601_wide, uv_data[x + U], uv_data[x + V], &r, &g, &b);
|
||||
get_uv_values (&itu601_wide, uv_data[x / X_SUB * 2 + U], uv_data[x / X_SUB * 2 + V], &r, &g, &b);
|
||||
|
||||
set_rgb_values (&dst_data[3 * x], y_data[x], r, g, b);
|
||||
if (x + 1 < width)
|
||||
set_rgb_values (&dst_data[3 * (x + 1)], y_data[x], r, g, b);
|
||||
if (y + 1 < height)
|
||||
{
|
||||
set_rgb_values (&dst2_data[3 * x], y2_data[x], r, g, b);
|
||||
if (x + 1 < width)
|
||||
set_rgb_values (&dst2_data[3 * (x + 1)], y2_data[x], r, g, b);
|
||||
}
|
||||
for (ys = 0; ys < Y_SUB && y + ys < height; ys++)
|
||||
for (xs = 0; xs < X_SUB && x + xs < width; xs++)
|
||||
set_rgb_values (&dst_data[3 * (x + xs) + dst_stride * ys], y_data[x + xs + y_stride * ys], r, g, b);
|
||||
}
|
||||
dst_data += 2 * dst_stride;
|
||||
y_data += 2 * y_stride;
|
||||
dst_data += Y_SUB * dst_stride;
|
||||
y_data += Y_SUB * y_stride;
|
||||
uv_data += uv_stride;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
download_yuv_3 (guchar *dst_data,
|
||||
gsize dst_stride,
|
||||
GdkMemoryFormat dst_format,
|
||||
gsize width,
|
||||
gsize height,
|
||||
const GdkDmabuf *dmabuf,
|
||||
const guchar *src_data[GDK_DMABUF_MAX_PLANES],
|
||||
gsize sizes[GDK_DMABUF_MAX_PLANES])
|
||||
{
|
||||
const guchar *y_data, *u_data, *v_data;
|
||||
gsize x, y, y_stride, u_stride, v_stride;
|
||||
gsize U, V, X_SUB, Y_SUB;
|
||||
|
||||
switch (dmabuf->fourcc)
|
||||
{
|
||||
case DRM_FORMAT_YUV410:
|
||||
U = 1; V = 2; X_SUB = 4; Y_SUB = 4;
|
||||
break;
|
||||
case DRM_FORMAT_YVU410:
|
||||
U = 2; V = 1; X_SUB = 4; Y_SUB = 4;
|
||||
break;
|
||||
case DRM_FORMAT_YUV411:
|
||||
U = 1; V = 2; X_SUB = 4; Y_SUB = 1;
|
||||
break;
|
||||
case DRM_FORMAT_YVU411:
|
||||
U = 2; V = 1; X_SUB = 4; Y_SUB = 1;
|
||||
break;
|
||||
case DRM_FORMAT_YUV420:
|
||||
U = 1; V = 2; X_SUB = 2; Y_SUB = 2;
|
||||
break;
|
||||
case DRM_FORMAT_YVU420:
|
||||
U = 2; V = 1; X_SUB = 2; Y_SUB = 2;
|
||||
break;
|
||||
case DRM_FORMAT_YUV422:
|
||||
U = 1; V = 2; X_SUB = 2; Y_SUB = 1;
|
||||
break;
|
||||
case DRM_FORMAT_YVU422:
|
||||
U = 2; V = 1; X_SUB = 2; Y_SUB = 1;
|
||||
break;
|
||||
case DRM_FORMAT_YUV444:
|
||||
U = 1; V = 2; X_SUB = 1; Y_SUB = 1;
|
||||
break;
|
||||
case DRM_FORMAT_YVU444:
|
||||
U = 2; V = 1; X_SUB = 1; Y_SUB = 1;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return;
|
||||
}
|
||||
|
||||
y_stride = dmabuf->planes[0].stride;
|
||||
y_data = src_data[0] + dmabuf->planes[0].offset;
|
||||
g_return_if_fail (sizes[0] >= dmabuf->planes[0].offset + height * y_stride);
|
||||
u_stride = dmabuf->planes[U].stride;
|
||||
u_data = src_data[U] + dmabuf->planes[U].offset;
|
||||
g_return_if_fail (sizes[U] >= dmabuf->planes[U].offset + (height + Y_SUB - 1) / Y_SUB * u_stride);
|
||||
v_stride = dmabuf->planes[V].stride;
|
||||
v_data = src_data[V] + dmabuf->planes[V].offset;
|
||||
g_return_if_fail (sizes[V] >= dmabuf->planes[V].offset + (height + Y_SUB - 1) / Y_SUB * v_stride);
|
||||
|
||||
for (y = 0; y < height; y += Y_SUB)
|
||||
{
|
||||
for (x = 0; x < width; x += X_SUB)
|
||||
{
|
||||
int r, g, b;
|
||||
gsize xs, ys;
|
||||
|
||||
get_uv_values (&itu601_wide, u_data[x / X_SUB], v_data[x / X_SUB], &r, &g, &b);
|
||||
|
||||
for (ys = 0; ys < Y_SUB && y + ys < height; ys++)
|
||||
for (xs = 0; xs < X_SUB && x + xs < width; xs++)
|
||||
set_rgb_values (&dst_data[3 * (x + xs) + dst_stride * ys], y_data[x + xs + y_stride * ys], r, g, b);
|
||||
}
|
||||
dst_data += Y_SUB * dst_stride;
|
||||
y_data += Y_SUB * y_stride;
|
||||
u_data += u_stride;
|
||||
v_data += v_stride;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
download_yuyv (guchar *dst_data,
|
||||
gsize dst_stride,
|
||||
@@ -246,10 +335,24 @@ static const GdkDrmFormatInfo supported_formats[] = {
|
||||
/* YUV formats */
|
||||
{ DRM_FORMAT_NV12, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8, download_nv12 },
|
||||
{ DRM_FORMAT_NV21, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8, download_nv12 },
|
||||
{ DRM_FORMAT_NV16, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8, download_nv12 },
|
||||
{ DRM_FORMAT_NV61, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8, download_nv12 },
|
||||
{ DRM_FORMAT_NV24, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8, download_nv12 },
|
||||
{ DRM_FORMAT_NV42, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8, download_nv12 },
|
||||
{ DRM_FORMAT_YUYV, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8, download_yuyv },
|
||||
{ DRM_FORMAT_YVYU, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8, download_yuyv },
|
||||
{ DRM_FORMAT_VYUY, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8, download_yuyv },
|
||||
{ DRM_FORMAT_UYVY, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8, download_yuyv },
|
||||
{ DRM_FORMAT_YUV410, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8, download_yuv_3 },
|
||||
{ DRM_FORMAT_YVU410, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8, download_yuv_3 },
|
||||
{ DRM_FORMAT_YUV411, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8, download_yuv_3 },
|
||||
{ DRM_FORMAT_YVU411, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8, download_yuv_3 },
|
||||
{ DRM_FORMAT_YUV420, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8, download_yuv_3 },
|
||||
{ DRM_FORMAT_YVU420, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8, download_yuv_3 },
|
||||
{ DRM_FORMAT_YUV422, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8, download_yuv_3 },
|
||||
{ DRM_FORMAT_YVU422, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8, download_yuv_3 },
|
||||
{ DRM_FORMAT_YUV444, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8, download_yuv_3 },
|
||||
{ DRM_FORMAT_YVU444, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8, download_yuv_3 },
|
||||
};
|
||||
|
||||
static const GdkDrmFormatInfo *
|
||||
@@ -264,7 +367,7 @@ get_drm_format_info (guint32 fourcc)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
gdk_dmabuf_direct_downloader_add_formats (const GdkDmabufDownloader *downloader,
|
||||
GdkDisplay *display,
|
||||
GdkDmabufFormatsBuilder *builder)
|
||||
@@ -273,10 +376,16 @@ gdk_dmabuf_direct_downloader_add_formats (const GdkDmabufDownloader *downloader,
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (supported_formats); i++)
|
||||
{
|
||||
GDK_DEBUG (DMABUF, "%s dmabuf format %.4s:%#" G_GINT64_MODIFIER "x",
|
||||
downloader->name,
|
||||
(char *) &supported_formats[i].fourcc, (guint64) DRM_FORMAT_MOD_LINEAR);
|
||||
|
||||
gdk_dmabuf_formats_builder_add_format (builder,
|
||||
supported_formats[i].fourcc,
|
||||
DRM_FORMAT_MOD_LINEAR);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -288,7 +397,6 @@ gdk_dmabuf_direct_downloader_supports (const GdkDmabufDownloader *downloader,
|
||||
GError **error)
|
||||
{
|
||||
const GdkDrmFormatInfo *info;
|
||||
char buf[36];
|
||||
|
||||
info = get_drm_format_info (dmabuf->fourcc);
|
||||
|
||||
@@ -296,8 +404,8 @@ gdk_dmabuf_direct_downloader_supports (const GdkDmabufDownloader *downloader,
|
||||
{
|
||||
g_set_error (error,
|
||||
GDK_DMABUF_ERROR, GDK_DMABUF_ERROR_UNSUPPORTED_FORMAT,
|
||||
"Unsupported dmabuf format %s",
|
||||
gdk_dmabuf_fourcc_print (buf, sizeof (buf), dmabuf->fourcc));
|
||||
"Unsupported dmabuf format %.4s",
|
||||
(char *) &dmabuf->fourcc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -305,8 +413,8 @@ gdk_dmabuf_direct_downloader_supports (const GdkDmabufDownloader *downloader,
|
||||
{
|
||||
g_set_error (error,
|
||||
GDK_DMABUF_ERROR, GDK_DMABUF_ERROR_UNSUPPORTED_FORMAT,
|
||||
"Unsupported dmabuf modifier %s (only linear buffers are supported)",
|
||||
gdk_dmabuf_modifier_print (buf, sizeof (buf), dmabuf->modifier));
|
||||
"Unsupported dmabuf modifier %#lx (only linear buffers are supported)",
|
||||
dmabuf->modifier);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -327,14 +435,13 @@ gdk_dmabuf_direct_downloader_do_download (GdkTexture *texture,
|
||||
gsize sizes[GDK_DMABUF_MAX_PLANES];
|
||||
gsize needs_unmap[GDK_DMABUF_MAX_PLANES] = { FALSE, };
|
||||
gsize i, j;
|
||||
gchar buf[64];
|
||||
|
||||
dmabuf = gdk_dmabuf_texture_get_dmabuf (GDK_DMABUF_TEXTURE (texture));
|
||||
info = get_drm_format_info (dmabuf->fourcc);
|
||||
|
||||
GDK_DEBUG (DMABUF,
|
||||
"Using mmap() and memcpy() for downloading a dmabuf (format %s)",
|
||||
gdk_dmabuf_format_print (buf, sizeof (buf), dmabuf->fourcc, dmabuf->modifier));
|
||||
"Using mmap() and memcpy() for downloading a dmabuf (format %.4s:%#lx)",
|
||||
(char *)&dmabuf->fourcc, dmabuf->modifier);
|
||||
|
||||
for (i = 0; i < dmabuf->n_planes; i++)
|
||||
{
|
||||
@@ -356,6 +463,8 @@ gdk_dmabuf_direct_downloader_do_download (GdkTexture *texture,
|
||||
g_warning ("Failed to seek dmabuf: %s", g_strerror (errno));
|
||||
goto out;
|
||||
}
|
||||
/* be a good citizen and seek back to the start, as the dos recommend */
|
||||
lseek (dmabuf->planes[i].fd, 0, SEEK_SET);
|
||||
|
||||
if (ioctl (dmabuf->planes[i].fd, 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));
|
||||
@@ -447,15 +556,14 @@ gdk_dmabuf_get_direct_downloader (void)
|
||||
* controlled by the callers.
|
||||
*
|
||||
* Things we do here:
|
||||
*
|
||||
*
|
||||
* 1. Disallow any dmabuf format that we do not know.
|
||||
*
|
||||
* 1. Treat the INVALID modifier the same as LINEAR.
|
||||
* 1. Reject the INVALID modifier, accept the LINEAR one.
|
||||
*
|
||||
* 2. Ignore all other modifiers.
|
||||
*
|
||||
* 3. Try and fix various inconsistencies between V4L and Mesa,
|
||||
* like NV12.
|
||||
* 3. Try and fix various inconsistencies between V4L and Mesa, like NV12.
|
||||
*
|
||||
* *** WARNING ***
|
||||
*
|
||||
@@ -484,6 +592,14 @@ gdk_dmabuf_sanitize (GdkDmabuf *dest,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (src->modifier == DRM_FORMAT_MOD_INVALID)
|
||||
{
|
||||
g_set_error (error,
|
||||
GDK_DMABUF_ERROR, GDK_DMABUF_ERROR_UNSUPPORTED_FORMAT,
|
||||
"GTK does not support the INVALID modifier.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
info = get_drm_format_info (src->fourcc);
|
||||
|
||||
if (info == NULL)
|
||||
@@ -497,12 +613,15 @@ gdk_dmabuf_sanitize (GdkDmabuf *dest,
|
||||
|
||||
*dest = *src;
|
||||
|
||||
if (src->modifier && src->modifier != DRM_FORMAT_MOD_INVALID)
|
||||
if (src->modifier)
|
||||
return TRUE;
|
||||
|
||||
switch (dest->fourcc)
|
||||
{
|
||||
case DRM_FORMAT_NV12:
|
||||
case DRM_FORMAT_NV21:
|
||||
case DRM_FORMAT_NV16:
|
||||
case DRM_FORMAT_NV61:
|
||||
if (dest->n_planes == 1)
|
||||
{
|
||||
dest->n_planes = 2;
|
||||
@@ -512,6 +631,87 @@ gdk_dmabuf_sanitize (GdkDmabuf *dest,
|
||||
}
|
||||
break;
|
||||
|
||||
case DRM_FORMAT_NV24:
|
||||
case DRM_FORMAT_NV42:
|
||||
if (dest->n_planes == 1)
|
||||
{
|
||||
dest->n_planes = 2;
|
||||
dest->planes[1].fd = dest->planes[0].fd;
|
||||
dest->planes[1].stride = dest->planes[0].stride * 2;
|
||||
dest->planes[1].offset = dest->planes[0].offset + dest->planes[0].stride * height;
|
||||
}
|
||||
break;
|
||||
|
||||
case DRM_FORMAT_YUV410:
|
||||
case DRM_FORMAT_YVU410:
|
||||
if (dest->n_planes == 1)
|
||||
{
|
||||
dest->n_planes = 3;
|
||||
dest->planes[1].fd = dest->planes[0].fd;
|
||||
dest->planes[1].stride = (dest->planes[0].stride + 3) / 4;
|
||||
dest->planes[1].offset = dest->planes[0].offset + dest->planes[0].stride * height;
|
||||
dest->planes[2].fd = dest->planes[1].fd;
|
||||
dest->planes[2].stride = dest->planes[1].stride;
|
||||
dest->planes[2].offset = dest->planes[1].offset + dest->planes[1].stride * ((height + 3) / 4);
|
||||
}
|
||||
break;
|
||||
|
||||
case DRM_FORMAT_YUV411:
|
||||
case DRM_FORMAT_YVU411:
|
||||
if (dest->n_planes == 1)
|
||||
{
|
||||
dest->n_planes = 3;
|
||||
dest->planes[1].fd = dest->planes[0].fd;
|
||||
dest->planes[1].stride = (dest->planes[0].stride + 3) / 4;
|
||||
dest->planes[1].offset = dest->planes[0].offset + dest->planes[0].stride * height;
|
||||
dest->planes[2].fd = dest->planes[1].fd;
|
||||
dest->planes[2].stride = dest->planes[1].stride;
|
||||
dest->planes[2].offset = dest->planes[1].offset + dest->planes[1].stride * height;
|
||||
}
|
||||
break;
|
||||
|
||||
case DRM_FORMAT_YUV420:
|
||||
case DRM_FORMAT_YVU420:
|
||||
if (dest->n_planes == 1)
|
||||
{
|
||||
dest->n_planes = 3;
|
||||
dest->planes[1].fd = dest->planes[0].fd;
|
||||
dest->planes[1].stride = (dest->planes[0].stride + 1) / 2;
|
||||
dest->planes[1].offset = dest->planes[0].offset + dest->planes[0].stride * height;
|
||||
dest->planes[2].fd = dest->planes[1].fd;
|
||||
dest->planes[2].stride = dest->planes[1].stride;
|
||||
dest->planes[2].offset = dest->planes[1].offset + dest->planes[1].stride * ((height + 1) / 2);
|
||||
}
|
||||
break;
|
||||
|
||||
case DRM_FORMAT_YUV422:
|
||||
case DRM_FORMAT_YVU422:
|
||||
if (dest->n_planes == 1)
|
||||
{
|
||||
dest->n_planes = 3;
|
||||
dest->planes[1].fd = dest->planes[0].fd;
|
||||
dest->planes[1].stride = (dest->planes[0].stride + 1) / 2;
|
||||
dest->planes[1].offset = dest->planes[0].offset + dest->planes[0].stride * height;
|
||||
dest->planes[2].fd = dest->planes[1].fd;
|
||||
dest->planes[2].stride = dest->planes[1].stride;
|
||||
dest->planes[2].offset = dest->planes[1].offset + dest->planes[1].stride * height;
|
||||
}
|
||||
break;
|
||||
|
||||
case DRM_FORMAT_YUV444:
|
||||
case DRM_FORMAT_YVU444:
|
||||
if (dest->n_planes == 1)
|
||||
{
|
||||
dest->n_planes = 3;
|
||||
dest->planes[1].fd = dest->planes[0].fd;
|
||||
dest->planes[1].stride = dest->planes[0].stride;
|
||||
dest->planes[1].offset = dest->planes[0].offset + dest->planes[0].stride * height;
|
||||
dest->planes[2].fd = dest->planes[1].fd;
|
||||
dest->planes[2].stride = dest->planes[1].stride;
|
||||
dest->planes[2].offset = dest->planes[1].offset + dest->planes[1].stride * height;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -519,84 +719,27 @@ gdk_dmabuf_sanitize (GdkDmabuf *dest,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
const char *
|
||||
gdk_dmabuf_fourcc_print (char *buf,
|
||||
gsize size,
|
||||
guint32 fourcc)
|
||||
/*
|
||||
* gdk_dmabuf_is_disjoint:
|
||||
* @dmabuf: a sanitized GdkDmabuf
|
||||
*
|
||||
* A dmabuf is considered disjoint if it uses more than
|
||||
* 1 file descriptor.
|
||||
*
|
||||
* Returns: %TRUE if the dmabuf is disjoint
|
||||
**/
|
||||
gboolean
|
||||
gdk_dmabuf_is_disjoint (const GdkDmabuf *dmabuf)
|
||||
{
|
||||
snprintf (buf, size, "%.4s", (char *)&fourcc);
|
||||
return buf;
|
||||
}
|
||||
unsigned i;
|
||||
|
||||
static const char *
|
||||
get_modifier_name (char *buf,
|
||||
gsize size,
|
||||
guint64 modifier)
|
||||
{
|
||||
static struct {
|
||||
guchar id;
|
||||
const char *name;
|
||||
} vendors[] = {
|
||||
{ DRM_FORMAT_MOD_VENDOR_NONE, "NONE" },
|
||||
{ DRM_FORMAT_MOD_VENDOR_INTEL, "Intel" },
|
||||
{ DRM_FORMAT_MOD_VENDOR_AMD, "AMD" },
|
||||
{ DRM_FORMAT_MOD_VENDOR_NVIDIA, "NVidia" },
|
||||
{ DRM_FORMAT_MOD_VENDOR_SAMSUNG, "Samsung" },
|
||||
{ DRM_FORMAT_MOD_VENDOR_QCOM, "Qualcomm" },
|
||||
{ DRM_FORMAT_MOD_VENDOR_VIVANTE, "Vivante" },
|
||||
{ DRM_FORMAT_MOD_VENDOR_BROADCOM, "Broadcom" },
|
||||
{ DRM_FORMAT_MOD_VENDOR_ARM, "Arm" },
|
||||
{ DRM_FORMAT_MOD_VENDOR_ALLWINNER, "Allwinner" },
|
||||
{ DRM_FORMAT_MOD_VENDOR_AMLOGIC, "Amlogic" },
|
||||
};
|
||||
|
||||
if (modifier == DRM_FORMAT_MOD_INVALID)
|
||||
return "INVALID";
|
||||
else if (modifier == DRM_FORMAT_MOD_LINEAR)
|
||||
return "LINEAR";
|
||||
|
||||
for (int i = 0; i < G_N_ELEMENTS (vendors); i++)
|
||||
for (i = 1; i < dmabuf->n_planes; i++)
|
||||
{
|
||||
if (vendors[i].id == fourcc_mod_get_vendor (modifier))
|
||||
{
|
||||
snprintf (buf, size, "%s,%" G_GINT64_MODIFIER "u", vendors[i].name, modifier & 0x00ffffffffffffffUL);
|
||||
|
||||
return buf;
|
||||
}
|
||||
if (dmabuf->planes[0].fd != dmabuf->planes[i].fd)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
snprintf (buf, size, "%#" G_GINT64_MODIFIER "x", modifier);
|
||||
|
||||
return buf;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const char *
|
||||
gdk_dmabuf_modifier_print (char *buf,
|
||||
gsize size,
|
||||
guint64 modifier)
|
||||
{
|
||||
char buf2[64];
|
||||
|
||||
snprintf (buf, size, "%s", get_modifier_name (buf2, sizeof (buf2), modifier));
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
const char *
|
||||
gdk_dmabuf_format_print (char *buf,
|
||||
gsize size,
|
||||
guint32 fourcc,
|
||||
guint64 modifier)
|
||||
{
|
||||
gsize len;
|
||||
char buf2[64];
|
||||
|
||||
gdk_dmabuf_fourcc_print (buf, size, fourcc);
|
||||
len = strlen (buf);
|
||||
|
||||
snprintf (buf + len, size - len, ":%s", get_modifier_name (buf2, sizeof (buf2), modifier));
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
#endif /* HAVE_LINUX_DMA_BUF_H */
|
||||
#endif /* HAVE_DMABUF */
|
||||
|
||||
413
gdk/gdkdmabufegl.c
Normal file
413
gdk/gdkdmabufegl.c
Normal file
@@ -0,0 +1,413 @@
|
||||
/* gdkdmabufegl.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"
|
||||
|
||||
#if defined(HAVE_DMABUF) && defined (HAVE_EGL)
|
||||
#include "gdkdmabufprivate.h"
|
||||
|
||||
#include "gdkdmabufformatsbuilderprivate.h"
|
||||
#include "gdkdebugprivate.h"
|
||||
#include "gdkdmabuftextureprivate.h"
|
||||
#include "gdkmemoryformatprivate.h"
|
||||
#include "gdkdisplayprivate.h"
|
||||
#include "gdkglcontextprivate.h"
|
||||
#include "gdktexturedownloader.h"
|
||||
|
||||
#include <graphene.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <drm_fourcc.h>
|
||||
#include <epoxy/egl.h>
|
||||
|
||||
/* A dmabuf downloader implementation that downloads buffers via
|
||||
* gsk_renderer_render_texture + GL texture download.
|
||||
*/
|
||||
|
||||
static gboolean
|
||||
gdk_dmabuf_egl_downloader_add_formats (const GdkDmabufDownloader *downloader,
|
||||
GdkDisplay *display,
|
||||
GdkDmabufFormatsBuilder *builder)
|
||||
{
|
||||
GdkGLContext *context = gdk_display_get_gl_context (display);
|
||||
EGLDisplay egl_display = gdk_display_get_egl_display (display);
|
||||
GdkDmabufFormatsBuilder *external;
|
||||
gboolean retval = FALSE;
|
||||
|
||||
g_assert (display->egl_external_formats == NULL);
|
||||
|
||||
external = gdk_dmabuf_formats_builder_new ();
|
||||
|
||||
gdk_gl_context_make_current (context);
|
||||
|
||||
if (egl_display != EGL_NO_DISPLAY &&
|
||||
display->have_egl_dma_buf_import &&
|
||||
gdk_gl_context_has_image_storage (context))
|
||||
{
|
||||
int num_fourccs;
|
||||
int *fourccs;
|
||||
guint64 *modifiers;
|
||||
unsigned int *external_only;
|
||||
int n_mods;
|
||||
|
||||
eglQueryDmaBufFormatsEXT (egl_display, 0, NULL, &num_fourccs);
|
||||
fourccs = g_new (int, num_fourccs);
|
||||
eglQueryDmaBufFormatsEXT (egl_display, num_fourccs, fourccs, &num_fourccs);
|
||||
|
||||
n_mods = 80;
|
||||
modifiers = g_new (guint64, n_mods);
|
||||
external_only = g_new (unsigned int, n_mods);
|
||||
|
||||
for (int i = 0; i < num_fourccs; i++)
|
||||
{
|
||||
int num_modifiers;
|
||||
|
||||
eglQueryDmaBufModifiersEXT (egl_display,
|
||||
fourccs[i],
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
&num_modifiers);
|
||||
|
||||
if (num_modifiers > n_mods)
|
||||
{
|
||||
n_mods = num_modifiers;
|
||||
modifiers = g_renew (guint64, modifiers, n_mods);
|
||||
external_only = g_renew (unsigned int, external_only, n_mods);
|
||||
}
|
||||
|
||||
eglQueryDmaBufModifiersEXT (egl_display,
|
||||
fourccs[i],
|
||||
num_modifiers,
|
||||
modifiers,
|
||||
external_only,
|
||||
&num_modifiers);
|
||||
|
||||
for (int j = 0; j < num_modifiers; j++)
|
||||
{
|
||||
/* All linear formats we support are already added my the mmap downloader.
|
||||
* We don't add external formats, unless we can use them (via GLES)
|
||||
*/
|
||||
if (modifiers[j] != DRM_FORMAT_MOD_LINEAR &&
|
||||
(!external_only[j] || gdk_gl_context_get_use_es (context)))
|
||||
{
|
||||
GDK_DEBUG (DMABUF, "%s%s dmabuf format %.4s:%#" G_GINT64_MODIFIER "x",
|
||||
external_only[j] ? "external " : "",
|
||||
downloader->name,
|
||||
(char *) &fourccs[i],
|
||||
modifiers[j]);
|
||||
|
||||
gdk_dmabuf_formats_builder_add_format (builder, fourccs[i], modifiers[j]);
|
||||
}
|
||||
if (external_only[j])
|
||||
gdk_dmabuf_formats_builder_add_format (external, fourccs[i], modifiers[j]);
|
||||
}
|
||||
}
|
||||
|
||||
g_free (modifiers);
|
||||
g_free (external_only);
|
||||
g_free (fourccs);
|
||||
|
||||
retval = TRUE;
|
||||
}
|
||||
|
||||
display->egl_external_formats = gdk_dmabuf_formats_builder_free_to_formats (external);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static GdkMemoryFormat
|
||||
get_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:
|
||||
#ifdef DRM_FORMAT_XVUY8888
|
||||
case DRM_FORMAT_XVUY8888:
|
||||
#endif
|
||||
case DRM_FORMAT_VUY888:
|
||||
return GDK_MEMORY_R8G8B8;
|
||||
|
||||
/* Add more formats here */
|
||||
default:
|
||||
return premultiplied ? GDK_MEMORY_A8R8G8B8_PREMULTIPLIED : GDK_MEMORY_A8R8G8B8;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_dmabuf_egl_downloader_supports (const GdkDmabufDownloader *downloader,
|
||||
GdkDisplay *display,
|
||||
const GdkDmabuf *dmabuf,
|
||||
gboolean premultiplied,
|
||||
GdkMemoryFormat *out_format,
|
||||
GError **error)
|
||||
{
|
||||
EGLDisplay egl_display;
|
||||
GdkGLContext *context;
|
||||
int num_modifiers;
|
||||
guint64 *modifiers;
|
||||
unsigned int *external_only;
|
||||
|
||||
egl_display = gdk_display_get_egl_display (display);
|
||||
if (egl_display == EGL_NO_DISPLAY)
|
||||
{
|
||||
g_set_error_literal (error,
|
||||
GDK_DMABUF_ERROR, GDK_DMABUF_ERROR_UNSUPPORTED_FORMAT,
|
||||
"EGL not available");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
context = gdk_display_get_gl_context (display);
|
||||
|
||||
gdk_gl_context_make_current (context);
|
||||
|
||||
eglQueryDmaBufModifiersEXT (egl_display,
|
||||
dmabuf->fourcc,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
&num_modifiers);
|
||||
|
||||
modifiers = g_newa (uint64_t, num_modifiers);
|
||||
external_only = g_newa (unsigned int, num_modifiers);
|
||||
|
||||
eglQueryDmaBufModifiersEXT (egl_display,
|
||||
dmabuf->fourcc,
|
||||
num_modifiers,
|
||||
modifiers,
|
||||
external_only,
|
||||
&num_modifiers);
|
||||
|
||||
for (int i = 0; i < num_modifiers; i++)
|
||||
{
|
||||
if (modifiers[i] == dmabuf->modifier)
|
||||
{
|
||||
*out_format = get_memory_format (dmabuf->fourcc, premultiplied);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
g_set_error (error,
|
||||
GDK_DMABUF_ERROR, GDK_DMABUF_ERROR_UNSUPPORTED_FORMAT,
|
||||
"Unsupported dmabuf format: %.4s:%#" G_GINT64_MODIFIER "x",
|
||||
(char *) &dmabuf->fourcc, dmabuf->modifier);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
extern GskRenderer * gsk_gl_renderer_new (void);
|
||||
extern gboolean gsk_renderer_realize (GskRenderer *renderer,
|
||||
GdkSurface *surface,
|
||||
GError **error);
|
||||
extern GdkTexture * gsk_renderer_convert_texture (GskRenderer *renderer,
|
||||
GdkTexture *texture);
|
||||
|
||||
typedef void (* InvokeFunc) (gpointer data);
|
||||
|
||||
typedef struct _InvokeData
|
||||
{
|
||||
volatile int spinlock;
|
||||
InvokeFunc func;
|
||||
gpointer data;
|
||||
} InvokeData;
|
||||
|
||||
static gboolean
|
||||
gdk_dmabuf_egl_downloader_invoke_callback (gpointer data)
|
||||
{
|
||||
InvokeData *invoke = data;
|
||||
GdkGLContext *previous;
|
||||
|
||||
previous = gdk_gl_context_get_current ();
|
||||
|
||||
invoke->func (invoke->data);
|
||||
|
||||
if (previous)
|
||||
gdk_gl_context_make_current (previous);
|
||||
else
|
||||
gdk_gl_context_clear_current ();
|
||||
|
||||
g_atomic_int_set (&invoke->spinlock, 1);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Run func in the main thread, taking care not to disturb
|
||||
* the current GL context of the caller.
|
||||
*/
|
||||
static void
|
||||
gdk_dmabuf_egl_downloader_run (InvokeFunc func,
|
||||
gpointer data)
|
||||
{
|
||||
InvokeData invoke = { 0, func, data };
|
||||
|
||||
g_main_context_invoke (NULL, gdk_dmabuf_egl_downloader_invoke_callback, &invoke);
|
||||
|
||||
while (g_atomic_int_get (&invoke.spinlock) == 0) ;
|
||||
}
|
||||
|
||||
typedef struct _Download Download;
|
||||
|
||||
struct _Download
|
||||
{
|
||||
GdkDmabufTexture *texture;
|
||||
GdkMemoryFormat format;
|
||||
guchar *data;
|
||||
gsize stride;
|
||||
};
|
||||
|
||||
static GskRenderer *
|
||||
get_gsk_renderer (GdkDisplay *display)
|
||||
{
|
||||
if (!display->egl_gsk_renderer)
|
||||
{
|
||||
GskRenderer *renderer;
|
||||
GError *error = NULL;
|
||||
|
||||
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 NULL;
|
||||
}
|
||||
|
||||
display->egl_gsk_renderer = renderer;
|
||||
}
|
||||
|
||||
return display->egl_gsk_renderer;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_dmabuf_egl_downloader_do_download (gpointer data)
|
||||
{
|
||||
Download *download = data;
|
||||
GdkDisplay *display;
|
||||
GskRenderer *renderer;
|
||||
GdkTexture *native;
|
||||
GdkTextureDownloader *downloader;
|
||||
|
||||
display = gdk_dmabuf_texture_get_display (download->texture);
|
||||
|
||||
renderer = get_gsk_renderer (display);
|
||||
|
||||
native = gsk_renderer_convert_texture (renderer, GDK_TEXTURE (download->texture));
|
||||
|
||||
downloader = gdk_texture_downloader_new (native);
|
||||
gdk_texture_downloader_set_format (downloader, download->format);
|
||||
gdk_texture_downloader_download_into (downloader, download->data, download->stride);
|
||||
gdk_texture_downloader_free (downloader);
|
||||
|
||||
g_object_unref (native);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_dmabuf_egl_downloader_download (const GdkDmabufDownloader *downloader,
|
||||
GdkTexture *texture,
|
||||
GdkMemoryFormat format,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
Download download;
|
||||
|
||||
GDK_DEBUG (DMABUF, "Using %s for downloading a dmabuf", downloader->name);
|
||||
|
||||
download.texture = GDK_DMABUF_TEXTURE (texture);
|
||||
download.format = format;
|
||||
download.data = data;
|
||||
download.stride = stride;
|
||||
|
||||
gdk_dmabuf_egl_downloader_run (gdk_dmabuf_egl_downloader_do_download, &download);
|
||||
}
|
||||
|
||||
const GdkDmabufDownloader *
|
||||
gdk_dmabuf_get_egl_downloader (void)
|
||||
{
|
||||
static const GdkDmabufDownloader downloader = {
|
||||
"egl",
|
||||
gdk_dmabuf_egl_downloader_add_formats,
|
||||
gdk_dmabuf_egl_downloader_supports,
|
||||
gdk_dmabuf_egl_downloader_download,
|
||||
};
|
||||
|
||||
return &downloader;
|
||||
}
|
||||
|
||||
#endif /* HAVE_DMABUF && HAVE_EGL */
|
||||
@@ -22,6 +22,10 @@
|
||||
|
||||
#include "gdkdmabufformatsprivate.h"
|
||||
|
||||
#ifdef HAVE_DMABUF
|
||||
#include <drm_fourcc.h>
|
||||
#endif
|
||||
|
||||
#define GDK_ARRAY_NAME gdk_dmabuf_formats_builder
|
||||
#define GDK_ARRAY_TYPE_NAME GdkDmabufFormatsBuilder
|
||||
#define GDK_ARRAY_ELEMENT_TYPE GdkDmabufFormat
|
||||
@@ -117,6 +121,12 @@ gdk_dmabuf_formats_builder_add_format (GdkDmabufFormatsBuilder *self,
|
||||
guint32 fourcc,
|
||||
guint64 modifier)
|
||||
{
|
||||
#ifdef HAVE_DMABUF
|
||||
g_return_if_fail (modifier != DRM_FORMAT_MOD_INVALID);
|
||||
#else
|
||||
g_return_if_reached ();
|
||||
#endif
|
||||
|
||||
gdk_dmabuf_formats_builder_append (self, &(GdkDmabufFormat) { fourcc, modifier });
|
||||
}
|
||||
|
||||
|
||||
@@ -22,10 +22,9 @@ struct _GdkDmabuf
|
||||
struct _GdkDmabufDownloader
|
||||
{
|
||||
const char *name;
|
||||
void (* add_formats) (const GdkDmabufDownloader *downloader,
|
||||
gboolean (* add_formats) (const GdkDmabufDownloader *downloader,
|
||||
GdkDisplay *display,
|
||||
GdkDmabufFormatsBuilder *builder);
|
||||
|
||||
gboolean (* supports) (const GdkDmabufDownloader *downloader,
|
||||
GdkDisplay *display,
|
||||
const GdkDmabuf *dmabuf,
|
||||
@@ -39,25 +38,17 @@ struct _GdkDmabufDownloader
|
||||
gsize stride);
|
||||
};
|
||||
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
const GdkDmabufDownloader *
|
||||
gdk_dmabuf_get_direct_downloader (void) G_GNUC_CONST;
|
||||
#ifdef HAVE_DMABUF
|
||||
|
||||
gboolean gdk_dmabuf_sanitize (GdkDmabuf *dest,
|
||||
const GdkDmabufDownloader * gdk_dmabuf_get_direct_downloader (void) G_GNUC_CONST;
|
||||
const GdkDmabufDownloader * gdk_dmabuf_get_egl_downloader (void) G_GNUC_CONST;
|
||||
|
||||
gboolean gdk_dmabuf_sanitize (GdkDmabuf *dest,
|
||||
gsize width,
|
||||
gsize height,
|
||||
const GdkDmabuf *src,
|
||||
GError **error);
|
||||
|
||||
const char * gdk_dmabuf_fourcc_print (char *str,
|
||||
gsize size,
|
||||
guint32 fourcc);
|
||||
const char * gdk_dmabuf_modifier_print (char *str,
|
||||
gsize size,
|
||||
guint64 modifier);
|
||||
const char * gdk_dmabuf_format_print (char *str,
|
||||
gsize size,
|
||||
guint32 fourcc,
|
||||
guint64 modifier);
|
||||
gboolean gdk_dmabuf_is_disjoint (const GdkDmabuf *dmabuf);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -28,11 +28,11 @@
|
||||
#include <gdk/gdkgltexturebuilder.h>
|
||||
#include <gdk/gdktexturedownloader.h>
|
||||
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
#ifdef HAVE_DMABUF
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm_fourcc.h>
|
||||
#include <epoxy/egl.h>
|
||||
#endif
|
||||
|
||||
@@ -129,7 +129,7 @@ gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
|
||||
gpointer data,
|
||||
GError **error)
|
||||
{
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
#ifdef HAVE_DMABUF
|
||||
GdkDmabufTexture *self;
|
||||
GdkTexture *update_texture;
|
||||
GdkDisplay *display;
|
||||
@@ -210,7 +210,7 @@ gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
|
||||
|
||||
return GDK_TEXTURE (self);
|
||||
|
||||
#else /* !HAVE_LINUX_DMA_BUF_H */
|
||||
#else /* !HAVE_DMABUF */
|
||||
g_set_error_literal (error, GDK_DMABUF_ERROR, GDK_DMABUF_ERROR_NOT_AVAILABLE,
|
||||
"dmabuf support disabled at compile-time.");
|
||||
return NULL;
|
||||
|
||||
@@ -27,6 +27,11 @@
|
||||
#include "gdkdmabuftextureprivate.h"
|
||||
|
||||
#include <cairo-gobject.h>
|
||||
#ifdef HAVE_DMABUF
|
||||
#include <drm_fourcc.h>
|
||||
#else
|
||||
#define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
|
||||
#endif
|
||||
|
||||
|
||||
struct _GdkDmabufTextureBuilder
|
||||
@@ -81,7 +86,7 @@ struct _GdkDmabufTextureBuilderClass
|
||||
*
|
||||
* The format of the data (for graphics data, essentially its colorspace) is described
|
||||
* by a 32-bit integer. These format identifiers are defined in the header file
|
||||
* [drm/drm_fourcc.h](https://github.com/torvalds/linux/blob/master/include/uapi/drm/drm_fourcc.h)
|
||||
* [drm_fourcc.h](https://github.com/torvalds/linux/blob/master/include/uapi/drm_fourcc.h)
|
||||
* and commonly referred to as **_fourcc_** values, since they are identified by 4 ASCII
|
||||
* characters. Additionally, each DMA buffer has a **_modifier_**, which is a 64-bit integer
|
||||
* that describes driver-specific details of the memory layout, such as tiling or compression.
|
||||
@@ -91,9 +96,12 @@ struct _GdkDmabufTextureBuilderClass
|
||||
* to create the new texture.
|
||||
*
|
||||
* The required properties for a dma-buf texture are
|
||||
* - The width and height in pixels
|
||||
* - The `fourcc` code and `modifier` which identify the format and memory layout of the dma-buf
|
||||
* - The file descriptor, offset and stride for each of the planes
|
||||
*
|
||||
* * The width and height in pixels
|
||||
*
|
||||
* * The `fourcc` code and `modifier` which identify the format and memory layout of the dma-buf
|
||||
*
|
||||
* * The file descriptor, offset and stride for each of the planes
|
||||
*
|
||||
* `GdkDmabufTextureBuilder` can be used for quick one-shot construction of
|
||||
* textures as well as kept around and reused to construct multiple textures.
|
||||
@@ -598,6 +606,13 @@ gdk_dmabuf_texture_builder_set_modifier (GdkDmabufTextureBuilder *self,
|
||||
guint64 modifier)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
|
||||
if (modifier == DRM_FORMAT_MOD_INVALID)
|
||||
{
|
||||
g_critical ("GTK does not support the INVALID modifier. "
|
||||
"If you use code that produces it, it should include "
|
||||
"instructions how to transform it into a regular modifier.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->dmabuf.modifier == modifier)
|
||||
return;
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
#include "gdkmemorytextureprivate.h"
|
||||
#include "gdkprofilerprivate.h"
|
||||
#include "gdkglversionprivate.h"
|
||||
#include "gdkdmabufformatsprivate.h"
|
||||
|
||||
#include "gdkprivate.h"
|
||||
|
||||
@@ -95,6 +96,10 @@
|
||||
#include <epoxy/egl.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DMABUF
|
||||
#include <drm_fourcc.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#define DEFAULT_ALLOWED_APIS GDK_GL_API_GL | GDK_GL_API_GLES
|
||||
@@ -110,6 +115,7 @@ typedef struct {
|
||||
guint has_unpack_subimage : 1;
|
||||
guint has_debug_output : 1;
|
||||
guint has_bgra : 1;
|
||||
guint has_image_storage : 1;
|
||||
guint extensions_checked : 1;
|
||||
guint debug_enabled : 1;
|
||||
guint forward_compatible : 1;
|
||||
@@ -1558,6 +1564,8 @@ 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;
|
||||
@@ -1569,9 +1577,10 @@ gdk_gl_context_check_extensions (GdkGLContext *context)
|
||||
"* Extensions checked:\n"
|
||||
" - GL_KHR_debug: %s\n"
|
||||
" - GL_EXT_unpack_subimage: %s\n"
|
||||
" - GL_EXT_texture_format_BGRA8888: %s\n"
|
||||
" - GL_EXT_EGL_image_storage: %s\n"
|
||||
" - half float: %s\n"
|
||||
" - sync: %s\n"
|
||||
" - bgra: %s",
|
||||
" - sync: %s",
|
||||
gdk_gl_context_get_use_es (context) ? "OpenGL ES" : "OpenGL",
|
||||
gdk_gl_version_get_major (&priv->gl_version), gdk_gl_version_get_minor (&priv->gl_version),
|
||||
priv->is_legacy ? "legacy" : "core",
|
||||
@@ -1579,9 +1588,10 @@ gdk_gl_context_check_extensions (GdkGLContext *context)
|
||||
max_texture_size,
|
||||
priv->has_khr_debug ? "yes" : "no",
|
||||
priv->has_unpack_subimage ? "yes" : "no",
|
||||
priv->has_bgra ? "yes" : "no",
|
||||
priv->has_image_storage ? "yes" : "no",
|
||||
priv->has_half_float ? "yes" : "no",
|
||||
priv->has_sync ? "yes" : "no",
|
||||
priv->has_bgra ? "yes" : "no");
|
||||
priv->has_sync ? "yes" : "no");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1897,6 +1907,14 @@ gdk_gl_context_has_vertex_arrays (GdkGLContext *self)
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_gl_context_has_image_storage (GdkGLContext *self)
|
||||
{
|
||||
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (self);
|
||||
|
||||
return priv->has_image_storage;
|
||||
}
|
||||
|
||||
/* This is currently private! */
|
||||
/* When using GL/ES, don't flip the 'R' and 'B' bits on Windows/ANGLE for glReadPixels() */
|
||||
gboolean
|
||||
@@ -1977,3 +1995,201 @@ gdk_gl_backend_use (GdkGLBackend backend_type)
|
||||
|
||||
g_assert (the_gl_backend_type == backend_type);
|
||||
}
|
||||
|
||||
guint
|
||||
gdk_gl_context_import_dmabuf (GdkGLContext *self,
|
||||
int width,
|
||||
int height,
|
||||
const GdkDmabuf *dmabuf,
|
||||
int target)
|
||||
{
|
||||
#if defined(HAVE_EGL) && defined(HAVE_DMABUF)
|
||||
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 <= dmabuf->n_planes && dmabuf->n_planes <= 4, 0);
|
||||
g_return_val_if_fail (target == GL_TEXTURE_2D || target == GL_TEXTURE_EXTERNAL_OES, 0);
|
||||
|
||||
if (egl_display == EGL_NO_DISPLAY || !display->have_egl_dma_buf_import)
|
||||
return 0;
|
||||
|
||||
GDK_DEBUG (DMABUF,
|
||||
"Importing dmabuf (format: %.4s:%#" G_GINT64_MODIFIER "x, planes: %u) into GL",
|
||||
(char *) &dmabuf->fourcc, dmabuf->modifier, dmabuf->n_planes);
|
||||
|
||||
i = 0;
|
||||
attribs[i++] = EGL_IMAGE_PRESERVED_KHR;
|
||||
attribs[i++] = EGL_TRUE;
|
||||
attribs[i++] = EGL_WIDTH;
|
||||
attribs[i++] = width;
|
||||
attribs[i++] = EGL_HEIGHT;
|
||||
attribs[i++] = height;
|
||||
attribs[i++] = EGL_LINUX_DRM_FOURCC_EXT;
|
||||
attribs[i++] = dmabuf->fourcc;
|
||||
|
||||
#define ADD_PLANE(plane) \
|
||||
{ \
|
||||
if (dmabuf->modifier != DRM_FORMAT_MOD_INVALID) \
|
||||
{ \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE## plane ##_MODIFIER_LO_EXT; \
|
||||
attribs[i++] = dmabuf->modifier & 0xFFFFFFFF; \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE## plane ## _MODIFIER_HI_EXT; \
|
||||
attribs[i++] = dmabuf->modifier >> 32; \
|
||||
} \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE## plane ##_FD_EXT; \
|
||||
attribs[i++] = dmabuf->planes[plane].fd; \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE## plane ##_PITCH_EXT; \
|
||||
attribs[i++] = dmabuf->planes[plane].stride; \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE## plane ##_OFFSET_EXT; \
|
||||
attribs[i++] = dmabuf->planes[plane].offset; \
|
||||
}
|
||||
|
||||
ADD_PLANE (0);
|
||||
|
||||
if (dmabuf->n_planes > 1) ADD_PLANE (1);
|
||||
if (dmabuf->n_planes > 2) ADD_PLANE (2);
|
||||
if (dmabuf->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)
|
||||
{
|
||||
GDK_DEBUG (DMABUF, "Creating EGLImage for dmabuf failed: %#x", eglGetError ());
|
||||
return 0;
|
||||
}
|
||||
|
||||
glGenTextures (1, &texture_id);
|
||||
glBindTexture (target, texture_id);
|
||||
glEGLImageTargetTexture2DOES (target, image);
|
||||
glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri (target, 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,
|
||||
GdkDmabuf *dmabuf)
|
||||
{
|
||||
#if defined(HAVE_EGL) && defined(HAVE_DMABUF)
|
||||
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];
|
||||
EGLImage image;
|
||||
gboolean result = FALSE;
|
||||
int i;
|
||||
int fourcc;
|
||||
int n_planes;
|
||||
guint64 modifier;
|
||||
int fds[GDK_DMABUF_MAX_PLANES];
|
||||
int strides[GDK_DMABUF_MAX_PLANES];
|
||||
int offsets[GDK_DMABUF_MAX_PLANES];
|
||||
|
||||
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 (dmabuf != 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)
|
||||
{
|
||||
GDK_DEBUG (DMABUF, "Creating EGLImage for dmabuf failed: %#x", eglGetError ());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!eglExportDMABUFImageQueryMESA (egl_display,
|
||||
image,
|
||||
&fourcc,
|
||||
&n_planes,
|
||||
&modifier))
|
||||
{
|
||||
GDK_DEBUG (DMABUF, "eglExportDMABUFImageQueryMESA failed: %#x", eglGetError ());
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (n_planes < 1 || n_planes > GDK_DMABUF_MAX_PLANES)
|
||||
{
|
||||
GDK_DEBUG (DMABUF, "dmabufs with %d planes are not supported", n_planes);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!eglExportDMABUFImageMESA (egl_display,
|
||||
image,
|
||||
fds,
|
||||
strides,
|
||||
offsets))
|
||||
{
|
||||
g_warning ("eglExportDMABUFImage failed: %#x", eglGetError ());
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < n_planes; i++)
|
||||
{
|
||||
if (fds[i] == -1)
|
||||
{
|
||||
g_warning ("dmabuf plane %d has no file descriptor", i);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
dmabuf->fourcc = (guint32)fourcc;
|
||||
dmabuf->modifier = modifier;
|
||||
dmabuf->n_planes = n_planes;
|
||||
|
||||
for (i = 0; i < n_planes; i++)
|
||||
{
|
||||
dmabuf->planes[i].fd = fds[i];
|
||||
dmabuf->planes[i].stride = (int) strides[i];
|
||||
dmabuf->planes[i].offset = (int) offsets[i];
|
||||
}
|
||||
|
||||
GDK_DEBUG (DMABUF,
|
||||
"Exported GL texture to dmabuf (format: %.4s:%#" G_GINT64_MODIFIER "x, planes: %d)",
|
||||
(char *)&fourcc, modifier, n_planes);
|
||||
|
||||
result = TRUE;
|
||||
|
||||
out:
|
||||
eglDestroyImageKHR (egl_display, image);
|
||||
|
||||
return result;
|
||||
#else
|
||||
return FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "gdkglcontext.h"
|
||||
#include "gdkdrawcontextprivate.h"
|
||||
#include "gdkglversionprivate.h"
|
||||
#include "gdkdmabufprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@@ -161,7 +162,18 @@ gboolean gdk_gl_context_has_bgra (GdkGLContext
|
||||
|
||||
gboolean gdk_gl_context_has_vertex_arrays (GdkGLContext *self) G_GNUC_PURE;
|
||||
|
||||
gboolean gdk_gl_context_has_image_storage (GdkGLContext *self) G_GNUC_PURE;
|
||||
|
||||
double gdk_gl_context_get_scale (GdkGLContext *self);
|
||||
|
||||
G_END_DECLS
|
||||
guint gdk_gl_context_import_dmabuf (GdkGLContext *self,
|
||||
int width,
|
||||
int height,
|
||||
const GdkDmabuf *dmabuf,
|
||||
int target);
|
||||
|
||||
gboolean gdk_gl_context_export_dmabuf (GdkGLContext *self,
|
||||
unsigned int texture_id,
|
||||
GdkDmabuf *dmabuf);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
@@ -569,7 +569,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
|
||||
GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
||||
16,
|
||||
G_ALIGNOF (float),
|
||||
TRUE,
|
||||
GDK_MEMORY_FLOAT32,
|
||||
{ 0, 0, 3, 0 },
|
||||
{ GL_RGBA32F, GL_RGBA, GL_FLOAT, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
||||
r32g32b32a32_float_to_float,
|
||||
|
||||
@@ -493,6 +493,12 @@ gdk_surface_real_get_scale (GdkSurface *surface)
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
static GdkSubsurface *
|
||||
gdk_surface_real_create_subsurface (GdkSurface *surface)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_surface_constructed (GObject *object)
|
||||
{
|
||||
@@ -515,6 +521,7 @@ gdk_surface_class_init (GdkSurfaceClass *klass)
|
||||
|
||||
klass->beep = gdk_surface_real_beep;
|
||||
klass->get_scale = gdk_surface_real_get_scale;
|
||||
klass->create_subsurface = gdk_surface_real_create_subsurface;
|
||||
|
||||
/**
|
||||
* GdkSurface:cursor: (attributes org.gtk.Property.get=gdk_surface_get_cursor org.gtk.Property.set=gdk_surface_set_cursor)
|
||||
@@ -3054,3 +3061,40 @@ gdk_surface_leave_monitor (GdkSurface *surface,
|
||||
{
|
||||
g_signal_emit (surface, signals[LEAVE_MONITOR], 0, monitor);
|
||||
}
|
||||
|
||||
GdkSubsurface *
|
||||
gdk_surface_create_subsurface (GdkSurface *surface)
|
||||
{
|
||||
return GDK_SURFACE_GET_CLASS (surface)->create_subsurface (surface);
|
||||
}
|
||||
|
||||
void
|
||||
gdk_subsurface_destroy (GdkSubsurface *subsurface)
|
||||
{
|
||||
subsurface->class->destroy (subsurface);
|
||||
}
|
||||
|
||||
void
|
||||
gdk_subsurface_attach (GdkSubsurface *subsurface,
|
||||
GdkTexture *texture,
|
||||
const graphene_rect_t *bounds)
|
||||
{
|
||||
subsurface->class->attach (subsurface, texture, bounds);
|
||||
}
|
||||
|
||||
/* If sibling is NULL, place the subsurface above its parent */
|
||||
void
|
||||
gdk_subsurface_place_above (GdkSubsurface *subsurface,
|
||||
GdkSubsurface *sibling)
|
||||
{
|
||||
subsurface->class->place_above (subsurface, sibling);
|
||||
}
|
||||
|
||||
/* If sibling is NULL, place the subsurface below its parent */
|
||||
void
|
||||
gdk_subsurface_place_below (GdkSubsurface *subsurface,
|
||||
GdkSubsurface *sibling)
|
||||
{
|
||||
subsurface->class->place_below (subsurface, sibling);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,9 +23,14 @@
|
||||
#include "gdkenumtypes.h"
|
||||
#include "gdksurface.h"
|
||||
#include "gdktoplevel.h"
|
||||
#include <graphene.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GdkSubsurface GdkSubsurface;
|
||||
|
||||
typedef struct _GskRenderNode GskRenderNode;
|
||||
|
||||
struct _GdkSurface
|
||||
{
|
||||
GObject parent_instance;
|
||||
@@ -146,6 +151,9 @@ struct _GdkSurfaceClass
|
||||
cairo_region_t *region);
|
||||
void (* request_layout) (GdkSurface *surface);
|
||||
gboolean (* compute_size) (GdkSurface *surface);
|
||||
|
||||
GdkSubsurface *
|
||||
(* create_subsurface) (GdkSurface *surface);
|
||||
};
|
||||
|
||||
#define GDK_SURFACE_DESTROYED(d) (((GdkSurface *)(d))->destroyed)
|
||||
@@ -334,7 +342,34 @@ void gdk_surface_request_motion (GdkSurface *surface);
|
||||
|
||||
gboolean gdk_surface_supports_edge_constraints (GdkSurface *surface);
|
||||
|
||||
GdkSubsurface * gdk_surface_create_subsurface (GdkSurface *surface);
|
||||
|
||||
typedef struct _GdkSubsurfaceClass GdkSubsurfaceClass;
|
||||
struct _GdkSubsurfaceClass
|
||||
{
|
||||
void (* destroy) (GdkSubsurface *subsurface);
|
||||
void (* attach) (GdkSubsurface *subsurface,
|
||||
GdkTexture *texture,
|
||||
const graphene_rect_t *bounds);
|
||||
void (* place_above) (GdkSubsurface *subsurface,
|
||||
GdkSubsurface *sibling);
|
||||
void (* place_below) (GdkSubsurface *subsurface,
|
||||
GdkSubsurface *sibling);
|
||||
};
|
||||
|
||||
struct _GdkSubsurface
|
||||
{
|
||||
const GdkSubsurfaceClass *class;
|
||||
};
|
||||
|
||||
void gdk_subsurface_destroy (GdkSubsurface *subsurface);
|
||||
void gdk_subsurface_attach (GdkSubsurface *subsurface,
|
||||
GdkTexture *texture,
|
||||
const graphene_rect_t *bounds);
|
||||
void gdk_subsurface_place_above (GdkSubsurface *subsurface,
|
||||
GdkSubsurface *sibling);
|
||||
void gdk_subsurface_place_below (GdkSubsurface *subsurface,
|
||||
GdkSubsurface *sibling);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ gdk_public_sources = files([
|
||||
'gdkdisplay.c',
|
||||
'gdkdisplaymanager.c',
|
||||
'gdkdmabuf.c',
|
||||
'gdkdmabufegl.c',
|
||||
'gdkdmabufformats.c',
|
||||
'gdkdmabufformatsbuilder.c',
|
||||
'gdkdmabuftexture.c',
|
||||
@@ -216,6 +217,7 @@ gdk_deps = [
|
||||
platform_gio_dep,
|
||||
pangocairo_dep,
|
||||
vulkan_dep,
|
||||
dmabuf_dep,
|
||||
png_dep,
|
||||
tiff_dep,
|
||||
jpeg_dep,
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -267,45 +269,105 @@ postpone_on_globals_closure (GdkWaylandDisplay *display_wayland,
|
||||
g_list_append (display_wayland->on_has_globals_closures, closure);
|
||||
}
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
|
||||
static const char *
|
||||
get_format_name (uint32_t format,
|
||||
char name[10])
|
||||
{
|
||||
if (format == 0)
|
||||
g_strlcpy (name, "ARGB8888", 10);
|
||||
else if (format == 1)
|
||||
g_strlcpy (name, "XRGB8888", 10);
|
||||
else
|
||||
g_snprintf (name, 10, "4cc %c%c%c%c",
|
||||
(char) (format & 0xff),
|
||||
(char) ((format >> 8) & 0xff),
|
||||
(char) ((format >> 16) & 0xff),
|
||||
(char) ((format >> 24) & 0xff));
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void
|
||||
wl_shm_format (void *data,
|
||||
struct wl_shm *wl_shm,
|
||||
uint32_t format)
|
||||
{
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
char buf[10];
|
||||
#endif
|
||||
|
||||
GDK_DEBUG (MISC, "supported pixel format %s (0x%X)",
|
||||
get_format_name (format, buf), (guint) format);
|
||||
GDK_DEBUG (MISC, "supported shm pixel format %.4s (0x%X)", (char *) &format, format);
|
||||
}
|
||||
|
||||
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, " %.4s:%#" G_GINT64_MODIFIER "x", (char *) &f, 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 +444,16 @@ 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 && version >= 4)
|
||||
{
|
||||
display_wayland->linux_dmabuf =
|
||||
wl_registry_bind (display_wayland->wl_registry, id, &zwp_linux_dmabuf_v1_interface, version);
|
||||
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 +798,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;
|
||||
|
||||
@@ -75,7 +75,7 @@ gdk_wayland_gl_context_end_frame (GdkDrawContext *draw_context,
|
||||
WL_SURFACE_OFFSET_SINCE_VERSION)
|
||||
wl_surface_offset (impl->display_server.wl_surface, dx, dy);
|
||||
|
||||
/* We should do ths when setting up the EGLSurface, but we don't make_current then */
|
||||
/* We should do this when setting up the EGLSurface, but we don't make_current then */
|
||||
eglSwapInterval (gdk_display_get_egl_display (gdk_draw_context_get_display (draw_context)), 0);
|
||||
|
||||
GDK_DRAW_CONTEXT_CLASS (gdk_wayland_gl_context_parent_class)->end_frame (draw_context, painted);
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <gdk/wayland/gdkdisplay-wayland.h>
|
||||
#include <gdk/wayland/gdkseat-wayland.h>
|
||||
|
||||
#include <gsk/gsk.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
|
||||
@@ -222,4 +223,3 @@ void gdk_wayland_surface_update_scale (GdkSurface *surface);
|
||||
|
||||
GdkModifierType gdk_wayland_keymap_get_gdk_modifiers (GdkKeymap *keymap,
|
||||
guint32 mods);
|
||||
|
||||
|
||||
@@ -86,6 +86,8 @@ struct _GdkWaylandSurface
|
||||
uint32_t last_configure_serial;
|
||||
|
||||
int state_freeze_count;
|
||||
|
||||
GPtrArray *subsurfaces;
|
||||
};
|
||||
|
||||
typedef struct _GdkWaylandSurfaceClass GdkWaylandSurfaceClass;
|
||||
|
||||
@@ -33,9 +33,11 @@
|
||||
#include "gdksurfaceprivate.h"
|
||||
#include "gdktoplevelprivate.h"
|
||||
#include "gdkdevice-wayland-private.h"
|
||||
#include "gdkdmabuftextureprivate.h"
|
||||
|
||||
#include <wayland/xdg-shell-unstable-v6-client-protocol.h>
|
||||
#include <wayland/xdg-foreign-unstable-v2-client-protocol.h>
|
||||
#include "linux-dmabuf-unstable-v1-client-protocol.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@@ -48,6 +50,7 @@
|
||||
#include "gdksurface-wayland-private.h"
|
||||
#include "gdktoplevel-wayland-private.h"
|
||||
|
||||
|
||||
/**
|
||||
* GdkWaylandSurface:
|
||||
*
|
||||
@@ -152,13 +155,17 @@ wl_region_from_cairo_region (GdkWaylandDisplay *display,
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
/* {{{ Surface implementation */
|
||||
/* {{{ Surface implementation */
|
||||
|
||||
static void gdk_wayland_subsurface_destroy (GdkSubsurface *sub);
|
||||
|
||||
static void
|
||||
gdk_wayland_surface_init (GdkWaylandSurface *impl)
|
||||
{
|
||||
impl->scale = GDK_FRACTIONAL_SCALE_INIT_INT (1);
|
||||
impl->viewport_dirty = TRUE;
|
||||
|
||||
impl->subsurfaces = g_ptr_array_new ();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -552,6 +559,7 @@ gdk_wayland_surface_finalize (GObject *object)
|
||||
|
||||
g_clear_pointer (&impl->opaque_region, cairo_region_destroy);
|
||||
g_clear_pointer (&impl->input_region, cairo_region_destroy);
|
||||
g_clear_pointer (&impl->subsurfaces, g_ptr_array_unref);
|
||||
|
||||
G_OBJECT_CLASS (gdk_wayland_surface_parent_class)->finalize (object);
|
||||
}
|
||||
@@ -1135,6 +1143,17 @@ gdk_wayland_surface_set_input_region (GdkSurface *surface,
|
||||
impl->input_region_dirty = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_surface_destroy_subsurfaces (GdkWaylandSurface *impl)
|
||||
{
|
||||
for (gsize i = 0; i < impl->subsurfaces->len; i++)
|
||||
{
|
||||
GdkSubsurface *sub = g_ptr_array_index (impl->subsurfaces, i);
|
||||
gdk_subsurface_destroy (sub);
|
||||
}
|
||||
g_ptr_array_set_size (impl->subsurfaces, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_surface_destroy (GdkSurface *surface,
|
||||
gboolean foreign_destroy)
|
||||
@@ -1151,6 +1170,7 @@ gdk_wayland_surface_destroy (GdkSurface *surface,
|
||||
if (GDK_IS_TOPLEVEL (surface))
|
||||
gdk_wayland_toplevel_destroy (GDK_TOPLEVEL (surface));
|
||||
|
||||
gdk_wayland_surface_destroy_subsurfaces (GDK_WAYLAND_SURFACE (surface));
|
||||
gdk_wayland_surface_destroy_wl_surface (GDK_WAYLAND_SURFACE (surface));
|
||||
|
||||
frame_clock = gdk_surface_get_frame_clock (surface);
|
||||
@@ -1207,6 +1227,8 @@ gdk_wayland_surface_default_hide_surface (GdkWaylandSurface *surface)
|
||||
{
|
||||
}
|
||||
|
||||
static GdkSubsurface *gdk_wayland_surface_create_subsurface (GdkSurface *surface);
|
||||
|
||||
static void
|
||||
gdk_wayland_surface_class_init (GdkWaylandSurfaceClass *klass)
|
||||
{
|
||||
@@ -1230,6 +1252,7 @@ gdk_wayland_surface_class_init (GdkWaylandSurfaceClass *klass)
|
||||
surface_class->get_scale = gdk_wayland_surface_get_scale;
|
||||
surface_class->set_opaque_region = gdk_wayland_surface_set_opaque_region;
|
||||
surface_class->request_layout = gdk_wayland_surface_request_layout;
|
||||
surface_class->create_subsurface = gdk_wayland_surface_create_subsurface;
|
||||
|
||||
klass->handle_configure = gdk_wayland_surface_default_handle_configure;
|
||||
klass->handle_frame = gdk_wayland_surface_default_handle_frame;
|
||||
@@ -1305,4 +1328,236 @@ gdk_wayland_surface_get_wl_surface (GdkSurface *surface)
|
||||
}
|
||||
|
||||
/* }}}} */
|
||||
/* {{{ Subsurface */
|
||||
|
||||
typedef struct {
|
||||
GdkSubsurface subsurface;
|
||||
|
||||
GdkWaylandSurface *parent;
|
||||
|
||||
struct wl_surface *wl_surface;
|
||||
struct wl_subsurface *wl_subsurface;
|
||||
struct wp_viewport *wp_viewport;
|
||||
} GdkWaylandSubsurface;
|
||||
|
||||
static void
|
||||
dmabuf_buffer_release (void *data,
|
||||
struct wl_buffer *wl_buffer)
|
||||
{
|
||||
GdkTexture *texture = data;
|
||||
|
||||
g_object_unref (texture);
|
||||
wl_buffer_destroy (wl_buffer);
|
||||
}
|
||||
|
||||
static const struct wl_buffer_listener dmabuf_buffer_listener = {
|
||||
dmabuf_buffer_release,
|
||||
};
|
||||
|
||||
static struct wl_buffer *
|
||||
get_dmabuf_wl_buffer (GdkWaylandSubsurface *self,
|
||||
GdkTexture *texture)
|
||||
{
|
||||
GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (self->parent)));
|
||||
const GdkDmabuf *dmabuf;
|
||||
struct zwp_linux_buffer_params_v1 *params;
|
||||
struct wl_buffer *wl_buffer;
|
||||
|
||||
dmabuf = gdk_dmabuf_texture_get_dmabuf (GDK_DMABUF_TEXTURE (texture));
|
||||
|
||||
params = zwp_linux_dmabuf_v1_create_params (display->linux_dmabuf);
|
||||
|
||||
for (gsize i = 0; i < dmabuf->n_planes; i++)
|
||||
zwp_linux_buffer_params_v1_add (params,
|
||||
dmabuf->planes[i].fd,
|
||||
i,
|
||||
dmabuf->planes[i].offset,
|
||||
dmabuf->planes[i].stride,
|
||||
dmabuf->modifier >> 32,
|
||||
dmabuf->modifier & 0xffffffff);
|
||||
|
||||
wl_buffer = zwp_linux_buffer_params_v1_create_immed (params,
|
||||
gdk_texture_get_width (texture),
|
||||
gdk_texture_get_height (texture),
|
||||
dmabuf->fourcc,
|
||||
0);
|
||||
|
||||
wl_buffer_add_listener (wl_buffer, &dmabuf_buffer_listener, g_object_ref (texture));
|
||||
|
||||
return wl_buffer;
|
||||
}
|
||||
|
||||
static void
|
||||
shm_buffer_release (void *data,
|
||||
struct wl_buffer *wl_buffer)
|
||||
{
|
||||
cairo_surface_t *surface = data;
|
||||
|
||||
/* Note: the wl_buffer is destroyed as cairo user data */
|
||||
cairo_surface_destroy (surface);
|
||||
}
|
||||
|
||||
static const struct wl_buffer_listener shm_buffer_listener = {
|
||||
shm_buffer_release,
|
||||
};
|
||||
|
||||
static struct wl_buffer *
|
||||
get_shm_wl_buffer (GdkWaylandSubsurface *self,
|
||||
GdkTexture *texture)
|
||||
{
|
||||
GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (GDK_SURFACE (self->parent)));
|
||||
int width, height;
|
||||
cairo_surface_t *surface;
|
||||
GdkTextureDownloader *downloader;
|
||||
struct wl_buffer *wl_buffer;
|
||||
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
surface = gdk_wayland_display_create_shm_surface (display, width, height, &GDK_FRACTIONAL_SCALE_INIT_INT (1));
|
||||
|
||||
downloader = gdk_texture_downloader_new (texture);
|
||||
|
||||
gdk_texture_downloader_download_into (downloader,
|
||||
cairo_image_surface_get_data (surface),
|
||||
cairo_image_surface_get_stride (surface));
|
||||
|
||||
gdk_texture_downloader_free (downloader);
|
||||
|
||||
wl_buffer = _gdk_wayland_shm_surface_get_wl_buffer (surface);
|
||||
wl_buffer_add_listener (wl_buffer, &shm_buffer_listener, surface);
|
||||
|
||||
return wl_buffer;
|
||||
}
|
||||
|
||||
static struct wl_buffer *
|
||||
get_wl_buffer (GdkWaylandSubsurface *self,
|
||||
GdkTexture *texture)
|
||||
{
|
||||
if (GDK_IS_DMABUF_TEXTURE (texture))
|
||||
return get_dmabuf_wl_buffer (self, texture);
|
||||
else
|
||||
return get_shm_wl_buffer (self, texture);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_subsurface_attach (GdkSubsurface *sub,
|
||||
GdkTexture *texture,
|
||||
const graphene_rect_t *rect)
|
||||
{
|
||||
GdkWaylandSubsurface *self = (GdkWaylandSubsurface *)sub;
|
||||
|
||||
GDK_DEBUG (DMABUF,
|
||||
"Attaching texture %p at %f %f %f %f",
|
||||
texture,
|
||||
rect->origin.x, rect->origin.y, rect->size.width, rect->size.height);
|
||||
|
||||
if (rect)
|
||||
{
|
||||
wl_subsurface_set_position (self->wl_subsurface,
|
||||
floorf (rect->origin.x),
|
||||
floorf (rect->origin.y));
|
||||
wp_viewport_set_destination (self->wp_viewport,
|
||||
ceilf (rect->origin.x + rect->size.width) - floorf (rect->origin.x),
|
||||
ceilf (rect->origin.y + rect->size.height) - floorf (rect->origin.y));
|
||||
}
|
||||
|
||||
if (texture)
|
||||
{
|
||||
wl_surface_attach (self->wl_surface, get_wl_buffer (self, texture), 0, 0);
|
||||
wl_surface_damage_buffer (self->wl_surface,
|
||||
0, 0,
|
||||
gdk_texture_get_width (texture),
|
||||
gdk_texture_get_height (texture));
|
||||
}
|
||||
else
|
||||
{
|
||||
wl_surface_attach (self->wl_surface, NULL, 0, 0);
|
||||
}
|
||||
|
||||
wl_surface_commit (self->wl_surface);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_subsurface_destroy (GdkSubsurface *sub)
|
||||
{
|
||||
GdkWaylandSubsurface *self = (GdkWaylandSubsurface *)sub;
|
||||
|
||||
g_clear_pointer (&self->wp_viewport, wp_viewport_destroy);
|
||||
g_clear_pointer (&self->wl_subsurface, wl_subsurface_destroy);
|
||||
g_clear_pointer (&self->wl_surface, wl_surface_destroy);
|
||||
|
||||
g_ptr_array_remove (self->parent->subsurfaces, self);
|
||||
|
||||
g_free (self);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_subsurface_place_above (GdkSubsurface *sub,
|
||||
GdkSubsurface *sibling)
|
||||
{
|
||||
GdkWaylandSubsurface *self = (GdkWaylandSubsurface *)sub;
|
||||
GdkWaylandSubsurface *sib = (GdkWaylandSubsurface *)sibling;
|
||||
|
||||
g_return_if_fail (sib == NULL || self->parent == sib->parent);
|
||||
|
||||
wl_subsurface_place_above (self->wl_subsurface,
|
||||
sib ? sib->wl_surface : self->parent->display_server.wl_surface);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_wayland_subsurface_place_below (GdkSubsurface *sub,
|
||||
GdkSubsurface *sibling)
|
||||
{
|
||||
GdkWaylandSubsurface *self = (GdkWaylandSubsurface *)sub;
|
||||
GdkWaylandSubsurface *sib = (GdkWaylandSubsurface *)sibling;
|
||||
|
||||
g_return_if_fail (sib == NULL || self->parent == sib->parent);
|
||||
|
||||
wl_subsurface_place_below (self->wl_subsurface,
|
||||
sib ? sib->wl_surface : self->parent->display_server.wl_surface);
|
||||
}
|
||||
|
||||
static const GdkSubsurfaceClass subsurface_class = {
|
||||
gdk_wayland_subsurface_destroy,
|
||||
gdk_wayland_subsurface_attach,
|
||||
gdk_wayland_subsurface_place_above,
|
||||
gdk_wayland_subsurface_place_below,
|
||||
};
|
||||
|
||||
static GdkSubsurface *
|
||||
gdk_wayland_surface_create_subsurface (GdkSurface *surface)
|
||||
{
|
||||
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
|
||||
GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
|
||||
GdkWaylandSubsurface *sub;
|
||||
struct wl_region *wl_region;
|
||||
|
||||
if (display->viewporter == NULL)
|
||||
{
|
||||
GDK_DEBUG (DMABUF, "Can't use subsurfaces without viewporter");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sub = g_new0 (GdkWaylandSubsurface, 1);
|
||||
|
||||
sub->subsurface.class = &subsurface_class;
|
||||
|
||||
sub->parent = impl;
|
||||
g_ptr_array_add (sub->parent->subsurfaces, sub);
|
||||
|
||||
sub->wl_surface = wl_compositor_create_surface (display->compositor);
|
||||
wl_region = wl_compositor_create_region (display->compositor);
|
||||
wl_surface_set_input_region (sub->wl_surface, wl_region);
|
||||
wl_region_destroy (wl_region);
|
||||
sub->wl_subsurface = wl_subcompositor_get_subsurface (display->subcompositor,
|
||||
sub->wl_surface,
|
||||
impl->display_server.wl_surface);
|
||||
sub->wp_viewport = wp_viewporter_get_viewport (display->viewporter, sub->wl_surface);
|
||||
|
||||
GDK_DEBUG (DMABUF, "Subsurface created");
|
||||
|
||||
return (GdkSubsurface *) sub;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
/* vim:set foldmethod=marker expandtab: */
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
@@ -76,7 +76,8 @@ gsk_gl_attachment_state_bind_texture (GskGLAttachmentState *self,
|
||||
g_assert (self != NULL);
|
||||
g_assert (target == GL_TEXTURE_1D ||
|
||||
target == GL_TEXTURE_2D ||
|
||||
target == GL_TEXTURE_3D);
|
||||
target == GL_TEXTURE_3D ||
|
||||
target == GL_TEXTURE_EXTERNAL_OES);
|
||||
g_assert (texture >= GL_TEXTURE0 && texture <= GL_TEXTURE16);
|
||||
g_assert (texture - GL_TEXTURE0 < G_N_ELEMENTS (self->textures));
|
||||
|
||||
|
||||
@@ -29,6 +29,9 @@ typedef struct _GskGLBindFramebuffer GskGLBindFramebuffer;
|
||||
typedef struct _GskGLBindTexture GskGLBindTexture;
|
||||
|
||||
#define GSK_GL_N_FILTERS 3
|
||||
#define SAMPLER_EXTERNAL 9
|
||||
|
||||
G_STATIC_ASSERT (SAMPLER_EXTERNAL >= GSK_GL_N_FILTERS * GSK_GL_N_FILTERS);
|
||||
|
||||
static inline guint
|
||||
filter_index (GLint filter)
|
||||
|
||||
@@ -282,7 +282,10 @@ snapshot_attachments (const GskGLAttachmentState *state,
|
||||
{
|
||||
bind[count].id = state->textures[i].id;
|
||||
bind[count].texture = state->textures[i].texture;
|
||||
bind[count].sampler = state->textures[i].sampler;
|
||||
if (state->textures[i].target == GL_TEXTURE_EXTERNAL_OES)
|
||||
bind[count].sampler = SAMPLER_EXTERNAL;
|
||||
else
|
||||
bind[count].sampler = state->textures[i].sampler;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
@@ -1190,12 +1193,23 @@ gsk_gl_command_queue_execute (GskGLCommandQueue *self,
|
||||
s->sync = NULL;
|
||||
}
|
||||
|
||||
glBindTexture (GL_TEXTURE_2D, bind->id);
|
||||
if (bind->sampler == SAMPLER_EXTERNAL)
|
||||
glBindTexture (GL_TEXTURE_EXTERNAL_OES, bind->id);
|
||||
else
|
||||
glBindTexture (GL_TEXTURE_2D, bind->id);
|
||||
textures[bind->texture] = bind->id;
|
||||
if (!self->has_samplers)
|
||||
{
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_from_index (bind->sampler / GSK_GL_N_FILTERS));
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_from_index (bind->sampler % GSK_GL_N_FILTERS));
|
||||
if (bind->sampler == SAMPLER_EXTERNAL)
|
||||
{
|
||||
glTexParameteri (GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri (GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_from_index (bind->sampler / GSK_GL_N_FILTERS));
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_from_index (bind->sampler % GSK_GL_N_FILTERS));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1205,8 +1219,16 @@ gsk_gl_command_queue_execute (GskGLCommandQueue *self,
|
||||
glBindSampler (bind->texture, self->samplers[bind->sampler]);
|
||||
else
|
||||
{
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_from_index (bind->sampler / GSK_GL_N_FILTERS));
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_from_index (bind->sampler % GSK_GL_N_FILTERS));
|
||||
if (bind->sampler == SAMPLER_EXTERNAL)
|
||||
{
|
||||
glTexParameteri (GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri (GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_from_index (bind->sampler / GSK_GL_N_FILTERS));
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_from_index (bind->sampler % GSK_GL_N_FILTERS));
|
||||
}
|
||||
}
|
||||
samplers[bind->texture] = bind->sampler;
|
||||
}
|
||||
@@ -1324,7 +1346,7 @@ gsk_gl_command_queue_end_frame (GskGLCommandQueue *self)
|
||||
if (self->attachments->textures[i].id != 0)
|
||||
{
|
||||
glActiveTexture (GL_TEXTURE0 + i);
|
||||
glBindTexture (GL_TEXTURE_2D, 0);
|
||||
glBindTexture (self->attachments->textures[i].target, 0);
|
||||
|
||||
self->attachments->textures[i].id = 0;
|
||||
self->attachments->textures[i].changed = FALSE;
|
||||
@@ -1401,7 +1423,7 @@ gsk_gl_command_queue_create_texture (GskGLCommandQueue *self,
|
||||
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
glBindTexture (GL_TEXTURE_2D, texture_id);
|
||||
|
||||
|
||||
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);
|
||||
@@ -1429,8 +1451,9 @@ gsk_gl_command_queue_create_texture (GskGLCommandQueue *self,
|
||||
}
|
||||
|
||||
/* Restore the previous texture if it was set */
|
||||
if (self->attachments->textures[0].id != 0)
|
||||
glBindTexture (GL_TEXTURE_2D, self->attachments->textures[0].id);
|
||||
if (self->attachments->textures[0].id != 0 &&
|
||||
self->attachments->textures[0].target == GL_TEXTURE_2D)
|
||||
glBindTexture (self->attachments->textures[0].target, self->attachments->textures[0].id);
|
||||
|
||||
return (int)texture_id;
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ typedef struct _GskGLCommandBind
|
||||
*/
|
||||
guint texture : 4;
|
||||
|
||||
/* the sampler to use. We set sampler to 15 to indicate external textures */
|
||||
guint sampler : 4;
|
||||
|
||||
/* The identifier for the texture created with glGenTextures(). */
|
||||
@@ -234,8 +235,13 @@ struct _GskGLCommandQueue
|
||||
|
||||
/* Array of samplers that we use for mag/min filter handling. It is indexed
|
||||
* by the sampler_index() function.
|
||||
*
|
||||
* Note that when samplers are not supported (hello GLES), we fall back to
|
||||
* setting the texture filter, but that needs to be done for every texture.
|
||||
*
|
||||
* Also note that we don't use all of these samplers since some combinations
|
||||
* are invalid. An index of SAMPLER_EXTERNAL is used to indicate an external
|
||||
* texture, which needs special sampler treatment.
|
||||
*/
|
||||
GLuint samplers[GSK_GL_N_FILTERS * GSK_GL_N_FILTERS];
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ struct _GskGLCompiler
|
||||
|
||||
guint gl3 : 1;
|
||||
guint gles : 1;
|
||||
guint gles3 : 1;
|
||||
guint legacy : 1;
|
||||
guint debug_shaders : 1;
|
||||
};
|
||||
@@ -134,7 +135,10 @@ gsk_gl_compiler_new (GskGLDriver *driver,
|
||||
gdk_gl_context_get_version (context, &maj, &min);
|
||||
|
||||
if (maj >= 3)
|
||||
self->glsl_version = SHADER_VERSION_GLES3;
|
||||
{
|
||||
self->glsl_version = SHADER_VERSION_GLES3;
|
||||
self->gles3 = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
self->glsl_version = SHADER_VERSION_GLES;
|
||||
@@ -543,6 +547,7 @@ gsk_gl_compiler_compile (GskGLCompiler *self,
|
||||
const char *legacy = "";
|
||||
const char *gl3 = "";
|
||||
const char *gles = "";
|
||||
const char *gles3 = "";
|
||||
int program_id;
|
||||
int vertex_id;
|
||||
int fragment_id;
|
||||
@@ -569,15 +574,17 @@ gsk_gl_compiler_compile (GskGLCompiler *self,
|
||||
if (self->gles)
|
||||
gles = "#define GSK_GLES 1\n";
|
||||
|
||||
if (self->gles3)
|
||||
gles3 = "#define GSK_GLES3 1\n";
|
||||
|
||||
if (self->gl3)
|
||||
gl3 = "#define GSK_GL3 1\n";
|
||||
|
||||
vertex_id = glCreateShader (GL_VERTEX_SHADER);
|
||||
glShaderSource (vertex_id,
|
||||
10,
|
||||
11,
|
||||
(const char *[]) {
|
||||
version, debug, legacy, gl3, gles,
|
||||
clip,
|
||||
version, debug, legacy, gl3, gles, gles3, clip,
|
||||
get_shader_string (self->all_preamble),
|
||||
get_shader_string (self->vertex_preamble),
|
||||
get_shader_string (self->vertex_source),
|
||||
@@ -589,6 +596,7 @@ gsk_gl_compiler_compile (GskGLCompiler *self,
|
||||
strlen (legacy),
|
||||
strlen (gl3),
|
||||
strlen (gles),
|
||||
strlen (gles3),
|
||||
strlen (clip),
|
||||
g_bytes_get_size (self->all_preamble),
|
||||
g_bytes_get_size (self->vertex_preamble),
|
||||
@@ -607,10 +615,9 @@ gsk_gl_compiler_compile (GskGLCompiler *self,
|
||||
|
||||
fragment_id = glCreateShader (GL_FRAGMENT_SHADER);
|
||||
glShaderSource (fragment_id,
|
||||
10,
|
||||
11,
|
||||
(const char *[]) {
|
||||
version, debug, legacy, gl3, gles,
|
||||
clip,
|
||||
version, debug, legacy, gl3, gles, gles3, clip,
|
||||
get_shader_string (self->all_preamble),
|
||||
get_shader_string (self->fragment_preamble),
|
||||
get_shader_string (self->fragment_source),
|
||||
@@ -622,6 +629,7 @@ gsk_gl_compiler_compile (GskGLCompiler *self,
|
||||
strlen (legacy),
|
||||
strlen (gl3),
|
||||
strlen (gles),
|
||||
strlen (gles3),
|
||||
strlen (clip),
|
||||
g_bytes_get_size (self->all_preamble),
|
||||
g_bytes_get_size (self->fragment_preamble),
|
||||
|
||||
@@ -44,6 +44,8 @@
|
||||
#include <gdk/gdktextureprivate.h>
|
||||
|
||||
#include <gdk/gdkmemoryformatprivate.h>
|
||||
#include <gdk/gdkdmabuftextureprivate.h>
|
||||
|
||||
|
||||
G_DEFINE_TYPE (GskGLDriver, gsk_gl_driver, G_TYPE_OBJECT)
|
||||
|
||||
@@ -224,6 +226,8 @@ gsk_gl_driver_dispose (GObject *object)
|
||||
GSK_GL_DELETE_PROGRAM(name); \
|
||||
GSK_GL_DELETE_PROGRAM(name ## _no_clip); \
|
||||
GSK_GL_DELETE_PROGRAM(name ## _rect_clip);
|
||||
#define GSK_GL_DEFINE_PROGRAM_NO_CLIP(name, resource, uniforms) \
|
||||
GSK_GL_DELETE_PROGRAM(name);
|
||||
#define GSK_GL_DELETE_PROGRAM(name) \
|
||||
G_STMT_START { \
|
||||
if (self->name) \
|
||||
@@ -238,6 +242,7 @@ gsk_gl_driver_dispose (GObject *object)
|
||||
#undef GSK_GL_SHADER_JOINED
|
||||
#undef GSK_GL_ADD_UNIFORM
|
||||
#undef GSK_GL_DEFINE_PROGRAM
|
||||
#undef GSK_GL_DEFINE_PROGRAM_NO_CLIP
|
||||
|
||||
if (self->shader_cache != NULL)
|
||||
{
|
||||
@@ -373,6 +378,11 @@ gsk_gl_driver_load_programs (GskGLDriver *self,
|
||||
GSK_GL_COMPILE_PROGRAM(name ## _no_clip, uniforms, "#define NO_CLIP 1\n"); \
|
||||
GSK_GL_COMPILE_PROGRAM(name ## _rect_clip, uniforms, "#define RECT_CLIP 1\n"); \
|
||||
GSK_GL_COMPILE_PROGRAM(name, uniforms, "");
|
||||
#define GSK_GL_DEFINE_PROGRAM_NO_CLIP(name, sources, uniforms) \
|
||||
gsk_gl_compiler_set_source (compiler, GSK_GL_COMPILER_VERTEX, NULL); \
|
||||
gsk_gl_compiler_set_source (compiler, GSK_GL_COMPILER_FRAGMENT, NULL); \
|
||||
sources \
|
||||
GSK_GL_COMPILE_PROGRAM(name, uniforms, "#define NO_CLIP 1\n");
|
||||
#define GSK_GL_COMPILE_PROGRAM(name, uniforms, clip) \
|
||||
G_STMT_START { \
|
||||
GskGLProgram *program; \
|
||||
@@ -400,6 +410,7 @@ gsk_gl_driver_load_programs (GskGLDriver *self,
|
||||
} G_STMT_END;
|
||||
# include "gskglprograms.defs"
|
||||
#undef GSK_GL_DEFINE_PROGRAM
|
||||
#undef GSK_GL_DEFINE_PROGRAM_NO_CLIP
|
||||
#undef GSK_GL_ADD_UNIFORM
|
||||
#undef GSK_GL_SHADER_SINGLE
|
||||
#undef GSK_GL_SHADER_JOINED
|
||||
@@ -702,6 +713,180 @@ gsk_gl_driver_cache_texture (GskGLDriver *self,
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HAVE_DMABUF) && defined (HAVE_EGL)
|
||||
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 } };
|
||||
}
|
||||
|
||||
static unsigned int release_render_target (GskGLDriver *self,
|
||||
GskGLRenderTarget *render_target,
|
||||
gboolean release_texture,
|
||||
gboolean cache_texture);
|
||||
|
||||
static guint
|
||||
gsk_gl_driver_import_dmabuf_texture (GskGLDriver *self,
|
||||
GdkDmabufTexture *texture)
|
||||
{
|
||||
GdkGLContext *context = self->command_queue->context;
|
||||
GdkDisplay *display = gdk_gl_context_get_display (context);
|
||||
int max_texture_size = self->command_queue->max_texture_size;
|
||||
const GdkDmabuf *dmabuf;
|
||||
guint texture_id;
|
||||
int width, height;
|
||||
GskGLProgram *program;
|
||||
GskGLRenderTarget *render_target;
|
||||
guint prev_fbo;
|
||||
|
||||
gdk_gl_context_make_current (context);
|
||||
|
||||
width = gdk_texture_get_width (GDK_TEXTURE (texture));
|
||||
height = gdk_texture_get_height (GDK_TEXTURE (texture));
|
||||
|
||||
if (width > max_texture_size || height > max_texture_size)
|
||||
{
|
||||
GDK_DEBUG (DMABUF, "Can't import dmabuf bigger than MAX_TEXTURE_SIZE (%d)", max_texture_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dmabuf = gdk_dmabuf_texture_get_dmabuf (texture);
|
||||
|
||||
GDK_DEBUG (DMABUF, "DMA-buf Format %.4s:%#lx", (char *) &dmabuf->fourcc, dmabuf->modifier);
|
||||
|
||||
gdk_display_init_dmabuf (display);
|
||||
|
||||
if (!gdk_dmabuf_formats_contains (display->egl_external_formats, dmabuf->fourcc, dmabuf->modifier))
|
||||
{
|
||||
GDK_DEBUG (DMABUF, "Import dmabuf as GL_TEXTURE_2D texture");
|
||||
return gdk_gl_context_import_dmabuf (context, width, height,
|
||||
dmabuf,
|
||||
GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
if (!gdk_gl_context_get_use_es (context))
|
||||
{
|
||||
GDK_DEBUG (DMABUF, "Can't import external_only dmabuf outside of GLES");
|
||||
return 0;
|
||||
}
|
||||
|
||||
GDK_DEBUG (DMABUF, "Import dmabuf as GL_TEXTURE_EXTERNAL_OES texture");
|
||||
|
||||
texture_id = gdk_gl_context_import_dmabuf (context, width, height,
|
||||
dmabuf,
|
||||
GL_TEXTURE_EXTERNAL_OES);
|
||||
|
||||
if (texture_id == 0)
|
||||
return 0;
|
||||
|
||||
gsk_gl_driver_autorelease_texture (self, texture_id);
|
||||
|
||||
program = self->external;
|
||||
|
||||
gsk_gl_driver_create_render_target (self, width, height, GL_RGBA8, &render_target);
|
||||
|
||||
prev_fbo = gsk_gl_command_queue_bind_framebuffer (self->command_queue, render_target->framebuffer_id);
|
||||
gsk_gl_command_queue_clear (self->command_queue, 0, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
|
||||
if (gsk_gl_command_queue_begin_draw (self->command_queue, program->program_info, width, height))
|
||||
{
|
||||
set_projection_for_size (self, program, width, height);
|
||||
set_viewport_for_size (self, program, width, height);
|
||||
reset_modelview (self, program);
|
||||
|
||||
gsk_gl_program_set_uniform_texture (program,
|
||||
UNIFORM_EXTERNAL_SOURCE, 0,
|
||||
GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE0, texture_id);
|
||||
|
||||
draw_rect (self->command_queue, 0, 0, width, height);
|
||||
|
||||
gsk_gl_command_queue_end_draw (self->command_queue);
|
||||
}
|
||||
|
||||
gsk_gl_command_queue_bind_framebuffer (self->command_queue, prev_fbo);
|
||||
|
||||
return release_render_target (self, render_target, FALSE, FALSE);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static guint
|
||||
gsk_gl_driver_import_dmabuf_texture (GskGLDriver *self,
|
||||
GdkDmabufTexture *texture)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* HAVE_DMABUF && HAVE_EGL */
|
||||
|
||||
/**
|
||||
* gsk_gl_driver_load_texture:
|
||||
* @self: a `GdkTexture`
|
||||
@@ -758,7 +943,11 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
|
||||
return t->texture_id;
|
||||
}
|
||||
|
||||
if (GDK_IS_GL_TEXTURE (texture))
|
||||
if (GDK_IS_DMABUF_TEXTURE (texture))
|
||||
{
|
||||
texture_id = gsk_gl_driver_import_dmabuf_texture (self, GDK_DMABUF_TEXTURE (texture));
|
||||
}
|
||||
else if (GDK_IS_GL_TEXTURE (texture))
|
||||
{
|
||||
GdkGLTexture *gl_texture = (GdkGLTexture *) texture;
|
||||
GdkGLContext *texture_context = gdk_gl_texture_get_context (gl_texture);
|
||||
@@ -961,6 +1150,47 @@ gsk_gl_driver_create_render_target (GskGLDriver *self,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
release_render_target (GskGLDriver *self,
|
||||
GskGLRenderTarget *render_target,
|
||||
gboolean release_texture,
|
||||
gboolean cache_texture)
|
||||
{
|
||||
guint texture_id;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_GL_DRIVER (self), 0);
|
||||
g_return_val_if_fail (render_target != NULL, 0);
|
||||
|
||||
if (release_texture)
|
||||
{
|
||||
texture_id = 0;
|
||||
g_ptr_array_add (self->render_targets, render_target);
|
||||
}
|
||||
else
|
||||
{
|
||||
texture_id = render_target->texture_id;
|
||||
|
||||
if (cache_texture)
|
||||
{
|
||||
GskGLTexture *texture;
|
||||
|
||||
texture = gsk_gl_texture_new (render_target->texture_id,
|
||||
render_target->width,
|
||||
render_target->height,
|
||||
self->current_frame_id);
|
||||
g_hash_table_insert (self->textures,
|
||||
GUINT_TO_POINTER (texture_id),
|
||||
g_steal_pointer (&texture));
|
||||
}
|
||||
|
||||
gsk_gl_driver_autorelease_framebuffer (self, render_target->framebuffer_id);
|
||||
g_free (render_target);
|
||||
|
||||
}
|
||||
|
||||
return texture_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_gl_driver_release_render_target:
|
||||
* @self: a `GskGLDriver`
|
||||
@@ -986,36 +1216,7 @@ gsk_gl_driver_release_render_target (GskGLDriver *self,
|
||||
GskGLRenderTarget *render_target,
|
||||
gboolean release_texture)
|
||||
{
|
||||
guint texture_id;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_GL_DRIVER (self), 0);
|
||||
g_return_val_if_fail (render_target != NULL, 0);
|
||||
|
||||
if (release_texture)
|
||||
{
|
||||
texture_id = 0;
|
||||
g_ptr_array_add (self->render_targets, render_target);
|
||||
}
|
||||
else
|
||||
{
|
||||
GskGLTexture *texture;
|
||||
|
||||
texture_id = render_target->texture_id;
|
||||
|
||||
texture = gsk_gl_texture_new (render_target->texture_id,
|
||||
render_target->width,
|
||||
render_target->height,
|
||||
self->current_frame_id);
|
||||
g_hash_table_insert (self->textures,
|
||||
GUINT_TO_POINTER (texture_id),
|
||||
g_steal_pointer (&texture));
|
||||
|
||||
gsk_gl_driver_autorelease_framebuffer (self, render_target->framebuffer_id);
|
||||
g_free (render_target);
|
||||
|
||||
}
|
||||
|
||||
return texture_id;
|
||||
return release_render_target (self, render_target, release_texture, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1600,8 +1801,9 @@ create_texture_from_texture_destroy (gpointer data)
|
||||
}
|
||||
|
||||
GdkTexture *
|
||||
gsk_gl_driver_create_gdk_texture (GskGLDriver *self,
|
||||
guint texture_id)
|
||||
gsk_gl_driver_create_gdk_texture (GskGLDriver *self,
|
||||
guint texture_id,
|
||||
GdkMemoryFormat format)
|
||||
{
|
||||
GskGLTextureState *state;
|
||||
GdkGLTextureBuilder *builder;
|
||||
@@ -1629,6 +1831,7 @@ gsk_gl_driver_create_gdk_texture (GskGLDriver *self,
|
||||
builder = gdk_gl_texture_builder_new ();
|
||||
gdk_gl_texture_builder_set_context (builder, self->command_queue->context);
|
||||
gdk_gl_texture_builder_set_id (builder, texture_id);
|
||||
gdk_gl_texture_builder_set_format (builder, format);
|
||||
gdk_gl_texture_builder_set_width (builder, texture->width);
|
||||
gdk_gl_texture_builder_set_height (builder, texture->height);
|
||||
gdk_gl_texture_builder_set_sync (builder, state->sync);
|
||||
|
||||
@@ -69,7 +69,9 @@ typedef struct {
|
||||
#define CONCAT_EXPANDED2(a,b) a##b
|
||||
#define GSK_GL_ADD_UNIFORM(pos, KEY, name) UNIFORM_##KEY = UNIFORM_SHARED_LAST + pos,
|
||||
#define GSK_GL_DEFINE_PROGRAM(name, resource, uniforms) enum { uniforms };
|
||||
#define GSK_GL_DEFINE_PROGRAM_NO_CLIP(name, resource, uniforms) enum { uniforms };
|
||||
# include "gskglprograms.defs"
|
||||
#undef GSK_GL_DEFINE_PROGRAM_NO_CLIP
|
||||
#undef GSK_GL_DEFINE_PROGRAM
|
||||
#undef GSK_GL_ADD_UNIFORM
|
||||
#undef GSK_GL_NO_UNIFORMS
|
||||
@@ -116,10 +118,13 @@ struct _GskGLDriver
|
||||
GskGLProgram *name ## _no_clip; \
|
||||
GskGLProgram *name ## _rect_clip; \
|
||||
GskGLProgram *name;
|
||||
#define GSK_GL_DEFINE_PROGRAM_NO_CLIP(name, resource, uniforms) \
|
||||
GskGLProgram *name;
|
||||
# include "gskglprograms.defs"
|
||||
#undef GSK_GL_NO_UNIFORMS
|
||||
#undef GSK_GL_ADD_UNIFORM
|
||||
#undef GSK_GL_DEFINE_PROGRAM
|
||||
#undef GSK_GL_DEFINE_PROGRAM_NO_CLIP
|
||||
|
||||
gint64 current_frame_id;
|
||||
|
||||
@@ -149,7 +154,8 @@ void gsk_gl_driver_begin_frame (GskGLDriver *s
|
||||
void gsk_gl_driver_end_frame (GskGLDriver *self);
|
||||
void gsk_gl_driver_after_frame (GskGLDriver *self);
|
||||
GdkTexture * gsk_gl_driver_create_gdk_texture (GskGLDriver *self,
|
||||
guint texture_id);
|
||||
guint texture_id,
|
||||
GdkMemoryFormat format);
|
||||
void gsk_gl_driver_cache_texture (GskGLDriver *self,
|
||||
const GskTextureKey *key,
|
||||
guint texture_id);
|
||||
|
||||
@@ -119,7 +119,11 @@ gsk_gl_glyph_library_init_atlas (GskGLTextureLibrary *self,
|
||||
|
||||
memset (pixel_data, 255, sizeof pixel_data);
|
||||
|
||||
if (!gdk_gl_context_has_bgra (gdk_gl_context_get_current ()))
|
||||
if (!gdk_gl_context_has_bgra (gdk_gl_context_get_current ())
|
||||
#if G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
|| gdk_gl_context_get_use_es (gdk_gl_context_get_current ())
|
||||
#endif
|
||||
)
|
||||
{
|
||||
gl_format = GL_RGBA;
|
||||
gl_type = GL_UNSIGNED_BYTE;
|
||||
|
||||
@@ -111,7 +111,11 @@ gsk_gl_icon_library_add (GskGLIconLibrary *self,
|
||||
gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (),
|
||||
"Uploading texture");
|
||||
|
||||
if (!gdk_gl_context_has_bgra (gdk_gl_context_get_current ()))
|
||||
if (!gdk_gl_context_has_bgra (gdk_gl_context_get_current ())
|
||||
#if G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
|| gdk_gl_context_get_use_es (gdk_gl_context_get_current ())
|
||||
#endif
|
||||
)
|
||||
{
|
||||
pixel_data = free_data = g_malloc (width * height * 4);
|
||||
gdk_memory_convert (pixel_data, width * 4,
|
||||
|
||||
@@ -87,3 +87,13 @@ GSK_GL_DEFINE_PROGRAM (unblurred_outset_shadow,
|
||||
GSK_GL_ADD_UNIFORM (1, UNBLURRED_OUTSET_SHADOW_SPREAD, u_spread)
|
||||
GSK_GL_ADD_UNIFORM (2, UNBLURRED_OUTSET_SHADOW_OFFSET, u_offset)
|
||||
GSK_GL_ADD_UNIFORM (3, UNBLURRED_OUTSET_SHADOW_OUTLINE_RECT, u_outline_rect))
|
||||
|
||||
/* Texture conversion shaders.
|
||||
*
|
||||
* Note: If you add new formats here, they need to be added
|
||||
* to the list of supported formats in gdk/gdkdmabuftexture.c.
|
||||
*/
|
||||
|
||||
GSK_GL_DEFINE_PROGRAM_NO_CLIP (external,
|
||||
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("external.glsl")),
|
||||
GSK_GL_ADD_UNIFORM (1, EXTERNAL_SOURCE, u_external_source))
|
||||
|
||||
@@ -332,6 +332,7 @@ gsk_gl_renderer_render_texture (GskRenderer *renderer,
|
||||
GskGLRenderJob *job;
|
||||
GdkTexture *texture;
|
||||
guint texture_id;
|
||||
GdkMemoryFormat gdk_format;
|
||||
int width, height, max_size;
|
||||
int format;
|
||||
|
||||
@@ -375,9 +376,15 @@ gsk_gl_renderer_render_texture (GskRenderer *renderer,
|
||||
|
||||
if (gsk_render_node_get_preferred_depth (root) != GDK_MEMORY_U8 &&
|
||||
gdk_gl_context_check_version (self->context, "3.0", "3.0"))
|
||||
format = GL_RGBA32F;
|
||||
{
|
||||
gdk_format = GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED;
|
||||
format = GL_RGBA32F;
|
||||
}
|
||||
else
|
||||
format = GL_RGBA8;
|
||||
{
|
||||
format = GL_RGBA8;
|
||||
gdk_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
|
||||
}
|
||||
|
||||
gdk_gl_context_make_current (self->context);
|
||||
|
||||
@@ -394,7 +401,7 @@ gsk_gl_renderer_render_texture (GskRenderer *renderer,
|
||||
#endif
|
||||
gsk_gl_render_job_render_flipped (job, root);
|
||||
texture_id = gsk_gl_driver_release_render_target (self->driver, render_target, FALSE);
|
||||
texture = gsk_gl_driver_create_gdk_texture (self->driver, texture_id);
|
||||
texture = gsk_gl_driver_create_gdk_texture (self->driver, texture_id, gdk_format);
|
||||
gsk_gl_driver_end_frame (self->driver);
|
||||
gsk_gl_render_job_free (job);
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#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>
|
||||
@@ -47,6 +48,7 @@
|
||||
#include "ninesliceprivate.h"
|
||||
#include "fp16private.h"
|
||||
|
||||
|
||||
#define ORTHO_NEAR_PLANE -10000
|
||||
#define ORTHO_FAR_PLANE 10000
|
||||
#define MAX_GRADIENT_STOPS 6
|
||||
@@ -3630,16 +3632,12 @@ gsk_gl_render_job_upload_texture (GskGLRenderJob *job,
|
||||
gboolean ensure_mipmap,
|
||||
GskGLRenderOffscreen *offscreen)
|
||||
{
|
||||
GdkGLTexture *gl_texture = NULL;
|
||||
|
||||
if (GDK_IS_GL_TEXTURE (texture))
|
||||
gl_texture = GDK_GL_TEXTURE (texture);
|
||||
|
||||
/* Don't put GL or dmabuf textures into icon caches, they are already on the GPU side */
|
||||
if (!ensure_mipmap &&
|
||||
gsk_gl_texture_library_can_cache ((GskGLTextureLibrary *)job->driver->icons_library,
|
||||
texture->width,
|
||||
texture->height) &&
|
||||
!gl_texture)
|
||||
!(GDK_IS_GL_TEXTURE (texture) || GDK_IS_DMABUF_TEXTURE (texture)))
|
||||
{
|
||||
const GskGLIconData *icon_data;
|
||||
|
||||
@@ -3653,16 +3651,18 @@ 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 (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);
|
||||
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));
|
||||
|
||||
offscreen->texture_id = gsk_gl_driver_load_texture (job->driver, texture, ensure_mipmap);
|
||||
init_full_texture_region (offscreen);
|
||||
offscreen->has_mipmap = ensure_mipmap;
|
||||
|
||||
if (gl_texture && offscreen->texture_id == gdk_gl_texture_get_id (gl_texture))
|
||||
offscreen->sync = gdk_gl_texture_get_sync (gl_texture);
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3784,12 +3784,6 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
|
||||
GskTextureKey key;
|
||||
guint texture_id;
|
||||
|
||||
if (filter == GSK_SCALING_FILTER_LINEAR)
|
||||
{
|
||||
gsk_gl_render_job_visit_texture (job, texture, bounds);
|
||||
return;
|
||||
}
|
||||
|
||||
gsk_gl_render_job_untransform_bounds (job, &job->current_clip->rect.bounds, &clip_rect);
|
||||
|
||||
if (!graphene_rect_intersection (bounds, &clip_rect, &clip_rect))
|
||||
|
||||
28
gsk/gl/resources/external.glsl
Normal file
28
gsk/gl/resources/external.glsl
Normal file
@@ -0,0 +1,28 @@
|
||||
// VERTEX_SHADER:
|
||||
// external.glsl
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
// external.glsl
|
||||
|
||||
#if defined(GSK_GLES) || defined(GSK_GLES3)
|
||||
uniform samplerExternalOES u_external_source;
|
||||
#else
|
||||
/* Just to make this compile, we won't use it without GLES */
|
||||
uniform sampler2D u_external_source;
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
/* Open-code this here, since GskTexture() expects a sampler2D */
|
||||
#if defined(GSK_GLES) || defined(GSK_LEGACY)
|
||||
vec4 color = texture2D(u_external_source, vUv);
|
||||
#else
|
||||
vec4 color = texture(u_external_source, vUv);
|
||||
#endif
|
||||
gskSetOutputColor(color);
|
||||
}
|
||||
@@ -1,3 +1,9 @@
|
||||
#if defined(GSK_GLES3)
|
||||
#extension GL_OES_EGL_image_external_essl3 : require
|
||||
#elif defined (GSK_GLES)
|
||||
#extension GL_OES_EGL_image_external : require
|
||||
#endif
|
||||
|
||||
#ifndef GSK_LEGACY
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
@@ -684,3 +684,22 @@ gsk_renderer_set_debug_flags (GskRenderer *renderer,
|
||||
|
||||
priv->debug_flags = flags;
|
||||
}
|
||||
|
||||
/* Feed a texture through a renderer and return the resulting 'native' texture. */
|
||||
GdkTexture *
|
||||
gsk_renderer_convert_texture (GskRenderer *self,
|
||||
GdkTexture *texture)
|
||||
{
|
||||
int width, height;
|
||||
GskRenderNode *node;
|
||||
GdkTexture *result;
|
||||
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
|
||||
node = gsk_texture_node_new (texture, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
result = gsk_renderer_render_texture (self, node, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gsk_render_node_unref (node);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -56,5 +56,8 @@ GskDebugFlags gsk_renderer_get_debug_flags (GskRenderer
|
||||
void gsk_renderer_set_debug_flags (GskRenderer *renderer,
|
||||
GskDebugFlags flags);
|
||||
|
||||
GdkTexture * gsk_renderer_convert_texture (GskRenderer *renderer,
|
||||
GdkTexture *texture);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ gsk_private_gl_shaders = [
|
||||
'gl/resources/custom.glsl',
|
||||
'gl/resources/filled_border.glsl',
|
||||
'gl/resources/mask.glsl',
|
||||
'gl/resources/external.glsl',
|
||||
]
|
||||
|
||||
gsk_public_sources = files([
|
||||
|
||||
21
meson.build
21
meson.build
@@ -1,5 +1,5 @@
|
||||
project('gtk', 'c',
|
||||
version: '4.13.2',
|
||||
version: '4.13.3',
|
||||
default_options: [
|
||||
'buildtype=debugoptimized',
|
||||
'warning_level=1',
|
||||
@@ -162,7 +162,6 @@ check_headers = [
|
||||
'inttypes.h',
|
||||
'linux/input.h',
|
||||
'linux/memfd.h',
|
||||
'linux/dma-buf.h',
|
||||
'locale.h',
|
||||
'memory.h',
|
||||
'stdint.h',
|
||||
@@ -186,10 +185,6 @@ foreach h : check_headers
|
||||
endif
|
||||
endforeach
|
||||
|
||||
if os_linux and not cc.has_header('linux/dma-buf.h')
|
||||
error('OS is Linux, but linux/dma-buf.h not found.')
|
||||
endif
|
||||
|
||||
# Maths functions might be implemented in libm
|
||||
libm = cc.find_library('m', required: false)
|
||||
|
||||
@@ -623,6 +618,20 @@ else
|
||||
vulkan_pkg_found = false
|
||||
endif
|
||||
|
||||
if cc.has_header('linux/dma-buf.h')
|
||||
dmabuf_dep = dependency('libdrm',
|
||||
required: os_linux)
|
||||
else
|
||||
if os_linux
|
||||
error('OS is Linux, but linux/dma-buf.h not found.')
|
||||
endif
|
||||
dmabuf_dep = dependency('', required: false)
|
||||
endif
|
||||
cdata.set('HAVE_DMABUF', dmabuf_dep.found())
|
||||
# We only care about drm_fourcc.h for all the fourccs,
|
||||
# but not about linking to libdrm
|
||||
dmabuf_dep = dmabuf_dep.partial_dependency(includes: true, compile_args: true)
|
||||
|
||||
cloudproviders_dep = dependency('cloudproviders',
|
||||
required: get_option('cloudproviders'),
|
||||
version: cloudproviders_req,
|
||||
|
||||
@@ -149,3 +149,11 @@ foreach t: gtk_tests
|
||||
dependencies: [libgtk_dep, libm],
|
||||
)
|
||||
endforeach
|
||||
|
||||
executable('testsubsurface',
|
||||
sources: '@0@.c'.format('testsubsurface'),
|
||||
c_args: common_cflags + ['-DGTK_COMPILATION'],
|
||||
dependencies: libgtk_static_dep,
|
||||
install: false,
|
||||
)
|
||||
|
||||
|
||||
@@ -2,43 +2,68 @@
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/dma-heap.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm_fourcc.h>
|
||||
|
||||
/* For this to work, you may need to give /dev/dma_heap/system
|
||||
* lax permissions.
|
||||
*/
|
||||
|
||||
static int dma_heap_fd = -1;
|
||||
|
||||
static gboolean
|
||||
initialize_dma_heap (void)
|
||||
{
|
||||
dma_heap_fd = open ("/dev/dma_heap/system", O_RDONLY | O_CLOEXEC);
|
||||
return dma_heap_fd != -1;
|
||||
}
|
||||
|
||||
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);
|
||||
ret = ioctl (dma_heap_fd, DMA_HEAP_IOCTL_ALLOC, &heap_data);
|
||||
if (ret)
|
||||
g_error ("dma-buf allocation failed");
|
||||
|
||||
return heap_data.fd;
|
||||
}
|
||||
|
||||
static int
|
||||
allocate_memfd (gsize size)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = memfd_create ("buffer", MFD_CLOEXEC);
|
||||
if (fd == -1)
|
||||
g_error ("memfd allocation failed");
|
||||
|
||||
ftruncate (fd, size);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int
|
||||
allocate_buffer (gsize size)
|
||||
{
|
||||
if (dma_heap_fd != -1)
|
||||
return allocate_dma_buf (size);
|
||||
else
|
||||
return allocate_memfd (size);
|
||||
}
|
||||
|
||||
static void
|
||||
populate_dma_buf (int fd,
|
||||
const guchar *data,
|
||||
gsize size)
|
||||
populate_buffer (int fd,
|
||||
const guchar *data,
|
||||
gsize size)
|
||||
{
|
||||
guchar *buf;
|
||||
|
||||
@@ -253,8 +278,8 @@ texture_builder_set_planes (GdkDmabufTextureBuilder *builder,
|
||||
|
||||
for (i = 0; i < n_planes; i++)
|
||||
{
|
||||
int fd = allocate_dma_buf (sizes[i]);
|
||||
populate_dma_buf (fd, buf + offset, sizes[i]);
|
||||
int fd = allocate_buffer (sizes[i]);
|
||||
populate_buffer (fd, buf + offset, sizes[i]);
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, i, fd);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, i, strides[i]);
|
||||
@@ -266,8 +291,8 @@ texture_builder_set_planes (GdkDmabufTextureBuilder *builder,
|
||||
{
|
||||
unsigned offset = 0;
|
||||
unsigned i;
|
||||
int fd = allocate_dma_buf (size);
|
||||
populate_dma_buf (fd, buf, size);
|
||||
int fd = allocate_buffer (size);
|
||||
populate_buffer (fd, buf, size);
|
||||
|
||||
for (i = 0; i < n_planes; i++)
|
||||
{
|
||||
@@ -292,6 +317,11 @@ make_dmabuf_texture (const char *filename,
|
||||
GdkDmabufTextureBuilder *builder;
|
||||
GError *error = NULL;
|
||||
|
||||
if (initialize_dma_heap ())
|
||||
g_print ("Using dma_heap\n");
|
||||
else
|
||||
g_print ("Using memfd\n");
|
||||
|
||||
texture = gdk_texture_new_from_filename (filename, NULL);
|
||||
|
||||
width = gdk_texture_get_width (texture);
|
||||
@@ -318,8 +348,8 @@ make_dmabuf_texture (const char *filename,
|
||||
{
|
||||
gdk_dmabuf_texture_builder_set_n_planes (builder, 1);
|
||||
|
||||
fd = allocate_dma_buf (rgb_size);
|
||||
populate_dma_buf (fd, rgb_data, rgb_size);
|
||||
fd = allocate_buffer (rgb_size);
|
||||
populate_buffer (fd, rgb_data, rgb_size);
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 0, fd);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 0, rgb_stride);
|
||||
|
||||
257
tests/testsubsurface.c
Normal file
257
tests/testsubsurface.c
Normal file
@@ -0,0 +1,257 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include "gtk/gtkwidgetprivate.h"
|
||||
#include "gdk/gdksurfaceprivate.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/dma-heap.h>
|
||||
#include <drm_fourcc.h>
|
||||
|
||||
static int dma_heap_fd = -1;
|
||||
|
||||
static gboolean
|
||||
initialize_dma_heap (void)
|
||||
{
|
||||
dma_heap_fd = open ("/dev/dma_heap/system", O_RDONLY | O_CLOEXEC);
|
||||
return dma_heap_fd != -1;
|
||||
}
|
||||
|
||||
static int
|
||||
allocate_dma_buf (gsize size)
|
||||
{
|
||||
struct dma_heap_allocation_data heap_data;
|
||||
int ret;
|
||||
|
||||
heap_data.len = size;
|
||||
heap_data.fd = 0;
|
||||
heap_data.fd_flags = O_RDWR | O_CLOEXEC;
|
||||
heap_data.heap_flags = 0;
|
||||
|
||||
ret = ioctl (dma_heap_fd, DMA_HEAP_IOCTL_ALLOC, &heap_data);
|
||||
if (ret)
|
||||
g_error ("dma-buf allocation failed");
|
||||
|
||||
return heap_data.fd;
|
||||
}
|
||||
|
||||
static void
|
||||
free_dmabuf (gpointer data)
|
||||
{
|
||||
close (GPOINTER_TO_INT (data));
|
||||
}
|
||||
|
||||
static GdkTexture *
|
||||
make_dmabuf_color_texture (int width,
|
||||
int height,
|
||||
GdkRGBA *color)
|
||||
{
|
||||
int fd;
|
||||
guchar *buf;
|
||||
GdkDmabufTextureBuilder *builder;
|
||||
GdkTexture *texture;
|
||||
gsize stride, size;
|
||||
GError *error = NULL;
|
||||
|
||||
stride = width * 4;
|
||||
size = height * stride;
|
||||
fd = allocate_dma_buf (size);
|
||||
|
||||
buf = mmap (NULL, size, PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
|
||||
for (gsize i = 0; i < width * height * 4; i += 4)
|
||||
{
|
||||
buf[i] = 255 * color->blue;
|
||||
buf[i + 1] = 255 * color->green;
|
||||
buf[i + 2] = 255 * color->red;
|
||||
buf[i + 3] = 255 * color->alpha;
|
||||
}
|
||||
|
||||
munmap (buf, size);
|
||||
|
||||
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, DRM_FORMAT_ARGB8888);
|
||||
gdk_dmabuf_texture_builder_set_modifier (builder, DRM_FORMAT_MOD_LINEAR);
|
||||
gdk_dmabuf_texture_builder_set_n_planes (builder, 1);
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 0, fd);
|
||||
gdk_dmabuf_texture_builder_set_offset (builder, 0, 0);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 0, stride);
|
||||
|
||||
texture = gdk_dmabuf_texture_builder_build (builder, free_dmabuf, GINT_TO_POINTER (fd), &error);
|
||||
if (texture == NULL)
|
||||
g_error ("%s", error->message);
|
||||
|
||||
g_object_unref (builder);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
static GdkTexture *
|
||||
make_shm_color_texture (int width,
|
||||
int height,
|
||||
GdkRGBA *color)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr;
|
||||
guchar *data;
|
||||
gsize stride;
|
||||
GBytes *bytes;
|
||||
GdkTexture *texture;
|
||||
|
||||
stride = 4 * width;
|
||||
data = g_new (guchar, stride * height);
|
||||
|
||||
surface = cairo_image_surface_create_for_data (data,
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
width, height,
|
||||
stride);
|
||||
cr = cairo_create (surface);
|
||||
gdk_cairo_set_source_rgba (cr, color);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_destroy (cr);
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
bytes = g_bytes_new_take (data, stride * height);
|
||||
texture = gdk_memory_texture_new (width, height, GDK_MEMORY_DEFAULT, bytes, stride);
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
static GdkTexture *
|
||||
make_color_texture (int width,
|
||||
int height,
|
||||
GdkRGBA *color)
|
||||
{
|
||||
if (dma_heap_fd != -1)
|
||||
return make_dmabuf_color_texture (width, height, color);
|
||||
else
|
||||
return make_shm_color_texture (width, height, color);
|
||||
}
|
||||
|
||||
static GdkSubsurface *
|
||||
add_subsurface (GtkWidget *window,
|
||||
GdkRGBA *color,
|
||||
const graphene_rect_t *rect)
|
||||
{
|
||||
GdkSurface *surface;
|
||||
GdkSubsurface *subsurface;
|
||||
GdkTexture *texture;
|
||||
|
||||
surface = gtk_widget_get_surface (GTK_WIDGET (window));
|
||||
|
||||
subsurface = gdk_surface_create_subsurface (surface);
|
||||
|
||||
texture = make_color_texture (20, 20, color);
|
||||
|
||||
gdk_subsurface_attach (subsurface, texture, rect);
|
||||
|
||||
g_object_unref (texture);
|
||||
|
||||
return subsurface;
|
||||
}
|
||||
|
||||
static GdkSubsurface *red, *blue;
|
||||
|
||||
static void red_above_blue (GtkButton *button) { gdk_subsurface_place_above (red, blue); }
|
||||
static void red_below_blue (GtkButton *button) { gdk_subsurface_place_below (red, blue); }
|
||||
static void blue_above_red (GtkButton *button) { gdk_subsurface_place_above (blue, red); }
|
||||
static void blue_below_red (GtkButton *button) { gdk_subsurface_place_below (blue, red); }
|
||||
static void red_above_main (GtkButton *button) { gdk_subsurface_place_above (red, NULL); }
|
||||
static void red_below_main (GtkButton *button) { gdk_subsurface_place_below (red, NULL); }
|
||||
static void blue_above_main (GtkButton *button) { gdk_subsurface_place_above (blue, NULL); }
|
||||
static void blue_below_main (GtkButton *button) { gdk_subsurface_place_below (blue, NULL); }
|
||||
|
||||
static GtkWidget *
|
||||
make_button (const char *name, gpointer cb)
|
||||
{
|
||||
GtkWidget *button;
|
||||
|
||||
button = gtk_button_new_with_label (name);
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (cb), NULL);
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
static void
|
||||
change_colors (GtkButton *button)
|
||||
{
|
||||
GdkRGBA color;
|
||||
GdkTexture *texture;
|
||||
|
||||
color.red = g_random_double_range (0.5, 1);
|
||||
color.green = g_random_double_range (0, 0.5);
|
||||
color.blue = g_random_double_range (0, 0.5);
|
||||
color.alpha = 1;
|
||||
|
||||
texture = make_color_texture (20, 20, &color);
|
||||
gdk_subsurface_attach (red, texture, &GRAPHENE_RECT_INIT (200, 100, 50, 50));
|
||||
g_object_unref (texture);
|
||||
|
||||
color.red = g_random_double_range (0, 0.5);
|
||||
color.green = g_random_double_range (0, 0.5);
|
||||
color.blue = g_random_double_range (0.5, 1);
|
||||
color.alpha = 1;
|
||||
|
||||
texture = make_color_texture (20, 20, &color);
|
||||
gdk_subsurface_attach (blue, texture, &GRAPHENE_RECT_INIT (180, 120, 100, 20));
|
||||
g_object_unref (texture);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
make_buttons (void)
|
||||
{
|
||||
GtkWidget *box;
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_box_append (GTK_BOX (box), make_button ("Red above blue", red_above_blue));
|
||||
gtk_box_append (GTK_BOX (box), make_button ("Red below blue", red_below_blue));
|
||||
gtk_box_append (GTK_BOX (box), make_button ("Red above main", red_above_main));
|
||||
gtk_box_append (GTK_BOX (box), make_button ("Red below main", red_below_main));
|
||||
gtk_box_append (GTK_BOX (box), make_button ("Blue above red", blue_above_red));
|
||||
gtk_box_append (GTK_BOX (box), make_button ("Blue below red", blue_below_red));
|
||||
gtk_box_append (GTK_BOX (box), make_button ("Blue above main", blue_above_main));
|
||||
gtk_box_append (GTK_BOX (box), make_button ("Blue below main", blue_below_main));
|
||||
gtk_box_append (GTK_BOX (box), make_button ("Change colors", change_colors));
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
GtkWidget *window, *box;
|
||||
|
||||
gtk_init ();
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 210, -1);
|
||||
gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
|
||||
|
||||
gtk_widget_realize (window);
|
||||
|
||||
if (initialize_dma_heap ())
|
||||
g_print ("Using dambufs\n");
|
||||
else
|
||||
g_print ("Failed to initialize dma-heap, using shm\n");
|
||||
|
||||
red = add_subsurface (window, &(GdkRGBA) { 1, 0, 0, 1 }, &GRAPHENE_RECT_INIT (200, 100, 50, 50));
|
||||
blue = add_subsurface (window, &(GdkRGBA) { 0, 0, 1, 1 }, &GRAPHENE_RECT_INIT (180, 120, 100, 20));
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_window_set_child (GTK_WINDOW (window), box);
|
||||
|
||||
gtk_box_append (GTK_BOX (box), make_buttons ());
|
||||
|
||||
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;
|
||||
}
|
||||
295
testsuite/gdk/dmabuftexture.c
Normal file
295
testsuite/gdk/dmabuftexture.c
Normal file
@@ -0,0 +1,295 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkdisplayprivate.h>
|
||||
#include <gdk/gdkglcontextprivate.h>
|
||||
#include <gdk/gdkdmabuftextureprivate.h>
|
||||
|
||||
#ifdef HAVE_DMABUF
|
||||
#include <drm_fourcc.h>
|
||||
#endif
|
||||
|
||||
static void
|
||||
test_dmabuf_formats (void)
|
||||
{
|
||||
GdkDisplay *display;
|
||||
GdkDmabufFormats *formats;
|
||||
|
||||
display = gdk_display_get_default ();
|
||||
|
||||
formats = gdk_display_get_dmabuf_formats (display);
|
||||
|
||||
#ifdef HAVE_DMABUF
|
||||
/* We always have basic linear formats */
|
||||
g_assert_true (gdk_dmabuf_formats_get_n_formats (formats) >= 6);
|
||||
|
||||
g_assert_true (gdk_dmabuf_formats_contains (formats, DRM_FORMAT_ARGB8888, DRM_FORMAT_MOD_LINEAR));
|
||||
g_assert_true (gdk_dmabuf_formats_contains (formats, DRM_FORMAT_RGBA8888, DRM_FORMAT_MOD_LINEAR));
|
||||
g_assert_true (gdk_dmabuf_formats_contains (formats, DRM_FORMAT_BGRA8888, DRM_FORMAT_MOD_LINEAR));
|
||||
g_assert_true (gdk_dmabuf_formats_contains (formats, DRM_FORMAT_ABGR16161616F, DRM_FORMAT_MOD_LINEAR));
|
||||
g_assert_true (gdk_dmabuf_formats_contains (formats, DRM_FORMAT_RGB888, DRM_FORMAT_MOD_LINEAR));
|
||||
g_assert_true (gdk_dmabuf_formats_contains (formats, DRM_FORMAT_BGR888, DRM_FORMAT_MOD_LINEAR));
|
||||
#else
|
||||
g_assert_true (gdk_dmabuf_formats_get_n_formats (formats) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
make_surface (int width,
|
||||
int height)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr;
|
||||
guchar *data;
|
||||
int stride;
|
||||
|
||||
stride = width * 4;
|
||||
data = g_malloc (stride * height);
|
||||
surface = cairo_image_surface_create_for_data (data,
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
width, height, stride);
|
||||
cr = cairo_create (surface);
|
||||
cairo_set_source_rgb (cr, 1, 0, 0);
|
||||
cairo_paint (cr);
|
||||
cairo_destroy (cr);
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
upload_gl_texture (GdkGLContext *context,
|
||||
cairo_surface_t *surface)
|
||||
{
|
||||
unsigned int id;
|
||||
int width, height;
|
||||
|
||||
width = cairo_image_surface_get_width (surface);
|
||||
height = cairo_image_surface_get_height (surface);
|
||||
|
||||
glGenTextures (1, &id);
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
glBindTexture (GL_TEXTURE_2D, id);
|
||||
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE,
|
||||
cairo_image_surface_get_data (surface));
|
||||
|
||||
g_assert_true (glGetError () == GL_NO_ERROR);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static void
|
||||
export_dmabuf (GdkGLContext *context,
|
||||
unsigned int texture_id,
|
||||
GdkDmabuf *dmabuf)
|
||||
{
|
||||
gboolean ret;
|
||||
|
||||
ret = gdk_gl_context_export_dmabuf (context, texture_id, dmabuf);
|
||||
|
||||
g_assert_true (ret);
|
||||
}
|
||||
|
||||
static void
|
||||
free_dmabuf (gpointer data)
|
||||
{
|
||||
GdkDmabuf *dmabuf = data;
|
||||
|
||||
for (int i = 0; i < dmabuf->n_planes; i++)
|
||||
close (dmabuf->planes[i].fd);
|
||||
|
||||
g_free (dmabuf);
|
||||
}
|
||||
|
||||
static GdkTexture *
|
||||
make_dmabuf_texture (GdkDisplay *display,
|
||||
int width,
|
||||
int height,
|
||||
gboolean premultiplied,
|
||||
GdkDmabuf *dmabuf)
|
||||
{
|
||||
GdkDmabufTextureBuilder *builder;
|
||||
GdkTexture *texture;
|
||||
GdkDmabuf *dmabuf2;
|
||||
|
||||
builder = gdk_dmabuf_texture_builder_new ();
|
||||
|
||||
gdk_dmabuf_texture_builder_set_display (builder, display);
|
||||
gdk_dmabuf_texture_builder_set_width (builder, width);
|
||||
gdk_dmabuf_texture_builder_set_premultiplied (builder, premultiplied);
|
||||
gdk_dmabuf_texture_builder_set_height (builder, height);
|
||||
gdk_dmabuf_texture_builder_set_fourcc (builder, dmabuf->fourcc);
|
||||
gdk_dmabuf_texture_builder_set_modifier (builder, dmabuf->modifier);
|
||||
gdk_dmabuf_texture_builder_set_n_planes (builder, dmabuf->n_planes);
|
||||
for (int i = 0; i < dmabuf->n_planes; i++)
|
||||
{
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, i, dmabuf->planes[i].fd);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, i, dmabuf->planes[i].stride);
|
||||
gdk_dmabuf_texture_builder_set_offset (builder, i, dmabuf->planes[i].offset);
|
||||
}
|
||||
|
||||
dmabuf2 = g_new (GdkDmabuf, 1);
|
||||
memcpy (dmabuf2, dmabuf, sizeof (GdkDmabuf));
|
||||
|
||||
texture = gdk_dmabuf_texture_builder_build (builder, free_dmabuf, dmabuf2, NULL);
|
||||
|
||||
g_assert_true (texture != NULL);
|
||||
|
||||
g_object_unref (builder);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
/* Make a dmabuftexture by exporting a GL texture,
|
||||
* then download it and compare with the original
|
||||
*/
|
||||
static void
|
||||
test_dmabuf_export (void)
|
||||
{
|
||||
GdkDisplay *display;
|
||||
GdkGLContext *context;
|
||||
GError *error = NULL;
|
||||
cairo_surface_t *surface;
|
||||
unsigned int texture_id;
|
||||
GdkDmabuf dmabuf;
|
||||
GdkTexture *texture;
|
||||
guchar *data;
|
||||
|
||||
display = gdk_display_get_default ();
|
||||
if (!gdk_display_prepare_gl (display, &error))
|
||||
{
|
||||
g_test_skip_printf ("no GL support: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gdk_dmabuf_formats_get_n_formats (gdk_display_get_dmabuf_formats (display)) == 0)
|
||||
{
|
||||
g_test_skip_printf ("no dmabuf support");
|
||||
return;
|
||||
}
|
||||
|
||||
context = gdk_display_create_gl_context (display, &error);
|
||||
g_assert_nonnull (context);
|
||||
g_assert_no_error (error);
|
||||
|
||||
gdk_gl_context_realize (context, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
surface = make_surface (64, 64);
|
||||
|
||||
gdk_gl_context_make_current (context);
|
||||
|
||||
texture_id = upload_gl_texture (context, surface);
|
||||
export_dmabuf (context, texture_id, &dmabuf);
|
||||
texture = make_dmabuf_texture (display, 64, 64, TRUE, &dmabuf);
|
||||
|
||||
data = g_malloc (64 * 64 * 4);
|
||||
gdk_texture_download (texture, data, 64 * 4);
|
||||
|
||||
g_assert_true (memcmp (cairo_image_surface_get_data (surface), data, 64 * 64 * 4) == 0);
|
||||
|
||||
g_free (data);
|
||||
g_object_unref (texture);
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
gdk_gl_context_make_current (context);
|
||||
glDeleteTextures (1, &texture_id);
|
||||
|
||||
g_object_unref (context);
|
||||
}
|
||||
|
||||
/* Make a dmabuftexture by exporting a GL texture,
|
||||
* then import it into another GL context, download
|
||||
* the resulting texture, and compare it to the original.
|
||||
*/
|
||||
static void
|
||||
test_dmabuf_import (void)
|
||||
{
|
||||
GdkDisplay *display;
|
||||
GdkGLContext *context;
|
||||
GdkGLContext *context2;
|
||||
GError *error = NULL;
|
||||
cairo_surface_t *surface;
|
||||
unsigned int texture_id;
|
||||
unsigned int texture_id2;
|
||||
GdkDmabuf dmabuf;
|
||||
const GdkDmabuf *dmabuf2;
|
||||
GdkTexture *texture;
|
||||
GdkTexture *texture2;
|
||||
GdkGLTextureBuilder *builder;
|
||||
guchar *data;
|
||||
|
||||
display = gdk_display_get_default ();
|
||||
if (!gdk_display_prepare_gl (display, &error))
|
||||
{
|
||||
g_test_skip_printf ("no GL support: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gdk_dmabuf_formats_get_n_formats (gdk_display_get_dmabuf_formats (display)) == 0)
|
||||
{
|
||||
g_test_skip_printf ("no dmabuf support");
|
||||
return;
|
||||
}
|
||||
|
||||
context = gdk_display_create_gl_context (display, &error);
|
||||
g_assert_nonnull (context);
|
||||
g_assert_no_error (error);
|
||||
|
||||
gdk_gl_context_realize (context, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
surface = make_surface (64, 64);
|
||||
|
||||
gdk_gl_context_make_current (context);
|
||||
|
||||
texture_id = upload_gl_texture (context, surface);
|
||||
export_dmabuf (context, texture_id, &dmabuf);
|
||||
texture = make_dmabuf_texture (display, 64, 64, TRUE, &dmabuf);
|
||||
|
||||
context2 = gdk_display_create_gl_context (display, &error);
|
||||
g_assert_nonnull (context2);
|
||||
g_assert_no_error (error);
|
||||
|
||||
gdk_gl_context_realize (context2, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
dmabuf2 = gdk_dmabuf_texture_get_dmabuf (GDK_DMABUF_TEXTURE (texture));
|
||||
texture_id2 = gdk_gl_context_import_dmabuf (context2, 64, 64, dmabuf2, GL_TEXTURE_2D);
|
||||
|
||||
builder = gdk_gl_texture_builder_new ();
|
||||
gdk_gl_texture_builder_set_context (builder, context2);
|
||||
gdk_gl_texture_builder_set_id (builder, texture_id2);
|
||||
gdk_gl_texture_builder_set_width (builder, 64);
|
||||
gdk_gl_texture_builder_set_height (builder, 64);
|
||||
gdk_gl_texture_builder_set_format (builder, GDK_MEMORY_A8R8G8B8_PREMULTIPLIED);
|
||||
texture2 = gdk_gl_texture_builder_build (builder, NULL, NULL);
|
||||
|
||||
data = g_malloc (64 * 64 * 4);
|
||||
gdk_texture_download (texture2, data, 64 * 4);
|
||||
|
||||
g_assert_true (memcmp (cairo_image_surface_get_data (surface), data, 64 * 64 * 4) == 0);
|
||||
|
||||
g_free (data);
|
||||
g_object_unref (texture);
|
||||
g_object_unref (texture2);
|
||||
|
||||
gdk_gl_context_make_current (context);
|
||||
glDeleteTextures (1, &texture_id);
|
||||
|
||||
g_object_unref (context);
|
||||
g_object_unref (context2);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
gtk_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_test_add_func ("/dmabuf/formats", test_dmabuf_formats);
|
||||
g_test_add_func ("/dmabuf/export", test_dmabuf_export);
|
||||
g_test_add_func ("/dmabuf/import", test_dmabuf_import);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
@@ -52,19 +52,24 @@ foreach t : tests
|
||||
endforeach
|
||||
|
||||
internal_tests = [
|
||||
'image',
|
||||
'texture',
|
||||
'gltexture',
|
||||
{ 'name': 'image' },
|
||||
{ 'name': 'texture' },
|
||||
{ 'name': 'gltexture' },
|
||||
{ 'name': 'dmabuftexture', 'suites': 'failing' },
|
||||
]
|
||||
|
||||
foreach t : internal_tests
|
||||
test_exe = executable(t, '@0@.c'.format(t),
|
||||
test_name = t.get('name')
|
||||
test_exe = executable(test_name,
|
||||
sources: '@0@.c'.format(test_name),
|
||||
c_args: common_cflags + ['-DGTK_COMPILATION'],
|
||||
dependencies: libgtk_static_dep,
|
||||
install: false,
|
||||
)
|
||||
|
||||
test(t, test_exe,
|
||||
suites = ['gdk'] + t.get('suites', [])
|
||||
|
||||
test(test_name, test_exe,
|
||||
args: [ '--tap', '-k' ],
|
||||
protocol: 'tap',
|
||||
env: [
|
||||
@@ -72,6 +77,6 @@ foreach t : internal_tests
|
||||
'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()),
|
||||
'DBUS_SESSION_BUS_ADDRESS=',
|
||||
],
|
||||
suite: 'gdk',
|
||||
suite: suites,
|
||||
)
|
||||
endforeach
|
||||
|
||||
30
testsuite/gsk/compare/texture-scale-filters-3d.node
Normal file
30
testsuite/gsk/compare/texture-scale-filters-3d.node
Normal file
@@ -0,0 +1,30 @@
|
||||
texture-scale {
|
||||
bounds: 4 4 24 24;
|
||||
filter: nearest;
|
||||
texture: "texture1" url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAJ0lEQVQYlWNkYPjwnwEPYMInSbqC\
|
||||
AwwCDAcYBPCb4HAAlc9Ie0cCAB8uBo20gfbVAAAAAElFTkSuQmCC\
|
||||
");
|
||||
}
|
||||
repeat {
|
||||
bounds: 32 0 32 32;
|
||||
child: texture-scale {
|
||||
bounds: 0 0 1 1;
|
||||
filter: nearest;
|
||||
texture: "texture1";
|
||||
}
|
||||
}
|
||||
repeat {
|
||||
bounds: 0 32 32 32;
|
||||
child: texture-scale {
|
||||
bounds: 0 0 1 1;
|
||||
texture: "texture1";
|
||||
}
|
||||
}
|
||||
repeat {
|
||||
bounds: 32 32 32 32;
|
||||
child: texture-scale {
|
||||
bounds: 0 0 1 1;
|
||||
filter: trilinear;
|
||||
texture: "texture1";
|
||||
}
|
||||
}
|
||||
BIN
testsuite/gsk/compare/texture-scale-filters-3d.png
Normal file
BIN
testsuite/gsk/compare/texture-scale-filters-3d.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 295 B |
@@ -98,6 +98,7 @@ compare_render_tests = [
|
||||
'shadow-opacity',
|
||||
'shrink-rounded-border',
|
||||
'stroke',
|
||||
'texture-scale-filters-3d',
|
||||
'texture-scale-magnify-10000x',
|
||||
'texture-scale-magnify-rotate',
|
||||
'texture-scale-stripes',
|
||||
|
||||
Reference in New Issue
Block a user