summaryrefslogtreecommitdiff
path: root/gsk
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2016-11-07 17:59:38 +0100
committerBenjamin Otte <otte@redhat.com>2016-11-08 20:31:34 +0100
commit46eb2c1be9e92e9e41d86367d88a826f97c3d7ce (patch)
tree3db9eff51e6b9069bd6d1911cf74631ba328a5b2 /gsk
parent71aeb8075bc5ff46bdd301d9caf7b102a8a2205d (diff)
downloadgtk+-46eb2c1be9e92e9e41d86367d88a826f97c3d7ce.tar.gz
gsk: Add GskTexture
Diffstat (limited to 'gsk')
-rw-r--r--gsk/Makefile.am7
-rw-r--r--gsk/gsk.h1
-rw-r--r--gsk/gskgldriver.c24
-rw-r--r--gsk/gskgldriverprivate.h3
-rw-r--r--gsk/gskglrenderer.c105
-rw-r--r--gsk/gskrenderer.c42
-rw-r--r--gsk/gskrendererprivate.h9
-rw-r--r--gsk/gskrendernode.c24
-rw-r--r--gsk/gskrendernode.h2
-rw-r--r--gsk/gskrendernodeprivate.h6
-rw-r--r--gsk/gsktexture.c197
-rw-r--r--gsk/gsktexture.h61
-rw-r--r--gsk/gsktextureprivate.h30
-rw-r--r--gsk/gsktypes.h1
14 files changed, 497 insertions, 15 deletions
diff --git a/gsk/Makefile.am b/gsk/Makefile.am
index 26aced18c9..b4cf4f63a2 100644
--- a/gsk/Makefile.am
+++ b/gsk/Makefile.am
@@ -27,6 +27,7 @@ gsk_public_source_h = \
gskrenderer.h \
gskrendernode.h \
gskrendernodeiter.h \
+ gsktexture.h \
gsktypes.h
gsk_private_source_h = \
gskcairorendererprivate.h \
@@ -38,11 +39,13 @@ gsk_private_source_h = \
gskprofilerprivate.h \
gskrendererprivate.h \
gskrendernodeprivate.h \
- gskshaderbuilderprivate.h
+ gskshaderbuilderprivate.h \
+ gsktextureprivate.h
gsk_public_source_c = \
gskrenderer.c \
gskrendernode.c \
- gskrendernodeiter.c
+ gskrendernodeiter.c \
+ gsktexture.c
gsk_private_source_c = \
gskcairorenderer.c \
gskdebug.c \
diff --git a/gsk/gsk.h b/gsk/gsk.h
index 01c45693f5..394895c1aa 100644
--- a/gsk/gsk.h
+++ b/gsk/gsk.h
@@ -24,6 +24,7 @@
#include <gsk/gskrenderer.h>
#include <gsk/gskrendernode.h>
#include <gsk/gskrendernodeiter.h>
+#include <gsk/gsktexture.h>
#include <gsk/gsktypes.h>
#include <gsk/gskenumtypes.h>
diff --git a/gsk/gskgldriver.c b/gsk/gskgldriver.c
index a0bd8e34a9..da21f6ae72 100644
--- a/gsk/gskgldriver.c
+++ b/gsk/gskgldriver.c
@@ -15,6 +15,7 @@ typedef struct {
GLuint mag_filter;
GArray *fbos;
gboolean in_use : 1;
+ gboolean reserved : 1;
} Texture;
typedef struct {
@@ -75,6 +76,8 @@ texture_free (gpointer data)
{
Texture *t = data;
+ g_warn_if_fail (!t->reserved);
+
g_clear_pointer (&t->fbos, g_array_unref);
glDeleteTextures (1, &t->texture_id);
g_slice_free (Texture, t);
@@ -269,6 +272,9 @@ gsk_gl_driver_collect_textures (GskGLDriver *driver)
{
Texture *t = value_p;
+ if (t->reserved)
+ continue;
+
if (t->in_use)
{
t->in_use = FALSE;
@@ -379,6 +385,7 @@ find_texture_by_size (GHashTable *textures,
int
gsk_gl_driver_create_texture (GskGLDriver *driver,
+ gboolean reserve,
int width,
int height)
{
@@ -404,6 +411,7 @@ gsk_gl_driver_create_texture (GskGLDriver *driver,
GSK_NOTE (OPENGL, g_print ("Reusing Texture(%d) for size %dx%d\n",
t->texture_id, t->width, t->height));
t->in_use = TRUE;
+ t->reserved = reserve;
return t->texture_id;
}
@@ -416,11 +424,27 @@ gsk_gl_driver_create_texture (GskGLDriver *driver,
t->min_filter = GL_NEAREST;
t->mag_filter = GL_NEAREST;
t->in_use = TRUE;
+ t->reserved = reserve;
g_hash_table_insert (driver->textures, GINT_TO_POINTER (texture_id), t);
return t->texture_id;
}
+void
+gsk_gl_driver_release_texture (GskGLDriver *driver,
+ int texture_id)
+{
+ Texture *t;
+
+ g_return_if_fail (GSK_IS_GL_DRIVER (driver));
+
+ t = gsk_gl_driver_get_texture (driver, texture_id);
+ g_return_if_fail (t != NULL);
+ g_return_if_fail (t->reserved);
+
+ t->reserved = FALSE;
+}
+
static Vao *
find_vao (GHashTable *vaos,
int position_id,
diff --git a/gsk/gskgldriverprivate.h b/gsk/gskgldriverprivate.h
index 6a411742b1..636f59c889 100644
--- a/gsk/gskgldriverprivate.h
+++ b/gsk/gskgldriverprivate.h
@@ -24,8 +24,11 @@ void gsk_gl_driver_begin_frame (GskGLDriver *driver
void gsk_gl_driver_end_frame (GskGLDriver *driver);
int gsk_gl_driver_create_texture (GskGLDriver *driver,
+ gboolean reserved,
int width,
int height);
+void gsk_gl_driver_release_texture (GskGLDriver *driver,
+ int texture_id);
int gsk_gl_driver_create_vao_for_quad (GskGLDriver *driver,
int position_id,
int uv_id,
diff --git a/gsk/gskglrenderer.c b/gsk/gskglrenderer.c
index 8f849a7a8f..be9479944b 100644
--- a/gsk/gskglrenderer.c
+++ b/gsk/gskglrenderer.c
@@ -11,6 +11,7 @@
#include "gskrendernodeprivate.h"
#include "gskrendernodeiter.h"
#include "gskshaderbuilderprivate.h"
+#include "gsktextureprivate.h"
#include "gskprivate.h"
@@ -89,6 +90,13 @@ typedef struct {
} ProfileTimers;
#endif
+typedef struct _GskGLTexture GskGLTexture;
+struct _GskGLTexture {
+ GskTexture texture;
+
+ int texture_id;
+};
+
struct _GskGLRenderer
{
GskRenderer parent_instance;
@@ -128,6 +136,86 @@ struct _GskGLRendererClass
G_DEFINE_TYPE (GskGLRenderer, gsk_gl_renderer, GSK_TYPE_RENDERER)
+static GskTexture *
+gsk_gl_renderer_texture_new_for_data (GskRenderer *renderer,
+ const guchar *data,
+ int width,
+ int height,
+ int stride)
+{
+ GskGLRenderer *self = GSK_GL_RENDERER (renderer);
+ GskGLTexture *texture;
+ cairo_surface_t *surface;
+
+ gdk_gl_context_make_current (self->gl_context);
+ gsk_gl_driver_begin_frame (self->gl_driver);
+
+ /* XXX: Make this work without having to create cairo surfaces */
+ surface = cairo_image_surface_create_for_data ((guchar *) data, CAIRO_FORMAT_ARGB32, width, height, stride);
+
+ texture = gsk_texture_new (GskGLTexture, renderer, width, height);
+
+ texture->texture_id = gsk_gl_driver_create_texture (self->gl_driver,
+ TRUE,
+ width, height);
+ gsk_gl_driver_bind_source_texture (self->gl_driver, texture->texture_id);
+ gsk_gl_driver_init_texture_with_surface (self->gl_driver,
+ texture->texture_id,
+ surface,
+ GL_NEAREST,
+ GL_NEAREST);
+
+ cairo_surface_destroy (surface);
+
+ gsk_gl_driver_end_frame (self->gl_driver);
+
+ return &texture->texture;
+}
+
+static GskTexture *
+gsk_gl_renderer_texture_new_for_pixbuf (GskRenderer *renderer,
+ GdkPixbuf *pixbuf)
+{
+ GskGLRenderer *self = GSK_GL_RENDERER (renderer);
+ GskGLTexture *texture;
+ cairo_surface_t *surface;
+ int width, height;
+
+ gdk_gl_context_make_current (self->gl_context);
+ gsk_gl_driver_begin_frame (self->gl_driver);
+
+ surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, 1, NULL);
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
+
+ texture = gsk_texture_new (GskGLTexture, renderer, width, height);
+
+ texture->texture_id = gsk_gl_driver_create_texture (self->gl_driver,
+ TRUE,
+ width, height);
+ gsk_gl_driver_bind_source_texture (self->gl_driver, texture->texture_id);
+ gsk_gl_driver_init_texture_with_surface (self->gl_driver,
+ texture->texture_id,
+ surface,
+ GL_NEAREST,
+ GL_NEAREST);
+
+ gsk_gl_driver_end_frame (self->gl_driver);
+
+ cairo_surface_destroy (surface);
+
+ return &texture->texture;
+}
+
+static void
+gsk_gl_renderer_texture_destroy (GskTexture *texture)
+{
+ GskGLTexture *gltexture = (GskGLTexture *) texture;
+ GskGLRenderer *self = GSK_GL_RENDERER (gsk_texture_get_renderer (texture));
+
+ gsk_gl_driver_release_texture (self->gl_driver, gltexture->texture_id);
+}
+
static void
gsk_gl_renderer_dispose (GObject *gobject)
{
@@ -152,6 +240,7 @@ gsk_gl_renderer_create_buffers (GskGLRenderer *self,
if (self->texture_id == 0)
{
self->texture_id = gsk_gl_driver_create_texture (self->gl_driver,
+ FALSE,
width * scale_factor,
height * scale_factor);
gsk_gl_driver_bind_source_texture (self->gl_driver, self->texture_id);
@@ -693,7 +782,7 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self,
if (render_node_needs_render_target (node))
{
item.render_data.render_target_id =
- gsk_gl_driver_create_texture (self->gl_driver, item.size.width, item.size.height);
+ gsk_gl_driver_create_texture (self->gl_driver, FALSE, item.size.width, item.size.height);
gsk_gl_driver_init_texture_empty (self->gl_driver, item.render_data.render_target_id);
gsk_gl_driver_create_render_target (self->gl_driver, item.render_data.render_target_id, TRUE, TRUE);
@@ -708,7 +797,14 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self,
if (gsk_render_node_has_texture (node))
{
- item.render_data.texture_id = gsk_render_node_get_texture (node);
+ GskTexture *texture = gsk_render_node_get_texture (node);
+
+ if (gsk_texture_get_renderer (texture) != GSK_RENDERER (self))
+ {
+ g_warning ("Given Texture belongs to wrong renderer, ignoring.");
+ goto out;
+ }
+ item.render_data.texture_id = ((GskGLTexture *) texture)->texture_id;
}
else if (gsk_render_node_has_surface (node))
{
@@ -719,6 +815,7 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self,
/* Upload the Cairo surface to a GL texture */
item.render_data.texture_id = gsk_gl_driver_create_texture (self->gl_driver,
+ FALSE,
item.size.width,
item.size.height);
gsk_gl_driver_bind_source_texture (self->gl_driver, item.render_data.texture_id);
@@ -965,6 +1062,10 @@ gsk_gl_renderer_class_init (GskGLRendererClass *klass)
renderer_class->realize = gsk_gl_renderer_realize;
renderer_class->unrealize = gsk_gl_renderer_unrealize;
renderer_class->render = gsk_gl_renderer_render;
+
+ renderer_class->texture_new_for_data = gsk_gl_renderer_texture_new_for_data;
+ renderer_class->texture_new_for_pixbuf = gsk_gl_renderer_texture_new_for_pixbuf;
+ renderer_class->texture_destroy = gsk_gl_renderer_texture_destroy;
}
static void
diff --git a/gsk/gskrenderer.c b/gsk/gskrenderer.c
index 3bdab325eb..de2867fea5 100644
--- a/gsk/gskrenderer.c
+++ b/gsk/gskrenderer.c
@@ -42,6 +42,7 @@
#include "gskglrendererprivate.h"
#include "gskprofilerprivate.h"
#include "gskrendernodeprivate.h"
+#include "gsktexture.h"
#include "gskenumtypes.h"
@@ -133,6 +134,44 @@ gsk_renderer_real_create_cairo_surface (GskRenderer *self,
return res;
}
+static GskTexture *
+gsk_renderer_real_texture_new_for_data (GskRenderer *self,
+ const guchar *data,
+ int width,
+ int height,
+ int stride)
+{
+ GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD (self, texture_new_for_data);
+
+ return NULL;
+}
+
+static GskTexture *
+gsk_renderer_real_texture_new_for_pixbuf (GskRenderer *renderer,
+ GdkPixbuf *pixbuf)
+{
+ GskTexture *texture;
+ cairo_surface_t *surface;
+
+ surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, 1, NULL);
+
+ texture = gsk_texture_new_for_data (renderer,
+ cairo_image_surface_get_data (surface),
+ cairo_image_surface_get_width (surface),
+ cairo_image_surface_get_height (surface),
+ cairo_image_surface_get_stride (surface));
+
+ cairo_surface_destroy (surface);
+
+ return texture;
+}
+
+static void
+gsk_renderer_real_texture_destroy (GskTexture *texture)
+{
+ GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD (gsk_texture_get_renderer (texture), texture_destroy);
+}
+
static void
gsk_renderer_dispose (GObject *gobject)
{
@@ -239,6 +278,9 @@ gsk_renderer_class_init (GskRendererClass *klass)
klass->unrealize = gsk_renderer_real_unrealize;
klass->render = gsk_renderer_real_render;
klass->create_cairo_surface = gsk_renderer_real_create_cairo_surface;
+ klass->texture_new_for_data = gsk_renderer_real_texture_new_for_data;
+ klass->texture_new_for_pixbuf = gsk_renderer_real_texture_new_for_pixbuf;
+ klass->texture_destroy = gsk_renderer_real_texture_destroy;
gobject_class->constructed = gsk_renderer_constructed;
gobject_class->set_property = gsk_renderer_set_property;
diff --git a/gsk/gskrendererprivate.h b/gsk/gskrendererprivate.h
index 57f7e861f3..5fdc130e4c 100644
--- a/gsk/gskrendererprivate.h
+++ b/gsk/gskrendererprivate.h
@@ -47,6 +47,15 @@ struct _GskRendererClass
cairo_format_t,
int width,
int height);
+ /* called from gsktexture.c */
+ GskTexture * (* texture_new_for_data) (GskRenderer *renderer,
+ const guchar *data,
+ int width,
+ int height,
+ int stride);
+ GskTexture * (* texture_new_for_pixbuf) (GskRenderer *renderer,
+ GdkPixbuf *pixbuf);
+ void (* texture_destroy) (GskTexture *texture);
};
gboolean gsk_renderer_is_realized (GskRenderer *renderer);
diff --git a/gsk/gskrendernode.c b/gsk/gskrendernode.c
index 2b56b104eb..24bb2a7836 100644
--- a/gsk/gskrendernode.c
+++ b/gsk/gskrendernode.c
@@ -46,6 +46,7 @@
#include "gskdebugprivate.h"
#include "gskrendernodeiter.h"
#include "gskrendererprivate.h"
+#include "gsktexture.h"
#include <graphene-gobject.h>
@@ -1204,33 +1205,42 @@ gsk_render_node_has_texture (GskRenderNode *node)
{
g_return_val_if_fail (GSK_IS_RENDER_NODE (node), FALSE);
- return node->texture_id != 0;
+ return node->texture != NULL;
}
-int
+GskTexture *
gsk_render_node_get_texture (GskRenderNode *node)
{
g_return_val_if_fail (GSK_IS_RENDER_NODE (node), 0);
- return node->texture_id;
+ return node->texture;
}
/**
* gsk_render_node_set_texture:
* @node: a #GskRenderNode
- * @texture_id: the object id of a GL texture
+ * @texture: the #GskTexture
*
- * Associates a @texture_id to a #GskRenderNode.
+ * Associates a #GskTexture to a #GskRenderNode.
*
* Since: 3.90
*/
void
gsk_render_node_set_texture (GskRenderNode *node,
- int texture_id)
+ GskTexture *texture)
{
g_return_if_fail (GSK_IS_RENDER_NODE (node));
- node->texture_id = texture_id;
+ if (node->texture == texture)
+ return;
+
+ if (node->texture)
+ gsk_texture_unref (node->texture);
+
+ node->texture = texture;
+
+ if (texture)
+ gsk_texture_ref (texture);
}
/*< private >
diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h
index 3863423762..c6f5086562 100644
--- a/gsk/gskrendernode.h
+++ b/gsk/gskrendernode.h
@@ -119,7 +119,7 @@ void gsk_render_node_set_blend_mode (GskRenderNode *
GskBlendMode blend_mode);
GDK_AVAILABLE_IN_3_90
void gsk_render_node_set_texture (GskRenderNode *node,
- int texture_id);
+ GskTexture *texture);
GDK_AVAILABLE_IN_3_90
void gsk_render_node_set_scaling_filter (GskRenderNode *node,
GskScalingFilter min_filter,
diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h
index 20e6084d0c..3447822060 100644
--- a/gsk/gskrendernodeprivate.h
+++ b/gsk/gskrendernodeprivate.h
@@ -34,8 +34,8 @@ struct _GskRenderNode
/* The contents of the node as a Cairo surface */
cairo_surface_t *surface;
- /* The contents of the node as a GL surface */
- int texture_id;
+ /* The contents of the node as a texture */
+ GskTexture *texture;
/* Paint opacity */
double opacity;
@@ -85,7 +85,7 @@ double gsk_render_node_get_opacity (GskRenderNode *node);
cairo_surface_t *gsk_render_node_get_surface (GskRenderNode *node);
-int gsk_render_node_get_texture (GskRenderNode *node);
+GskTexture *gsk_render_node_get_texture (GskRenderNode *node);
gboolean gsk_render_node_has_surface (GskRenderNode *node);
gboolean gsk_render_node_has_texture (GskRenderNode *node);
diff --git a/gsk/gsktexture.c b/gsk/gsktexture.c
new file mode 100644
index 0000000000..956625b787
--- /dev/null
+++ b/gsk/gsktexture.c
@@ -0,0 +1,197 @@
+/* GSK - The GTK Scene Kit
+ *
+ * Copyright 2016 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 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/>.
+ */
+
+/**
+ * SECTION:GskTexture
+ * @Title: GskTexture
+ * @Short_description: Pixel data uploaded to a #GskRenderer
+ *
+ * #GskTexture is the basic element used to refer to pixel data.
+ *
+ * It can only be created for an existing realized #GskRenderer and becomes
+ * invalid when the renderer gets unrealized.
+ *
+ * You cannot get your pixel data back once you've uploaded it.
+ *
+ * #GskTexture is an immutable structure: That means you cannot change
+ * anything about it other than increasing the reference count via
+ * gsk_texture_ref().
+ */
+
+#include "config.h"
+
+#include "gsktextureprivate.h"
+
+#include "gskdebugprivate.h"
+#include "gskrendererprivate.h"
+
+/**
+ * GskTexture: (ref-func gsk_texture_ref) (unref-func gsk_texture_unref)
+ *
+ * The `GskTexture` structure contains only private data.
+ *
+ * Since: 3.90
+ */
+
+G_DEFINE_BOXED_TYPE(GskTexture, gsk_texture, gsk_texture_ref, gsk_texture_unref)
+
+static void
+gsk_texture_finalize (GskTexture *self)
+{
+ GSK_RENDERER_GET_CLASS (self->renderer)->texture_destroy (self);
+
+ g_object_unref (self->renderer);
+
+ g_free (self);
+}
+
+/**
+ * gsk_texture_ref:
+ * @texture: a #GskTexture
+ *
+ * Acquires a reference on the given #GskTexture.
+ *
+ * Returns: (transfer none): the #GskTexture with an additional reference
+ *
+ * Since: 3.90
+ */
+GskTexture *
+gsk_texture_ref (GskTexture *texture)
+{
+ g_return_val_if_fail (GSK_IS_TEXTURE (texture), NULL);
+
+ g_atomic_int_inc (&texture->ref_count);
+
+ return texture;
+}
+
+/**
+ * gsk_texture_unref:
+ * @texture: a #GskTexture
+ *
+ * Releases a reference on the given #GskTexture.
+ *
+ * If the reference was the last, the resources associated to the @texture are
+ * freed.
+ *
+ * Since: 3.90
+ */
+void
+gsk_texture_unref (GskTexture *texture)
+{
+ g_return_if_fail (GSK_IS_TEXTURE (texture));
+
+ if (g_atomic_int_dec_and_test (&texture->ref_count))
+ gsk_texture_finalize (texture);
+}
+
+GskTexture *
+gsk_texture_alloc (gsize size,
+ GskRenderer *renderer,
+ int width,
+ int height)
+{
+ GskTexture *self;
+
+ g_assert (size >= sizeof (GskTexture));
+
+ self = g_malloc0 (size);
+
+ self->ref_count = 1;
+
+ self->renderer = g_object_ref (renderer);
+ self->width = width;
+ self->height = height;
+
+ return self;
+}
+
+GskTexture *
+gsk_texture_new_for_data (GskRenderer *renderer,
+ const guchar *data,
+ int width,
+ int height,
+ int stride)
+{
+ return GSK_RENDERER_GET_CLASS (renderer)->texture_new_for_data (renderer, data, width, height, stride);
+}
+
+GskTexture *
+gsk_texture_new_for_pixbuf (GskRenderer *renderer,
+ GdkPixbuf *pixbuf)
+{
+ g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
+ g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
+
+ return GSK_RENDERER_GET_CLASS (renderer)->texture_new_for_pixbuf (renderer, pixbuf);
+}
+
+/**
+ * gsk_texture_get_renderer:
+ * @texture: a #GskTexture
+ *
+ * Returns the renderer that @texture was created for.
+ *
+ * Returns: (transfer none): the renderer of the #GskTexture
+ *
+ * Since: 3.90
+ */
+GskRenderer *
+gsk_texture_get_renderer (GskTexture *texture)
+{
+ g_return_val_if_fail (GSK_IS_TEXTURE (texture), NULL);
+
+ return texture->renderer;
+}
+
+/**
+ * gsk_texture_get_width:
+ * @texture: a #GskTexture
+ *
+ * Returns the width of @texture.
+ *
+ * Returns: the width of the #GskTexture
+ *
+ * Since: 3.90
+ */
+int
+gsk_texture_get_width (GskTexture *texture)
+{
+ g_return_val_if_fail (GSK_IS_TEXTURE (texture), 0);
+
+ return texture->width;
+}
+
+/**
+ * gsk_texture_get_height:
+ * @texture: a #GskTexture
+ *
+ * Returns the height of the @texture.
+ *
+ * Returns: the height of the #GskTexture
+ *
+ * Since: 3.90
+ */
+int
+gsk_texture_get_height (GskTexture *texture)
+{
+ g_return_val_if_fail (GSK_IS_TEXTURE (texture), 0);
+
+ return texture->height;
+}
+
diff --git a/gsk/gsktexture.h b/gsk/gsktexture.h
new file mode 100644
index 0000000000..1d1c81e472
--- /dev/null
+++ b/gsk/gsktexture.h
@@ -0,0 +1,61 @@
+/* GSK - The GTK Scene Kit
+ *
+ * Copyright 2016 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 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/>.
+ */
+
+#ifndef __GSK_TEXTURE_H__
+#define __GSK_TEXTURE_H__
+
+#if !defined (__GSK_H_INSIDE__) && !defined (GSK_COMPILATION)
+#error "Only <gsk/gsk.h> can be included directly."
+#endif
+
+#include <gsk/gsktypes.h>
+
+G_BEGIN_DECLS
+
+#define GSK_TYPE_TEXTURE (gsk_texture_get_type ())
+
+#define GSK_IS_TEXTURE(texture) ((texture) != NULL)
+
+GDK_AVAILABLE_IN_3_90
+GType gsk_texture_get_type (void) G_GNUC_CONST;
+
+GDK_AVAILABLE_IN_3_90
+GskTexture * gsk_texture_ref (GskTexture *texture);
+GDK_AVAILABLE_IN_3_90
+void gsk_texture_unref (GskTexture *texture);
+
+GDK_AVAILABLE_IN_3_90
+GskTexture * gsk_texture_new_for_data (GskRenderer *renderer,
+ const guchar *data,
+ int width,
+ int height,
+ int stride);
+GDK_AVAILABLE_IN_3_90
+GskTexture * gsk_texture_new_for_pixbuf (GskRenderer *renderer,
+ GdkPixbuf *pixbuf);
+
+GDK_AVAILABLE_IN_3_90
+GskRenderer * gsk_texture_get_renderer (GskTexture *texture);
+GDK_AVAILABLE_IN_3_90
+int gsk_texture_get_width (GskTexture *texture);
+GDK_AVAILABLE_IN_3_90
+int gsk_texture_get_height (GskTexture *texture);
+
+G_END_DECLS
+
+#endif /* __GSK_TEXTURE_H__ */
diff --git a/gsk/gsktextureprivate.h b/gsk/gsktextureprivate.h
new file mode 100644
index 0000000000..887a03adcc
--- /dev/null
+++ b/gsk/gsktextureprivate.h
@@ -0,0 +1,30 @@
+#ifndef __GSK_TEXTURE_PRIVATE_H__
+#define __GSK_TEXTURE_PRIVATE_H__
+
+#include "gsktexture.h"
+
+G_BEGIN_DECLS
+
+#define GSK_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_TEXTURE, GskTextureClass))
+#define GSK_IS_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_TEXTURE))
+#define GSK_TEXTURE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_TEXTURE, GskTextureClass))
+
+struct _GskTexture
+{
+ volatile int ref_count;
+
+ GskRenderer *renderer;
+ int width;
+ int height;
+};
+
+#define gsk_texture_new(type,renderer,width,height) \
+ (type *) gsk_texture_alloc(sizeof (type),(renderer),(width),(height))
+GskTexture *gsk_texture_alloc (gsize size,
+ GskRenderer *renderer,
+ int width,
+ int height);
+
+G_END_DECLS
+
+#endif /* __GSK_TEXTURE_PRIVATE_H__ */
diff --git a/gsk/gsktypes.h b/gsk/gsktypes.h
index eae1591dad..32fab4cf49 100644
--- a/gsk/gsktypes.h
+++ b/gsk/gsktypes.h
@@ -27,5 +27,6 @@
#include <gsk/gskenums.h>
typedef struct _GskRenderer GskRenderer;
+typedef struct _GskTexture GskTexture;
#endif /* __GSK_TYPES_H__ */