Compare commits

...

4 Commits

Author SHA1 Message Date
Matthias Clasen
a339c85a98 texturebuilder: Add has-mipmap
Add this as a builder property, and pass it
to the created texture.
2023-04-25 08:32:00 +02:00
Matthias Clasen
e37dfea637 gltexture: Pass in has_mipmap
Take the has_mipmap boolean in our internal constructor.

The code is still in a bit of flux - we still try to
determine if we have a mipmap while poking at formats.
Eventually, that code should probably be moved to the
builder side.
2023-04-25 08:30:37 +02:00
Matthias Clasen
98c3f365db gltexture: Add a new private constructor
We need a place to pass more data from the builder
to the constructed texture, and this is it.
2023-04-25 08:25:38 +02:00
Benjamin Otte
3646c470d5 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 07:02:15 +02:00
6 changed files with 621 additions and 12 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

@@ -39,6 +39,7 @@ struct _GdkGLTexture {
GdkGLContext *context;
guint id;
gboolean has_mipmap;
gboolean has_mipmap_set;
GdkTexture *saved;
@@ -338,7 +339,6 @@ gdk_gl_texture_determine_format (GdkGLTexture *self)
!gdk_gl_context_check_version (context, 0, 0, 3, 1))
{
texture->format = GDK_MEMORY_DEFAULT;
self->has_mipmap = FALSE;
return;
}
@@ -428,18 +428,21 @@ gdk_gl_texture_determine_format (GdkGLTexture *self)
break;
}
/* Determine if the texture has a mipmap.
* We do this here, since it requires binding the texture,
* and we're already doing that here.
* GL has no way to directly query 'mipmap completeness' of textures,
* so we just check that level 1 has the expected size, and assume
* that means somebody called glGenerateMipmap().
*/
glGetTexLevelParameteriv (GL_TEXTURE_2D, 1, GL_TEXTURE_WIDTH, &width);
glGetTexLevelParameteriv (GL_TEXTURE_2D, 1, GL_TEXTURE_HEIGHT, &height);
if (!self->has_mipmap)
{
/* Determine if the texture has a mipmap.
* We do this here, since it requires binding the texture,
* and we're already doing that here.
* GL has no way to directly query 'mipmap completeness' of textures,
* so we just check that level 1 has the expected size, and assume
* that means somebody called glGenerateMipmap().
*/
glGetTexLevelParameteriv (GL_TEXTURE_2D, 1, GL_TEXTURE_WIDTH, &width);
glGetTexLevelParameteriv (GL_TEXTURE_2D, 1, GL_TEXTURE_HEIGHT, &height);
self->has_mipmap = width == texture->width / 2 &&
height == texture->height / 2;
self->has_mipmap = width == texture->width / 2 &&
height == texture->height / 2;
}
/* restore previous state */
glBindTexture (GL_TEXTURE_2D, active_texture);
@@ -471,6 +474,18 @@ gdk_gl_texture_new (GdkGLContext *context,
int height,
GDestroyNotify destroy,
gpointer data)
{
return gdk_gl_texture_new_full (context, id, width, height, FALSE, destroy, data);
}
GdkTexture *
gdk_gl_texture_new_full (GdkGLContext *context,
guint id,
int width,
int height,
gboolean has_mipmap,
GDestroyNotify destroy,
gpointer data)
{
GdkGLTexture *self;
@@ -486,6 +501,7 @@ gdk_gl_texture_new (GdkGLContext *context,
self->context = g_object_ref (context);
self->id = id;
self->has_mipmap = has_mipmap;
self->destroy = destroy;
self->data = data;

505
gdk/gdkgltexturebuilder.c Normal file
View File

@@ -0,0 +1,505 @@
/*
* 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 "gdkglcontext.h"
#include "gdkgltextureprivate.h"
struct _GdkGLTextureBuilder
{
GObject parent_instance;
GdkGLContext *context;
guint id;
int width;
int height;
gboolean has_mipmap;
GDestroyNotify destroy;
gpointer data;
};
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.TextureBuilder:context],
* [property@Gdk.TextureBuilder:id], [property@Gdk.TextureBuilder:width], and
* [property@Gdk.TextureBuilder:height] are mandatory - and then call
* [method@Gdk.TextureBuilder.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_HAS_MIPMAP,
PROP_HEIGHT,
PROP_ID,
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_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_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_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_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: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)
*
* Whether 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: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)
{
}
/**
* 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.TextureBuilder.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.TextureBuilder.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.TextureBuilder.set_notify]
* for a longer discussion.
*
* The id must be set before calling [method@Gdk.TextureBuilder.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.TextureBuilder.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]);
}
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;
}
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_set_notify:
* @self: a `GdkGLTextureBuilder`
* @destroy: (nullable): destroy function to be called when a texture is
* released
* @data: user data to pass to the destroy function
*
* Sets the funciton to be called when the texture built with
* [method@Gdk.TextureBuilder.build] gets released, either when the
* texture is finalized or by an explicit call to [method@Gdk.Texture.release].
*
* This function should release all GL resources associated with the texture,
* such as the [property@Gdk.TextureBuilder:id].
**/
void
gdk_gl_texture_builder_set_notify (GdkGLTextureBuilder *self,
GDestroyNotify destroy,
gpointer data)
{
g_return_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self));
g_return_if_fail (destroy == NULL || data != NULL);
self->destroy = destroy;
self->data = data;
}
/**
* gdk_gl_texture_builder_build:
* @self: a `GdkGLTextureBuilder`
*
* Builds a new `GdkTexture` with the values set up in the builder.
*
* Note that it is a programming error if any mandatory property has not been set.
*
* Returns: (transfer full): a newly built `GdkTexture`
**/
GdkTexture *
gdk_gl_texture_builder_build (GdkGLTextureBuilder *self)
{
g_return_val_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self), 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_full (self->context,
self->id,
self->width,
self->height,
self->has_mipmap,
self->destroy,
self->data);
}

77
gdk/gdkgltexturebuilder.h Normal file
View File

@@ -0,0 +1,77 @@
/*
* 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/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
gboolean gdk_gl_texture_builder_get_has_mipmap (GdkGLTextureBuilder *self);
GDK_AVAILABLE_IN_4_12
void gdk_gl_texture_builder_set_has_mipmap (GdkGLTextureBuilder *self,
gboolean has_mipmap);
GDK_AVAILABLE_IN_4_12
void gdk_gl_texture_builder_set_notify (GdkGLTextureBuilder *self,
GDestroyNotify destroy,
gpointer data);
GDK_AVAILABLE_IN_4_12
GdkTexture * gdk_gl_texture_builder_build (GdkGLTextureBuilder *self);
G_END_DECLS

View File

@@ -10,5 +10,13 @@ GdkGLContext * gdk_gl_texture_get_context (GdkGLTexture
guint gdk_gl_texture_get_id (GdkGLTexture *self);
gboolean gdk_gl_texture_has_mipmap (GdkGLTexture *self);
GdkTexture * gdk_gl_texture_new_full (GdkGLContext *context,
guint id,
int width,
int height,
gboolean has_mipmap,
GDestroyNotify destroy,
gpointer data);
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',