From 48781cf7f7b67fe2f769423150b8fecce67a3549 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Wed, 22 Sep 2021 02:01:41 +0200 Subject: [PATCH 01/12] memorytexture: Split out GdkMemoryFormat handling Also, now make gdk_memory_convert() the only conversion functions and allow conversions between any 2 formats by going via a float[4]. This could be optimized via fast-paths, but so far it isn't. --- gdk/gdkglcontext.c | 3 +- gdk/gdkgltexture.c | 1 + gdk/gdkmemoryformat.c | 366 ++++++++++++++++++++++++ gdk/gdkmemoryformatprivate.h | 42 +++ gdk/gdkmemorytexture.c | 518 +--------------------------------- gdk/gdkmemorytextureprivate.h | 35 --- gdk/loaders/gdkpng.c | 1 + gdk/loaders/gdktiff.c | 1 + gdk/meson.build | 1 + gsk/ngl/gsknglcommandqueue.c | 1 + gsk/ngl/gsknglglyphlibrary.c | 4 +- gsk/ngl/gskngliconlibrary.c | 4 +- 12 files changed, 430 insertions(+), 547 deletions(-) create mode 100644 gdk/gdkmemoryformat.c create mode 100644 gdk/gdkmemoryformatprivate.h diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c index 11c3f77dd4..ece50c8cd2 100644 --- a/gdk/gdkglcontext.c +++ b/gdk/gdkglcontext.c @@ -79,6 +79,7 @@ #include "gdkdebug.h" #include "gdkdisplayprivate.h" #include "gdkintl.h" +#include "gdkmemoryformatprivate.h" #include "gdkmemorytextureprivate.h" #include "gdkprofilerprivate.h" @@ -303,7 +304,7 @@ gdk_gl_context_upload_texture (GdkGLContext *context, { copy = g_malloc (width * height * 4); gdk_memory_convert (copy, width * 4, - GDK_MEMORY_CONVERT_GLES_RGBA, + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, data, stride, data_format, width, height); data_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; diff --git a/gdk/gdkgltexture.c b/gdk/gdkgltexture.c index e2e292964d..1a321fa879 100644 --- a/gdk/gdkgltexture.c +++ b/gdk/gdkgltexture.c @@ -21,6 +21,7 @@ #include "gdkgltextureprivate.h" #include "gdkdisplayprivate.h" +#include "gdkmemoryformatprivate.h" #include "gdkmemorytextureprivate.h" #include "gdktextureprivate.h" diff --git a/gdk/gdkmemoryformat.c b/gdk/gdkmemoryformat.c new file mode 100644 index 0000000000..2a4cfa1e92 --- /dev/null +++ b/gdk/gdkmemoryformat.c @@ -0,0 +1,366 @@ +/* + * Copyright © 2021 Benjamin Otte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Authors: Benjamin Otte + */ + +#include "config.h" + +#include "gdkmemoryformatprivate.h" + +#include "gsk/ngl/fp16private.h" + +typedef struct _GdkMemoryFormatDescription GdkMemoryFormatDescription; + +typedef enum { + GDK_MEMORY_ALPHA_PREMULTIPLIED, + GDK_MEMORY_ALPHA_STRAIGHT, + GDK_MEMORY_ALPHA_OPAQUE +} GdkMemoryAlpha; + +#define TYPED_FUNCS(name, T, R, G, B, A, bpp, scale) \ +static void \ +name ## _to_float (float *dest, \ + const guchar *src_data, \ + gsize n) \ +{ \ + for (gsize i = 0; i < n; i++) \ + { \ + T *src = (T *) (src_data + i * bpp); \ + dest[0] = (float) src[R] / scale; \ + dest[1] = (float) src[G] / scale; \ + dest[2] = (float) src[B] / scale; \ + if (A >= 0) dest[3] = (float) src[A] / scale; else dest[3] = 1.0; \ + dest += 4; \ + } \ +} \ +\ +static void \ +name ## _from_float (guchar *dest_data, \ + const float *src, \ + gsize n) \ +{ \ + for (gsize i = 0; i < n; i++) \ + { \ + T *dest = (T *) (dest_data + i * bpp); \ + dest[R] = CLAMP (src[0] * scale + 0.5, 0, scale); \ + dest[G] = CLAMP (src[1] * scale + 0.5, 0, scale); \ + dest[B] = CLAMP (src[2] * scale + 0.5, 0, scale); \ + if (A >= 0) dest[A] = CLAMP (src[3] * scale + 0.5, 0, scale); \ + src += 4; \ + } \ +} + +TYPED_FUNCS (b8g8r8a8_premultiplied, guchar, 2, 1, 0, 3, 4, 255) +TYPED_FUNCS (a8r8g8b8_premultiplied, guchar, 1, 2, 3, 0, 4, 255) +TYPED_FUNCS (r8g8b8a8_premultiplied, guchar, 0, 1, 2, 3, 4, 255) +TYPED_FUNCS (b8g8r8a8, guchar, 2, 1, 0, 3, 4, 255) +TYPED_FUNCS (a8r8g8b8, guchar, 1, 2, 3, 0, 4, 255) +TYPED_FUNCS (r8g8b8a8, guchar, 0, 1, 2, 3, 4, 255) +TYPED_FUNCS (a8b8g8r8, guchar, 3, 2, 1, 0, 4, 255) +TYPED_FUNCS (r8g8b8, guchar, 0, 1, 2, -1, 3, 255) +TYPED_FUNCS (b8g8r8, guchar, 2, 1, 0, -1, 3, 255) +TYPED_FUNCS (r16g16b16, guint16, 0, 1, 2, -1, 6, 65535) +TYPED_FUNCS (r16g16b16a16, guint16, 0, 1, 2, 3, 8, 65535) + +static void +r16g16b16_float_to_float (float *dest, + const guchar *src_data, + gsize n) +{ + guint16 *src = (guint16 *) src_data; + for (gsize i = 0; i < n; i++) + { + half_to_float (src, dest, 3); + dest[3] = 1.0; + dest += 4; + src += 3; + } +} + +static void +r16g16b16_float_from_float (guchar *dest_data, + const float *src, + gsize n) +{ + guint16 *dest = (guint16 *) dest_data; + for (gsize i = 0; i < n; i++) + { + float_to_half (src, dest, 3); + dest += 3; + src += 4; + } +} + +static void +r16g16b16a16_float_to_float (float *dest, + const guchar *src, + gsize n) +{ + half_to_float ((const guint16 *) src, dest, 4 * n); +} + +static void +r16g16b16a16_float_from_float (guchar *dest, + const float *src, + gsize n) +{ + float_to_half (src, (guint16 *) dest, 4 * n); +} + +static void +r32g32b32_float_to_float (float *dest, + const guchar *src_data, + gsize n) +{ + float *src = (float *) src_data; + for (gsize i = 0; i < n; i++) + { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = 1.0; + dest += 4; + src += 3; + } +} + +static void +r32g32b32_float_from_float (guchar *dest_data, + const float *src, + gsize n) +{ + float *dest = (float *) dest_data; + for (gsize i = 0; i < n; i++) + { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest += 3; + src += 4; + } +} + +static void +r32g32b32a32_float_to_float (float *dest, + const guchar *src, + gsize n) +{ + memcpy (dest, src, sizeof (float) * n * 4); +} + +static void +r32g32b32a32_float_from_float (guchar *dest, + const float *src, + gsize n) +{ + memcpy (dest, src, sizeof (float) * n * 4); +} + +struct _GdkMemoryFormatDescription +{ + GdkMemoryAlpha alpha; + gsize bytes_per_pixel; + gsize alignment; + + /* no premultiplication going on here */ + void (* to_float) (float *, const guchar*, gsize); + void (* from_float) (guchar *, const float *, gsize); +}; + +static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { + [GDK_MEMORY_B8G8R8A8_PREMULTIPLIED] = { + GDK_MEMORY_ALPHA_PREMULTIPLIED, + 4, + G_ALIGNOF (guchar), + b8g8r8a8_premultiplied_to_float, + b8g8r8a8_premultiplied_from_float, + }, + [GDK_MEMORY_A8R8G8B8_PREMULTIPLIED] = { + GDK_MEMORY_ALPHA_PREMULTIPLIED, + 4, + G_ALIGNOF (guchar), + a8r8g8b8_premultiplied_to_float, + a8r8g8b8_premultiplied_from_float, + }, + [GDK_MEMORY_R8G8B8A8_PREMULTIPLIED] = { + GDK_MEMORY_ALPHA_PREMULTIPLIED, + 4, + G_ALIGNOF (guchar), + r8g8b8a8_premultiplied_to_float, + r8g8b8a8_premultiplied_from_float, + }, + [GDK_MEMORY_B8G8R8A8] = { + GDK_MEMORY_ALPHA_STRAIGHT, + 4, + G_ALIGNOF (guchar), + b8g8r8a8_to_float, + b8g8r8a8_from_float, + }, + [GDK_MEMORY_A8R8G8B8] = { + GDK_MEMORY_ALPHA_STRAIGHT, + 4, + G_ALIGNOF (guchar), + a8r8g8b8_to_float, + a8r8g8b8_from_float, + }, + [GDK_MEMORY_R8G8B8A8] = { + GDK_MEMORY_ALPHA_STRAIGHT, + 4, + G_ALIGNOF (guchar), + r8g8b8a8_to_float, + r8g8b8a8_from_float, + }, + [GDK_MEMORY_A8B8G8R8] = { + GDK_MEMORY_ALPHA_STRAIGHT, + 4, + G_ALIGNOF (guchar), + a8b8g8r8_to_float, + a8b8g8r8_from_float, + }, + [GDK_MEMORY_R8G8B8] = { + GDK_MEMORY_ALPHA_OPAQUE, + 3, + G_ALIGNOF (guchar), + r8g8b8_to_float, + r8g8b8_from_float, + }, + [GDK_MEMORY_B8G8R8] = { + GDK_MEMORY_ALPHA_OPAQUE, + 3, + G_ALIGNOF (guchar), + b8g8r8_to_float, + b8g8r8_from_float, + }, + [GDK_MEMORY_R16G16B16] = { + GDK_MEMORY_ALPHA_OPAQUE, + 6, + G_ALIGNOF (guint16), + r16g16b16_to_float, + r16g16b16_from_float, + }, + [GDK_MEMORY_R16G16B16A16_PREMULTIPLIED] = { + GDK_MEMORY_ALPHA_PREMULTIPLIED, + 8, + G_ALIGNOF (guint16), + r16g16b16a16_to_float, + r16g16b16a16_from_float, + }, + [GDK_MEMORY_R16G16B16_FLOAT] = { + GDK_MEMORY_ALPHA_OPAQUE, + 6, + G_ALIGNOF (guint16), + r16g16b16_float_to_float, + r16g16b16_float_from_float, + }, + [GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED] = { + GDK_MEMORY_ALPHA_PREMULTIPLIED, + 8, + G_ALIGNOF (guint16), + r16g16b16a16_float_to_float, + r16g16b16a16_float_from_float, + }, + [GDK_MEMORY_R32G32B32_FLOAT] = { + GDK_MEMORY_ALPHA_OPAQUE, + 12, + G_ALIGNOF (float), + r32g32b32_float_to_float, + r32g32b32_float_from_float, + }, + [GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED] = { + GDK_MEMORY_ALPHA_PREMULTIPLIED, + 16, + G_ALIGNOF (float), + r32g32b32a32_float_to_float, + r32g32b32a32_float_from_float, + } +}; + +gsize +gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format) +{ + return memory_formats[format].bytes_per_pixel; +} + +gsize +gdk_memory_format_alignment (GdkMemoryFormat format) +{ + return memory_formats[format].alignment; +} + +static void +premultiply (float *rgba, + gsize n) +{ + for (gsize i = 0; i < n; i++) + { + rgba[0] *= rgba[3]; + rgba[1] *= rgba[3]; + rgba[2] *= rgba[3]; + rgba += 4; + } +} + +static void +unpremultiply (float *rgba, + gsize n) +{ + for (gsize i = 0; i < n; i++) + { + if (rgba[3] > 1/255.0) + { + rgba[0] /= rgba[3]; + rgba[1] /= rgba[3]; + rgba[2] /= rgba[3]; + } + rgba += 4; + } +} + +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) +{ + const GdkMemoryFormatDescription *dest_desc = &memory_formats[dest_format]; + const GdkMemoryFormatDescription *src_desc = &memory_formats[src_format]; + float *tmp; + gsize y; + + g_assert (dest_format < GDK_MEMORY_N_FORMATS); + g_assert (src_format < GDK_MEMORY_N_FORMATS); + + tmp = g_new (float, width * 4); + + for (y = 0; y < height; y++) + { + src_desc->to_float (tmp, src_data, width); + if (src_desc->alpha == GDK_MEMORY_ALPHA_PREMULTIPLIED && dest_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT) + unpremultiply (tmp, width); + else if (src_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT && dest_desc->alpha != GDK_MEMORY_ALPHA_STRAIGHT) + premultiply (tmp, width); + dest_desc->from_float (dest_data, tmp, width); + src_data += src_stride; + dest_data += dest_stride; + } + + g_free (tmp); +} diff --git a/gdk/gdkmemoryformatprivate.h b/gdk/gdkmemoryformatprivate.h new file mode 100644 index 0000000000..0de89f0756 --- /dev/null +++ b/gdk/gdkmemoryformatprivate.h @@ -0,0 +1,42 @@ +/* + * Copyright © 2021 Benjamin Otte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Authors: Benjamin Otte + */ + +#ifndef __GDK_MEMORY_CONVERT_PRIVATE_H__ +#define __GDK_MEMORY_CONVERT_PRIVATE_H__ + +#include "gdkmemorytexture.h" + +G_BEGIN_DECLS + +gsize gdk_memory_format_alignment (GdkMemoryFormat format) G_GNUC_CONST; +gsize gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format) G_GNUC_CONST; + +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); + + +G_END_DECLS + +#endif /* __GDK_MEMORY_CONVERT_PRIVATE_H__ */ diff --git a/gdk/gdkmemorytexture.c b/gdk/gdkmemorytexture.c index 6c08ef531b..33ba90fe5c 100644 --- a/gdk/gdkmemorytexture.c +++ b/gdk/gdkmemorytexture.c @@ -20,6 +20,8 @@ #include "config.h" #include "gdkmemorytextureprivate.h" + +#include "gdkmemoryformatprivate.h" #include "gsk/ngl/fp16private.h" /** @@ -45,80 +47,6 @@ struct _GdkMemoryTextureClass G_DEFINE_TYPE (GdkMemoryTexture, gdk_memory_texture, GDK_TYPE_TEXTURE) -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 gsize -gdk_memory_format_alignment (GdkMemoryFormat format) -{ - switch (format) - { - case GDK_MEMORY_R8G8B8: - case GDK_MEMORY_B8G8R8: - 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 G_ALIGNOF (double); - } -} - static void gdk_memory_texture_dispose (GObject *object) { @@ -143,7 +71,7 @@ gdk_memory_texture_download (GdkTexture *texture, GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (texture); gdk_memory_convert (data, stride, - GDK_MEMORY_CONVERT_DOWNLOAD, + GDK_MEMORY_DEFAULT, (guchar *) g_bytes_get_data (self->bytes, NULL), self->stride, self->format, @@ -158,12 +86,14 @@ gdk_memory_texture_download_float (GdkTexture *texture, { 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)); + gdk_memory_convert ((guchar *) data, + stride * sizeof (float), + GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, + (guchar *) g_bytes_get_data (self->bytes, NULL), + self->stride, + self->format, + gdk_texture_get_width (texture), + gdk_texture_get_height (texture)); } static void @@ -279,429 +209,3 @@ gdk_memory_texture_get_stride (GdkMemoryTexture *self) return self->stride; } -static void -convert_memcpy (guchar *dest_data, - gsize dest_stride, - const guchar *src_data, - gsize src_stride, - gsize width, - gsize height) -{ - gsize y; - - for (y = 0; y < height; y++) - memcpy (dest_data + y * dest_stride, src_data + y * src_stride, 4 * width); -} - -#define SWIZZLE(A,R,G,B) \ -static void \ -convert_swizzle ## A ## R ## G ## B (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++) \ - { \ - dest_data[4 * x + A] = src_data[4 * x + 0]; \ - dest_data[4 * x + R] = src_data[4 * x + 1]; \ - dest_data[4 * x + G] = src_data[4 * x + 2]; \ - dest_data[4 * x + B] = src_data[4 * x + 3]; \ - } \ -\ - dest_data += dest_stride; \ - src_data += src_stride; \ - } \ -} - -SWIZZLE(3,2,1,0) -SWIZZLE(2,1,0,3) -SWIZZLE(3,0,1,2) -SWIZZLE(1,2,3,0) - -#define SWIZZLE_OPAQUE(A,R,G,B) \ -static void \ -convert_swizzle_opaque_## A ## R ## G ## B (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++) \ - { \ - dest_data[4 * x + A] = 0xFF; \ - dest_data[4 * x + R] = src_data[3 * x + 0]; \ - dest_data[4 * x + G] = src_data[3 * x + 1]; \ - dest_data[4 * x + B] = src_data[3 * x + 2]; \ - } \ -\ - dest_data += dest_stride; \ - src_data += src_stride; \ - } \ -} - -SWIZZLE_OPAQUE(3,2,1,0) -SWIZZLE_OPAQUE(3,0,1,2) -SWIZZLE_OPAQUE(0,1,2,3) -SWIZZLE_OPAQUE(0,3,2,1) - -#define PREMULTIPLY(d,c,a) G_STMT_START { guint t = c * a + 0x80; d = ((t >> 8) + t) >> 8; } G_STMT_END -#define SWIZZLE_PREMULTIPLY(A,R,G,B, A2,R2,G2,B2) \ -static void \ -convert_swizzle_premultiply_ ## A ## R ## G ## B ## _ ## A2 ## R2 ## G2 ## B2 \ - (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++) \ - { \ - dest_data[4 * x + A] = src_data[4 * x + A2]; \ - PREMULTIPLY(dest_data[4 * x + R], src_data[4 * x + R2], src_data[4 * x + A2]); \ - PREMULTIPLY(dest_data[4 * x + G], src_data[4 * x + G2], src_data[4 * x + A2]); \ - PREMULTIPLY(dest_data[4 * x + B], src_data[4 * x + B2], src_data[4 * x + A2]); \ - } \ -\ - dest_data += dest_stride; \ - src_data += src_stride; \ - } \ -} - -SWIZZLE_PREMULTIPLY (3,2,1,0, 3,2,1,0) -SWIZZLE_PREMULTIPLY (0,1,2,3, 3,2,1,0) -SWIZZLE_PREMULTIPLY (3,2,1,0, 0,1,2,3) -SWIZZLE_PREMULTIPLY (0,1,2,3, 0,1,2,3) -SWIZZLE_PREMULTIPLY (3,2,1,0, 3,0,1,2) -SWIZZLE_PREMULTIPLY (0,1,2,3, 3,0,1,2) -SWIZZLE_PREMULTIPLY (3,2,1,0, 0,3,2,1) -SWIZZLE_PREMULTIPLY (0,1,2,3, 0,3,2,1) -SWIZZLE_PREMULTIPLY (3,0,1,2, 3,2,1,0) -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, - gsize src_stride, - gsize width, - gsize height); - -static ConversionFunc converters[GDK_MEMORY_N_FORMATS][GDK_MEMORY_N_CONVERSIONS] = -{ - { convert_memcpy, convert_swizzle3210, convert_swizzle2103 }, - { convert_swizzle3210, convert_memcpy, convert_swizzle3012 }, - { convert_swizzle2103, convert_swizzle1230, convert_memcpy }, - { convert_swizzle_premultiply_3210_3210, convert_swizzle_premultiply_0123_3210, convert_swizzle_premultiply_3012_3210, }, - { convert_swizzle_premultiply_3210_0123, convert_swizzle_premultiply_0123_0123, convert_swizzle_premultiply_3012_0123 }, - { 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_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, - 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] = src[3] / 65535.f; -} - -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/gdkmemorytextureprivate.h b/gdk/gdkmemorytextureprivate.h index ddd9fd1c37..f61cccb9ef 100644 --- a/gdk/gdkmemorytextureprivate.h +++ b/gdk/gdkmemorytextureprivate.h @@ -29,45 +29,10 @@ G_BEGIN_DECLS #define GDK_MEMORY_GDK_PIXBUF_OPAQUE GDK_MEMORY_R8G8B8 #define GDK_MEMORY_GDK_PIXBUF_ALPHA GDK_MEMORY_R8G8B8A8 -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); - GdkMemoryFormat gdk_memory_texture_get_format (GdkMemoryTexture *self); 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, - 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/loaders/gdkpng.c b/gdk/loaders/gdkpng.c index 97e6dfffd0..df453fc6a3 100644 --- a/gdk/loaders/gdkpng.c +++ b/gdk/loaders/gdkpng.c @@ -20,6 +20,7 @@ #include "gdkpngprivate.h" #include "gdkintl.h" +#include "gdkmemoryformatprivate.h" #include "gdkmemorytextureprivate.h" #include "gdkprofilerprivate.h" #include "gdktexture.h" diff --git a/gdk/loaders/gdktiff.c b/gdk/loaders/gdktiff.c index d7416391ee..ed1b0e566b 100644 --- a/gdk/loaders/gdktiff.c +++ b/gdk/loaders/gdktiff.c @@ -20,6 +20,7 @@ #include "gdktiffprivate.h" #include "gdkintl.h" +#include "gdkmemoryformatprivate.h" #include "gdkmemorytextureprivate.h" #include "gdkprofilerprivate.h" #include "gdktexture.h" diff --git a/gdk/meson.build b/gdk/meson.build index 06905233f8..0756f7667c 100644 --- a/gdk/meson.build +++ b/gdk/meson.build @@ -30,6 +30,7 @@ gdk_public_sources = files([ 'gdkhsla.c', 'gdkkeys.c', 'gdkkeyuni.c', + 'gdkmemoryformat.c', 'gdkmemorytexture.c', 'gdkmonitor.c', 'gdkpaintable.c', diff --git a/gsk/ngl/gsknglcommandqueue.c b/gsk/ngl/gsknglcommandqueue.c index a5fbf0dc8d..b2a474cf59 100644 --- a/gsk/ngl/gsknglcommandqueue.c +++ b/gsk/ngl/gsknglcommandqueue.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include diff --git a/gsk/ngl/gsknglglyphlibrary.c b/gsk/ngl/gsknglglyphlibrary.c index 33c86cc967..ede4f19105 100644 --- a/gsk/ngl/gsknglglyphlibrary.c +++ b/gsk/ngl/gsknglglyphlibrary.c @@ -21,7 +21,7 @@ #include "config.h" #include -#include +#include #include #include "gsknglcommandqueueprivate.h" @@ -237,7 +237,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_CONVERT_GLES_RGBA, + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, cairo_image_surface_get_data (surface), width * 4, GDK_MEMORY_DEFAULT, diff --git a/gsk/ngl/gskngliconlibrary.c b/gsk/ngl/gskngliconlibrary.c index ab4d1b4d6f..cfc662a9e6 100644 --- a/gsk/ngl/gskngliconlibrary.c +++ b/gsk/ngl/gskngliconlibrary.c @@ -21,7 +21,7 @@ #include "config.h" #include -#include +#include #include #include @@ -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_CONVERT_GLES_RGBA, + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, surface_data, cairo_image_surface_get_stride (surface), GDK_MEMORY_DEFAULT, width, height); gl_format = GL_RGBA; From 149395c306bb13589c60d01024ad65d1bc07e99c Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 25 Sep 2021 04:47:45 +0200 Subject: [PATCH 02/12] gl: Move memory <=> GL format mapping Put it into gdkmemoryformat.c, where all the mapping goes. --- gdk/gdkglcontext.c | 89 ++++++++++-------------------------- gdk/gdkmemoryformat.c | 67 ++++++++++++++++++++++++++- gdk/gdkmemoryformatprivate.h | 5 ++ 3 files changed, 95 insertions(+), 66 deletions(-) diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c index ece50c8cd2..01b26120eb 100644 --- a/gdk/gdkglcontext.c +++ b/gdk/gdkglcontext.c @@ -239,80 +239,39 @@ gdk_gl_context_upload_texture (GdkGLContext *context, { GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context); guchar *copy = NULL; - GLint gl_internalformat; - GLint gl_format; - GLint gl_type; + GLenum gl_internalformat; + GLenum gl_format; + GLenum gl_type; gsize bpp; g_return_if_fail (GDK_IS_GL_CONTEXT (context)); - if (!priv->use_es && data_format == GDK_MEMORY_DEFAULT) /* Cairo surface format */ + if (!gdk_memory_format_gl_format (data_format, + priv->use_es, + &gl_internalformat, + &gl_format, + &gl_type)) { - gl_internalformat = GL_RGBA8; - 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 if (priv->use_es && data_format == GDK_MEMORY_B8G8R8) - { - 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); + copy = g_malloc_n (width * 4, height); gdk_memory_convert (copy, width * 4, GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, - data, stride, data_format, + 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; + data_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; + if (!gdk_memory_format_gl_format (data_format, + priv->use_es, + &gl_internalformat, + &gl_format, + &gl_type)) + { + g_assert_not_reached (); + } + } + else + { + copy = NULL; } bpp = gdk_memory_format_bytes_per_pixel (data_format); diff --git a/gdk/gdkmemoryformat.c b/gdk/gdkmemoryformat.c index 2a4cfa1e92..8b2ba6ae6d 100644 --- a/gdk/gdkmemoryformat.c +++ b/gdk/gdkmemoryformat.c @@ -23,6 +23,8 @@ #include "gsk/ngl/fp16private.h" +#include + typedef struct _GdkMemoryFormatDescription GdkMemoryFormatDescription; typedef enum { @@ -175,17 +177,32 @@ struct _GdkMemoryFormatDescription GdkMemoryAlpha alpha; gsize bytes_per_pixel; gsize alignment; - + gboolean supports_gles; + struct { + guint internal_format; + guint format; + guint type; + } gl; /* no premultiplication going on here */ void (* to_float) (float *, const guchar*, gsize); void (* from_float) (guchar *, const float *, gsize); }; +#if G_BYTE_ORDER == G_LITTLE_ENDIAN +# define GDK_GL_UNSIGNED_BYTE_FLIPPED GL_UNSIGNED_INT_8_8_8_8 +#elif G_BYTE_ORDER == G_BIG_ENDIAN +# define GDK_GL_UNSIGNED_BYTE_FLIPPED GL_UNSIGNED_INT_8_8_8_8_REV +#else +# error "Define the right GL flags here" +#endif + static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { [GDK_MEMORY_B8G8R8A8_PREMULTIPLIED] = { GDK_MEMORY_ALPHA_PREMULTIPLIED, 4, G_ALIGNOF (guchar), + FALSE, + { GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE }, b8g8r8a8_premultiplied_to_float, b8g8r8a8_premultiplied_from_float, }, @@ -193,6 +210,8 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { GDK_MEMORY_ALPHA_PREMULTIPLIED, 4, G_ALIGNOF (guchar), + FALSE, + { GL_RGBA8, GL_BGRA, GDK_GL_UNSIGNED_BYTE_FLIPPED }, a8r8g8b8_premultiplied_to_float, a8r8g8b8_premultiplied_from_float, }, @@ -200,6 +219,8 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { GDK_MEMORY_ALPHA_PREMULTIPLIED, 4, G_ALIGNOF (guchar), + TRUE, + { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }, r8g8b8a8_premultiplied_to_float, r8g8b8a8_premultiplied_from_float, }, @@ -207,6 +228,8 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { GDK_MEMORY_ALPHA_STRAIGHT, 4, G_ALIGNOF (guchar), + FALSE, + { GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE }, b8g8r8a8_to_float, b8g8r8a8_from_float, }, @@ -214,6 +237,8 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { GDK_MEMORY_ALPHA_STRAIGHT, 4, G_ALIGNOF (guchar), + FALSE, + { GL_RGBA8, GL_RGBA, GDK_GL_UNSIGNED_BYTE_FLIPPED }, a8r8g8b8_to_float, a8r8g8b8_from_float, }, @@ -221,6 +246,8 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { GDK_MEMORY_ALPHA_STRAIGHT, 4, G_ALIGNOF (guchar), + TRUE, + { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }, r8g8b8a8_to_float, r8g8b8a8_from_float, }, @@ -228,6 +255,8 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { GDK_MEMORY_ALPHA_STRAIGHT, 4, G_ALIGNOF (guchar), + FALSE, + { GL_RGBA8, GL_BGRA, GDK_GL_UNSIGNED_BYTE_FLIPPED }, a8b8g8r8_to_float, a8b8g8r8_from_float, }, @@ -235,6 +264,8 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { GDK_MEMORY_ALPHA_OPAQUE, 3, G_ALIGNOF (guchar), + TRUE, + { GL_RGBA8, GL_RGB, GL_UNSIGNED_BYTE }, r8g8b8_to_float, r8g8b8_from_float, }, @@ -242,6 +273,8 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { GDK_MEMORY_ALPHA_OPAQUE, 3, G_ALIGNOF (guchar), + FALSE, + { GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE }, b8g8r8_to_float, b8g8r8_from_float, }, @@ -249,6 +282,8 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { GDK_MEMORY_ALPHA_OPAQUE, 6, G_ALIGNOF (guint16), + TRUE, + { GL_RGB16, GL_RGB, GL_UNSIGNED_SHORT }, r16g16b16_to_float, r16g16b16_from_float, }, @@ -256,6 +291,8 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { GDK_MEMORY_ALPHA_PREMULTIPLIED, 8, G_ALIGNOF (guint16), + TRUE, + { GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT }, r16g16b16a16_to_float, r16g16b16a16_from_float, }, @@ -263,6 +300,8 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { GDK_MEMORY_ALPHA_OPAQUE, 6, G_ALIGNOF (guint16), + TRUE, + { GL_RGB16F, GL_RGB, GL_HALF_FLOAT }, r16g16b16_float_to_float, r16g16b16_float_from_float, }, @@ -270,6 +309,8 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { GDK_MEMORY_ALPHA_PREMULTIPLIED, 8, G_ALIGNOF (guint16), + TRUE, + { GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT }, r16g16b16a16_float_to_float, r16g16b16a16_float_from_float, }, @@ -277,6 +318,8 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { GDK_MEMORY_ALPHA_OPAQUE, 12, G_ALIGNOF (float), + TRUE, + { GL_RGB32F, GL_RGB, GL_FLOAT }, r32g32b32_float_to_float, r32g32b32_float_from_float, }, @@ -284,6 +327,8 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { GDK_MEMORY_ALPHA_PREMULTIPLIED, 16, G_ALIGNOF (float), + TRUE, + { GL_RGBA32F, GL_RGBA, GL_FLOAT }, r32g32b32a32_float_to_float, r32g32b32a32_float_from_float, } @@ -301,6 +346,26 @@ gdk_memory_format_alignment (GdkMemoryFormat format) return memory_formats[format].alignment; } +gboolean +gdk_memory_format_gl_format (GdkMemoryFormat format, + gboolean gles, + guint *out_internal_format, + guint *out_format, + guint *out_type) +{ + *out_internal_format = memory_formats[format].gl.internal_format; + *out_format = memory_formats[format].gl.format; + *out_type = memory_formats[format].gl.type; + + if (memory_formats[format].alpha == GDK_MEMORY_ALPHA_STRAIGHT) + return FALSE; + + if (gles && !memory_formats[format].supports_gles) + return FALSE; + + return TRUE; +} + static void premultiply (float *rgba, gsize n) diff --git a/gdk/gdkmemoryformatprivate.h b/gdk/gdkmemoryformatprivate.h index 0de89f0756..8c8e024b23 100644 --- a/gdk/gdkmemoryformatprivate.h +++ b/gdk/gdkmemoryformatprivate.h @@ -26,6 +26,11 @@ G_BEGIN_DECLS gsize gdk_memory_format_alignment (GdkMemoryFormat format) G_GNUC_CONST; gsize gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format) G_GNUC_CONST; +gboolean gdk_memory_format_gl_format (GdkMemoryFormat format, + gboolean gles, + guint *out_internal_format, + guint *out_format, + guint *out_type); void gdk_memory_convert (guchar *dest_data, gsize dest_stride, From afa004fb8b94078ffe570fcdc30801cd4492c73d Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Wed, 6 Oct 2021 17:55:14 +0200 Subject: [PATCH 03/12] memoryformat: Add gdk_memory_format_prefers_high_depth() This is unused so far, but is part of preparations for high depth support in renderers. --- gdk/gdkmemoryformat.c | 36 ++++++++++++++++++++++++++++++++++++ gdk/gdkmemoryformatprivate.h | 1 + 2 files changed, 37 insertions(+) diff --git a/gdk/gdkmemoryformat.c b/gdk/gdkmemoryformat.c index 8b2ba6ae6d..5af2bb8516 100644 --- a/gdk/gdkmemoryformat.c +++ b/gdk/gdkmemoryformat.c @@ -177,6 +177,7 @@ struct _GdkMemoryFormatDescription GdkMemoryAlpha alpha; gsize bytes_per_pixel; gsize alignment; + gboolean prefers_high_depth; gboolean supports_gles; struct { guint internal_format; @@ -202,6 +203,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { 4, G_ALIGNOF (guchar), FALSE, + FALSE, { GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE }, b8g8r8a8_premultiplied_to_float, b8g8r8a8_premultiplied_from_float, @@ -211,6 +213,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { 4, G_ALIGNOF (guchar), FALSE, + FALSE, { GL_RGBA8, GL_BGRA, GDK_GL_UNSIGNED_BYTE_FLIPPED }, a8r8g8b8_premultiplied_to_float, a8r8g8b8_premultiplied_from_float, @@ -219,6 +222,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { GDK_MEMORY_ALPHA_PREMULTIPLIED, 4, G_ALIGNOF (guchar), + FALSE, TRUE, { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }, r8g8b8a8_premultiplied_to_float, @@ -229,6 +233,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { 4, G_ALIGNOF (guchar), FALSE, + FALSE, { GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE }, b8g8r8a8_to_float, b8g8r8a8_from_float, @@ -238,6 +243,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { 4, G_ALIGNOF (guchar), FALSE, + FALSE, { GL_RGBA8, GL_RGBA, GDK_GL_UNSIGNED_BYTE_FLIPPED }, a8r8g8b8_to_float, a8r8g8b8_from_float, @@ -246,6 +252,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { GDK_MEMORY_ALPHA_STRAIGHT, 4, G_ALIGNOF (guchar), + FALSE, TRUE, { GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE }, r8g8b8a8_to_float, @@ -256,6 +263,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { 4, G_ALIGNOF (guchar), FALSE, + FALSE, { GL_RGBA8, GL_BGRA, GDK_GL_UNSIGNED_BYTE_FLIPPED }, a8b8g8r8_to_float, a8b8g8r8_from_float, @@ -264,6 +272,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { GDK_MEMORY_ALPHA_OPAQUE, 3, G_ALIGNOF (guchar), + FALSE, TRUE, { GL_RGBA8, GL_RGB, GL_UNSIGNED_BYTE }, r8g8b8_to_float, @@ -274,6 +283,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { 3, G_ALIGNOF (guchar), FALSE, + FALSE, { GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE }, b8g8r8_to_float, b8g8r8_from_float, @@ -283,6 +293,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { 6, G_ALIGNOF (guint16), TRUE, + TRUE, { GL_RGB16, GL_RGB, GL_UNSIGNED_SHORT }, r16g16b16_to_float, r16g16b16_from_float, @@ -292,6 +303,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { 8, G_ALIGNOF (guint16), TRUE, + TRUE, { GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT }, r16g16b16a16_to_float, r16g16b16a16_from_float, @@ -301,6 +313,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { 6, G_ALIGNOF (guint16), TRUE, + TRUE, { GL_RGB16F, GL_RGB, GL_HALF_FLOAT }, r16g16b16_float_to_float, r16g16b16_float_from_float, @@ -310,6 +323,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { 8, G_ALIGNOF (guint16), TRUE, + TRUE, { GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT }, r16g16b16a16_float_to_float, r16g16b16a16_float_from_float, @@ -319,6 +333,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { 12, G_ALIGNOF (float), TRUE, + TRUE, { GL_RGB32F, GL_RGB, GL_FLOAT }, r32g32b32_float_to_float, r32g32b32_float_from_float, @@ -328,6 +343,7 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = { 16, G_ALIGNOF (float), TRUE, + TRUE, { GL_RGBA32F, GL_RGBA, GL_FLOAT }, r32g32b32a32_float_to_float, r32g32b32a32_float_from_float, @@ -346,6 +362,26 @@ gdk_memory_format_alignment (GdkMemoryFormat format) return memory_formats[format].alignment; } +/* + * gdk_memory_format_prefers_high_depth: + * @format: a memory format + * + * Checks if the given format benefits from being rendered + * in bit depths higher than 8bits per pixel. See + * gsk_render_node_prefers_high_depth() for more information + * on this. + * Usually this is the case when + * gdk_memory_format_bytes_per_pixel() is larger than 4. + * + * Returns: %TRUE if the format benefits from being + * composited in hgiher bit depths. + **/ +gboolean +gdk_memory_format_prefers_high_depth (GdkMemoryFormat format) +{ + return memory_formats[format].prefers_high_depth; +} + gboolean gdk_memory_format_gl_format (GdkMemoryFormat format, gboolean gles, diff --git a/gdk/gdkmemoryformatprivate.h b/gdk/gdkmemoryformatprivate.h index 8c8e024b23..344e47fade 100644 --- a/gdk/gdkmemoryformatprivate.h +++ b/gdk/gdkmemoryformatprivate.h @@ -26,6 +26,7 @@ G_BEGIN_DECLS gsize gdk_memory_format_alignment (GdkMemoryFormat format) G_GNUC_CONST; gsize gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format) G_GNUC_CONST; +gboolean gdk_memory_format_prefers_high_depth(GdkMemoryFormat format) G_GNUC_CONST; gboolean gdk_memory_format_gl_format (GdkMemoryFormat format, gboolean gles, guint *out_internal_format, From dc6e8315245d275451dc2a9372530f2c8f75746e Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Wed, 6 Oct 2021 18:25:30 +0200 Subject: [PATCH 04/12] gdk: hdr => high depth The term "hdr" is so overloaded, we shouldn't use them anywhere, except from maybe describing all of this work in blog posts and other marketing materials. So do renames: * hdr => high_depth * request_hdr => prefers_high_depth This more accurately describes what is going on. --- gdk/broadway/gdkcairocontext-broadway.c | 2 +- gdk/broadway/gdkdrawcontext-broadway.c | 2 +- gdk/gdk.c | 2 +- gdk/gdkdebug.h | 2 +- gdk/gdkdisplay.c | 26 ++++++++++---------- gdk/gdkdisplayprivate.h | 3 ++- gdk/gdkdrawcontext.c | 32 +++++++++++++------------ gdk/gdkdrawcontextprivate.h | 4 ++-- gdk/gdkglcontext.c | 4 ++-- gdk/gdksurface.c | 14 +++++------ gdk/gdkvulkancontext.c | 2 +- gdk/macos/gdkmacoscairocontext.c | 2 +- gdk/macos/gdkmacosglcontext.c | 4 ++-- gdk/wayland/gdkcairocontext-wayland.c | 2 +- gdk/wayland/gdkglcontext-wayland.c | 4 ++-- gdk/win32/gdkcairocontext-win32.c | 2 +- gdk/win32/gdkglcontext-win32-egl.c | 4 ++-- gdk/win32/gdkglcontext-win32-wgl.c | 4 ++-- gdk/win32/gdkvulkancontext-win32.c | 4 ++-- gdk/x11/gdkcairocontext-x11.c | 2 +- gdk/x11/gdkglcontext-egl.c | 4 ++-- 21 files changed, 64 insertions(+), 61 deletions(-) diff --git a/gdk/broadway/gdkcairocontext-broadway.c b/gdk/broadway/gdkcairocontext-broadway.c index 46fdbaf637..c2924bdf29 100644 --- a/gdk/broadway/gdkcairocontext-broadway.c +++ b/gdk/broadway/gdkcairocontext-broadway.c @@ -34,7 +34,7 @@ gdk_broadway_cairo_context_dispose (GObject *object) static void gdk_broadway_cairo_context_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *region) { GdkBroadwayCairoContext *self = GDK_BROADWAY_CAIRO_CONTEXT (draw_context); diff --git a/gdk/broadway/gdkdrawcontext-broadway.c b/gdk/broadway/gdkdrawcontext-broadway.c index 660976bff5..da65aab78a 100644 --- a/gdk/broadway/gdkdrawcontext-broadway.c +++ b/gdk/broadway/gdkdrawcontext-broadway.c @@ -34,7 +34,7 @@ gdk_broadway_draw_context_dispose (GObject *object) static void gdk_broadway_draw_context_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *region) { GdkBroadwayDrawContext *self = GDK_BROADWAY_DRAW_CONTEXT (draw_context); diff --git a/gdk/gdk.c b/gdk/gdk.c index b050c5916b..123b0413ef 100644 --- a/gdk/gdk.c +++ b/gdk/gdk.c @@ -129,7 +129,7 @@ static const GdkDebugKey gdk_debug_keys[] = { { "vulkan-disable", GDK_DEBUG_VULKAN_DISABLE, "Disable Vulkan support" }, { "vulkan-validate", GDK_DEBUG_VULKAN_VALIDATE, "Load the Vulkan validation layer" }, { "default-settings",GDK_DEBUG_DEFAULT_SETTINGS, "Force default values for xsettings", TRUE }, - { "hdr", GDK_DEBUG_HDR, "Use HDR rendering if possible", TRUE }, + { "high-depth", GDK_DEBUG_HIGH_DEPTH, "Use high bit depth rendering if possible", TRUE }, }; diff --git a/gdk/gdkdebug.h b/gdk/gdkdebug.h index 52460a7a82..acd2259440 100644 --- a/gdk/gdkdebug.h +++ b/gdk/gdkdebug.h @@ -50,7 +50,7 @@ typedef enum { GDK_DEBUG_VULKAN_DISABLE = 1 << 21, GDK_DEBUG_VULKAN_VALIDATE = 1 << 22, GDK_DEBUG_DEFAULT_SETTINGS= 1 << 23, - GDK_DEBUG_HDR = 1 << 24, + GDK_DEBUG_HIGH_DEPTH = 1 << 24, } GdkDebugFlags; extern guint _gdk_debug_flags; diff --git a/gdk/gdkdisplay.c b/gdk/gdkdisplay.c index 875cf5c82b..7d36f2e371 100644 --- a/gdk/gdkdisplay.c +++ b/gdk/gdkdisplay.c @@ -93,7 +93,7 @@ struct _GdkDisplayPrivate { #ifdef HAVE_EGL EGLDisplay egl_display; EGLConfig egl_config; - EGLConfig egl_config_hdr; + EGLConfig egl_config_high_depth; #endif guint rgba : 1; @@ -1439,11 +1439,11 @@ gdk_display_get_egl_config (GdkDisplay *self) } gpointer -gdk_display_get_egl_config_hdr (GdkDisplay *self) +gdk_display_get_egl_config_high_depth (GdkDisplay *self) { GdkDisplayPrivate *priv = gdk_display_get_instance_private (self); - return priv->egl_config_hdr; + return priv->egl_config_high_depth; } static EGLDisplay @@ -1721,16 +1721,16 @@ gdk_display_init_egl (GdkDisplay *self, epoxy_has_egl_extension (priv->egl_display, "EGL_EXT_pixel_format_float"); if (self->have_egl_no_config_context) - priv->egl_config_hdr = gdk_display_create_egl_config (self, + priv->egl_config_high_depth = gdk_display_create_egl_config (self, GDK_EGL_CONFIG_HDR, error); - if (priv->egl_config_hdr == NULL) - priv->egl_config_hdr = priv->egl_config; + if (priv->egl_config_high_depth == NULL) + priv->egl_config_high_depth = priv->egl_config; GDK_DISPLAY_NOTE (self, OPENGL, { char *ext = describe_extensions (priv->egl_display); - char *sdr_cfg = describe_egl_config (priv->egl_display, priv->egl_config); - char *hdr_cfg = describe_egl_config (priv->egl_display, priv->egl_config_hdr); + char *std_cfg = describe_egl_config (priv->egl_display, priv->egl_config); + char *hd_cfg = describe_egl_config (priv->egl_display, priv->egl_config_high_depth); g_message ("EGL API version %d.%d found\n" " - Vendor: %s\n" " - Version: %s\n" @@ -1738,15 +1738,15 @@ gdk_display_init_egl (GdkDisplay *self, " - Extensions:\n" "\t%s\n" " - Selected fbconfig: %s\n" - " HDR fbconfig: %s", + " high depth: %s", major, minor, eglQueryString (priv->egl_display, EGL_VENDOR), eglQueryString (priv->egl_display, EGL_VERSION), eglQueryString (priv->egl_display, EGL_CLIENT_APIS), - ext, sdr_cfg, - priv->egl_config_hdr == priv->egl_config ? "none" : hdr_cfg); - g_free (hdr_cfg); - g_free (sdr_cfg); + ext, std_cfg, + priv->egl_config_high_depth == priv->egl_config ? "none" : hd_cfg); + g_free (hd_cfg); + g_free (std_cfg); g_free (ext); }); diff --git a/gdk/gdkdisplayprivate.h b/gdk/gdkdisplayprivate.h index 4cb85b2ea4..cb80ad3f88 100644 --- a/gdk/gdkdisplayprivate.h +++ b/gdk/gdkdisplayprivate.h @@ -226,7 +226,8 @@ gboolean gdk_display_init_egl (GdkDisplay *display GError **error); gpointer gdk_display_get_egl_display (GdkDisplay *display); gpointer gdk_display_get_egl_config (GdkDisplay *display); -gpointer gdk_display_get_egl_config_hdr (GdkDisplay *display); +gpointer gdk_display_get_egl_config_high_depth + (GdkDisplay *display); void gdk_display_set_rgba (GdkDisplay *display, gboolean rgba); diff --git a/gdk/gdkdrawcontext.c b/gdk/gdkdrawcontext.c index b1988c4034..b51e1139dd 100644 --- a/gdk/gdkdrawcontext.c +++ b/gdk/gdkdrawcontext.c @@ -315,28 +315,30 @@ gdk_draw_context_begin_frame (GdkDrawContext *context, } /* - * @request_hdr: %TRUE to request high dynamic range. + * @prefers_high_depth: %TRUE to request a higher bit depth * - * If HDR is requested, GDK will see about providing a rendering target - * that supports high dynamic range. Typically this means a target supporting - * 16bit floating point pixels, but that is not guaranteed. + * If high depth is preferred, GDK will see about providing a rendering target + * that supports higher bit depth than 8 bits per channel. Typically this means + * a target supporting 16bit floating point pixels, but that is not guaranteed. * * This is only a request and if the GDK backend does not support HDR rendering * or does not consider it worthwhile, it may choose to not honor the request. - * It may also choose to provide HDR even if it was not requested. + * It may also choose to provide high depth even if it was not requested. * Typically the steps undertaken by a backend are: - * 1. Check if HDR is supported by this drawing backend. - * 2. Check if the compositor supports HDR. - * 3. Check if the compositor prefers SDR. This is usually the case when the attached - * monitors do not support HDR content or when the system is resource constrained. + * 1. Check if high depth is supported by this drawing backend. + * 2. Check if the compositor supports high depth. + * 3. Check if the compositor prefers regular bit depth. This is usually the case + * when the attached monitors do not support high depth content or when the + * system is resource constrained. * In either of those cases, the context will usually choose to not honor the request. * - * The rendering code must be able to deal with HDR and SDR content, no matter if HDR - * was requested. The request is only a hint and GDK is free to choose. + * The rendering code must be able to deal with content in any bit depth, no matter + * the preference. The prefers_high_depth argument is only a hint and GDK is free + * to choose. */ void gdk_draw_context_begin_frame_full (GdkDrawContext *context, - gboolean request_hdr, + gboolean prefers_high_depth, const cairo_region_t *region) { GdkDrawContextPrivate *priv = gdk_draw_context_get_instance_private (context); @@ -362,13 +364,13 @@ gdk_draw_context_begin_frame_full (GdkDrawContext *context, return; } - if (GDK_DISPLAY_DEBUG_CHECK (priv->display, HDR)) - request_hdr = TRUE; + if (GDK_DISPLAY_DEBUG_CHECK (priv->display, HIGH_DEPTH)) + prefers_high_depth = TRUE; priv->frame_region = cairo_region_copy (region); priv->surface->paint_context = g_object_ref (context); - GDK_DRAW_CONTEXT_GET_CLASS (context)->begin_frame (context, request_hdr, priv->frame_region); + GDK_DRAW_CONTEXT_GET_CLASS (context)->begin_frame (context, prefers_high_depth, priv->frame_region); } #ifdef HAVE_SYSPROF diff --git a/gdk/gdkdrawcontextprivate.h b/gdk/gdkdrawcontextprivate.h index 0171876d9d..4674d25f30 100644 --- a/gdk/gdkdrawcontextprivate.h +++ b/gdk/gdkdrawcontextprivate.h @@ -41,7 +41,7 @@ struct _GdkDrawContextClass GObjectClass parent_class; void (* begin_frame) (GdkDrawContext *context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *update_area); void (* end_frame) (GdkDrawContext *context, cairo_region_t *painted); @@ -51,7 +51,7 @@ struct _GdkDrawContextClass void gdk_draw_context_surface_resized (GdkDrawContext *context); void gdk_draw_context_begin_frame_full (GdkDrawContext *context, - gboolean request_hdr, + gboolean prefers_high_depth, const cairo_region_t *region); G_END_DECLS diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c index 01b26120eb..5ea41cdeec 100644 --- a/gdk/gdkglcontext.c +++ b/gdk/gdkglcontext.c @@ -589,7 +589,7 @@ gdk_gl_context_real_make_current (GdkGLContext *context, static void gdk_gl_context_real_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *region) { GdkGLContext *context = GDK_GL_CONTEXT (draw_context); @@ -602,7 +602,7 @@ gdk_gl_context_real_begin_frame (GdkDrawContext *draw_context, #ifdef HAVE_EGL if (priv->egl_context) - gdk_surface_ensure_egl_surface (surface, request_hdr); + gdk_surface_ensure_egl_surface (surface, prefers_high_depth); #endif damage = GDK_GL_CONTEXT_GET_CLASS (context)->get_damage (context); diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index 13d779a817..40d9c21b8f 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -71,7 +71,7 @@ struct _GdkSurfacePrivate gpointer egl_native_window; #ifdef HAVE_EGL EGLSurface egl_surface; - gboolean egl_surface_hdr; + gboolean egl_surface_high_depth; #endif gpointer widget; @@ -1109,16 +1109,16 @@ gdk_surface_get_egl_surface (GdkSurface *self) void gdk_surface_ensure_egl_surface (GdkSurface *self, - gboolean hdr) + gboolean high_depth) { GdkSurfacePrivate *priv = gdk_surface_get_instance_private (self); GdkDisplay *display = gdk_surface_get_display (self); g_return_if_fail (priv->egl_native_window != NULL); - if (priv->egl_surface_hdr != hdr && + if (priv->egl_surface_high_depth != high_depth && priv->egl_surface != NULL && - gdk_display_get_egl_config_hdr (display) != gdk_display_get_egl_config (display)) + gdk_display_get_egl_config_high_depth (display) != gdk_display_get_egl_config (display)) { eglDestroySurface (gdk_surface_get_display (self), priv->egl_surface); priv->egl_surface = NULL; @@ -1127,11 +1127,11 @@ gdk_surface_ensure_egl_surface (GdkSurface *self, if (priv->egl_surface == NULL) { priv->egl_surface = eglCreateWindowSurface (gdk_display_get_egl_display (display), - hdr ? gdk_display_get_egl_config_hdr (display) - : gdk_display_get_egl_config (display), + high_depth ? gdk_display_get_egl_config_high_depth (display) + : gdk_display_get_egl_config (display), (EGLNativeWindowType) priv->egl_native_window, NULL); - priv->egl_surface_hdr = hdr; + priv->egl_surface_high_depth = high_depth; } #endif } diff --git a/gdk/gdkvulkancontext.c b/gdk/gdkvulkancontext.c index 2466c317b8..20c1860645 100644 --- a/gdk/gdkvulkancontext.c +++ b/gdk/gdkvulkancontext.c @@ -425,7 +425,7 @@ device_supports_incremental_present (VkPhysicalDevice device) static void gdk_vulkan_context_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *region) { GdkVulkanContext *context = GDK_VULKAN_CONTEXT (draw_context); diff --git a/gdk/macos/gdkmacoscairocontext.c b/gdk/macos/gdkmacoscairocontext.c index 7a195ab063..73ba7cffa0 100644 --- a/gdk/macos/gdkmacoscairocontext.c +++ b/gdk/macos/gdkmacoscairocontext.c @@ -82,7 +82,7 @@ _gdk_macos_cairo_context_cairo_create (GdkCairoContext *cairo_context) static void _gdk_macos_cairo_context_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *region) { GdkMacosCairoContext *self = (GdkMacosCairoContext *)draw_context; diff --git a/gdk/macos/gdkmacosglcontext.c b/gdk/macos/gdkmacosglcontext.c index 967648626c..313be91fb9 100644 --- a/gdk/macos/gdkmacosglcontext.c +++ b/gdk/macos/gdkmacosglcontext.c @@ -291,7 +291,7 @@ opaque_region_covers_surface (GdkMacosGLContext *self) static void gdk_macos_gl_context_begin_frame (GdkDrawContext *context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *painted) { GdkMacosGLContext *self = (GdkMacosGLContext *)context; @@ -345,7 +345,7 @@ gdk_macos_gl_context_begin_frame (GdkDrawContext *context, [self->gl_context update]; } - GDK_DRAW_CONTEXT_CLASS (gdk_macos_gl_context_parent_class)->begin_frame (context, request_hdr, painted); + GDK_DRAW_CONTEXT_CLASS (gdk_macos_gl_context_parent_class)->begin_frame (context, prefers_high_depth, painted); if (!self->is_attached) { diff --git a/gdk/wayland/gdkcairocontext-wayland.c b/gdk/wayland/gdkcairocontext-wayland.c index e06eaa1096..e05ea6a7d9 100644 --- a/gdk/wayland/gdkcairocontext-wayland.c +++ b/gdk/wayland/gdkcairocontext-wayland.c @@ -144,7 +144,7 @@ gdk_wayland_cairo_context_create_surface (GdkWaylandCairoContext *self) static void gdk_wayland_cairo_context_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *region) { GdkWaylandCairoContext *self = GDK_WAYLAND_CAIRO_CONTEXT (draw_context); diff --git a/gdk/wayland/gdkglcontext-wayland.c b/gdk/wayland/gdkglcontext-wayland.c index 9fc887367a..d631816286 100644 --- a/gdk/wayland/gdkglcontext-wayland.c +++ b/gdk/wayland/gdkglcontext-wayland.c @@ -47,12 +47,12 @@ G_DEFINE_TYPE (GdkWaylandGLContext, gdk_wayland_gl_context, GDK_TYPE_GL_CONTEXT) static void gdk_wayland_gl_context_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *region) { gdk_wayland_surface_ensure_wl_egl_window (gdk_draw_context_get_surface (draw_context)); - GDK_DRAW_CONTEXT_CLASS (gdk_wayland_gl_context_parent_class)->begin_frame (draw_context, request_hdr, region); + GDK_DRAW_CONTEXT_CLASS (gdk_wayland_gl_context_parent_class)->begin_frame (draw_context, prefers_high_depth, region); glDrawBuffers (1, (GLenum[1]) { GL_BACK }); } diff --git a/gdk/win32/gdkcairocontext-win32.c b/gdk/win32/gdkcairocontext-win32.c index 65aef46b48..480baf7802 100644 --- a/gdk/win32/gdkcairocontext-win32.c +++ b/gdk/win32/gdkcairocontext-win32.c @@ -53,7 +53,7 @@ create_cairo_surface_for_surface (GdkSurface *surface, static void gdk_win32_cairo_context_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *region) { GdkWin32CairoContext *self = GDK_WIN32_CAIRO_CONTEXT (draw_context); diff --git a/gdk/win32/gdkglcontext-win32-egl.c b/gdk/win32/gdkglcontext-win32-egl.c index 8d6bef9e17..1507dd8225 100644 --- a/gdk/win32/gdkglcontext-win32-egl.c +++ b/gdk/win32/gdkglcontext-win32-egl.c @@ -471,12 +471,12 @@ gdk_win32_gl_context_egl_make_current (GdkGLContext *context, static void gdk_win32_gl_context_egl_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *update_area) { gdk_win32_surface_handle_queued_move_resize (draw_context); - GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_egl_parent_class)->begin_frame (draw_context, request_hdr, update_area); + GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_egl_parent_class)->begin_frame (draw_context, prefers_high_depth, update_area); } static void diff --git a/gdk/win32/gdkglcontext-win32-wgl.c b/gdk/win32/gdkglcontext-win32-wgl.c index 9f9bc257a3..ea5f377966 100644 --- a/gdk/win32/gdkglcontext-win32-wgl.c +++ b/gdk/win32/gdkglcontext-win32-wgl.c @@ -118,12 +118,12 @@ gdk_win32_gl_context_wgl_end_frame (GdkDrawContext *draw_context, static void gdk_win32_gl_context_wgl_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *update_area) { gdk_win32_surface_handle_queued_move_resize (draw_context); - GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_wgl_parent_class)->begin_frame (draw_context, request_hdr, update_area); + GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_wgl_parent_class)->begin_frame (draw_context, prefers_high_depth, update_area); } static int diff --git a/gdk/win32/gdkvulkancontext-win32.c b/gdk/win32/gdkvulkancontext-win32.c index d82cb15d27..894bbfa548 100644 --- a/gdk/win32/gdkvulkancontext-win32.c +++ b/gdk/win32/gdkvulkancontext-win32.c @@ -68,12 +68,12 @@ gdk_win32_vulkan_context_create_surface (GdkVulkanContext *context, static void gdk_win32_vulkan_context_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *update_area) { gdk_win32_surface_handle_queued_move_resize (draw_context); - GDK_DRAW_CONTEXT_CLASS (gdk_win32_vulkan_context_parent_class)->begin_frame (draw_context, request_hdr, update_area); + GDK_DRAW_CONTEXT_CLASS (gdk_win32_vulkan_context_parent_class)->begin_frame (draw_context, prefers_high_depth, update_area); } static void diff --git a/gdk/x11/gdkcairocontext-x11.c b/gdk/x11/gdkcairocontext-x11.c index e6accbb6ad..e25ec197a7 100644 --- a/gdk/x11/gdkcairocontext-x11.c +++ b/gdk/x11/gdkcairocontext-x11.c @@ -55,7 +55,7 @@ create_cairo_surface_for_surface (GdkSurface *surface) static void gdk_x11_cairo_context_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *region) { GdkX11CairoContext *self = GDK_X11_CAIRO_CONTEXT (draw_context); diff --git a/gdk/x11/gdkglcontext-egl.c b/gdk/x11/gdkglcontext-egl.c index 39255ac881..67d730fcfb 100644 --- a/gdk/x11/gdkglcontext-egl.c +++ b/gdk/x11/gdkglcontext-egl.c @@ -61,10 +61,10 @@ gdk_x11_display_get_egl_display (GdkDisplay *display) static void gdk_x11_gl_context_egl_begin_frame (GdkDrawContext *draw_context, - gboolean request_hdr, + gboolean prefers_high_depth, cairo_region_t *region) { - GDK_DRAW_CONTEXT_CLASS (gdk_x11_gl_context_egl_parent_class)->begin_frame (draw_context, request_hdr, region); + GDK_DRAW_CONTEXT_CLASS (gdk_x11_gl_context_egl_parent_class)->begin_frame (draw_context, prefers_high_depth, region); glDrawBuffers (1, (GLenum[1]) { GL_BACK }); } From 3f4fb93379618626485dac32d15eb389a6b2c10e Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Wed, 6 Oct 2021 22:17:11 +0200 Subject: [PATCH 05/12] cairo: Use GdkTexture for converting from pixbuf --- gdk/gdkcairo.c | 76 ++++---------------------------------------------- 1 file changed, 6 insertions(+), 70 deletions(-) diff --git a/gdk/gdkcairo.c b/gdk/gdkcairo.c index ef8f5d2fb5..d69b9bc602 100644 --- a/gdk/gdkcairo.c +++ b/gdk/gdkcairo.c @@ -91,11 +91,7 @@ void gdk_cairo_surface_paint_pixbuf (cairo_surface_t *surface, const GdkPixbuf *pixbuf) { - int width, height; - guchar *gdk_pixels, *cairo_pixels; - int gdk_rowstride, cairo_stride; - int n_channels; - int j; + GdkTexture *texture; if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) return; @@ -111,71 +107,11 @@ gdk_cairo_surface_paint_pixbuf (cairo_surface_t *surface, cairo_surface_flush (surface); - width = gdk_pixbuf_get_width (pixbuf); - height = gdk_pixbuf_get_height (pixbuf); - gdk_pixels = gdk_pixbuf_get_pixels (pixbuf); - gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf); - n_channels = gdk_pixbuf_get_n_channels (pixbuf); - cairo_stride = cairo_image_surface_get_stride (surface); - cairo_pixels = cairo_image_surface_get_data (surface); - - for (j = height; j; j--) - { - guchar *p = gdk_pixels; - guchar *q = cairo_pixels; - - if (n_channels == 3) - { - guchar *end = p + 3 * width; - - while (p < end) - { -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - q[0] = p[2]; - q[1] = p[1]; - q[2] = p[0]; - q[3] = 0xFF; -#else - q[0] = 0xFF; - q[1] = p[0]; - q[2] = p[1]; - q[3] = p[2]; -#endif - p += 3; - q += 4; - } - } - else - { - guchar *end = p + 4 * width; - guint t1,t2,t3; - -#define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x80; d = ((t >> 8) + t) >> 8; } G_STMT_END - - while (p < end) - { -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - MULT(q[0], p[2], p[3], t1); - MULT(q[1], p[1], p[3], t2); - MULT(q[2], p[0], p[3], t3); - q[3] = p[3]; -#else - q[0] = p[3]; - MULT(q[1], p[0], p[3], t1); - MULT(q[2], p[1], p[3], t2); - MULT(q[3], p[2], p[3], t3); -#endif - - p += 4; - q += 4; - } - -#undef MULT - } - - gdk_pixels += gdk_rowstride; - cairo_pixels += cairo_stride; - } + texture = gdk_texture_new_for_pixbuf (GDK_PIXBUF (pixbuf)); + gdk_texture_download (texture, + cairo_image_surface_get_data (surface), + cairo_image_surface_get_stride (surface)); + g_object_unref (texture); cairo_surface_mark_dirty (surface); } From 2e555db9a4210480360cde2770981daf22a74619 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Wed, 6 Oct 2021 22:17:33 +0200 Subject: [PATCH 06/12] testsuite: Fail more accurately Don't run the full test and then return "something failed" - instead just explode when you find the failure. --- testsuite/gdk/texture.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/testsuite/gdk/texture.c b/testsuite/gdk/texture.c index fc1f728c7c..1a218ddd4a 100644 --- a/testsuite/gdk/texture.c +++ b/testsuite/gdk/texture.c @@ -1,6 +1,6 @@ #include -static gboolean +static void compare_pixels (int width, int height, guchar *data1, @@ -8,15 +8,17 @@ compare_pixels (int width, guchar *data2, gsize stride2) { - int i; - for (i = 0; i < height; i++) + int x, y; + for (y = 0; y < height; y++) { - gconstpointer p1 = data1 + i * stride1; - gconstpointer p2 = data2 + i * stride2; - if (memcmp (p1, p2, width * 4) != 0) - return FALSE; + const guint32 *p1 = (const guint32*) (data1 + y * stride1); + const guint32 *p2 = (const guint32*) (data2 + y * stride2); + + for (x = 0; x < width; x++) + { + g_assert_cmphex (p1[x], ==, p2[x]); + } } - return TRUE; } static void @@ -55,10 +57,10 @@ test_texture_from_pixbuf (void) cairo_paint (cr); cairo_destroy (cr); - g_assert_true (compare_pixels (width, height, - data, stride, - cairo_image_surface_get_data (surface), - cairo_image_surface_get_stride (surface))); + compare_pixels (width, height, + data, stride, + cairo_image_surface_get_data (surface), + cairo_image_surface_get_stride (surface)); g_free (data); From 8950c0dc960da50e7e38bcb5984b74286a9f178c Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Thu, 7 Oct 2021 02:41:30 +0200 Subject: [PATCH 07/12] texture: Make format a property of GdkTexture For MemoryTexture, this is a simple change. For GLTexture, we need to query the format at texture creation. This sounds like a bad idea and extra work until one realizes that we'd need to do that anyway when using the texure the first time - either when downloading, or when trying to use it in a rendernode, where we will soon need that information to determine if the texture prefers high depth. --- gdk/gdkgltexture.c | 133 +++++++++++++++++----------------- gdk/gdkmemorytexture.c | 14 +--- gdk/gdkmemorytextureprivate.h | 1 - gdk/gdktexture.c | 7 +- gdk/gdktextureprivate.h | 4 + gdk/loaders/gdkpng.c | 2 +- gdk/loaders/gdktiff.c | 2 +- gsk/ngl/gsknglcommandqueue.c | 2 +- 8 files changed, 83 insertions(+), 82 deletions(-) diff --git a/gdk/gdkgltexture.c b/gdk/gdkgltexture.c index 1a321fa879..e39fcd3fbb 100644 --- a/gdk/gdkgltexture.c +++ b/gdk/gdkgltexture.c @@ -140,82 +140,29 @@ gdk_gl_texture_get_tex_image (GdkGLTexture *self, data); } } + static void gdk_gl_texture_do_download_texture (gpointer texture_, gpointer result_) { GdkTexture *texture = texture_; GdkTexture **result = result_; - GdkMemoryFormat format; - GLint internal_format, gl_format, gl_type; + guint gl_internalformat, gl_format, gl_type; guchar *data; gsize stride; GBytes *bytes; - glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format); + if (!gdk_memory_format_gl_format (texture->format, + gdk_gl_context_get_use_es (gdk_gl_context_get_current ()), + &gl_internalformat, + &gl_format, + &gl_type)) + { + g_assert_not_reached (); + } - 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); + stride = gdk_memory_format_bytes_per_pixel (texture->format) * texture->width; + data = g_malloc_n (stride, texture->height); gdk_gl_texture_get_tex_image (texture_, gl_format, @@ -225,7 +172,7 @@ gdk_gl_texture_do_download_texture (gpointer texture_, bytes = g_bytes_new_take (data, stride * texture->height); *result = gdk_memory_texture_new (texture->width, texture->height, - format, + texture->format, bytes, stride); @@ -378,6 +325,58 @@ gdk_gl_texture_release (GdkGLTexture *self) self->id = 0; } +static void +gdk_gl_texture_do_determine_format (gpointer texture_, + gpointer unused) +{ + GdkTexture *texture = texture_; + GLint internal_format; + + glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format); + + switch (internal_format) + { + case GL_RGB8: + texture->format = GDK_MEMORY_R8G8B8; + break; + + case GL_RGBA8: + texture->format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; + break; + + case GL_RGB16: + texture->format = GDK_MEMORY_R16G16B16; + break; + + case GL_RGBA16: + texture->format = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED; + break; + + case GL_RGB16F: + texture->format = GDK_MEMORY_R16G16B16_FLOAT; + break; + + case GL_RGBA16F: + texture->format = GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED; + break; + + case GL_RGB32F: + texture->format = GDK_MEMORY_R32G32B32_FLOAT; + break; + + case GL_RGBA32F: + texture->format = GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED; + 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 */ + texture->format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; + break; + } +} + /** * gdk_gl_texture_new: * @context: a `GdkGLContext` @@ -421,6 +420,8 @@ gdk_gl_texture_new (GdkGLContext *context, self->destroy = destroy; self->data = data; + gdk_gl_texture_run (self, gdk_gl_texture_do_determine_format, NULL); + return GDK_TEXTURE (self); } diff --git a/gdk/gdkmemorytexture.c b/gdk/gdkmemorytexture.c index 33ba90fe5c..52723ef805 100644 --- a/gdk/gdkmemorytexture.c +++ b/gdk/gdkmemorytexture.c @@ -34,8 +34,6 @@ struct _GdkMemoryTexture { GdkTexture parent_instance; - GdkMemoryFormat format; - GBytes *bytes; gsize stride; }; @@ -74,7 +72,7 @@ gdk_memory_texture_download (GdkTexture *texture, GDK_MEMORY_DEFAULT, (guchar *) g_bytes_get_data (self->bytes, NULL), self->stride, - self->format, + texture->format, gdk_texture_get_width (texture), gdk_texture_get_height (texture)); } @@ -91,7 +89,7 @@ gdk_memory_texture_download_float (GdkTexture *texture, GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, (guchar *) g_bytes_get_data (self->bytes, NULL), self->stride, - self->format, + texture->format, gdk_texture_get_width (texture), gdk_texture_get_height (texture)); } @@ -184,19 +182,13 @@ gdk_memory_texture_new (int width, "height", height, NULL); - self->format = format; + GDK_TEXTURE (self)->format = format; self->bytes = bytes; self->stride = stride; return GDK_TEXTURE (self); } -GdkMemoryFormat -gdk_memory_texture_get_format (GdkMemoryTexture *self) -{ - return self->format; -} - const guchar * gdk_memory_texture_get_data (GdkMemoryTexture *self) { diff --git a/gdk/gdkmemorytextureprivate.h b/gdk/gdkmemorytextureprivate.h index f61cccb9ef..0cd5e91f27 100644 --- a/gdk/gdkmemorytextureprivate.h +++ b/gdk/gdkmemorytextureprivate.h @@ -29,7 +29,6 @@ G_BEGIN_DECLS #define GDK_MEMORY_GDK_PIXBUF_OPAQUE GDK_MEMORY_R8G8B8 #define GDK_MEMORY_GDK_PIXBUF_ALPHA GDK_MEMORY_R8G8B8A8 -GdkMemoryFormat gdk_memory_texture_get_format (GdkMemoryTexture *self); const guchar * gdk_memory_texture_get_data (GdkMemoryTexture *self); gsize gdk_memory_texture_get_stride (GdkMemoryTexture *self); diff --git a/gdk/gdktexture.c b/gdk/gdktexture.c index b79b671a53..f4c5928c8d 100644 --- a/gdk/gdktexture.c +++ b/gdk/gdktexture.c @@ -808,6 +808,12 @@ gdk_texture_download_texture (GdkTexture *texture) return texture; } +GdkMemoryFormat +gdk_texture_get_format (GdkTexture *self) +{ + return self->format; +} + gboolean gdk_texture_set_render_data (GdkTexture *self, gpointer key, @@ -972,4 +978,3 @@ gdk_texture_save_to_tiff_bytes (GdkTexture *texture) return gdk_save_tiff (texture); } - diff --git a/gdk/gdktextureprivate.h b/gdk/gdktextureprivate.h index 814ed5d92c..994c9901f8 100644 --- a/gdk/gdktextureprivate.h +++ b/gdk/gdktextureprivate.h @@ -3,6 +3,8 @@ #include "gdktexture.h" +#include "gdkmemorytexture.h" + G_BEGIN_DECLS #define GDK_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_TEXTURE, GdkTextureClass)) @@ -13,6 +15,7 @@ struct _GdkTexture { GObject parent_instance; + GdkMemoryFormat format; int width; int height; @@ -42,6 +45,7 @@ cairo_surface_t * gdk_texture_download_surface (GdkTexture /* NB: GdkMemoryTexture */ GdkTexture * gdk_texture_download_texture (GdkTexture *texture); +GdkMemoryFormat gdk_texture_get_format (GdkTexture *self); gboolean gdk_texture_set_render_data (GdkTexture *self, gpointer key, gpointer data, diff --git a/gdk/loaders/gdkpng.c b/gdk/loaders/gdkpng.c index df453fc6a3..9bdc5e3a43 100644 --- a/gdk/loaders/gdkpng.c +++ b/gdk/loaders/gdkpng.c @@ -481,7 +481,7 @@ gdk_save_png (GdkTexture *texture) height = gdk_texture_get_height (texture); mtexture = gdk_texture_download_texture (texture); - format = gdk_memory_texture_get_format (GDK_MEMORY_TEXTURE (mtexture)); + format = gdk_texture_get_format (mtexture); switch (format) { diff --git a/gdk/loaders/gdktiff.c b/gdk/loaders/gdktiff.c index ed1b0e566b..d2d8dfdbde 100644 --- a/gdk/loaders/gdktiff.c +++ b/gdk/loaders/gdktiff.c @@ -284,7 +284,7 @@ gdk_save_tiff (GdkTexture *texture) height = gdk_texture_get_height (texture); memory_texture = gdk_texture_download_texture (texture); - format = gdk_memory_texture_get_format (GDK_MEMORY_TEXTURE (memory_texture)); + format = gdk_texture_get_format (memory_texture); for (int i = 0; i < G_N_ELEMENTS (format_data); i++) { diff --git a/gsk/ngl/gsknglcommandqueue.c b/gsk/ngl/gsknglcommandqueue.c index b2a474cf59..29cbb551d0 100644 --- a/gsk/ngl/gsknglcommandqueue.c +++ b/gsk/ngl/gsknglcommandqueue.c @@ -1362,7 +1362,7 @@ gsk_ngl_command_queue_upload_texture (GskNglCommandQueue *self, { GdkMemoryTexture *memory_texture = GDK_MEMORY_TEXTURE (texture); data = gdk_memory_texture_get_data (memory_texture); - data_format = gdk_memory_texture_get_format (memory_texture); + data_format = gdk_texture_get_format (texture); data_stride = gdk_memory_texture_get_stride (memory_texture); } else From 2a08641f595f9e199f6d8cc5f58f34cb3080c322 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 1 Oct 2021 16:23:12 -0400 Subject: [PATCH 08/12] gsk: Add high depth rendernode api Add private api to find out if the content of a render node should be considered 'deep'. The information is collected at creation time, so there is no tree-walking involved when we are using this information in the renderer. Currently, this comes down to whether there are any texture nodes with high depth textures in the subtree. In the future, we may want to allow marking gradient nodes in this way as well. --- gsk/gskrendernode.c | 5 +++++ gsk/gskrendernodeimpl.c | 32 +++++++++++++++++++++++++++++++- gsk/gskrendernodeprivate.h | 3 +++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/gsk/gskrendernode.c b/gsk/gskrendernode.c index 9c4332fe01..6381d334d8 100644 --- a/gsk/gskrendernode.c +++ b/gsk/gskrendernode.c @@ -725,3 +725,8 @@ gsk_value_dup_render_node (const GValue *value) return gsk_render_node_ref (value->data[0].v_pointer); } +gboolean +gsk_render_node_prefers_high_depth (const GskRenderNode *node) +{ + return node->prefers_high_depth; +} diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index fd2a9e5d44..28cb14ae64 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -28,6 +28,7 @@ #include "gsktransformprivate.h" #include "gdk/gdktextureprivate.h" +#include "gdk/gdkmemoryformatprivate.h" #include "gdk/gdk-private.h" #include @@ -1560,6 +1561,8 @@ gsk_texture_node_new (GdkTexture *texture, self->texture = g_object_ref (texture); graphene_rect_init_from_rect (&node->bounds, bounds); + node->prefers_high_depth = gdk_memory_format_prefers_high_depth (gdk_texture_get_format (texture)); + return node; } @@ -2730,11 +2733,13 @@ gsk_container_node_new (GskRenderNode **children, self->children[0] = gsk_render_node_ref (children[0]); graphene_rect_init_from_rect (&bounds, &(children[0]->bounds)); + node->prefers_high_depth = gsk_render_node_prefers_high_depth (children[0]); for (guint i = 1; i < n_children; i++) { self->children[i] = gsk_render_node_ref (children[i]); graphene_rect_union (&bounds, &(children[i]->bounds), &bounds); + node->prefers_high_depth |= gsk_render_node_prefers_high_depth (children[i]); } graphene_rect_init_from_rect (&node->bounds, &bounds); @@ -2965,6 +2970,8 @@ gsk_transform_node_new (GskRenderNode *child, &child->bounds, &node->bounds); + node->prefers_high_depth = gsk_render_node_prefers_high_depth (child); + return node; } @@ -3100,6 +3107,8 @@ gsk_opacity_node_new (GskRenderNode *child, graphene_rect_init_from_rect (&node->bounds, &child->bounds); + node->prefers_high_depth = gsk_render_node_prefers_high_depth (child); + return node; } @@ -3302,6 +3311,8 @@ gsk_color_matrix_node_new (GskRenderNode *child, graphene_rect_init_from_rect (&node->bounds, &child->bounds); + node->prefers_high_depth = gsk_render_node_prefers_high_depth (child); + return node; } @@ -3451,6 +3462,8 @@ gsk_repeat_node_new (const graphene_rect_t *bounds, else graphene_rect_init_from_rect (&self->child_bounds, &child->bounds); + node->prefers_high_depth = gsk_render_node_prefers_high_depth (child); + return node; } @@ -3582,6 +3595,8 @@ gsk_clip_node_new (GskRenderNode *child, graphene_rect_intersection (&self->clip, &child->bounds, &node->bounds); + node->prefers_high_depth = gsk_render_node_prefers_high_depth (child); + return node; } @@ -3713,6 +3728,8 @@ gsk_rounded_clip_node_new (GskRenderNode *child, graphene_rect_intersection (&self->clip.bounds, &child->bounds, &node->bounds); + node->prefers_high_depth = gsk_render_node_prefers_high_depth (child); + return node; } @@ -3932,6 +3949,8 @@ gsk_shadow_node_new (GskRenderNode *child, gsk_shadow_node_get_bounds (self, &node->bounds); + node->prefers_high_depth = gsk_render_node_prefers_high_depth (child); + return node; } @@ -4125,6 +4144,8 @@ gsk_blend_node_new (GskRenderNode *bottom, graphene_rect_union (&bottom->bounds, &top->bounds, &node->bounds); + node->prefers_high_depth = gsk_render_node_prefers_high_depth (bottom) || gsk_render_node_prefers_high_depth (top); + return node; } @@ -4273,6 +4294,8 @@ gsk_cross_fade_node_new (GskRenderNode *start, graphene_rect_union (&start->bounds, &end->bounds, &node->bounds); + node->prefers_high_depth = gsk_render_node_prefers_high_depth (start) || gsk_render_node_prefers_high_depth (end); + return node; } @@ -4864,6 +4887,8 @@ gsk_blur_node_new (GskRenderNode *child, - clip_radius, - clip_radius); + node->prefers_high_depth = gsk_render_node_prefers_high_depth (child); + return node; } @@ -4986,6 +5011,8 @@ gsk_debug_node_new (GskRenderNode *child, graphene_rect_init_from_rect (&node->bounds, &child->bounds); + node->prefers_high_depth = gsk_render_node_prefers_high_depth (child); + return node; } @@ -5150,7 +5177,10 @@ gsk_gl_shader_node_new (GskGLShader *shader, { self->children = g_malloc_n (n_children, sizeof (GskRenderNode *)); for (guint i = 0; i < n_children; i++) - self->children[i] = gsk_render_node_ref (children[i]); + { + self->children[i] = gsk_render_node_ref (children[i]); + node->prefers_high_depth |= gsk_render_node_prefers_high_depth (children[i]); + } } return node; diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h index ac20813b65..cdb75afd2f 100644 --- a/gsk/gskrendernodeprivate.h +++ b/gsk/gskrendernodeprivate.h @@ -27,6 +27,8 @@ struct _GskRenderNode gatomicrefcount ref_count; graphene_rect_t bounds; + + guint prefers_high_depth : 1; }; struct _GskRenderNodeClass @@ -109,6 +111,7 @@ GskRenderNode ** gsk_container_node_get_children (const GskRenderNode *no void gsk_transform_node_get_translate (const GskRenderNode *node, float *dx, float *dy); +gboolean gsk_render_node_prefers_high_depth (const GskRenderNode *node); G_END_DECLS From 917481468617b37703d752ca4cc2ed6ab50fc64b Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Tue, 5 Oct 2021 23:36:49 -0400 Subject: [PATCH 09/12] ngl: Allow specifying texture formats Allow passing a format when creating textures or render targets. Update all callers to pass GL_RGBA8, which is the format we have always used so far. --- gsk/ngl/gsknglcommandqueue.c | 9 ++++++--- gsk/ngl/gsknglcommandqueueprivate.h | 2 ++ gsk/ngl/gskngldriver.c | 20 +++++++++++++++++++- gsk/ngl/gskngldriverprivate.h | 3 +++ gsk/ngl/gsknglrenderer.c | 1 + gsk/ngl/gsknglrenderjob.c | 6 ++++++ gsk/ngl/gskngltexture.c | 2 ++ gsk/ngl/gskngltexturelibrary.c | 2 +- gsk/ngl/gskngltextureprivate.h | 2 ++ 9 files changed, 42 insertions(+), 5 deletions(-) diff --git a/gsk/ngl/gsknglcommandqueue.c b/gsk/ngl/gsknglcommandqueue.c index 29cbb551d0..8dde9ff269 100644 --- a/gsk/ngl/gsknglcommandqueue.c +++ b/gsk/ngl/gsknglcommandqueue.c @@ -1232,6 +1232,7 @@ gboolean gsk_ngl_command_queue_create_render_target (GskNglCommandQueue *self, int width, int height, + int format, int min_filter, int mag_filter, guint *out_fbo_id, @@ -1248,6 +1249,7 @@ gsk_ngl_command_queue_create_render_target (GskNglCommandQueue *self, texture_id = gsk_ngl_command_queue_create_texture (self, width, height, + format, min_filter, mag_filter); if (texture_id == -1) @@ -1273,6 +1275,7 @@ int gsk_ngl_command_queue_create_texture (GskNglCommandQueue *self, int width, int height, + int format, int min_filter, int mag_filter) { @@ -1297,9 +1300,9 @@ gsk_ngl_command_queue_create_texture (GskNglCommandQueue *self, glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); if (gdk_gl_context_get_use_es (self->context)) - glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexImage2D (GL_TEXTURE_2D, 0, format, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); else - glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); + glTexImage2D (GL_TEXTURE_2D, 0, format, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); /* Restore the previous texture if it was set */ if (self->attachments->textures[0].id != 0) @@ -1354,7 +1357,7 @@ gsk_ngl_command_queue_upload_texture (GskNglCommandQueue *self, height = MAX (height, self->max_texture_size); } - texture_id = gsk_ngl_command_queue_create_texture (self, width, height, min_filter, mag_filter); + texture_id = gsk_ngl_command_queue_create_texture (self, width, height, GL_RGBA8, min_filter, mag_filter); if (texture_id == -1) return texture_id; diff --git a/gsk/ngl/gsknglcommandqueueprivate.h b/gsk/ngl/gsknglcommandqueueprivate.h index b13838d48e..40cca01162 100644 --- a/gsk/ngl/gsknglcommandqueueprivate.h +++ b/gsk/ngl/gsknglcommandqueueprivate.h @@ -290,12 +290,14 @@ int gsk_ngl_command_queue_upload_texture (GskNglCommandQue int gsk_ngl_command_queue_create_texture (GskNglCommandQueue *self, int width, int height, + int format, int min_filter, int mag_filter); guint gsk_ngl_command_queue_create_framebuffer (GskNglCommandQueue *self); gboolean gsk_ngl_command_queue_create_render_target (GskNglCommandQueue *self, int width, int height, + int format, int min_filter, int mag_filter, guint *out_fbo_id, diff --git a/gsk/ngl/gskngldriver.c b/gsk/ngl/gskngldriver.c index 3bf4ace071..87f2864241 100644 --- a/gsk/ngl/gskngldriver.c +++ b/gsk/ngl/gskngldriver.c @@ -183,6 +183,7 @@ gsk_ngl_driver_create_atlas (GskNglDriver *self) atlas->texture_id = gsk_ngl_command_queue_create_texture (self->command_queue, atlas->width, atlas->height, + GL_RGBA8, GL_LINEAR, GL_LINEAR); @@ -750,6 +751,7 @@ gsk_ngl_driver_load_texture (GskNglDriver *self, guint texture_id; int height; int width; + int format; g_return_val_if_fail (GSK_IS_NGL_DRIVER (self), 0); g_return_val_if_fail (GDK_IS_TEXTURE (texture), 0); @@ -757,6 +759,8 @@ gsk_ngl_driver_load_texture (GskNglDriver *self, context = self->command_queue->context; + format = GL_RGBA8; + if (GDK_IS_GL_TEXTURE (texture)) { GdkGLTexture *gl_texture = (GdkGLTexture *) texture; @@ -799,7 +803,7 @@ gsk_ngl_driver_load_texture (GskNglDriver *self, mag_filter); t = gsk_ngl_texture_new (texture_id, - width, height, min_filter, mag_filter, + width, height, format, min_filter, mag_filter, self->current_frame_id); g_hash_table_insert (self->textures, GUINT_TO_POINTER (texture_id), t); @@ -820,6 +824,7 @@ gsk_ngl_driver_load_texture (GskNglDriver *self, * @self: a `GskNglDriver` * @width: the width of the texture * @height: the height of the texture + * @format: format for the texture * @min_filter: GL_NEAREST or GL_LINEAR * @mag_filter: GL_NEAREST or GL_FILTER * @@ -827,6 +832,8 @@ gsk_ngl_driver_load_texture (GskNglDriver *self, * to upload data, map to a framebuffer, or other uses which may * modify the texture immediately. * + * Typical examples for @format are GK_RGBA8, GL_RGBA16F or GL_RGBA32F. + * * Use gsk_ngl_driver_release_texture() to release this texture back into * the pool so it may be reused later in the pipeline. * @@ -837,6 +844,7 @@ GskNglTexture * gsk_ngl_driver_create_texture (GskNglDriver *self, float width, float height, + int format, int min_filter, int mag_filter) { @@ -847,9 +855,11 @@ gsk_ngl_driver_create_texture (GskNglDriver *self, texture_id = gsk_ngl_command_queue_create_texture (self->command_queue, width, height, + format, min_filter, mag_filter); texture = gsk_ngl_texture_new (texture_id, width, height, + format, min_filter, mag_filter, self->current_frame_id); g_hash_table_insert (self->textures, @@ -896,6 +906,7 @@ gsk_ngl_driver_release_texture (GskNglDriver *self, * @self: a `GskNglDriver` * @width: the width for the render target * @height: the height for the render target + * @format: the format to use * @min_filter: the min filter to use for the texture * @mag_filter: the mag filter to use for the texture * @out_render_target: (out): a location for the render target @@ -904,6 +915,8 @@ gsk_ngl_driver_release_texture (GskNglDriver *self, * bound to that framebuffer of the size @width x @height and using the * appropriate filters. * + * Typical examples for @format are GK_RGBA8, GL_RGBA16F or GL_RGBA32F. + * * Use gsk_ngl_driver_release_render_target() when you are finished with * the render target to release it. You may steal the texture from the * render target when releasing it. @@ -915,6 +928,7 @@ gboolean gsk_ngl_driver_create_render_target (GskNglDriver *self, int width, int height, + int format, int min_filter, int mag_filter, GskNglRenderTarget **out_render_target) @@ -947,6 +961,7 @@ gsk_ngl_driver_create_render_target (GskNglDriver *self, if (gsk_ngl_command_queue_create_render_target (self->command_queue, width, height, + format, min_filter, mag_filter, &framebuffer_id, &texture_id)) { @@ -955,6 +970,7 @@ gsk_ngl_driver_create_render_target (GskNglDriver *self, render_target = g_slice_new0 (GskNglRenderTarget); render_target->min_filter = min_filter; render_target->mag_filter = mag_filter; + render_target->format = format; render_target->width = width; render_target->height = height; render_target->framebuffer_id = framebuffer_id; @@ -1014,6 +1030,7 @@ gsk_ngl_driver_release_render_target (GskNglDriver *self, texture = gsk_ngl_texture_new (render_target->texture_id, render_target->width, render_target->height, + render_target->format, render_target->min_filter, render_target->mag_filter, self->current_frame_id); @@ -1266,6 +1283,7 @@ gsk_ngl_driver_add_texture_slices (GskNglDriver *self, /* Allocate one Texture for the entire thing. */ t = gsk_ngl_texture_new (0, tex_width, tex_height, + GL_RGBA8, GL_NEAREST, GL_NEAREST, self->current_frame_id); diff --git a/gsk/ngl/gskngldriverprivate.h b/gsk/ngl/gskngldriverprivate.h index 9d40c81b2b..42b6263ec1 100644 --- a/gsk/ngl/gskngldriverprivate.h +++ b/gsk/ngl/gskngldriverprivate.h @@ -88,6 +88,7 @@ struct _GskNglRenderTarget guint texture_id; int min_filter; int mag_filter; + int format; int width; int height; }; @@ -144,6 +145,7 @@ GdkGLContext *gsk_ngl_driver_get_context (GskNglDriver gboolean gsk_ngl_driver_create_render_target (GskNglDriver *self, int width, int height, + int format, int min_filter, int mag_filter, GskNglRenderTarget **render_target); @@ -166,6 +168,7 @@ guint gsk_ngl_driver_load_texture (GskNglDriver GskNglTexture *gsk_ngl_driver_create_texture (GskNglDriver *self, float width, float height, + int format, int min_filter, int mag_filter); void gsk_ngl_driver_release_texture (GskNglDriver *self, diff --git a/gsk/ngl/gsknglrenderer.c b/gsk/ngl/gsknglrenderer.c index cdb6717043..7263d0b1e4 100644 --- a/gsk/ngl/gsknglrenderer.c +++ b/gsk/ngl/gsknglrenderer.c @@ -245,6 +245,7 @@ gsk_ngl_renderer_render_texture (GskRenderer *renderer, if (gsk_ngl_driver_create_render_target (self->driver, width, height, + GL_RGBA8, GL_NEAREST, GL_NEAREST, &render_target)) { diff --git a/gsk/ngl/gsknglrenderjob.c b/gsk/ngl/gsknglrenderjob.c index baf87f6461..d285eb24b0 100644 --- a/gsk/ngl/gsknglrenderjob.c +++ b/gsk/ngl/gsknglrenderjob.c @@ -1258,6 +1258,7 @@ blur_offscreen (GskNglRenderJob *job, if (!gsk_ngl_driver_create_render_target (job->driver, MAX (texture_to_blur_width, 1), MAX (texture_to_blur_height, 1), + GL_RGBA8, GL_NEAREST, GL_NEAREST, &pass1)) return 0; @@ -1268,6 +1269,7 @@ blur_offscreen (GskNglRenderJob *job, if (!gsk_ngl_driver_create_render_target (job->driver, texture_to_blur_width, texture_to_blur_height, + GL_RGBA8, GL_NEAREST, GL_NEAREST, &pass2)) return gsk_ngl_driver_release_render_target (job->driver, pass1, FALSE); @@ -2179,6 +2181,7 @@ gsk_ngl_render_job_visit_blurred_inset_shadow_node (GskNglRenderJob *job, if (!gsk_ngl_driver_create_render_target (job->driver, texture_width, texture_height, + GL_RGBA8, GL_NEAREST, GL_NEAREST, &render_target)) g_assert_not_reached (); @@ -2449,6 +2452,7 @@ gsk_ngl_render_job_visit_blurred_outset_shadow_node (GskNglRenderJob *job, gsk_ngl_driver_create_render_target (job->driver, texture_width, texture_height, + GL_RGBA8, GL_NEAREST, GL_NEAREST, &render_target); @@ -3856,6 +3860,7 @@ gsk_ngl_render_job_visit_node_with_offscreen (GskNglRenderJob *job, if (!gsk_ngl_driver_create_render_target (job->driver, scaled_width, scaled_height, + GL_RGBA8, filter, filter, &render_target)) g_assert_not_reached (); @@ -3954,6 +3959,7 @@ gsk_ngl_render_job_render_flipped (GskNglRenderJob *job, if (!gsk_ngl_command_queue_create_render_target (job->command_queue, MAX (1, job->viewport.size.width), MAX (1, job->viewport.size.height), + GL_RGBA8, GL_NEAREST, GL_NEAREST, &framebuffer_id, &texture_id)) return; diff --git a/gsk/ngl/gskngltexture.c b/gsk/ngl/gskngltexture.c index 5ee38f69b6..c70d4d91b2 100644 --- a/gsk/ngl/gskngltexture.c +++ b/gsk/ngl/gskngltexture.c @@ -59,6 +59,7 @@ GskNglTexture * gsk_ngl_texture_new (guint texture_id, int width, int height, + int format, int min_filter, int mag_filter, gint64 frame_id) @@ -70,6 +71,7 @@ gsk_ngl_texture_new (guint texture_id, texture->link.data = texture; texture->min_filter = min_filter; texture->mag_filter = mag_filter; + texture->format = format; texture->width = width; texture->height = height; texture->last_used_in_frame = frame_id; diff --git a/gsk/ngl/gskngltexturelibrary.c b/gsk/ngl/gskngltexturelibrary.c index 7998ae9850..03b8e252f7 100644 --- a/gsk/ngl/gskngltexturelibrary.c +++ b/gsk/ngl/gskngltexturelibrary.c @@ -228,7 +228,7 @@ gsk_ngl_texture_library_pack_one (GskNglTextureLibrary *self, height = MIN (height, self->driver->command_queue->max_texture_size); } - texture = gsk_ngl_driver_create_texture (self->driver, width, height, GL_LINEAR, GL_LINEAR); + texture = gsk_ngl_driver_create_texture (self->driver, width, height, GL_RGBA8, GL_LINEAR, GL_LINEAR); texture->permanent = TRUE; return texture; diff --git a/gsk/ngl/gskngltextureprivate.h b/gsk/ngl/gskngltextureprivate.h index 1d9052f625..55ef48c4d3 100644 --- a/gsk/ngl/gskngltextureprivate.h +++ b/gsk/ngl/gskngltextureprivate.h @@ -67,6 +67,7 @@ struct _GskNglTexture int height; int min_filter; int mag_filter; + int format; /* Set when used by an atlas so we don't drop the texture */ guint permanent : 1; @@ -75,6 +76,7 @@ struct _GskNglTexture GskNglTexture *gsk_ngl_texture_new (guint texture_id, int width, int height, + int format, int min_filter, int mag_filter, gint64 frame_id); From 985d2d221c6b34293cc2aff4f51b745f7680340e Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 1 Oct 2021 08:48:43 -0400 Subject: [PATCH 10/12] ngl: Determine intermediate formats Look at the framebuffer and the rendernode to determine what format to use for intermediate textures. Our preference here is to use fp16, if we have it and it makes sense for the framebuffer we're given. --- gsk/ngl/gsknglrenderjob.c | 44 +++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/gsk/ngl/gsknglrenderjob.c b/gsk/ngl/gsknglrenderjob.c index d285eb24b0..e3436e10f4 100644 --- a/gsk/ngl/gsknglrenderjob.c +++ b/gsk/ngl/gsknglrenderjob.c @@ -162,6 +162,11 @@ struct _GskNglRenderJob /* If we should be rendering red zones over fallback nodes */ guint debug_fallback : 1; + + /* Format we want to use for intermediate textures, determined by + * looking at the format of the framebuffer we are rendering on. + */ + int target_format; }; typedef struct _GskNglRenderOffscreen @@ -198,6 +203,16 @@ static gboolean gsk_ngl_render_job_visit_node_with_offscreen (GskNglRenderJob const GskRenderNode *node, GskNglRenderOffscreen *offscreen); +static inline int +get_target_format (GskNglRenderJob *job, + const GskRenderNode *node) +{ + if (gsk_render_node_prefers_high_depth (node)) + return job->target_format; + + return GL_RGBA8; +} + static inline void init_full_texture_region (GskNglRenderOffscreen *offscreen) { @@ -1258,7 +1273,7 @@ blur_offscreen (GskNglRenderJob *job, if (!gsk_ngl_driver_create_render_target (job->driver, MAX (texture_to_blur_width, 1), MAX (texture_to_blur_height, 1), - GL_RGBA8, + job->target_format, GL_NEAREST, GL_NEAREST, &pass1)) return 0; @@ -1269,7 +1284,7 @@ blur_offscreen (GskNglRenderJob *job, if (!gsk_ngl_driver_create_render_target (job->driver, texture_to_blur_width, texture_to_blur_height, - GL_RGBA8, + job->target_format, GL_NEAREST, GL_NEAREST, &pass2)) return gsk_ngl_driver_release_render_target (job->driver, pass1, FALSE); @@ -2181,7 +2196,7 @@ gsk_ngl_render_job_visit_blurred_inset_shadow_node (GskNglRenderJob *job, if (!gsk_ngl_driver_create_render_target (job->driver, texture_width, texture_height, - GL_RGBA8, + get_target_format (job, node), GL_NEAREST, GL_NEAREST, &render_target)) g_assert_not_reached (); @@ -2452,7 +2467,7 @@ gsk_ngl_render_job_visit_blurred_outset_shadow_node (GskNglRenderJob *job, gsk_ngl_driver_create_render_target (job->driver, texture_width, texture_height, - GL_RGBA8, + get_target_format (job, node), GL_NEAREST, GL_NEAREST, &render_target); @@ -3860,7 +3875,7 @@ gsk_ngl_render_job_visit_node_with_offscreen (GskNglRenderJob *job, if (!gsk_ngl_driver_create_render_target (job->driver, scaled_width, scaled_height, - GL_RGBA8, + get_target_format (job, node), filter, filter, &render_target)) g_assert_not_reached (); @@ -3959,7 +3974,7 @@ gsk_ngl_render_job_render_flipped (GskNglRenderJob *job, if (!gsk_ngl_command_queue_create_render_target (job->command_queue, MAX (1, job->viewport.size.width), MAX (1, job->viewport.size.height), - GL_RGBA8, + job->target_format, GL_NEAREST, GL_NEAREST, &framebuffer_id, &texture_id)) return; @@ -4050,6 +4065,22 @@ gsk_ngl_render_job_set_debug_fallback (GskNglRenderJob *job, job->debug_fallback = !!debug_fallback; } +static int +get_framebuffer_format (guint framebuffer) +{ + int size; + + glBindFramebuffer (GL_FRAMEBUFFER, framebuffer); + glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, &size); + + if (size >= 32) + return GL_RGBA32F; + else if (size >= 16) + return GL_RGBA16F; + else + return GL_RGBA8; +} + GskNglRenderJob * gsk_ngl_render_job_new (GskNglDriver *driver, const graphene_rect_t *viewport, @@ -4076,6 +4107,7 @@ gsk_ngl_render_job_new (GskNglDriver *driver, job->scale_x = scale_factor; job->scale_y = scale_factor; job->viewport = *viewport; + job->target_format = get_framebuffer_format (framebuffer); gsk_ngl_render_job_set_alpha (job, 1.0f); gsk_ngl_render_job_set_projection_from_rect (job, viewport, NULL); From 8a24deff97e2626beda86029b31d6340f613680f Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 1 Oct 2021 16:47:55 -0400 Subject: [PATCH 11/12] ngl: Update framebuffer format for each frame Look at whether the render nodes are high depth and if so, request a high depth framebuffer. Whether we actually get one is up to the backend. --- gsk/ngl/gsknglrenderer.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/gsk/ngl/gsknglrenderer.c b/gsk/ngl/gsknglrenderer.c index 7263d0b1e4..e5aaebd0a4 100644 --- a/gsk/ngl/gsknglrenderer.c +++ b/gsk/ngl/gsknglrenderer.c @@ -22,8 +22,11 @@ #include #include +#include +#include #include #include +#include #include "gsknglcommandqueueprivate.h" #include "gskngldriverprivate.h" @@ -201,7 +204,9 @@ gsk_ngl_renderer_render (GskRenderer *renderer, viewport.size.height = gdk_surface_get_height (surface) * scale_factor; gdk_gl_context_make_current (self->context); - gdk_draw_context_begin_frame (GDK_DRAW_CONTEXT (self->context), update_area); + gdk_draw_context_begin_frame_full (GDK_DRAW_CONTEXT (self->context), + gsk_render_node_prefers_high_depth (root), + update_area); /* Must be called *AFTER* gdk_draw_context_begin_frame() */ render_region = get_render_region (surface, self->context); From 6f1742970d788880b4e16073289d8c3e636de45e Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Wed, 6 Oct 2021 18:31:09 -0400 Subject: [PATCH 12/12] ngl: Make render_texture high depth aware Make a deep texture, if the render nodes have high depth content. For now, we use 32F here for the deep format, since using 16F causes small rounding errors that break the memorytexture roundtrip tests. --- gsk/ngl/gsknglrenderer.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gsk/ngl/gsknglrenderer.c b/gsk/ngl/gsknglrenderer.c index e5aaebd0a4..eea48b6e6d 100644 --- a/gsk/ngl/gsknglrenderer.c +++ b/gsk/ngl/gsknglrenderer.c @@ -241,6 +241,7 @@ gsk_ngl_renderer_render_texture (GskRenderer *renderer, guint texture_id; int width; int height; + int format; g_assert (GSK_IS_NGL_RENDERER (renderer)); g_assert (root != NULL); @@ -248,9 +249,11 @@ gsk_ngl_renderer_render_texture (GskRenderer *renderer, width = ceilf (viewport->size.width); height = ceilf (viewport->size.height); + format = gsk_render_node_prefers_high_depth (root) ? GL_RGBA32F : GL_RGBA8; + if (gsk_ngl_driver_create_render_target (self->driver, width, height, - GL_RGBA8, + format, GL_NEAREST, GL_NEAREST, &render_target)) {