summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte.benjamin@googlemail.com>2021-09-12 12:55:00 +0000
committerBenjamin Otte <otte.benjamin@googlemail.com>2021-09-12 12:55:00 +0000
commit6bbec8770088bb9fc61cb71ac9b11a61eae36b52 (patch)
tree32fec9fd73d15665f9f040c1fb3697f81a816f74
parentb35608a351bbec6b76b9f42ce9c04d6094dae759 (diff)
parent416763bf2d31edc21608dd20cc6cf125ea3d6563 (diff)
downloadgtk+-6bbec8770088bb9fc61cb71ac9b11a61eae36b52.tar.gz
Merge branch 'wip/otte/float-textures' into 'master'
Add float texture formats See merge request GNOME/gtk!3940
-rw-r--r--gdk/gdkcairo.h2
-rw-r--r--gdk/gdkgl.c8
-rw-r--r--gdk/gdkglcontext.c123
-rw-r--r--gdk/gdkgltexture.c233
-rw-r--r--gdk/gdkmemorytexture.c431
-rw-r--r--gdk/gdkmemorytexture.h20
-rw-r--r--gdk/gdkmemorytextureprivate.h40
-rw-r--r--gdk/gdktexture.c110
-rw-r--r--gdk/gdktexture.h4
-rw-r--r--gdk/gdktextureprivate.h13
-rw-r--r--gsk/ngl/gsknglglyphlibrary.c2
-rw-r--r--gsk/ngl/gskngliconlibrary.c2
-rw-r--r--testsuite/gdk/memorytexture.c667
13 files changed, 1359 insertions, 296 deletions
diff --git a/gdk/gdkcairo.h b/gdk/gdkcairo.h
index 40ab46baf6..f2dfa3177e 100644
--- a/gdk/gdkcairo.h
+++ b/gdk/gdkcairo.h
@@ -50,7 +50,7 @@ cairo_region_t *
gdk_cairo_region_create_from_surface
(cairo_surface_t *surface);
-GDK_AVAILABLE_IN_ALL
+GDK_DEPRECATED_IN_4_6_FOR(gdk_gl_texture_new)
void gdk_cairo_draw_from_gl (cairo_t *cr,
GdkSurface *surface,
int source,
diff --git a/gdk/gdkgl.c b/gdk/gdkgl.c
index 4e57853afb..417c29d15b 100644
--- a/gdk/gdkgl.c
+++ b/gdk/gdkgl.c
@@ -301,7 +301,7 @@ gdk_gl_texture_quads (GdkGLContext *paint_context,
* @width: The width of the region to draw
* @height: The height of the region to draw
*
- * The main way to draw GL content in GTK.
+ * The main way to not draw GL content in GTK.
*
* It takes a render buffer ID (@source_type == GL_RENDERBUFFER) or a texture
* id (@source_type == GL_TEXTURE) and draws it onto @cr with an OVER operation,
@@ -319,6 +319,12 @@ gdk_gl_texture_quads (GdkGLContext *paint_context,
* with alpha components, so make sure you use GL_TEXTURE if using alpha.
*
* Calling this may change the current GL context.
+ *
+ * Deprecated: 4.6: The function is overly complex and produces broken output
+ * in various combinations of arguments. If you want to draw with GL textures
+ * in GTK, use [ctor@Gdk.GLTexture.new]; if you want to use that texture in
+ * Cairo, use [method@Gdk.Texture.download] to download the data into a Cairo
+ * image surface.
*/
void
gdk_cairo_draw_from_gl (cairo_t *cr,
diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c
index 522cbcecf6..76be3c7ef9 100644
--- a/gdk/gdkglcontext.c
+++ b/gdk/gdkglcontext.c
@@ -229,71 +229,84 @@ gdk_gl_context_upload_texture (GdkGLContext *context,
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
guchar *copy = NULL;
- guint gl_internalformat;
- guint gl_format;
- guint gl_type;
- guint bpp;
+ GLint gl_internalformat;
+ GLint gl_format;
+ GLint gl_type;
+ gsize bpp;
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
- if (priv->use_es)
+ if (!priv->use_es && data_format == GDK_MEMORY_DEFAULT) /* Cairo surface format */
{
- /* GLES only supports rgba, so convert if necessary */
- if (data_format != GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
- {
- copy = g_malloc (width * height * 4);
- gdk_memory_convert (copy, width * 4,
- GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
- data, stride, data_format,
- width, height);
- stride = width * 4;
- data = copy;
- }
-
- bpp = 4;
gl_internalformat = GL_RGBA8;
- gl_format = GL_RGBA;
+ gl_format = GL_BGRA;
+ gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ }
+ else if (data_format == GDK_MEMORY_R8G8B8) /* Pixmap non-alpha data */
+ {
+ gl_internalformat = GL_RGBA8;
+ gl_format = GL_RGB;
gl_type = GL_UNSIGNED_BYTE;
}
- else
+ else if (priv->use_es && data_format == GDK_MEMORY_B8G8R8)
{
- if (data_format == GDK_MEMORY_DEFAULT) /* Cairo surface format */
- {
- gl_internalformat = GL_RGBA8;
- gl_format = GL_BGRA;
- gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
- bpp = 4;
- }
- else if (data_format == GDK_MEMORY_R8G8B8) /* Pixmap non-alpha data */
- {
- gl_internalformat = GL_RGBA8;
- gl_format = GL_RGB;
- gl_type = GL_UNSIGNED_BYTE;
- bpp = 3;
- }
- else if (data_format == GDK_MEMORY_B8G8R8)
- {
- gl_internalformat = GL_RGBA8;
- gl_format = GL_BGR;
- gl_type = GL_UNSIGNED_BYTE;
- bpp = 3;
- }
- else /* Fall-back, convert to cairo-surface-format */
- {
- copy = g_malloc (width * height * 4);
- gdk_memory_convert (copy, width * 4,
- GDK_MEMORY_DEFAULT,
- data, stride, data_format,
- width, height);
- stride = width * 4;
- bpp = 4;
- data = copy;
- gl_internalformat = GL_RGBA8;
- gl_format = GL_BGRA;
- gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
- }
+ gl_internalformat = GL_RGBA8;
+ gl_format = GL_BGR;
+ gl_type = GL_UNSIGNED_BYTE;
+ }
+ else if (data_format == GDK_MEMORY_R16G16B16)
+ {
+ gl_internalformat = GL_RGBA16;
+ gl_format = GL_RGB;
+ gl_type = GL_UNSIGNED_SHORT;
+ }
+ else if (data_format == GDK_MEMORY_R16G16B16A16_PREMULTIPLIED)
+ {
+ gl_internalformat = GL_RGBA16;
+ gl_format = GL_RGBA;
+ gl_type = GL_UNSIGNED_SHORT;
+ }
+ else if (data_format == GDK_MEMORY_R16G16B16_FLOAT)
+ {
+ gl_internalformat = GL_RGB16F;
+ gl_format = GL_RGB;
+ gl_type = GL_HALF_FLOAT;
+ }
+ else if (data_format == GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED)
+ {
+ gl_internalformat = GL_RGBA16F;
+ gl_format = GL_RGBA;
+ gl_type = GL_HALF_FLOAT;
+ }
+ else if (data_format == GDK_MEMORY_R32G32B32_FLOAT)
+ {
+ gl_internalformat = GL_RGB32F;
+ gl_format = GL_RGB;
+ gl_type = GL_FLOAT;
+ }
+ else if (data_format == GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED)
+ {
+ gl_internalformat = GL_RGBA32F;
+ gl_format = GL_RGBA;
+ gl_type = GL_FLOAT;
+ }
+ else /* Fall-back, convert to GLES format */
+ {
+ copy = g_malloc (width * height * 4);
+ gdk_memory_convert (copy, width * 4,
+ GDK_MEMORY_CONVERT_GLES_RGBA,
+ data, stride, data_format,
+ width, height);
+ data_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
+ stride = width * 4;
+ data = copy;
+ gl_internalformat = GL_RGBA8;
+ gl_format = GL_RGBA;
+ gl_type = GL_UNSIGNED_BYTE;
}
+ bpp = gdk_memory_format_bytes_per_pixel (data_format);
+
/* GL_UNPACK_ROW_LENGTH is available on desktop GL, OpenGL ES >= 3.0, or if
* the GL_EXT_unpack_subimage extension for OpenGL ES 2.0 is available
*/
diff --git a/gdk/gdkgltexture.c b/gdk/gdkgltexture.c
index caf3e7ab6b..6c91c70f70 100644
--- a/gdk/gdkgltexture.c
+++ b/gdk/gdkgltexture.c
@@ -20,7 +20,7 @@
#include "gdkgltextureprivate.h"
-#include "gdkcairo.h"
+#include "gdkmemorytextureprivate.h"
#include "gdktextureprivate.h"
#include <epoxy/gl.h>
@@ -37,7 +37,7 @@ struct _GdkGLTexture {
GdkGLContext *context;
guint id;
- cairo_surface_t *saved;
+ GdkTexture *saved;
GDestroyNotify destroy;
gpointer data;
@@ -64,50 +64,209 @@ gdk_gl_texture_dispose (GObject *object)
g_clear_object (&self->context);
self->id = 0;
+ g_clear_object (&self->saved);
+
+ G_OBJECT_CLASS (gdk_gl_texture_parent_class)->dispose (object);
+}
+
+static GdkTexture *
+gdk_gl_texture_download_texture (GdkTexture *texture)
+{
+ GdkGLTexture *self = GDK_GL_TEXTURE (texture);
+ GdkTexture *result;
+ int active_texture;
+ GdkMemoryFormat format;
+ GLint internal_format, gl_format, gl_type;
+ guchar *data;
+ gsize stride;
+ GBytes *bytes;
+
+ if (self->saved)
+ return g_object_ref (self->saved);
+
+ gdk_gl_context_make_current (self->context);
+
+ glGetIntegerv (GL_TEXTURE_BINDING_2D, &active_texture);
+ glBindTexture (GL_TEXTURE_2D, self->id);
+
+ glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format);
+
+ switch (internal_format)
+ {
+ case GL_RGB8:
+ format = GDK_MEMORY_R8G8B8;
+ gl_format = GL_RGB;
+ gl_type = GL_UNSIGNED_BYTE;
+ break;
+
+ case GL_RGBA8:
+ format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
+ gl_format = GL_RGBA;
+ gl_type = GL_UNSIGNED_BYTE;
+ break;
+
+ case GL_RGB16:
+ format = GDK_MEMORY_R16G16B16;
+ gl_format = GL_RGB;
+ gl_type = GL_UNSIGNED_SHORT;
+ break;
+
+ case GL_RGBA16:
+ format = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED;
+ gl_format = GL_RGBA;
+ gl_type = GL_UNSIGNED_SHORT;
+ break;
+
+ case GL_RGB16F:
+ format = GDK_MEMORY_R16G16B16_FLOAT;
+ gl_format = GL_RGB;
+ gl_type = GL_HALF_FLOAT;
+ break;
+
+ case GL_RGBA16F:
+ format = GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED;
+ gl_format = GL_RGBA;
+ gl_type = GL_HALF_FLOAT;
+ break;
+
+ case GL_RGB32F:
+ format = GDK_MEMORY_R32G32B32_FLOAT;
+ gl_format = GL_RGB;
+ gl_type = GL_FLOAT;
+ break;
+
+ case GL_RGBA32F:
+ format = GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED;
+ gl_format = GL_RGBA;
+ gl_type = GL_FLOAT;
+ break;
+
+ default:
+ g_warning ("Texture in unexpected format 0x%X (%d). File a bug about adding it to GTK", internal_format, internal_format);
+ /* fallback to the dumbest possible format
+ * so that even age old GLES can do it */
+ format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
+ gl_format = GL_RGBA;
+ gl_type = GL_UNSIGNED_BYTE;
+ break;
+ }
+
+ stride = gdk_memory_format_bytes_per_pixel (format) * texture->width;
+ data = g_malloc (stride * texture->height);
+
+ glGetTexImage (GL_TEXTURE_2D,
+ 0,
+ gl_format,
+ gl_type,
+ data);
+
+ bytes = g_bytes_new_take (data, stride * texture->height);
+ result = gdk_memory_texture_new (texture->width,
+ texture->height,
+ format,
+ bytes,
+ stride);
+
+ g_bytes_unref (bytes);
+
+ glBindTexture (GL_TEXTURE_2D, active_texture);
+
+ return result;
+}
+
+static void
+gdk_gl_texture_download (GdkTexture *texture,
+ guchar *data,
+ gsize stride)
+{
+ GdkGLTexture *self = GDK_GL_TEXTURE (texture);
+ GLint active_texture;
+
if (self->saved)
{
- cairo_surface_destroy (self->saved);
- self->saved = NULL;
+ gdk_texture_download (self->saved, data, stride);
+ return;
}
- G_OBJECT_CLASS (gdk_gl_texture_parent_class)->dispose (object);
+ if (gdk_gl_context_get_use_es (self->context) ||
+ stride != texture->width * 4)
+ {
+ GDK_TEXTURE_CLASS (gdk_gl_texture_parent_class)->download (texture, data, stride);
+ return;
+ }
+
+ gdk_gl_context_make_current (self->context);
+
+ glGetIntegerv (GL_TEXTURE_BINDING_2D, &active_texture);
+ glBindTexture (GL_TEXTURE_2D, self->id);
+
+ glGetTexImage (GL_TEXTURE_2D,
+ 0,
+ GL_BGRA,
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ GL_UNSIGNED_INT_8_8_8_8_REV,
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+ GL_UNSIGNED_BYTE,
+#else
+#error "Unknown byte order for gdk_gl_texture_download()"
+#endif
+ data);
+
+ glBindTexture (GL_TEXTURE_2D, active_texture);
}
static void
-gdk_gl_texture_download (GdkTexture *texture,
- const GdkRectangle *area,
- guchar *data,
- gsize stride)
+gdk_gl_texture_do_download_float (GdkTexture *texture,
+ float *data)
{
GdkGLTexture *self = GDK_GL_TEXTURE (texture);
- cairo_surface_t *surface;
- cairo_t *cr;
+ int active_texture;
+
+ gdk_gl_context_make_current (self->context);
- surface = cairo_image_surface_create_for_data (data,
- CAIRO_FORMAT_ARGB32,
- area->width, area->height,
- stride);
+ glGetIntegerv (GL_TEXTURE_BINDING_2D, &active_texture);
+ glBindTexture (GL_TEXTURE_2D, self->id);
- cr = cairo_create (surface);
+ glGetTexImage (GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ GL_FLOAT,
+ data);
+
+ glBindTexture (GL_TEXTURE_2D, active_texture);
+}
+
+static void
+gdk_gl_texture_download_float (GdkTexture *texture,
+ float *data,
+ gsize stride)
+{
+ GdkGLTexture *self = GDK_GL_TEXTURE (texture);
+ int width, height, y;
+ float *copy;
if (self->saved)
{
- cairo_set_source_surface (cr, self->saved, 0, 0);
- cairo_paint (cr);
+ gdk_texture_download_float (self->saved, data, stride);
+ return;
}
- else
- {
- GdkSurface *gl_surface;
- gl_surface = gdk_gl_context_get_surface (self->context);
- gdk_cairo_draw_from_gl (cr, gl_surface, self->id, GL_TEXTURE, 1,
- area->x, area->y,
- area->width, area->height);
+ width = gdk_texture_get_width (texture);
+ height = gdk_texture_get_height (texture);
+
+ if (stride == width * 4)
+ {
+ gdk_gl_texture_do_download_float (texture, data);
+ return;
}
- cairo_destroy (cr);
- cairo_surface_finish (surface);
- cairo_surface_destroy (surface);
+ copy = g_new (float, width * height * 4);
+
+ gdk_gl_texture_do_download_float (texture, copy);
+ for (y = 0; y < height; y++)
+ memcpy (data + y * stride, copy + y * 4 * width, 4 * width);
+
+ g_free (copy);
}
static void
@@ -116,7 +275,9 @@ gdk_gl_texture_class_init (GdkGLTextureClass *klass)
GdkTextureClass *texture_class = GDK_TEXTURE_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ texture_class->download_texture = gdk_gl_texture_download_texture;
texture_class->download = gdk_gl_texture_download;
+ texture_class->download_float = gdk_gl_texture_download_float;
gobject_class->dispose = gdk_gl_texture_dispose;
}
@@ -150,24 +311,10 @@ gdk_gl_texture_get_id (GdkGLTexture *self)
void
gdk_gl_texture_release (GdkGLTexture *self)
{
- GdkSurface *surface;
- GdkTexture *texture;
- cairo_t *cr;
-
g_return_if_fail (GDK_IS_GL_TEXTURE (self));
g_return_if_fail (self->saved == NULL);
- texture = GDK_TEXTURE (self);
- self->saved = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
- texture->width, texture->height);
-
- cr = cairo_create (self->saved);
-
- surface = gdk_gl_context_get_surface (self->context);
- gdk_cairo_draw_from_gl (cr, surface, self->id, GL_TEXTURE, 1, 0, 0,
- texture->width, texture->height);
-
- cairo_destroy (cr);
+ self->saved = gdk_texture_download_texture (GDK_TEXTURE (self));
if (self->destroy)
{
diff --git a/gdk/gdkmemorytexture.c b/gdk/gdkmemorytexture.c
index 06fa3d6619..631357bcc8 100644
--- a/gdk/gdkmemorytexture.c
+++ b/gdk/gdkmemorytexture.c
@@ -20,6 +20,7 @@
#include "config.h"
#include "gdkmemorytextureprivate.h"
+#include "gsk/ngl/fp16private.h"
/**
* GdkMemoryTexture:
@@ -49,6 +50,10 @@ gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format)
{
switch (format)
{
+ case GDK_MEMORY_R8G8B8:
+ case GDK_MEMORY_B8G8R8:
+ return 3;
+
case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
@@ -58,14 +63,59 @@ gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format)
case GDK_MEMORY_A8B8G8R8:
return 4;
+ case GDK_MEMORY_R16G16B16:
+ case GDK_MEMORY_R16G16B16_FLOAT:
+ return 6;
+
+ case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
+ case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
+ return 8;
+
+ case GDK_MEMORY_R32G32B32_FLOAT:
+ return 12;
+
+ case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
+ return 16;
+
+ case GDK_MEMORY_N_FORMATS:
+ default:
+ g_assert_not_reached ();
+ return 4;
+ }
+}
+
+static gsize
+gdk_memory_format_alignment (GdkMemoryFormat format)
+{
+ switch (format)
+ {
case GDK_MEMORY_R8G8B8:
case GDK_MEMORY_B8G8R8:
- return 3;
+ case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
+ case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
+ case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
+ case GDK_MEMORY_B8G8R8A8:
+ case GDK_MEMORY_A8R8G8B8:
+ case GDK_MEMORY_R8G8B8A8:
+ case GDK_MEMORY_A8B8G8R8:
+ return G_ALIGNOF (guchar);
+
+ case GDK_MEMORY_R16G16B16:
+ case GDK_MEMORY_R16G16B16_FLOAT:
+ return G_ALIGNOF (guint16);
+
+ case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
+ case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
+ return G_ALIGNOF (guint16);
+
+ case GDK_MEMORY_R32G32B32_FLOAT:
+ case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
+ return G_ALIGNOF (float);
case GDK_MEMORY_N_FORMATS:
default:
g_assert_not_reached ();
- return 4;
+ return G_ALIGNOF (double);
}
}
@@ -79,22 +129,41 @@ gdk_memory_texture_dispose (GObject *object)
G_OBJECT_CLASS (gdk_memory_texture_parent_class)->dispose (object);
}
+static GdkTexture *
+gdk_memory_texture_download_texture (GdkTexture *texture)
+{
+ return g_object_ref (texture);
+}
+
static void
-gdk_memory_texture_download (GdkTexture *texture,
- const GdkRectangle *area,
- guchar *data,
- gsize stride)
+gdk_memory_texture_download (GdkTexture *texture,
+ guchar *data,
+ gsize stride)
{
GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (texture);
gdk_memory_convert (data, stride,
- GDK_MEMORY_CAIRO_FORMAT_ARGB32,
- (guchar *) g_bytes_get_data (self->bytes, NULL)
- + area->x * gdk_memory_format_bytes_per_pixel (self->format)
- + area->y * self->stride,
+ GDK_MEMORY_CONVERT_DOWNLOAD,
+ (guchar *) g_bytes_get_data (self->bytes, NULL),
self->stride,
self->format,
- area->width, area->height);
+ gdk_texture_get_width (texture),
+ gdk_texture_get_height (texture));
+}
+
+static void
+gdk_memory_texture_download_float (GdkTexture *texture,
+ float *data,
+ gsize stride)
+{
+ GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (texture);
+
+ gdk_memory_convert_to_float (data, stride,
+ (guchar *) g_bytes_get_data (self->bytes, NULL),
+ self->stride,
+ self->format,
+ gdk_texture_get_width (texture),
+ gdk_texture_get_height (texture));
}
static void
@@ -103,7 +172,9 @@ gdk_memory_texture_class_init (GdkMemoryTextureClass *klass)
GdkTextureClass *texture_class = GDK_TEXTURE_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ texture_class->download_texture = gdk_memory_texture_download_texture;
texture_class->download = gdk_memory_texture_download;
+ texture_class->download_float = gdk_memory_texture_download_float;
gobject_class->dispose = gdk_memory_texture_dispose;
}
@@ -112,6 +183,41 @@ gdk_memory_texture_init (GdkMemoryTexture *self)
{
}
+static GBytes *
+gdk_memory_sanitize (GBytes *bytes,
+ int width,
+ int height,
+ GdkMemoryFormat format,
+ gsize stride,
+ gsize *out_stride)
+{
+ gsize align, size, copy_stride, bpp;
+ const guchar *data;
+ guchar *copy;
+ int y;
+
+ data = g_bytes_get_data (bytes, &size);
+ align = gdk_memory_format_alignment (format);
+
+ if (GPOINTER_TO_SIZE (data) % align == 0 &&
+ stride % align == 0)
+ {
+ *out_stride = stride;
+ return g_bytes_ref (bytes);
+ }
+
+ bpp = gdk_memory_format_bytes_per_pixel (format);
+ copy_stride = bpp * width;
+ /* align to multiples of 4, just to be sure */
+ copy_stride = (copy_stride + 3) & ~3;
+ copy = g_malloc (copy_stride * height);
+ for (y = 0; y < height; y++)
+ memcpy (copy + y * copy_stride, data + y * stride, bpp * width);
+
+ *out_stride = copy_stride;
+ return g_bytes_new_take (copy, copy_stride * height);
+}
+
/**
* gdk_memory_texture_new:
* @width: the width of the texture
@@ -136,13 +242,20 @@ gdk_memory_texture_new (int width,
{
GdkMemoryTexture *self;
+ g_return_val_if_fail (width > 0, NULL);
+ g_return_val_if_fail (height > 0, NULL);
+ g_return_val_if_fail (bytes != NULL, NULL);
+ g_return_val_if_fail (stride >= width * gdk_memory_format_bytes_per_pixel (format), NULL);
+
+ bytes = gdk_memory_sanitize (bytes, width, height, format, stride, &stride);
+
self = g_object_new (GDK_TYPE_MEMORY_TEXTURE,
"width", width,
"height", height,
NULL);
self->format = format;
- self->bytes = g_bytes_ref (bytes);
+ self->bytes = bytes;
self->stride = stride;
return GDK_TEXTURE (self);
@@ -283,6 +396,109 @@ SWIZZLE_PREMULTIPLY (3,0,1,2, 0,1,2,3)
SWIZZLE_PREMULTIPLY (3,0,1,2, 3,0,1,2)
SWIZZLE_PREMULTIPLY (3,0,1,2, 0,3,2,1)
+#define CONVERT_FUNC(name,suffix,R,G,B,A,step) \
+static void \
+convert_ ## name ## _to_ ## suffix (guchar *dest_data, \
+ gsize dest_stride, \
+ const guchar *src_data, \
+ gsize src_stride, \
+ gsize width, \
+ gsize height) \
+{ \
+ gsize x, y; \
+\
+ for (y = 0; y < height; y++) \
+ { \
+ for (x = 0; x < width; x++) \
+ { \
+ guchar conv[4]; \
+ convert_pixel_ ## name (conv, src_data + step * x); \
+ dest_data[4 * x + R] = conv[0]; \
+ dest_data[4 * x + G] = conv[1]; \
+ dest_data[4 * x + B] = conv[2]; \
+ dest_data[4 * x + A] = conv[3]; \
+ } \
+\
+ dest_data += dest_stride; \
+ src_data += src_stride; \
+ } \
+}
+
+#define CONVERT_FUNCS(name,step) \
+CONVERT_FUNC(name, download_le, 2, 1, 0, 3, step) \
+CONVERT_FUNC(name, download_be, 1, 2, 3, 0, step) \
+CONVERT_FUNC(name, gles_rgba, 0, 1, 2, 3, step) \
+
+static inline void
+convert_pixel_rgb16 (guchar *dest_data, const guchar *src_data)
+{
+ const guint16 *src = (const guint16 *) src_data;
+ dest_data[0] = (guchar)(src[0] >> 8);
+ dest_data[1] = (guchar)(src[1] >> 8);
+ dest_data[2] = (guchar)(src[2] >> 8);
+ dest_data[3] = 0xFF;
+}
+CONVERT_FUNCS(rgb16, 3 * sizeof (guint16))
+
+static inline void
+convert_pixel_rgba16 (guchar *dest_data, const guchar *src_data)
+{
+ const guint16 *src = (const guint16 *) src_data;
+ dest_data[0] = (guchar)(src[0] >> 8);
+ dest_data[1] = (guchar)(src[1] >> 8);
+ dest_data[2] = (guchar)(src[2] >> 8);
+ dest_data[3] = (guchar)(src[3] >> 8);
+}
+CONVERT_FUNCS(rgba16, 4 * sizeof (guint16))
+
+static inline void
+convert_pixel_rgb16f (guchar *dest_data, const guchar *src_data)
+{
+ float src[4];
+ guint16 tmp[4];
+ memcpy(tmp, src_data, sizeof(guint16) * 3);
+ half_to_float4(tmp, src);
+ dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f);
+ dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f);
+ dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f);
+ dest_data[3] = 0xFF;
+}
+CONVERT_FUNCS(rgb16f, 3 * sizeof (guint16))
+
+static inline void
+convert_pixel_rgba16f (guchar *dest_data, const guchar *src_data)
+{
+ float src[4];
+ half_to_float4((const guint16 *) src_data, src);
+ dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f);
+ dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f);
+ dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f);
+ dest_data[3] = CLAMP (src[3] * 256.f, 0.f, 255.f);
+}
+CONVERT_FUNCS(rgba16f, 4 * sizeof (guint16))
+
+static inline void
+convert_pixel_rgb32f (guchar *dest_data, const guchar *src_data)
+{
+ float *src = (float *) src_data;
+ dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f);
+ dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f);
+ dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f);
+ dest_data[3] = 0xFF;
+}
+CONVERT_FUNCS(rgb32f, 3 * sizeof (float))
+
+static inline void
+convert_pixel_rgba32f (guchar *dest_data, const guchar *src_data)
+{
+ float *src = (float *) src_data;
+ dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f);
+ dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f);
+ dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f);
+ dest_data[3] = CLAMP (src[3] * 256.f, 0.f, 255.f);
+}
+CONVERT_FUNCS(rgba32f, 4 * sizeof (float))
+
typedef void (* ConversionFunc) (guchar *dest_data,
gsize dest_stride,
const guchar *src_data,
@@ -290,7 +506,7 @@ typedef void (* ConversionFunc) (guchar *dest_data,
gsize width,
gsize height);
-static ConversionFunc converters[GDK_MEMORY_N_FORMATS][3] =
+static ConversionFunc converters[GDK_MEMORY_N_FORMATS][GDK_MEMORY_N_CONVERSIONS] =
{
{ convert_memcpy, convert_swizzle3210, convert_swizzle2103 },
{ convert_swizzle3210, convert_memcpy, convert_swizzle3012 },
@@ -300,21 +516,192 @@ static ConversionFunc converters[GDK_MEMORY_N_FORMATS][3] =
{ convert_swizzle_premultiply_3210_3012, convert_swizzle_premultiply_0123_3012, convert_swizzle_premultiply_3012_3012 },
{ convert_swizzle_premultiply_3210_0321, convert_swizzle_premultiply_0123_0321, convert_swizzle_premultiply_3012_0321 },
{ convert_swizzle_opaque_3210, convert_swizzle_opaque_0123, convert_swizzle_opaque_3012 },
- { convert_swizzle_opaque_3012, convert_swizzle_opaque_0321, convert_swizzle_opaque_3210 }
+ { convert_swizzle_opaque_3012, convert_swizzle_opaque_0321, convert_swizzle_opaque_3210 },
+ { convert_rgb16_to_download_le, convert_rgb16_to_download_be, convert_rgb16_to_gles_rgba },
+ { convert_rgba16_to_download_le, convert_rgba16_to_download_be, convert_rgba16_to_gles_rgba },
+ { convert_rgb16f_to_download_le, convert_rgb16f_to_download_be, convert_rgb16f_to_gles_rgba },
+ { convert_rgba16f_to_download_le, convert_rgba16f_to_download_be, convert_rgba16f_to_gles_rgba },
+ { convert_rgb32f_to_download_le, convert_rgb32f_to_download_be, convert_rgb32f_to_gles_rgba },
+ { convert_rgba32f_to_download_le, convert_rgba32f_to_download_be, convert_rgba32f_to_gles_rgba }
};
void
-gdk_memory_convert (guchar *dest_data,
- gsize dest_stride,
- GdkMemoryFormat dest_format,
- const guchar *src_data,
- gsize src_stride,
- GdkMemoryFormat src_format,
- gsize width,
- gsize height)
+gdk_memory_convert (guchar *dest_data,
+ gsize dest_stride,
+ GdkMemoryConversion dest_format,
+ const guchar *src_data,
+ gsize src_stride,
+ GdkMemoryFormat src_format,
+ gsize width,
+ gsize height)
{
g_assert (dest_format < 3);
g_assert (src_format < GDK_MEMORY_N_FORMATS);
converters[src_format][dest_format] (dest_data, dest_stride, src_data, src_stride, width, height);
}
+
+#define CONVERT_FLOAT(R,G,B,A,premultiply) G_STMT_START {\
+ for (y = 0; y < height; y++) \
+ { \
+ for (x = 0; x < width; x++) \
+ { \
+ if (A >= 0) \
+ { \
+ dest_data[4 * x + 0] = src_data[4 * x + R] / 255.0f; \
+ dest_data[4 * x + 1] = src_data[4 * x + G] / 255.0f; \
+ dest_data[4 * x + 2] = src_data[4 * x + B] / 255.0f; \
+ dest_data[4 * x + 3] = src_data[4 * x + A] / 255.0f; \
+ if (premultiply) \
+ { \
+ dest_data[4 * x + 0] *= dest_data[4 * x + 3]; \
+ dest_data[4 * x + 1] *= dest_data[4 * x + 3]; \
+ dest_data[4 * x + 2] *= dest_data[4 * x + 3]; \
+ } \
+ } \
+ else \
+ { \
+ dest_data[4 * x + 0] = src_data[3 * x + R] / 255.0f; \
+ dest_data[4 * x + 1] = src_data[3 * x + G] / 255.0f; \
+ dest_data[4 * x + 2] = src_data[3 * x + B] / 255.0f; \
+ dest_data[4 * x + 3] = 1.0; \
+ } \
+ } \
+\
+ dest_data += dest_stride; \
+ src_data += src_stride; \
+ } \
+}G_STMT_END
+
+#define CONVERT_FLOAT_PIXEL(func,step) G_STMT_START{\
+ for (y = 0; y < height; y++) \
+ { \
+ for (x = 0; x < width; x++) \
+ { \
+ func (dest_data + 4 * x, src_data + step * x); \
+ } \
+\
+ dest_data += dest_stride; \
+ src_data += src_stride; \
+ } \
+}G_STMT_END
+
+static inline void
+convert_rgb16_to_float (float *dest, const guchar *src_data)
+{
+ const guint16 *src = (const guint16 *) src_data;
+ dest[0] = src[0] / 65535.f;
+ dest[1] = src[1] / 65535.f;
+ dest[2] = src[2] / 65535.f;
+ dest[3] = 1.0;
+}
+
+static inline void
+convert_rgba16_to_float (float *dest, const guchar *src_data)
+{
+ const guint16 *src = (const guint16 *) src_data;
+ dest[0] = src[0] / 65535.f;
+ dest[1] = src[1] / 65535.f;
+ dest[2] = src[2] / 65535.f;
+ dest[3] = 1.0;
+}
+
+static inline void
+convert_rgb16f_to_float (float *dest, const guchar *src_data)
+{
+ guint16 tmp[4];
+ memcpy(tmp, src_data, sizeof(guint16) * 3);
+ tmp[3] = FP16_ONE;
+ half_to_float4 (tmp, dest);
+}
+
+static inline void
+convert_rgba16f_to_float (float *dest, const guchar *src_data)
+{
+ half_to_float4 ((const guint16 *) src_data, dest);
+}
+
+static inline void
+convert_rgb32f_to_float (float *dest, const guchar *src_data)
+{
+ const float *src = (const float *) src_data;
+ dest[0] = src[0];
+ dest[1] = src[1];
+ dest[2] = src[2];
+ dest[3] = 1.0;
+}
+
+static inline void
+convert_rgba32f_to_float (float *dest, const guchar *src_data)
+{
+ const float *src = (const float *) src_data;
+ dest[0] = src[0];
+ dest[1] = src[1];
+ dest[2] = src[2];
+ dest[3] = src[3];
+}
+
+void
+gdk_memory_convert_to_float (float *dest_data,
+ gsize dest_stride,
+ const guchar *src_data,
+ gsize src_stride,
+ GdkMemoryFormat src_format,
+ gsize width,
+ gsize height)
+{
+ gsize x, y;
+
+ switch (src_format)
+ {
+ case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
+ CONVERT_FLOAT (2, 1, 0, 3, FALSE);
+ break;
+ case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
+ CONVERT_FLOAT (1, 2, 3, 0, FALSE);
+ break;
+ case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
+ CONVERT_FLOAT (0, 1, 2, 3, FALSE);
+ break;
+ case GDK_MEMORY_B8G8R8A8:
+ CONVERT_FLOAT (2, 1, 0, 3, TRUE);
+ break;
+ case GDK_MEMORY_A8R8G8B8:
+ CONVERT_FLOAT (1, 2, 3, 0, TRUE);
+ break;
+ case GDK_MEMORY_R8G8B8A8:
+ CONVERT_FLOAT (0, 1, 2, 3, TRUE);
+ break;
+ case GDK_MEMORY_A8B8G8R8:
+ CONVERT_FLOAT (3, 2, 1, 0, TRUE);
+ break;
+ case GDK_MEMORY_R8G8B8:
+ CONVERT_FLOAT (0, 1, 2, -1, FALSE);
+ break;
+ case GDK_MEMORY_B8G8R8:
+ CONVERT_FLOAT (2, 1, 0, -1, FALSE);
+ break;
+ case GDK_MEMORY_R16G16B16:
+ CONVERT_FLOAT_PIXEL (convert_rgb16_to_float, 3 * sizeof (guint16));
+ break;
+ case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
+ CONVERT_FLOAT_PIXEL (convert_rgba16_to_float, 4 * sizeof (guint16));
+ break;
+ case GDK_MEMORY_R16G16B16_FLOAT:
+ CONVERT_FLOAT_PIXEL (convert_rgb16f_to_float, 3 * sizeof (guint16));
+ break;
+ case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
+ CONVERT_FLOAT_PIXEL (convert_rgba16f_to_float, 4 * sizeof (guint16));
+ break;
+ case GDK_MEMORY_R32G32B32_FLOAT:
+ CONVERT_FLOAT_PIXEL (convert_rgb32f_to_float, 3 * sizeof (float));
+ break;
+ case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
+ CONVERT_FLOAT_PIXEL (convert_rgba32f_to_float, 4 * sizeof (float));
+ break;
+
+ case GDK_MEMORY_N_FORMATS:
+ default:
+ g_assert_not_reached();
+ }
+}
diff --git a/gdk/gdkmemorytexture.h b/gdk/gdkmemorytexture.h
index b9f1f21282..114922153e 100644
--- a/gdk/gdkmemorytexture.h
+++ b/gdk/gdkmemorytexture.h
@@ -42,6 +42,20 @@ G_BEGIN_DECLS
* @GDK_MEMORY_A8B8G8R8: 4 bytes; for alpha, blue, green, red.
* @GDK_MEMORY_R8G8B8: 3 bytes; for red, green, blue. The data is opaque.
* @GDK_MEMORY_B8G8R8: 3 bytes; for blue, green, red. The data is opaque.
+ * @GDK_MEMORY_R16G16B16: 3 guint16 values; for red, green, blue. Since 4.6
+ * @GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: 4 guint16 values; for red, green,
+ * blue, alpha. The color values are premultiplied with the alpha value.
+ * Since 4.6
+ * @GDK_MEMORY_R16G16B16_FLOAT: 3 half-float values; for red, green, blue.
+ * The data is opaque. Since 4.6
+ * @GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: 4 half-float values; for
+ * red, green, blue and alpha. The color values are premultiplied with
+ * the alpha value. Since 4.6
+ * @GDK_MEMORY_B32G32R32_FLOAT: 3 float values; for blue, green, red.
+ * The data is opaque. Since 4.6
+ * @GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: 4 float values; for
+ * red, green, blue and alpha. The color values are premultiplied with
+ * the alpha value. Since 4.6
* @GDK_MEMORY_N_FORMATS: The number of formats. This value will change as
* more formats get added, so do not rely on its concrete integer.
*
@@ -67,6 +81,12 @@ typedef enum {
GDK_MEMORY_A8B8G8R8,
GDK_MEMORY_R8G8B8,
GDK_MEMORY_B8G8R8,
+ GDK_MEMORY_R16G16B16,
+ GDK_MEMORY_R16G16B16A16_PREMULTIPLIED,
+ GDK_MEMORY_R16G16B16_FLOAT,
+ GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED,
+ GDK_MEMORY_R32G32B32_FLOAT,
+ GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
GDK_MEMORY_N_FORMATS
} GdkMemoryFormat;
diff --git a/gdk/gdkmemorytextureprivate.h b/gdk/gdkmemorytextureprivate.h
index 740a59da6e..ddd9fd1c37 100644
--- a/gdk/gdkmemorytextureprivate.h
+++ b/gdk/gdkmemorytextureprivate.h
@@ -29,7 +29,21 @@ G_BEGIN_DECLS
#define GDK_MEMORY_GDK_PIXBUF_OPAQUE GDK_MEMORY_R8G8B8
#define GDK_MEMORY_GDK_PIXBUF_ALPHA GDK_MEMORY_R8G8B8A8
-#define GDK_MEMORY_CAIRO_FORMAT_ARGB32 GDK_MEMORY_DEFAULT
+typedef enum {
+ GDK_MEMORY_CONVERT_DOWNLOAD_LITTLE_ENDIAN,
+ GDK_MEMORY_CONVERT_DOWNLOAD_BIT_ENDIAN,
+ GDK_MEMORY_CONVERT_GLES_RGBA,
+
+ GDK_MEMORY_N_CONVERSIONS
+} GdkMemoryConversion;
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define GDK_MEMORY_CONVERT_DOWNLOAD GDK_MEMORY_CONVERT_DOWNLOAD_LITTLE_ENDIAN
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+#define GDK_MEMORY_CONVERT_DOWNLOAD GDK_MEMORY_CONVERT_DOWNLOAD_BIG_ENDIAN
+#else
+#error "Unknown byte order for GDK_MEMORY_CONVERT_DOWNLOAD"
+#endif
gsize gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format);
@@ -37,14 +51,22 @@ GdkMemoryFormat gdk_memory_texture_get_format (GdkMemoryTexture *
const guchar * gdk_memory_texture_get_data (GdkMemoryTexture *self);
gsize gdk_memory_texture_get_stride (GdkMemoryTexture *self);
-void gdk_memory_convert (guchar *dest_data,
- gsize dest_stride,
- GdkMemoryFormat dest_format,
- const guchar *src_data,
- gsize src_stride,
- GdkMemoryFormat src_format,
- gsize width,
- gsize height);
+void gdk_memory_convert (guchar *dest_data,
+ gsize dest_stride,
+ GdkMemoryConversion dest_format,
+ const guchar *src_data,
+ gsize src_stride,
+ GdkMemoryFormat src_format,
+ gsize width,
+ gsize height);
+
+void gdk_memory_convert_to_float (float *dest_data,
+ gsize dest_stride,
+ const guchar *src_data,
+ gsize src_stride,
+ GdkMemoryFormat src_format,
+ gsize width,
+ gsize height);
G_END_DECLS
diff --git a/gdk/gdktexture.c b/gdk/gdktexture.c
index 7ac4f1bb53..7b055238fd 100644
--- a/gdk/gdktexture.c
+++ b/gdk/gdktexture.c
@@ -115,13 +115,35 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GdkTexture, gdk_texture, G_TYPE_OBJECT,
#define GDK_TEXTURE_WARN_NOT_IMPLEMENTED_METHOD(obj,method) \
g_critical ("Texture of type '%s' does not implement GdkTexture::" # method, G_OBJECT_TYPE_NAME (obj))
+static GdkTexture *
+gdk_texture_real_download_texture (GdkTexture *self)
+{
+ GDK_TEXTURE_WARN_NOT_IMPLEMENTED_METHOD (self, download_texture);
+ return NULL;
+}
+
static void
-gdk_texture_real_download (GdkTexture *self,
- const GdkRectangle *area,
- guchar *data,
- gsize stride)
+gdk_texture_real_download (GdkTexture *texture,
+ guchar *data,
+ gsize stride)
{
- GDK_TEXTURE_WARN_NOT_IMPLEMENTED_METHOD (self, download);
+ GdkTexture *memory_texture;
+
+ memory_texture = gdk_texture_download_texture (texture);
+ gdk_texture_download (memory_texture, data, stride);
+ g_object_unref (memory_texture);
+}
+
+static void
+gdk_texture_real_download_float (GdkTexture *self,
+ float *data,
+ gsize stride)
+{
+ GdkTexture *memory_texture;
+
+ memory_texture = gdk_texture_download_texture (self);
+ gdk_texture_download_float (memory_texture, data, stride);
+ g_object_unref (memory_texture);
}
static void
@@ -187,7 +209,9 @@ gdk_texture_class_init (GdkTextureClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ klass->download_texture = gdk_texture_real_download_texture;
klass->download = gdk_texture_real_download;
+ klass->download_float = gdk_texture_real_download_float;
gobject_class->set_property = gdk_texture_set_property;
gobject_class->get_property = gdk_texture_get_property;
@@ -263,7 +287,7 @@ gdk_texture_new_for_surface (cairo_surface_t *surface)
texture = gdk_memory_texture_new (cairo_image_surface_get_width (surface),
cairo_image_surface_get_height (surface),
- GDK_MEMORY_CAIRO_FORMAT_ARGB32,
+ GDK_MEMORY_DEFAULT,
bytes,
cairo_image_surface_get_stride (surface));
@@ -435,20 +459,6 @@ gdk_texture_download_surface (GdkTexture *texture)
return surface;
}
-void
-gdk_texture_download_area (GdkTexture *texture,
- const GdkRectangle *area,
- guchar *data,
- gsize stride)
-{
- g_assert (area->x >= 0);
- g_assert (area->y >= 0);
- g_assert (area->x + area->width <= texture->width);
- g_assert (area->y + area->height <= texture->height);
-
- GDK_TEXTURE_GET_CLASS (texture)->download (texture, area, data, stride);
-}
-
/**
* gdk_texture_download:
* @texture: a `GdkTexture`
@@ -485,10 +495,62 @@ gdk_texture_download (GdkTexture *texture,
g_return_if_fail (data != NULL);
g_return_if_fail (stride >= gdk_texture_get_width (texture) * 4);
- gdk_texture_download_area (texture,
- &(GdkRectangle) { 0, 0, texture->width, texture->height },
- data,
- stride);
+ GDK_TEXTURE_GET_CLASS (texture)->download (texture, data, stride);
+}
+
+/**
+ * gdk_texture_download_float:
+ * @texture: a `GdkTexture`
+ * @data: (array): pointer to enough memory to be filled with the
+ * downloaded data of @texture
+ * @stride: rowstride in elements, will usually be equal to
+ * gdk_texture_get_width() * 4
+ *
+ * Downloads the @texture into local memory in a high dynamic range format.
+ *
+ * This may be an expensive operation, as the actual texture data
+ * may reside on a GPU or on a remote display server and because the data
+ * may need to be upsampled if it was not already available in this
+ * format.
+ *
+ * You may want to use [method@Gdk.Texture.download] instead if you don't
+ * need high dynamic range support.
+ *
+ * The data format of the downloaded data is equivalent to
+ * GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, so every downloaded
+ * pixel requires 16 bytes of memory.
+ *
+ * Note that the caller is responsible to provide sufficiently
+ * aligned memory to access the resulting data directly as floats.
+ *
+ * Since: 4.6
+ */
+void
+gdk_texture_download_float (GdkTexture *texture,
+ float *data,
+ gsize stride)
+{
+ g_return_if_fail (GDK_IS_TEXTURE (texture));
+ g_return_if_fail (data != NULL);
+ g_return_if_fail (stride >= gdk_texture_get_width (texture) * 4);
+
+ GDK_TEXTURE_GET_CLASS (texture)->download_float (texture, data, stride);
+}
+
+GdkTexture *
+gdk_texture_download_texture (GdkTexture *texture)
+{
+ g_return_val_if_fail (GDK_IS_TEXTURE (texture), NULL);
+
+ g_object_ref (texture);
+ while (!GDK_IS_MEMORY_TEXTURE (texture))
+ {
+ GdkTexture *downloaded = GDK_TEXTURE_GET_CLASS (texture)->download_texture (texture);
+ g_object_unref (texture);
+ texture = downloaded;
+ }
+
+ return texture;
}
gboolean
diff --git a/gdk/gdktexture.h b/gdk/gdktexture.h
index f3d0bc9765..9e3b7a93fa 100644
--- a/gdk/gdktexture.h
+++ b/gdk/gdktexture.h
@@ -59,6 +59,10 @@ GDK_AVAILABLE_IN_ALL
void gdk_texture_download (GdkTexture *texture,
guchar *data,
gsize stride);
+GDK_AVAILABLE_IN_4_6
+void gdk_texture_download_float (GdkTexture *texture,
+ float *data,
+ gsize stride);
GDK_AVAILABLE_IN_ALL
gboolean gdk_texture_save_to_png (GdkTexture *texture,
const char *filename);
diff --git a/gdk/gdktextureprivate.h b/gdk/gdktextureprivate.h
index 3e2e9f3a49..29fca0a9ba 100644
--- a/gdk/gdktextureprivate.h
+++ b/gdk/gdktextureprivate.h
@@ -24,10 +24,15 @@ struct _GdkTexture
struct _GdkTextureClass {
GObjectClass parent_class;
+ /* mandatory: Download into a GdkMemoryTexture */
+ GdkTexture * (* download_texture) (GdkTexture *texture);
+ /* optional */
void (* download) (GdkTexture *texture,
- const GdkRectangle *area,
guchar *data,
gsize stride);
+ void (* download_float) (GdkTexture *texture,
+ float *data,
+ gsize stride);
};
gpointer gdk_texture_new (const GdkTextureClass *klass,
@@ -35,10 +40,8 @@ gpointer gdk_texture_new (const GdkTextureClass
int height);
GdkTexture * gdk_texture_new_for_surface (cairo_surface_t *surface);
cairo_surface_t * gdk_texture_download_surface (GdkTexture *texture);
-void gdk_texture_download_area (GdkTexture *texture,
- const GdkRectangle *area,
- guchar *data,
- gsize stride);
+/* NB: GdkMemoryTexture */
+GdkTexture * gdk_texture_download_texture (GdkTexture *texture);
gboolean gdk_texture_set_render_data (GdkTexture *self,
gpointer key,
diff --git a/gsk/ngl/gsknglglyphlibrary.c b/gsk/ngl/gsknglglyphlibrary.c
index 9f269d8643..8ddf1ab265 100644
--- a/gsk/ngl/gsknglglyphlibrary.c
+++ b/gsk/ngl/gsknglglyphlibrary.c
@@ -235,7 +235,7 @@ gsk_ngl_glyph_library_upload_glyph (GskNglGlyphLibrary *self,
pixel_data = free_data = g_malloc (width * height * 4);
gdk_memory_convert (pixel_data,
width * 4,
- GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
+ GDK_MEMORY_CONVERT_GLES_RGBA,
cairo_image_surface_get_data (surface),
width * 4,
GDK_MEMORY_DEFAULT,
diff --git a/gsk/ngl/gskngliconlibrary.c b/gsk/ngl/gskngliconlibrary.c
index 977c201051..ab4d1b4d6f 100644
--- a/gsk/ngl/gskngliconlibrary.c
+++ b/gsk/ngl/gskngliconlibrary.c
@@ -115,7 +115,7 @@ gsk_ngl_icon_library_add (GskNglIconLibrary *self,
{
pixel_data = free_data = g_malloc (width * height * 4);
gdk_memory_convert (pixel_data, width * 4,
- GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
+ GDK_MEMORY_CONVERT_GLES_RGBA,
surface_data, cairo_image_surface_get_stride (surface),
GDK_MEMORY_DEFAULT, width, height);
gl_format = GL_RGBA;
diff --git a/testsuite/gdk/memorytexture.c b/testsuite/gdk/memorytexture.c
index ea24c827e3..021a7ad11b 100644
--- a/testsuite/gdk/memorytexture.c
+++ b/testsuite/gdk/memorytexture.c
@@ -1,57 +1,328 @@
-#include <locale.h>
-#include <gdk/gdk.h>
+#include <gtk/gtk.h>
-/* maximum bytes per pixel */
-#define MAX_BPP 4
+#include "gsk/ngl/gsknglrenderer.h"
+
+#define N 20
+
+static GskRenderer *gl_renderer = NULL;
+
+typedef struct _TextureBuilder TextureBuilder;
typedef enum {
- BLUE,
- GREEN,
- RED,
- TRANSPARENT,
- ALMOST_OPAQUE_REBECCAPURPLE,
- N_COLORS
-} Color;
-
-const char * color_names[N_COLORS] = {
- "blue",
- "green",
- "red",
- "transparent",
- "almost_opaque_rebeccapurple"
-};
+ TEXTURE_METHOD_LOCAL,
+ TEXTURE_METHOD_GL,
+ TEXTURE_METHOD_GL_RELEASED,
-typedef struct _MemoryData {
- gsize bytes_per_pixel;
- guint opaque : 1;
- guchar data[N_COLORS][MAX_BPP];
-} MemoryData;
+ N_TEXTURE_METHODS
+} TextureMethod;
-typedef struct _TestData {
+struct _TextureBuilder
+{
GdkMemoryFormat format;
- Color color;
-} TestData;
-
-#define RGBA(a, b, c, d) { 0x ## a, 0x ## b, 0x ## c, 0x ## d }
-
-static MemoryData tests[GDK_MEMORY_N_FORMATS] = {
- { 4, FALSE, { RGBA(FF,00,00,FF), RGBA(00,FF,00,FF), RGBA(00,00,FF,FF), RGBA(00,00,00,00), RGBA(66,22,44,AA) } },
- { 4, FALSE, { RGBA(FF,00,00,FF), RGBA(FF,00,FF,00), RGBA(FF,FF,00,00), RGBA(00,00,00,00), RGBA(AA,44,22,66) } },
- { 4, FALSE, { RGBA(00,00,FF,FF), RGBA(00,FF,00,FF), RGBA(FF,00,00,FF), RGBA(00,00,00,00), RGBA(44,22,66,AA) } },
- { 4, FALSE, { RGBA(FF,00,00,FF), RGBA(00,FF,00,FF), RGBA(00,00,FF,FF), RGBA(00,00,00,00), RGBA(99,33,66,AA) } },
- { 4, FALSE, { RGBA(FF,00,00,FF), RGBA(FF,00,FF,00), RGBA(FF,FF,00,00), RGBA(00,00,00,00), RGBA(AA,66,33,99) } },
- { 4, FALSE, { RGBA(00,00,FF,FF), RGBA(00,FF,00,FF), RGBA(FF,00,00,FF), RGBA(00,00,00,00), RGBA(66,33,99,AA) } },
- { 4, FALSE, { RGBA(FF,FF,00,00), RGBA(FF,00,FF,00), RGBA(FF,00,00,FF), RGBA(00,00,00,00), RGBA(AA,99,33,66) } },
- { 3, TRUE, { RGBA(00,00,FF,00), RGBA(00,FF,00,00), RGBA(FF,00,00,00), RGBA(00,00,00,00), RGBA(44,22,66,00) } },
- { 3, TRUE, { RGBA(FF,00,00,00), RGBA(00,FF,00,00), RGBA(00,00,FF,00), RGBA(00,00,00,00), RGBA(66,22,44,00) } },
+ int width;
+ int height;
+
+ guchar *pixels;
+ gsize stride;
+ gsize offset;
};
+static gsize
+gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format)
+{
+ switch (format)
+ {
+ case GDK_MEMORY_R8G8B8:
+ case GDK_MEMORY_B8G8R8:
+ return 3;
+
+ case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
+ case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
+ case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
+ case GDK_MEMORY_B8G8R8A8:
+ case GDK_MEMORY_A8R8G8B8:
+ case GDK_MEMORY_R8G8B8A8:
+ case GDK_MEMORY_A8B8G8R8:
+ return 4;
+
+ case GDK_MEMORY_R16G16B16:
+ case GDK_MEMORY_R16G16B16_FLOAT:
+ return 6;
+
+ case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
+ case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
+ return 8;
+
+ case GDK_MEMORY_R32G32B32_FLOAT:
+ return 12;
+
+ case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
+ return 16;
+
+ case GDK_MEMORY_N_FORMATS:
+ default:
+ g_assert_not_reached ();
+ return 4;
+ }
+}
+
+static gboolean
+gdk_memory_format_has_alpha (GdkMemoryFormat format)
+{
+ switch (format)
+ {
+ case GDK_MEMORY_R8G8B8:
+ case GDK_MEMORY_B8G8R8:
+ case GDK_MEMORY_R16G16B16:
+ case GDK_MEMORY_R16G16B16_FLOAT:
+ case GDK_MEMORY_R32G32B32_FLOAT:
+ return FALSE;
+
+ case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
+ case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
+ case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
+ case GDK_MEMORY_B8G8R8A8:
+ case GDK_MEMORY_A8R8G8B8:
+ case GDK_MEMORY_R8G8B8A8:
+ case GDK_MEMORY_A8B8G8R8:
+ case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
+ case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
+ case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
+ return TRUE;
+
+ case GDK_MEMORY_N_FORMATS:
+ default:
+ g_assert_not_reached ();
+ return TRUE;
+ }
+}
+
+static gpointer
+encode (GdkMemoryFormat format,
+ TextureMethod method)
+{
+ return GSIZE_TO_POINTER (method * GDK_MEMORY_N_FORMATS + format);
+}
+
+static void
+decode (gconstpointer data,
+ GdkMemoryFormat *format,
+ TextureMethod *method)
+{
+ gsize value = GPOINTER_TO_SIZE (data);
+
+ *format = value % GDK_MEMORY_N_FORMATS;
+ value /= GDK_MEMORY_N_FORMATS;
+
+ *method = value;
+}
+
+static void
+texture_builder_init (TextureBuilder *builder,
+ GdkMemoryFormat format,
+ int width,
+ int height)
+{
+ gsize extra_stride;
+
+ builder->format = format;
+ builder->width = width;
+ builder->height = height;
+
+ extra_stride = g_test_rand_bit() ? g_test_rand_int_range (0, 16) : 0;
+ builder->offset = g_test_rand_bit() ? g_test_rand_int_range (0, 128) : 0;
+ builder->stride = width * gdk_memory_format_bytes_per_pixel (format) + extra_stride;
+ builder->pixels = g_malloc0 (builder->offset + builder->stride * height);
+}
+
+static GdkTexture *
+texture_builder_finish (TextureBuilder *builder)
+{
+ GBytes *bytes;
+ GdkTexture *texture;
+
+ bytes = g_bytes_new_with_free_func (builder->pixels + builder->offset,
+ builder->height * builder->stride,
+ g_free,
+ builder->pixels);
+ texture = gdk_memory_texture_new (builder->width,
+ builder->height,
+ builder->format,
+ bytes,
+ builder->stride);
+ g_bytes_unref (bytes);
+
+ return texture;
+}
+
+static inline void
+set_pixel_u8 (guchar *data,
+ int r,
+ int g,
+ int b,
+ int a,
+ gboolean premultiply,
+ const GdkRGBA *color)
+{
+ if (a >= 0)
+ data[a] = CLAMP (color->alpha * 256.f, 0.f, 255.f);
+ if (premultiply)
+ {
+ data[r] = CLAMP (color->red * color->alpha * 256.f, 0.f, 255.f);
+ data[g] = CLAMP (color->green * color->alpha * 256.f, 0.f, 255.f);
+ data[b] = CLAMP (color->blue * color->alpha * 256.f, 0.f, 255.f);
+ }
+ else
+ {
+ data[r] = CLAMP (color->red * 256.f, 0.f, 255.f);
+ data[g] = CLAMP (color->green * 256.f, 0.f, 255.f);
+ data[b] = CLAMP (color->blue * 256.f, 0.f, 255.f);
+ }
+}
+
+static inline guint16
+float_to_half (const float x)
+{
+ const guint b = *(guint*)&x+0x00001000; // round-to-nearest-even
+ const guint e = (b&0x7F800000)>>23; // exponent
+ const guint m = b&0x007FFFFF; // mantissa
+ return (b&0x80000000)>>16 | (e>112)*((((e-112)<<10)&0x7C00)|m>>13) | ((e<113)&(e>101))*((((0x007FF000+m)>>(125-e))+1)>>1) | (e>143)*0x7FFF; // sign : normalized : denormalized : saturate
+}
+
+static void
+texture_builder_set_pixel (TextureBuilder *builder,
+ int x,
+ int y,
+ const GdkRGBA *color)
+{
+ guchar *data;
+
+ g_assert_cmpint (x, >=, 0);
+ g_assert_cmpint (x, <, builder->width);
+ g_assert_cmpint (y, >=, 0);
+ g_assert_cmpint (y, <, builder->height);
+
+ data = builder->pixels
+ + builder->offset
+ + y * builder->stride
+ + x * gdk_memory_format_bytes_per_pixel (builder->format);
+
+ switch (builder->format)
+ {
+ case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
+ set_pixel_u8 (data, 2, 1, 0, 3, TRUE, color);
+ break;
+ case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
+ set_pixel_u8 (data, 1, 2, 3, 0, TRUE, color);
+ break;
+ case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
+ set_pixel_u8 (data, 0, 1, 2, 3, TRUE, color);
+ break;
+ case GDK_MEMORY_B8G8R8A8:
+ set_pixel_u8 (data, 2, 1, 0, 3, FALSE, color);
+ break;
+ case GDK_MEMORY_A8R8G8B8:
+ set_pixel_u8 (data, 1, 2, 3, 0, FALSE, color);
+ break;
+ case GDK_MEMORY_R8G8B8A8:
+ set_pixel_u8 (data, 0, 1, 2, 3, FALSE, color);
+ break;
+ case GDK_MEMORY_A8B8G8R8:
+ set_pixel_u8 (data, 3, 2, 1, 0, FALSE, color);
+ break;
+ case GDK_MEMORY_R8G8B8:
+ set_pixel_u8 (data, 0, 1, 2, -1, TRUE, color);
+ break;
+ case GDK_MEMORY_B8G8R8:
+ set_pixel_u8 (data, 2, 1, 0, -1, TRUE, color);
+ break;
+ case GDK_MEMORY_R16G16B16:
+ {
+ guint16 pixels[3] = {
+ CLAMP (color->red * color->alpha * 65536.f, 0, 65535.f),
+ CLAMP (color->green * color->alpha * 65536.f, 0, 65535.f),
+ CLAMP (color->blue * color->alpha * 65536.f, 0, 65535.f),
+ };
+ memcpy (data, pixels, 3 * sizeof (guint16));
+ }
+ break;
+ case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
+ {
+ guint16 pixels[4] = {
+ CLAMP (color->red * color->alpha * 65536.f, 0, 65535.f),
+ CLAMP (color->green * color->alpha * 65536.f, 0, 65535.f),
+ CLAMP (color->blue * color->alpha * 65536.f, 0, 65535.f),
+ CLAMP (color->alpha * 65536.f, 0, 65535.f),
+ };
+ memcpy (data, pixels, 4 * sizeof (guint16));
+ }
+ break;
+ case GDK_MEMORY_R16G16B16_FLOAT:
+ {
+ guint16 pixels[3] = {
+ float_to_half (color->red * color->alpha),
+ float_to_half (color->green * color->alpha),
+ float_to_half (color->blue * color->alpha)
+ };
+ memcpy (data, pixels, 3 * sizeof (guint16));
+ }
+ break;
+ case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
+ {
+ guint16 pixels[4] = {
+ float_to_half (color->red * color->alpha),
+ float_to_half (color->green * color->alpha),
+ float_to_half (color->blue * color->alpha),
+ float_to_half (color->alpha)
+ };
+ memcpy (data, pixels, 4 * sizeof (guint16));
+ }
+ break;
+ case GDK_MEMORY_R32G32B32_FLOAT:
+ {
+ float pixels[3] = {
+ color->red * color->alpha,
+ color->green * color->alpha,
+ color->blue * color->alpha
+ };
+ memcpy (data, pixels, 3 * sizeof (float));
+ }
+ break;
+ case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
+ {
+ float pixels[4] = {
+ color->red * color->alpha,
+ color->green * color->alpha,
+ color->blue * color->alpha,
+ color->alpha
+ };
+ memcpy (data, pixels, 4 * sizeof (float));
+ }
+ break;
+ case GDK_MEMORY_N_FORMATS:
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+static void
+texture_builder_fill (TextureBuilder *builder,
+ const GdkRGBA *color)
+{
+ int x, y;
+
+ for (y = 0; y < builder->height; y++)
+ for (x = 0; x < builder->width; x++)
+ texture_builder_set_pixel (builder, x, y, color);
+}
+
static void
compare_textures (GdkTexture *expected,
GdkTexture *test,
- gboolean ignore_alpha)
+ gboolean has_alpha)
{
- guchar *expected_data, *test_data;
+ guint32 *expected_data, *test_data;
int width, height;
int x, y;
@@ -61,20 +332,64 @@ compare_textures (GdkTexture *expected,
width = gdk_texture_get_width (expected);
height = gdk_texture_get_height (expected);
- expected_data = g_malloc (width * height * 4);
- gdk_texture_download (expected, expected_data, width * 4);
+ expected_data = g_new (guint32, width * height);
+ gdk_texture_download (expected, (guchar *) expected_data, width * 4);
- test_data = g_malloc (width * height * 4);
- gdk_texture_download (test, test_data, width * 4);
+ test_data = g_new (guint32, width * height);
+ gdk_texture_download (test, (guchar *) test_data, width * 4);
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
- if (ignore_alpha)
- g_assert_cmphex (*(guint32 *) &expected_data[y * width + x * 4] & 0xFFFFFF, ==, *(guint32 *) &test_data[y * width + x * 4] & 0xFFFFFF);
+ if (has_alpha)
+ g_assert_cmphex (expected_data[y * width + x], ==, test_data[y * width + x]);
else
- g_assert_cmphex (*(guint32 *) &expected_data[y * width + x * 4], ==, *(guint32 *) &test_data[y * width + x * 4]);
+ g_assert_cmphex (expected_data[y * width + x] | 0xFF000000, ==, test_data[y * width + x]);
+ }
+ }
+
+ g_free (expected_data);
+ g_free (test_data);
+}
+
+static void
+compare_textures_float (GdkTexture *expected,
+ GdkTexture *test,
+ float eps,
+ gboolean has_alpha)
+{
+ static int R = 0;
+ static int G = 1;
+ static int B = 2;
+ static int A = 3;
+ float *expected_data, *test_data;
+ int width, height;
+ int x, y;
+
+ g_assert_cmpint (gdk_texture_get_width (expected), ==, gdk_texture_get_width (test));
+ g_assert_cmpint (gdk_texture_get_height (expected), ==, gdk_texture_get_height (test));
+
+ width = gdk_texture_get_width (expected);
+ height = gdk_texture_get_height (expected);
+
+ expected_data = g_new (float, width * height * 4);
+ gdk_texture_download_float (expected, expected_data, width * 4);
+
+ test_data = g_new (float, width * height * 4);
+ gdk_texture_download_float (test, test_data, width * 4);
+
+ for (y = 0; y < height; y++)
+ {
+ for (x = 0; x < width; x++)
+ {
+ g_assert_cmpfloat_with_epsilon (expected_data[y * width + 4 * x + R], test_data[y * width + 4 * x + R], eps);
+ g_assert_cmpfloat_with_epsilon (expected_data[y * width + 4 * x + G], test_data[y * width + 4 * x + G], eps);
+ g_assert_cmpfloat_with_epsilon (expected_data[y * width + 4 * x + B], test_data[y * width + 4 * x + B], eps);
+ if (has_alpha)
+ g_assert_cmpfloat_with_epsilon (expected_data[y * width + 4 * x + A], test_data[y * width + 4 * x + A], eps);
+ else
+ g_assert_cmpfloat (1.0, ==, test_data[y * width + 4 * x + A]);
}
}
@@ -83,148 +398,232 @@ compare_textures (GdkTexture *expected,
}
static GdkTexture *
+upload_to_gl (GdkTexture *texture)
+{
+ GskRenderNode *node;
+ GdkTexture *result;
+
+ if (gl_renderer == NULL)
+ return texture;
+
+ node = gsk_texture_node_new (texture,
+ &GRAPHENE_RECT_INIT(
+ 0, 0,
+ gdk_texture_get_width (texture),
+ gdk_texture_get_height (texture)
+ ));
+ result = gsk_renderer_render_texture (gl_renderer, node, NULL);
+ gsk_render_node_unref (node);
+ g_object_unref (texture);
+
+ return result;
+}
+
+static GdkTexture *
create_texture (GdkMemoryFormat format,
- Color color,
+ TextureMethod method,
int width,
int height,
- gsize stride)
+ const GdkRGBA *color)
{
+ TextureBuilder builder;
GdkTexture *texture;
- GBytes *bytes;
- guchar *data;
- int x, y;
- data = g_malloc (height * MAX (stride, tests[format].bytes_per_pixel));
- for (y = 0; y < height; y++)
- for (x = 0; x < width; x++)
- {
- memcpy (&data[y * stride + x * tests[format].bytes_per_pixel],
- &tests[format].data[color],
- tests[format].bytes_per_pixel);
- }
+ texture_builder_init (&builder, format, width, height);
+ texture_builder_fill (&builder, color);
- bytes = g_bytes_new_take (data, height * MAX (stride, tests[format].bytes_per_pixel));
- texture = gdk_memory_texture_new (width, height,
- format,
- bytes,
- stride);
- g_bytes_unref (bytes);
+ texture = texture_builder_finish (&builder);
+
+ switch (method)
+ {
+ case TEXTURE_METHOD_LOCAL:
+ break;
+
+ case TEXTURE_METHOD_GL:
+ texture = upload_to_gl (texture);
+ break;
+
+ case TEXTURE_METHOD_GL_RELEASED:
+ texture = upload_to_gl (texture);
+ gdk_gl_texture_release (GDK_GL_TEXTURE (texture));
+ break;
+
+ case N_TEXTURE_METHODS:
+ default:
+ g_assert_not_reached ();
+ break;
+ }
return texture;
}
static void
+create_random_color (GdkRGBA *color)
+{
+ /* Generate colors so that premultiplying will result in values in steps of 1/15th */
+ color->red = g_test_rand_int_range (0, 6) / 5.f;
+ color->green = g_test_rand_int_range (0, 6) / 5.f;
+ color->blue = g_test_rand_int_range (0, 6) / 5.f;
+ color->alpha = g_test_rand_int_range (0, 4) / 3.f;
+}
+
+static void
test_download_1x1 (gconstpointer data)
{
- const TestData *test_data = data;
+ GdkMemoryFormat format;
+ TextureMethod method;
GdkTexture *expected, *test;
+ gsize i;
+
+ decode (data, &format, &method);
- expected = create_texture (GDK_MEMORY_DEFAULT, test_data->color, 1, 1, tests[test_data->format].bytes_per_pixel);
- test = create_texture (test_data->format, test_data->color, 1, 1, tests[test_data->format].bytes_per_pixel);
+ for (i = 0; i < N; i++)
+ {
+ GdkRGBA color;
- compare_textures (expected, test, tests[test_data->format].opaque);
+ create_random_color (&color);
+ expected = create_texture (GDK_MEMORY_DEFAULT, TEXTURE_METHOD_LOCAL, 1, 1, &color);
+ test = create_texture (format, method, 1, 1, &color);
+
+ compare_textures (expected, test, gdk_memory_format_has_alpha (format));
- g_object_unref (expected);
- g_object_unref (test);
+ g_object_unref (expected);
+ g_object_unref (test);
+ }
}
static void
-test_download_1x1_with_stride (gconstpointer data)
+test_download_4x4 (gconstpointer data)
{
- const TestData *test_data = data;
+ GdkMemoryFormat format;
+ TextureMethod method;
GdkTexture *expected, *test;
+ gsize i;
+
+ decode (data, &format, &method);
- expected = create_texture (GDK_MEMORY_DEFAULT, test_data->color, 1, 1, 4);
- test = create_texture (test_data->format, test_data->color, 1, 1, 2 * MAX_BPP);
+ for (i = 0; i < N; i++)
+ {
+ GdkRGBA color;
- compare_textures (expected, test, tests[test_data->format].opaque);
+ create_random_color (&color);
+ expected = create_texture (GDK_MEMORY_DEFAULT, TEXTURE_METHOD_LOCAL, 4, 4, &color);
+ test = create_texture (format, method, 4, 4, &color);
+
+ compare_textures (expected, test, gdk_memory_format_has_alpha (format));
- g_object_unref (expected);
- g_object_unref (test);
+ g_object_unref (expected);
+ g_object_unref (test);
+ }
}
static void
-test_download_4x4 (gconstpointer data)
+test_download_float_1x1 (gconstpointer data)
{
- const TestData *test_data = data;
+ GdkMemoryFormat format;
+ TextureMethod method;
GdkTexture *expected, *test;
+ gsize i;
- expected = create_texture (GDK_MEMORY_DEFAULT, test_data->color, 4, 4, 16);
- test = create_texture (test_data->format, test_data->color, 4, 4, 4 * tests[test_data->format].bytes_per_pixel);
-
- compare_textures (expected, test, tests[test_data->format].opaque);
+ decode (data, &format, &method);
- g_object_unref (expected);
- g_object_unref (test);
+ for (i = 0; i < N; i++)
+ {
+ GdkRGBA color;
+
+ create_random_color (&color);
+ expected = create_texture (GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, TEXTURE_METHOD_LOCAL, 1, 1, &color);
+ test = create_texture (format, method, 1, 1, &color);
+
+ compare_textures_float (expected, test,
+ G_MINFLOAT,
+ gdk_memory_format_has_alpha (format));
+
+ g_object_unref (expected);
+ g_object_unref (test);
+ }
}
static void
-test_download_4x4_with_stride (gconstpointer data)
+test_download_float_4x4 (gconstpointer data)
{
- const TestData *test_data = data;
+ GdkMemoryFormat format;
+ TextureMethod method;
GdkTexture *expected, *test;
+ gsize i;
- expected = create_texture (GDK_MEMORY_DEFAULT, test_data->color, 4, 4, 16);
- test = create_texture (test_data->format, test_data->color, 4, 4, 4 * MAX_BPP);
+ decode (data, &format, &method);
- compare_textures (expected, test, tests[test_data->format].opaque);
+ for (i = 0; i < N; i++)
+ {
+ GdkRGBA color;
+
+ create_random_color (&color);
+ expected = create_texture (GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, TEXTURE_METHOD_LOCAL, 4, 4, &color);
+ test = create_texture (format, method, 4, 4, &color);
+
+ compare_textures_float (expected, test, G_MINFLOAT, gdk_memory_format_has_alpha (format));
- g_object_unref (expected);
- g_object_unref (test);
+ g_object_unref (expected);
+ g_object_unref (test);
+ }
}
-int
-main (int argc, char *argv[])
+
+static void
+add_test (const char *name,
+ GTestDataFunc func)
{
GdkMemoryFormat format;
- Color color;
+ TextureMethod method;
GEnumClass *enum_class;
- (g_test_init) (&argc, &argv, NULL);
-
enum_class = g_type_class_ref (GDK_TYPE_MEMORY_FORMAT);
for (format = 0; format < GDK_MEMORY_N_FORMATS; format++)
{
- for (color = 0; color < N_COLORS; color++)
+ for (method = 0; method < N_TEXTURE_METHODS; method++)
{
- TestData *test_data = g_new (TestData, 1);
- char *test_name = g_strdup_printf ("/memorytexture/download_1x1/%s/%s",
+ const char *method_names[N_TEXTURE_METHODS] = { "local", "gl", "gl-released" };
+ char *test_name = g_strdup_printf ("%s/%s/%s",
+ name,
g_enum_get_value (enum_class, format)->value_nick,
- color_names[color]);
- test_data->format = format;
- test_data->color = color;
- g_test_add_data_func_full (test_name, test_data, test_download_1x1, g_free);
+ method_names[method]);
+ g_test_add_data_func_full (test_name, encode (format, method), test_download_1x1, NULL);
g_free (test_name);
+ }
+ }
+}
- test_data = g_new (TestData, 1);
- test_name = g_strdup_printf ("/memorytexture/download_1x1_with_stride/%s/%s",
- g_enum_get_value (enum_class, format)->value_nick,
- color_names[color]);
- test_data->format = format;
- test_data->color = color;
- g_test_add_data_func_full (test_name, test_data, test_download_1x1_with_stride, g_free);
- g_free (test_name);
+int
+main (int argc, char *argv[])
+{
+ GdkSurface *surface;
+ int result;
- test_data = g_new (TestData, 1);
- test_name = g_strdup_printf ("/memorytexture/download_4x4/%s/%s",
- g_enum_get_value (enum_class, format)->value_nick,
- color_names[color]);
- test_data->format = format;
- test_data->color = color;
- g_test_add_data_func_full (test_name, test_data, test_download_4x4, g_free);
- g_free (test_name);
+ gtk_test_init (&argc, &argv, NULL);
- test_data = g_new (TestData, 1);
- test_name = g_strdup_printf ("/memorytexture/download_4x4_with_stride/%s/%s",
- g_enum_get_value (enum_class, format)->value_nick,
- color_names[color]);
- test_data->format = format;
- test_data->color = color;
- g_test_add_data_func_full (test_name, test_data, test_download_4x4_with_stride, g_free);
- g_free (test_name);
- }
+ add_test ("/memorytexture/download_1x1", test_download_1x1);
+ add_test ("/memorytexture/download_4x4", test_download_4x4);
+ add_test ("/memorytexture/download_float_1x1", test_download_float_1x1);
+ add_test ("/memorytexture/download_float_4x4", test_download_float_4x4);
+
+ surface = gdk_surface_new_toplevel (gdk_display_get_default());
+ gl_renderer = gsk_ngl_renderer_new ();
+ if (!gsk_renderer_realize (gl_renderer, surface, NULL))
+ {
+ g_clear_object (&gl_renderer);
+ g_clear_object (&surface);
+ }
+
+ result = g_test_run ();
+
+ if (gl_renderer)
+ {
+ gsk_renderer_unrealize (gl_renderer);
+ g_clear_object (&gl_renderer);
}
+ g_clear_object (&surface);
- return g_test_run ();
+ return result;
}