Compare commits
43 Commits
dboles/Men
...
dmabuf-tex
Author | SHA1 | Date | |
---|---|---|---|
|
b7c69d4ebc | ||
|
04cf18176f | ||
|
5d0aa63489 | ||
|
45e624a9d2 | ||
|
a14264f714 | ||
|
e6b11c8668 | ||
|
2a3fdf78d7 | ||
|
a8a0292f20 | ||
|
e83dcc4cab | ||
|
4957bed573 | ||
|
1297cc188d | ||
|
e584d17aad | ||
|
4936965fb6 | ||
|
e9cc53796e | ||
|
c93efe85dd | ||
|
44daa847ff | ||
|
d23e13aced | ||
|
40102a2b61 | ||
|
49fbbfb6cc | ||
|
fefd856d67 | ||
|
7b5b78b065 | ||
|
005b5042f6 | ||
|
b5149a483f | ||
|
15c43e5284 | ||
|
fc4c0f769c | ||
|
e8ecbb2009 | ||
|
964affb1cc | ||
|
05b51af2d5 | ||
|
28e51c763b | ||
|
ebf8e18319 | ||
|
d8bbe1c296 | ||
|
c1417d3d4a | ||
|
3b4359d76d | ||
|
16806294e3 | ||
|
822425072b | ||
|
7cc1283a26 | ||
|
f4198706d1 | ||
|
8478ba66fe | ||
|
1d58de6ffb | ||
|
f5cec5c0f2 | ||
|
368f2af634 | ||
|
66a9fee071 | ||
|
4c46f5a8f7 |
@@ -217,25 +217,32 @@ macos-x86_64:
|
||||
MESON_FORCE_BACKTRACKE: 1
|
||||
TMPDIR: /Users/Shared/work/tmp
|
||||
SDKROOT: /opt/sdks/MacOSX10.13.4.sdk
|
||||
CCACHE_DIR: /Users/Shared/work/ccache
|
||||
PIP_CACHE_DIR: /Users/Shared/build/cache
|
||||
PIPENV_CACHE_DIR: $PIP_CACHE_DIR
|
||||
PYTHONPYCACHEPREFIX: $PIP_CACHE_DIR
|
||||
EXTRA_MESON_FLAGS: "-Dgobject-introspection:werror=false"
|
||||
before_script:
|
||||
# Not using ccache on purpose as it accelerates the build so much that it
|
||||
# can trigger race conditions in the gobject-introspection subproject.
|
||||
- bash .gitlab-ci/show-info-osx.sh
|
||||
- python3 -m venv .venv
|
||||
- /opt/macports/bin/python3.10 -m venv .venv
|
||||
- ln -s /opt/cmake/CMake.app/Contents/bin/cmake .venv/bin
|
||||
- ln -s /opt/ccache/ccache .venv/bin
|
||||
- ln -s /opt/pkg-config/bin/pkg-config .venv/bin
|
||||
- ln -s /opt/bison/bin/bison .venv/bin
|
||||
- source .venv/bin/activate
|
||||
- pip3 install meson==1.2.0
|
||||
- pip3 install ninja==1.11.1
|
||||
- pip3 install /Users/Shared/build/pkgs/PyGObject-3.44.0-cp310-cp310-macosx_10_13_x86_64.whl
|
||||
/Users/Shared/build/pkgs/pycairo-1.23.0-cp310-cp310-macosx_10_13_x86_64.whl
|
||||
script:
|
||||
- meson setup ${COMMON_MESON_FLAGS}
|
||||
- meson setup
|
||||
${COMMON_MESON_FLAGS}
|
||||
${EXTRA_MESON_FLAGS}
|
||||
-Dx11-backend=false
|
||||
-Dbroadway-backend=true
|
||||
-Dmacos-backend=true
|
||||
-Dmedia-gstreamer=disabled
|
||||
-Dintrospection=disabled
|
||||
-Dintrospection=enabled
|
||||
-Dcpp_std=c++11
|
||||
-Dpixman:tests=disabled
|
||||
-Dlibjpeg-turbo:simd=disabled
|
||||
|
@@ -34,7 +34,7 @@ transition (GtkWidget *widget,
|
||||
{
|
||||
DemoWidget *self = DEMO_WIDGET (widget);
|
||||
DemoLayout *demo_layout = DEMO_LAYOUT (gtk_widget_get_layout_manager (widget));
|
||||
gint64 now = g_get_monotonic_time ();
|
||||
gint64 now = gdk_frame_clock_get_frame_time (frame_clock);
|
||||
|
||||
gtk_widget_queue_allocate (widget);
|
||||
|
||||
@@ -66,11 +66,13 @@ clicked (GtkGestureClick *gesture,
|
||||
gpointer data)
|
||||
{
|
||||
DemoWidget *self = data;
|
||||
GdkFrameClock *frame_clock;
|
||||
|
||||
if (self->tick_id != 0)
|
||||
return;
|
||||
|
||||
self->start_time = g_get_monotonic_time ();
|
||||
frame_clock = gtk_widget_get_frame_clock (GTK_WIDGET (self));
|
||||
self->start_time = gdk_frame_clock_get_frame_time (frame_clock);
|
||||
self->tick_id = gtk_widget_add_tick_callback (GTK_WIDGET (self), transition, NULL, NULL);
|
||||
}
|
||||
|
||||
|
@@ -42,6 +42,9 @@
|
||||
#include <gdk/gdkdevicetool.h>
|
||||
#include <gdk/gdkdisplay.h>
|
||||
#include <gdk/gdkdisplaymanager.h>
|
||||
#include <gdk/gdkdmabufformats.h>
|
||||
#include <gdk/gdkdmabuftexture.h>
|
||||
#include <gdk/gdkdmabuftexturebuilder.h>
|
||||
#include <gdk/gdkdrag.h>
|
||||
#include <gdk/gdkdragsurface.h>
|
||||
#include <gdk/gdkdragsurfacesize.h>
|
||||
|
133
gdk/gdkdisplay.c
133
gdk/gdkdisplay.c
@@ -37,10 +37,17 @@
|
||||
#include "gdkmonitorprivate.h"
|
||||
#include "gdkrectangle.h"
|
||||
#include "gdkvulkancontext.h"
|
||||
#include "gdkdmabuftextureprivate.h"
|
||||
#include "gdkdmabufformatsprivate.h"
|
||||
|
||||
#ifdef HAVE_EGL
|
||||
#include <epoxy/egl.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
#include <drm/drm_fourcc.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -69,6 +76,7 @@ enum
|
||||
PROP_COMPOSITED,
|
||||
PROP_RGBA,
|
||||
PROP_INPUT_SHAPES,
|
||||
PROP_DMABUF_FORMATS,
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
@@ -138,6 +146,10 @@ gdk_display_get_property (GObject *object,
|
||||
g_value_set_boolean (value, gdk_display_supports_input_shapes (display));
|
||||
break;
|
||||
|
||||
case PROP_DMABUF_FORMATS:
|
||||
g_value_set_boxed (value, gdk_display_get_dmabuf_formats (display));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
@@ -239,6 +251,11 @@ gdk_display_class_init (GdkDisplayClass *class)
|
||||
TRUE,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
props[PROP_DMABUF_FORMATS] =
|
||||
g_param_spec_boxed ("dmabuf-formats", NULL, NULL,
|
||||
GDK_TYPE_DMABUF_FORMATS,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (object_class, LAST_PROP, props);
|
||||
|
||||
/**
|
||||
@@ -404,6 +421,8 @@ gdk_display_finalize (GObject *object)
|
||||
|
||||
g_list_free_full (display->seats, g_object_unref);
|
||||
|
||||
g_clear_pointer (&display->dmabuf_formats, gdk_dmabuf_formats_unref);
|
||||
|
||||
G_OBJECT_CLASS (gdk_display_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@@ -1755,6 +1774,8 @@ 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");
|
||||
|
||||
if (self->have_egl_no_config_context)
|
||||
priv->egl_config_high_depth = gdk_display_create_egl_config (self,
|
||||
@@ -1824,6 +1845,118 @@ gdk_display_get_egl_display (GdkDisplay *self)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* GdkDmabufFormat:
|
||||
* @fourcc: the format code
|
||||
* @modifiers: the format modifier
|
||||
*
|
||||
* The `GdkDmabufFormat` struct represents a dma-buf format
|
||||
* as defined in the `drm_fourcc.h` header.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
|
||||
/* To support a drm format, we must be able to import it into GL
|
||||
* using the relevant EGL extensions, and download it into a memory
|
||||
* texture, possibly doing format conversion with shaders (in GSK).
|
||||
*/
|
||||
static void
|
||||
init_dmabuf_formats (GdkDisplay *display)
|
||||
{
|
||||
GdkDisplayPrivate *priv = gdk_display_get_instance_private (display);
|
||||
|
||||
if (display->dmabuf_formats != NULL)
|
||||
return;
|
||||
|
||||
gdk_display_prepare_gl (display, NULL);
|
||||
|
||||
gdk_gl_context_make_current (priv->gl_context);
|
||||
|
||||
#ifdef HAVE_EGL
|
||||
if (priv->egl_display != EGL_NO_DISPLAY &&
|
||||
display->have_egl_dma_buf_import)
|
||||
{
|
||||
int num_formats;
|
||||
int *formats;
|
||||
GArray *array;
|
||||
|
||||
eglQueryDmaBufFormatsEXT (priv->egl_display, 0, NULL, &num_formats);
|
||||
formats = g_new (int, num_formats);
|
||||
eglQueryDmaBufFormatsEXT (priv->egl_display, num_formats, formats, &num_formats);
|
||||
|
||||
array = g_array_new (FALSE, FALSE, sizeof (GdkDmabufFormat));
|
||||
|
||||
for (int i = 0; i < num_formats; i++)
|
||||
{
|
||||
int num_modifiers;
|
||||
uint64_t *modifiers;
|
||||
unsigned int *external_only;
|
||||
|
||||
// if (!gdk_dmabuf_texture_may_support ((unsigned int)formats[i]))
|
||||
// continue;
|
||||
|
||||
eglQueryDmaBufModifiersEXT (priv->egl_display, formats[i], 0, NULL, NULL, &num_modifiers);
|
||||
modifiers = g_new (uint64_t, num_modifiers);
|
||||
external_only = g_new (unsigned int, num_modifiers);
|
||||
eglQueryDmaBufModifiersEXT (priv->egl_display, formats[i], num_modifiers, modifiers, external_only, &num_modifiers);
|
||||
|
||||
for (int j = 0; j < num_modifiers; j++)
|
||||
{
|
||||
if (1 || !external_only[j])
|
||||
{
|
||||
GDK_DEBUG (MISC, "supported EGL dmabuf format %c%c%c%c:%#lx %s",
|
||||
formats[i] & 0xff,
|
||||
(formats[i] >> 8) & 0xff,
|
||||
(formats[i] >> 16) & 0xff,
|
||||
(formats[i] >> 24) & 0xff,
|
||||
modifiers[j],
|
||||
external_only[j] ? "EXT" : "");
|
||||
g_array_append_val (array, ((GdkDmabufFormat){ formats[i], modifiers[j] }));
|
||||
}
|
||||
}
|
||||
g_array_append_val (array, ((GdkDmabufFormat){ formats[i], DRM_FORMAT_MOD_INVALID }));
|
||||
|
||||
g_free (modifiers);
|
||||
}
|
||||
|
||||
g_free (formats);
|
||||
|
||||
display->dmabuf_formats = gdk_dmabuf_formats_new ((GdkDmabufFormat *)array->data, array->len);
|
||||
g_array_free (array, TRUE);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
GdkDmabufFormat *formats;
|
||||
gsize n_formats;
|
||||
|
||||
formats = gdk_dmabuf_texture_get_supported_formats (&n_formats);
|
||||
display->dmabuf_formats = gdk_dmabuf_formats_new (formats, n_formats);
|
||||
g_free (formats);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_display_get_dmabuf_formats:
|
||||
* @display: a `GdkDisplay`
|
||||
*
|
||||
* Returns the dma-buf formats that are supported on this display.
|
||||
*
|
||||
* GTK may use OpenGL or Vulkan to support some formats.
|
||||
* Calling this function will then initialize them if they aren't yet.
|
||||
*
|
||||
* Returns: (transfer none): a `GdkDmabufFormats` object
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
GdkDmabufFormats *
|
||||
gdk_display_get_dmabuf_formats (GdkDisplay *display)
|
||||
{
|
||||
init_dmabuf_formats (display);
|
||||
|
||||
return display->dmabuf_formats;
|
||||
}
|
||||
|
||||
GdkDebugFlags
|
||||
gdk_display_get_debug_flags (GdkDisplay *display)
|
||||
{
|
||||
|
@@ -134,6 +134,10 @@ gboolean gdk_display_get_setting (GdkDisplay *display,
|
||||
const char *name,
|
||||
GValue *value);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
GdkDmabufFormats *
|
||||
gdk_display_get_dmabuf_formats (GdkDisplay *display);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkDisplay, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include "gdksurfaceprivate.h"
|
||||
#include "gdkkeysprivate.h"
|
||||
#include "gdkdeviceprivate.h"
|
||||
#include "gdkdmabufformats.h"
|
||||
|
||||
#ifdef GDK_RENDERING_VULKAN
|
||||
#include <vulkan/vulkan.h>
|
||||
@@ -113,6 +114,9 @@ struct _GdkDisplay
|
||||
guint have_egl_buffer_age : 1;
|
||||
guint have_egl_no_config_context : 1;
|
||||
guint have_egl_pixel_format_float : 1;
|
||||
guint have_egl_dma_buf_import : 1;
|
||||
|
||||
GdkDmabufFormats *dmabuf_formats;
|
||||
};
|
||||
|
||||
struct _GdkDisplayClass
|
||||
|
209
gdk/gdkdmabufformats.c
Normal file
209
gdk/gdkdmabufformats.c
Normal file
@@ -0,0 +1,209 @@
|
||||
/* gdkdmabufformats.c
|
||||
*
|
||||
* Copyright 2023 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <glib-object.h>
|
||||
#include "gdkdmabufformatsprivate.h"
|
||||
|
||||
|
||||
/**
|
||||
* GdkDmabufFormats:
|
||||
*
|
||||
* The `GdkDmabufFormats struct provides information about
|
||||
* supported DMA buffer formats.
|
||||
*
|
||||
* You can query whether a given format is supported with
|
||||
* [method@Gdk.DmabufFormats.contains] and you can iterate
|
||||
* over the list of all supported formats with
|
||||
* [method@Gdk.DmabufFormats.get_n_formats] and
|
||||
* [method@Gdk.DmabufFormats.get_format].
|
||||
*
|
||||
* The list of supported formats is sorted by preference,
|
||||
* with the best formats coming first.
|
||||
*
|
||||
* See [class@Gdk.DmabufTextureBuilder] for more information
|
||||
* about DMA buffers.
|
||||
*
|
||||
* Note that DMA buffers only exist on Linux.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
|
||||
struct _GdkDmabufFormats
|
||||
{
|
||||
int ref_count;
|
||||
|
||||
gsize n_formats;
|
||||
GdkDmabufFormat *formats;
|
||||
};
|
||||
|
||||
G_DEFINE_BOXED_TYPE (GdkDmabufFormats, gdk_dmabuf_formats, gdk_dmabuf_formats_ref, gdk_dmabuf_formats_unref)
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_formats_ref:
|
||||
* @formats: a `GdkDmabufFormats`
|
||||
*
|
||||
* Increases the reference count of @formats.
|
||||
*
|
||||
* Returns: the passed-in object
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
GdkDmabufFormats *
|
||||
gdk_dmabuf_formats_ref (GdkDmabufFormats *formats)
|
||||
{
|
||||
formats->ref_count++;
|
||||
|
||||
return formats;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_formats_unref:
|
||||
* @formats: a `GdkDmabufFormats`
|
||||
*
|
||||
* Decreases the reference count of @formats.
|
||||
*
|
||||
* When the reference count reaches zero,
|
||||
* the object is freed.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
void
|
||||
gdk_dmabuf_formats_unref (GdkDmabufFormats *formats)
|
||||
{
|
||||
formats->ref_count--;
|
||||
|
||||
if (formats->ref_count > 0)
|
||||
return;
|
||||
|
||||
g_free (formats->formats);
|
||||
g_free (formats);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_formats_get_n_formats:
|
||||
* @formats: a `GdkDmabufFormats`
|
||||
*
|
||||
* Returns the number of formats that the @formats object
|
||||
* contains.
|
||||
*
|
||||
* Note that DMA buffers are a Linux concept, so on other
|
||||
* platforms, [method@Gdk.DmabufFormats.get_n_formats] will
|
||||
* always return zero.
|
||||
*
|
||||
* Returns: the number of formats
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
gsize
|
||||
gdk_dmabuf_formats_get_n_formats (GdkDmabufFormats *formats)
|
||||
{
|
||||
return formats->n_formats;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_formats_get_format:
|
||||
* @formats: a `GdkDmabufFormats`
|
||||
* @idx: the index of the format to return
|
||||
* @fourcc: (out): return location for the format code
|
||||
* @modifier: (out): return location for the format modifier
|
||||
*
|
||||
* Gets the fourcc code and modifier for a format
|
||||
* that is contained in @formats.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
void
|
||||
gdk_dmabuf_formats_get_format (GdkDmabufFormats *formats,
|
||||
gsize idx,
|
||||
guint32 *fourcc,
|
||||
guint64 *modifier)
|
||||
{
|
||||
GdkDmabufFormat *format;
|
||||
|
||||
g_return_if_fail (idx < formats->n_formats);
|
||||
g_return_if_fail (fourcc != NULL);
|
||||
g_return_if_fail (modifier != NULL);
|
||||
|
||||
format = &formats->formats[idx];
|
||||
|
||||
*fourcc = format->fourcc;
|
||||
*modifier = format->modifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_format_contains:
|
||||
* @formats: a `GdkDmabufFormats`
|
||||
* @fourcc: a format code
|
||||
* @modfier: a format modifier
|
||||
*
|
||||
* Returns whether a given format is contained in @formats.
|
||||
*
|
||||
* Returns: `TRUE` if the format specified by the arguments
|
||||
* is part of @formats
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
gboolean
|
||||
gdk_dmabuf_formats_contains (GdkDmabufFormats *formats,
|
||||
guint32 fourcc,
|
||||
guint64 modifier)
|
||||
{
|
||||
for (gsize i = 0; i < formats->n_formats; i++)
|
||||
{
|
||||
GdkDmabufFormat *format = &formats->formats[i];
|
||||
|
||||
if (format->fourcc == fourcc && format->modifier == modifier)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gdk_dmabuf_formats_new:
|
||||
* @formats: the formats
|
||||
* @n_formats: the length of @formats
|
||||
*
|
||||
* Creates a new `GdkDmabufFormats struct for
|
||||
* the given formats.
|
||||
*
|
||||
* The @formats array is expected to be sorted
|
||||
* by preference.
|
||||
*
|
||||
* Returns: (transfer full): the new `GdkDmabufFormats`
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
GdkDmabufFormats *
|
||||
gdk_dmabuf_formats_new (GdkDmabufFormat *formats,
|
||||
gsize n_formats)
|
||||
{
|
||||
GdkDmabufFormats *self;
|
||||
|
||||
self = g_new0 (GdkDmabufFormats, 1);
|
||||
|
||||
self->ref_count = 1;
|
||||
self->n_formats = n_formats;
|
||||
self->formats = g_new (GdkDmabufFormat, n_formats);
|
||||
|
||||
memcpy (self->formats, formats, n_formats * sizeof (GdkDmabufFormat));
|
||||
|
||||
return self;
|
||||
}
|
54
gdk/gdkdmabufformats.h
Normal file
54
gdk/gdkdmabufformats.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* gdkdmabufformats.h
|
||||
*
|
||||
* Copyright 2023 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gdk/gdk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gdk/gdktypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GDK_TYPE_DMABUF_FORMATS (gdk_dmabuf_formats_get_type ())
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
GType gdk_dmabuf_formats_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
GdkDmabufFormats * gdk_dmabuf_formats_ref (GdkDmabufFormats *formats);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gdk_dmabuf_formats_unref (GdkDmabufFormats *formats);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
gsize gdk_dmabuf_formats_get_n_formats (GdkDmabufFormats *formats);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gdk_dmabuf_formats_get_format (GdkDmabufFormats *formats,
|
||||
gsize idx,
|
||||
guint32 *fourcc,
|
||||
guint64 *modifier);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
gboolean gdk_dmabuf_formats_contains (GdkDmabufFormats *formats,
|
||||
guint32 fourcc,
|
||||
guint64 modifier);
|
||||
|
||||
G_END_DECLS
|
13
gdk/gdkdmabufformatsprivate.h
Normal file
13
gdk/gdkdmabufformatsprivate.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "gdkdmabufformats.h"
|
||||
|
||||
typedef struct _GdkDmabufFormat GdkDmabufFormat;
|
||||
struct _GdkDmabufFormat
|
||||
{
|
||||
guint32 fourcc;
|
||||
guint64 modifier;
|
||||
};
|
||||
|
||||
GdkDmabufFormats *gdk_dmabuf_formats_new (GdkDmabufFormat *formats,
|
||||
gsize n_formats);
|
444
gdk/gdkdmabuftexture.c
Normal file
444
gdk/gdkdmabuftexture.c
Normal file
@@ -0,0 +1,444 @@
|
||||
/* gdkdmabuftexture.c
|
||||
*
|
||||
* Copyright 2023 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gdkdmabuftextureprivate.h"
|
||||
|
||||
#include "gdkdisplayprivate.h"
|
||||
#include "gdkmemoryformatprivate.h"
|
||||
#include "gdkmemorytextureprivate.h"
|
||||
#include <gdk/gdkglcontext.h>
|
||||
#include <gdk/gdkgltexturebuilder.h>
|
||||
#include <gdk/gdktexturedownloader.h>
|
||||
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <epoxy/egl.h>
|
||||
#endif
|
||||
|
||||
/* We don't include gsk/gsk.h here to avoid a build order problem
|
||||
* with the generated header gskenumtypes.h
|
||||
*/
|
||||
#include <gsk/gskenums.h>
|
||||
#include <gsk/gsktypes.h>
|
||||
#include <gsk/gskrenderer.h>
|
||||
#include <gsk/gskrendernode.h>
|
||||
#include <gsk/gl/gskglrenderer.h>
|
||||
|
||||
/**
|
||||
* GdkDmabufTexture:
|
||||
*
|
||||
* A `GdkTexture` representing a dma-buf object.
|
||||
*
|
||||
* To create a `GdkDmabufTexture`, use the auxiliary
|
||||
* [class@Gdk.DmabufTextureBuilder] object.
|
||||
*
|
||||
* Dma-buf textures can only be created on Linux.
|
||||
*/
|
||||
|
||||
struct _GdkDmabufTexture
|
||||
{
|
||||
GdkTexture parent_instance;
|
||||
|
||||
GdkDisplay *display;
|
||||
|
||||
guint32 fourcc;
|
||||
guint64 modifier;
|
||||
|
||||
unsigned int n_planes;
|
||||
|
||||
/* Per-plane properties */
|
||||
int fds[MAX_DMABUF_PLANES];
|
||||
unsigned int strides[MAX_DMABUF_PLANES];
|
||||
unsigned int offsets[MAX_DMABUF_PLANES];
|
||||
|
||||
GDestroyNotify destroy;
|
||||
gpointer data;
|
||||
};
|
||||
|
||||
struct _GdkDmabufTextureClass
|
||||
{
|
||||
GdkTextureClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GdkDmabufTexture, gdk_dmabuf_texture, GDK_TYPE_TEXTURE)
|
||||
|
||||
static void
|
||||
gdk_dmabuf_texture_init (GdkDmabufTexture *self)
|
||||
{
|
||||
self->fds[0] = self->fds[1] = self->fds[2] = self->fds[3] = -1;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_dmabuf_texture_dispose (GObject *object)
|
||||
{
|
||||
GdkDmabufTexture *self = GDK_DMABUF_TEXTURE (object);
|
||||
|
||||
if (self->destroy)
|
||||
self->destroy (self->data);
|
||||
|
||||
G_OBJECT_CLASS (gdk_dmabuf_texture_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void gdk_dmabuf_texture_download (GdkTexture *texture,
|
||||
GdkMemoryFormat format,
|
||||
guchar *data,
|
||||
gsize stride);
|
||||
|
||||
static void
|
||||
gdk_dmabuf_texture_class_init (GdkDmabufTextureClass *klass)
|
||||
{
|
||||
GdkTextureClass *texture_class = GDK_TEXTURE_CLASS (klass);
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
texture_class->download = gdk_dmabuf_texture_download;
|
||||
|
||||
gobject_class->dispose = gdk_dmabuf_texture_dispose;
|
||||
}
|
||||
|
||||
guint32
|
||||
gdk_dmabuf_texture_get_fourcc (GdkDmabufTexture *texture)
|
||||
{
|
||||
return texture->fourcc;
|
||||
}
|
||||
|
||||
guint64
|
||||
gdk_dmabuf_texture_get_modifier (GdkDmabufTexture *texture)
|
||||
{
|
||||
return texture->modifier;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
gdk_dmabuf_texture_get_n_planes (GdkDmabufTexture *texture)
|
||||
{
|
||||
return texture->n_planes;
|
||||
}
|
||||
|
||||
int *
|
||||
gdk_dmabuf_texture_get_fds (GdkDmabufTexture *texture)
|
||||
{
|
||||
return texture->fds;
|
||||
}
|
||||
|
||||
unsigned int *
|
||||
gdk_dmabuf_texture_get_strides (GdkDmabufTexture *texture)
|
||||
{
|
||||
return texture->strides;
|
||||
}
|
||||
|
||||
unsigned int *
|
||||
gdk_dmabuf_texture_get_offsets (GdkDmabufTexture *texture)
|
||||
{
|
||||
return texture->offsets;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
|
||||
typedef struct _GdkDrmFormatInfo GdkDrmFormatInfo;
|
||||
struct _GdkDrmFormatInfo
|
||||
{
|
||||
guint32 fourcc;
|
||||
GdkMemoryFormat premultiplied_memory_format;
|
||||
GdkMemoryFormat unpremultiplied_memory_format;
|
||||
gboolean requires_gl;
|
||||
};
|
||||
|
||||
static GdkDrmFormatInfo supported_formats[] = {
|
||||
{ DRM_FORMAT_ARGB8888, GDK_MEMORY_A8R8G8B8_PREMULTIPLIED, GDK_MEMORY_A8R8G8B8, FALSE },
|
||||
{ DRM_FORMAT_RGBA8888, GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, GDK_MEMORY_R8G8B8A8, FALSE },
|
||||
{ DRM_FORMAT_BGRA8888, GDK_MEMORY_B8G8R8A8_PREMULTIPLIED, GDK_MEMORY_B8G8R8A8, FALSE },
|
||||
{ DRM_FORMAT_ABGR16161616F, GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED, GDK_MEMORY_R16G16B16A16_FLOAT, FALSE },
|
||||
{ DRM_FORMAT_RGB888, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8, FALSE },
|
||||
{ DRM_FORMAT_BGR888, GDK_MEMORY_B8G8R8, GDK_MEMORY_B8G8R8, FALSE },
|
||||
};
|
||||
|
||||
static GdkDrmFormatInfo *
|
||||
get_drm_format_info (guint32 fourcc)
|
||||
{
|
||||
for (int i = 0; i < G_N_ELEMENTS (supported_formats); i++)
|
||||
{
|
||||
if (supported_formats[i].fourcc == fourcc)
|
||||
return &supported_formats[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
do_indirect_download (GdkDmabufTexture *self,
|
||||
GdkMemoryFormat format,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
GskRenderer *renderer;
|
||||
int width, height;
|
||||
GskRenderNode *node;
|
||||
GdkTexture *gl_texture;
|
||||
GdkTextureDownloader *downloader;
|
||||
GError *error = NULL;
|
||||
|
||||
GDK_DEBUG (MISC, "Using gsk_renderer_render_texture import for downloading a dmabuf");
|
||||
|
||||
g_assert (GDK_IS_DISPLAY (self->display));
|
||||
g_assert (GDK_IS_GL_CONTEXT (gdk_display_get_gl_context (self->display)));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
width = gdk_texture_get_width (GDK_TEXTURE (self));
|
||||
height = gdk_texture_get_height (GDK_TEXTURE (self));
|
||||
|
||||
node = gsk_texture_node_new (GDK_TEXTURE (self), &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gl_texture = gsk_renderer_render_texture (renderer, node, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gsk_render_node_unref (node);
|
||||
|
||||
gsk_renderer_unrealize (renderer);
|
||||
g_object_unref (renderer);
|
||||
|
||||
downloader = gdk_texture_downloader_new (gl_texture);
|
||||
|
||||
gdk_texture_downloader_set_format (downloader, format);
|
||||
|
||||
gdk_texture_downloader_download_into (downloader, data, stride);
|
||||
|
||||
gdk_texture_downloader_free (downloader);
|
||||
g_object_unref (gl_texture);
|
||||
}
|
||||
|
||||
static void
|
||||
do_direct_download (GdkDmabufTexture *self,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
gsize size;
|
||||
unsigned int height;
|
||||
gsize src_stride;
|
||||
guchar *src_data;
|
||||
int bpp;
|
||||
|
||||
GDK_DEBUG (MISC, "Using mmap() and memcpy() for downloading a dmabuf");
|
||||
|
||||
height = gdk_texture_get_height (GDK_TEXTURE (self));
|
||||
bpp = gdk_memory_format_bytes_per_pixel (gdk_texture_get_format (GDK_TEXTURE (self)));
|
||||
|
||||
src_stride = self->strides[0];
|
||||
size = self->strides[0] * height;
|
||||
|
||||
if (ioctl (self->fds[0], DMA_BUF_IOCTL_SYNC, &(struct dma_buf_sync) { DMA_BUF_SYNC_START|DMA_BUF_SYNC_READ }) < 0)
|
||||
g_warning ("Failed to sync dma-buf: %s", g_strerror (errno));
|
||||
|
||||
src_data = mmap (NULL, size, PROT_READ, MAP_SHARED, self->fds[0], self->offsets[0]);
|
||||
|
||||
if (stride == src_stride)
|
||||
memcpy (data, src_data, size);
|
||||
else
|
||||
{
|
||||
for (unsigned int i = 0; i < height; i++)
|
||||
memcpy (data + i * stride, src_data + i * src_stride, height * bpp);
|
||||
}
|
||||
|
||||
munmap (src_data, size);
|
||||
|
||||
if (ioctl (self->fds[0], DMA_BUF_IOCTL_SYNC, &(struct dma_buf_sync) { DMA_BUF_SYNC_END|DMA_BUF_SYNC_READ }) < 0)
|
||||
g_warning ("Failed to sync dma-buf: %s", g_strerror (errno));
|
||||
}
|
||||
|
||||
#endif /* HAVE_LINUX_DMA_BUF_H */
|
||||
|
||||
GdkDmabufFormat *
|
||||
gdk_dmabuf_texture_get_supported_formats (gsize *n_formats)
|
||||
{
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
|
||||
GdkDmabufFormat *formats;
|
||||
|
||||
*n_formats = G_N_ELEMENTS (supported_formats);
|
||||
formats = g_new (GdkDmabufFormat, sizeof (GdkDmabufFormat) * *n_formats);
|
||||
|
||||
for (gsize i = 0; i < *n_formats; i++)
|
||||
{
|
||||
formats[i].fourcc = supported_formats[i].fourcc;
|
||||
formats[i].modifier = DRM_FORMAT_MOD_LINEAR;
|
||||
}
|
||||
|
||||
return formats;
|
||||
|
||||
#else
|
||||
|
||||
*n_formats = 0;
|
||||
return NULL;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_dmabuf_texture_may_support (guint32 fourcc)
|
||||
{
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
|
||||
for (gsize i = 0; i < G_N_ELEMENTS (supported_formats); i++)
|
||||
{
|
||||
if (supported_formats[i].fourcc == fourcc)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_dmabuf_texture_download (GdkTexture *texture,
|
||||
GdkMemoryFormat format,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
GdkDmabufTexture *self = GDK_DMABUF_TEXTURE (texture);
|
||||
GdkMemoryFormat src_format = gdk_texture_get_format (texture);
|
||||
GdkDrmFormatInfo *info;
|
||||
|
||||
info = get_drm_format_info (self->fourcc);
|
||||
|
||||
g_assert (info != NULL);
|
||||
|
||||
if (info->requires_gl || self->n_planes > 1 || self->modifier != DRM_FORMAT_MOD_LINEAR)
|
||||
do_indirect_download (self, format, data, stride);
|
||||
else if (format == src_format)
|
||||
do_direct_download (self, data, stride);
|
||||
else
|
||||
{
|
||||
unsigned int width, height;
|
||||
guchar *src_data;
|
||||
gsize src_stride;
|
||||
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
|
||||
src_stride = self->strides[0];
|
||||
src_data = g_new (guchar, src_stride * height);
|
||||
|
||||
do_direct_download (self, src_data, src_stride);
|
||||
|
||||
gdk_memory_convert (data, stride, format,
|
||||
src_data, src_stride, src_format,
|
||||
width, height);
|
||||
|
||||
g_free (src_data);
|
||||
}
|
||||
#endif /* HAVE_LINUX_DMA_BUF_H */
|
||||
}
|
||||
|
||||
static gboolean
|
||||
display_supports_format (GdkDisplay *display,
|
||||
guint32 fourcc,
|
||||
guint64 modifier)
|
||||
{
|
||||
GdkDmabufFormats *formats;
|
||||
|
||||
if (!display)
|
||||
return FALSE;
|
||||
|
||||
formats = gdk_display_get_dmabuf_formats (display);
|
||||
|
||||
return gdk_dmabuf_formats_contains (formats, fourcc, modifier);
|
||||
}
|
||||
|
||||
GdkTexture *
|
||||
gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
|
||||
GDestroyNotify destroy,
|
||||
gpointer data)
|
||||
{
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
GdkDmabufTexture *self;
|
||||
GdkTexture *update_texture;
|
||||
GdkDisplay *display = gdk_dmabuf_texture_builder_get_display (builder);
|
||||
guint32 fourcc = gdk_dmabuf_texture_builder_get_fourcc (builder);
|
||||
guint64 modifier = gdk_dmabuf_texture_builder_get_modifier (builder);
|
||||
gboolean premultiplied = gdk_dmabuf_texture_builder_get_premultiplied (builder);
|
||||
unsigned int n_planes = gdk_dmabuf_texture_builder_get_n_planes (builder);
|
||||
GdkDrmFormatInfo *info;
|
||||
|
||||
info = get_drm_format_info (fourcc);
|
||||
|
||||
if ((!info || info->requires_gl || n_planes > 1 || modifier != DRM_FORMAT_MOD_LINEAR) && !display_supports_format (display, fourcc, modifier))
|
||||
{
|
||||
g_warning ("Unsupported dmabuf format %c%c%c%c:%#lx",
|
||||
fourcc & 0xff, (fourcc >> 8) & 0xff, (fourcc >> 16) & 0xff, (fourcc >> 24) & 0xff, modifier);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GDK_DEBUG (MISC, "Dmabuf texture in format %c%c%c%c:%#lx",
|
||||
fourcc & 0xff, (fourcc >> 8) & 0xff, (fourcc >> 16) & 0xff, (fourcc >> 24) & 0xff, modifier);
|
||||
|
||||
self = g_object_new (GDK_TYPE_DMABUF_TEXTURE,
|
||||
"width", gdk_dmabuf_texture_builder_get_width (builder),
|
||||
"height", gdk_dmabuf_texture_builder_get_height (builder),
|
||||
NULL);
|
||||
|
||||
self->destroy = destroy;
|
||||
self->data = data;
|
||||
|
||||
if (info)
|
||||
GDK_TEXTURE (self)->format = premultiplied ? info->premultiplied_memory_format
|
||||
: info->unpremultiplied_memory_format;
|
||||
else
|
||||
GDK_TEXTURE (self)->format = premultiplied ? GDK_MEMORY_A8R8G8B8_PREMULTIPLIED : GDK_MEMORY_A8R8G8B8;
|
||||
|
||||
g_set_object (&self->display, display);
|
||||
|
||||
self->fourcc = fourcc;
|
||||
self->modifier = modifier;
|
||||
self->n_planes = n_planes;
|
||||
|
||||
memcpy (self->fds, gdk_dmabuf_texture_builder_get_fds (builder), sizeof (int) * MAX_DMABUF_PLANES);
|
||||
memcpy (self->strides, gdk_dmabuf_texture_builder_get_strides (builder), sizeof (unsigned int) * MAX_DMABUF_PLANES);
|
||||
memcpy (self->offsets, gdk_dmabuf_texture_builder_get_offsets (builder), sizeof (unsigned int) * MAX_DMABUF_PLANES);
|
||||
|
||||
update_texture = gdk_dmabuf_texture_builder_get_update_texture (builder);
|
||||
if (update_texture)
|
||||
{
|
||||
cairo_region_t *update_region = gdk_dmabuf_texture_builder_get_update_region (builder);
|
||||
if (update_region)
|
||||
{
|
||||
update_region = cairo_region_copy (update_region);
|
||||
cairo_region_intersect_rectangle (update_region,
|
||||
&(cairo_rectangle_int_t) {
|
||||
0, 0,
|
||||
update_texture->width, update_texture->height
|
||||
});
|
||||
gdk_texture_set_diff (GDK_TEXTURE (self), update_texture, update_region);
|
||||
}
|
||||
}
|
||||
|
||||
return GDK_TEXTURE (self);
|
||||
|
||||
#else /* !HAVE_LINUX_DMA_BUF_H */
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
43
gdk/gdkdmabuftexture.h
Normal file
43
gdk/gdkdmabuftexture.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/* gdkdmabuftexture.h
|
||||
*
|
||||
* Copyright 2023 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gdk/gdk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gdk/gdktypes.h>
|
||||
#include <gdk/gdktexture.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GDK_TYPE_DMABUF_TEXTURE (gdk_dmabuf_texture_get_type ())
|
||||
|
||||
#define GDK_DMABUF_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_DMABUF_TEXTURE, GdkDmabufTexture))
|
||||
#define GDK_IS_DMABUF_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_DMABUF_TEXTURE))
|
||||
|
||||
typedef struct _GdkDmabufTexture GdkDmabufTexture;
|
||||
typedef struct _GdkDmabufTextureClass GdkDmabufTextureClass;
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
GType gdk_dmabuf_texture_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkDmabufTexture, g_object_unref)
|
||||
|
||||
G_END_DECLS
|
992
gdk/gdkdmabuftexturebuilder.c
Normal file
992
gdk/gdkdmabuftexturebuilder.c
Normal file
@@ -0,0 +1,992 @@
|
||||
/*
|
||||
* Copyright © 2023 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gdkdmabuftexturebuilder.h"
|
||||
|
||||
#include "gdkdisplay.h"
|
||||
#include "gdkenumtypes.h"
|
||||
#include "gdkdmabuftextureprivate.h"
|
||||
|
||||
#include <cairo-gobject.h>
|
||||
|
||||
|
||||
struct _GdkDmabufTextureBuilder
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GdkDisplay *display;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
guint32 fourcc;
|
||||
guint64 modifier;
|
||||
gboolean premultiplied;
|
||||
|
||||
unsigned int n_planes;
|
||||
|
||||
/* per-plane properties */
|
||||
int fds[MAX_DMABUF_PLANES];
|
||||
unsigned int strides[MAX_DMABUF_PLANES];
|
||||
unsigned int offsets[MAX_DMABUF_PLANES];
|
||||
|
||||
GdkTexture *update_texture;
|
||||
cairo_region_t *update_region;
|
||||
};
|
||||
|
||||
struct _GdkDmabufTextureBuilderClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
/**
|
||||
* GdkDmabufTextureBuilder:
|
||||
*
|
||||
* `GdkDmabufTextureBuilder` is a builder used to construct [class@Gdk.Texture]
|
||||
* objects from DMA buffers.
|
||||
*
|
||||
* DMA buffers are commonly called **_dma-bufs_**.
|
||||
*
|
||||
* DMA buffers a feature of the Linux kernel to enable efficient buffer and
|
||||
* memory sharing between hardware such as codecs, GPUs, displays, cameras and the
|
||||
* kernel drivers controlling them. For example, a decoder may want its output to
|
||||
* be directly shared with the display server for rendering without a copy.
|
||||
*
|
||||
* Any device driver which participates in DMA buffer sharing, can do so as either
|
||||
* the exporter or importer of buffers (or both).
|
||||
*
|
||||
* The memory that is shared via DMA buffers is usually stored in non-system memory
|
||||
* (maybe in device's local memory or something else not directly accessible by the
|
||||
* CPU), and accessing this memory from the CPU may have higher than usual overhead.
|
||||
*
|
||||
* In particular for graphics data, it is not uncommon that data consists of multiple
|
||||
* separate blocks of memory, for example one block for each of the red, green and
|
||||
* blue channels. These blocks are called **_planes_**. DMA buffers can have up to
|
||||
* four planes. Even if the memory is a single block, the data can be organized in
|
||||
* multiple planes, by specifying offsets from the beginning of the data.
|
||||
*
|
||||
* DMA buffers are exposed to user-space as file descriptors allowing to pass them
|
||||
* between processes. If a DMA buffer has multiple planes, there is one file
|
||||
* descriptor per plane.
|
||||
*
|
||||
* 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)
|
||||
* 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.
|
||||
*
|
||||
* The operation of `GdkDmabufTextureBuilder` is quite simple: Create a texture builder,
|
||||
* set all the necessary properties, and then call [method@Gdk.DmabufTextureBuilder.build]
|
||||
* 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
|
||||
*
|
||||
* `GdkDmabufTextureBuilder` can be used for quick one-shot construction of
|
||||
* textures as well as kept around and reused to construct multiple textures.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_DISPLAY,
|
||||
PROP_WIDTH,
|
||||
PROP_HEIGHT,
|
||||
PROP_FOURCC,
|
||||
PROP_MODIFIER,
|
||||
PROP_PREMULTIPLIED,
|
||||
PROP_N_PLANES,
|
||||
PROP_UPDATE_REGION,
|
||||
PROP_UPDATE_TEXTURE,
|
||||
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GdkDmabufTextureBuilder, gdk_dmabuf_texture_builder, G_TYPE_OBJECT)
|
||||
|
||||
static GParamSpec *properties[N_PROPS] = { NULL, };
|
||||
|
||||
static void
|
||||
gdk_dmabuf_texture_builder_dispose (GObject *object)
|
||||
{
|
||||
GdkDmabufTextureBuilder *self = GDK_DMABUF_TEXTURE_BUILDER (object);
|
||||
|
||||
g_clear_object (&self->update_texture);
|
||||
g_clear_pointer (&self->update_region, cairo_region_destroy);
|
||||
|
||||
G_OBJECT_CLASS (gdk_dmabuf_texture_builder_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_dmabuf_texture_builder_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GdkDmabufTextureBuilder *self = GDK_DMABUF_TEXTURE_BUILDER (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_DISPLAY:
|
||||
g_value_set_object (value, self->display);
|
||||
break;
|
||||
|
||||
case PROP_WIDTH:
|
||||
g_value_set_uint (value, self->width);
|
||||
break;
|
||||
|
||||
case PROP_HEIGHT:
|
||||
g_value_set_uint (value, self->height);
|
||||
break;
|
||||
|
||||
case PROP_FOURCC:
|
||||
g_value_set_uint (value, self->fourcc);
|
||||
break;
|
||||
|
||||
case PROP_MODIFIER:
|
||||
g_value_set_uint64 (value, self->modifier);
|
||||
break;
|
||||
|
||||
case PROP_PREMULTIPLIED:
|
||||
g_value_set_boolean (value, self->premultiplied);
|
||||
break;
|
||||
|
||||
case PROP_N_PLANES:
|
||||
g_value_set_uint (value, self->n_planes);
|
||||
break;
|
||||
|
||||
case PROP_UPDATE_REGION:
|
||||
g_value_set_boxed (value, self->update_region);
|
||||
break;
|
||||
|
||||
case PROP_UPDATE_TEXTURE:
|
||||
g_value_set_object (value, self->update_texture);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_dmabuf_texture_builder_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GdkDmabufTextureBuilder *self = GDK_DMABUF_TEXTURE_BUILDER (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_DISPLAY:
|
||||
gdk_dmabuf_texture_builder_set_display (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_WIDTH:
|
||||
gdk_dmabuf_texture_builder_set_width (self, g_value_get_uint (value));
|
||||
break;
|
||||
|
||||
case PROP_HEIGHT:
|
||||
gdk_dmabuf_texture_builder_set_height (self, g_value_get_uint (value));
|
||||
break;
|
||||
|
||||
case PROP_FOURCC:
|
||||
gdk_dmabuf_texture_builder_set_fourcc (self, g_value_get_uint (value));
|
||||
break;
|
||||
|
||||
case PROP_MODIFIER:
|
||||
gdk_dmabuf_texture_builder_set_modifier (self, g_value_get_uint64 (value));
|
||||
break;
|
||||
|
||||
case PROP_PREMULTIPLIED:
|
||||
gdk_dmabuf_texture_builder_set_premultiplied (self, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
case PROP_N_PLANES:
|
||||
gdk_dmabuf_texture_builder_set_n_planes (self, g_value_get_uint (value));
|
||||
break;
|
||||
|
||||
case PROP_UPDATE_REGION:
|
||||
gdk_dmabuf_texture_builder_set_update_region (self, g_value_get_boxed (value));
|
||||
break;
|
||||
|
||||
case PROP_UPDATE_TEXTURE:
|
||||
gdk_dmabuf_texture_builder_set_update_texture (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_dmabuf_texture_builder_class_init (GdkDmabufTextureBuilderClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->dispose = gdk_dmabuf_texture_builder_dispose;
|
||||
gobject_class->get_property = gdk_dmabuf_texture_builder_get_property;
|
||||
gobject_class->set_property = gdk_dmabuf_texture_builder_set_property;
|
||||
|
||||
/**
|
||||
* GdkDmabufTextureBuilder:display: (attributes org.gdk.Property.get=gdk_dmabuf_texture_builder_get_display org.gdk.Property.set=gdk_dmabuf_texture_builder_set_display)
|
||||
*
|
||||
* The display that this texture will be used on.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
properties[PROP_DISPLAY] =
|
||||
g_param_spec_object ("display", NULL, NULL,
|
||||
GDK_TYPE_DISPLAY,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GdkDmabufTextureBuilder:width: (attributes org.gdk.Property.get=gdk_dmabuf_texture_builder_get_width org.gdk.Property.set=gdk_dmabuf_texture_builder_set_width)
|
||||
*
|
||||
* The width of the texture.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
properties[PROP_WIDTH] =
|
||||
g_param_spec_uint ("width", NULL, NULL,
|
||||
0, G_MAXUINT, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GdkDmabufTextureBuilder:height: (attributes org.gdk.Property.get=gdk_dmabuf_texture_builder_get_height org.gdk.Property.set=gdk_dmabuf_texture_builder_set_height)
|
||||
*
|
||||
* The height of the texture.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
properties[PROP_HEIGHT] =
|
||||
g_param_spec_uint ("height", NULL, NULL,
|
||||
0, G_MAXUINT, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GdkDmabufTextureBuilder:fourcc: (attributes org.gdk.Property.get=gdk_dmabuf_texture_builder_get_fourcc org.gdk.Property.set=gdk_dmabuf_texture_builder_set_fourcc)
|
||||
*
|
||||
* The format of the texture, as a fourcc value.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
properties[PROP_FOURCC] =
|
||||
g_param_spec_uint ("fourcc", NULL, NULL,
|
||||
0, 0xffffffff, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GdkDmabufTextureBuilder:modifier:
|
||||
*
|
||||
* The modifier.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
properties[PROP_MODIFIER] =
|
||||
g_param_spec_uint64 ("modifier", NULL, NULL,
|
||||
0, G_MAXUINT, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GdkDmabufTextureBuilder:premultiplied:
|
||||
*
|
||||
* Whether the alpha channel is premultiplied into the others.
|
||||
*
|
||||
* Only relevant if the format has alpha.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
properties[PROP_PREMULTIPLIED] =
|
||||
g_param_spec_boolean ("premultiplied", NULL, NULL,
|
||||
TRUE,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GdkDmabufTextureBuilder:n-planes: (attributes org.gdk.Property.get=gdk_dmabuf_texture_builder_get_n_planes org.gdk.Property.set=gdk_dmabuf_texture_builder_set_n_planes)
|
||||
*
|
||||
* The number of planes of the texture.
|
||||
*
|
||||
* Note that you can set properties for other planes,
|
||||
* but they will be ignored when constructing the texture.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
properties[PROP_N_PLANES] =
|
||||
g_param_spec_uint ("n-planes", NULL, NULL,
|
||||
0, 4, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GdkDmabufTextureBuilder:update-region: (attributes org.gdk.Property.get=gdk_dmabuf_texture_builder_get_update_region org.gdk.Property.set=gdk_dmabuf_texture_builder_set_update_region)
|
||||
*
|
||||
* The update region for [property@Gdk.GLTextureBuilder:update-texture].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
properties[PROP_UPDATE_REGION] =
|
||||
g_param_spec_boxed ("update-region", NULL, NULL,
|
||||
CAIRO_GOBJECT_TYPE_REGION,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GdkDmabufTextureBuilder:update-texture: (attributes org.gdk.Property.get=gdk_dmabuf_texture_builder_get_update_texture org.gdk.Property.set=gdk_dmabuf_texture_builder_set_update_texture)
|
||||
*
|
||||
* The texture [property@Gdk.GLTextureBuilder:update-region] is an update for.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
properties[PROP_UPDATE_TEXTURE] =
|
||||
g_param_spec_object ("update-texture", NULL, NULL,
|
||||
GDK_TYPE_TEXTURE,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_dmabuf_texture_builder_init (GdkDmabufTextureBuilder *self)
|
||||
{
|
||||
self->fds[0] = self->fds[1] = self->fds[2] = self->fds[3] = -1;
|
||||
self->premultiplied = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_new: (constructor):
|
||||
*
|
||||
* Creates a new texture builder.
|
||||
*
|
||||
* Returns: the new `GdkTextureBuilder`
|
||||
*
|
||||
* Since: 4.14
|
||||
**/
|
||||
GdkDmabufTextureBuilder *
|
||||
gdk_dmabuf_texture_builder_new (void)
|
||||
{
|
||||
return g_object_new (GDK_TYPE_DMABUF_TEXTURE_BUILDER, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_get_display:
|
||||
* @self: a `GdkDmabufTextureBuilder
|
||||
*
|
||||
* Returns the display that this texture builder is
|
||||
* associated with.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): the display
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
GdkDisplay *
|
||||
gdk_dmabuf_texture_builder_get_display (GdkDmabufTextureBuilder *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), NULL);
|
||||
|
||||
return self->display;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_set_display:
|
||||
* @self: a `GdkDmabufTextureBuilder
|
||||
* @display: the display
|
||||
*
|
||||
* Sets the display that this texture builder is
|
||||
* associated with.
|
||||
*
|
||||
* The display is used to determine the supported
|
||||
* dma-buf formats.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
void
|
||||
gdk_dmabuf_texture_builder_set_display (GdkDmabufTextureBuilder *self,
|
||||
GdkDisplay *display)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
|
||||
|
||||
if (g_set_object (&self->display, display))
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DISPLAY]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_get_width: (attributes org.gdk.Method.get_property=width)
|
||||
* @self: a `GdkDmabufTextureBuilder`
|
||||
*
|
||||
* Gets the width previously set via gdk_dmabuf_texture_builder_set_width() or
|
||||
* 0 if the width wasn't set.
|
||||
*
|
||||
* Returns: The width
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
unsigned int
|
||||
gdk_dmabuf_texture_builder_get_width (GdkDmabufTextureBuilder *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), 0);
|
||||
|
||||
return self->width;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_set_width: (attributes org.gdk.Method.set_property=width)
|
||||
* @self: a `GdkDmabufTextureBuilder`
|
||||
* @width: The texture's width or 0 to unset
|
||||
*
|
||||
* Sets the width of the texture.
|
||||
*
|
||||
* The width must be set before calling [method@Gdk.GLTextureBuilder.build].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
void
|
||||
gdk_dmabuf_texture_builder_set_width (GdkDmabufTextureBuilder *self,
|
||||
unsigned int width)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
|
||||
|
||||
if (self->width == width)
|
||||
return;
|
||||
|
||||
self->width = width;
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_WIDTH]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_get_height: (attributes org.gdk.Method.get_property=height)
|
||||
* @self: a `GdkDmabufTextureBuilder`
|
||||
*
|
||||
* Gets the height previously set via gdk_dmabuf_texture_builder_set_height() or
|
||||
* 0 if the height wasn't set.
|
||||
*
|
||||
* Returns: The height
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
unsigned int
|
||||
gdk_dmabuf_texture_builder_get_height (GdkDmabufTextureBuilder *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), 0);
|
||||
|
||||
return self->height;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_set_height: (attributes org.gdk.Method.set_property=height)
|
||||
* @self: a `GdkDmabufTextureBuilder`
|
||||
* @height: the texture's height or 0 to unset
|
||||
*
|
||||
* Sets the height of the texture.
|
||||
*
|
||||
* The height must be set before calling [method@Gdk.GLTextureBuilder.build].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
void
|
||||
gdk_dmabuf_texture_builder_set_height (GdkDmabufTextureBuilder *self,
|
||||
unsigned int height)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
|
||||
|
||||
if (self->height == height)
|
||||
return;
|
||||
|
||||
self->height = height;
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HEIGHT]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_get_fourcc: (attributes org.gdk.Method.get_property=fourcc)
|
||||
* @self: a `GdkDmabufTextureBuilder`
|
||||
*
|
||||
* Gets the format previously set via gdk_dmabuf_texture_builder_set_fourcc()
|
||||
* or 0 if the format wasn't set.
|
||||
*
|
||||
* The format is specified as a fourcc code.
|
||||
*
|
||||
* Returns: The format
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
guint32
|
||||
gdk_dmabuf_texture_builder_get_fourcc (GdkDmabufTextureBuilder *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), 0);
|
||||
|
||||
return self->fourcc;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_set_fourcc: (attributes org.gdk.Method.set_property=fourcc)
|
||||
* @self: a `GdkDmabufTextureBuilder`
|
||||
* @fourcc: the texture's format or 0 to unset
|
||||
*
|
||||
* Sets the format of the texture.
|
||||
*
|
||||
* The format is specified as a fourcc code.
|
||||
*
|
||||
* The format must be set before calling [method@Gdk.GLTextureBuilder.build].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
void
|
||||
gdk_dmabuf_texture_builder_set_fourcc (GdkDmabufTextureBuilder *self,
|
||||
guint32 fourcc)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
|
||||
|
||||
if (self->fourcc == fourcc)
|
||||
return;
|
||||
|
||||
self->fourcc = fourcc;
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FOURCC]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_get_modifier:
|
||||
* @self: a `GdkDmabufTextureBuilder`
|
||||
*
|
||||
* Gets the modifier value.
|
||||
*
|
||||
* Returns: the modifier
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
guint64
|
||||
gdk_dmabuf_texture_builder_get_modifier (GdkDmabufTextureBuilder *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), 0);
|
||||
|
||||
return self->modifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_set_modifier:
|
||||
* @self: a `GdkDmabufTextureBuilder`
|
||||
* @modifier: the modifier value
|
||||
*
|
||||
* Sets the modifier.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
void
|
||||
gdk_dmabuf_texture_builder_set_modifier (GdkDmabufTextureBuilder *self,
|
||||
guint64 modifier)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
|
||||
|
||||
if (self->modifier == modifier)
|
||||
return;
|
||||
|
||||
self->modifier = modifier;
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODIFIER]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_get_n_planes: (attributes org.gdk.Method.get_property=n-planes)
|
||||
* @self: a `GdkDmabufTextureBuilder`
|
||||
*
|
||||
* Gets the number of planes.
|
||||
*
|
||||
* Returns: The number of planes
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
unsigned int
|
||||
gdk_dmabuf_texture_builder_get_n_planes (GdkDmabufTextureBuilder *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), 0);
|
||||
|
||||
return self->n_planes;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_get_premultiplied:
|
||||
* @self: a `GdkDmabufTextureBuilder`
|
||||
*
|
||||
* Whether the data is premultiplied.
|
||||
*
|
||||
* Returns: whether the data is premultiplied
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
gboolean
|
||||
gdk_dmabuf_texture_builder_get_premultiplied (GdkDmabufTextureBuilder *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), TRUE);
|
||||
|
||||
return self->premultiplied;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_set_premultiplied:
|
||||
* @self: a `GdkDmabufTextureBuilder`
|
||||
* @premultiplied: whether the data is premultiplied
|
||||
*
|
||||
* Sets whether the data is premultiplied.
|
||||
*
|
||||
* Unless otherwise specified, all formats including alpha channels are assumed
|
||||
* to be premultiplied.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
void
|
||||
gdk_dmabuf_texture_builder_set_premultiplied (GdkDmabufTextureBuilder *self,
|
||||
gboolean premultiplied)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
|
||||
|
||||
if (self->premultiplied == premultiplied)
|
||||
return;
|
||||
|
||||
self->premultiplied = premultiplied;
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PREMULTIPLIED]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_set_n_planes: (attributes org.gdk.Method.set_property=n-planes)
|
||||
* @self: a `GdkDmabufTextureBuilder`
|
||||
* @n_planes: the number of planes
|
||||
*
|
||||
* Sets the number of planes of the texture.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
void
|
||||
gdk_dmabuf_texture_builder_set_n_planes (GdkDmabufTextureBuilder *self,
|
||||
unsigned int n_planes)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
|
||||
|
||||
if (self->n_planes == n_planes)
|
||||
return;
|
||||
|
||||
self->n_planes = n_planes;
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_N_PLANES]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_get_fd:
|
||||
* @self: a `GdkDmabufTextureBuilder`
|
||||
* @plane: the plane to get the fd for
|
||||
*
|
||||
* Gets the file descriptor for a plane.
|
||||
*
|
||||
* Returns: the file descriptor
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
int
|
||||
gdk_dmabuf_texture_builder_get_fd (GdkDmabufTextureBuilder *self,
|
||||
unsigned int plane)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), 0);
|
||||
g_return_val_if_fail (0 <= plane && plane < MAX_DMABUF_PLANES, 0);
|
||||
|
||||
return self->fds[plane];
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_set_fd:
|
||||
* @self: a `GdkDmabufTextureBuilder`
|
||||
* @plane: the plane to set the fd for
|
||||
* @fd: the file descriptor
|
||||
*
|
||||
* Sets the file descriptor for a plane.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
void
|
||||
gdk_dmabuf_texture_builder_set_fd (GdkDmabufTextureBuilder *self,
|
||||
unsigned int plane,
|
||||
int fd)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
|
||||
g_return_if_fail (0 <= plane && plane < MAX_DMABUF_PLANES);
|
||||
|
||||
if (self->fds[plane] == fd)
|
||||
return;
|
||||
|
||||
self->fds[plane] = fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_get_stride:
|
||||
* @self: a `GdkDmabufTextureBuilder`
|
||||
* @plane: the plane to get the stride for
|
||||
*
|
||||
* Gets the stride value for a plane.
|
||||
*
|
||||
* Returns: the stride
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
unsigned int
|
||||
gdk_dmabuf_texture_builder_get_stride (GdkDmabufTextureBuilder *self,
|
||||
unsigned int plane)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), 0);
|
||||
g_return_val_if_fail (0 <= plane && plane < MAX_DMABUF_PLANES, 0);
|
||||
|
||||
return self->strides[plane];
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_set_stride:
|
||||
* @self: a `GdkDmabufTextureBuilder`
|
||||
* @plane: the plane to set the stride for
|
||||
* @stride: the stride value
|
||||
*
|
||||
* Sets the stride for a plane.
|
||||
*
|
||||
* The stride must be set for all planes before calling [method@Gdk.GLTextureBuilder.build].
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
void
|
||||
gdk_dmabuf_texture_builder_set_stride (GdkDmabufTextureBuilder *self,
|
||||
unsigned int plane,
|
||||
unsigned int stride)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
|
||||
g_return_if_fail (0 <= plane && plane < MAX_DMABUF_PLANES);
|
||||
|
||||
if (self->strides[plane] == stride)
|
||||
return;
|
||||
|
||||
self->strides[plane] = stride;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_get_offset:
|
||||
* @self: a `GdkDmabufTextureBuilder`
|
||||
* @plane: the plane to get the offset for
|
||||
*
|
||||
* Gets the offset value for a plane.
|
||||
*
|
||||
* Returns: the offset
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
unsigned int
|
||||
gdk_dmabuf_texture_builder_get_offset (GdkDmabufTextureBuilder *self,
|
||||
unsigned int plane)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), 0);
|
||||
g_return_val_if_fail (0 <= plane && plane < MAX_DMABUF_PLANES, 0);
|
||||
|
||||
return self->offsets[plane];
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_set_offset:
|
||||
* @self: a `GdkDmabufTextureBuilder`
|
||||
* @plane: the plane to set the offset for
|
||||
* @offset: the offset value
|
||||
*
|
||||
* Sets the offset for a plane.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
void
|
||||
gdk_dmabuf_texture_builder_set_offset (GdkDmabufTextureBuilder *self,
|
||||
unsigned int plane,
|
||||
unsigned int offset)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
|
||||
g_return_if_fail (0 <= plane && plane < MAX_DMABUF_PLANES);
|
||||
|
||||
if (self->offsets[plane] == offset)
|
||||
return;
|
||||
|
||||
self->offsets[plane] = offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_get_update_texture: (attributes org.gdk.Method.get_property=update_texture)
|
||||
* @self: a `GdkDmabufTextureBuilder`
|
||||
*
|
||||
* Gets the texture previously set via gdk_dmabuf_texture_builder_set_update_texture() or
|
||||
* %NULL if none was set.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): The texture
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
GdkTexture *
|
||||
gdk_dmabuf_texture_builder_get_update_texture (GdkDmabufTextureBuilder *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), NULL);
|
||||
|
||||
return self->update_texture;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_set_update_texture: (attributes org.gdk.Method.set_property=update_texture)
|
||||
* @self: a `GdkDmabufTextureBuilder`
|
||||
* @texture: (nullable): the texture to update
|
||||
*
|
||||
* Sets the texture to be updated by this texture. See
|
||||
* [method@Gdk.DmabufTextureBuilder.set_update_region] for an explanation.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
void
|
||||
gdk_dmabuf_texture_builder_set_update_texture (GdkDmabufTextureBuilder *self,
|
||||
GdkTexture *texture)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
|
||||
g_return_if_fail (texture == NULL || GDK_IS_TEXTURE (texture));
|
||||
|
||||
if (!g_set_object (&self->update_texture, texture))
|
||||
return;
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_UPDATE_TEXTURE]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_get_update_region: (attributes org.gdk.Method.get_property=update_region)
|
||||
* @self: a `GdkDmabufTextureBuilder`
|
||||
*
|
||||
* Gets the region previously set via gdk_dmabuf_texture_builder_set_update_region() or
|
||||
* %NULL if none was set.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): The region
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
cairo_region_t *
|
||||
gdk_dmabuf_texture_builder_get_update_region (GdkDmabufTextureBuilder *self)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), NULL);
|
||||
|
||||
return self->update_region;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_set_update_region: (attributes org.gdk.Method.set_property=update_region)
|
||||
* @self: a `GdkDmabufTextureBuilder`
|
||||
* @region: (nullable): the region to update
|
||||
*
|
||||
* Sets the region to be updated by this texture. Together with
|
||||
* [property@Gdk.DmabufTextureBuilder:update-texture] this describes an
|
||||
* update of a previous texture.
|
||||
*
|
||||
* When rendering animations of large textures, it is possible that
|
||||
* consecutive textures are only updating contents in parts of the texture.
|
||||
* It is then possible to describe this update via these two properties,
|
||||
* so that GTK can avoid rerendering parts that did not change.
|
||||
*
|
||||
* An example would be a screen recording where only the mouse pointer moves.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
void
|
||||
gdk_dmabuf_texture_builder_set_update_region (GdkDmabufTextureBuilder *self,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
|
||||
|
||||
if (self->update_region == region)
|
||||
return;
|
||||
|
||||
g_clear_pointer (&self->update_region, cairo_region_destroy);
|
||||
|
||||
if (region)
|
||||
self->update_region = cairo_region_reference (region);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_UPDATE_REGION]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_dmabuf_texture_builder_build:
|
||||
* @self: a `GdkDmabufTextureBuilder`
|
||||
* @destroy: (nullable): destroy function to be called when the texture is
|
||||
* released
|
||||
* @data: user data to pass to the destroy function
|
||||
*
|
||||
* Builds a new `GdkTexture` with the values set up in the builder.
|
||||
*
|
||||
* The `destroy` function gets called when the returned texture gets released.
|
||||
*
|
||||
* Note that it is a programming error to call this function if any mandatory
|
||||
* property has not been set.
|
||||
*
|
||||
* It is possible to call this function multiple times to create multiple textures,
|
||||
* possibly with changing properties in between.
|
||||
*
|
||||
* It is the responsibility of the caller to keep the file descriptors for the planes
|
||||
* open until the created texture is no longer used, and close them afterwards (possibly
|
||||
* using the @destroy notify).
|
||||
*
|
||||
* Not all formats defined in the `drm_fourcc.h` header are supported. You can use
|
||||
* [method@Gdk.Display.get_dmabuf_formats] to get a list of supported formats.
|
||||
*
|
||||
* Returns: (transfer full) (nullable): a newly built `GdkTexture` or `NULL`
|
||||
* if the format is not supported
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
GdkTexture *
|
||||
gdk_dmabuf_texture_builder_build (GdkDmabufTextureBuilder *self,
|
||||
GDestroyNotify destroy,
|
||||
gpointer data)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), NULL);
|
||||
g_return_val_if_fail (destroy == NULL || data != NULL, NULL);
|
||||
g_return_val_if_fail (self->width > 0, NULL);
|
||||
g_return_val_if_fail (self->height > 0, NULL);
|
||||
g_return_val_if_fail (self->fourcc != 0, NULL);
|
||||
g_return_val_if_fail (self->n_planes > 0, NULL);
|
||||
|
||||
for (int i = 0; i < self->n_planes; i++)
|
||||
g_return_val_if_fail (self->fds[i] != -1 || self->offsets[i] != 0, NULL);
|
||||
|
||||
return gdk_dmabuf_texture_new_from_builder (self, destroy, data);
|
||||
}
|
||||
|
||||
int *
|
||||
gdk_dmabuf_texture_builder_get_fds (GdkDmabufTextureBuilder *self)
|
||||
{
|
||||
return self->fds;
|
||||
}
|
||||
|
||||
unsigned int *
|
||||
gdk_dmabuf_texture_builder_get_strides (GdkDmabufTextureBuilder *self)
|
||||
{
|
||||
return self->strides;
|
||||
}
|
||||
|
||||
unsigned int *
|
||||
gdk_dmabuf_texture_builder_get_offsets (GdkDmabufTextureBuilder *self)
|
||||
{
|
||||
return self->offsets;
|
||||
}
|
121
gdk/gdkdmabuftexturebuilder.h
Normal file
121
gdk/gdkdmabuftexturebuilder.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright © 2023 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gdk/gdk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gdk/gdktypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GDK_TYPE_DMABUF_TEXTURE_BUILDER (gdk_dmabuf_texture_builder_get_type ())
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
GDK_DECLARE_INTERNAL_TYPE (GdkDmabufTextureBuilder, gdk_dmabuf_texture_builder, GDK, DMABUF_TEXTURE_BUILDER, GObject)
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
GdkDmabufTextureBuilder *gdk_dmabuf_texture_builder_new (void);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
GdkDisplay * gdk_dmabuf_texture_builder_get_display (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gdk_dmabuf_texture_builder_set_display (GdkDmabufTextureBuilder *self,
|
||||
GdkDisplay *display);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
unsigned int gdk_dmabuf_texture_builder_get_width (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gdk_dmabuf_texture_builder_set_width (GdkDmabufTextureBuilder *self,
|
||||
unsigned int width);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
unsigned int gdk_dmabuf_texture_builder_get_height (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gdk_dmabuf_texture_builder_set_height (GdkDmabufTextureBuilder *self,
|
||||
unsigned int height);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
guint32 gdk_dmabuf_texture_builder_get_fourcc (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gdk_dmabuf_texture_builder_set_fourcc (GdkDmabufTextureBuilder *self,
|
||||
guint32 fourcc);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
guint64 gdk_dmabuf_texture_builder_get_modifier (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gdk_dmabuf_texture_builder_set_modifier (GdkDmabufTextureBuilder *self,
|
||||
guint64 modifier);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
gboolean gdk_dmabuf_texture_builder_get_premultiplied (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gdk_dmabuf_texture_builder_set_premultiplied (GdkDmabufTextureBuilder *self,
|
||||
gboolean premultiplied);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
unsigned int gdk_dmabuf_texture_builder_get_n_planes (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gdk_dmabuf_texture_builder_set_n_planes (GdkDmabufTextureBuilder *self,
|
||||
unsigned int n_planes);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
int gdk_dmabuf_texture_builder_get_fd (GdkDmabufTextureBuilder *self,
|
||||
unsigned int plane) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gdk_dmabuf_texture_builder_set_fd (GdkDmabufTextureBuilder *self,
|
||||
unsigned int plane,
|
||||
int fd);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
unsigned int gdk_dmabuf_texture_builder_get_stride (GdkDmabufTextureBuilder *self,
|
||||
unsigned int plane) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gdk_dmabuf_texture_builder_set_stride (GdkDmabufTextureBuilder *self,
|
||||
unsigned int plane,
|
||||
unsigned int stride);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
unsigned int gdk_dmabuf_texture_builder_get_offset (GdkDmabufTextureBuilder *self,
|
||||
unsigned int plane) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gdk_dmabuf_texture_builder_set_offset (GdkDmabufTextureBuilder *self,
|
||||
unsigned int plane,
|
||||
unsigned int offset);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
GdkTexture * gdk_dmabuf_texture_builder_get_update_texture (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gdk_dmabuf_texture_builder_set_update_texture (GdkDmabufTextureBuilder *self,
|
||||
GdkTexture *texture);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
cairo_region_t * gdk_dmabuf_texture_builder_get_update_region (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
void gdk_dmabuf_texture_builder_set_update_region (GdkDmabufTextureBuilder *self,
|
||||
cairo_region_t *region);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
GdkTexture * gdk_dmabuf_texture_builder_build (GdkDmabufTextureBuilder *self,
|
||||
GDestroyNotify destroy,
|
||||
gpointer data);
|
||||
|
||||
G_END_DECLS
|
||||
|
34
gdk/gdkdmabuftextureprivate.h
Normal file
34
gdk/gdkdmabuftextureprivate.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include "gdkdmabuftexture.h"
|
||||
|
||||
#include "gdkdmabuftexturebuilder.h"
|
||||
#include "gdkdmabufformatsprivate.h"
|
||||
#include "gdktextureprivate.h"
|
||||
#include "gdkdisplay.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define MAX_DMABUF_PLANES 4
|
||||
|
||||
int * gdk_dmabuf_texture_builder_get_fds (GdkDmabufTextureBuilder *builder);
|
||||
unsigned int * gdk_dmabuf_texture_builder_get_offsets (GdkDmabufTextureBuilder *builder);
|
||||
unsigned int * gdk_dmabuf_texture_builder_get_strides (GdkDmabufTextureBuilder *builder);
|
||||
|
||||
GdkTexture * gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
|
||||
GDestroyNotify destroy,
|
||||
gpointer data);
|
||||
|
||||
guint32 gdk_dmabuf_texture_get_fourcc (GdkDmabufTexture *texture);
|
||||
guint64 gdk_dmabuf_texture_get_modifier (GdkDmabufTexture *texture);
|
||||
unsigned int gdk_dmabuf_texture_get_n_planes (GdkDmabufTexture *texture);
|
||||
int * gdk_dmabuf_texture_get_fds (GdkDmabufTexture *texture);
|
||||
unsigned int * gdk_dmabuf_texture_get_offsets (GdkDmabufTexture *texture);
|
||||
unsigned int * gdk_dmabuf_texture_get_strides (GdkDmabufTexture *texture);
|
||||
|
||||
GdkDmabufFormat * gdk_dmabuf_texture_get_supported_formats (gsize *n_formats);
|
||||
gboolean gdk_dmabuf_texture_may_support (guint32 fourcc);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
@@ -40,7 +40,7 @@ struct _GdkIOPipe
|
||||
GCond cond;
|
||||
guchar *buffer;
|
||||
gsize size;
|
||||
GdkIOPipeState state : 2;
|
||||
guint state : 2; /* GdkIOPipeState */
|
||||
guint input_closed : 1;
|
||||
guint output_closed : 1;
|
||||
};
|
||||
|
@@ -96,6 +96,8 @@ typedef struct _GdkCairoContext GdkCairoContext;
|
||||
typedef struct _GdkGLContext GdkGLContext;
|
||||
typedef struct _GdkVulkanContext GdkVulkanContext;
|
||||
|
||||
typedef struct _GdkDmabufFormats GdkDmabufFormats;
|
||||
|
||||
/*
|
||||
* GDK_DECLARE_INTERNAL_TYPE:
|
||||
* @ModuleObjName: The name of the new type, in camel case (like GtkWidget)
|
||||
|
@@ -17,6 +17,9 @@ gdk_public_sources = files([
|
||||
'gdkdevicetool.c',
|
||||
'gdkdisplay.c',
|
||||
'gdkdisplaymanager.c',
|
||||
'gdkdmabufformats.c',
|
||||
'gdkdmabuftexture.c',
|
||||
'gdkdmabuftexturebuilder.c',
|
||||
'gdkdrag.c',
|
||||
'gdkdragsurface.c',
|
||||
'gdkdragsurfacesize.c',
|
||||
@@ -79,6 +82,9 @@ gdk_public_headers = files([
|
||||
'gdkdisplay.h',
|
||||
'gdkdisplaymanager.h',
|
||||
'gdkdrag.h',
|
||||
'gdkdmabufformats.h',
|
||||
'gdkdmabuftexture.h',
|
||||
'gdkdmabuftexturebuilder.h',
|
||||
'gdkdragsurfacesize.h',
|
||||
'gdkdrawcontext.h',
|
||||
'gdkdrop.h',
|
||||
|
@@ -4442,6 +4442,10 @@ _gdk_win32_surface_request_layout (GdkSurface *surface)
|
||||
{
|
||||
_gdk_win32_get_window_rect (surface, &rect);
|
||||
|
||||
/* Keep current position if rect is invalid (i.e. queried in bad context) */
|
||||
if (rect.right == rect.left || rect.bottom == rect.top)
|
||||
return;
|
||||
|
||||
impl->next_layout.configured_width = (rect.right - rect.left + scale - 1) / scale;
|
||||
impl->next_layout.configured_height = (rect.bottom - rect.top + scale - 1) / scale;
|
||||
|
||||
|
@@ -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));
|
||||
|
||||
|
@@ -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 = 15;
|
||||
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 == 15)
|
||||
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 == 15)
|
||||
{
|
||||
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 == 15)
|
||||
{
|
||||
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,10 @@ 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(). */
|
||||
|
@@ -42,9 +42,16 @@
|
||||
#include <gdk/gdkmemorytextureprivate.h>
|
||||
#include <gdk/gdkprofilerprivate.h>
|
||||
#include <gdk/gdktextureprivate.h>
|
||||
|
||||
#include <gdk/gdkdmabuftextureprivate.h>
|
||||
#include <gdk/gdkmemoryformatprivate.h>
|
||||
|
||||
#ifdef HAVE_EGL
|
||||
#include <epoxy/egl.h>
|
||||
#endif
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
#include <drm/drm_fourcc.h>
|
||||
#endif
|
||||
|
||||
G_DEFINE_TYPE (GskGLDriver, gsk_gl_driver, G_TYPE_OBJECT)
|
||||
|
||||
static guint
|
||||
@@ -224,6 +231,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 +247,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 +383,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; \
|
||||
@@ -399,8 +414,8 @@ gsk_gl_driver_load_programs (GskGLDriver *self,
|
||||
g_steal_pointer (&program); \
|
||||
} G_STMT_END;
|
||||
# include "gskglprograms.defs"
|
||||
#undef GSK_GL_DEFINE_PROGRAM_CLIP
|
||||
#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
|
||||
@@ -703,6 +718,395 @@ gsk_gl_driver_cache_texture (GskGLDriver *self,
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HAVE_EGL) && defined(HAVE_LINUX_DMA_BUF_H)
|
||||
static EGLImage
|
||||
egl_create_dmabuf_image (EGLDisplay display,
|
||||
int width,
|
||||
int height,
|
||||
unsigned int fourcc,
|
||||
guint64 modifier,
|
||||
unsigned int n_planes,
|
||||
int *fds,
|
||||
unsigned int *strides,
|
||||
unsigned int *offsets)
|
||||
{
|
||||
EGLint attribs[64];
|
||||
int i;
|
||||
|
||||
g_assert (1 <= n_planes && n_planes <= 4);
|
||||
|
||||
GSK_DEBUG (OPENGL,
|
||||
"Importing dma-buf into GL via EGLImage. Format %c%c%c%c:%#lx",
|
||||
fourcc & 0xff, (fourcc >> 8) & 0xff, (fourcc >> 16) & 0xff, (fourcc >> 24) & 0xff, modifier);
|
||||
|
||||
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++] = fourcc;
|
||||
|
||||
#define ADD_PLANE(plane) \
|
||||
{ \
|
||||
if (modifier != DRM_FORMAT_MOD_INVALID) \
|
||||
{ \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE## plane ##_MODIFIER_LO_EXT; \
|
||||
attribs[i++] = modifier & 0xFFFFFFFF; \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE## plane ## _MODIFIER_HI_EXT; \
|
||||
attribs[i++] = modifier >> 32; \
|
||||
} \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE## plane ##_FD_EXT; \
|
||||
attribs[i++] = fds[plane]; \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE## plane ##_PITCH_EXT; \
|
||||
attribs[i++] = strides[plane]; \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE## plane ##_OFFSET_EXT; \
|
||||
attribs[i++] = offsets[plane]; \
|
||||
}
|
||||
|
||||
ADD_PLANE (0);
|
||||
|
||||
if (n_planes > 1) ADD_PLANE (1);
|
||||
if (n_planes > 2) ADD_PLANE (2);
|
||||
if (n_planes > 3) ADD_PLANE (3);
|
||||
|
||||
attribs[i++] = EGL_NONE;
|
||||
|
||||
return eglCreateImageKHR (display,
|
||||
EGL_NO_CONTEXT,
|
||||
EGL_LINUX_DMA_BUF_EXT,
|
||||
(EGLClientBuffer)NULL,
|
||||
attribs);
|
||||
}
|
||||
|
||||
static guint
|
||||
egl_import_image (EGLImage image,
|
||||
int target)
|
||||
{
|
||||
guint texture_id;
|
||||
|
||||
glGenTextures (1, &texture_id);
|
||||
glBindTexture (target, texture_id);
|
||||
g_assert (glGetError() == GL_NO_ERROR);
|
||||
glEGLImageTargetTexture2DOES (target, image);
|
||||
g_assert (glGetError() == GL_NO_ERROR);
|
||||
glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
g_assert (glGetError() == GL_NO_ERROR);
|
||||
glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
g_assert (glGetError() == GL_NO_ERROR);
|
||||
|
||||
return texture_id;
|
||||
}
|
||||
|
||||
static void
|
||||
egl_destroy_image (EGLDisplay display,
|
||||
EGLImage image)
|
||||
{
|
||||
eglDestroyImageKHR (display, image);
|
||||
}
|
||||
|
||||
static int
|
||||
import_dmabuf_planes (EGLDisplay display,
|
||||
int width,
|
||||
int height,
|
||||
unsigned int fourcc,
|
||||
guint64 modifier,
|
||||
unsigned int n_planes,
|
||||
int *fds,
|
||||
unsigned int *strides,
|
||||
unsigned int *offsets,
|
||||
int target)
|
||||
{
|
||||
EGLImage image;
|
||||
int texture_id;
|
||||
|
||||
image = egl_create_dmabuf_image (display, width, height, fourcc, modifier, n_planes,fds, strides, offsets);
|
||||
|
||||
if (image == EGL_NO_IMAGE)
|
||||
{
|
||||
g_warning ("Failed to create EGL image: %#x\n", eglGetError ());
|
||||
return 0;
|
||||
}
|
||||
|
||||
texture_id = egl_import_image (image, target);
|
||||
|
||||
egl_destroy_image (display, image);
|
||||
|
||||
return texture_id;
|
||||
}
|
||||
|
||||
static void
|
||||
set_viewport_for_size (GskGLDriver *self,
|
||||
GskGLProgram *program,
|
||||
float width,
|
||||
float height)
|
||||
{
|
||||
float viewport[4] = { 0, 0, width, height };
|
||||
|
||||
gsk_gl_uniform_state_set4fv (program->uniforms,
|
||||
program->program_info,
|
||||
UNIFORM_SHARED_VIEWPORT, 0,
|
||||
1,
|
||||
(const float *)&viewport);
|
||||
self->stamps[UNIFORM_SHARED_VIEWPORT]++;
|
||||
}
|
||||
|
||||
#define ORTHO_NEAR_PLANE -10000
|
||||
#define ORTHO_FAR_PLANE 10000
|
||||
|
||||
static void
|
||||
set_projection_for_size (GskGLDriver *self,
|
||||
GskGLProgram *program,
|
||||
float width,
|
||||
float height)
|
||||
{
|
||||
graphene_matrix_t projection;
|
||||
|
||||
graphene_matrix_init_ortho (&projection, 0, width, 0, height, ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE);
|
||||
graphene_matrix_scale (&projection, 1, -1, 1);
|
||||
|
||||
gsk_gl_uniform_state_set_matrix (program->uniforms,
|
||||
program->program_info,
|
||||
UNIFORM_SHARED_PROJECTION, 0,
|
||||
&projection);
|
||||
self->stamps[UNIFORM_SHARED_PROJECTION]++;
|
||||
}
|
||||
|
||||
static void
|
||||
reset_modelview (GskGLDriver *self,
|
||||
GskGLProgram *program)
|
||||
{
|
||||
graphene_matrix_t modelview;
|
||||
|
||||
graphene_matrix_init_identity (&modelview);
|
||||
|
||||
gsk_gl_uniform_state_set_matrix (program->uniforms,
|
||||
program->program_info,
|
||||
UNIFORM_SHARED_MODELVIEW, 0,
|
||||
&modelview);
|
||||
self->stamps[UNIFORM_SHARED_MODELVIEW]++;
|
||||
}
|
||||
|
||||
static void
|
||||
draw_rect (GskGLCommandQueue *command_queue,
|
||||
float min_x,
|
||||
float min_y,
|
||||
float max_x,
|
||||
float max_y)
|
||||
{
|
||||
GskGLDrawVertex *vertices = gsk_gl_command_queue_add_vertices (command_queue);
|
||||
float min_u = 0;
|
||||
float max_u = 1;
|
||||
float min_v = 1;
|
||||
float max_v = 0;
|
||||
guint16 c = FP16_ZERO;
|
||||
|
||||
vertices[0] = (GskGLDrawVertex) { .position = { min_x, min_y }, .uv = { min_u, min_v }, .color = { c, c, c, c } };
|
||||
vertices[1] = (GskGLDrawVertex) { .position = { min_x, max_y }, .uv = { min_u, max_v }, .color = { c, c, c, c } };
|
||||
vertices[2] = (GskGLDrawVertex) { .position = { max_x, min_y }, .uv = { max_u, min_v }, .color = { c, c, c, c } };
|
||||
vertices[3] = (GskGLDrawVertex) { .position = { max_x, max_y }, .uv = { max_u, max_v }, .color = { c, c, c, c } };
|
||||
vertices[4] = (GskGLDrawVertex) { .position = { min_x, max_y }, .uv = { min_u, max_v }, .color = { c, c, c, c } };
|
||||
vertices[5] = (GskGLDrawVertex) { .position = { max_x, min_y }, .uv = { max_u, min_v }, .color = { c, c, c, c } };
|
||||
}
|
||||
|
||||
typedef struct _TextureFormatInfo TextureFormatInfo;
|
||||
struct _TextureFormatInfo
|
||||
{
|
||||
int n_planes;
|
||||
unsigned int subformats[3];
|
||||
int plane_indices[3];
|
||||
int hsub[3];
|
||||
int vsub[3];
|
||||
int uniforms[3];
|
||||
};
|
||||
|
||||
static TextureFormatInfo texture_format_info[] = {
|
||||
{ .n_planes = 2,
|
||||
.subformats = { DRM_FORMAT_GR88, DRM_FORMAT_ARGB8888 },
|
||||
.plane_indices = { 0, 0 },
|
||||
.hsub = { 1, 2 },
|
||||
.vsub = { 1, 1 },
|
||||
.uniforms = { UNIFORM_SHARED_SOURCE, UNIFORM_YUYV_SOURCE2 },
|
||||
},
|
||||
{ .n_planes = 2,
|
||||
.subformats = { DRM_FORMAT_R8, DRM_FORMAT_GR88 },
|
||||
.plane_indices = { 0, 1 },
|
||||
.hsub = { 1, 2 },
|
||||
.vsub = { 1, 2 },
|
||||
.uniforms = { UNIFORM_SHARED_SOURCE, UNIFORM_NV12_SOURCE2 },
|
||||
},
|
||||
{ .n_planes = 2,
|
||||
.subformats = { DRM_FORMAT_R16, DRM_FORMAT_GR1616 },
|
||||
.plane_indices = { 0, 1 },
|
||||
.hsub = { 1, 2 },
|
||||
.vsub = { 1, 2 },
|
||||
.uniforms = { UNIFORM_SHARED_SOURCE, UNIFORM_NV12_SOURCE2 },
|
||||
},
|
||||
{ .n_planes = 3,
|
||||
.subformats = { DRM_FORMAT_R8, DRM_FORMAT_R8, DRM_FORMAT_R8 },
|
||||
.plane_indices = { 0, 1, 2 },
|
||||
.hsub = { 1, 2, 2 },
|
||||
.vsub = { 1, 2, 2 },
|
||||
.uniforms = { UNIFORM_SHARED_SOURCE, UNIFORM_YUV420_SOURCE2, UNIFORM_YUV420_SOURCE3 },
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
static unsigned int release_render_target (GskGLDriver *self,
|
||||
GskGLRenderTarget *render_target,
|
||||
gboolean release_texture,
|
||||
gboolean cache_texture);
|
||||
|
||||
static unsigned int
|
||||
gsk_gl_driver_import_dmabuf_texture (GskGLDriver *self,
|
||||
GdkDmabufTexture *texture)
|
||||
{
|
||||
GdkGLContext *context = self->command_queue->context;
|
||||
GdkDisplay *display = gdk_gl_context_get_display (context);
|
||||
EGLDisplay egl_display;
|
||||
int width, height;
|
||||
guint32 fourcc;
|
||||
guint64 modifier;
|
||||
TextureFormatInfo *info = NULL;
|
||||
GskGLProgram *program;
|
||||
GskGLRenderTarget *render_target;
|
||||
guint prev_fbo;
|
||||
|
||||
egl_display = gdk_display_get_egl_display (display);
|
||||
if (egl_display == NULL)
|
||||
{
|
||||
g_warning ("Can't import dmabufs when not using EGL");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!display->have_egl_dma_buf_import)
|
||||
{
|
||||
g_warning ("EGL does ont support importing dmabufs");
|
||||
return 0;
|
||||
}
|
||||
|
||||
gdk_gl_context_make_current (context);
|
||||
|
||||
width = gdk_texture_get_width (GDK_TEXTURE (texture));
|
||||
height = gdk_texture_get_height (GDK_TEXTURE (texture));
|
||||
fourcc = gdk_dmabuf_texture_get_fourcc (texture);
|
||||
modifier = gdk_dmabuf_texture_get_modifier (texture);
|
||||
|
||||
GSK_DEBUG (OPENGL,
|
||||
"DMA-buf Format %c%c%c%c:%#lx",
|
||||
fourcc & 0xff, (fourcc >> 8) & 0xff, (fourcc >> 16) & 0xff, (fourcc >> 24) & 0xff, modifier);
|
||||
|
||||
if (gdk_gl_context_get_api (context) == GDK_GL_API_GLES)
|
||||
{
|
||||
program = self->external;
|
||||
}
|
||||
else if (gdk_dmabuf_texture_get_fourcc (texture) == DRM_FORMAT_YUYV)
|
||||
{
|
||||
info = &texture_format_info[0];
|
||||
program = self->yuyv;
|
||||
}
|
||||
else if (gdk_dmabuf_texture_get_fourcc (texture) == DRM_FORMAT_NV12)
|
||||
{
|
||||
info = &texture_format_info[1];
|
||||
program = self->nv12;
|
||||
}
|
||||
else if (gdk_dmabuf_texture_get_fourcc (texture) == DRM_FORMAT_P010)
|
||||
{
|
||||
info = &texture_format_info[2];
|
||||
program = self->nv12;
|
||||
}
|
||||
else if (gdk_dmabuf_texture_get_fourcc (texture) == DRM_FORMAT_YUV420)
|
||||
{
|
||||
info = &texture_format_info[3];
|
||||
program = self->yuv420;
|
||||
}
|
||||
else
|
||||
{
|
||||
return import_dmabuf_planes (egl_display,
|
||||
gdk_texture_get_width (GDK_TEXTURE (texture)),
|
||||
gdk_texture_get_height (GDK_TEXTURE (texture)),
|
||||
gdk_dmabuf_texture_get_fourcc (texture),
|
||||
gdk_dmabuf_texture_get_modifier (texture),
|
||||
gdk_dmabuf_texture_get_n_planes (texture),
|
||||
gdk_dmabuf_texture_get_fds (texture),
|
||||
gdk_dmabuf_texture_get_strides (texture),
|
||||
gdk_dmabuf_texture_get_offsets (texture),
|
||||
GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
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);
|
||||
|
||||
if (gdk_gl_context_get_api (context) == GDK_GL_API_GLES)
|
||||
{
|
||||
int texture_id = import_dmabuf_planes (egl_display,
|
||||
gdk_texture_get_width (GDK_TEXTURE (texture)),
|
||||
gdk_texture_get_height (GDK_TEXTURE (texture)),
|
||||
gdk_dmabuf_texture_get_fourcc (texture),
|
||||
gdk_dmabuf_texture_get_modifier (texture),
|
||||
gdk_dmabuf_texture_get_n_planes (texture),
|
||||
gdk_dmabuf_texture_get_fds (texture),
|
||||
gdk_dmabuf_texture_get_strides (texture),
|
||||
gdk_dmabuf_texture_get_offsets (texture),
|
||||
GL_TEXTURE_EXTERNAL_OES);
|
||||
|
||||
gsk_gl_program_set_uniform_texture (program,
|
||||
UNIFORM_EXTERNAL_SOURCE, 0,
|
||||
GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE0, texture_id);
|
||||
|
||||
gsk_gl_driver_autorelease_texture (self, texture_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < info->n_planes; i++)
|
||||
{
|
||||
int plane = info->plane_indices[i];
|
||||
int texture_id = import_dmabuf_planes (egl_display,
|
||||
width / info->hsub[i],
|
||||
height / info->vsub[i],
|
||||
info->subformats[i],
|
||||
modifier,
|
||||
1,
|
||||
gdk_dmabuf_texture_get_fds (texture) + plane,
|
||||
gdk_dmabuf_texture_get_strides (texture) + plane,
|
||||
gdk_dmabuf_texture_get_offsets (texture) + plane,
|
||||
GL_TEXTURE_2D);
|
||||
|
||||
gsk_gl_program_set_uniform_texture (program,
|
||||
info->uniforms[i], 0,
|
||||
GL_TEXTURE_2D, GL_TEXTURE0 + i, texture_id);
|
||||
|
||||
gsk_gl_driver_autorelease_texture (self, 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 unsigned int
|
||||
gsk_gl_driver_import_dmabuf_texture (GskGLDriver *self,
|
||||
GdkDmabufTexture *texture)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* HAVE_EGL && HAVE_LINUX_DMA_BUF_H */
|
||||
|
||||
/**
|
||||
* gsk_gl_driver_load_texture:
|
||||
* @self: a `GdkTexture`
|
||||
@@ -759,7 +1163,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);
|
||||
@@ -788,9 +1196,8 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
|
||||
t = gsk_gl_texture_new (texture_id,
|
||||
width, height,
|
||||
self->current_frame_id);
|
||||
t = gsk_gl_texture_new (texture_id, width, height, self->current_frame_id);
|
||||
|
||||
if (ensure_mipmap)
|
||||
{
|
||||
glBindTexture (GL_TEXTURE_2D, t->texture_id);
|
||||
@@ -962,6 +1369,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`
|
||||
@@ -987,36 +1435,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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -87,3 +87,26 @@ 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))
|
||||
|
||||
GSK_GL_DEFINE_PROGRAM_NO_CLIP (yuyv,
|
||||
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("yuyv.glsl")),
|
||||
GSK_GL_ADD_UNIFORM (1, YUYV_SOURCE2, u_source2))
|
||||
|
||||
GSK_GL_DEFINE_PROGRAM_NO_CLIP (nv12,
|
||||
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("nv12.glsl")),
|
||||
GSK_GL_ADD_UNIFORM (1, NV12_SOURCE2, u_source2))
|
||||
|
||||
GSK_GL_DEFINE_PROGRAM_NO_CLIP (yuv420,
|
||||
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("yuv420.glsl")),
|
||||
GSK_GL_ADD_UNIFORM (1, YUV420_SOURCE2, u_source2)
|
||||
GSK_GL_ADD_UNIFORM (2, YUV420_SOURCE3, u_source2))
|
||||
|
@@ -30,6 +30,8 @@
|
||||
#include <gsk/gskglshaderprivate.h>
|
||||
#include <gdk/gdktextureprivate.h>
|
||||
#include <gdk/gdkmemorytextureprivate.h>
|
||||
#include <gdk/gdkdmabuftextureprivate.h>
|
||||
#include <gdk/gdkdisplayprivate.h>
|
||||
#include <gsk/gsktransformprivate.h>
|
||||
#include <gsk/gskroundedrectprivate.h>
|
||||
#include <gsk/gskrectprivate.h>
|
||||
@@ -43,10 +45,15 @@
|
||||
#include "gskglprogramprivate.h"
|
||||
#include "gskglrenderjobprivate.h"
|
||||
#include "gskglshadowlibraryprivate.h"
|
||||
#include "gskdebugprivate.h"
|
||||
|
||||
#include "ninesliceprivate.h"
|
||||
#include "fp16private.h"
|
||||
|
||||
#include <epoxy/egl.h>
|
||||
|
||||
#include <drm/drm_fourcc.h>
|
||||
|
||||
#define ORTHO_NEAR_PLANE -10000
|
||||
#define ORTHO_FAR_PLANE 10000
|
||||
#define MAX_GRADIENT_STOPS 6
|
||||
@@ -208,6 +215,10 @@ static void gsk_gl_render_job_visit_node (GskGLRenderJob
|
||||
static gboolean gsk_gl_render_job_visit_node_with_offscreen (GskGLRenderJob *job,
|
||||
const GskRenderNode *node,
|
||||
GskGLRenderOffscreen *offscreen);
|
||||
static void gsk_gl_render_job_upload_texture (GskGLRenderJob *job,
|
||||
GdkTexture *texture,
|
||||
gboolean ensure_mipmap,
|
||||
GskGLRenderOffscreen *offscreen);
|
||||
|
||||
static inline GskGLRenderClip *
|
||||
clips_grow_one (Clips *clips)
|
||||
@@ -3328,6 +3339,53 @@ gsk_gl_render_job_visit_blend_node (GskGLRenderJob *job,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_gl_render_job_texture_mask_for_color (GskGLRenderJob *job,
|
||||
const GskRenderNode *mask,
|
||||
const GskRenderNode *color,
|
||||
const graphene_rect_t *bounds)
|
||||
{
|
||||
int max_texture_size = job->command_queue->max_texture_size;
|
||||
GdkTexture *texture = gsk_texture_node_get_texture (mask);
|
||||
const GdkRGBA *rgba;
|
||||
|
||||
rgba = gsk_color_node_get_color (color);
|
||||
if (RGBA_IS_CLEAR (rgba))
|
||||
return TRUE;
|
||||
|
||||
if G_LIKELY (texture->width <= max_texture_size &&
|
||||
texture->height <= max_texture_size &&
|
||||
gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, coloring)))
|
||||
{
|
||||
GskGLRenderOffscreen offscreen = {0};
|
||||
float scale_x = mask->bounds.size.width / texture->width;
|
||||
float scale_y = mask->bounds.size.height / texture->height;
|
||||
gboolean use_mipmap;
|
||||
guint16 cc[4];
|
||||
|
||||
use_mipmap = (scale_x * fabs (job->scale_x)) < 0.5 ||
|
||||
(scale_y * fabs (job->scale_y)) < 0.5;
|
||||
|
||||
rgba_to_half (rgba, cc);
|
||||
gsk_gl_render_job_upload_texture (job, texture, use_mipmap, &offscreen);
|
||||
gsk_gl_program_set_uniform_texture_with_sync (job->current_program,
|
||||
UNIFORM_SHARED_SOURCE, 0,
|
||||
GL_TEXTURE_2D,
|
||||
GL_TEXTURE0,
|
||||
offscreen.texture_id,
|
||||
offscreen.has_mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR,
|
||||
GL_LINEAR,
|
||||
offscreen.sync);
|
||||
job->source_is_glyph_atlas = FALSE;
|
||||
gsk_gl_render_job_draw_offscreen_with_color (job, bounds, &offscreen, cc);
|
||||
gsk_gl_render_job_end_draw (job);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static inline void
|
||||
gsk_gl_render_job_visit_mask_node (GskGLRenderJob *job,
|
||||
const GskRenderNode *node)
|
||||
@@ -3337,6 +3395,17 @@ gsk_gl_render_job_visit_mask_node (GskGLRenderJob *job,
|
||||
GskGLRenderOffscreen source_offscreen = {0};
|
||||
GskGLRenderOffscreen mask_offscreen = {0};
|
||||
|
||||
/* If the mask is a texture and the source is a color node
|
||||
* then we can take a shortcut and avoid offscreens.
|
||||
*/
|
||||
if (GSK_RENDER_NODE_TYPE (mask) == GSK_TEXTURE_NODE &&
|
||||
GSK_RENDER_NODE_TYPE (source) == GSK_COLOR_NODE &&
|
||||
gsk_mask_node_get_mask_mode (node) == GSK_MASK_MODE_ALPHA)
|
||||
{
|
||||
if (gsk_gl_render_job_texture_mask_for_color (job, mask, source, &node->bounds))
|
||||
return;
|
||||
}
|
||||
|
||||
source_offscreen.bounds = &node->bounds;
|
||||
source_offscreen.force_offscreen = TRUE;
|
||||
source_offscreen.reset_clip = TRUE;
|
||||
@@ -3568,16 +3637,11 @@ 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);
|
||||
|
||||
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;
|
||||
|
||||
@@ -3591,16 +3655,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));
|
||||
}
|
||||
}
|
||||
|
||||
|
24
gsk/gl/resources/external.glsl
Normal file
24
gsk/gl/resources/external.glsl
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
// 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
|
||||
|
||||
#ifdef GSK_GLES
|
||||
uniform samplerExternalOES u_external_source;
|
||||
#else
|
||||
uniform sampler2D u_external_source;
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
vec4 diffuse = texture2D(u_external_source, vUv);
|
||||
|
||||
gskSetOutputColor(diffuse);
|
||||
}
|
49
gsk/gl/resources/nv12.glsl
Normal file
49
gsk/gl/resources/nv12.glsl
Normal file
@@ -0,0 +1,49 @@
|
||||
// VERTEX_SHADER:
|
||||
// nv12.glsl
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
// nv12.glsl
|
||||
|
||||
uniform sampler2D u_source2;
|
||||
|
||||
vec4 yuv_to_rgb(vec4 yuv)
|
||||
{
|
||||
vec4 res;
|
||||
|
||||
float Y = 1.16438356 * (yuv.x - 0.0625);
|
||||
float su = yuv.y - 0.5;
|
||||
float sv = yuv.z - 0.5;
|
||||
|
||||
res.r = Y + 1.59602678 * sv;
|
||||
res.g = Y - 0.39176229 * su - 0.81296764 * sv;
|
||||
res.b = Y + 2.01723214 * su;
|
||||
|
||||
res.rgb *= yuv.w;
|
||||
res.a = yuv.w;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* This shader converts 2-plane yuv (DRM_FORMAT_NV12 or DRM_FORMAT_P010)
|
||||
* into rgb. It assumes that the two planes have been imported separately,
|
||||
* the first one as R texture, the second one as RG.
|
||||
*/
|
||||
|
||||
void main() {
|
||||
vec4 y = GskTexture(u_source, vUv);
|
||||
vec4 uv = GskTexture(u_source2, vUv);
|
||||
|
||||
vec4 yuv;
|
||||
|
||||
yuv.x = y.x;
|
||||
yuv.yz = uv.xy;
|
||||
yuv.w = 1.0;
|
||||
|
||||
gskSetOutputColor(yuv_to_rgb(yuv));
|
||||
}
|
@@ -1,3 +1,7 @@
|
||||
#ifdef GSK_GLES
|
||||
#extension GL_OES_EGL_image_external : require
|
||||
#endif
|
||||
|
||||
#ifndef GSK_LEGACY
|
||||
precision highp float;
|
||||
#endif
|
||||
|
51
gsk/gl/resources/yuv420.glsl
Normal file
51
gsk/gl/resources/yuv420.glsl
Normal file
@@ -0,0 +1,51 @@
|
||||
// VERTEX_SHADER:
|
||||
// y_uv_to_rgba.glsl
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
// y_uv_to_rgba.glsl
|
||||
|
||||
uniform sampler2D u_source2;
|
||||
uniform sampler2D u_source3;
|
||||
|
||||
vec4 yuv_to_rgb(vec4 yuv)
|
||||
{
|
||||
vec4 res;
|
||||
|
||||
float Y = 1.16438356 * (yuv.x - 0.0625);
|
||||
float su = yuv.y - 0.5;
|
||||
float sv = yuv.z - 0.5;
|
||||
|
||||
res.r = Y + 1.59602678 * sv;
|
||||
res.g = Y - 0.39176229 * su - 0.81296764 * sv;
|
||||
res.b = Y + 2.01723214 * su;
|
||||
|
||||
res.rgb *= yuv.w;
|
||||
res.a = yuv.w;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* This shader converts 3-plane yuv (DRM_FORMAT_YUY420) into rgb.
|
||||
*/
|
||||
|
||||
|
||||
void main() {
|
||||
vec4 y = GskTexture(u_source, vUv);
|
||||
vec4 u = GskTexture(u_source2, vUv);
|
||||
vec4 v = GskTexture(u_source3, vUv);
|
||||
|
||||
vec4 yuv;
|
||||
|
||||
yuv.x = y.x;
|
||||
yuv.y = u.x;
|
||||
yuv.z = v.x;
|
||||
yuv.w = 1.0;
|
||||
|
||||
gskSetOutputColor(yuv_to_rgb(yuv));
|
||||
}
|
49
gsk/gl/resources/yuyv.glsl
Normal file
49
gsk/gl/resources/yuyv.glsl
Normal file
@@ -0,0 +1,49 @@
|
||||
// VERTEX_SHADER:
|
||||
// y_xuxv_to_rgba.glsl
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
// y_xuxv_to_rgba.glsl
|
||||
|
||||
uniform sampler2D u_source2;
|
||||
|
||||
vec4 yuv_to_rgb(vec4 yuv)
|
||||
{
|
||||
vec4 res;
|
||||
|
||||
float Y = 1.16438356 * (yuv.x - 0.0625);
|
||||
float su = yuv.y - 0.5;
|
||||
float sv = yuv.z - 0.5;
|
||||
|
||||
res.r = Y + 1.59602678 * sv;
|
||||
res.g = Y - 0.39176229 * su - 0.81296764 * sv;
|
||||
res.b = Y + 2.01723214 * su;
|
||||
|
||||
res.rgb *= yuv.w;
|
||||
res.a = yuv.w;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* This shader converts single-plane yuv (DRM_FORMAT_YUYV) into rgb.
|
||||
* It assumes that the buffer has been imported twice - once as RG
|
||||
* texture with full size, and once as RGBA textures with half the
|
||||
* width (to account for the subsampling).
|
||||
*/
|
||||
void main() {
|
||||
vec4 y = GskTexture(u_source, vUv);
|
||||
vec4 uv = GskTexture(u_source2, vUv);
|
||||
|
||||
vec4 yuv;
|
||||
|
||||
yuv.x = y.x;
|
||||
yuv.yz = uv.yw;
|
||||
yuv.w = 1.0;
|
||||
|
||||
gskSetOutputColor(yuv_to_rgb(yuv));
|
||||
}
|
@@ -19,8 +19,10 @@
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define STBRP__NOTUSED(v) (void)(v)
|
||||
#define STBRP__CDECL __cdecl
|
||||
#else
|
||||
#define STBRP__NOTUSED(v) (void)sizeof(v)
|
||||
#define STBRP__CDECL
|
||||
#endif
|
||||
|
||||
enum
|
||||
@@ -63,9 +65,6 @@ STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_ou
|
||||
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
|
||||
{
|
||||
int i;
|
||||
#ifndef STBRP_LARGE_RECTS
|
||||
STBRP_ASSERT(width <= 0xffff && height <= 0xffff);
|
||||
#endif
|
||||
|
||||
for (i=0; i < num_nodes-1; ++i)
|
||||
nodes[i].next = &nodes[i+1];
|
||||
@@ -84,11 +83,7 @@ STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height,
|
||||
context->extra[0].y = 0;
|
||||
context->extra[0].next = &context->extra[1];
|
||||
context->extra[1].x = (stbrp_coord) width;
|
||||
#ifdef STBRP_LARGE_RECTS
|
||||
context->extra[1].y = (1<<30);
|
||||
#else
|
||||
context->extra[1].y = 65535;
|
||||
#endif
|
||||
context->extra[1].next = NULL;
|
||||
}
|
||||
|
||||
@@ -160,6 +155,13 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int widt
|
||||
width -= width % c->align;
|
||||
STBRP_ASSERT(width % c->align == 0);
|
||||
|
||||
// if it can't possibly fit, bail immediately
|
||||
if (width > c->width || height > c->height) {
|
||||
fr.prev_link = NULL;
|
||||
fr.x = fr.y = 0;
|
||||
return fr;
|
||||
}
|
||||
|
||||
node = c->active_head;
|
||||
prev = &c->active_head;
|
||||
while (node->x + width <= c->width) {
|
||||
@@ -223,7 +225,7 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int widt
|
||||
}
|
||||
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
|
||||
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
|
||||
if (y + height < c->height) {
|
||||
if (y + height <= c->height) {
|
||||
if (y <= best_y) {
|
||||
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
|
||||
best_x = xpos;
|
||||
@@ -323,7 +325,7 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, i
|
||||
return res;
|
||||
}
|
||||
|
||||
static int rect_height_compare(const void *a, const void *b)
|
||||
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
@@ -334,19 +336,13 @@ static int rect_height_compare(const void *a, const void *b)
|
||||
return (p->w > q->w) ? -1 : (p->w < q->w);
|
||||
}
|
||||
|
||||
static int rect_original_order(const void *a, const void *b)
|
||||
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
|
||||
}
|
||||
|
||||
#ifdef STBRP_LARGE_RECTS
|
||||
#define STBRP__MAXVAL 0xffffffff
|
||||
#else
|
||||
#define STBRP__MAXVAL 0xffff
|
||||
#endif
|
||||
|
||||
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
|
||||
{
|
||||
int i, all_rects_packed = 1;
|
||||
|
@@ -1,9 +1,15 @@
|
||||
// stb_rect_pack.h - v0.99 - public domain - rectangle packing
|
||||
// stb_rect_pack.h - v1.01 - public domain - rectangle packing
|
||||
// Sean Barrett 2014
|
||||
//
|
||||
// Useful for e.g. packing rectangular textures into an atlas.
|
||||
// Does not do rotation.
|
||||
//
|
||||
// Before #including,
|
||||
//
|
||||
// #define STB_RECT_PACK_IMPLEMENTATION
|
||||
//
|
||||
// in the file that you want to have the implementation.
|
||||
//
|
||||
// Not necessarily the awesomest packing method, but better than
|
||||
// the totally naive one in stb_truetype (which is primarily what
|
||||
// this is meant to replace).
|
||||
@@ -31,9 +37,12 @@
|
||||
//
|
||||
// Bugfixes / warning fixes
|
||||
// Jeremy Jaussaud
|
||||
// Fabian Giesen
|
||||
//
|
||||
// Version history:
|
||||
//
|
||||
// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section
|
||||
// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
|
||||
// 0.99 (2019-02-07) warning fixes
|
||||
// 0.11 (2017-03-03) return packing success/fail result
|
||||
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
|
||||
@@ -72,11 +81,10 @@ typedef struct stbrp_context stbrp_context;
|
||||
typedef struct stbrp_node stbrp_node;
|
||||
typedef struct stbrp_rect stbrp_rect;
|
||||
|
||||
#ifdef STBRP_LARGE_RECTS
|
||||
typedef int stbrp_coord;
|
||||
#else
|
||||
typedef unsigned short stbrp_coord;
|
||||
#endif
|
||||
|
||||
#define STBRP__MAXVAL 0x7fffffff
|
||||
// Mostly for internal use, but this is the maximum supported coordinate value.
|
||||
|
||||
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
|
||||
// Assign packed locations to rectangles. The rectangles are of type
|
||||
|
@@ -20,6 +20,10 @@ gsk_private_gl_shaders = [
|
||||
'gl/resources/custom.glsl',
|
||||
'gl/resources/filled_border.glsl',
|
||||
'gl/resources/mask.glsl',
|
||||
'gl/resources/yuyv.glsl',
|
||||
'gl/resources/nv12.glsl',
|
||||
'gl/resources/yuv420.glsl',
|
||||
'gl/resources/external.glsl',
|
||||
]
|
||||
|
||||
gsk_public_sources = files([
|
||||
|
@@ -714,7 +714,9 @@ emit_text_changed (GtkAtSpiContext *self,
|
||||
"org.a11y.atspi.Event.Object",
|
||||
"TextChanged",
|
||||
g_variant_new ("(siiva{sv})",
|
||||
kind, start, end, g_variant_new_string (text), NULL),
|
||||
kind, start, end,
|
||||
g_variant_new_take_string (g_strndup (text, end)),
|
||||
NULL),
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
@@ -1629,6 +1629,10 @@ delete_text_cb (GtkEditable *editable,
|
||||
return;
|
||||
|
||||
text = gtk_editable_get_chars (editable, start, end);
|
||||
|
||||
if (end < 0)
|
||||
end = g_utf8_strlen(text, -1);
|
||||
|
||||
changed->text_changed (changed->data, "delete", start, end - start, text);
|
||||
g_free (text);
|
||||
}
|
||||
@@ -1784,7 +1788,7 @@ buffer_changed (GtkWidget *widget,
|
||||
if (changed->buffer)
|
||||
{
|
||||
g_object_ref (changed->buffer);
|
||||
g_signal_connect (changed->buffer, "insert-text", G_CALLBACK (insert_range_cb), changed);
|
||||
g_signal_connect_after (changed->buffer, "insert-text", G_CALLBACK (insert_range_cb), changed);
|
||||
g_signal_connect (changed->buffer, "delete-range", G_CALLBACK (delete_range_cb), changed);
|
||||
g_signal_connect_after (changed->buffer, "delete-range", G_CALLBACK (delete_range_after_cb), changed);
|
||||
g_signal_connect_after (changed->buffer, "mark-set", G_CALLBACK (mark_set_cb), changed);
|
||||
|
BIN
gtk/emoji/bn.data
Normal file
BIN
gtk/emoji/bn.data
Normal file
Binary file not shown.
BIN
gtk/emoji/et.data
Normal file
BIN
gtk/emoji/et.data
Normal file
Binary file not shown.
BIN
gtk/emoji/fi.data
Normal file
BIN
gtk/emoji/fi.data
Normal file
Binary file not shown.
BIN
gtk/emoji/hi.data
Normal file
BIN
gtk/emoji/hi.data
Normal file
Binary file not shown.
BIN
gtk/emoji/ja.data
Normal file
BIN
gtk/emoji/ja.data
Normal file
Binary file not shown.
BIN
gtk/emoji/nb.data
Normal file
BIN
gtk/emoji/nb.data
Normal file
Binary file not shown.
BIN
gtk/emoji/th.data
Normal file
BIN
gtk/emoji/th.data
Normal file
Binary file not shown.
@@ -86,7 +86,7 @@ struct _GtkMenuTrackerItem
|
||||
char *action_namespace;
|
||||
char *action_and_target;
|
||||
GMenuItem *item;
|
||||
GtkMenuTrackerItemRole role : 4;
|
||||
guint role : 4; /* GtkMenuTrackerItemRole */
|
||||
guint is_separator : 1;
|
||||
guint can_activate : 1;
|
||||
guint sensitive : 1;
|
||||
|
@@ -70,7 +70,7 @@ typedef struct {
|
||||
CachedSizeX cached_size_x;
|
||||
CachedSizeY cached_size_y;
|
||||
|
||||
GtkSizeRequestMode request_mode : 3;
|
||||
guint request_mode : 3; /* GtkSizeRequestMode */
|
||||
guint request_mode_valid : 1;
|
||||
struct {
|
||||
guint n_cached_requests : 15;
|
||||
|
@@ -855,20 +855,27 @@ else
|
||||
endif
|
||||
|
||||
foreach lang : [
|
||||
'bn',
|
||||
'de',
|
||||
'da',
|
||||
'fr',
|
||||
'es',
|
||||
'et',
|
||||
'fi',
|
||||
'hi',
|
||||
'hu',
|
||||
'it',
|
||||
'ja',
|
||||
'ko',
|
||||
'lt',
|
||||
'ms',
|
||||
'nb',
|
||||
'nl',
|
||||
'pl',
|
||||
'pt',
|
||||
'ru',
|
||||
'sv',
|
||||
'th',
|
||||
'uk',
|
||||
'zh'
|
||||
]
|
||||
|
@@ -162,6 +162,7 @@ check_headers = [
|
||||
'inttypes.h',
|
||||
'linux/input.h',
|
||||
'linux/memfd.h',
|
||||
'linux/dma-buf.h',
|
||||
'locale.h',
|
||||
'memory.h',
|
||||
'stdint.h',
|
||||
@@ -185,6 +186,10 @@ 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)
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
gtk_tests = [
|
||||
# testname, optional extra sources
|
||||
['testdmabuf'],
|
||||
['testsections'],
|
||||
['testfilelauncher'],
|
||||
['input'],
|
||||
|
440
tests/testdmabuf.c
Normal file
440
tests/testdmabuf.c
Normal file
@@ -0,0 +1,440 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/dma-heap.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
|
||||
/* For this to work, you may need to give /dev/dma_heap/system
|
||||
* lax permissions.
|
||||
*/
|
||||
|
||||
static int
|
||||
allocate_dma_buf (gsize size)
|
||||
{
|
||||
static int fd = -1;
|
||||
struct dma_heap_allocation_data heap_data;
|
||||
int ret;
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
fd = open ("/dev/dma_heap/system", O_RDONLY | O_CLOEXEC);
|
||||
if (fd == -1)
|
||||
g_error ("Failed to open /dev/dma_heap/system");
|
||||
}
|
||||
|
||||
heap_data.len = size;
|
||||
heap_data.fd = 0;
|
||||
heap_data.fd_flags = O_RDWR | O_CLOEXEC;
|
||||
heap_data.heap_flags = 0;
|
||||
|
||||
ret = ioctl (fd, DMA_HEAP_IOCTL_ALLOC, &heap_data);
|
||||
if (ret)
|
||||
g_error ("dma-buf allocation failed");
|
||||
|
||||
return heap_data.fd;
|
||||
}
|
||||
|
||||
static void
|
||||
populate_dma_buf (int fd,
|
||||
guchar *data,
|
||||
gsize size)
|
||||
{
|
||||
guchar *buf;
|
||||
|
||||
buf = mmap (NULL, size, PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
memcpy (buf, data, size);
|
||||
munmap (buf, size);
|
||||
}
|
||||
|
||||
|
||||
/* The YUV conversion code is adapted from weston/tests/yuv-buffer-test.c */
|
||||
|
||||
/*
|
||||
* Based on Rec. ITU-R BT.601-7
|
||||
*
|
||||
* This is intended to be obvious and accurate, not fast.
|
||||
*/
|
||||
static void
|
||||
x8r8g8b8_to_ycbcr8_bt601 (guint32 xrgb,
|
||||
guchar *y_out,
|
||||
guchar *cb_out,
|
||||
guchar *cr_out)
|
||||
{
|
||||
double y, cb, cr;
|
||||
double r = (xrgb >> 16) & 0xff;
|
||||
double g = (xrgb >> 8) & 0xff;
|
||||
double b = (xrgb >> 0) & 0xff;
|
||||
|
||||
/* normalize to [0.0, 1.0] */
|
||||
r /= 255.0;
|
||||
g /= 255.0;
|
||||
b /= 255.0;
|
||||
|
||||
/* Y normalized to [0.0, 1.0], Cb and Cr [-0.5, 0.5] */
|
||||
y = 0.299 * r + 0.587 * g + 0.114 * b;
|
||||
cr = (r - y) / 1.402;
|
||||
cb = (b - y) / 1.772;
|
||||
|
||||
/* limited range quantization to 8 bit */
|
||||
*y_out = round(219.0 * y + 16.0);
|
||||
if (cr_out)
|
||||
*cr_out = round(224.0 * cr + 128.0);
|
||||
if (cb_out)
|
||||
*cb_out = round(224.0 * cb + 128.0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 3 plane YCbCr
|
||||
* plane 0: Y plane, [7:0] Y
|
||||
* plane 1: Cb plane, [7:0] Cb
|
||||
* plane 2: Cr plane, [7:0] Cr
|
||||
* YUV420: 2x2 subsampled Cb (1) and Cr (2) planes
|
||||
* YUV444: no subsampling
|
||||
*/
|
||||
static guchar *
|
||||
y_u_v_create_buffer (uint32_t drm_format,
|
||||
guchar *rgb_data,
|
||||
int rgb_width,
|
||||
int rgb_height,
|
||||
int *size,
|
||||
int *u_offset,
|
||||
int *v_offset)
|
||||
{
|
||||
gsize bytes;
|
||||
int x, y;
|
||||
guint32 *rgb_row;
|
||||
guchar *y_base;
|
||||
guchar *u_base;
|
||||
guchar *v_base;
|
||||
guchar *y_row;
|
||||
guchar *u_row;
|
||||
guchar *v_row;
|
||||
guint32 argb;
|
||||
int sub = (drm_format == DRM_FORMAT_YUV420) ? 2 : 1;
|
||||
guchar *buf;
|
||||
|
||||
g_assert (drm_format == DRM_FORMAT_YUV420 ||
|
||||
drm_format == DRM_FORMAT_YUV444);
|
||||
|
||||
/* Full size Y plus quarter U and V */
|
||||
bytes = rgb_width * rgb_height +
|
||||
(rgb_width / sub) * (rgb_height / sub) * 2;
|
||||
|
||||
buf = g_new (guchar, bytes);
|
||||
|
||||
*size = bytes;
|
||||
*u_offset = rgb_width * rgb_height;
|
||||
*v_offset = *u_offset + (rgb_width / sub) * (rgb_height / sub);
|
||||
|
||||
y_base = buf;
|
||||
u_base = y_base + rgb_width * rgb_height;
|
||||
v_base = u_base + (rgb_width / sub) * (rgb_height / sub);
|
||||
|
||||
for (y = 0; y < rgb_height; y++)
|
||||
{
|
||||
rgb_row = (guint32 *) (rgb_data + y * 4 * rgb_width);
|
||||
y_row = y_base + y * rgb_width;
|
||||
u_row = u_base + (y / sub) * (rgb_width / sub);
|
||||
v_row = v_base + (y / sub) * (rgb_width / sub);
|
||||
|
||||
for (x = 0; x < rgb_width; x++)
|
||||
{
|
||||
/*
|
||||
* Sub-sample the source image instead, so that U and V
|
||||
* sub-sampling does not require proper
|
||||
* filtering/averaging/siting.
|
||||
*/
|
||||
argb = *(rgb_row + x / 2 * 2);
|
||||
|
||||
/*
|
||||
* A stupid way of "sub-sampling" chroma. This does not
|
||||
* do the necessary filtering/averaging/siting or
|
||||
* alternate Cb/Cr rows.
|
||||
*/
|
||||
if ((y & (sub - 1)) == 0 && (x & (sub - 1)) == 0)
|
||||
x8r8g8b8_to_ycbcr8_bt601 (argb, y_row + x, u_row + x / sub, v_row + x / sub);
|
||||
else
|
||||
x8r8g8b8_to_ycbcr8_bt601 (argb, y_row + x, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* 2 plane YCbCr
|
||||
* plane 0 = Y plane, [7:0] Y
|
||||
* plane 1 = Cr:Cb plane, [15:0] Cr:Cb little endian
|
||||
* 2x2 subsampled Cr:Cb plane
|
||||
*/
|
||||
static guchar *
|
||||
nv12_create_buffer (uint32_t drm_format,
|
||||
guchar *rgb_data,
|
||||
int rgb_width,
|
||||
int rgb_height,
|
||||
int *size,
|
||||
int *uv_offset)
|
||||
{
|
||||
size_t bytes;
|
||||
int x, y;
|
||||
uint32_t *rgb_row;
|
||||
uint8_t *y_base;
|
||||
uint16_t *uv_base;
|
||||
uint8_t *y_row;
|
||||
uint16_t *uv_row;
|
||||
uint32_t argb;
|
||||
uint8_t cr;
|
||||
uint8_t cb;
|
||||
guchar *buf;
|
||||
|
||||
g_assert (drm_format == DRM_FORMAT_NV12);
|
||||
|
||||
/* Full size Y, quarter UV */
|
||||
bytes = rgb_width * rgb_height +
|
||||
(rgb_width / 2) * (rgb_height / 2) * sizeof (uint16_t);
|
||||
|
||||
buf = g_new0 (guchar, bytes);
|
||||
|
||||
*uv_offset = rgb_width * rgb_height;
|
||||
y_base = buf;
|
||||
uv_base = (uint16_t *)(y_base + rgb_width * rgb_height);
|
||||
|
||||
for (y = 0; y < rgb_height; y++)
|
||||
{
|
||||
rgb_row = (uint32_t *) (rgb_data + y * 4 * rgb_width);
|
||||
y_row = y_base + y * rgb_width;
|
||||
uv_row = (uint16_t *) (uv_base + (y / 2) * (rgb_width / 2));
|
||||
|
||||
for (x = 0; x < rgb_width; x++)
|
||||
{
|
||||
/*
|
||||
* Sub-sample the source image instead, so that U and V
|
||||
* sub-sampling does not require proper
|
||||
* filtering/averaging/siting.
|
||||
*/
|
||||
argb = *(rgb_row + x / 2 * 2);
|
||||
|
||||
/*
|
||||
* A stupid way of "sub-sampling" chroma. This does not
|
||||
* do the necessary filtering/averaging/siting.
|
||||
*/
|
||||
if ((y & 1) == 0 && (x & 1) == 0)
|
||||
{
|
||||
x8r8g8b8_to_ycbcr8_bt601(argb, y_row + x, &cb, &cr);
|
||||
*(uv_row + x / 2) = ((uint16_t)cr << 8) | cb;
|
||||
}
|
||||
else
|
||||
{
|
||||
x8r8g8b8_to_ycbcr8_bt601(argb, y_row + x, NULL, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static GdkTexture *
|
||||
make_dmabuf_texture (const char *filename,
|
||||
guint32 format)
|
||||
{
|
||||
GdkTexture *texture;
|
||||
int width, height;
|
||||
gsize rgb_stride, rgb_size;
|
||||
guchar *rgb_data;
|
||||
int fd;
|
||||
GdkDmabufTextureBuilder *builder;
|
||||
GError *error = NULL;
|
||||
|
||||
texture = gdk_texture_new_from_filename (filename, NULL);
|
||||
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
rgb_stride = 4 * width;
|
||||
rgb_size = rgb_stride * height;
|
||||
|
||||
rgb_data = g_new0 (guchar, rgb_size);
|
||||
|
||||
gdk_texture_download (texture, rgb_data, rgb_stride);
|
||||
|
||||
g_object_unref (texture);
|
||||
|
||||
builder = gdk_dmabuf_texture_builder_new ();
|
||||
|
||||
gdk_dmabuf_texture_builder_set_display (builder, gdk_display_get_default ());
|
||||
gdk_dmabuf_texture_builder_set_width (builder, width);
|
||||
gdk_dmabuf_texture_builder_set_height (builder, height);
|
||||
gdk_dmabuf_texture_builder_set_fourcc (builder, format);
|
||||
gdk_dmabuf_texture_builder_set_modifier (builder, DRM_FORMAT_MOD_LINEAR);
|
||||
|
||||
if (format == DRM_FORMAT_XRGB8888)
|
||||
{
|
||||
gdk_dmabuf_texture_builder_set_n_planes (builder, 1);
|
||||
|
||||
fd = allocate_dma_buf (rgb_size);
|
||||
populate_dma_buf (fd, rgb_data, rgb_size);
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 0, fd);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 0, rgb_stride);
|
||||
}
|
||||
else if (format == DRM_FORMAT_YUV420)
|
||||
{
|
||||
guchar *buf;
|
||||
int size, u_offset, v_offset;
|
||||
|
||||
gdk_dmabuf_texture_builder_set_n_planes (builder, 3);
|
||||
|
||||
buf = y_u_v_create_buffer (format, rgb_data, width, height, &size, &u_offset, &v_offset);
|
||||
|
||||
fd = allocate_dma_buf (width * height);
|
||||
populate_dma_buf (fd, buf, width * height);
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 0, fd);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 0, width);
|
||||
gdk_dmabuf_texture_builder_set_offset (builder, 0, 0);
|
||||
|
||||
fd = allocate_dma_buf ((width / 2) * (height / 2));
|
||||
populate_dma_buf (fd, buf + u_offset, (width / 2) * (height / 2));
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 1, fd);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 1, width / 2);
|
||||
gdk_dmabuf_texture_builder_set_offset (builder, 1, 0);
|
||||
|
||||
fd = allocate_dma_buf ((width / 2) * (height / 2));
|
||||
populate_dma_buf (fd, buf + v_offset, (width / 2) * (height / 2));
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 2, fd);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 2, width / 2);
|
||||
gdk_dmabuf_texture_builder_set_offset (builder, 2, 0);
|
||||
|
||||
g_free (buf);
|
||||
}
|
||||
else if (format == DRM_FORMAT_NV12)
|
||||
{
|
||||
guchar *buf;
|
||||
int size, uv_offset;
|
||||
|
||||
gdk_dmabuf_texture_builder_set_n_planes (builder, 2);
|
||||
|
||||
buf = nv12_create_buffer (format, rgb_data, width, height, &size, &uv_offset);
|
||||
|
||||
fd = allocate_dma_buf (width * height);
|
||||
populate_dma_buf (fd, buf, width * height);
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 0, fd);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 0, width);
|
||||
gdk_dmabuf_texture_builder_set_offset (builder, 0, 0);
|
||||
|
||||
fd = allocate_dma_buf ((width / 2) * (height / 2) * sizeof (uint16_t));
|
||||
populate_dma_buf (fd, buf + uv_offset, (width / 2) * (height / 2) * sizeof (uint16_t));
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 1, fd);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 1, width);
|
||||
gdk_dmabuf_texture_builder_set_offset (builder, 1, 0);
|
||||
|
||||
g_free (buf);
|
||||
}
|
||||
|
||||
g_free (rgb_data);
|
||||
|
||||
texture = gdk_dmabuf_texture_builder_build (builder, NULL, NULL, &error);
|
||||
if (!texture)
|
||||
g_error ("Failed to create dmabuf texture: %s", error->message);
|
||||
|
||||
g_object_unref (builder);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
static guint32 supported_formats[] = {
|
||||
DRM_FORMAT_XRGB8888,
|
||||
DRM_FORMAT_YUV420,
|
||||
DRM_FORMAT_NV12,
|
||||
};
|
||||
|
||||
static gboolean
|
||||
format_is_supported (guint32 fmt)
|
||||
{
|
||||
for (int i = 0; i < G_N_ELEMENTS (supported_formats); i++)
|
||||
{
|
||||
if (supported_formats[i] == fmt)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static char *
|
||||
supported_formats_to_string (void)
|
||||
{
|
||||
GString *s;
|
||||
|
||||
s = g_string_new ("");
|
||||
for (int i = 0; i < G_N_ELEMENTS (supported_formats); i++)
|
||||
{
|
||||
if (s->len)
|
||||
g_string_append (s, ", ");
|
||||
g_string_append_printf (s, "%.4s", (char *)&supported_formats[i]);
|
||||
}
|
||||
|
||||
return g_string_free (s, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
usage (void)
|
||||
{
|
||||
char *formats = supported_formats_to_string ();
|
||||
g_print ("Usage: testdmabuf FORMAT FILE\n"
|
||||
"Supported formats: %s\n", formats);
|
||||
g_free (formats);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
static guint32
|
||||
parse_format (const char *a)
|
||||
{
|
||||
if (strlen (a) == 4)
|
||||
{
|
||||
guint32 format = fourcc_code (a[0], a[1], a[2], a[3]);
|
||||
if (format_is_supported (format))
|
||||
return format;
|
||||
}
|
||||
|
||||
usage ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
GdkTexture *texture;
|
||||
GtkWidget *window, *picture;
|
||||
char *filename;
|
||||
guint32 format;
|
||||
|
||||
if (argc != 3)
|
||||
g_assert (argc == 3);
|
||||
|
||||
format = parse_format (argv[1]);
|
||||
filename = argv[2];
|
||||
|
||||
gtk_init ();
|
||||
|
||||
/* Get the list of supported formats with GDK_DEBUG=opengl */
|
||||
gdk_display_get_dmabuf_formats (gdk_display_get_default ());
|
||||
|
||||
texture = make_dmabuf_texture (filename, format);
|
||||
|
||||
window = gtk_window_new ();
|
||||
|
||||
picture = gtk_picture_new_for_paintable (GDK_PAINTABLE (texture));
|
||||
|
||||
gtk_window_set_child (GTK_WINDOW (window), picture);
|
||||
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
|
||||
while (g_list_model_get_n_items (gtk_window_get_toplevels ()) > 0)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
return 0;
|
||||
}
|
10
testsuite/gsk/compare/mask-texture-color-alpha.node
Normal file
10
testsuite/gsk/compare/mask-texture-color-alpha.node
Normal file
@@ -0,0 +1,10 @@
|
||||
mask {
|
||||
source: color {
|
||||
bounds: 0 0 16 16;
|
||||
color: rgb(85,109,89);
|
||||
}
|
||||
mask: texture {
|
||||
bounds: 0 0 16 16;
|
||||
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAAAmJLR0QAKwYx2nIAAAIbSURBVCgVARAC7/0BRP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAD6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAEAADCAAAAAABE/wAAAAAAAAAAAAAAAAAAvAEAAAAARAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABRP/5AQAAAAAH/wAAAAAAAAAAAAAAAAAA+QEAAAAAB/8EAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAC+AAAAAABCAAAAAAAAAAAAAAAAAAAAvgAAAAAAQgAEAAD+AAAAAAC8AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABRP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADS0BDC/NHlFQAAAABJRU5ErkJggg==");
|
||||
}
|
||||
}
|
BIN
testsuite/gsk/compare/mask-texture-color-alpha.png
Normal file
BIN
testsuite/gsk/compare/mask-texture-color-alpha.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 120 B |
@@ -70,6 +70,7 @@ compare_render_tests = [
|
||||
'mask-clipped-inverted-alpha',
|
||||
'mask-modes',
|
||||
'mask-modes-with-alpha',
|
||||
'mask-texture-color-alpha',
|
||||
'nested-rounded-clips',
|
||||
'opacity_clip',
|
||||
'opacity-overdraw',
|
||||
|
@@ -217,6 +217,10 @@ test_type (gconstpointer data)
|
||||
(strcmp (pspec->name, "default-display") == 0))
|
||||
check = FALSE;
|
||||
|
||||
if (g_type_is_a (type, GDK_TYPE_DISPLAY) &&
|
||||
(strcmp (pspec->name, "dmabuf-formats") == 0))
|
||||
check = FALSE;
|
||||
|
||||
if (g_type_is_a (type, GDK_TYPE_MONITOR) &&
|
||||
(strcmp (pspec->name, "geometry") == 0))
|
||||
check = FALSE;
|
||||
|
Reference in New Issue
Block a user