mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-25 21:21:21 +00:00
Merge branch 'wip/otte/texturebuilder' into 'main'
Add GdkGLTextureBuilder See merge request GNOME/gtk!5862
This commit is contained in:
commit
76777cdd18
@ -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>
|
||||
|
@ -106,6 +106,7 @@ typedef struct {
|
||||
guint has_khr_debug : 1;
|
||||
guint use_khr_debug : 1;
|
||||
guint has_half_float : 1;
|
||||
guint has_sync : 1;
|
||||
guint has_unpack_subimage : 1;
|
||||
guint has_debug_output : 1;
|
||||
guint extensions_checked : 1;
|
||||
@ -1553,6 +1554,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_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;
|
||||
@ -1564,7 +1569,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"
|
||||
" - sync: %s",
|
||||
gdk_gl_context_get_use_es (context) ? "OpenGL ES" : "OpenGL",
|
||||
gdk_gl_version_get_major (&priv->gl_version), gdk_gl_version_get_minor (&priv->gl_version),
|
||||
priv->is_legacy ? "legacy" : "core",
|
||||
@ -1572,7 +1578,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_sync ? "yes" : "no");
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1800,6 +1807,14 @@ gdk_gl_context_has_vertex_half_float (GdkGLContext *self)
|
||||
return priv->has_half_float;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_gl_context_has_sync (GdkGLContext *self)
|
||||
{
|
||||
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (self);
|
||||
|
||||
return priv->has_sync;
|
||||
}
|
||||
|
||||
/* This is currently private! */
|
||||
/* When using GL/ES, don't flip the 'R' and 'B' bits on Windows/ANGLE for glReadPixels() */
|
||||
gboolean
|
||||
|
@ -148,6 +148,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_sync (GdkGLContext *self) G_GNUC_PURE;
|
||||
|
||||
double gdk_gl_context_get_scale (GdkGLContext *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
@ -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,30 @@ 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);
|
||||
if (gdk_gl_context_has_sync (self->context))
|
||||
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 +498,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,
|
||||
|
@ -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,
|
||||
|
655
gdk/gdkgltexturebuilder.c
Normal file
655
gdk/gdkgltexturebuilder.c
Normal file
@ -0,0 +1,655 @@
|
||||
/*
|
||||
* 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 set, GTK will wait 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` previously set via gdk_gl_texture_builder_set_sync().
|
||||
*
|
||||
* Returns: (nullable): the `GLSync`
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* GTK will wait on this object before using the created `GdkTexture`.
|
||||
*
|
||||
* The `destroy` function that is passed to [method@Gdk.GLTextureBuilder.build]
|
||||
* is responsible for freeing the sync object when it is no longer needed.
|
||||
* The texture builder does not destroy it and it is the callers
|
||||
* responsibility to make sure it doesn't leak.
|
||||
*
|
||||
* 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
87
gdk/gdkgltexturebuilder.h
Normal 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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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',
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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_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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,16 @@ static void
|
||||
delete_one_texture (gpointer data)
|
||||
{
|
||||
Texture *texture = data;
|
||||
guint id;
|
||||
|
||||
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);
|
||||
|
||||
g_object_unref (texture->builder);
|
||||
|
||||
g_free (texture);
|
||||
}
|
||||
@ -452,13 +453,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 +520,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 +534,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 +579,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)
|
||||
{
|
||||
@ -691,6 +699,15 @@ static void
|
||||
release_texture (gpointer data)
|
||||
{
|
||||
Texture *texture = data;
|
||||
gpointer sync;
|
||||
|
||||
sync = gdk_gl_texture_builder_get_sync (texture->builder);
|
||||
if (sync)
|
||||
{
|
||||
glDeleteSync (sync);
|
||||
gdk_gl_texture_builder_set_sync (texture->builder, NULL);
|
||||
}
|
||||
|
||||
texture->holder = NULL;
|
||||
}
|
||||
|
||||
@ -736,6 +753,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 +772,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_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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user