diff options
author | Benjamin Otte <otte.benjamin@googlemail.com> | 2021-09-12 12:55:00 +0000 |
---|---|---|
committer | Benjamin Otte <otte.benjamin@googlemail.com> | 2021-09-12 12:55:00 +0000 |
commit | 6bbec8770088bb9fc61cb71ac9b11a61eae36b52 (patch) | |
tree | 32fec9fd73d15665f9f040c1fb3697f81a816f74 | |
parent | b35608a351bbec6b76b9f42ce9c04d6094dae759 (diff) | |
parent | 416763bf2d31edc21608dd20cc6cf125ea3d6563 (diff) | |
download | gtk+-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.h | 2 | ||||
-rw-r--r-- | gdk/gdkgl.c | 8 | ||||
-rw-r--r-- | gdk/gdkglcontext.c | 123 | ||||
-rw-r--r-- | gdk/gdkgltexture.c | 233 | ||||
-rw-r--r-- | gdk/gdkmemorytexture.c | 431 | ||||
-rw-r--r-- | gdk/gdkmemorytexture.h | 20 | ||||
-rw-r--r-- | gdk/gdkmemorytextureprivate.h | 40 | ||||
-rw-r--r-- | gdk/gdktexture.c | 110 | ||||
-rw-r--r-- | gdk/gdktexture.h | 4 | ||||
-rw-r--r-- | gdk/gdktextureprivate.h | 13 | ||||
-rw-r--r-- | gsk/ngl/gsknglglyphlibrary.c | 2 | ||||
-rw-r--r-- | gsk/ngl/gskngliconlibrary.c | 2 | ||||
-rw-r--r-- | testsuite/gdk/memorytexture.c | 667 |
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; } |