texture: Add gdk_texture_download_float()

This commit is contained in:
Benjamin Otte 2021-09-10 02:40:21 +02:00
parent cbe6d0da76
commit 53275481a5
6 changed files with 217 additions and 0 deletions

View File

@ -179,6 +179,60 @@ gdk_gl_texture_download (GdkTexture *texture,
glBindTexture (GL_TEXTURE_2D, active_texture);
}
static void
gdk_gl_texture_do_download_float (GdkTexture *texture,
float *data)
{
GdkGLTexture *self = GDK_GL_TEXTURE (texture);
int active_texture;
gdk_gl_context_make_current (self->context);
glGetIntegerv (GL_TEXTURE_BINDING_2D, &active_texture);
glBindTexture (GL_TEXTURE_2D, self->id);
glGetTexImage (GL_TEXTURE_2D,
0,
GL_RGBA,
GL_FLOAT,
data);
glBindTexture (GL_TEXTURE_2D, active_texture);
}
static void
gdk_gl_texture_download_float (GdkTexture *texture,
float *data,
gsize stride)
{
GdkGLTexture *self = GDK_GL_TEXTURE (texture);
int width, height, y;
float *copy;
if (self->saved)
{
gdk_texture_download_float (self->saved, data, stride);
return;
}
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
if (stride == width * 4)
{
gdk_gl_texture_do_download_float (texture, data);
return;
}
copy = g_new (float, width * height * 4);
gdk_gl_texture_do_download_float (texture, copy);
for (y = 0; y < height; y++)
memcpy (data + y * stride, copy + y * 4 * width, 4 * width);
g_free (copy);
}
static void
gdk_gl_texture_class_init (GdkGLTextureClass *klass)
{
@ -187,6 +241,7 @@ gdk_gl_texture_class_init (GdkGLTextureClass *klass)
texture_class->download_texture = gdk_gl_texture_download_texture;
texture_class->download = gdk_gl_texture_download;
texture_class->download_float = gdk_gl_texture_download_float;
gobject_class->dispose = gdk_gl_texture_dispose;
}

View File

@ -101,6 +101,21 @@ gdk_memory_texture_download (GdkTexture *texture,
gdk_texture_get_height (texture));
}
static void
gdk_memory_texture_download_float (GdkTexture *texture,
float *data,
gsize stride)
{
GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (texture);
gdk_memory_convert_to_float (data, stride,
(guchar *) g_bytes_get_data (self->bytes, NULL),
self->stride,
self->format,
gdk_texture_get_width (texture),
gdk_texture_get_height (texture));
}
static void
gdk_memory_texture_class_init (GdkMemoryTextureClass *klass)
{
@ -109,6 +124,7 @@ gdk_memory_texture_class_init (GdkMemoryTextureClass *klass)
texture_class->download_texture = gdk_memory_texture_download_texture;
texture_class->download = gdk_memory_texture_download;
texture_class->download_float = gdk_memory_texture_download_float;
gobject_class->dispose = gdk_memory_texture_dispose;
}
@ -323,3 +339,82 @@ gdk_memory_convert (guchar *dest_data,
converters[src_format][dest_format] (dest_data, dest_stride, src_data, src_stride, width, height);
}
#define CONVERT_FLOAT(R,G,B,A,premultiply) G_STMT_START {\
for (y = 0; y < height; y++) \
{ \
for (x = 0; x < width; x++) \
{ \
if (A >= 0) \
{ \
dest_data[4 * x + 0] = src_data[4 * x + R] / 255.0f; \
dest_data[4 * x + 1] = src_data[4 * x + G] / 255.0f; \
dest_data[4 * x + 2] = src_data[4 * x + B] / 255.0f; \
dest_data[4 * x + 3] = src_data[4 * x + A] / 255.0f; \
if (premultiply) \
{ \
dest_data[4 * x + 0] *= dest_data[4 * x + 3]; \
dest_data[4 * x + 1] *= dest_data[4 * x + 3]; \
dest_data[4 * x + 2] *= dest_data[4 * x + 3]; \
} \
} \
else \
{ \
dest_data[4 * x + 0] = src_data[3 * x + R] / 255.0f; \
dest_data[4 * x + 1] = src_data[3 * x + G] / 255.0f; \
dest_data[4 * x + 2] = src_data[3 * x + B] / 255.0f; \
dest_data[4 * x + 3] = 1.0; \
} \
} \
\
dest_data += dest_stride; \
src_data += src_stride; \
} \
}G_STMT_END
void
gdk_memory_convert_to_float (float *dest_data,
gsize dest_stride,
const guchar *src_data,
gsize src_stride,
GdkMemoryFormat src_format,
gsize width,
gsize height)
{
gsize x, y;
switch (src_format)
{
case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
CONVERT_FLOAT (2, 1, 0, 3, FALSE);
break;
case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
CONVERT_FLOAT (1, 2, 3, 0, FALSE);
break;
case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
CONVERT_FLOAT (0, 1, 2, 3, FALSE);
break;
case GDK_MEMORY_B8G8R8A8:
CONVERT_FLOAT (2, 1, 0, 3, TRUE);
break;
case GDK_MEMORY_A8R8G8B8:
CONVERT_FLOAT (1, 2, 3, 0, TRUE);
break;
case GDK_MEMORY_R8G8B8A8:
CONVERT_FLOAT (0, 1, 2, 3, TRUE);
break;
case GDK_MEMORY_A8B8G8R8:
CONVERT_FLOAT (3, 2, 1, 0, TRUE);
break;
case GDK_MEMORY_R8G8B8:
CONVERT_FLOAT (0, 1, 2, -1, FALSE);
break;
case GDK_MEMORY_B8G8R8:
CONVERT_FLOAT (2, 1, 0, -1, FALSE);
break;
case GDK_MEMORY_N_FORMATS:
default:
g_assert_not_reached();
}
}

View File

@ -60,6 +60,14 @@ void gdk_memory_convert (guchar
gsize width,
gsize height);
void gdk_memory_convert_to_float (float *dest_data,
gsize dest_stride,
const guchar *src_data,
gsize src_stride,
GdkMemoryFormat src_format,
gsize width,
gsize height);
G_END_DECLS

View File

@ -134,6 +134,18 @@ gdk_texture_real_download (GdkTexture *texture,
g_object_unref (memory_texture);
}
static void
gdk_texture_real_download_float (GdkTexture *self,
float *data,
gsize stride)
{
GdkTexture *memory_texture;
memory_texture = gdk_texture_download_texture (self);
gdk_texture_download_float (memory_texture, data, stride);
g_object_unref (memory_texture);
}
static void
gdk_texture_set_property (GObject *gobject,
guint prop_id,
@ -199,6 +211,7 @@ gdk_texture_class_init (GdkTextureClass *klass)
klass->download_texture = gdk_texture_real_download_texture;
klass->download = gdk_texture_real_download;
klass->download_float = gdk_texture_real_download_float;
gobject_class->set_property = gdk_texture_set_property;
gobject_class->get_property = gdk_texture_get_property;
@ -485,6 +498,45 @@ gdk_texture_download (GdkTexture *texture,
GDK_TEXTURE_GET_CLASS (texture)->download (texture, data, stride);
}
/**
* gdk_texture_download_float:
* @texture: a `GdkTexture`
* @data: (array): pointer to enough memory to be filled with the
* downloaded data of @texture
* @stride: rowstride in elements, will usually be equal to
* gdk_texture_get_width() * 4
*
* Downloads the @texture into local memory in a high dynamic range format.
*
* This may be an expensive operation, as the actual texture data
* may reside on a GPU or on a remote display server and because the data
* may need to be upsampled if it was not already available in this
* format.
*
* You may want to use [method@Gdk.Texture.download] instead if you don't
* need high dynamic range support.
*
* The data format of the downloaded data is equivalent to
* GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, so every downloaded
* pixel requires 16 bytes of memory.
*
* Note that the caller is responsible to provide sufficiently
* aligned memory to access the resulting data directly as floats.
*
* Since: 4.6
*/
void
gdk_texture_download_float (GdkTexture *texture,
float *data,
gsize stride)
{
g_return_if_fail (GDK_IS_TEXTURE (texture));
g_return_if_fail (data != NULL);
g_return_if_fail (stride >= gdk_texture_get_width (texture) * 4);
GDK_TEXTURE_GET_CLASS (texture)->download_float (texture, data, stride);
}
GdkTexture *
gdk_texture_download_texture (GdkTexture *texture)
{

View File

@ -59,6 +59,10 @@ GDK_AVAILABLE_IN_ALL
void gdk_texture_download (GdkTexture *texture,
guchar *data,
gsize stride);
GDK_AVAILABLE_IN_4_6
void gdk_texture_download_float (GdkTexture *texture,
float *data,
gsize stride);
GDK_AVAILABLE_IN_ALL
gboolean gdk_texture_save_to_png (GdkTexture *texture,
const char *filename);

View File

@ -30,6 +30,9 @@ struct _GdkTextureClass {
void (* download) (GdkTexture *texture,
guchar *data,
gsize stride);
void (* download_float) (GdkTexture *texture,
float *data,
gsize stride);
};
gpointer gdk_texture_new (const GdkTextureClass *klass,