Support 16-bit floating point textures

Add R16G16B16_FLOAT and R16B16B16A16_FLOAT_PREMULTIPLIED
formats, which are using half floats.

The intention is to use these for HDR content.

Not done here: Update memory texture tests
to include floating point textures.
This commit is contained in:
Matthias Clasen
2021-09-06 08:27:42 -04:00
parent 4fcb46a387
commit 9a9d20e274
5 changed files with 108 additions and 1 deletions

View File

@@ -292,6 +292,20 @@ gdk_gl_context_upload_texture (GdkGLContext *context,
gl_type = GL_UNSIGNED_SHORT;
bpp = 8;
}
else if (data_format == GDK_MEMORY_R16G16B16_FLOAT)
{
gl_internalformat = GL_RGB16F;
gl_format = GL_RGB;
gl_type = GL_HALF_FLOAT;
bpp = 6;
}
else if (data_format == GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED)
{
gl_internalformat = GL_RGBA16F;
gl_format = GL_RGBA;
gl_type = GL_HALF_FLOAT;
bpp = 8;
}
else /* Fall-back, convert to cairo-surface-format */
{
copy = g_malloc (width * height * 4);

View File

@@ -120,6 +120,9 @@ type_from_internal_format (int internal_format)
case GL_RGB16:
case GL_RGBA16:
return GL_UNSIGNED_SHORT;
case GL_RGB16F:
case GL_RGBA16F:
return GL_HALF_FLOAT;
default:
g_assert_not_reached ();
}
@@ -134,6 +137,10 @@ internal_format_for_format (GdkMemoryFormat format)
return GL_RGB16;
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
return GL_RGBA16;
case GDK_MEMORY_R16G16B16_FLOAT:
return GL_RGB16F;
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
return GL_RGB16F;
default:
g_assert_not_reached ();
}

View File

@@ -20,6 +20,7 @@
#include "config.h"
#include "gdkmemorytextureprivate.h"
#include "gsk/ngl/fp16private.h"
/**
* GdkMemoryTexture:
@@ -66,8 +67,12 @@ gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format)
return 6;
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
return 8;
case GDK_MEMORY_R16G16B16_FLOAT:
return 6;
case GDK_MEMORY_N_FORMATS:
default:
g_assert_not_reached ();
@@ -364,6 +369,74 @@ SWIZZLE_16TO8(0,1,2,3)
SWIZZLE_16TO8(2,1,0,3)
SWIZZLE_16TO8(1,2,3,0)
#define SWIZZLE_FP16_OPAQUE(A,R,G,B) \
static void \
convert_fp16_swizzle_opaque_ ## A ## R ## G ## B (guchar *dest_data, \
gsize dest_stride, \
const guchar *src_data, \
gsize src_stride, \
gsize width, \
gsize height) \
{ \
gsize x, y; \
float *c; \
\
c = g_malloc (width * sizeof (float)); \
for (y = 0; y < height; y++) \
{ \
guint16 *src = (guint16 *)src_data; \
half_to_float (src, c, width); \
for (x = 0; x < width; x++) \
{ \
dest_data[4 * x + A] = 255; \
dest_data[4 * x + R] = (guchar)(255 * c[3 * x + 0]); \
dest_data[4 * x + G] = (guchar)(255 * c[3 * x + 1]); \
dest_data[4 * x + B] = (guchar)(255 * c[3 * x + 2]); \
} \
dest_data += dest_stride; \
src_data += src_stride; \
} \
g_free (c); \
}
SWIZZLE_FP16_OPAQUE(3,2,1,0)
SWIZZLE_FP16_OPAQUE(0,1,2,3)
SWIZZLE_FP16_OPAQUE(3,0,1,2)
#define SWIZZLE_FP16(A,R,G,B) \
static void \
convert_fp16_swizzle_ ## A ## R ## G ## B (guchar *dest_data, \
gsize dest_stride, \
const guchar *src_data, \
gsize src_stride, \
gsize width, \
gsize height) \
{ \
gsize x, y; \
float *c; \
\
c = g_malloc (width * sizeof (float)); \
for (y = 0; y < height; y++) \
{ \
guint16 *src = (guint16 *)src_data; \
half_to_float (src, c, width); \
for (x = 0; x < width; x++) \
{ \
dest_data[4 * x + A] = (guchar)(255 * c[4 * x + 0]); \
dest_data[4 * x + R] = (guchar)(255 * c[4 * x + 1]); \
dest_data[4 * x + G] = (guchar)(255 * c[4 * x + 2]); \
dest_data[4 * x + B] = (guchar)(255 * c[4 * x + 3]); \
} \
dest_data += dest_stride; \
src_data += src_stride; \
} \
g_free (c); \
}
SWIZZLE_FP16(3,2,1,0)
SWIZZLE_FP16(0,1,2,3)
SWIZZLE_FP16(3,0,1,2)
typedef void (* ConversionFunc) (guchar *dest_data,
gsize dest_stride,
const guchar *src_data,
@@ -383,7 +456,9 @@ static ConversionFunc converters[GDK_MEMORY_N_FORMATS][3] =
{ convert_swizzle_opaque_3210, convert_swizzle_opaque_0123, convert_swizzle_opaque_3012 },
{ convert_swizzle_opaque_3012, convert_swizzle_opaque_0321, convert_swizzle_opaque_3210 },
{ convert_16to8_swizzle_opaque_2103, convert_16to8_swizzle_opaque_1230, convert_16to8_swizzle_opaque_0123 },
{ convert_16to8_swizzle_2103, convert_16to8_swizzle_1230, convert_16to8_swizzle_0123 }
{ convert_16to8_swizzle_2103, convert_16to8_swizzle_1230, convert_16to8_swizzle_0123 },
{ convert_fp16_swizzle_opaque_3210, convert_fp16_swizzle_opaque_0123, convert_fp16_swizzle_opaque_3012 },
{ convert_fp16_swizzle_3210, convert_fp16_swizzle_0123, convert_fp16_swizzle_3012 }
};
void

View File

@@ -46,6 +46,11 @@ G_BEGIN_DECLS
* @GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: 4 guint16 values; for red, green,
* blue, alpha. The color values are premultiplied with the alpha value.
* Since 4.6
* @GDK_MEMORY_R16G16B16_FLOAT: 3 half-float values; for red, green, blue.
* The data is opaque. Since 4.6
* @GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: 4 half-float values; for
* red, green, blue and alpha. The color values are premultiplied with
* the alpha value. Since 4.6
* @GDK_MEMORY_N_FORMATS: The number of formats. This value will change as
* more formats get added, so do not rely on its concrete integer.
*
@@ -75,6 +80,8 @@ typedef enum {
GDK_MEMORY_B8G8R8,
GDK_MEMORY_R16G16B16,
GDK_MEMORY_R16G16B16A16_PREMULTIPLIED,
GDK_MEMORY_R16G16B16_FLOAT,
GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED,
GDK_MEMORY_N_FORMATS
} GdkMemoryFormat;

View File

@@ -189,6 +189,10 @@ main (int argc, char *argv[])
for (format = 0; format < GDK_MEMORY_N_FORMATS; format++)
{
if (format == GDK_MEMORY_R16G16B16_FLOAT ||
format == GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED)
continue;
for (color = 0; color < N_COLORS; color++)
{
TestData *test_data = g_new (TestData, 1);