Compare commits

...

19 Commits

Author SHA1 Message Date
Matthias Clasen
39c5c5a561 gsk: Only use fences when supported 2023-04-26 12:03:41 +02:00
Matthias Clasen
69a0d4c7d7 glarea: Only use fences when supported 2023-04-26 12:03:29 +02:00
Matthias Clasen
7fe48792ee glcontext: Add a way to check for fence sync 2023-04-26 11:59:51 +02:00
Matthias Clasen
57a75f760d glarea: Delete the sync object too
This is the responsibility of the destroy function
passed to the gl texture builder.
2023-04-26 09:26:25 +02:00
Matthias Clasen
bc618470bf Improve the documentation 2023-04-26 09:26:25 +02:00
Matthias Clasen
f56ba41893 gldriver: Add a sync when creating textures 2023-04-25 11:54:34 +02:00
Matthias Clasen
854591a5f9 gstreamer: Defer the sync
Don't sync right when we receive the buffer,
pass it along with the texture to be executed
later in the renderer.
2023-04-25 11:54:34 +02:00
Matthias Clasen
c9e02edfc3 glarea: Synchronize
Create a fence object and pass it along when
creating the GL texture, so that the GL renderer
can wait for the texture to be ready.
2023-04-25 11:54:34 +02:00
Matthias Clasen
12ed685013 gsk: Synchronize when using textures
Pass the GLsync object from texture into our
command queue, and when executing the queue,
wait on the sync object the first time we
use its associated texture.
2023-04-25 11:54:34 +02:00
Matthias Clasen
ac991483f2 gltexture: Synchronize when downloading
If the GL texture has a sync object, wait
on it before downloading the data.
2023-04-25 11:54:34 +02:00
Matthias Clasen
f3d84fd513 gltexture: Optionally take a sync object
Add a new (private, for now) constructor takes
a GLsync together with a texture id, for synchronization.
2023-04-25 11:03:51 +02:00
Benjamin Otte
318faf7b0d gltexture: Deprecate gdk_gl_texture_new()
Use GdkGLTextureBuilder instead.
2023-04-24 23:14:48 +02:00
Benjamin Otte
fdc72775ab glrenderer: Port to GdkGLTextureBuilder 2023-04-24 23:14:48 +02:00
Benjamin Otte
b9684c6036 media-gstreamer: Port to GdkGLTextureBuilder
This is a rudimentary port that does not take advantage of all the cool
new formats that we could support now.
2023-04-24 23:14:48 +02:00
Benjamin Otte
408ea049de testsuite: Use GLTextureBuilder 2023-04-24 23:14:48 +02:00
Benjamin Otte
1bd13c819b glarea: Port to GdkGLTextureBuilder 2023-04-24 23:14:48 +02:00
Benjamin Otte
6559e34cac texturebuilder: Pass the destroy notify to the build() function
This is more compatible with bindings that want to create per-object
callbacks and not have their callbacks reused over different build()
calls.
2023-04-24 23:14:48 +02:00
Benjamin Otte
ef4d3f172d texturebuilder: Add ::format and ::has-mipmap
We were trying to deduce that previously. Now we have explicit API
2023-04-24 21:27:53 +02:00
Benjamin Otte
8d3593af55 gdk: Add GdkGLTextureBuilder
Building GL textures is complicated, so create an object to make them.

So far, this object just contains the functionality of
gdk_gl_texture_new(), but that will change in the future.
2023-04-24 14:39:03 +02:00
17 changed files with 1002 additions and 66 deletions

View File

@@ -54,6 +54,7 @@
#include <gdk/gdkframetimings.h>
#include <gdk/gdkglcontext.h>
#include <gdk/gdkgltexture.h>
#include <gdk/gdkgltexturebuilder.h>
#include <gdk/gdkkeys.h>
#include <gdk/gdkkeysyms.h>
#include <gdk/gdkmemorytexture.h>

View File

@@ -106,6 +106,7 @@ typedef struct {
guint has_khr_debug : 1;
guint use_khr_debug : 1;
guint has_half_float : 1;
guint has_fence_sync : 1;
guint has_unpack_subimage : 1;
guint has_debug_output : 1;
guint extensions_checked : 1;
@@ -1557,6 +1558,10 @@ gdk_gl_context_check_extensions (GdkGLContext *context)
priv->has_half_float = gdk_gl_context_check_version (context, 3, 0, 3, 0) ||
epoxy_has_gl_extension ("OES_vertex_half_float");
priv->has_fence_sync = gdk_gl_context_check_version (context, 3, 2, 3, 0) ||
epoxy_has_gl_extension ("GL_ARB_sync") ||
epoxy_has_gl_extension ("GK_APPLE_sync");
#ifdef G_ENABLE_DEBUG
{
int max_texture_size;
@@ -1568,7 +1573,8 @@ gdk_gl_context_check_extensions (GdkGLContext *context)
"* Extensions checked:\n"
" - GL_KHR_debug: %s\n"
" - GL_EXT_unpack_subimage: %s\n"
" - OES_vertex_half_float: %s",
" - half float: %s\n"
" - fence sync: %s",
gdk_gl_context_get_use_es (context) ? "OpenGL ES" : "OpenGL",
priv->gl_version / 10, priv->gl_version % 10,
priv->is_legacy ? "legacy" : "core",
@@ -1576,7 +1582,8 @@ gdk_gl_context_check_extensions (GdkGLContext *context)
max_texture_size,
priv->has_khr_debug ? "yes" : "no",
priv->has_unpack_subimage ? "yes" : "no",
priv->has_half_float ? "yes" : "no");
priv->has_half_float ? "yes" : "no",
priv->has_fence_sync ? "yes" : "no");
}
#endif
@@ -1808,6 +1815,14 @@ gdk_gl_context_has_vertex_half_float (GdkGLContext *self)
return priv->has_half_float;
}
gboolean
gdk_gl_context_has_fence_sync (GdkGLContext *self)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (self);
return priv->has_fence_sync;
}
/* This is currently private! */
/* When using GL/ES, don't flip the 'R' and 'B' bits on Windows/ANGLE for glReadPixels() */
gboolean

View File

@@ -162,6 +162,8 @@ gboolean gdk_gl_context_use_es_bgra (GdkGLContext
gboolean gdk_gl_context_has_vertex_half_float (GdkGLContext *self) G_GNUC_PURE;
gboolean gdk_gl_context_has_fence_sync (GdkGLContext *self) G_GNUC_PURE;
double gdk_gl_context_get_scale (GdkGLContext *self);
G_END_DECLS

View File

@@ -39,6 +39,7 @@ struct _GdkGLTexture {
GdkGLContext *context;
guint id;
gboolean has_mipmap;
gpointer sync;
GdkTexture *saved;
@@ -99,6 +100,10 @@ gdk_gl_texture_invoke_callback (gpointer data)
context = gdk_display_get_gl_context (gdk_gl_context_get_display (invoke->self->context));
gdk_gl_context_make_current (context);
if (invoke->self->sync && context != invoke->self->context)
glWaitSync (invoke->self->sync, 0, GL_TIMEOUT_IGNORED);
glBindTexture (GL_TEXTURE_2D, invoke->self->id);
invoke->func (invoke->self, context, invoke->data);
@@ -296,6 +301,12 @@ gdk_gl_texture_has_mipmap (GdkGLTexture *self)
return self->has_mipmap;
}
gpointer
gdk_gl_texture_get_sync (GdkGLTexture *self)
{
return self->sync;
}
/**
* gdk_gl_texture_release:
* @self: a `GdkTexture` wrapping a GL texture
@@ -321,6 +332,29 @@ gdk_gl_texture_release (GdkGLTexture *self)
drop_gl_resources (self);
}
GdkTexture *
gdk_gl_texture_new_from_builder (GdkGLTextureBuilder *builder,
GDestroyNotify destroy,
gpointer data)
{
GdkGLTexture *self;
self = g_object_new (GDK_TYPE_GL_TEXTURE,
"width", gdk_gl_texture_builder_get_width (builder),
"height", gdk_gl_texture_builder_get_height (builder),
NULL);
self->context = g_object_ref (gdk_gl_texture_builder_get_context (builder));
self->id = gdk_gl_texture_builder_get_id (builder);
GDK_TEXTURE (self)->format = gdk_gl_texture_builder_get_format (builder);
self->has_mipmap = gdk_gl_texture_builder_get_has_mipmap (builder);
self->sync = gdk_gl_texture_builder_get_sync (builder);
self->destroy = destroy;
self->data = data;
return GDK_TEXTURE (self);
}
static void
gdk_gl_texture_determine_format (GdkGLTexture *self)
{
@@ -463,6 +497,9 @@ gdk_gl_texture_determine_format (GdkGLTexture *self)
*
* Return value: (transfer full) (type GdkGLTexture): A newly-created
* `GdkTexture`
*
* Deprecated: 4.12: [class@Gdk.GLTextureBuilder] supercedes this function
* and provides extended functionality for creating GL textures.
*/
GdkTexture *
gdk_gl_texture_new (GdkGLContext *context,

View File

@@ -38,7 +38,7 @@ typedef struct _GdkGLTextureClass GdkGLTextureClass;
GDK_AVAILABLE_IN_ALL
GType gdk_gl_texture_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GDK_DEPRECATED_IN_4_12_FOR(GdkGLTextureBuilder)
GdkTexture * gdk_gl_texture_new (GdkGLContext *context,
guint id,
int width,

654
gdk/gdkgltexturebuilder.c Normal file
View File

@@ -0,0 +1,654 @@
/*
* Copyright © 2023 Benjamin Otte
*
* 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: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gdkgltexturebuilder.h"
#include "gdkenumtypes.h"
#include "gdkglcontext.h"
#include "gdkgltextureprivate.h"
struct _GdkGLTextureBuilder
{
GObject parent_instance;
GdkGLContext *context;
guint id;
int width;
int height;
GdkMemoryFormat format;
gboolean has_mipmap;
gpointer sync;
};
struct _GdkGLTextureBuilderClass
{
GObjectClass parent_class;
};
/**
* GdkGLTextureBuilder:
*
* `GdkGLTextureBuilder` is a buider used to construct [class@Gdk.Texture] objects from
* GL textures.
*
* The operation is quite simple: Create a texture builder, set all the necessary
* properties - keep in mind that the properties [property@Gdk.GLTextureBuilder:context],
* [property@Gdk.GLTextureBuilder:id], [property@Gdk.GLTextureBuilder:width], and
* [property@Gdk.GLTextureBuilder:height] are mandatory - and then call
* [method@Gdk.GLTextureBuilder.build] to create the new texture.
*
* `GdkGLTextureBuilder` can be used for quick one-shot construction of
* textures as well as kept around and reused to construct multiple textures.
*
* Since: 4.12
*/
enum
{
PROP_0,
PROP_CONTEXT,
PROP_FORMAT,
PROP_HAS_MIPMAP,
PROP_HEIGHT,
PROP_ID,
PROP_SYNC,
PROP_WIDTH,
N_PROPS
};
G_DEFINE_TYPE (GdkGLTextureBuilder, gdk_gl_texture_builder, G_TYPE_OBJECT)
static GParamSpec *properties[N_PROPS] = { NULL, };
static void
gdk_gl_texture_builder_dispose (GObject *object)
{
GdkGLTextureBuilder *self = GDK_GL_TEXTURE_BUILDER (object);
g_clear_object (&self->context);
G_OBJECT_CLASS (gdk_gl_texture_builder_parent_class)->dispose (object);
}
static void
gdk_gl_texture_builder_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GdkGLTextureBuilder *self = GDK_GL_TEXTURE_BUILDER (object);
switch (property_id)
{
case PROP_CONTEXT:
g_value_set_object (value, self->context);
break;
case PROP_FORMAT:
g_value_set_enum (value, self->format);
break;
case PROP_HAS_MIPMAP:
g_value_set_boolean (value, self->has_mipmap);
break;
case PROP_HEIGHT:
g_value_set_int (value, self->height);
break;
case PROP_ID:
g_value_set_uint (value, self->id);
break;
case PROP_SYNC:
g_value_set_pointer (value, self->sync);
break;
case PROP_WIDTH:
g_value_set_int (value, self->width);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gdk_gl_texture_builder_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GdkGLTextureBuilder *self = GDK_GL_TEXTURE_BUILDER (object);
switch (property_id)
{
case PROP_CONTEXT:
gdk_gl_texture_builder_set_context (self, g_value_get_object (value));
break;
case PROP_FORMAT:
gdk_gl_texture_builder_set_format (self, g_value_get_enum (value));
break;
case PROP_HAS_MIPMAP:
gdk_gl_texture_builder_set_has_mipmap (self, g_value_get_boolean (value));
break;
case PROP_HEIGHT:
gdk_gl_texture_builder_set_height (self, g_value_get_int (value));
break;
case PROP_ID:
gdk_gl_texture_builder_set_id (self, g_value_get_uint (value));
break;
case PROP_SYNC:
gdk_gl_texture_builder_set_sync (self, g_value_get_pointer (value));
break;
case PROP_WIDTH:
gdk_gl_texture_builder_set_width (self, g_value_get_int (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gdk_gl_texture_builder_class_init (GdkGLTextureBuilderClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = gdk_gl_texture_builder_dispose;
gobject_class->get_property = gdk_gl_texture_builder_get_property;
gobject_class->set_property = gdk_gl_texture_builder_set_property;
/**
* GdkGLTextureBuilder:context: (attributes org.gdk.Property.get=gdk_gl_texture_builder_get_context org.gdk.Property.set=gdk_gl_texture_builder_set_context)
*
* The context owning the texture.
*
* Since: 4.12
*/
properties[PROP_CONTEXT] =
g_param_spec_object ("context", NULL, NULL,
GDK_TYPE_GL_CONTEXT,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkGLTextureBuilder:format: (attributes org.gdk.Property.get=gdk_gl_texture_builder_get_format org.gdk.Property.set=gdk_gl_texture_builder_set_format)
*
* The format when downloading the texture.
*
* Since: 4.12
*/
properties[PROP_FORMAT] =
g_param_spec_enum ("format", NULL, NULL,
GDK_TYPE_MEMORY_FORMAT,
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkGLTextureBuilder:has-mipmap: (attributes org.gdk.Property.get=gdk_gl_texture_builder_get_has_mipmap org.gdk.Property.set=gdk_gl_texture_builder_set_has_mipmap)
*
* If the texture has a mipmap.
*
* Since: 4.12
*/
properties[PROP_HAS_MIPMAP] =
g_param_spec_boolean ("has-mipmap", NULL, NULL,
FALSE,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkGLTextureBuilder:height: (attributes org.gdk.Property.get=gdk_gl_texture_builder_get_height org.gdk.Property.set=gdk_gl_texture_builder_set_height)
*
* The height of the texture.
*
* Since: 4.12
*/
properties[PROP_HEIGHT] =
g_param_spec_int ("height", NULL, NULL,
G_MININT, G_MAXINT, 0,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkGLTextureBuilder:id: (attributes org.gdk.Property.get=gdk_gl_texture_builder_get_id org.gdk.Property.set=gdk_gl_texture_builder_set_id)
*
* The texture ID to use.
*
* Since: 4.12
*/
properties[PROP_ID] =
g_param_spec_uint ("id", NULL, NULL,
0, G_MAXUINT, 0,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkGLTextureBuilder:sync: (attributes org.gdk.Property.get=gdk_gl_texture_builder_get_sync org.gdk.Property.set=gdk_gl_texture_builder_set_sync)
*
* An optional GLSync object.
*
* If this is not `NULL, you have to call `glWaitSync` on it before using the texture.
*
* Since: 4.12
*/
properties[PROP_SYNC] =
g_param_spec_pointer ("sync", NULL, NULL,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkGLTextureBuilder:width: (attributes org.gdk.Property.get=gdk_gl_texture_builder_get_width org.gdk.Property.set=gdk_gl_texture_builder_set_width)
*
* The width of the texture.
*
* Since: 4.12
*/
properties[PROP_WIDTH] =
g_param_spec_int ("width", NULL, NULL,
G_MININT, G_MAXINT, 0,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
static void
gdk_gl_texture_builder_init (GdkGLTextureBuilder *self)
{
self->format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
}
/**
* gdk_gl_texture_builder_new: (constructor):
*
* Creates a new texture builder.
*
* Returns: the new `GdkTextureBuilder`
*
* Since: 4.12
**/
GdkGLTextureBuilder *
gdk_gl_texture_builder_new (void)
{
return g_object_new (GDK_TYPE_GL_TEXTURE_BUILDER, NULL);
}
/**
* gdk_gl_texture_builder_get_context: (attributes org.gdk.Method.get_property=context)
* @self: a `GdkGLTextureBuilder`
*
* Gets the context previously set via gdk_gl_texture_builder_set_context() or
* %NULL if none was set.
*
* Returns: (transfer none) (nullable): The context
*
* Since: 4.12
*/
GdkGLContext *
gdk_gl_texture_builder_get_context (GdkGLTextureBuilder *self)
{
g_return_val_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self), NULL);
return self->context;
}
/**
* gdk_gl_texture_builder_set_context: (attributes org.gdk.Method.set_property=context)
* @self: a `GdkGLTextureBuilder`
* @context: (nullable): The context the texture beongs to or %NULL to unset
*
* Sets the context to be used for the texture. This is the context that owns
* the texture.
*
* The context must be set before calling [method@Gdk.GLTextureBuilder.build].
*
* Since: 4.12
*/
void
gdk_gl_texture_builder_set_context (GdkGLTextureBuilder *self,
GdkGLContext *context)
{
g_return_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self));
g_return_if_fail (context == NULL || GDK_IS_GL_CONTEXT (context));
if (!g_set_object (&self->context, context))
return;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CONTEXT]);
}
/**
* gdk_gl_texture_builder_get_height: (attributes org.gdk.Method.get_property=height)
* @self: a `GdkGLTextureBuilder`
*
* Gets the height previously set via gdk_gl_texture_builder_set_height() or
* 0 if the height wasn't set.
*
* Returns: The height
*
* Since: 4.12
*/
int
gdk_gl_texture_builder_get_height (GdkGLTextureBuilder *self)
{
g_return_val_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self), 0);
return self->height;
}
/**
* gdk_gl_texture_builder_set_height: (attributes org.gdk.Method.set_property=height)
* @self: a `GdkGLTextureBuilder`
* @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.12
*/
void
gdk_gl_texture_builder_set_height (GdkGLTextureBuilder *self,
int height)
{
g_return_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self));
if (self->height == height)
return;
self->height = height;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HEIGHT]);
}
/**
* gdk_gl_texture_builder_get_id: (attributes org.gdk.Method.get_property=id)
* @self: a `GdkGLTextureBuilder`
*
* Gets the texture id previously set via gdk_gl_texture_builder_set_id() or
* 0 if the id wasn't set.
*
* Returns: The id
*
* Since: 4.12
*/
guint
gdk_gl_texture_builder_get_id (GdkGLTextureBuilder *self)
{
g_return_val_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self), 0);
return self->id;
}
/**
* gdk_gl_texture_builder_set_id: (attributes org.gdk.Method.set_property=id)
* @self: a `GdkGLTextureBuilder`
* @id: The texture id to be used for creating the texture
*
* Sets the texture id of the texture. The texture id must remain unmodified
* until the texture was finalized. See [method@Gdk.GLTextureBuilder.build]
* for a longer discussion.
*
* The id must be set before calling [method@Gdk.GLTextureBuilder.build].
*
* Since: 4.12
*/
void
gdk_gl_texture_builder_set_id (GdkGLTextureBuilder *self,
guint id)
{
g_return_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self));
if (self->id == id)
return;
self->id = id;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ID]);
}
/**
* gdk_gl_texture_builder_get_width: (attributes org.gdk.Method.get_property=width)
* @self: a `GdkGLTextureBuilder`
*
* Gets the width previously set via gdk_gl_texture_builder_set_width() or
* 0 if the width wasn't set.
*
* Returns: The width
*
* Since: 4.12
*/
int
gdk_gl_texture_builder_get_width (GdkGLTextureBuilder *self)
{
g_return_val_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self), 0);
return self->width;
}
/**
* gdk_gl_texture_builder_set_width: (attributes org.gdk.Method.set_property=width)
* @self: a `GdkGLTextureBuilder`
* @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.12
*/
void
gdk_gl_texture_builder_set_width (GdkGLTextureBuilder *self,
int width)
{
g_return_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self));
if (self->width == width)
return;
self->width = width;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_WIDTH]);
}
/**
* gdk_gl_texture_builder_get_has_mipmap: (attributes org.gdk.Method.get_property=has-mipmap)
* @self: a `GdkGLTextureBuilder`
*
* Gets whether the texture has a mipmap.
*
* Returns: Whether the texture has a mipmap
*
* Since: 4.12
*/
gboolean
gdk_gl_texture_builder_get_has_mipmap (GdkGLTextureBuilder *self)
{
g_return_val_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self), FALSE);
return self->has_mipmap;
}
/**
* gdk_gl_texture_builder_set_has_mipmap: (attributes org.gdk.Method.set_property=has-mipmap)
* @self: a `GdkGLTextureBuilder`
* @has_mipmap: Whether the texture has a mipmap
*
* Sets whether the texture has a mipmap. This allows the renderer and other users of the
* generated texture to use a higher quality downscaling.
*
* Typically, the `glGenerateMipmap` function is used to generate a mimap.
*
* Since: 4.12
*/
void
gdk_gl_texture_builder_set_has_mipmap (GdkGLTextureBuilder *self,
gboolean has_mipmap)
{
g_return_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self));
if (self->has_mipmap == has_mipmap)
return;
self->has_mipmap = has_mipmap;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HAS_MIPMAP]);
}
/**
* gdk_gl_texture_builder_get_sync: (attributes org.gdk.Method.get_property=sync)
* @self: a `GdkGLTextureBuilder`
*
* Gets the GLSync object associated with the texture builder.
*
* If this function is returning something other than `NULL`, you have to
* call `glWaitSync` on the returned object before using the texture.
*
* Returns: (nullable): the GLSync object
*
* Since: 4.12
*/
gpointer
gdk_gl_texture_builder_get_sync (GdkGLTextureBuilder *self)
{
g_return_val_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self), NULL);
return self->sync;
}
/**
* gdk_gl_texture_builder_set_sync: (attributes org.gdk.Method.set_property=sync)
* @self: a `GdkGLTextureBuilder`
* @sync: (nullable): the GLSync object
*
* Sets the GLSync object to use for the texture.
*
* The `destroy` function that is passed to [method@Gdk.GLTextureBuilder.build]
* is responsible for freeing the sync object when it is no longer needed.
*
* Since: 4.12
*/
void
gdk_gl_texture_builder_set_sync (GdkGLTextureBuilder *self,
gpointer sync)
{
g_return_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self));
if (self->sync == sync)
return;
self->sync = sync;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SYNC]);
}
/**
* gdk_gl_texture_builder_get_format: (attributes org.gdk.Method.get_property=format)
* @self: a `GdkGLTextureBuilder`
*
* Gets the format previously set via gdk_gl_texture_builder_set_format().
*
* Returns: The format
*
* Since: 4.12
*/
GdkMemoryFormat
gdk_gl_texture_builder_get_format (GdkGLTextureBuilder *self)
{
g_return_val_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self), GDK_MEMORY_R8G8B8A8_PREMULTIPLIED);
return self->format;
}
/**
* gdk_gl_texture_builder_set_format: (attributes org.gdk.Method.set_property=format)
* @self: a `GdkGLTextureBuilder`
* @format: The texture's format
*
* Sets the format of the texture. The default is `GDK_MEMORY_R8G8B8A8_PREMULTIPLIED`.
*
* The format is the preferred format the texture data should be downloaded to. The
* format must be supported by the GL version of [property@Gdk.GLTextureBuilder:context].
*
* Setting the right format is particularly useful when using high bit depth textures
* to preserve the bit depth, to set the correct value for unpremultiplied textures
* and to make sure opaque textures are treated as such.
*
* Since: 4.12
*/
void
gdk_gl_texture_builder_set_format (GdkGLTextureBuilder *self,
GdkMemoryFormat format)
{
g_return_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self));
if (self->format == format)
return;
self->format = format;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FORMAT]);
}
/**
* gdk_gl_texture_builder_build:
* @self: a `GdkGLTextureBuilder`
* @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;
* either when the texture is finalized or by an explicit call to
* [method@Gdk.GLTexture.release]. It should release all GL resources associated
* with the texture, such as the [property@Gdk.GLTextureBuilder:id] and the
* [property@Gdk.GLTextureBuilder:sync].
*
* 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.
*
* Returns: (transfer full): a newly built `GdkTexture`
*
* Since: 4.12
*/
GdkTexture *
gdk_gl_texture_builder_build (GdkGLTextureBuilder *self,
GDestroyNotify destroy,
gpointer data)
{
g_return_val_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self), NULL);
g_return_val_if_fail (destroy == NULL || data != NULL, NULL);
g_return_val_if_fail (self->context != NULL, NULL);
g_return_val_if_fail (self->id != 0, NULL);
g_return_val_if_fail (self->width > 0, NULL);
g_return_val_if_fail (self->height > 0, NULL);
return gdk_gl_texture_new_from_builder (self, destroy, data);
}

87
gdk/gdkgltexturebuilder.h Normal file
View File

@@ -0,0 +1,87 @@
/*
* Copyright © 2023 Benjamin Otte
*
* 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: Benjamin Otte <otte@gnome.org>
*/
#pragma once
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif
#include <gdk/gdkenums.h>
#include <gdk/gdktypes.h>
#include <gdk/gdkversionmacros.h>
G_BEGIN_DECLS
#define GDK_TYPE_GL_TEXTURE_BUILDER (gdk_gl_texture_builder_get_type ())
GDK_AVAILABLE_IN_4_12
GDK_DECLARE_INTERNAL_TYPE (GdkGLTextureBuilder, gdk_gl_texture_builder, GDK, GL_TEXTURE_BUILDER, GObject)
GDK_AVAILABLE_IN_4_12
GdkGLTextureBuilder * gdk_gl_texture_builder_new (void);
GDK_AVAILABLE_IN_4_12
GdkGLContext * gdk_gl_texture_builder_get_context (GdkGLTextureBuilder *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_12
void gdk_gl_texture_builder_set_context (GdkGLTextureBuilder *self,
GdkGLContext *context);
GDK_AVAILABLE_IN_4_12
guint gdk_gl_texture_builder_get_id (GdkGLTextureBuilder *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_12
void gdk_gl_texture_builder_set_id (GdkGLTextureBuilder *self,
guint id);
GDK_AVAILABLE_IN_4_12
int gdk_gl_texture_builder_get_width (GdkGLTextureBuilder *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_12
void gdk_gl_texture_builder_set_width (GdkGLTextureBuilder *self,
int width);
GDK_AVAILABLE_IN_4_12
int gdk_gl_texture_builder_get_height (GdkGLTextureBuilder *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_12
void gdk_gl_texture_builder_set_height (GdkGLTextureBuilder *self,
int height);
GDK_AVAILABLE_IN_4_12
GdkMemoryFormat gdk_gl_texture_builder_get_format (GdkGLTextureBuilder *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_12
void gdk_gl_texture_builder_set_format (GdkGLTextureBuilder *self,
GdkMemoryFormat format);
GDK_AVAILABLE_IN_4_12
gboolean gdk_gl_texture_builder_get_has_mipmap (GdkGLTextureBuilder *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_12
void gdk_gl_texture_builder_set_has_mipmap (GdkGLTextureBuilder *self,
gboolean has_mipmap);
GDK_AVAILABLE_IN_4_12
gpointer gdk_gl_texture_builder_get_sync (GdkGLTextureBuilder *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_12
void gdk_gl_texture_builder_set_sync (GdkGLTextureBuilder *self,
gpointer sync);
GDK_AVAILABLE_IN_4_12
GdkTexture * gdk_gl_texture_builder_build (GdkGLTextureBuilder *self,
GDestroyNotify destroy,
gpointer data);
G_END_DECLS

View File

@@ -2,13 +2,20 @@
#include "gdkgltexture.h"
#include "gdkgltexturebuilder.h"
#include "gdktextureprivate.h"
G_BEGIN_DECLS
GdkTexture * gdk_gl_texture_new_from_builder (GdkGLTextureBuilder *builder,
GDestroyNotify destroy,
gpointer data);
GdkGLContext * gdk_gl_texture_get_context (GdkGLTexture *self);
guint gdk_gl_texture_get_id (GdkGLTexture *self);
gboolean gdk_gl_texture_has_mipmap (GdkGLTexture *self);
gpointer gdk_gl_texture_get_sync (GdkGLTexture *self);
G_END_DECLS

View File

@@ -29,6 +29,7 @@ gdk_public_sources = files([
'gdkglcontext.c',
'gdkglobals.c',
'gdkgltexture.c',
'gdkgltexturebuilder.c',
'gdkhsla.c',
'gdkkeys.c',
'gdkkeyuni.c',
@@ -86,6 +87,7 @@ gdk_public_headers = files([
'gdkframetimings.h',
'gdkglcontext.h',
'gdkgltexture.h',
'gdkgltexturebuilder.h',
'gdkkeys.h',
'gdkkeysyms.h',
'gdkmemorytexture.h',

View File

@@ -427,6 +427,7 @@ gsk_gl_command_queue_dispose (GObject *object)
gsk_gl_command_batches_clear (&self->batches);
gsk_gl_command_binds_clear (&self->batch_binds);
gsk_gl_command_uniforms_clear (&self->batch_uniforms);
gsk_gl_syncs_clear (&self->syncs);
gsk_gl_buffer_destroy (&self->vertices);
@@ -449,6 +450,7 @@ gsk_gl_command_queue_init (GskGLCommandQueue *self)
gsk_gl_command_batches_init (&self->batches, 128);
gsk_gl_command_binds_init (&self->batch_binds, 1024);
gsk_gl_command_uniforms_init (&self->batch_uniforms, 2048);
gsk_gl_syncs_init (&self->syncs, 10);
gsk_gl_buffer_init (&self->vertices, GL_ARRAY_BUFFER, sizeof (GskGLDrawVertex));
}
@@ -1159,17 +1161,25 @@ gsk_gl_command_queue_execute (GskGLCommandQueue *self,
if G_UNLIKELY (batch->draw.bind_count > 0)
{
const GskGLCommandBind *bind = &self->batch_binds.items[batch->draw.bind_offset];
for (guint i = 0; i < batch->draw.bind_count; i++)
{
if (textures[bind->texture] != bind->id)
{
GskGLSync *s;
if (active != bind->texture)
{
active = bind->texture;
glActiveTexture (GL_TEXTURE0 + bind->texture);
}
s = gsk_gl_syncs_get_sync (&self->syncs, bind->id);
if (s && s->sync)
{
glWaitSync ((GLsync) s->sync, 0, GL_TIMEOUT_IGNORED);
s->sync = NULL;
}
glBindTexture (GL_TEXTURE_2D, bind->id);
textures[bind->texture] = bind->id;
if (!self->has_samplers)
@@ -1315,6 +1325,7 @@ gsk_gl_command_queue_end_frame (GskGLCommandQueue *self)
self->batches.len = 0;
self->batch_binds.len = 0;
self->batch_uniforms.len = 0;
self->syncs.len = 0;
self->n_uploads = 0;
self->tail_batch_index = -1;
self->in_frame = FALSE;

View File

@@ -168,9 +168,15 @@ typedef union _GskGLCommandBatch
G_STATIC_ASSERT (sizeof (GskGLCommandBatch) == 32);
typedef struct _GskGLSync {
guint id;
gpointer sync;
} GskGLSync;
DEFINE_INLINE_ARRAY (GskGLCommandBatches, gsk_gl_command_batches, GskGLCommandBatch)
DEFINE_INLINE_ARRAY (GskGLCommandBinds, gsk_gl_command_binds, GskGLCommandBind)
DEFINE_INLINE_ARRAY (GskGLCommandUniforms, gsk_gl_command_uniforms, GskGLCommandUniform)
DEFINE_INLINE_ARRAY (GskGLSyncs, gsk_gl_syncs, GskGLSync)
struct _GskGLCommandQueue
{
@@ -233,6 +239,10 @@ struct _GskGLCommandQueue
*/
GLuint samplers[GSK_GL_N_FILTERS * GSK_GL_N_FILTERS];
/* Array of sync objects to wait on.
*/
GskGLSyncs syncs;
/* Discovered max texture size when loading the command queue so that we
* can either scale down or slice textures to fit within this size. Assumed
* to be both height and width.
@@ -371,5 +381,36 @@ gsk_gl_command_queue_bind_framebuffer (GskGLCommandQueue *self,
return ret;
}
static inline GskGLSync *
gsk_gl_syncs_get_sync (GskGLSyncs *syncs,
guint id)
{
for (unsigned int i = 0; i < syncs->len; i++)
{
GskGLSync *sync = &syncs->items[i];
if (sync->id == id)
return sync;
}
return NULL;
}
static inline void
gsk_gl_syncs_add_sync (GskGLSyncs *syncs,
guint id,
gpointer sync)
{
GskGLSync *s;
s = gsk_gl_syncs_get_sync (syncs, id);
if (s)
g_assert (s->sync == sync);
else
{
s = gsk_gl_syncs_append (syncs);
s->id = id;
s->sync = sync;
}
}
G_END_DECLS

View File

@@ -1126,14 +1126,20 @@ write_atlas_to_png (GskGLDriver *driver,
GskGLTextureAtlas *atlas,
const char *filename)
{
GdkGLTextureBuilder *builder;
GdkTexture *texture;
texture = gdk_gl_texture_new (gsk_gl_driver_get_context (driver),
atlas->texture_id,
atlas->width, atlas->height,
NULL, NULL);
builder = gdk_gl_texture_builder_new ();
gdk_gl_texture_builder_set_context (builder, gsk_gl_driver_get_context (driver));
gdk_gl_texture_builder_set_id (builder, atlas->texture_id);
gdk_gl_texture_builder_set_width (builder, atlas->width);
gdk_gl_texture_builder_set_height (builder, atlas->height);
texture = gdk_gl_texture_builder_build (builder, NULL, NULL);
gdk_texture_save_to_png (texture, filename);
g_object_unref (texture);
g_object_unref (builder);
}
void
@@ -1557,6 +1563,7 @@ typedef struct _GskGLTextureState
{
GdkGLContext *context;
GLuint texture_id;
GLsync sync;
} GskGLTextureState;
static void
@@ -1569,6 +1576,8 @@ create_texture_from_texture_destroy (gpointer data)
gdk_gl_context_make_current (state->context);
glDeleteTextures (1, &state->texture_id);
if (state->sync)
glDeleteSync (state->sync);
g_clear_object (&state->context);
g_free (state);
}
@@ -1578,8 +1587,9 @@ gsk_gl_driver_create_gdk_texture (GskGLDriver *self,
guint texture_id)
{
GskGLTextureState *state;
GdkGLTextureBuilder *builder;
GskGLTexture *texture;
int width, height;
GdkTexture *result;
g_return_val_if_fail (GSK_IS_GL_DRIVER (self), NULL);
g_return_val_if_fail (self->command_queue != NULL, NULL);
@@ -1594,19 +1604,25 @@ gsk_gl_driver_create_gdk_texture (GskGLDriver *self,
state = g_new0 (GskGLTextureState, 1);
state->texture_id = texture_id;
state->context = g_object_ref (self->command_queue->context);
if (gdk_gl_context_has_fence_sync (self->command_queue->context))
state->sync = glFenceSync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
g_hash_table_steal (self->textures, GUINT_TO_POINTER (texture_id));
width = texture->width;
height = texture->height;
builder = gdk_gl_texture_builder_new ();
gdk_gl_texture_builder_set_context (builder, self->command_queue->context);
gdk_gl_texture_builder_set_id (builder, texture_id);
gdk_gl_texture_builder_set_width (builder, texture->width);
gdk_gl_texture_builder_set_height (builder, texture->height);
gdk_gl_texture_builder_set_sync (builder, state->sync);
result = gdk_gl_texture_builder_build (builder,
create_texture_from_texture_destroy,
state);
texture->texture_id = 0;
gsk_gl_texture_free (texture);
g_object_unref (builder);
return gdk_gl_texture_new (self->command_queue->context,
texture_id,
width,
height,
create_texture_from_texture_destroy,
state);
return result;
}

View File

@@ -285,6 +285,22 @@ gsk_gl_program_set_uniform_texture (GskGLProgram *self,
GL_LINEAR);
}
static inline void
gsk_gl_program_set_uniform_texture_with_sync (GskGLProgram *self,
guint key,
guint stamp,
GLenum texture_target,
GLenum texture_slot,
guint texture_id,
GLint min_filter,
GLint max_filter,
gpointer sync)
{
gsk_gl_program_set_uniform_texture_with_filter (self, key, stamp, texture_target, texture_slot, texture_id,
min_filter, max_filter);
gsk_gl_syncs_add_sync (&self->driver->command_queue->syncs, texture_id, sync);
}
static inline void
gsk_gl_program_set_uniform_matrix (GskGLProgram *self,
guint key,

View File

@@ -191,6 +191,7 @@ typedef struct _GskGLRenderOffscreen
/* Return location for texture ID */
guint texture_id;
gpointer sync;
/* Whether to force creating a new texture, even if the
* input already is a texture
@@ -3570,6 +3571,9 @@ gsk_gl_render_job_upload_texture (GskGLRenderJob *job,
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);
}
}
@@ -3597,13 +3601,15 @@ gsk_gl_render_job_visit_texture (GskGLRenderJob *job,
g_assert (offscreen.was_offscreen == FALSE);
gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit));
gsk_gl_program_set_uniform_texture_with_filter (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);
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);
gsk_gl_render_job_draw_offscreen (job, bounds, &offscreen);
gsk_gl_render_job_end_draw (job);
}
@@ -3733,21 +3739,29 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
if G_LIKELY (texture->width <= max_texture_size &&
texture->height <= max_texture_size)
{
gpointer sync;
texture_id = gsk_gl_driver_load_texture (job->driver, texture, filter == GSK_SCALING_FILTER_TRILINEAR);
if (GDK_IS_GL_TEXTURE (texture) && texture_id == gdk_gl_texture_get_id (GDK_GL_TEXTURE (texture)))
sync = gdk_gl_texture_get_sync (GDK_GL_TEXTURE (texture));
else
sync = NULL;
u0 = (clip_rect.origin.x - bounds->origin.x) / bounds->size.width;
v0 = (clip_rect.origin.y - bounds->origin.y) / bounds->size.height;
u1 = (clip_rect.origin.x + clip_rect.size.width - bounds->origin.x) / bounds->size.width;
v1 = (clip_rect.origin.y + clip_rect.size.height - bounds->origin.y) / bounds->size.height;
gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit));
gsk_gl_program_set_uniform_texture_with_filter (job->current_program,
UNIFORM_SHARED_SOURCE, 0,
GL_TEXTURE_2D,
GL_TEXTURE0,
texture_id,
min_filter,
mag_filter);
gsk_gl_program_set_uniform_texture_with_sync (job->current_program,
UNIFORM_SHARED_SOURCE, 0,
GL_TEXTURE_2D,
GL_TEXTURE0,
texture_id,
min_filter,
mag_filter,
sync);
gsk_gl_render_job_draw_coords (job,
0, 0, clip_rect.size.width, clip_rect.size.height,
u0, v0, u1, v1,

View File

@@ -32,6 +32,8 @@
#include "gtksnapshot.h"
#include "gtkrenderlayoutprivate.h"
#include "gtkcssnodeprivate.h"
#include "gdk/gdkgltextureprivate.h"
#include "gdk/gdkglcontextprivate.h"
#include <epoxy/gl.h>
@@ -143,9 +145,7 @@
*/
typedef struct {
guint id;
int width;
int height;
GdkGLTextureBuilder *builder;
GdkTexture *holder;
} Texture;
@@ -403,15 +403,21 @@ static void
delete_one_texture (gpointer data)
{
Texture *texture = data;
guint id;
gpointer sync;
if (texture->holder)
gdk_gl_texture_release (GDK_GL_TEXTURE (texture->holder));
if (texture->id != 0)
{
glDeleteTextures (1, &texture->id);
texture->id = 0;
}
id = gdk_gl_texture_builder_get_id (texture->builder);
if (id != 0)
glDeleteTextures (1, &id);
sync = gdk_gl_texture_builder_get_sync (texture->builder);
if (sync)
glDeleteSync (sync);
g_object_unref (texture->builder);
g_free (texture);
}
@@ -452,13 +458,20 @@ gtk_gl_area_ensure_texture (GtkGLArea *area)
if (priv->texture == NULL)
{
priv->texture = g_new (Texture, 1);
GLuint id;
priv->texture->width = 0;
priv->texture->height = 0;
priv->texture = g_new (Texture, 1);
priv->texture->holder = NULL;
glGenTextures (1, &priv->texture->id);
priv->texture->builder = gdk_gl_texture_builder_new ();
gdk_gl_texture_builder_set_context (priv->texture->builder, priv->context);
if (gdk_gl_context_get_api (priv->context) == GDK_GL_API_GLES)
gdk_gl_texture_builder_set_format (priv->texture->builder, GDK_MEMORY_R8G8B8A8_PREMULTIPLIED);
else
gdk_gl_texture_builder_set_format (priv->texture->builder, GDK_MEMORY_B8G8R8A8_PREMULTIPLIED);
glGenTextures (1, &id);
gdk_gl_texture_builder_set_id (priv->texture->builder, id);
}
gtk_gl_area_allocate_texture (area);
@@ -512,10 +525,10 @@ gtk_gl_area_allocate_texture (GtkGLArea *area)
width = gtk_widget_get_width (widget) * scale;
height = gtk_widget_get_height (widget) * scale;
if (priv->texture->width != width ||
priv->texture->height != height)
if (gdk_gl_texture_builder_get_width (priv->texture->builder) != width ||
gdk_gl_texture_builder_get_height (priv->texture->builder) != height)
{
glBindTexture (GL_TEXTURE_2D, priv->texture->id);
glBindTexture (GL_TEXTURE_2D, gdk_gl_texture_builder_get_id (priv->texture->builder));
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@@ -526,8 +539,8 @@ gtk_gl_area_allocate_texture (GtkGLArea *area)
else
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
priv->texture->width = width;
priv->texture->height = height;
gdk_gl_texture_builder_set_width (priv->texture->builder, width);
gdk_gl_texture_builder_set_height (priv->texture->builder, height);
}
}
@@ -571,7 +584,7 @@ gtk_gl_area_attach_buffers (GtkGLArea *area)
if (priv->texture != NULL)
glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, priv->texture->id, 0);
GL_TEXTURE_2D, gdk_gl_texture_builder_get_id (priv->texture->builder), 0);
if (priv->depth_stencil_buffer)
{
@@ -736,6 +749,7 @@ gtk_gl_area_snapshot (GtkWidget *widget,
if (status == GL_FRAMEBUFFER_COMPLETE)
{
Texture *texture;
gpointer sync = NULL;
if (priv->needs_render || priv->auto_render)
{
@@ -754,11 +768,14 @@ gtk_gl_area_snapshot (GtkWidget *widget,
priv->texture = NULL;
priv->textures = g_list_prepend (priv->textures, texture);
texture->holder = gdk_gl_texture_new (priv->context,
texture->id,
texture->width,
texture->height,
release_texture, texture);
if (gdk_gl_context_has_fence_sync (priv->context))
sync = glFenceSync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
gdk_gl_texture_builder_set_sync (texture->builder, sync);
texture->holder = gdk_gl_texture_builder_build (texture->builder,
release_texture,
texture);
/* Our texture is rendered by OpenGL, so it is upside down,
* compared to what GSK expects, so flip it back.

View File

@@ -287,21 +287,30 @@ gtk_gst_sink_texture_from_buffer (GtkGstSink *self,
gst_video_frame_map (frame, &self->v_info, buffer, GST_MAP_READ | GST_MAP_GL))
{
GstGLSyncMeta *sync_meta;
GdkGLTextureBuilder *builder;
sync_meta = gst_buffer_get_gl_sync_meta (buffer);
if (sync_meta) {
if (sync_meta)
gst_gl_sync_meta_set_sync_point (sync_meta, self->gst_context);
gst_gl_context_activate (self->gst_gdk_context, TRUE);
gst_gl_sync_meta_wait (sync_meta, self->gst_gdk_context);
gst_gl_context_activate (self->gst_gdk_context, FALSE);
}
texture = gdk_gl_texture_new (self->gdk_context,
*(guint *) frame->data[0],
frame->info.width,
frame->info.height,
(GDestroyNotify) video_frame_free,
frame);
/* Note: using the gdk_context here is a (harmless) lie,
* since the texture really originates in the gst_context.
* But that is not a GdkGLContext. It is harmless, because
* we are never using the texture in the gdk_context, so we
* never make the (erroneous) decision to ignore the sync.
*/
builder = gdk_gl_texture_builder_new ();
gdk_gl_texture_builder_set_context (builder, self->gdk_context);
gdk_gl_texture_builder_set_id (builder, *(guint *) frame->data[0]);
gdk_gl_texture_builder_set_width (builder, frame->info.width);
gdk_gl_texture_builder_set_height (builder, frame->info.height);
gdk_gl_texture_builder_set_sync (builder, sync_meta ? sync_meta->data : NULL);
texture = gdk_gl_texture_builder_build (builder,
(GDestroyNotify) video_frame_free,
frame);
g_object_unref (builder);
*pixel_aspect_ratio = ((double) frame->info.par_n) / ((double) frame->info.par_d);
}

View File

@@ -32,6 +32,7 @@ test_gltexture (int test)
GdkDisplay *display;
GdkGLContext *context;
GdkGLContext *context2 = NULL;
GdkGLTextureBuilder *builder;
GdkTexture *texture;
cairo_surface_t *surface;
GError *error = NULL;
@@ -80,7 +81,12 @@ test_gltexture (int test)
gdk_gl_context_make_current (context2);
}
texture = gdk_gl_texture_new (context, id, 64, 64, NULL, NULL);
builder = gdk_gl_texture_builder_new ();
gdk_gl_texture_builder_set_id (builder, id);
gdk_gl_texture_builder_set_context (builder, context);
gdk_gl_texture_builder_set_width (builder, 64);
gdk_gl_texture_builder_set_height (builder, 64);
texture = gdk_gl_texture_builder_build (builder, NULL, NULL);
data = g_malloc0 (64 * 64 * 4);
gdk_texture_download (texture, data, 64 * 4);
@@ -89,6 +95,7 @@ test_gltexture (int test)
g_free (data);
g_object_unref (texture);
g_object_unref (builder);
cairo_surface_destroy (surface);