mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2025-01-06 10:50:08 +00:00
0f61c52593
Make the callers of this function check for straight alpha themselves, and only do the version compatibility check here. This makes the function usable in contexts where straight alpha is acceptable.
733 lines
22 KiB
C
733 lines
22 KiB
C
/*
|
|
* 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"
|
|
|
|
#include "gsk/gl/fp16private.h"
|
|
|
|
#include <epoxy/gl.h>
|
|
|
|
typedef struct _GdkMemoryFormatDescription GdkMemoryFormatDescription;
|
|
|
|
#define TYPED_FUNCS(name, T, R, G, B, A, bpp, scale) \
|
|
static void \
|
|
name ## _to_float (float *dest, \
|
|
const guchar *src_data, \
|
|
gsize n) \
|
|
{ \
|
|
for (gsize i = 0; i < n; i++) \
|
|
{ \
|
|
T *src = (T *) (src_data + i * bpp); \
|
|
dest[0] = (float) src[R] / scale; \
|
|
dest[1] = (float) src[G] / scale; \
|
|
dest[2] = (float) src[B] / scale; \
|
|
if (A >= 0) dest[3] = (float) src[A] / scale; else dest[3] = 1.0; \
|
|
dest += 4; \
|
|
} \
|
|
} \
|
|
\
|
|
static void \
|
|
name ## _from_float (guchar *dest_data, \
|
|
const float *src, \
|
|
gsize n) \
|
|
{ \
|
|
for (gsize i = 0; i < n; i++) \
|
|
{ \
|
|
T *dest = (T *) (dest_data + i * bpp); \
|
|
dest[R] = CLAMP (src[0] * scale + 0.5, 0, scale); \
|
|
dest[G] = CLAMP (src[1] * scale + 0.5, 0, scale); \
|
|
dest[B] = CLAMP (src[2] * scale + 0.5, 0, scale); \
|
|
if (A >= 0) dest[A] = CLAMP (src[3] * scale + 0.5, 0, scale); \
|
|
src += 4; \
|
|
} \
|
|
}
|
|
|
|
#define TYPED_GRAY_FUNCS(name, T, G, A, bpp, scale) \
|
|
static void \
|
|
name ## _to_float (float *dest, \
|
|
const guchar *src_data, \
|
|
gsize n) \
|
|
{ \
|
|
for (gsize i = 0; i < n; i++) \
|
|
{ \
|
|
T *src = (T *) (src_data + i * bpp); \
|
|
if (G >= 0) dest[0] = (float) src[G] / scale; else dest[0] = 1.0; \
|
|
dest[1] = dest[2] = dest[0]; \
|
|
if (A >= 0) dest[3] = (float) src[A] / scale; else dest[3] = 1.0; \
|
|
dest += 4; \
|
|
} \
|
|
} \
|
|
\
|
|
static void \
|
|
name ## _from_float (guchar *dest_data, \
|
|
const float *src, \
|
|
gsize n) \
|
|
{ \
|
|
for (gsize i = 0; i < n; i++) \
|
|
{ \
|
|
T *dest = (T *) (dest_data + i * bpp); \
|
|
if (G >= 0) dest[G] = CLAMP ((src[0] + src[1] + src[2]) * scale / 3.f + 0.5, 0, scale); \
|
|
if (A >= 0) dest[A] = CLAMP (src[3] * scale + 0.5, 0, scale); \
|
|
src += 4; \
|
|
} \
|
|
}
|
|
|
|
TYPED_FUNCS (b8g8r8a8_premultiplied, guchar, 2, 1, 0, 3, 4, 255)
|
|
TYPED_FUNCS (a8r8g8b8_premultiplied, guchar, 1, 2, 3, 0, 4, 255)
|
|
TYPED_FUNCS (r8g8b8a8_premultiplied, guchar, 0, 1, 2, 3, 4, 255)
|
|
TYPED_FUNCS (b8g8r8a8, guchar, 2, 1, 0, 3, 4, 255)
|
|
TYPED_FUNCS (a8r8g8b8, guchar, 1, 2, 3, 0, 4, 255)
|
|
TYPED_FUNCS (r8g8b8a8, guchar, 0, 1, 2, 3, 4, 255)
|
|
TYPED_FUNCS (a8b8g8r8, guchar, 3, 2, 1, 0, 4, 255)
|
|
TYPED_FUNCS (r8g8b8, guchar, 0, 1, 2, -1, 3, 255)
|
|
TYPED_FUNCS (b8g8r8, guchar, 2, 1, 0, -1, 3, 255)
|
|
TYPED_FUNCS (r16g16b16, guint16, 0, 1, 2, -1, 6, 65535)
|
|
TYPED_FUNCS (r16g16b16a16, guint16, 0, 1, 2, 3, 8, 65535)
|
|
|
|
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)
|
|
|
|
static void
|
|
r16g16b16_float_to_float (float *dest,
|
|
const guchar *src_data,
|
|
gsize n)
|
|
{
|
|
guint16 *src = (guint16 *) src_data;
|
|
for (gsize i = 0; i < n; i++)
|
|
{
|
|
half_to_float (src, dest, 3);
|
|
dest[3] = 1.0;
|
|
dest += 4;
|
|
src += 3;
|
|
}
|
|
}
|
|
|
|
static void
|
|
r16g16b16_float_from_float (guchar *dest_data,
|
|
const float *src,
|
|
gsize n)
|
|
{
|
|
guint16 *dest = (guint16 *) dest_data;
|
|
for (gsize i = 0; i < n; i++)
|
|
{
|
|
float_to_half (src, dest, 3);
|
|
dest += 3;
|
|
src += 4;
|
|
}
|
|
}
|
|
|
|
static void
|
|
r16g16b16a16_float_to_float (float *dest,
|
|
const guchar *src,
|
|
gsize n)
|
|
{
|
|
half_to_float ((const guint16 *) src, dest, 4 * n);
|
|
}
|
|
|
|
static void
|
|
r16g16b16a16_float_from_float (guchar *dest,
|
|
const float *src,
|
|
gsize n)
|
|
{
|
|
float_to_half (src, (guint16 *) dest, 4 * n);
|
|
}
|
|
|
|
static void
|
|
r32g32b32_float_to_float (float *dest,
|
|
const guchar *src_data,
|
|
gsize n)
|
|
{
|
|
float *src = (float *) src_data;
|
|
for (gsize i = 0; i < n; i++)
|
|
{
|
|
dest[0] = src[0];
|
|
dest[1] = src[1];
|
|
dest[2] = src[2];
|
|
dest[3] = 1.0;
|
|
dest += 4;
|
|
src += 3;
|
|
}
|
|
}
|
|
|
|
static void
|
|
r32g32b32_float_from_float (guchar *dest_data,
|
|
const float *src,
|
|
gsize n)
|
|
{
|
|
float *dest = (float *) dest_data;
|
|
for (gsize i = 0; i < n; i++)
|
|
{
|
|
dest[0] = src[0];
|
|
dest[1] = src[1];
|
|
dest[2] = src[2];
|
|
dest += 3;
|
|
src += 4;
|
|
}
|
|
}
|
|
|
|
static void
|
|
r32g32b32a32_float_to_float (float *dest,
|
|
const guchar *src,
|
|
gsize n)
|
|
{
|
|
memcpy (dest, src, sizeof (float) * n * 4);
|
|
}
|
|
|
|
static void
|
|
r32g32b32a32_float_from_float (guchar *dest,
|
|
const float *src,
|
|
gsize n)
|
|
{
|
|
memcpy (dest, src, sizeof (float) * n * 4);
|
|
}
|
|
|
|
#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; \
|
|
} \
|
|
}
|
|
|
|
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)
|
|
|
|
#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)
|
|
|
|
struct _GdkMemoryFormatDescription
|
|
{
|
|
GdkMemoryAlpha alpha;
|
|
gsize bytes_per_pixel;
|
|
gsize alignment;
|
|
gboolean prefers_high_depth;
|
|
struct {
|
|
guint gl_major;
|
|
guint gl_minor;
|
|
guint gles_major;
|
|
guint gles_minor;
|
|
} min_gl_version;
|
|
struct {
|
|
guint internal_format;
|
|
guint format;
|
|
guint type;
|
|
GLint swizzle[4];
|
|
} gl;
|
|
/* no premultiplication going on here */
|
|
void (* to_float) (float *, const guchar*, gsize);
|
|
void (* from_float) (guchar *, const float *, gsize);
|
|
};
|
|
|
|
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
|
# define GDK_GL_UNSIGNED_BYTE_FLIPPED GL_UNSIGNED_INT_8_8_8_8
|
|
#elif G_BYTE_ORDER == G_BIG_ENDIAN
|
|
# define GDK_GL_UNSIGNED_BYTE_FLIPPED GL_UNSIGNED_INT_8_8_8_8_REV
|
|
#else
|
|
# error "Define the right GL flags here"
|
|
#endif
|
|
|
|
static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
|
[GDK_MEMORY_B8G8R8A8_PREMULTIPLIED] = {
|
|
GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
|
4,
|
|
G_ALIGNOF (guchar),
|
|
FALSE,
|
|
{ 0, 0, G_MAXUINT, G_MAXUINT },
|
|
{ GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
|
b8g8r8a8_premultiplied_to_float,
|
|
b8g8r8a8_premultiplied_from_float,
|
|
},
|
|
[GDK_MEMORY_A8R8G8B8_PREMULTIPLIED] = {
|
|
GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
|
4,
|
|
G_ALIGNOF (guchar),
|
|
FALSE,
|
|
{ 0, 0, G_MAXUINT, G_MAXUINT },
|
|
{ GL_RGBA8, GL_BGRA, GDK_GL_UNSIGNED_BYTE_FLIPPED, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
|
a8r8g8b8_premultiplied_to_float,
|
|
a8r8g8b8_premultiplied_from_float,
|
|
},
|
|
[GDK_MEMORY_R8G8B8A8_PREMULTIPLIED] = {
|
|
GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
|
4,
|
|
G_ALIGNOF (guchar),
|
|
FALSE,
|
|
{ 0, 0, 0, 0 },
|
|
{ GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
|
r8g8b8a8_premultiplied_to_float,
|
|
r8g8b8a8_premultiplied_from_float,
|
|
},
|
|
[GDK_MEMORY_B8G8R8A8] = {
|
|
GDK_MEMORY_ALPHA_STRAIGHT,
|
|
4,
|
|
G_ALIGNOF (guchar),
|
|
FALSE,
|
|
{ 0, 0, G_MAXUINT, G_MAXUINT },
|
|
{ GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
|
b8g8r8a8_to_float,
|
|
b8g8r8a8_from_float,
|
|
},
|
|
[GDK_MEMORY_A8R8G8B8] = {
|
|
GDK_MEMORY_ALPHA_STRAIGHT,
|
|
4,
|
|
G_ALIGNOF (guchar),
|
|
FALSE,
|
|
{ 0, 0, G_MAXUINT, G_MAXUINT },
|
|
{ GL_RGBA8, GL_RGBA, GDK_GL_UNSIGNED_BYTE_FLIPPED, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
|
a8r8g8b8_to_float,
|
|
a8r8g8b8_from_float,
|
|
},
|
|
[GDK_MEMORY_R8G8B8A8] = {
|
|
GDK_MEMORY_ALPHA_STRAIGHT,
|
|
4,
|
|
G_ALIGNOF (guchar),
|
|
FALSE,
|
|
{ 0, 0, 0, 0 },
|
|
{ GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
|
r8g8b8a8_to_float,
|
|
r8g8b8a8_from_float,
|
|
},
|
|
[GDK_MEMORY_A8B8G8R8] = {
|
|
GDK_MEMORY_ALPHA_STRAIGHT,
|
|
4,
|
|
G_ALIGNOF (guchar),
|
|
FALSE,
|
|
{ 0, 0, G_MAXUINT, G_MAXUINT },
|
|
{ GL_RGBA8, GL_BGRA, GDK_GL_UNSIGNED_BYTE_FLIPPED, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
|
a8b8g8r8_to_float,
|
|
a8b8g8r8_from_float,
|
|
},
|
|
[GDK_MEMORY_R8G8B8] = {
|
|
GDK_MEMORY_ALPHA_OPAQUE,
|
|
3,
|
|
G_ALIGNOF (guchar),
|
|
FALSE,
|
|
{ 0, 0, 0, 0 },
|
|
{ GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, { GL_RED, GL_GREEN, GL_BLUE, GL_ONE } },
|
|
r8g8b8_to_float,
|
|
r8g8b8_from_float,
|
|
},
|
|
[GDK_MEMORY_B8G8R8] = {
|
|
GDK_MEMORY_ALPHA_OPAQUE,
|
|
3,
|
|
G_ALIGNOF (guchar),
|
|
FALSE,
|
|
{ 0, 0, G_MAXUINT, G_MAXUINT },
|
|
{ GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE, { GL_RED, GL_GREEN, GL_BLUE, GL_ONE } },
|
|
b8g8r8_to_float,
|
|
b8g8r8_from_float,
|
|
},
|
|
[GDK_MEMORY_R16G16B16] = {
|
|
GDK_MEMORY_ALPHA_OPAQUE,
|
|
6,
|
|
G_ALIGNOF (guint16),
|
|
TRUE,
|
|
{ 0, 0, 3, 0 },
|
|
{ GL_RGB16, GL_RGB, GL_UNSIGNED_SHORT, { GL_RED, GL_GREEN, GL_BLUE, GL_ONE } },
|
|
r16g16b16_to_float,
|
|
r16g16b16_from_float,
|
|
},
|
|
[GDK_MEMORY_R16G16B16A16_PREMULTIPLIED] = {
|
|
GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
|
8,
|
|
G_ALIGNOF (guint16),
|
|
TRUE,
|
|
{ 0, 0, 3, 0 },
|
|
{ GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
|
r16g16b16a16_to_float,
|
|
r16g16b16a16_from_float,
|
|
},
|
|
[GDK_MEMORY_R16G16B16A16] = {
|
|
GDK_MEMORY_ALPHA_STRAIGHT,
|
|
8,
|
|
G_ALIGNOF (guint16),
|
|
TRUE,
|
|
{ 0, 0, 3, 0 },
|
|
{ GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
|
r16g16b16a16_to_float,
|
|
r16g16b16a16_from_float,
|
|
},
|
|
[GDK_MEMORY_R16G16B16_FLOAT] = {
|
|
GDK_MEMORY_ALPHA_OPAQUE,
|
|
6,
|
|
G_ALIGNOF (guint16),
|
|
TRUE,
|
|
{ 0, 0, 3, 0 },
|
|
{ GL_RGB16F, GL_RGB, GL_HALF_FLOAT, { GL_RED, GL_GREEN, GL_BLUE, GL_ONE } },
|
|
r16g16b16_float_to_float,
|
|
r16g16b16_float_from_float,
|
|
},
|
|
[GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED] = {
|
|
GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
|
8,
|
|
G_ALIGNOF (guint16),
|
|
TRUE,
|
|
{ 0, 0, 3, 0 },
|
|
{ GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
|
r16g16b16a16_float_to_float,
|
|
r16g16b16a16_float_from_float,
|
|
},
|
|
[GDK_MEMORY_R16G16B16A16_FLOAT] = {
|
|
GDK_MEMORY_ALPHA_STRAIGHT,
|
|
8,
|
|
G_ALIGNOF (guint16),
|
|
TRUE,
|
|
{ 0, 0, 3, 0 },
|
|
{ GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
|
r16g16b16a16_float_to_float,
|
|
r16g16b16a16_float_from_float,
|
|
},
|
|
[GDK_MEMORY_R32G32B32_FLOAT] = {
|
|
GDK_MEMORY_ALPHA_OPAQUE,
|
|
12,
|
|
G_ALIGNOF (float),
|
|
TRUE,
|
|
{ 0, 0, 3, 0 },
|
|
{ GL_RGB32F, GL_RGB, GL_FLOAT, { GL_RED, GL_GREEN, GL_BLUE, GL_ONE } },
|
|
r32g32b32_float_to_float,
|
|
r32g32b32_float_from_float,
|
|
},
|
|
[GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED] = {
|
|
GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
|
16,
|
|
G_ALIGNOF (float),
|
|
TRUE,
|
|
{ 0, 0, 3, 0 },
|
|
{ GL_RGBA32F, GL_RGBA, GL_FLOAT, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
|
r32g32b32a32_float_to_float,
|
|
r32g32b32a32_float_from_float,
|
|
},
|
|
[GDK_MEMORY_R32G32B32A32_FLOAT] = {
|
|
GDK_MEMORY_ALPHA_STRAIGHT,
|
|
16,
|
|
G_ALIGNOF (float),
|
|
TRUE,
|
|
{ 0, 0, 3, 0 },
|
|
{ GL_RGBA32F, GL_RGBA, GL_FLOAT, { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA } },
|
|
r32g32b32a32_float_to_float,
|
|
r32g32b32a32_float_from_float,
|
|
},
|
|
[GDK_MEMORY_G8A8_PREMULTIPLIED] = {
|
|
GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
|
2,
|
|
G_ALIGNOF (guchar),
|
|
FALSE,
|
|
{ 0, 0, 3, 0 },
|
|
{ GL_RG8, GL_RG, GL_UNSIGNED_BYTE, { GL_RED, GL_RED, GL_RED, GL_GREEN } },
|
|
g8a8_premultiplied_to_float,
|
|
g8a8_premultiplied_from_float,
|
|
},
|
|
[GDK_MEMORY_G8A8] = {
|
|
GDK_MEMORY_ALPHA_STRAIGHT,
|
|
2,
|
|
G_ALIGNOF (guchar),
|
|
FALSE,
|
|
{ 0, 0, 3, 0 },
|
|
{ GL_RG8, GL_RG, GL_UNSIGNED_BYTE, { GL_RED, GL_RED, GL_RED, GL_GREEN } },
|
|
g8a8_to_float,
|
|
g8a8_from_float,
|
|
},
|
|
[GDK_MEMORY_G8] = {
|
|
GDK_MEMORY_ALPHA_OPAQUE,
|
|
1,
|
|
G_ALIGNOF (guchar),
|
|
FALSE,
|
|
{ 0, 0, 3, 0 },
|
|
{ GL_R8, GL_RED, GL_UNSIGNED_BYTE, { GL_RED, GL_RED, GL_RED, GL_ONE } },
|
|
g8_to_float,
|
|
g8_from_float,
|
|
},
|
|
[GDK_MEMORY_G16A16_PREMULTIPLIED] = {
|
|
GDK_MEMORY_ALPHA_PREMULTIPLIED,
|
|
4,
|
|
G_ALIGNOF (guint16),
|
|
TRUE,
|
|
{ 0, 0, 3, 0 },
|
|
{ GL_RG16, GL_RG, GL_UNSIGNED_SHORT, { GL_RED, GL_RED, GL_RED, GL_GREEN } },
|
|
g16a16_premultiplied_to_float,
|
|
g16a16_premultiplied_from_float,
|
|
},
|
|
[GDK_MEMORY_G16A16] = {
|
|
GDK_MEMORY_ALPHA_STRAIGHT,
|
|
4,
|
|
G_ALIGNOF (guint16),
|
|
TRUE,
|
|
{ 0, 0, 3, 0 },
|
|
{ GL_RG16, GL_RG, GL_UNSIGNED_SHORT, { GL_RED, GL_RED, GL_RED, GL_GREEN } },
|
|
g16a16_to_float,
|
|
g16a16_from_float,
|
|
},
|
|
[GDK_MEMORY_G16] = {
|
|
GDK_MEMORY_ALPHA_OPAQUE,
|
|
2,
|
|
G_ALIGNOF (guint16),
|
|
TRUE,
|
|
{ 0, 0, 3, 0 },
|
|
{ GL_R16, GL_RED, GL_UNSIGNED_SHORT, { GL_RED, GL_RED, GL_RED, GL_ONE } },
|
|
g16_to_float,
|
|
g16_from_float,
|
|
},
|
|
[GDK_MEMORY_A8] = {
|
|
GDK_MEMORY_ALPHA_STRAIGHT,
|
|
1,
|
|
G_ALIGNOF (guchar),
|
|
FALSE,
|
|
{ 0, 0, 3, 0 },
|
|
{ GL_R8, GL_RED, GL_UNSIGNED_BYTE, { GL_ONE, GL_ONE, GL_ONE, GL_RED } },
|
|
a8_to_float,
|
|
a8_from_float,
|
|
},
|
|
[GDK_MEMORY_A16] = {
|
|
GDK_MEMORY_ALPHA_STRAIGHT,
|
|
2,
|
|
G_ALIGNOF (guint16),
|
|
TRUE,
|
|
{ 0, 0, 3, 0 },
|
|
{ GL_R16, GL_RED, GL_UNSIGNED_SHORT, { GL_ONE, GL_ONE, GL_ONE, GL_RED } },
|
|
a16_to_float,
|
|
a16_from_float,
|
|
}
|
|
};
|
|
|
|
gsize
|
|
gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format)
|
|
{
|
|
return memory_formats[format].bytes_per_pixel;
|
|
}
|
|
|
|
GdkMemoryAlpha
|
|
gdk_memory_format_alpha (GdkMemoryFormat format)
|
|
{
|
|
return memory_formats[format].alpha;
|
|
}
|
|
|
|
gsize
|
|
gdk_memory_format_alignment (GdkMemoryFormat format)
|
|
{
|
|
return memory_formats[format].alignment;
|
|
}
|
|
|
|
/*<private>
|
|
* gdk_memory_format_prefers_high_depth:
|
|
* @format: a memory format
|
|
*
|
|
* Checks if the given format benefits from being rendered
|
|
* in bit depths higher than 8bits per pixel. See
|
|
* gsk_render_node_prefers_high_depth() for more information
|
|
* on this.
|
|
* Usually this is the case when
|
|
* gdk_memory_format_bytes_per_pixel() is larger than 4.
|
|
*
|
|
* Returns: %TRUE if the format benefits from being
|
|
* composited in hgiher bit depths.
|
|
**/
|
|
gboolean
|
|
gdk_memory_format_prefers_high_depth (GdkMemoryFormat format)
|
|
{
|
|
return memory_formats[format].prefers_high_depth;
|
|
}
|
|
|
|
gboolean
|
|
gdk_memory_format_gl_format (GdkMemoryFormat format,
|
|
gboolean gles,
|
|
guint gl_major,
|
|
guint gl_minor,
|
|
guint *out_internal_format,
|
|
guint *out_format,
|
|
guint *out_type,
|
|
GLint (*out_swizzle)[4])
|
|
{
|
|
*out_internal_format = memory_formats[format].gl.internal_format;
|
|
*out_format = memory_formats[format].gl.format;
|
|
*out_type = memory_formats[format].gl.type;
|
|
memcpy (out_swizzle, &memory_formats[format].gl.swizzle, sizeof(GLint) * 4);
|
|
|
|
if (gles)
|
|
{
|
|
if (memory_formats[format].min_gl_version.gles_major > gl_major ||
|
|
(memory_formats[format].min_gl_version.gles_major == gl_major &&
|
|
memory_formats[format].min_gl_version.gles_minor > gl_minor))
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (memory_formats[format].min_gl_version.gl_major > gl_major ||
|
|
(memory_formats[format].min_gl_version.gl_major == gl_major &&
|
|
memory_formats[format].min_gl_version.gl_minor > gl_minor))
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
premultiply (float *rgba,
|
|
gsize n)
|
|
{
|
|
for (gsize i = 0; i < n; i++)
|
|
{
|
|
rgba[0] *= rgba[3];
|
|
rgba[1] *= rgba[3];
|
|
rgba[2] *= rgba[3];
|
|
rgba += 4;
|
|
}
|
|
}
|
|
|
|
static void
|
|
unpremultiply (float *rgba,
|
|
gsize n)
|
|
{
|
|
for (gsize i = 0; i < n; i++)
|
|
{
|
|
if (rgba[3] > 1/255.0)
|
|
{
|
|
rgba[0] /= rgba[3];
|
|
rgba[1] /= rgba[3];
|
|
rgba[2] /= rgba[3];
|
|
}
|
|
rgba += 4;
|
|
}
|
|
}
|
|
|
|
void
|
|
gdk_memory_convert (guchar *dest_data,
|
|
gsize dest_stride,
|
|
GdkMemoryFormat dest_format,
|
|
const guchar *src_data,
|
|
gsize src_stride,
|
|
GdkMemoryFormat src_format,
|
|
gsize width,
|
|
gsize height)
|
|
{
|
|
const GdkMemoryFormatDescription *dest_desc = &memory_formats[dest_format];
|
|
const GdkMemoryFormatDescription *src_desc = &memory_formats[src_format];
|
|
float *tmp;
|
|
gsize y;
|
|
void (*func) (guchar *, const guchar *, gsize) = NULL;
|
|
|
|
g_assert (dest_format < GDK_MEMORY_N_FORMATS);
|
|
g_assert (src_format < GDK_MEMORY_N_FORMATS);
|
|
|
|
if (src_format == GDK_MEMORY_R8G8B8A8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
|
|
func = r8g8b8a8_to_r8g8b8a8_premultiplied;
|
|
else if (src_format == GDK_MEMORY_B8G8R8A8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
|
|
func = r8g8b8a8_to_b8g8r8a8_premultiplied;
|
|
else if (src_format == GDK_MEMORY_R8G8B8A8 && dest_format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED)
|
|
func = r8g8b8a8_to_b8g8r8a8_premultiplied;
|
|
else if (src_format == GDK_MEMORY_B8G8R8A8 && dest_format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED)
|
|
func = r8g8b8a8_to_r8g8b8a8_premultiplied;
|
|
else if (src_format == GDK_MEMORY_R8G8B8A8 && dest_format == GDK_MEMORY_A8R8G8B8_PREMULTIPLIED)
|
|
func = r8g8b8a8_to_a8r8g8b8_premultiplied;
|
|
else if (src_format == GDK_MEMORY_B8G8R8A8 && dest_format == GDK_MEMORY_A8R8G8B8_PREMULTIPLIED)
|
|
func = r8g8b8a8_to_a8b8g8r8_premultiplied;
|
|
else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
|
|
func = r8g8b8_to_r8g8b8a8;
|
|
else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
|
|
func = r8g8b8_to_b8g8r8a8;
|
|
else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED)
|
|
func = r8g8b8_to_b8g8r8a8;
|
|
else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED)
|
|
func = r8g8b8_to_r8g8b8a8;
|
|
else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_A8R8G8B8_PREMULTIPLIED)
|
|
func = r8g8b8_to_a8r8g8b8;
|
|
else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_A8R8G8B8_PREMULTIPLIED)
|
|
func = r8g8b8_to_a8b8g8r8;
|
|
else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_R8G8B8A8)
|
|
func = r8g8b8_to_r8g8b8a8;
|
|
else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_R8G8B8A8)
|
|
func = r8g8b8_to_b8g8r8a8;
|
|
else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_B8G8R8A8)
|
|
func = r8g8b8_to_b8g8r8a8;
|
|
else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_B8G8R8A8)
|
|
func = r8g8b8_to_r8g8b8a8;
|
|
else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_A8R8G8B8)
|
|
func = r8g8b8_to_a8r8g8b8;
|
|
else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_A8R8G8B8)
|
|
func = r8g8b8_to_a8b8g8r8;
|
|
|
|
if (func != NULL)
|
|
{
|
|
for (y = 0; y < height; y++)
|
|
{
|
|
func (dest_data, src_data, width);
|
|
src_data += src_stride;
|
|
dest_data += dest_stride;
|
|
}
|
|
return;
|
|
}
|
|
|
|
tmp = g_new (float, width * 4);
|
|
|
|
for (y = 0; y < height; y++)
|
|
{
|
|
src_desc->to_float (tmp, src_data, width);
|
|
if (src_desc->alpha == GDK_MEMORY_ALPHA_PREMULTIPLIED && dest_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT)
|
|
unpremultiply (tmp, width);
|
|
else if (src_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT && dest_desc->alpha != GDK_MEMORY_ALPHA_STRAIGHT)
|
|
premultiply (tmp, width);
|
|
dest_desc->from_float (dest_data, tmp, width);
|
|
src_data += src_stride;
|
|
dest_data += dest_stride;
|
|
}
|
|
|
|
g_free (tmp);
|
|
}
|