2021-09-22 00:01:41 +00:00
|
|
|
/*
|
|
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
* Authors: Benjamin Otte <otte@gnome.org>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include "gdkmemoryformatprivate.h"
|
2023-12-16 09:27:24 +00:00
|
|
|
|
|
|
|
#include "gdkdmabuffourccprivate.h"
|
2024-06-19 12:24:35 +00:00
|
|
|
#include "gdkcolorstateprivate.h"
|
2024-09-01 19:39:29 +00:00
|
|
|
#include "gdkparalleltaskprivate.h"
|
2024-06-19 12:24:35 +00:00
|
|
|
#include "gtk/gtkcolorutilsprivate.h"
|
2024-09-06 16:31:27 +00:00
|
|
|
#include "gdkprofilerprivate.h"
|
2021-09-22 00:01:41 +00:00
|
|
|
|
2021-10-07 03:15:25 +00:00
|
|
|
#include "gsk/gl/fp16private.h"
|
2021-09-22 00:01:41 +00:00
|
|
|
|
2021-09-25 02:47:45 +00:00
|
|
|
#include <epoxy/gl.h>
|
|
|
|
|
2024-09-06 16:31:27 +00:00
|
|
|
/* Don't report quick (< 0.5 msec) runs */
|
|
|
|
#define MIN_MARK_DURATION 500000
|
|
|
|
|
|
|
|
#define ADD_MARK(before,name,fmt,...) \
|
|
|
|
if (GDK_PROFILER_IS_RUNNING) \
|
|
|
|
{ \
|
|
|
|
gint64 duration = GDK_PROFILER_CURRENT_TIME - before; \
|
|
|
|
if (duration > MIN_MARK_DURATION) \
|
|
|
|
gdk_profiler_add_markf (before, duration, name, fmt, __VA_ARGS__); \
|
|
|
|
}
|
|
|
|
|
2024-07-03 16:36:49 +00:00
|
|
|
G_STATIC_ASSERT ((1 << GDK_MEMORY_DEPTH_BITS) > GDK_N_DEPTHS);
|
|
|
|
|
2021-09-22 00:01:41 +00:00
|
|
|
typedef struct _GdkMemoryFormatDescription GdkMemoryFormatDescription;
|
|
|
|
|
|
|
|
#define TYPED_FUNCS(name, T, R, G, B, A, bpp, scale) \
|
|
|
|
static void \
|
2024-07-01 04:48:35 +00:00
|
|
|
name ## _to_float (float (*dest)[4], \
|
|
|
|
const guchar *src_data, \
|
|
|
|
gsize n) \
|
2021-09-22 00:01:41 +00:00
|
|
|
{ \
|
|
|
|
for (gsize i = 0; i < n; i++) \
|
|
|
|
{ \
|
|
|
|
T *src = (T *) (src_data + i * bpp); \
|
2024-07-01 04:48:35 +00:00
|
|
|
dest[i][0] = (float) src[R] / scale; \
|
|
|
|
dest[i][1] = (float) src[G] / scale; \
|
|
|
|
dest[i][2] = (float) src[B] / scale; \
|
|
|
|
if (A >= 0) dest[i][3] = (float) src[A] / scale; else dest[i][3] = 1.0; \
|
2021-09-22 00:01:41 +00:00
|
|
|
} \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
static void \
|
2024-07-01 04:48:35 +00:00
|
|
|
name ## _from_float (guchar *dest_data, \
|
|
|
|
const float (*src)[4], \
|
|
|
|
gsize n) \
|
2021-09-22 00:01:41 +00:00
|
|
|
{ \
|
|
|
|
for (gsize i = 0; i < n; i++) \
|
|
|
|
{ \
|
|
|
|
T *dest = (T *) (dest_data + i * bpp); \
|
2024-07-01 04:48:35 +00:00
|
|
|
dest[R] = CLAMP (src[i][0] * scale + 0.5, 0, scale); \
|
|
|
|
dest[G] = CLAMP (src[i][1] * scale + 0.5, 0, scale); \
|
|
|
|
dest[B] = CLAMP (src[i][2] * scale + 0.5, 0, scale); \
|
|
|
|
if (A >= 0) dest[A] = CLAMP (src[i][3] * scale + 0.5, 0, scale); \
|
2021-09-22 00:01:41 +00:00
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
2023-05-26 12:38:25 +00:00
|
|
|
#define TYPED_GRAY_FUNCS(name, T, G, A, bpp, scale) \
|
|
|
|
static void \
|
2024-07-01 04:48:35 +00:00
|
|
|
name ## _to_float (float (*dest)[4], \
|
|
|
|
const guchar *src_data, \
|
|
|
|
gsize n) \
|
2023-05-26 12:38:25 +00:00
|
|
|
{ \
|
|
|
|
for (gsize i = 0; i < n; i++) \
|
|
|
|
{ \
|
|
|
|
T *src = (T *) (src_data + i * bpp); \
|
2024-07-01 04:48:35 +00:00
|
|
|
if (A >= 0) dest[i][3] = (float) src[A] / scale; else dest[i][3] = 1.0; \
|
|
|
|
if (G >= 0) dest[i][0] = (float) src[G] / scale; else dest[i][0] = dest[i][3]; \
|
|
|
|
dest[i][1] = dest[i][2] = dest[i][0]; \
|
2023-05-26 12:38:25 +00:00
|
|
|
} \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
static void \
|
2024-07-01 04:48:35 +00:00
|
|
|
name ## _from_float (guchar *dest_data, \
|
|
|
|
const float (*src)[4], \
|
|
|
|
gsize n) \
|
2023-05-26 12:38:25 +00:00
|
|
|
{ \
|
|
|
|
for (gsize i = 0; i < n; i++) \
|
|
|
|
{ \
|
|
|
|
T *dest = (T *) (dest_data + i * bpp); \
|
2024-07-01 04:48:35 +00:00
|
|
|
if (G >= 0) dest[G] = CLAMP ((src[i][0] + src[i][1] + src[i][2]) * scale / 3.f + 0.5, 0, scale); \
|
|
|
|
if (A >= 0) dest[A] = CLAMP (src[i][3] * scale + 0.5, 0, scale); \
|
2023-05-26 12:38:25 +00:00
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
2021-09-22 00:01:41 +00:00
|
|
|
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)
|
2023-10-20 03:20:15 +00:00
|
|
|
TYPED_FUNCS (a8b8g8r8_premultiplied, guchar, 3, 2, 1, 0, 4, 255)
|
2021-09-22 00:01:41 +00:00
|
|
|
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)
|
2023-10-20 11:33:46 +00:00
|
|
|
|
|
|
|
TYPED_FUNCS (r8g8b8x8, guchar, 0, 1, 2, -1, 4, 255)
|
|
|
|
TYPED_FUNCS (x8r8g8b8, guchar, 1, 2, 3, -1, 4, 255)
|
|
|
|
TYPED_FUNCS (b8g8r8x8, guchar, 2, 1, 0, -1, 4, 255)
|
|
|
|
TYPED_FUNCS (x8b8g8r8, guchar, 3, 2, 1, -1, 4, 255)
|
|
|
|
|
2021-09-22 00:01:41 +00:00
|
|
|
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)
|
|
|
|
|
2023-05-26 12:38:25 +00:00
|
|
|
TYPED_GRAY_FUNCS (g8a8_premultiplied, guchar, 0, 1, 2, 255)
|
|
|
|
TYPED_GRAY_FUNCS (g8a8, guchar, 0, 1, 2, 255)
|
|
|
|
TYPED_GRAY_FUNCS (g8, guchar, 0, -1, 1, 255)
|
|
|
|
TYPED_GRAY_FUNCS (a8, guchar, -1, 0, 1, 255)
|
|
|
|
TYPED_GRAY_FUNCS (g16a16_premultiplied, guint16, 0, 1, 4, 65535)
|
|
|
|
TYPED_GRAY_FUNCS (g16a16, guint16, 0, 1, 4, 65535)
|
|
|
|
TYPED_GRAY_FUNCS (g16, guint16, 0, -1, 2, 65535)
|
|
|
|
TYPED_GRAY_FUNCS (a16, guint16, -1, 0, 2, 65535)
|
|
|
|
|
2021-09-22 00:01:41 +00:00
|
|
|
static void
|
2024-07-01 04:48:35 +00:00
|
|
|
r16g16b16_float_to_float (float (*dest)[4],
|
|
|
|
const guchar *src_data,
|
|
|
|
gsize n)
|
2021-09-22 00:01:41 +00:00
|
|
|
{
|
|
|
|
guint16 *src = (guint16 *) src_data;
|
|
|
|
for (gsize i = 0; i < n; i++)
|
|
|
|
{
|
2024-07-01 04:48:35 +00:00
|
|
|
half_to_float (src, dest[i], 3);
|
|
|
|
dest[i][3] = 1.0;
|
2021-09-22 00:01:41 +00:00
|
|
|
src += 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2024-07-01 04:48:35 +00:00
|
|
|
r16g16b16_float_from_float (guchar *dest_data,
|
|
|
|
const float (*src)[4],
|
|
|
|
gsize n)
|
2021-09-22 00:01:41 +00:00
|
|
|
{
|
|
|
|
guint16 *dest = (guint16 *) dest_data;
|
|
|
|
for (gsize i = 0; i < n; i++)
|
|
|
|
{
|
2024-07-01 04:48:35 +00:00
|
|
|
float_to_half (src[i], dest, 3);
|
2021-09-22 00:01:41 +00:00
|
|
|
dest += 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2024-07-01 04:48:35 +00:00
|
|
|
r16g16b16a16_float_to_float (float (*dest)[4],
|
|
|
|
const guchar *src,
|
|
|
|
gsize n)
|
2021-09-22 00:01:41 +00:00
|
|
|
{
|
2024-07-01 04:48:35 +00:00
|
|
|
half_to_float ((const guint16 *) src, (float *) dest, 4 * n);
|
2021-09-22 00:01:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2024-07-01 04:48:35 +00:00
|
|
|
r16g16b16a16_float_from_float (guchar *dest,
|
|
|
|
const float (*src)[4],
|
|
|
|
gsize n)
|
2021-09-22 00:01:41 +00:00
|
|
|
{
|
2024-07-01 04:48:35 +00:00
|
|
|
float_to_half ((const float *) src, (guint16 *) dest, 4 * n);
|
2021-09-22 00:01:41 +00:00
|
|
|
}
|
|
|
|
|
2023-07-21 01:02:33 +00:00
|
|
|
static void
|
2024-07-01 04:48:35 +00:00
|
|
|
a16_float_to_float (float (*dest)[4],
|
|
|
|
const guchar *src_data,
|
|
|
|
gsize n)
|
2023-07-21 01:02:33 +00:00
|
|
|
{
|
|
|
|
const guint16 *src = (const guint16 *) src_data;
|
|
|
|
for (gsize i = 0; i < n; i++)
|
|
|
|
{
|
2024-07-01 04:48:35 +00:00
|
|
|
half_to_float (src, &dest[i][0], 1);
|
|
|
|
dest[i][1] = dest[i][0];
|
|
|
|
dest[i][2] = dest[i][0];
|
|
|
|
dest[i][3] = dest[i][0];
|
2023-07-21 01:02:33 +00:00
|
|
|
src++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2024-07-01 04:48:35 +00:00
|
|
|
a16_float_from_float (guchar *dest_data,
|
|
|
|
const float (*src)[4],
|
|
|
|
gsize n)
|
2023-07-21 01:02:33 +00:00
|
|
|
{
|
|
|
|
guint16 *dest = (guint16 *) dest_data;
|
|
|
|
for (gsize i = 0; i < n; i++)
|
|
|
|
{
|
2024-07-01 04:48:35 +00:00
|
|
|
float_to_half (&src[i][3], dest, 1);
|
2023-07-21 01:02:33 +00:00
|
|
|
dest ++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-22 00:01:41 +00:00
|
|
|
static void
|
2024-07-01 04:48:35 +00:00
|
|
|
r32g32b32_float_to_float (float (*dest)[4],
|
|
|
|
const guchar *src_data,
|
|
|
|
gsize n)
|
2021-09-22 00:01:41 +00:00
|
|
|
{
|
2024-07-01 04:48:35 +00:00
|
|
|
const float (*src)[3] = (const float (*)[3]) src_data;
|
2021-09-22 00:01:41 +00:00
|
|
|
for (gsize i = 0; i < n; i++)
|
|
|
|
{
|
2024-07-01 04:48:35 +00:00
|
|
|
dest[i][0] = src[i][0];
|
|
|
|
dest[i][1] = src[i][1];
|
|
|
|
dest[i][2] = src[i][2];
|
|
|
|
dest[i][3] = 1.0;
|
2021-09-22 00:01:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2024-07-01 04:48:35 +00:00
|
|
|
r32g32b32_float_from_float (guchar *dest_data,
|
|
|
|
const float (*src)[4],
|
|
|
|
gsize n)
|
2021-09-22 00:01:41 +00:00
|
|
|
{
|
2024-07-01 04:48:35 +00:00
|
|
|
float (*dest)[3] = (float (*)[3]) dest_data;
|
2021-09-22 00:01:41 +00:00
|
|
|
for (gsize i = 0; i < n; i++)
|
|
|
|
{
|
2024-07-01 04:48:35 +00:00
|
|
|
dest[i][0] = src[i][0];
|
|
|
|
dest[i][1] = src[i][1];
|
|
|
|
dest[i][2] = src[i][2];
|
2021-09-22 00:01:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2024-07-01 04:48:35 +00:00
|
|
|
r32g32b32a32_float_to_float (float (*dest)[4],
|
|
|
|
const guchar *src,
|
|
|
|
gsize n)
|
2021-09-22 00:01:41 +00:00
|
|
|
{
|
|
|
|
memcpy (dest, src, sizeof (float) * n * 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2024-07-01 04:48:35 +00:00
|
|
|
r32g32b32a32_float_from_float (guchar *dest,
|
|
|
|
const float (*src)[4],
|
|
|
|
gsize n)
|
2021-09-22 00:01:41 +00:00
|
|
|
{
|
|
|
|
memcpy (dest, src, sizeof (float) * n * 4);
|
|
|
|
}
|
|
|
|
|
2023-07-21 01:02:33 +00:00
|
|
|
static void
|
2024-07-01 04:48:35 +00:00
|
|
|
a32_float_to_float (float (*dest)[4],
|
|
|
|
const guchar *src_data,
|
|
|
|
gsize n)
|
2023-07-21 01:02:33 +00:00
|
|
|
{
|
|
|
|
const float *src = (const float *) src_data;
|
|
|
|
for (gsize i = 0; i < n; i++)
|
|
|
|
{
|
2024-07-01 04:48:35 +00:00
|
|
|
dest[i][0] = src[i];
|
|
|
|
dest[i][1] = src[i];
|
|
|
|
dest[i][2] = src[i];
|
|
|
|
dest[i][3] = src[i];
|
2023-07-21 01:02:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2024-07-01 04:48:35 +00:00
|
|
|
a32_float_from_float (guchar *dest_data,
|
|
|
|
const float (*src)[4],
|
|
|
|
gsize n)
|
2023-07-21 01:02:33 +00:00
|
|
|
{
|
|
|
|
float *dest = (float *) dest_data;
|
|
|
|
for (gsize i = 0; i < n; i++)
|
|
|
|
{
|
2024-07-01 04:48:35 +00:00
|
|
|
dest[i] = src[i][3];
|
2023-07-21 01:02:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-03 14:34:29 +00:00
|
|
|
#define PREMULTIPLY_FUNC(name, R1, G1, B1, A1, R2, G2, B2, A2) \
|
|
|
|
static void \
|
|
|
|
name (guchar *dest, \
|
|
|
|
const guchar *src, \
|
|
|
|
gsize n) \
|
|
|
|
{ \
|
|
|
|
for (; n > 0; n--) \
|
|
|
|
{ \
|
|
|
|
guchar a = src[A1]; \
|
|
|
|
guint16 r = (guint16)src[R1] * a + 127; \
|
|
|
|
guint16 g = (guint16)src[G1] * a + 127; \
|
|
|
|
guint16 b = (guint16)src[B1] * a + 127; \
|
|
|
|
dest[R2] = (r + (r >> 8) + 1) >> 8; \
|
|
|
|
dest[G2] = (g + (g >> 8) + 1) >> 8; \
|
|
|
|
dest[B2] = (b + (b >> 8) + 1) >> 8; \
|
|
|
|
dest[A2] = a; \
|
|
|
|
dest += 4; \
|
|
|
|
src += 4; \
|
|
|
|
} \
|
2022-02-15 19:54:18 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 14:34:29 +00:00
|
|
|
PREMULTIPLY_FUNC(r8g8b8a8_to_r8g8b8a8_premultiplied, 0, 1, 2, 3, 0, 1, 2, 3)
|
|
|
|
PREMULTIPLY_FUNC(r8g8b8a8_to_b8g8r8a8_premultiplied, 0, 1, 2, 3, 2, 1, 0, 3)
|
|
|
|
PREMULTIPLY_FUNC(r8g8b8a8_to_a8r8g8b8_premultiplied, 0, 1, 2, 3, 1, 2, 3, 0)
|
|
|
|
PREMULTIPLY_FUNC(r8g8b8a8_to_a8b8g8r8_premultiplied, 0, 1, 2, 3, 3, 2, 1, 0)
|
|
|
|
|
2022-03-03 14:36:57 +00:00
|
|
|
#define ADD_ALPHA_FUNC(name, R1, G1, B1, R2, G2, B2, A2) \
|
|
|
|
static void \
|
|
|
|
name (guchar *dest, \
|
|
|
|
const guchar *src, \
|
|
|
|
gsize n) \
|
|
|
|
{ \
|
|
|
|
for (; n > 0; n--) \
|
|
|
|
{ \
|
|
|
|
dest[R2] = src[R1]; \
|
|
|
|
dest[G2] = src[G1]; \
|
|
|
|
dest[B2] = src[B1]; \
|
|
|
|
dest[A2] = 255; \
|
|
|
|
dest += 4; \
|
|
|
|
src += 3; \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
ADD_ALPHA_FUNC(r8g8b8_to_r8g8b8a8, 0, 1, 2, 0, 1, 2, 3)
|
|
|
|
ADD_ALPHA_FUNC(r8g8b8_to_b8g8r8a8, 0, 1, 2, 2, 1, 0, 3)
|
|
|
|
ADD_ALPHA_FUNC(r8g8b8_to_a8r8g8b8, 0, 1, 2, 1, 2, 3, 0)
|
|
|
|
ADD_ALPHA_FUNC(r8g8b8_to_a8b8g8r8, 0, 1, 2, 3, 2, 1, 0)
|
|
|
|
|
2024-08-27 02:48:43 +00:00
|
|
|
#define MIPMAP_FUNC(SumType, DataType, n_units) \
|
|
|
|
static void \
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
gdk_mipmap_ ## DataType ## _ ## n_units ## _nearest (guchar *dest, \
|
|
|
|
gsize dest_stride, \
|
|
|
|
const guchar *src, \
|
|
|
|
gsize src_stride, \
|
|
|
|
gsize src_width, \
|
|
|
|
gsize src_height, \
|
|
|
|
guint lod_level) \
|
|
|
|
{ \
|
|
|
|
gsize y, x, i; \
|
|
|
|
gsize n = 1 << lod_level; \
|
|
|
|
\
|
|
|
|
for (y = 0; y < src_height; y += n) \
|
|
|
|
{ \
|
|
|
|
DataType *dest_data = (DataType *) dest; \
|
|
|
|
for (x = 0; x < src_width; x += n) \
|
|
|
|
{ \
|
|
|
|
const DataType *src_data = (const DataType *) (src + (y + MIN (n / 2, src_height - y)) * src_stride); \
|
|
|
|
\
|
|
|
|
for (i = 0; i < n_units; i++) \
|
|
|
|
*dest_data++ = src_data[n_units * (x + MIN (n / 2, src_width - n_units)) + i]; \
|
|
|
|
} \
|
|
|
|
dest += dest_stride; \
|
|
|
|
src += src_stride * n; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
static void \
|
|
|
|
gdk_mipmap_ ## DataType ## _ ## n_units ## _linear (guchar *dest, \
|
|
|
|
gsize dest_stride, \
|
|
|
|
const guchar *src, \
|
|
|
|
gsize src_stride, \
|
|
|
|
gsize src_width, \
|
|
|
|
gsize src_height, \
|
|
|
|
guint lod_level) \
|
2024-08-27 02:48:43 +00:00
|
|
|
{ \
|
|
|
|
gsize y_dest, y, x_dest, x, i; \
|
|
|
|
gsize n = 1 << lod_level; \
|
|
|
|
\
|
|
|
|
for (y_dest = 0; y_dest < src_height; y_dest += n) \
|
|
|
|
{ \
|
|
|
|
DataType *dest_data = (DataType *) dest; \
|
|
|
|
for (x_dest = 0; x_dest < src_width; x_dest += n) \
|
|
|
|
{ \
|
|
|
|
SumType tmp[n_units] = { 0, }; \
|
|
|
|
\
|
|
|
|
for (y = 0; y < MIN (n, src_height - y_dest); y++) \
|
|
|
|
{ \
|
|
|
|
const DataType *src_data = (const DataType *) (src + y * src_stride); \
|
|
|
|
for (x = 0; x < MIN (n, src_width - x_dest); x++) \
|
|
|
|
{ \
|
|
|
|
for (i = 0; i < n_units; i++) \
|
|
|
|
tmp[i] += src_data[n_units * (x_dest + x) + i]; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
for (i = 0; i < n_units; i++) \
|
|
|
|
*dest_data++ = tmp[i] / (x * y); \
|
|
|
|
} \
|
|
|
|
dest += dest_stride; \
|
|
|
|
src += src_stride * n; \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
MIPMAP_FUNC(guint32, guint8, 1)
|
|
|
|
MIPMAP_FUNC(guint32, guint8, 2)
|
|
|
|
MIPMAP_FUNC(guint32, guint8, 3)
|
|
|
|
MIPMAP_FUNC(guint32, guint8, 4)
|
|
|
|
MIPMAP_FUNC(guint32, guint16, 1)
|
|
|
|
MIPMAP_FUNC(guint32, guint16, 2)
|
|
|
|
MIPMAP_FUNC(guint32, guint16, 3)
|
|
|
|
MIPMAP_FUNC(guint32, guint16, 4)
|
|
|
|
MIPMAP_FUNC(float, float, 1)
|
|
|
|
MIPMAP_FUNC(float, float, 3)
|
|
|
|
MIPMAP_FUNC(float, float, 4)
|
|
|
|
#define half_float guint16
|
|
|
|
MIPMAP_FUNC(float, half_float, 1)
|
|
|
|
MIPMAP_FUNC(float, half_float, 3)
|
|
|
|
MIPMAP_FUNC(float, half_float, 4)
|
|
|
|
#undef half_float
|
|
|
|
|
2021-09-22 00:01:41 +00:00
|
|
|
struct _GdkMemoryFormatDescription
|
|
|
|
{
|
2024-06-09 19:52:18 +00:00
|
|
|
const char *name;
|
2021-09-22 00:01:41 +00:00
|
|
|
GdkMemoryAlpha alpha;
|
2023-12-11 03:20:32 +00:00
|
|
|
GdkMemoryFormat premultiplied;
|
|
|
|
GdkMemoryFormat straight;
|
2021-09-22 00:01:41 +00:00
|
|
|
gsize bytes_per_pixel;
|
|
|
|
gsize alignment;
|
2023-06-15 18:02:46 +00:00
|
|
|
GdkMemoryDepth depth;
|
2023-12-11 03:23:16 +00:00
|
|
|
const GdkMemoryFormat *fallbacks;
|
2021-09-25 02:47:45 +00:00
|
|
|
struct {
|
2024-01-16 19:12:00 +00:00
|
|
|
GLint internal_gl_format;
|
|
|
|
GLint internal_gles_format;
|
2024-06-17 20:10:24 +00:00
|
|
|
GLint internal_srgb_format;
|
2023-12-11 04:31:32 +00:00
|
|
|
GLenum format;
|
2024-06-17 20:10:24 +00:00
|
|
|
GLenum srgb_format;
|
2023-12-11 04:31:32 +00:00
|
|
|
GLenum type;
|
2023-05-26 12:38:25 +00:00
|
|
|
GLint swizzle[4];
|
2023-12-09 06:17:51 +00:00
|
|
|
/* -1 if none exists, ie the format is already RGBA
|
|
|
|
* or the format doesn't have 4 channels */
|
|
|
|
GdkMemoryFormat rgba_format;
|
|
|
|
GLint rgba_swizzle[4];
|
2021-09-25 02:47:45 +00:00
|
|
|
} gl;
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
VkFormat vk_format;
|
2024-06-17 20:10:02 +00:00
|
|
|
VkFormat vk_srgb_format;
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
guint32 dmabuf_fourcc;
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2021-09-22 00:01:41 +00:00
|
|
|
/* no premultiplication going on here */
|
2024-07-01 04:48:35 +00:00
|
|
|
void (* to_float) (float (*)[4], const guchar*, gsize);
|
|
|
|
void (* from_float) (guchar *, const float (*)[4], gsize);
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
void (* mipmap_nearest) (guchar *, gsize, const guchar *, gsize, gsize, gsize, guint);
|
|
|
|
void (* mipmap_linear) (guchar *, gsize, const guchar *, gsize, gsize, gsize, guint);
|
2021-09-22 00:01:41 +00:00
|
|
|
};
|
|
|
|
|
2021-09-25 02:47:45 +00:00
|
|
|
#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
|
|
|
|
|
2023-07-21 01:05:40 +00:00
|
|
|
static const GdkMemoryFormatDescription memory_formats[] = {
|
2021-09-22 00:01:41 +00:00
|
|
|
[GDK_MEMORY_B8G8R8A8_PREMULTIPLIED] = {
|
2024-08-06 20:13:32 +00:00
|
|
|
.name = "BGRA8(p)",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_B8G8R8A8_PREMULTIPLIED,
|
|
|
|
.straight = GDK_MEMORY_B8G8R8A8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 4,
|
|
|
|
.alignment = G_ALIGNOF (guchar),
|
|
|
|
.depth = GDK_MEMORY_U8,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RGBA8,
|
2024-01-16 19:30:56 +00:00
|
|
|
.internal_gles_format = GL_BGRA,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_BGRA,
|
|
|
|
.type = GL_UNSIGNED_BYTE,
|
|
|
|
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
2023-12-14 15:01:19 +00:00
|
|
|
.rgba_swizzle = { GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA },
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_B8G8R8A8_UNORM,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_B8G8R8A8_SRGB,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = DRM_FORMAT_ARGB8888,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = b8g8r8a8_premultiplied_to_float,
|
|
|
|
.from_float = b8g8r8a8_premultiplied_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint8_4_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint8_4_linear,
|
2021-09-22 00:01:41 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_A8R8G8B8_PREMULTIPLIED] = {
|
2024-08-06 20:13:32 +00:00
|
|
|
.name = "ARGB8(p)",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_A8R8G8B8_PREMULTIPLIED,
|
|
|
|
.straight = GDK_MEMORY_A8R8G8B8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 4,
|
|
|
|
.alignment = G_ALIGNOF (guchar),
|
|
|
|
.depth = GDK_MEMORY_U8,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RGBA8,
|
|
|
|
.internal_gles_format = GL_RGBA8,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = GL_SRGB8_ALPHA8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_BGRA,
|
|
|
|
.type = GDK_GL_UNSIGNED_BYTE_FLIPPED,
|
|
|
|
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
|
|
.rgba_swizzle = { GL_GREEN, GL_BLUE, GL_ALPHA, GL_RED },
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_UNDEFINED,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_UNDEFINED,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = DRM_FORMAT_BGRA8888,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = a8r8g8b8_premultiplied_to_float,
|
|
|
|
.from_float = a8r8g8b8_premultiplied_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint8_4_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint8_4_linear,
|
2021-09-22 00:01:41 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_R8G8B8A8_PREMULTIPLIED] = {
|
2024-08-06 20:13:32 +00:00
|
|
|
.name = "RGBA8(p)",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
|
|
.straight = GDK_MEMORY_R8G8B8A8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 4,
|
|
|
|
.alignment = G_ALIGNOF (guchar),
|
|
|
|
.depth = GDK_MEMORY_U8,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RGBA8,
|
|
|
|
.internal_gles_format = GL_RGBA8,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = GL_SRGB8_ALPHA8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RGBA,
|
|
|
|
.type = GL_UNSIGNED_BYTE,
|
|
|
|
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_R8G8B8A8_UNORM,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_R8G8B8A8_SRGB,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = DRM_FORMAT_ABGR8888,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = r8g8b8a8_premultiplied_to_float,
|
|
|
|
.from_float = r8g8b8a8_premultiplied_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint8_4_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint8_4_linear,
|
2021-09-22 00:01:41 +00:00
|
|
|
},
|
2023-10-20 03:20:15 +00:00
|
|
|
[GDK_MEMORY_A8B8G8R8_PREMULTIPLIED] = {
|
2024-08-06 20:13:32 +00:00
|
|
|
.name = "ABGR8(p)",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_A8B8G8R8_PREMULTIPLIED,
|
|
|
|
.straight = GDK_MEMORY_A8B8G8R8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 4,
|
|
|
|
.alignment = G_ALIGNOF (guchar),
|
|
|
|
.depth = GDK_MEMORY_U8,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RGBA8,
|
|
|
|
.internal_gles_format = GL_RGBA8,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = GL_SRGB8_ALPHA8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RGBA,
|
|
|
|
.type = GDK_GL_UNSIGNED_BYTE_FLIPPED,
|
|
|
|
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
|
|
.rgba_swizzle = { GL_ALPHA, GL_BLUE, GL_GREEN, GL_RED },
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_UNDEFINED,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_UNDEFINED,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = DRM_FORMAT_RGBA8888,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = a8b8g8r8_premultiplied_to_float,
|
|
|
|
.from_float = a8b8g8r8_premultiplied_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint8_4_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint8_4_linear,
|
2023-10-20 03:20:15 +00:00
|
|
|
},
|
2021-09-22 00:01:41 +00:00
|
|
|
[GDK_MEMORY_B8G8R8A8] = {
|
2024-06-09 19:52:18 +00:00
|
|
|
.name = "BGRA8",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_STRAIGHT,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_B8G8R8A8_PREMULTIPLIED,
|
|
|
|
.straight = GDK_MEMORY_B8G8R8A8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 4,
|
|
|
|
.alignment = G_ALIGNOF (guchar),
|
|
|
|
.depth = GDK_MEMORY_U8,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RGBA8,
|
2024-01-16 19:30:56 +00:00
|
|
|
.internal_gles_format = GL_BGRA,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_BGRA,
|
|
|
|
.type = GL_UNSIGNED_BYTE,
|
|
|
|
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = GDK_MEMORY_R8G8B8A8,
|
2023-12-14 15:01:19 +00:00
|
|
|
.rgba_swizzle = { GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA },
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_B8G8R8A8_UNORM,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_B8G8R8A8_SRGB,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = DRM_FORMAT_ARGB8888,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = b8g8r8a8_to_float,
|
|
|
|
.from_float = b8g8r8a8_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint8_4_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint8_4_linear,
|
2021-09-22 00:01:41 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_A8R8G8B8] = {
|
2024-06-09 19:52:18 +00:00
|
|
|
.name = "ARGB8",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_STRAIGHT,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_A8R8G8B8_PREMULTIPLIED,
|
|
|
|
.straight = GDK_MEMORY_A8R8G8B8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 4,
|
|
|
|
.alignment = G_ALIGNOF (guchar),
|
|
|
|
.depth = GDK_MEMORY_U8,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RGBA8,
|
|
|
|
.internal_gles_format = GL_RGBA8,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = GL_SRGB8_ALPHA8,
|
2023-12-09 18:23:28 +00:00
|
|
|
.format = GL_BGRA,
|
2023-12-09 01:42:33 +00:00
|
|
|
.type = GDK_GL_UNSIGNED_BYTE_FLIPPED,
|
|
|
|
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = GDK_MEMORY_R8G8B8A8,
|
|
|
|
.rgba_swizzle = { GL_GREEN, GL_BLUE, GL_ALPHA, GL_RED },
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_UNDEFINED,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_UNDEFINED,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = DRM_FORMAT_BGRA8888,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = a8r8g8b8_to_float,
|
|
|
|
.from_float = a8r8g8b8_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint8_4_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint8_4_linear,
|
2021-09-22 00:01:41 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_R8G8B8A8] = {
|
2024-06-09 19:52:18 +00:00
|
|
|
.name = "RGBA8",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_STRAIGHT,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
|
|
.straight = GDK_MEMORY_R8G8B8A8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 4,
|
|
|
|
.alignment = G_ALIGNOF (guchar),
|
|
|
|
.depth = GDK_MEMORY_U8,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RGBA8,
|
|
|
|
.internal_gles_format = GL_RGBA8,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = GL_SRGB8_ALPHA8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RGBA,
|
|
|
|
.type = GL_UNSIGNED_BYTE,
|
|
|
|
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_R8G8B8A8_UNORM,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_R8G8B8A8_SRGB,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = DRM_FORMAT_ABGR8888,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = r8g8b8a8_to_float,
|
|
|
|
.from_float = r8g8b8a8_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint8_4_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint8_4_linear,
|
2021-09-22 00:01:41 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_A8B8G8R8] = {
|
2024-06-09 19:52:18 +00:00
|
|
|
.name = "ABGR8",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_STRAIGHT,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_A8B8G8R8_PREMULTIPLIED,
|
|
|
|
.straight = GDK_MEMORY_A8B8G8R8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 4,
|
|
|
|
.alignment = G_ALIGNOF (guchar),
|
|
|
|
.depth = GDK_MEMORY_U8,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RGBA8,
|
|
|
|
.internal_gles_format = GL_RGBA8,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = GL_SRGB8_ALPHA8,
|
2023-12-09 18:23:28 +00:00
|
|
|
.format = GL_RGBA,
|
2023-12-09 01:42:33 +00:00
|
|
|
.type = GDK_GL_UNSIGNED_BYTE_FLIPPED,
|
|
|
|
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = GDK_MEMORY_R8G8B8A8,
|
|
|
|
.rgba_swizzle = { GL_ALPHA, GL_BLUE, GL_GREEN, GL_RED },
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_UNDEFINED,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_UNDEFINED,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = DRM_FORMAT_RGBA8888,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = a8b8g8r8_to_float,
|
|
|
|
.from_float = a8b8g8r8_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint8_4_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint8_4_linear,
|
2023-10-20 11:33:46 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_B8G8R8X8] = {
|
2024-06-09 19:52:18 +00:00
|
|
|
.name = "BGRX8",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_OPAQUE,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_B8G8R8X8,
|
|
|
|
.straight = GDK_MEMORY_B8G8R8X8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 4,
|
|
|
|
.alignment = G_ALIGNOF (guchar),
|
|
|
|
.depth = GDK_MEMORY_U8,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RGBA8,
|
2024-01-16 19:30:56 +00:00
|
|
|
.internal_gles_format = GL_BGRA,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_BGRA,
|
|
|
|
.type = GL_UNSIGNED_BYTE,
|
|
|
|
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ONE },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = GDK_MEMORY_R8G8B8X8,
|
2023-12-14 15:01:19 +00:00
|
|
|
.rgba_swizzle = { GL_BLUE, GL_GREEN, GL_RED, GL_ONE },
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_B8G8R8A8_UNORM,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_B8G8R8A8_SRGB,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = DRM_FORMAT_XRGB8888,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = b8g8r8x8_to_float,
|
|
|
|
.from_float = b8g8r8x8_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint8_4_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint8_4_linear,
|
2023-10-20 11:33:46 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_X8R8G8B8] = {
|
2024-06-09 19:52:18 +00:00
|
|
|
.name = "XRGB8",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_OPAQUE,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_X8R8G8B8,
|
|
|
|
.straight = GDK_MEMORY_X8R8G8B8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 4,
|
|
|
|
.alignment = G_ALIGNOF (guchar),
|
|
|
|
.depth = GDK_MEMORY_U8,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RGBA8,
|
|
|
|
.internal_gles_format = GL_RGBA8,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = GL_SRGB8_ALPHA8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_BGRA,
|
|
|
|
.type = GDK_GL_UNSIGNED_BYTE_FLIPPED,
|
|
|
|
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ONE },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = GDK_MEMORY_R8G8B8A8,
|
|
|
|
.rgba_swizzle = { GL_GREEN, GL_BLUE, GL_ALPHA, GL_ONE },
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_UNDEFINED,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_UNDEFINED,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = DRM_FORMAT_BGRX8888,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = x8r8g8b8_to_float,
|
|
|
|
.from_float = x8r8g8b8_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint8_4_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint8_4_linear,
|
2023-10-20 11:33:46 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_R8G8B8X8] = {
|
2024-06-09 19:52:18 +00:00
|
|
|
.name = "RGBX8",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_OPAQUE,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_R8G8B8X8,
|
|
|
|
.straight = GDK_MEMORY_R8G8B8X8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 4,
|
|
|
|
.alignment = G_ALIGNOF (guchar),
|
|
|
|
.depth = GDK_MEMORY_U8,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RGBA8,
|
|
|
|
.internal_gles_format = GL_RGBA8,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = GL_SRGB8_ALPHA8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RGBA,
|
|
|
|
.type = GL_UNSIGNED_BYTE,
|
|
|
|
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ONE },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_R8G8B8A8_UNORM,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_R8G8B8A8_SRGB,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = DRM_FORMAT_XBGR8888,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = r8g8b8x8_to_float,
|
|
|
|
.from_float = r8g8b8x8_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint8_4_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint8_4_linear,
|
2023-10-20 11:33:46 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_X8B8G8R8] = {
|
2024-06-09 19:52:18 +00:00
|
|
|
.name = "XBGR8",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_OPAQUE,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_X8B8G8R8,
|
|
|
|
.straight = GDK_MEMORY_X8B8G8R8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 4,
|
|
|
|
.alignment = G_ALIGNOF (guchar),
|
|
|
|
.depth = GDK_MEMORY_U8,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RGBA8,
|
|
|
|
.internal_gles_format = GL_RGBA8,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = GL_SRGB8_ALPHA8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RGBA,
|
|
|
|
.type = GDK_GL_UNSIGNED_BYTE_FLIPPED,
|
|
|
|
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ONE },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = GDK_MEMORY_R8G8B8A8,
|
|
|
|
.rgba_swizzle = { GL_ALPHA, GL_BLUE, GL_GREEN, GL_ONE },
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_UNDEFINED,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_UNDEFINED,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = DRM_FORMAT_RGBX8888,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = x8b8g8r8_to_float,
|
|
|
|
.from_float = x8b8g8r8_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint8_4_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint8_4_linear,
|
2021-09-22 00:01:41 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_R8G8B8] = {
|
2024-06-09 19:52:18 +00:00
|
|
|
.name = "RGB8",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_OPAQUE,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_R8G8B8,
|
|
|
|
.straight = GDK_MEMORY_R8G8B8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 3,
|
|
|
|
.alignment = G_ALIGNOF (guchar),
|
|
|
|
.depth = GDK_MEMORY_U8,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RGB8,
|
|
|
|
.internal_gles_format = GL_RGB8,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = GL_SRGB8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RGB,
|
|
|
|
.type = GL_UNSIGNED_BYTE,
|
|
|
|
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_R8G8B8_UNORM,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_R8G8B8_SRGB,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = DRM_FORMAT_BGR888,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = r8g8b8_to_float,
|
|
|
|
.from_float = r8g8b8_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint8_3_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint8_3_linear,
|
2021-09-22 00:01:41 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_B8G8R8] = {
|
2024-06-09 19:52:18 +00:00
|
|
|
.name = "BGR8",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_OPAQUE,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_B8G8R8,
|
|
|
|
.straight = GDK_MEMORY_B8G8R8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 3,
|
|
|
|
.alignment = G_ALIGNOF (guchar),
|
|
|
|
.depth = GDK_MEMORY_U8,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RGB8,
|
|
|
|
.internal_gles_format = GL_RGB8,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = GL_SRGB8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_BGR,
|
|
|
|
.type = GL_UNSIGNED_BYTE,
|
|
|
|
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = GDK_MEMORY_R8G8B8,
|
|
|
|
.rgba_swizzle = { GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA },
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_B8G8R8_UNORM,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_B8G8R8_SRGB,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = DRM_FORMAT_RGB888,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = b8g8r8_to_float,
|
|
|
|
.from_float = b8g8r8_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint8_3_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint8_3_linear,
|
2021-09-22 00:01:41 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_R16G16B16] = {
|
2024-06-09 19:52:18 +00:00
|
|
|
.name = "RGB16",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_OPAQUE,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_R16G16B16,
|
|
|
|
.straight = GDK_MEMORY_R16G16B16,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 6,
|
|
|
|
.alignment = G_ALIGNOF (guint16),
|
|
|
|
.depth = GDK_MEMORY_U16,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R16G16B16A16_PREMULTIPLIED,
|
|
|
|
GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
|
|
|
|
GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED,
|
|
|
|
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RGB16,
|
|
|
|
.internal_gles_format = GL_RGB16,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RGB,
|
|
|
|
.type = GL_UNSIGNED_SHORT,
|
|
|
|
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_R16G16B16_UNORM,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_UNDEFINED,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = 0,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = r16g16b16_to_float,
|
|
|
|
.from_float = r16g16b16_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint16_3_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint16_3_linear,
|
2021-09-22 00:01:41 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_R16G16B16A16_PREMULTIPLIED] = {
|
2024-08-06 20:13:32 +00:00
|
|
|
.name = "RGBA16(p)",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED,
|
|
|
|
.straight = GDK_MEMORY_R16G16B16A16,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 8,
|
|
|
|
.alignment = G_ALIGNOF (guint16),
|
|
|
|
.depth = GDK_MEMORY_U16,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
|
|
|
|
GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED,
|
|
|
|
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RGBA16,
|
|
|
|
.internal_gles_format = GL_RGBA16,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RGBA,
|
|
|
|
.type = GL_UNSIGNED_SHORT,
|
|
|
|
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_R16G16B16A16_UNORM,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_UNDEFINED,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = DRM_FORMAT_ABGR16161616,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = r16g16b16a16_to_float,
|
|
|
|
.from_float = r16g16b16a16_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint16_4_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint16_4_linear,
|
2021-09-22 00:01:41 +00:00
|
|
|
},
|
2021-09-26 14:47:34 +00:00
|
|
|
[GDK_MEMORY_R16G16B16A16] = {
|
2024-06-09 19:52:18 +00:00
|
|
|
.name = "RGBA16",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_STRAIGHT,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED,
|
|
|
|
.straight = GDK_MEMORY_R16G16B16A16,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 8,
|
|
|
|
.alignment = G_ALIGNOF (guint16),
|
|
|
|
.depth = GDK_MEMORY_U16,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R32G32B32A32_FLOAT,
|
|
|
|
GDK_MEMORY_R16G16B16A16_FLOAT,
|
|
|
|
GDK_MEMORY_R8G8B8A8,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RGBA16,
|
|
|
|
.internal_gles_format = GL_RGBA16,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RGBA,
|
|
|
|
.type = GL_UNSIGNED_SHORT,
|
|
|
|
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_R16G16B16A16_UNORM,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_UNDEFINED,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = DRM_FORMAT_ABGR16161616,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = r16g16b16a16_to_float,
|
|
|
|
.from_float = r16g16b16a16_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint16_4_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint16_4_linear,
|
2021-09-26 14:47:34 +00:00
|
|
|
},
|
2021-09-22 00:01:41 +00:00
|
|
|
[GDK_MEMORY_R16G16B16_FLOAT] = {
|
2024-06-09 19:52:18 +00:00
|
|
|
.name = "RGBA16f",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_OPAQUE,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_R16G16B16_FLOAT,
|
|
|
|
.straight = GDK_MEMORY_R16G16B16_FLOAT,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 6,
|
|
|
|
.alignment = G_ALIGNOF (guint16),
|
|
|
|
.depth = GDK_MEMORY_FLOAT16,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED,
|
|
|
|
GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
|
|
|
|
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RGB16F,
|
|
|
|
.internal_gles_format = GL_RGB16F,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RGB,
|
|
|
|
.type = GL_HALF_FLOAT,
|
|
|
|
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_R16G16B16_SFLOAT,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_UNDEFINED,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = 0,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = r16g16b16_float_to_float,
|
|
|
|
.from_float = r16g16b16_float_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_half_float_3_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_half_float_3_linear,
|
2021-09-22 00:01:41 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED] = {
|
2024-08-06 20:13:32 +00:00
|
|
|
.name = "RGBA16f(p)",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED,
|
|
|
|
.straight = GDK_MEMORY_R16G16B16A16_FLOAT,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 8,
|
|
|
|
.alignment = G_ALIGNOF (guint16),
|
|
|
|
.depth = GDK_MEMORY_FLOAT16,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
|
|
|
|
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RGBA16F,
|
|
|
|
.internal_gles_format = GL_RGBA16F,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RGBA,
|
|
|
|
.type = GL_HALF_FLOAT,
|
|
|
|
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_R16G16B16A16_SFLOAT,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_UNDEFINED,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = DRM_FORMAT_ABGR16161616F,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = r16g16b16a16_float_to_float,
|
|
|
|
.from_float = r16g16b16a16_float_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_half_float_4_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_half_float_4_linear,
|
2021-09-22 00:01:41 +00:00
|
|
|
},
|
2021-09-26 14:47:34 +00:00
|
|
|
[GDK_MEMORY_R16G16B16A16_FLOAT] = {
|
2024-06-09 19:52:18 +00:00
|
|
|
.name = "RGBA16f",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_STRAIGHT,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED,
|
|
|
|
.straight = GDK_MEMORY_R16G16B16A16_FLOAT,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 8,
|
|
|
|
.alignment = G_ALIGNOF (guint16),
|
|
|
|
.depth = GDK_MEMORY_FLOAT16,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R32G32B32A32_FLOAT,
|
|
|
|
GDK_MEMORY_R8G8B8A8,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RGBA16F,
|
|
|
|
.internal_gles_format = GL_RGBA16F,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RGBA,
|
|
|
|
.type = GL_HALF_FLOAT,
|
|
|
|
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_R16G16B16A16_SFLOAT,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_UNDEFINED,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = DRM_FORMAT_ABGR16161616F,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = r16g16b16a16_float_to_float,
|
|
|
|
.from_float = r16g16b16a16_float_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_half_float_4_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_half_float_4_linear,
|
2021-09-26 14:47:34 +00:00
|
|
|
},
|
2021-09-22 00:01:41 +00:00
|
|
|
[GDK_MEMORY_R32G32B32_FLOAT] = {
|
2024-06-09 19:52:18 +00:00
|
|
|
.name = "RGB32f",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_OPAQUE,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_R32G32B32_FLOAT,
|
|
|
|
.straight = GDK_MEMORY_R32G32B32_FLOAT,
|
2021-09-22 00:01:41 +00:00
|
|
|
12,
|
2023-12-09 01:42:33 +00:00
|
|
|
.alignment = G_ALIGNOF (float),
|
|
|
|
.depth = GDK_MEMORY_FLOAT32,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
|
|
|
|
GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED,
|
|
|
|
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RGB32F,
|
|
|
|
.internal_gles_format = GL_RGB32F,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RGB,
|
|
|
|
.type = GL_FLOAT,
|
|
|
|
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_R32G32B32_SFLOAT,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_UNDEFINED,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = 0,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = r32g32b32_float_to_float,
|
|
|
|
.from_float = r32g32b32_float_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_float_3_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_float_3_linear,
|
2021-09-22 00:01:41 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED] = {
|
2024-08-06 20:13:32 +00:00
|
|
|
.name = "RGBA32f(p)",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
|
|
|
|
.straight = GDK_MEMORY_R32G32B32A32_FLOAT,
|
2021-09-22 00:01:41 +00:00
|
|
|
16,
|
2023-12-09 01:42:33 +00:00
|
|
|
.alignment = G_ALIGNOF (float),
|
|
|
|
.depth = GDK_MEMORY_FLOAT32,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED,
|
|
|
|
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RGBA32F,
|
|
|
|
.internal_gles_format = GL_RGBA32F,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RGBA,
|
|
|
|
.type = GL_FLOAT,
|
|
|
|
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_UNDEFINED,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = 0,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = r32g32b32a32_float_to_float,
|
|
|
|
.from_float = r32g32b32a32_float_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_float_4_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_float_4_linear,
|
2021-09-26 14:47:34 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_R32G32B32A32_FLOAT] = {
|
2024-06-09 19:52:18 +00:00
|
|
|
.name = "RGBA32f",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_STRAIGHT,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
|
|
|
|
.straight = GDK_MEMORY_R32G32B32A32_FLOAT,
|
2021-09-26 14:47:34 +00:00
|
|
|
16,
|
2023-12-09 01:42:33 +00:00
|
|
|
.alignment = G_ALIGNOF (float),
|
|
|
|
.depth = GDK_MEMORY_FLOAT32,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R16G16B16A16_FLOAT,
|
|
|
|
GDK_MEMORY_R8G8B8A8,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RGBA32F,
|
|
|
|
.internal_gles_format = GL_RGBA32F,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RGBA,
|
|
|
|
.type = GL_FLOAT,
|
|
|
|
.swizzle = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_UNDEFINED,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = 0,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = r32g32b32a32_float_to_float,
|
|
|
|
.from_float = r32g32b32a32_float_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_float_4_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_float_4_linear,
|
2023-05-26 12:38:25 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_G8A8_PREMULTIPLIED] = {
|
2024-08-06 20:13:32 +00:00
|
|
|
.name = "GA8(p)",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_G8A8_PREMULTIPLIED,
|
|
|
|
.straight = GDK_MEMORY_G8A8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 2,
|
|
|
|
.alignment = G_ALIGNOF (guchar),
|
|
|
|
.depth = GDK_MEMORY_U8,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RG8,
|
|
|
|
.internal_gles_format = GL_RG8,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RG,
|
|
|
|
.type = GL_UNSIGNED_BYTE,
|
|
|
|
.swizzle = { GL_RED, GL_RED, GL_RED, GL_GREEN },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_R8G8_UNORM,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_UNDEFINED,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = 0,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = g8a8_premultiplied_to_float,
|
|
|
|
.from_float = g8a8_premultiplied_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint8_2_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint8_2_linear,
|
2023-05-26 12:38:25 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_G8A8] = {
|
2024-06-09 19:52:18 +00:00
|
|
|
.name = "GA8",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_STRAIGHT,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_G8A8_PREMULTIPLIED,
|
|
|
|
.straight = GDK_MEMORY_G8A8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 2,
|
|
|
|
.alignment = G_ALIGNOF (guchar),
|
|
|
|
.depth = GDK_MEMORY_U8,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R8G8B8A8,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RG8,
|
|
|
|
.internal_gles_format = GL_RG8,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RG,
|
|
|
|
.type = GL_UNSIGNED_BYTE,
|
|
|
|
.swizzle = { GL_RED, GL_RED, GL_RED, GL_GREEN },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_R8G8_UNORM,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_UNDEFINED,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = 0,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = g8a8_to_float,
|
|
|
|
.from_float = g8a8_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint8_2_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint8_2_linear,
|
2023-05-26 12:38:25 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_G8] = {
|
2024-06-09 19:52:18 +00:00
|
|
|
.name = "G8",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_OPAQUE,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_G8,
|
|
|
|
.straight = GDK_MEMORY_G8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 1,
|
|
|
|
.alignment = G_ALIGNOF (guchar),
|
|
|
|
.depth = GDK_MEMORY_U8,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_R8,
|
|
|
|
.internal_gles_format = GL_R8,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RED,
|
|
|
|
.type = GL_UNSIGNED_BYTE,
|
|
|
|
.swizzle = { GL_RED, GL_RED, GL_RED, GL_ONE },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_R8_UNORM,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_R8_SRGB,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = DRM_FORMAT_R8,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = g8_to_float,
|
|
|
|
.from_float = g8_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint8_1_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint8_1_linear,
|
2023-05-26 12:38:25 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_G16A16_PREMULTIPLIED] = {
|
2024-08-06 20:13:32 +00:00
|
|
|
.name = "GA16(p)",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_G16A16_PREMULTIPLIED,
|
|
|
|
.straight = GDK_MEMORY_G16A16,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 4,
|
|
|
|
.alignment = G_ALIGNOF (guint16),
|
|
|
|
.depth = GDK_MEMORY_U16,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R16G16B16A16_PREMULTIPLIED,
|
|
|
|
GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
|
|
|
|
GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED,
|
|
|
|
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RG16,
|
|
|
|
.internal_gles_format = GL_RG16,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RG,
|
|
|
|
.type = GL_UNSIGNED_SHORT,
|
|
|
|
.swizzle = { GL_RED, GL_RED, GL_RED, GL_GREEN },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_R16G16_UNORM,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_UNDEFINED,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = 0,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = g16a16_premultiplied_to_float,
|
|
|
|
.from_float = g16a16_premultiplied_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint16_2_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint16_2_linear,
|
2023-05-26 12:38:25 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_G16A16] = {
|
2024-06-09 19:52:18 +00:00
|
|
|
.name = "GA16",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_STRAIGHT,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_G16A16_PREMULTIPLIED,
|
|
|
|
.straight = GDK_MEMORY_G16A16,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 4,
|
|
|
|
.alignment = G_ALIGNOF (guint16),
|
|
|
|
.depth = GDK_MEMORY_U16,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R16G16B16A16,
|
|
|
|
GDK_MEMORY_R32G32B32A32_FLOAT,
|
|
|
|
GDK_MEMORY_R16G16B16A16_FLOAT,
|
|
|
|
GDK_MEMORY_R8G8B8A8,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_RG16,
|
|
|
|
.internal_gles_format = GL_RG16,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RG,
|
|
|
|
.type = GL_UNSIGNED_SHORT,
|
|
|
|
.swizzle = { GL_RED, GL_RED, GL_RED, GL_GREEN },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_R16G16_UNORM,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_UNDEFINED,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = 0,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = g16a16_to_float,
|
|
|
|
.from_float = g16a16_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint16_2_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint16_2_linear,
|
2023-05-26 12:38:25 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_G16] = {
|
2024-06-09 19:52:18 +00:00
|
|
|
.name = "G16",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_OPAQUE,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_G16,
|
|
|
|
.straight = GDK_MEMORY_G16,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 2,
|
|
|
|
.alignment = G_ALIGNOF (guint16),
|
|
|
|
.depth = GDK_MEMORY_U16,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R16G16B16A16_PREMULTIPLIED,
|
|
|
|
GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
|
|
|
|
GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED,
|
|
|
|
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_R16,
|
|
|
|
.internal_gles_format = GL_R16,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RED,
|
|
|
|
.type = GL_UNSIGNED_SHORT,
|
|
|
|
.swizzle = { GL_RED, GL_RED, GL_RED, GL_ONE },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_R16_UNORM,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_UNDEFINED,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = DRM_FORMAT_R16,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = g16_to_float,
|
|
|
|
.from_float = g16_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint16_1_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint16_1_linear,
|
2023-05-26 12:38:25 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_A8] = {
|
2024-06-09 19:52:18 +00:00
|
|
|
.name = "A8",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_A8,
|
|
|
|
.straight = GDK_MEMORY_A8,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 1,
|
|
|
|
.alignment = G_ALIGNOF (guchar),
|
|
|
|
.depth = GDK_MEMORY_U8,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_R8,
|
|
|
|
.internal_gles_format = GL_R8,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RED,
|
|
|
|
.type = GL_UNSIGNED_BYTE,
|
|
|
|
.swizzle = { GL_RED, GL_RED, GL_RED, GL_RED },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_R8_UNORM,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_UNDEFINED,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = 0,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = a8_to_float,
|
|
|
|
.from_float = a8_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint8_1_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint8_1_linear,
|
2023-05-26 12:38:25 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_A16] = {
|
2024-06-09 19:52:18 +00:00
|
|
|
.name = "A16",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_A16,
|
|
|
|
.straight = GDK_MEMORY_A16,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 2,
|
|
|
|
.alignment = G_ALIGNOF (guint16),
|
|
|
|
.depth = GDK_MEMORY_U16,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R16G16B16A16_PREMULTIPLIED,
|
|
|
|
GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
|
|
|
|
GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED,
|
|
|
|
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_R16,
|
|
|
|
.internal_gles_format = GL_R16,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RED,
|
|
|
|
.type = GL_UNSIGNED_SHORT,
|
|
|
|
.swizzle = { GL_RED, GL_RED, GL_RED, GL_RED },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_R16_UNORM,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_UNDEFINED,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = 0,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = a16_to_float,
|
|
|
|
.from_float = a16_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_guint16_1_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_guint16_1_linear,
|
2023-07-21 01:02:33 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_A16_FLOAT] = {
|
2024-06-09 19:52:18 +00:00
|
|
|
.name = "A16f",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_A16_FLOAT,
|
|
|
|
.straight = GDK_MEMORY_A16_FLOAT,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 2,
|
|
|
|
.alignment = G_ALIGNOF (guint16),
|
|
|
|
.depth = GDK_MEMORY_FLOAT16,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED,
|
|
|
|
GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
|
|
|
|
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_R16F,
|
|
|
|
.internal_gles_format = GL_R16F,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RED,
|
|
|
|
.type = GL_HALF_FLOAT,
|
|
|
|
.swizzle = { GL_RED, GL_RED, GL_RED, GL_RED },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_R16_SFLOAT,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_UNDEFINED,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = 0,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = a16_float_to_float,
|
|
|
|
.from_float = a16_float_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_half_float_1_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_half_float_1_linear,
|
2023-07-21 01:02:33 +00:00
|
|
|
},
|
|
|
|
[GDK_MEMORY_A32_FLOAT] = {
|
2024-06-09 19:52:18 +00:00
|
|
|
.name = "A32f",
|
2023-12-09 01:42:33 +00:00
|
|
|
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
2023-12-11 03:20:32 +00:00
|
|
|
.premultiplied = GDK_MEMORY_A32_FLOAT,
|
|
|
|
.straight = GDK_MEMORY_A32_FLOAT,
|
2023-12-09 01:42:33 +00:00
|
|
|
.bytes_per_pixel = 4,
|
|
|
|
.alignment = G_ALIGNOF (float),
|
|
|
|
.depth = GDK_MEMORY_FLOAT32,
|
2023-12-11 03:23:16 +00:00
|
|
|
.fallbacks = (GdkMemoryFormat[]) {
|
|
|
|
GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
|
|
|
|
GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED,
|
|
|
|
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
|
|
-1,
|
|
|
|
},
|
2023-12-09 01:42:33 +00:00
|
|
|
.gl = {
|
2024-01-16 19:12:00 +00:00
|
|
|
.internal_gl_format = GL_R32F,
|
|
|
|
.internal_gles_format = GL_R32F,
|
2024-06-17 20:10:24 +00:00
|
|
|
.internal_srgb_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
.format = GL_RED,
|
|
|
|
.type = GL_FLOAT,
|
|
|
|
.swizzle = { GL_RED, GL_RED, GL_RED, GL_RED },
|
2023-12-09 06:17:51 +00:00
|
|
|
.rgba_format = -1,
|
2023-12-09 01:42:33 +00:00
|
|
|
},
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
.vk_format = VK_FORMAT_R32_SFLOAT,
|
2024-06-17 20:10:02 +00:00
|
|
|
.vk_srgb_format = VK_FORMAT_UNDEFINED,
|
2023-12-16 09:27:24 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
.dmabuf_fourcc = 0,
|
2023-12-15 07:27:09 +00:00
|
|
|
#endif
|
2023-12-09 01:42:33 +00:00
|
|
|
.to_float = a32_float_to_float,
|
|
|
|
.from_float = a32_float_from_float,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.mipmap_nearest = gdk_mipmap_float_1_nearest,
|
|
|
|
.mipmap_linear = gdk_mipmap_float_1_linear,
|
2021-09-22 00:01:41 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-07-21 01:05:40 +00:00
|
|
|
/* if this fails, somebody forgot to add formats above */
|
|
|
|
G_STATIC_ASSERT (G_N_ELEMENTS (memory_formats) == GDK_MEMORY_N_FORMATS);
|
|
|
|
|
2021-09-22 00:01:41 +00:00
|
|
|
gsize
|
|
|
|
gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format)
|
|
|
|
{
|
|
|
|
return memory_formats[format].bytes_per_pixel;
|
|
|
|
}
|
|
|
|
|
2021-09-25 22:22:20 +00:00
|
|
|
GdkMemoryAlpha
|
|
|
|
gdk_memory_format_alpha (GdkMemoryFormat format)
|
|
|
|
{
|
|
|
|
return memory_formats[format].alpha;
|
|
|
|
}
|
|
|
|
|
2023-12-11 03:20:32 +00:00
|
|
|
GdkMemoryFormat
|
|
|
|
gdk_memory_format_get_premultiplied (GdkMemoryFormat format)
|
|
|
|
{
|
|
|
|
return memory_formats[format].premultiplied;
|
|
|
|
}
|
|
|
|
|
|
|
|
GdkMemoryFormat
|
|
|
|
gdk_memory_format_get_straight (GdkMemoryFormat format)
|
|
|
|
{
|
|
|
|
return memory_formats[format].straight;
|
|
|
|
}
|
|
|
|
|
2021-09-22 00:01:41 +00:00
|
|
|
gsize
|
|
|
|
gdk_memory_format_alignment (GdkMemoryFormat format)
|
|
|
|
{
|
|
|
|
return memory_formats[format].alignment;
|
|
|
|
}
|
|
|
|
|
2023-12-11 03:23:16 +00:00
|
|
|
/*
|
|
|
|
* gdk_memory_format_get_fallbacks:
|
|
|
|
* @format: a format
|
|
|
|
*
|
|
|
|
* Gets a list of fallback formats to use for @format.
|
|
|
|
*
|
2023-12-13 17:44:09 +00:00
|
|
|
* These formats are RGBA formats that ideally have a higher depth
|
|
|
|
* than the given format. They will always include a guaranteed
|
|
|
|
* supported format though, even if it is of lower quality (unless
|
|
|
|
* @format is already guaranteed supported).
|
2023-12-11 03:23:16 +00:00
|
|
|
*
|
|
|
|
* Fallbacks will use the same alpha format, ie a premultiplied
|
|
|
|
* format will never fall back to a straight alpha format and
|
2023-12-13 17:44:09 +00:00
|
|
|
* vice versa. Either may fall back to an opaque format. Opaque
|
|
|
|
* formats will fall back to premultiplied formats only.
|
2023-12-11 03:23:16 +00:00
|
|
|
*
|
2023-12-13 17:44:09 +00:00
|
|
|
* Use gdk_memory_format_get_premultiplied() and
|
|
|
|
* gdk_memory_format_get_straight() to transition between
|
|
|
|
* premultiplied and straight alpha if you need to.
|
2023-12-11 03:23:16 +00:00
|
|
|
*
|
2023-12-13 17:44:09 +00:00
|
|
|
* Use gdk_memory_format_gl_rgba_format() to get an equivalent RGBA
|
|
|
|
* format and swizzle.
|
|
|
|
*
|
|
|
|
* The expected order of operation when looking for supported formats
|
|
|
|
* is the following:
|
|
|
|
*
|
|
|
|
* 1. Try the format itself
|
|
|
|
* 2. If swizzling is supported, try the RGBA format with swizzling
|
|
|
|
* 3. If swizzling is not supported, try the RGBA without swizzling,
|
|
|
|
* and with CPU conversion
|
|
|
|
* 4. Try fallback formats
|
|
|
|
*
|
2023-12-11 03:23:16 +00:00
|
|
|
* Returns: A list of fallbacks, terminated with -1
|
|
|
|
**/
|
|
|
|
const GdkMemoryFormat *
|
|
|
|
gdk_memory_format_get_fallbacks (GdkMemoryFormat format)
|
|
|
|
{
|
|
|
|
return memory_formats[format].fallbacks;
|
|
|
|
}
|
|
|
|
|
2024-07-02 20:46:56 +00:00
|
|
|
gsize
|
|
|
|
gdk_memory_format_min_buffer_size (GdkMemoryFormat format,
|
|
|
|
gsize stride,
|
|
|
|
gsize width,
|
|
|
|
gsize height)
|
|
|
|
{
|
|
|
|
return stride * (height - 1) + width * gdk_memory_format_bytes_per_pixel (format);
|
|
|
|
}
|
|
|
|
|
2021-10-06 15:55:14 +00:00
|
|
|
/*<private>
|
2023-06-15 18:02:46 +00:00
|
|
|
* gdk_memory_format_get_depth:
|
2021-10-06 15:55:14 +00:00
|
|
|
* @format: a memory format
|
2024-06-26 17:40:55 +00:00
|
|
|
* @srgb: whether an SRGB depth should be returned.
|
2021-10-06 15:55:14 +00:00
|
|
|
*
|
2023-06-15 18:02:46 +00:00
|
|
|
* Gets the depth of the individual channels of the format.
|
|
|
|
* See gsk_render_node_prefers_high_depth() for more
|
|
|
|
* information on this.
|
|
|
|
*
|
|
|
|
* Usually renderers want to use higher depth for render
|
|
|
|
* targets to match these formats.
|
2021-10-06 15:55:14 +00:00
|
|
|
*
|
2023-06-15 18:02:46 +00:00
|
|
|
* Returns: The depth of this format
|
2021-10-06 15:55:14 +00:00
|
|
|
**/
|
2023-06-15 18:02:46 +00:00
|
|
|
GdkMemoryDepth
|
2024-06-26 17:40:55 +00:00
|
|
|
gdk_memory_format_get_depth (GdkMemoryFormat format,
|
|
|
|
gboolean srgb)
|
2021-10-06 15:55:14 +00:00
|
|
|
{
|
2024-06-26 17:40:55 +00:00
|
|
|
GdkMemoryDepth depth;
|
|
|
|
|
|
|
|
depth = memory_formats[format].depth;
|
|
|
|
if (depth == GDK_MEMORY_U8 && srgb)
|
|
|
|
depth = GDK_MEMORY_U8_SRGB;
|
|
|
|
|
|
|
|
return depth;
|
2021-10-06 15:55:14 +00:00
|
|
|
}
|
|
|
|
|
2024-08-07 12:21:01 +00:00
|
|
|
const char *
|
|
|
|
gdk_memory_depth_get_name (GdkMemoryDepth depth)
|
|
|
|
{
|
|
|
|
const char *names[] = { "none", "u8", "u8-srgb", "u16", "f16", "f32" };
|
|
|
|
|
|
|
|
return names[depth];
|
|
|
|
}
|
|
|
|
|
2023-06-15 18:27:13 +00:00
|
|
|
/*<private>
|
|
|
|
* gdk_memory_depth_merge:
|
|
|
|
* @depth1: the first depth
|
|
|
|
* @depth2: the second depth
|
|
|
|
*
|
2024-01-08 01:43:26 +00:00
|
|
|
* Returns a depth that can accommodate both given depths
|
2023-06-15 18:27:13 +00:00
|
|
|
* without any loss of precision.
|
|
|
|
*
|
|
|
|
* Returns: The merged depth
|
|
|
|
**/
|
|
|
|
GdkMemoryDepth
|
|
|
|
gdk_memory_depth_merge (GdkMemoryDepth depth1,
|
|
|
|
GdkMemoryDepth depth2)
|
|
|
|
{
|
2024-06-29 00:31:56 +00:00
|
|
|
static const GdkMemoryDepth merged_depths[GDK_N_DEPTHS][GDK_N_DEPTHS] = {
|
2024-07-03 20:40:45 +00:00
|
|
|
/* NONE U8 U8_SRGB U16 FLOAT16 FLOAT32 */
|
|
|
|
[GDK_MEMORY_NONE] = { GDK_MEMORY_NONE, GDK_MEMORY_U8, GDK_MEMORY_U8_SRGB, GDK_MEMORY_U16, GDK_MEMORY_FLOAT16, GDK_MEMORY_FLOAT32 },
|
|
|
|
[GDK_MEMORY_U8] = { GDK_MEMORY_U8, GDK_MEMORY_U8, GDK_MEMORY_FLOAT16, GDK_MEMORY_U16, GDK_MEMORY_FLOAT16, GDK_MEMORY_FLOAT32 },
|
|
|
|
[GDK_MEMORY_U8_SRGB] = { GDK_MEMORY_U8_SRGB, GDK_MEMORY_FLOAT16, GDK_MEMORY_U8_SRGB, GDK_MEMORY_FLOAT32, GDK_MEMORY_FLOAT16, GDK_MEMORY_FLOAT32 },
|
|
|
|
[GDK_MEMORY_U16] = { GDK_MEMORY_U16, GDK_MEMORY_U16, GDK_MEMORY_FLOAT32, GDK_MEMORY_U16, GDK_MEMORY_FLOAT32, GDK_MEMORY_FLOAT32 },
|
|
|
|
[GDK_MEMORY_FLOAT16] = { GDK_MEMORY_FLOAT16, GDK_MEMORY_FLOAT16, GDK_MEMORY_FLOAT16, GDK_MEMORY_FLOAT32, GDK_MEMORY_FLOAT16, GDK_MEMORY_FLOAT32 },
|
|
|
|
[GDK_MEMORY_FLOAT32] = { GDK_MEMORY_FLOAT32, GDK_MEMORY_FLOAT32, GDK_MEMORY_FLOAT32, GDK_MEMORY_FLOAT32, GDK_MEMORY_FLOAT32, GDK_MEMORY_FLOAT32 },
|
2024-06-29 00:31:56 +00:00
|
|
|
};
|
2023-06-15 18:27:13 +00:00
|
|
|
|
2024-06-29 00:31:56 +00:00
|
|
|
g_assert (depth1 < GDK_N_DEPTHS);
|
|
|
|
g_assert (depth2 < GDK_N_DEPTHS);
|
2023-06-15 18:27:13 +00:00
|
|
|
|
2024-06-29 00:31:56 +00:00
|
|
|
return merged_depths[depth1][depth2];
|
2023-06-15 18:27:13 +00:00
|
|
|
}
|
|
|
|
|
2023-12-07 04:49:22 +00:00
|
|
|
/*
|
|
|
|
* gdk_memory_depth_get_format:
|
|
|
|
* @depth: the depth
|
|
|
|
*
|
|
|
|
* Gets the preferred format to use for rendering at the
|
|
|
|
* given depth
|
|
|
|
*
|
|
|
|
* Returns: the format
|
|
|
|
**/
|
|
|
|
GdkMemoryFormat
|
|
|
|
gdk_memory_depth_get_format (GdkMemoryDepth depth)
|
|
|
|
{
|
|
|
|
switch (depth)
|
|
|
|
{
|
2024-07-03 20:40:45 +00:00
|
|
|
case GDK_MEMORY_NONE:
|
2023-12-07 04:49:22 +00:00
|
|
|
case GDK_MEMORY_U8:
|
2024-06-26 17:40:55 +00:00
|
|
|
case GDK_MEMORY_U8_SRGB:
|
2023-12-07 04:49:22 +00:00
|
|
|
return GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
|
|
|
|
case GDK_MEMORY_U16:
|
|
|
|
return GDK_MEMORY_R16G16B16A16_PREMULTIPLIED;
|
|
|
|
case GDK_MEMORY_FLOAT16:
|
|
|
|
return GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED;
|
|
|
|
case GDK_MEMORY_FLOAT32:
|
|
|
|
return GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED;
|
2024-06-26 18:01:13 +00:00
|
|
|
case GDK_N_DEPTHS:
|
2023-12-07 04:49:22 +00:00
|
|
|
default:
|
|
|
|
g_return_val_if_reached (GDK_MEMORY_R8G8B8A8_PREMULTIPLIED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-21 23:11:19 +00:00
|
|
|
/*
|
|
|
|
* gdk_memory_depth_get_alpha_format:
|
|
|
|
* @depth: the depth
|
|
|
|
*
|
|
|
|
* Gets the preferred format to use for rendering masks and other
|
|
|
|
* alpha-only content.
|
|
|
|
*
|
|
|
|
* Returns: the format
|
|
|
|
**/
|
|
|
|
GdkMemoryFormat
|
|
|
|
gdk_memory_depth_get_alpha_format (GdkMemoryDepth depth)
|
|
|
|
{
|
|
|
|
switch (depth)
|
|
|
|
{
|
2024-07-03 20:40:45 +00:00
|
|
|
case GDK_MEMORY_NONE:
|
2023-07-21 23:11:19 +00:00
|
|
|
case GDK_MEMORY_U8:
|
2024-06-26 17:40:55 +00:00
|
|
|
case GDK_MEMORY_U8_SRGB:
|
2023-07-21 23:11:19 +00:00
|
|
|
return GDK_MEMORY_A8;
|
|
|
|
case GDK_MEMORY_U16:
|
|
|
|
return GDK_MEMORY_A16;
|
|
|
|
case GDK_MEMORY_FLOAT16:
|
|
|
|
return GDK_MEMORY_A16_FLOAT;
|
|
|
|
case GDK_MEMORY_FLOAT32:
|
|
|
|
return GDK_MEMORY_A32_FLOAT;
|
2024-06-26 18:01:13 +00:00
|
|
|
case GDK_N_DEPTHS:
|
2023-07-21 23:11:19 +00:00
|
|
|
default:
|
|
|
|
g_return_val_if_reached (GDK_MEMORY_A8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-26 17:40:55 +00:00
|
|
|
gboolean
|
|
|
|
gdk_memory_depth_is_srgb (GdkMemoryDepth depth)
|
|
|
|
{
|
|
|
|
/* Putting a switch here instead of a simple check
|
|
|
|
* so the compiler makes us look here
|
|
|
|
* when adding new formats */
|
|
|
|
|
|
|
|
switch (depth)
|
|
|
|
{
|
|
|
|
case GDK_MEMORY_U8_SRGB:
|
|
|
|
return TRUE;
|
|
|
|
|
2024-07-03 20:40:45 +00:00
|
|
|
case GDK_MEMORY_NONE:
|
2024-06-26 17:40:55 +00:00
|
|
|
case GDK_MEMORY_U8:
|
|
|
|
case GDK_MEMORY_U16:
|
|
|
|
case GDK_MEMORY_FLOAT16:
|
|
|
|
case GDK_MEMORY_FLOAT32:
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case GDK_N_DEPTHS:
|
|
|
|
default:
|
|
|
|
g_return_val_if_reached (GDK_MEMORY_A8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-07 04:49:22 +00:00
|
|
|
void
|
2021-09-25 02:47:45 +00:00
|
|
|
gdk_memory_format_gl_format (GdkMemoryFormat format,
|
2024-01-16 19:10:50 +00:00
|
|
|
gboolean gles,
|
2023-12-11 04:31:32 +00:00
|
|
|
GLint *out_internal_format,
|
2024-06-17 20:10:24 +00:00
|
|
|
GLint *out_internal_srgb_format,
|
2023-12-11 04:31:32 +00:00
|
|
|
GLenum *out_format,
|
|
|
|
GLenum *out_type,
|
2023-08-12 20:17:29 +00:00
|
|
|
GLint out_swizzle[4])
|
2021-09-25 02:47:45 +00:00
|
|
|
{
|
2024-01-16 19:12:00 +00:00
|
|
|
if (gles)
|
|
|
|
*out_internal_format = memory_formats[format].gl.internal_gles_format;
|
|
|
|
else
|
|
|
|
*out_internal_format = memory_formats[format].gl.internal_gl_format;
|
2024-06-17 20:10:24 +00:00
|
|
|
*out_internal_srgb_format = memory_formats[format].gl.internal_srgb_format;
|
2021-09-25 02:47:45 +00:00
|
|
|
*out_format = memory_formats[format].gl.format;
|
|
|
|
*out_type = memory_formats[format].gl.type;
|
2023-08-12 20:17:29 +00:00
|
|
|
memcpy (out_swizzle, memory_formats[format].gl.swizzle, sizeof(GLint) * 4);
|
2021-09-25 02:47:45 +00:00
|
|
|
}
|
|
|
|
|
2023-12-09 06:17:51 +00:00
|
|
|
/*
|
|
|
|
* gdk_memory_format_gl_rgba_format:
|
|
|
|
* @format: The format to query
|
2024-01-16 19:10:50 +00:00
|
|
|
* @gles: TRUE for GLES, FALSE for GL
|
2023-12-09 06:17:51 +00:00
|
|
|
* @out_actual_format: The actual RGBA format
|
|
|
|
* @out_internal_format: the GL internal format
|
2024-06-17 20:10:24 +00:00
|
|
|
* @out_internal_srgb_format: the GL internal format to use for automatic
|
|
|
|
* sRGB<=>linear conversion
|
2023-12-09 06:17:51 +00:00
|
|
|
* @out_format: the GL format
|
|
|
|
* @out_type: the GL type
|
|
|
|
* @out_swizzle: The swizzle to use
|
|
|
|
*
|
|
|
|
* Maps the given format to a GL format that uses RGBA and uses swizzling,
|
|
|
|
* as opposed to trying to find a GL format that is swapped in the right
|
|
|
|
* direction.
|
|
|
|
*
|
|
|
|
* This format is guaranteed equivalent in memory layout to the original
|
|
|
|
* format, so uploading/downloading code can treat them the same.
|
|
|
|
*
|
|
|
|
* Returns: %TRUE if the format exists and is different from the given format.
|
|
|
|
**/
|
|
|
|
gboolean
|
|
|
|
gdk_memory_format_gl_rgba_format (GdkMemoryFormat format,
|
2024-01-16 19:10:50 +00:00
|
|
|
gboolean gles,
|
2023-12-09 06:17:51 +00:00
|
|
|
GdkMemoryFormat *out_actual_format,
|
2023-12-11 04:31:32 +00:00
|
|
|
GLint *out_internal_format,
|
2024-06-17 20:10:24 +00:00
|
|
|
GLint *out_internal_srgb_format,
|
2023-12-11 04:31:32 +00:00
|
|
|
GLenum *out_format,
|
|
|
|
GLenum *out_type,
|
2023-12-09 06:17:51 +00:00
|
|
|
GLint out_swizzle[4])
|
|
|
|
{
|
|
|
|
GdkMemoryFormat actual = memory_formats[format].gl.rgba_format;
|
|
|
|
|
|
|
|
if (actual == -1)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
*out_actual_format = actual;
|
2024-01-16 19:12:00 +00:00
|
|
|
if (gles)
|
|
|
|
*out_internal_format = memory_formats[actual].gl.internal_gles_format;
|
|
|
|
else
|
|
|
|
*out_internal_format = memory_formats[actual].gl.internal_gl_format;
|
2024-06-17 20:10:24 +00:00
|
|
|
*out_internal_srgb_format = memory_formats[actual].gl.internal_srgb_format;
|
2023-12-09 06:17:51 +00:00
|
|
|
*out_format = memory_formats[actual].gl.format;
|
|
|
|
*out_type = memory_formats[actual].gl.type;
|
|
|
|
memcpy (out_swizzle, memory_formats[format].gl.rgba_swizzle, sizeof(GLint) * 4);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2023-12-15 07:27:09 +00:00
|
|
|
#ifdef GDK_RENDERING_VULKAN
|
|
|
|
|
|
|
|
static VkComponentSwizzle
|
|
|
|
vk_swizzle_from_gl_swizzle_one (GLint swizzle)
|
|
|
|
{
|
|
|
|
switch (swizzle)
|
|
|
|
{
|
|
|
|
case GL_RED:
|
|
|
|
return VK_COMPONENT_SWIZZLE_R;
|
|
|
|
case GL_GREEN:
|
|
|
|
return VK_COMPONENT_SWIZZLE_G;
|
|
|
|
case GL_BLUE:
|
|
|
|
return VK_COMPONENT_SWIZZLE_B;
|
|
|
|
case GL_ALPHA:
|
|
|
|
return VK_COMPONENT_SWIZZLE_A;
|
|
|
|
case GL_ZERO:
|
|
|
|
return VK_COMPONENT_SWIZZLE_ZERO;
|
|
|
|
case GL_ONE:
|
|
|
|
return VK_COMPONENT_SWIZZLE_ONE;
|
|
|
|
default:
|
|
|
|
g_assert_not_reached ();
|
|
|
|
return VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
vk_swizzle_from_gl_swizzle (VkComponentMapping *vk_swizzle,
|
|
|
|
const GLint gl_swizzle[4])
|
|
|
|
{
|
|
|
|
vk_swizzle->r = vk_swizzle_from_gl_swizzle_one (gl_swizzle[0]);
|
|
|
|
vk_swizzle->g = vk_swizzle_from_gl_swizzle_one (gl_swizzle[1]);
|
|
|
|
vk_swizzle->b = vk_swizzle_from_gl_swizzle_one (gl_swizzle[2]);
|
|
|
|
vk_swizzle->a = vk_swizzle_from_gl_swizzle_one (gl_swizzle[3]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Vulkan version of gdk_memory_format_gl_format()
|
|
|
|
* Returns VK_FORMAT_UNDEFINED on failure */
|
|
|
|
VkFormat
|
|
|
|
gdk_memory_format_vk_format (GdkMemoryFormat format,
|
|
|
|
VkComponentMapping *out_swizzle)
|
|
|
|
{
|
|
|
|
if (out_swizzle)
|
|
|
|
vk_swizzle_from_gl_swizzle (out_swizzle, memory_formats[format].gl.swizzle);
|
|
|
|
return memory_formats[format].vk_format;
|
|
|
|
}
|
|
|
|
|
2024-06-17 20:10:02 +00:00
|
|
|
/* Gets the matching SRGB version of a VkFormat
|
|
|
|
* Returns VK_FORMAT_UNDEFINED if none exists */
|
|
|
|
VkFormat
|
|
|
|
gdk_memory_format_vk_srgb_format (GdkMemoryFormat format)
|
|
|
|
{
|
|
|
|
return memory_formats[format].vk_srgb_format;
|
|
|
|
}
|
|
|
|
|
2023-12-15 07:27:09 +00:00
|
|
|
/* Vulkan version of gdk_memory_format_gl_rgba_format()
|
|
|
|
* Returns VK_FORMAT_UNDEFINED on failure */
|
|
|
|
VkFormat
|
|
|
|
gdk_memory_format_vk_rgba_format (GdkMemoryFormat format,
|
|
|
|
GdkMemoryFormat *out_rgba_format,
|
|
|
|
VkComponentMapping *out_swizzle)
|
|
|
|
{
|
|
|
|
GdkMemoryFormat actual = memory_formats[format].gl.rgba_format;
|
|
|
|
|
|
|
|
if (actual == -1)
|
|
|
|
return VK_FORMAT_UNDEFINED;
|
|
|
|
|
|
|
|
if (out_rgba_format)
|
|
|
|
*out_rgba_format = actual;
|
|
|
|
if (out_swizzle)
|
|
|
|
vk_swizzle_from_gl_swizzle (out_swizzle, memory_formats[format].gl.rgba_swizzle);
|
|
|
|
return memory_formats[actual].vk_format;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2023-12-16 09:27:24 +00:00
|
|
|
/*
|
|
|
|
* gdk_memory_format_get_dmabuf_fourcc:
|
|
|
|
* @format: The memory format
|
|
|
|
*
|
|
|
|
* Gets the dmabuf fourcc for a given memory format.
|
|
|
|
*
|
|
|
|
* The format is an exact match, so data can be copied between the
|
|
|
|
* dmabuf and data of the format. This is different from the
|
|
|
|
* memoryformat returned by a GdkDmabufTexture, which is just the
|
|
|
|
* closest match.
|
|
|
|
*
|
|
|
|
* Not all formats have a corresponding dmabuf format.
|
|
|
|
* In those cases 0 will be returned.
|
|
|
|
*
|
|
|
|
* If dmabuf support is not compiled in, always returns 0.
|
|
|
|
*
|
|
|
|
* Returns: the fourcc or 0
|
|
|
|
**/
|
|
|
|
guint32
|
|
|
|
gdk_memory_format_get_dmabuf_fourcc (GdkMemoryFormat format)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_DMABUF
|
|
|
|
return memory_formats[format].dmabuf_fourcc;
|
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2024-06-09 19:52:18 +00:00
|
|
|
const char *
|
|
|
|
gdk_memory_format_get_name (GdkMemoryFormat format)
|
|
|
|
{
|
|
|
|
return memory_formats[format].name;
|
|
|
|
}
|
|
|
|
|
2021-09-22 00:01:41 +00:00
|
|
|
static void
|
2024-07-01 04:48:35 +00:00
|
|
|
premultiply (float (*rgba)[4],
|
2021-09-22 00:01:41 +00:00
|
|
|
gsize n)
|
|
|
|
{
|
|
|
|
for (gsize i = 0; i < n; i++)
|
|
|
|
{
|
2024-07-01 04:48:35 +00:00
|
|
|
rgba[i][0] *= rgba[i][3];
|
|
|
|
rgba[i][1] *= rgba[i][3];
|
|
|
|
rgba[i][2] *= rgba[i][3];
|
2021-09-22 00:01:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2024-07-01 04:48:35 +00:00
|
|
|
unpremultiply (float (*rgba)[4],
|
|
|
|
gsize n)
|
2021-09-22 00:01:41 +00:00
|
|
|
{
|
|
|
|
for (gsize i = 0; i < n; i++)
|
|
|
|
{
|
2024-07-01 04:48:35 +00:00
|
|
|
if (rgba[i][3] > 1/255.0)
|
2021-09-22 00:01:41 +00:00
|
|
|
{
|
2024-07-01 04:48:35 +00:00
|
|
|
rgba[i][0] /= rgba[i][3];
|
|
|
|
rgba[i][1] /= rgba[i][3];
|
|
|
|
rgba[i][2] /= rgba[i][3];
|
2021-09-22 00:01:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-27 04:13:06 +00:00
|
|
|
typedef void (* FastConversionFunc) (guchar *dest,
|
|
|
|
const guchar *src,
|
|
|
|
gsize n);
|
2024-08-27 04:09:26 +00:00
|
|
|
|
|
|
|
static FastConversionFunc
|
|
|
|
get_fast_conversion_func (GdkMemoryFormat dest_format,
|
|
|
|
GdkMemoryFormat src_format)
|
|
|
|
{
|
|
|
|
if (src_format == GDK_MEMORY_R8G8B8A8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
|
|
|
|
return r8g8b8a8_to_r8g8b8a8_premultiplied;
|
|
|
|
else if (src_format == GDK_MEMORY_B8G8R8A8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
|
|
|
|
return r8g8b8a8_to_b8g8r8a8_premultiplied;
|
|
|
|
else if (src_format == GDK_MEMORY_R8G8B8A8 && dest_format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED)
|
|
|
|
return r8g8b8a8_to_b8g8r8a8_premultiplied;
|
|
|
|
else if (src_format == GDK_MEMORY_B8G8R8A8 && dest_format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED)
|
|
|
|
return r8g8b8a8_to_r8g8b8a8_premultiplied;
|
|
|
|
else if (src_format == GDK_MEMORY_R8G8B8A8 && dest_format == GDK_MEMORY_A8R8G8B8_PREMULTIPLIED)
|
|
|
|
return r8g8b8a8_to_a8r8g8b8_premultiplied;
|
|
|
|
else if (src_format == GDK_MEMORY_B8G8R8A8 && dest_format == GDK_MEMORY_A8R8G8B8_PREMULTIPLIED)
|
|
|
|
return r8g8b8a8_to_a8b8g8r8_premultiplied;
|
|
|
|
else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
|
|
|
|
return r8g8b8_to_r8g8b8a8;
|
|
|
|
else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
|
|
|
|
return r8g8b8_to_b8g8r8a8;
|
|
|
|
else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED)
|
|
|
|
return r8g8b8_to_b8g8r8a8;
|
|
|
|
else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED)
|
|
|
|
return r8g8b8_to_r8g8b8a8;
|
|
|
|
else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_A8R8G8B8_PREMULTIPLIED)
|
|
|
|
return r8g8b8_to_a8r8g8b8;
|
|
|
|
else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_A8R8G8B8_PREMULTIPLIED)
|
|
|
|
return r8g8b8_to_a8b8g8r8;
|
|
|
|
else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_R8G8B8A8)
|
|
|
|
return r8g8b8_to_r8g8b8a8;
|
|
|
|
else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_R8G8B8A8)
|
|
|
|
return r8g8b8_to_b8g8r8a8;
|
|
|
|
else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_B8G8R8A8)
|
|
|
|
return r8g8b8_to_b8g8r8a8;
|
|
|
|
else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_B8G8R8A8)
|
|
|
|
return r8g8b8_to_r8g8b8a8;
|
|
|
|
else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_A8R8G8B8)
|
|
|
|
return r8g8b8_to_a8r8g8b8;
|
|
|
|
else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_A8R8G8B8)
|
|
|
|
return r8g8b8_to_a8b8g8r8;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2024-09-02 01:17:53 +00:00
|
|
|
typedef struct _MemoryConvert MemoryConvert;
|
|
|
|
|
|
|
|
struct _MemoryConvert
|
|
|
|
{
|
|
|
|
guchar *dest_data;
|
|
|
|
gsize dest_stride;
|
|
|
|
GdkMemoryFormat dest_format;
|
|
|
|
GdkColorState *dest_cs;
|
|
|
|
const guchar *src_data;
|
|
|
|
gsize src_stride;
|
|
|
|
GdkMemoryFormat src_format;
|
|
|
|
GdkColorState *src_cs;
|
|
|
|
gsize width;
|
|
|
|
gsize height;
|
|
|
|
|
|
|
|
/* atomic */ int rows_done;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_memory_convert_generic (gpointer data)
|
|
|
|
{
|
|
|
|
MemoryConvert *mc = data;
|
|
|
|
const GdkMemoryFormatDescription *dest_desc = &memory_formats[mc->dest_format];
|
|
|
|
const GdkMemoryFormatDescription *src_desc = &memory_formats[mc->src_format];
|
|
|
|
float (*tmp)[4];
|
|
|
|
GdkFloatColorConvert convert_func = NULL;
|
|
|
|
GdkFloatColorConvert convert_func2 = NULL;
|
|
|
|
gboolean needs_premultiply, needs_unpremultiply;
|
|
|
|
gsize y, n;
|
2024-09-06 16:31:27 +00:00
|
|
|
gint64 before = GDK_PROFILER_CURRENT_TIME;
|
|
|
|
gsize rows;
|
2024-09-02 01:17:53 +00:00
|
|
|
|
|
|
|
convert_func = gdk_color_state_get_convert_to (mc->src_cs, mc->dest_cs);
|
|
|
|
|
|
|
|
if (!convert_func)
|
|
|
|
convert_func2 = gdk_color_state_get_convert_from (mc->dest_cs, mc->src_cs);
|
|
|
|
|
|
|
|
if (!convert_func && !convert_func2)
|
|
|
|
{
|
|
|
|
GdkColorState *connection = GDK_COLOR_STATE_REC2100_LINEAR;
|
|
|
|
convert_func = gdk_color_state_get_convert_to (mc->src_cs, connection);
|
|
|
|
convert_func2 = gdk_color_state_get_convert_from (mc->dest_cs, connection);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (convert_func)
|
|
|
|
{
|
|
|
|
needs_unpremultiply = src_desc->alpha == GDK_MEMORY_ALPHA_PREMULTIPLIED;
|
|
|
|
needs_premultiply = src_desc->alpha != GDK_MEMORY_ALPHA_OPAQUE && dest_desc->alpha != GDK_MEMORY_ALPHA_STRAIGHT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
needs_unpremultiply = src_desc->alpha == GDK_MEMORY_ALPHA_PREMULTIPLIED && dest_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT;
|
|
|
|
needs_premultiply = src_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT && dest_desc->alpha != GDK_MEMORY_ALPHA_STRAIGHT;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = g_malloc (sizeof (*tmp) * mc->width);
|
|
|
|
n = 1;
|
|
|
|
|
2024-09-06 16:31:27 +00:00
|
|
|
for (y = g_atomic_int_add (&mc->rows_done, n), rows = 0;
|
2024-09-02 01:17:53 +00:00
|
|
|
y < mc->height;
|
2024-09-06 16:31:27 +00:00
|
|
|
y = g_atomic_int_add (&mc->rows_done, n), rows++)
|
2024-09-02 01:17:53 +00:00
|
|
|
{
|
|
|
|
const guchar *src_data = mc->src_data + y * mc->src_stride;
|
|
|
|
guchar *dest_data = mc->dest_data + y * mc->dest_stride;
|
|
|
|
|
|
|
|
src_desc->to_float (tmp, src_data, mc->width);
|
|
|
|
|
|
|
|
if (needs_unpremultiply)
|
|
|
|
unpremultiply (tmp, mc->width);
|
|
|
|
|
|
|
|
if (convert_func)
|
|
|
|
convert_func (mc->src_cs, tmp, mc->width);
|
|
|
|
|
|
|
|
if (convert_func2)
|
|
|
|
convert_func2 (mc->dest_cs, tmp, mc->width);
|
|
|
|
|
|
|
|
if (needs_premultiply)
|
|
|
|
premultiply (tmp, mc->width);
|
|
|
|
|
|
|
|
dest_desc->from_float (dest_data, tmp, mc->width);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (tmp);
|
2024-09-06 16:31:27 +00:00
|
|
|
|
|
|
|
ADD_MARK (before,
|
|
|
|
"Memory convert (thread)", "size %lux%lu, %lu rows",
|
|
|
|
mc->width, mc->height, rows);
|
2024-09-02 01:17:53 +00:00
|
|
|
}
|
|
|
|
|
2021-09-22 00:01:41 +00:00
|
|
|
void
|
|
|
|
gdk_memory_convert (guchar *dest_data,
|
|
|
|
gsize dest_stride,
|
|
|
|
GdkMemoryFormat dest_format,
|
2024-07-13 22:51:05 +00:00
|
|
|
GdkColorState *dest_cs,
|
2021-09-22 00:01:41 +00:00
|
|
|
const guchar *src_data,
|
|
|
|
gsize src_stride,
|
|
|
|
GdkMemoryFormat src_format,
|
2024-07-13 22:51:05 +00:00
|
|
|
GdkColorState *src_cs,
|
2021-09-22 00:01:41 +00:00
|
|
|
gsize width,
|
|
|
|
gsize height)
|
|
|
|
{
|
2024-09-02 01:17:53 +00:00
|
|
|
MemoryConvert mc = {
|
|
|
|
.dest_data = dest_data,
|
|
|
|
.dest_stride = dest_stride,
|
|
|
|
.dest_format = dest_format,
|
|
|
|
.dest_cs = dest_cs,
|
|
|
|
.src_data = src_data,
|
|
|
|
.src_stride = src_stride,
|
|
|
|
.src_format = src_format,
|
|
|
|
.src_cs = src_cs,
|
|
|
|
.width = width,
|
|
|
|
.height = height,
|
|
|
|
};
|
2021-09-22 00:01:41 +00:00
|
|
|
|
|
|
|
g_assert (dest_format < GDK_MEMORY_N_FORMATS);
|
|
|
|
g_assert (src_format < GDK_MEMORY_N_FORMATS);
|
2024-06-19 12:24:35 +00:00
|
|
|
/* We don't allow overlap here. If you want to do in-place color state conversions,
|
|
|
|
* use gdk_memory_convert_color_state.
|
|
|
|
*/
|
|
|
|
g_assert (dest_data + gdk_memory_format_min_buffer_size (dest_format, dest_stride, width, height) <= src_data ||
|
|
|
|
src_data + gdk_memory_format_min_buffer_size (src_format, src_stride, width, height) <= dest_data);
|
2021-09-22 00:01:41 +00:00
|
|
|
|
2024-07-13 22:51:05 +00:00
|
|
|
if (src_format == dest_format && gdk_color_state_equal (dest_cs, src_cs))
|
2023-07-19 04:45:00 +00:00
|
|
|
{
|
2024-09-02 01:17:53 +00:00
|
|
|
const GdkMemoryFormatDescription *src_desc = &memory_formats[src_format];
|
2023-07-19 04:45:00 +00:00
|
|
|
gsize bytes_per_row = src_desc->bytes_per_pixel * width;
|
|
|
|
|
|
|
|
if (bytes_per_row == src_stride && bytes_per_row == dest_stride)
|
|
|
|
{
|
|
|
|
memcpy (dest_data, src_data, bytes_per_row * height);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-09-02 01:17:53 +00:00
|
|
|
gsize y;
|
|
|
|
|
2023-07-19 04:45:00 +00:00
|
|
|
for (y = 0; y < height; y++)
|
|
|
|
{
|
|
|
|
memcpy (dest_data, src_data, bytes_per_row);
|
|
|
|
src_data += src_stride;
|
|
|
|
dest_data += dest_stride;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-09-02 01:17:53 +00:00
|
|
|
if (gdk_color_state_equal (dest_cs, src_cs))
|
2022-02-15 19:54:18 +00:00
|
|
|
{
|
2024-08-27 04:09:26 +00:00
|
|
|
FastConversionFunc func;
|
|
|
|
|
|
|
|
func = get_fast_conversion_func (dest_format, src_format);
|
|
|
|
|
|
|
|
if (func != NULL)
|
2022-02-15 19:54:18 +00:00
|
|
|
{
|
2024-09-02 01:17:53 +00:00
|
|
|
gsize y;
|
|
|
|
|
2024-08-27 04:09:26 +00:00
|
|
|
for (y = 0; y < height; y++)
|
|
|
|
{
|
|
|
|
func (dest_data, src_data, width);
|
|
|
|
src_data += src_stride;
|
|
|
|
dest_data += dest_stride;
|
|
|
|
}
|
|
|
|
return;
|
2022-02-15 19:54:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-02 01:17:53 +00:00
|
|
|
gdk_parallel_task_run (gdk_memory_convert_generic, &mc);
|
2021-09-22 00:01:41 +00:00
|
|
|
}
|
2024-06-19 12:24:35 +00:00
|
|
|
|
2024-09-02 01:31:43 +00:00
|
|
|
typedef struct _MemoryConvertColorState MemoryConvertColorState;
|
|
|
|
|
|
|
|
struct _MemoryConvertColorState
|
|
|
|
{
|
|
|
|
guchar *data;
|
|
|
|
gsize stride;
|
|
|
|
GdkMemoryFormat format;
|
|
|
|
GdkColorState *src_cs;
|
|
|
|
GdkColorState *dest_cs;
|
|
|
|
gsize width;
|
|
|
|
gsize height;
|
|
|
|
|
|
|
|
/* atomic */ int rows_done;
|
|
|
|
};
|
|
|
|
|
2024-06-19 23:49:37 +00:00
|
|
|
static const guchar srgb_lookup[] = {
|
|
|
|
0, 12, 21, 28, 33, 38, 42, 46, 49, 52, 55, 58, 61, 63, 66, 68,
|
|
|
|
70, 73, 75, 77, 79, 81, 82, 84, 86, 88, 89, 91, 93, 94, 96, 97,
|
|
|
|
99, 100, 102, 103, 104, 106, 107, 109, 110, 111, 112, 114, 115, 116, 117, 118,
|
|
|
|
120, 121, 122, 123, 124, 125, 126, 127, 129, 130, 131, 132, 133, 134, 135, 136,
|
|
|
|
137, 138, 139, 140, 141, 142, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151,
|
|
|
|
151, 152, 153, 154, 155, 156, 157, 157, 158, 159, 160, 161, 161, 162, 163, 164,
|
|
|
|
165, 165, 166, 167, 168, 168, 169, 170, 171, 171, 172, 173, 174, 174, 175, 176,
|
|
|
|
176, 177, 178, 179, 179, 180, 181, 181, 182, 183, 183, 184, 185, 185, 186, 187,
|
|
|
|
187, 188, 189, 189, 190, 191, 191, 192, 193, 193, 194, 194, 195, 196, 196, 197,
|
|
|
|
197, 198, 199, 199, 200, 201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206,
|
|
|
|
207, 208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 214, 215, 215,
|
|
|
|
216, 217, 217, 218, 218, 219, 219, 220, 220, 221, 221, 222, 222, 223, 223, 224,
|
|
|
|
224, 225, 226, 226, 227, 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232,
|
|
|
|
233, 233, 234, 234, 235, 235, 236, 236, 237, 237, 237, 238, 238, 239, 239, 240,
|
|
|
|
240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 245, 246, 246, 247, 247,
|
|
|
|
248, 248, 249, 249, 250, 250, 251, 251, 251, 252, 252, 253, 253, 254, 254, 255
|
|
|
|
};
|
|
|
|
|
|
|
|
static const guchar srgb_inverse_lookup[] = {
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
|
|
|
|
1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3,
|
|
|
|
3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7,
|
|
|
|
7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12,
|
|
|
|
13, 13, 13, 14, 14, 15, 15, 16, 16, 16, 17, 17, 18, 18, 19, 19,
|
|
|
|
20, 20, 21, 22, 22, 23, 23, 24, 24, 25, 26, 26, 27, 27, 28, 29,
|
|
|
|
29, 30, 31, 31, 32, 33, 33, 34, 35, 36, 36, 37, 38, 38, 39, 40,
|
|
|
|
41, 42, 42, 43, 44, 45, 46, 47, 47, 48, 49, 50, 51, 52, 53, 54,
|
|
|
|
55, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 70,
|
|
|
|
71, 72, 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 85, 87, 88,
|
|
|
|
89, 90, 92, 93, 94, 95, 97, 98, 99, 101, 102, 103, 105, 106, 107, 109,
|
|
|
|
110, 112, 113, 114, 116, 117, 119, 120, 122, 123, 125, 126, 128, 129, 131, 132,
|
|
|
|
134, 135, 137, 139, 140, 142, 144, 145, 147, 148, 150, 152, 153, 155, 157, 159,
|
|
|
|
160, 162, 164, 166, 167, 169, 171, 173, 175, 176, 178, 180, 182, 184, 186, 188,
|
|
|
|
190, 192, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 218, 220,
|
|
|
|
222, 224, 226, 228, 230, 232, 235, 237, 239, 241, 243, 245, 248, 250, 252, 255
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
convert_srgb_to_srgb_linear (guchar *data,
|
|
|
|
gsize n)
|
|
|
|
{
|
|
|
|
for (gsize i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
guint16 r = data[0];
|
|
|
|
guint16 g = data[1];
|
|
|
|
guint16 b = data[2];
|
|
|
|
guchar a = data[3];
|
|
|
|
|
|
|
|
if (a != 0)
|
|
|
|
{
|
|
|
|
r = (r * 255 + a / 2) / a;
|
|
|
|
g = (g * 255 + a / 2) / a;
|
|
|
|
b = (b * 255 + a / 2) / a;
|
|
|
|
|
|
|
|
r = srgb_inverse_lookup[r];
|
|
|
|
g = srgb_inverse_lookup[g];
|
|
|
|
b = srgb_inverse_lookup[b];
|
|
|
|
|
|
|
|
r = r * a + 127;
|
|
|
|
g = g * a + 127;
|
|
|
|
b = b * a + 127;
|
|
|
|
data[0] = (r + (r >> 8) + 1) >> 8;
|
|
|
|
data[1] = (g + (g >> 8) + 1) >> 8;
|
|
|
|
data[2] = (b + (b >> 8) + 1) >> 8;
|
|
|
|
}
|
|
|
|
data += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
convert_srgb_linear_to_srgb (guchar *data,
|
|
|
|
gsize n)
|
|
|
|
{
|
|
|
|
for (gsize i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
guint16 r = data[0];
|
|
|
|
guint16 g = data[1];
|
|
|
|
guint16 b = data[2];
|
|
|
|
guchar a = data[3];
|
|
|
|
|
|
|
|
if (a != 0)
|
|
|
|
{
|
|
|
|
r = (r * 255 + a / 2) / a;
|
|
|
|
g = (g * 255 + a / 2) / a;
|
|
|
|
b = (b * 255 + a / 2) / a;
|
|
|
|
|
|
|
|
r = srgb_lookup[r];
|
|
|
|
g = srgb_lookup[g];
|
|
|
|
b = srgb_lookup[b];
|
|
|
|
|
|
|
|
r = r * a + 127;
|
|
|
|
g = g * a + 127;
|
|
|
|
b = b * a + 127;
|
|
|
|
data[0] = (r + (r >> 8) + 1) >> 8;
|
|
|
|
data[1] = (g + (g >> 8) + 1) >> 8;
|
|
|
|
data[2] = (b + (b >> 8) + 1) >> 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
data += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2024-09-02 01:31:43 +00:00
|
|
|
gdk_memory_convert_color_state_srgb_to_srgb_linear (gpointer data)
|
2024-06-19 23:49:37 +00:00
|
|
|
{
|
2024-09-02 01:31:43 +00:00
|
|
|
MemoryConvertColorState *mc = data;
|
|
|
|
int y;
|
2024-09-06 16:31:27 +00:00
|
|
|
guint64 before = GDK_PROFILER_CURRENT_TIME;
|
|
|
|
gsize rows;
|
2024-09-02 01:31:43 +00:00
|
|
|
|
2024-09-06 16:31:27 +00:00
|
|
|
for (y = g_atomic_int_add (&mc->rows_done, 1), rows = 0;
|
2024-09-02 01:31:43 +00:00
|
|
|
y < mc->height;
|
2024-09-06 16:31:27 +00:00
|
|
|
y = g_atomic_int_add (&mc->rows_done, 1), rows++)
|
2024-06-19 23:49:37 +00:00
|
|
|
{
|
2024-09-02 01:31:43 +00:00
|
|
|
convert_srgb_to_srgb_linear (mc->data + y * mc->stride, mc->width);
|
2024-06-19 23:49:37 +00:00
|
|
|
}
|
2024-09-06 16:31:27 +00:00
|
|
|
|
|
|
|
ADD_MARK (before,
|
|
|
|
"Color state convert srgb->srgb-linear (thread)", "size %lux%lu, %lu rows",
|
|
|
|
mc->width, mc->height, rows);
|
2024-06-19 23:49:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2024-09-02 01:31:43 +00:00
|
|
|
gdk_memory_convert_color_state_srgb_linear_to_srgb (gpointer data)
|
2024-06-19 23:49:37 +00:00
|
|
|
{
|
2024-09-02 01:31:43 +00:00
|
|
|
MemoryConvertColorState *mc = data;
|
|
|
|
int y;
|
2024-09-06 16:31:27 +00:00
|
|
|
guint64 before = GDK_PROFILER_CURRENT_TIME;
|
|
|
|
gsize rows;
|
2024-09-02 01:31:43 +00:00
|
|
|
|
2024-09-06 16:31:27 +00:00
|
|
|
for (y = g_atomic_int_add (&mc->rows_done, 1), rows = 0;
|
2024-09-02 01:31:43 +00:00
|
|
|
y < mc->height;
|
2024-09-06 16:31:27 +00:00
|
|
|
y = g_atomic_int_add (&mc->rows_done, 1), rows++)
|
2024-06-19 23:49:37 +00:00
|
|
|
{
|
2024-09-02 01:31:43 +00:00
|
|
|
convert_srgb_linear_to_srgb (mc->data + y * mc->stride, mc->width);
|
2024-06-19 23:49:37 +00:00
|
|
|
}
|
2024-09-06 16:31:27 +00:00
|
|
|
|
|
|
|
ADD_MARK (before,
|
|
|
|
"Color state convert srgb-linear->srgb (thread)", "size %lux%lu, %lu rows",
|
|
|
|
mc->width, mc->height, rows);
|
2024-06-19 23:49:37 +00:00
|
|
|
}
|
|
|
|
|
2024-09-02 01:31:43 +00:00
|
|
|
static void
|
|
|
|
gdk_memory_convert_color_state_generic (gpointer user_data)
|
2024-06-19 12:24:35 +00:00
|
|
|
{
|
2024-09-02 01:31:43 +00:00
|
|
|
MemoryConvertColorState *mc = user_data;
|
|
|
|
const GdkMemoryFormatDescription *desc = &memory_formats[mc->format];
|
2024-07-15 02:49:45 +00:00
|
|
|
GdkFloatColorConvert convert_func = NULL;
|
|
|
|
GdkFloatColorConvert convert_func2 = NULL;
|
2024-06-19 12:24:35 +00:00
|
|
|
float (*tmp)[4];
|
2024-09-02 01:31:43 +00:00
|
|
|
int y;
|
2024-09-06 16:31:27 +00:00
|
|
|
guint64 before = GDK_PROFILER_CURRENT_TIME;
|
|
|
|
gsize rows;
|
2024-06-19 12:24:35 +00:00
|
|
|
|
2024-09-02 01:31:43 +00:00
|
|
|
convert_func = gdk_color_state_get_convert_to (mc->src_cs, mc->dest_cs);
|
2024-07-15 02:49:45 +00:00
|
|
|
|
|
|
|
if (!convert_func)
|
|
|
|
{
|
2024-09-02 01:31:43 +00:00
|
|
|
convert_func2 = gdk_color_state_get_convert_from (mc->dest_cs, mc->src_cs);
|
2024-07-15 02:49:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!convert_func && !convert_func2)
|
|
|
|
{
|
2024-07-29 03:40:59 +00:00
|
|
|
GdkColorState *connection = GDK_COLOR_STATE_REC2100_LINEAR;
|
2024-09-02 01:31:43 +00:00
|
|
|
convert_func = gdk_color_state_get_convert_to (mc->src_cs, connection);
|
|
|
|
convert_func2 = gdk_color_state_get_convert_from (mc->dest_cs, connection);
|
2024-07-15 02:49:45 +00:00
|
|
|
}
|
2024-06-19 12:24:35 +00:00
|
|
|
|
2024-09-02 01:31:43 +00:00
|
|
|
tmp = g_malloc (sizeof (*tmp) * mc->width);
|
2024-06-19 12:24:35 +00:00
|
|
|
|
2024-09-06 16:31:27 +00:00
|
|
|
for (y = g_atomic_int_add (&mc->rows_done, 1), rows = 0;
|
2024-09-02 01:31:43 +00:00
|
|
|
y < mc->height;
|
2024-09-06 16:31:27 +00:00
|
|
|
y = g_atomic_int_add (&mc->rows_done, 1), rows++)
|
2024-06-19 12:24:35 +00:00
|
|
|
{
|
2024-09-02 01:31:43 +00:00
|
|
|
guchar *data = mc->data + y * mc->stride;
|
|
|
|
|
|
|
|
desc->to_float (tmp, data, mc->width);
|
2024-06-19 12:24:35 +00:00
|
|
|
|
|
|
|
if (desc->alpha == GDK_MEMORY_ALPHA_PREMULTIPLIED)
|
2024-09-02 01:31:43 +00:00
|
|
|
unpremultiply (tmp, mc->width);
|
2024-06-19 12:24:35 +00:00
|
|
|
|
2024-07-15 02:49:45 +00:00
|
|
|
if (convert_func)
|
2024-09-02 01:31:43 +00:00
|
|
|
convert_func (mc->src_cs, tmp, mc->width);
|
2024-07-29 03:40:59 +00:00
|
|
|
|
2024-07-15 02:49:45 +00:00
|
|
|
if (convert_func2)
|
2024-09-02 01:31:43 +00:00
|
|
|
convert_func2 (mc->dest_cs, tmp, mc->width);
|
2024-06-19 12:24:35 +00:00
|
|
|
|
|
|
|
if (desc->alpha == GDK_MEMORY_ALPHA_PREMULTIPLIED)
|
2024-09-02 01:31:43 +00:00
|
|
|
premultiply (tmp, mc->width);
|
2024-06-19 12:24:35 +00:00
|
|
|
|
2024-09-02 01:31:43 +00:00
|
|
|
desc->from_float (data, tmp, mc->width);
|
2024-06-19 12:24:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
g_free (tmp);
|
2024-09-06 16:31:27 +00:00
|
|
|
|
|
|
|
ADD_MARK (before,
|
|
|
|
"Color state convert (thread)", "size %lux%lu, %lu rows",
|
|
|
|
mc->width, mc->height, rows);
|
2024-06-19 12:24:35 +00:00
|
|
|
}
|
2024-09-02 01:31:43 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
gdk_memory_convert_color_state (guchar *data,
|
|
|
|
gsize stride,
|
|
|
|
GdkMemoryFormat format,
|
|
|
|
GdkColorState *src_cs,
|
|
|
|
GdkColorState *dest_cs,
|
|
|
|
gsize width,
|
|
|
|
gsize height)
|
|
|
|
{
|
|
|
|
MemoryConvertColorState mc = {
|
|
|
|
.data = data,
|
|
|
|
.stride = stride,
|
|
|
|
.format = format,
|
|
|
|
.src_cs = src_cs,
|
|
|
|
.dest_cs = dest_cs,
|
|
|
|
.width = width,
|
|
|
|
.height = height,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (gdk_color_state_equal (src_cs, dest_cs))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED &&
|
|
|
|
src_cs == GDK_COLOR_STATE_SRGB &&
|
|
|
|
dest_cs == GDK_COLOR_STATE_SRGB_LINEAR)
|
|
|
|
{
|
|
|
|
gdk_parallel_task_run (gdk_memory_convert_color_state_srgb_to_srgb_linear, &mc);
|
|
|
|
}
|
|
|
|
else if (format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED &&
|
|
|
|
src_cs == GDK_COLOR_STATE_SRGB_LINEAR &&
|
|
|
|
dest_cs == GDK_COLOR_STATE_SRGB)
|
|
|
|
{
|
|
|
|
gdk_parallel_task_run (gdk_memory_convert_color_state_srgb_linear_to_srgb, &mc);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gdk_parallel_task_run (gdk_memory_convert_color_state_generic, &mc);
|
|
|
|
}
|
|
|
|
}
|
2024-08-27 02:48:43 +00:00
|
|
|
|
2024-09-02 01:35:50 +00:00
|
|
|
typedef struct _MipmapData MipmapData;
|
|
|
|
|
|
|
|
struct _MipmapData
|
|
|
|
{
|
|
|
|
guchar *dest;
|
|
|
|
gsize dest_stride;
|
|
|
|
GdkMemoryFormat dest_format;
|
|
|
|
const guchar *src;
|
|
|
|
gsize src_stride;
|
|
|
|
GdkMemoryFormat src_format;
|
|
|
|
gsize src_width;
|
|
|
|
gsize src_height;
|
|
|
|
guint lod_level;
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
gboolean linear;
|
2024-09-02 01:35:50 +00:00
|
|
|
|
|
|
|
gint rows_done;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
gdk_memory_mipmap_same_format_nearest (gpointer data)
|
2024-09-02 01:35:50 +00:00
|
|
|
{
|
|
|
|
MipmapData *mipmap = data;
|
|
|
|
const GdkMemoryFormatDescription *desc = &memory_formats[mipmap->src_format];
|
|
|
|
gsize n, y;
|
2024-09-06 16:31:27 +00:00
|
|
|
guint64 before = GDK_PROFILER_CURRENT_TIME;
|
|
|
|
gsize rows;
|
2024-09-02 01:35:50 +00:00
|
|
|
|
|
|
|
n = 1 << mipmap->lod_level;
|
|
|
|
|
2024-09-06 16:31:27 +00:00
|
|
|
for (y = g_atomic_int_add (&mipmap->rows_done, n), rows = 0;
|
2024-09-02 01:35:50 +00:00
|
|
|
y < mipmap->src_height;
|
2024-09-06 16:31:27 +00:00
|
|
|
y = g_atomic_int_add (&mipmap->rows_done, n), rows++)
|
2024-09-02 01:35:50 +00:00
|
|
|
{
|
|
|
|
guchar *dest = mipmap->dest + (y >> mipmap->lod_level) * mipmap->dest_stride;
|
|
|
|
const guchar *src = mipmap->src + y * mipmap->src_stride;
|
|
|
|
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
desc->mipmap_nearest (dest, mipmap->dest_stride,
|
|
|
|
src, mipmap->src_stride,
|
|
|
|
mipmap->src_width, MIN (n, mipmap->src_height - y),
|
|
|
|
mipmap->lod_level);
|
|
|
|
}
|
2024-09-06 16:31:27 +00:00
|
|
|
|
|
|
|
ADD_MARK (before,
|
|
|
|
"Mipmap nearest (thread)", "size %lux%lu, lod %u, %lu rows",
|
|
|
|
mipmap->src_width, mipmap->src_height, mipmap->lod_level, rows);
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_memory_mipmap_same_format_linear (gpointer data)
|
|
|
|
{
|
|
|
|
MipmapData *mipmap = data;
|
|
|
|
const GdkMemoryFormatDescription *desc = &memory_formats[mipmap->src_format];
|
|
|
|
gsize n, y;
|
2024-09-06 16:31:27 +00:00
|
|
|
guint64 before = GDK_PROFILER_CURRENT_TIME;
|
|
|
|
gsize rows;
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
|
|
|
|
n = 1 << mipmap->lod_level;
|
|
|
|
|
2024-09-06 16:31:27 +00:00
|
|
|
for (y = g_atomic_int_add (&mipmap->rows_done, n), rows = 0;
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
y < mipmap->src_height;
|
2024-09-06 16:31:27 +00:00
|
|
|
y = g_atomic_int_add (&mipmap->rows_done, n), rows++)
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
{
|
|
|
|
guchar *dest = mipmap->dest + (y >> mipmap->lod_level) * mipmap->dest_stride;
|
|
|
|
const guchar *src = mipmap->src + y * mipmap->src_stride;
|
|
|
|
|
|
|
|
desc->mipmap_linear (dest, mipmap->dest_stride,
|
|
|
|
src, mipmap->src_stride,
|
|
|
|
mipmap->src_width, MIN (n, mipmap->src_height - y),
|
|
|
|
mipmap->lod_level);
|
2024-09-02 01:35:50 +00:00
|
|
|
}
|
2024-09-06 16:31:27 +00:00
|
|
|
|
|
|
|
ADD_MARK (before,
|
|
|
|
"Mipmap linear (thread)", "size %lux%lu, lod %u, %lu rows",
|
|
|
|
mipmap->src_width, mipmap->src_height, mipmap->lod_level, rows);
|
2024-09-02 01:35:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gdk_memory_mipmap_generic (gpointer data)
|
|
|
|
{
|
|
|
|
MipmapData *mipmap = data;
|
|
|
|
const GdkMemoryFormatDescription *desc = &memory_formats[mipmap->src_format];
|
|
|
|
FastConversionFunc func;
|
|
|
|
gsize dest_width;
|
|
|
|
gsize size;
|
|
|
|
guchar *tmp;
|
|
|
|
gsize n, y;
|
2024-09-06 16:31:27 +00:00
|
|
|
guint64 before = GDK_PROFILER_CURRENT_TIME;
|
|
|
|
gsize rows;
|
2024-09-02 01:35:50 +00:00
|
|
|
|
|
|
|
n = 1 << mipmap->lod_level;
|
|
|
|
dest_width = (mipmap->src_width + n - 1) >> mipmap->lod_level;
|
|
|
|
size = gdk_memory_format_bytes_per_pixel (mipmap->src_format) * dest_width;
|
|
|
|
tmp = g_malloc (size);
|
|
|
|
func = get_fast_conversion_func (mipmap->dest_format, mipmap->src_format);
|
|
|
|
|
2024-09-06 16:31:27 +00:00
|
|
|
for (y = g_atomic_int_add (&mipmap->rows_done, n), rows = 0;
|
2024-09-02 01:35:50 +00:00
|
|
|
y < mipmap->src_height;
|
2024-09-06 16:31:27 +00:00
|
|
|
y = g_atomic_int_add (&mipmap->rows_done, n), rows++)
|
2024-09-02 01:35:50 +00:00
|
|
|
{
|
|
|
|
guchar *dest = mipmap->dest + (y >> mipmap->lod_level) * mipmap->dest_stride;
|
|
|
|
const guchar *src = mipmap->src + y * mipmap->src_stride;
|
|
|
|
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
if (mipmap->linear)
|
|
|
|
desc->mipmap_linear (tmp, (size + 7) & 7,
|
|
|
|
src, mipmap->src_stride,
|
|
|
|
mipmap->src_width, MIN (n, mipmap->src_height - y),
|
|
|
|
mipmap->lod_level);
|
|
|
|
else
|
|
|
|
desc->mipmap_nearest (tmp, (size + 7) & 7,
|
|
|
|
src, mipmap->src_stride,
|
|
|
|
mipmap->src_width, MIN (n, mipmap->src_height - y),
|
|
|
|
mipmap->lod_level);
|
2024-09-02 01:35:50 +00:00
|
|
|
if (func)
|
|
|
|
func (dest, tmp, dest_width);
|
|
|
|
else
|
|
|
|
gdk_memory_convert (dest, mipmap->dest_stride, mipmap->dest_format, GDK_COLOR_STATE_SRGB,
|
|
|
|
tmp, (size + 7) & 7, mipmap->src_format, GDK_COLOR_STATE_SRGB,
|
|
|
|
dest_width, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (tmp);
|
2024-09-06 16:31:27 +00:00
|
|
|
|
|
|
|
ADD_MARK (before,
|
|
|
|
"Mipmap generic (thread)", "size %lux%lu, lod %u, %lu rows",
|
|
|
|
mipmap->src_width, mipmap->src_height, mipmap->lod_level, rows);
|
2024-09-02 01:35:50 +00:00
|
|
|
}
|
|
|
|
|
2024-08-27 02:48:43 +00:00
|
|
|
void
|
|
|
|
gdk_memory_mipmap (guchar *dest,
|
|
|
|
gsize dest_stride,
|
2024-08-27 03:59:54 +00:00
|
|
|
GdkMemoryFormat dest_format,
|
2024-08-27 02:48:43 +00:00
|
|
|
const guchar *src,
|
|
|
|
gsize src_stride,
|
2024-08-27 03:59:54 +00:00
|
|
|
GdkMemoryFormat src_format,
|
2024-08-27 02:48:43 +00:00
|
|
|
gsize src_width,
|
|
|
|
gsize src_height,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
guint lod_level,
|
|
|
|
gboolean linear)
|
2024-08-27 02:48:43 +00:00
|
|
|
{
|
2024-09-02 01:35:50 +00:00
|
|
|
MipmapData mipmap = {
|
|
|
|
.dest = dest,
|
|
|
|
.dest_stride = dest_stride,
|
|
|
|
.dest_format = dest_format,
|
|
|
|
.src = src,
|
|
|
|
.src_stride = src_stride,
|
|
|
|
.src_format = src_format,
|
|
|
|
.src_width = src_width,
|
|
|
|
.src_height = src_height,
|
|
|
|
.lod_level = lod_level,
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
.linear = linear,
|
2024-09-02 01:35:50 +00:00
|
|
|
.rows_done = 0,
|
|
|
|
};
|
2024-08-27 02:48:43 +00:00
|
|
|
|
|
|
|
g_assert (lod_level > 0);
|
|
|
|
|
2024-08-27 03:59:54 +00:00
|
|
|
if (dest_format == src_format)
|
|
|
|
{
|
memoryformat: Add linear/nearest choice for mipmaping
linear will average all the pixels for the lod, nearest will just pick
one (using the same method as OpenGL/Vulkan, picking bottom right
center).
This doesn't really make linear/nearest filtering work as it should
(because it's still a form of mipmaps), but it has 2 advantages:
1. it gets closer to the desired effect
2. it is a lot faster
Because only 1 pixel is chosen from the original image, instead of
averaging all pixels, a lot less memory needs to be accessed, and
because memory access is the bottleneck for large images, the speedup is
almost linear with the number of pixels not accessed.
And that means that even for lot level 3, aka 1/8th scale, only 1/64 of
the pixels need to be accessed, and everything is 50x faster.
Switching gtk4-demo --run=image_scaling to linear/nearest makes all the
lag go away for me, even with a 64k x 64k image.
2024-09-03 04:12:03 +00:00
|
|
|
if (linear)
|
|
|
|
gdk_parallel_task_run (gdk_memory_mipmap_same_format_linear, &mipmap);
|
|
|
|
else
|
|
|
|
gdk_parallel_task_run (gdk_memory_mipmap_same_format_nearest, &mipmap);
|
2024-08-27 03:59:54 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-09-02 01:35:50 +00:00
|
|
|
gdk_parallel_task_run (gdk_memory_mipmap_generic, &mipmap);
|
2024-08-27 03:59:54 +00:00
|
|
|
}
|
2024-08-27 02:48:43 +00:00
|
|
|
}
|
|
|
|
|