forked from AuroraMiddleware/gtk
Merge branch 'wip/otte/memoryformat' into 'master'
Refactor various texture machinery See merge request GNOME/gtk!4057
This commit is contained in:
commit
a7ef4c75ea
@ -249,86 +249,6 @@ gdk_gl_context_get_property (GObject *object,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gdk_gl_context_upload_texture (GdkGLContext *context,
|
||||
const guchar *data,
|
||||
int width,
|
||||
int height,
|
||||
int stride,
|
||||
GdkMemoryFormat data_format,
|
||||
guint texture_target)
|
||||
{
|
||||
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
||||
guchar *copy = NULL;
|
||||
GLenum gl_internalformat;
|
||||
GLenum gl_format;
|
||||
GLenum gl_type;
|
||||
gsize bpp;
|
||||
|
||||
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
|
||||
|
||||
if (!gdk_memory_format_gl_format (data_format,
|
||||
gdk_gl_context_get_use_es (context),
|
||||
&gl_internalformat,
|
||||
&gl_format,
|
||||
&gl_type))
|
||||
{
|
||||
copy = g_malloc_n (width * 4, height);
|
||||
gdk_memory_convert (copy, width * 4,
|
||||
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
||||
data, stride,
|
||||
data_format,
|
||||
width, height);
|
||||
data = copy;
|
||||
data_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
|
||||
stride = width * 4;
|
||||
if (!gdk_memory_format_gl_format (data_format,
|
||||
gdk_gl_context_get_use_es (context),
|
||||
&gl_internalformat,
|
||||
&gl_format,
|
||||
&gl_type))
|
||||
{
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
copy = NULL;
|
||||
}
|
||||
|
||||
bpp = gdk_memory_format_bytes_per_pixel (data_format);
|
||||
|
||||
glPixelStorei (GL_UNPACK_ALIGNMENT, gdk_memory_format_alignment (data_format));
|
||||
|
||||
/* GL_UNPACK_ROW_LENGTH is available on desktop GL, OpenGL ES >= 3.0, or if
|
||||
* the GL_EXT_unpack_subimage extension for OpenGL ES 2.0 is available
|
||||
*/
|
||||
if (stride == width * bpp)
|
||||
{
|
||||
glTexImage2D (texture_target, 0, gl_internalformat, width, height, 0, gl_format, gl_type, data);
|
||||
}
|
||||
else if (stride % bpp == 0 &&
|
||||
(!gdk_gl_context_get_use_es (context) ||
|
||||
(priv->gl_version >= 30 || priv->has_unpack_subimage)))
|
||||
{
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, stride / bpp);
|
||||
|
||||
glTexImage2D (texture_target, 0, gl_internalformat, width, height, 0, gl_format, gl_type, data);
|
||||
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
glTexImage2D (texture_target, 0, gl_internalformat, width, height, 0, gl_format, gl_type, NULL);
|
||||
for (i = 0; i < height; i++)
|
||||
glTexSubImage2D (texture_target, 0, 0, i, width, 1, gl_format, gl_type, data + (i * stride));
|
||||
}
|
||||
glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
|
||||
|
||||
g_free (copy);
|
||||
}
|
||||
|
||||
#define N_EGL_ATTRS 16
|
||||
|
||||
static GdkGLAPI
|
||||
@ -1067,6 +987,19 @@ gdk_gl_context_set_required_version (GdkGLContext *context,
|
||||
priv->minor = version % 100;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_gl_context_check_version (GdkGLContext *context,
|
||||
int required_major,
|
||||
int required_minor)
|
||||
{
|
||||
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
||||
|
||||
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), FALSE);
|
||||
g_return_val_if_fail (required_minor < 10, FALSE);
|
||||
|
||||
return priv->gl_version >= required_major * 10 + required_minor;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_gl_context_get_required_version:
|
||||
* @context: a `GdkGLContext`
|
||||
|
@ -108,13 +108,10 @@ gboolean gdk_gl_context_is_api_allowed (GdkGLContext
|
||||
void gdk_gl_context_set_is_legacy (GdkGLContext *context,
|
||||
gboolean is_legacy);
|
||||
|
||||
void gdk_gl_context_upload_texture (GdkGLContext *context,
|
||||
const guchar *data,
|
||||
int width,
|
||||
int height,
|
||||
int stride,
|
||||
GdkMemoryFormat data_format,
|
||||
guint texture_target);
|
||||
gboolean gdk_gl_context_check_version (GdkGLContext *context,
|
||||
int required_major,
|
||||
int required_minor);
|
||||
|
||||
gboolean gdk_gl_context_has_unpack_subimage (GdkGLContext *context);
|
||||
void gdk_gl_context_push_debug_group (GdkGLContext *context,
|
||||
const char *message);
|
||||
|
@ -109,162 +109,131 @@ gdk_gl_texture_run (GdkGLTexture *self,
|
||||
while (g_atomic_int_get (&invoke.spinlock) == 0);
|
||||
}
|
||||
|
||||
static inline void
|
||||
gdk_gl_texture_get_tex_image (GdkGLTexture *self,
|
||||
GLenum gl_format,
|
||||
GLenum gl_type,
|
||||
GLvoid *data)
|
||||
{
|
||||
if (gdk_gl_context_get_use_es (self->context))
|
||||
{
|
||||
GdkTexture *texture = GDK_TEXTURE (self);
|
||||
GLuint fbo;
|
||||
typedef struct _Download Download;
|
||||
|
||||
glGenFramebuffers (1, &fbo);
|
||||
glBindFramebuffer (GL_FRAMEBUFFER, fbo);
|
||||
glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->id, 0);
|
||||
glReadPixels (0, 0,
|
||||
texture->width, texture->height,
|
||||
gl_format,
|
||||
gl_type,
|
||||
data);
|
||||
glBindFramebuffer (GL_FRAMEBUFFER, 0);
|
||||
glDeleteFramebuffers (1, &fbo);
|
||||
struct _Download
|
||||
{
|
||||
GdkMemoryFormat format;
|
||||
guchar *data;
|
||||
gsize stride;
|
||||
};
|
||||
|
||||
static gboolean
|
||||
gdk_gl_texture_find_format (gboolean use_es,
|
||||
GLint gl_format,
|
||||
GLint gl_type,
|
||||
GdkMemoryFormat *out_format)
|
||||
{
|
||||
GdkMemoryFormat format;
|
||||
|
||||
for (format = 0; format < GDK_MEMORY_N_FORMATS; format++)
|
||||
{
|
||||
GLenum q_internal_format, q_format, q_type;
|
||||
|
||||
if (!gdk_memory_format_gl_format (format, use_es, &q_internal_format, &q_format, &q_type))
|
||||
continue;
|
||||
|
||||
if (q_format != gl_format || q_type != gl_type)
|
||||
continue;
|
||||
|
||||
*out_format = format;
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static inline void
|
||||
gdk_gl_texture_do_download (gpointer texture_,
|
||||
gpointer download_)
|
||||
{
|
||||
gsize expected_stride;
|
||||
GdkGLTexture *self = texture_;
|
||||
GdkTexture *texture = texture_;
|
||||
Download *download = download_;
|
||||
GLenum gl_internal_format, gl_format, gl_type;
|
||||
|
||||
expected_stride = texture->width * gdk_memory_format_bytes_per_pixel (download->format);
|
||||
|
||||
if (download->stride != expected_stride &&
|
||||
!gdk_memory_format_gl_format (download->format, gdk_gl_context_get_use_es (self->context), &gl_internal_format, &gl_format, &gl_type))
|
||||
{
|
||||
glGetTexImage (GL_TEXTURE_2D,
|
||||
0,
|
||||
gl_format,
|
||||
gl_type,
|
||||
data);
|
||||
download->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_gl_texture_do_download_texture (gpointer texture_,
|
||||
gpointer result_)
|
||||
{
|
||||
GdkTexture *texture = texture_;
|
||||
GdkTexture **result = result_;
|
||||
guint gl_internalformat, gl_format, gl_type;
|
||||
guchar *data;
|
||||
gsize stride;
|
||||
GBytes *bytes;
|
||||
|
||||
if (!gdk_memory_format_gl_format (texture->format,
|
||||
gdk_gl_context_get_use_es (gdk_gl_context_get_current ()),
|
||||
&gl_internalformat,
|
||||
&gl_format,
|
||||
&gl_type))
|
||||
else
|
||||
{
|
||||
g_assert_not_reached ();
|
||||
GdkMemoryFormat actual_format;
|
||||
GLint gl_read_format, gl_read_type;
|
||||
GLuint fbo;
|
||||
|
||||
glGenFramebuffers (1, &fbo);
|
||||
glBindFramebuffer (GL_FRAMEBUFFER, fbo);
|
||||
glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->id, 0);
|
||||
glGetFramebufferParameteriv (GL_FRAMEBUFFER, GL_IMPLEMENTATION_COLOR_READ_FORMAT, &gl_read_format);
|
||||
glGetFramebufferParameteriv (GL_FRAMEBUFFER, GL_IMPLEMENTATION_COLOR_READ_TYPE, &gl_read_type);
|
||||
if (!gdk_gl_texture_find_format (gdk_gl_context_get_use_es (self->context), gl_read_format, gl_read_type, &actual_format))
|
||||
actual_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; /* pray */
|
||||
|
||||
if (download->format == actual_format &&
|
||||
(download->stride == expected_stride))
|
||||
{
|
||||
glReadPixels (0, 0,
|
||||
texture->width, texture->height,
|
||||
gl_read_format,
|
||||
gl_read_type,
|
||||
download->data);
|
||||
}
|
||||
else
|
||||
{
|
||||
gsize actual_bpp = gdk_memory_format_bytes_per_pixel (actual_format);
|
||||
guchar *pixels = g_malloc_n (texture->width * actual_bpp, texture->height);
|
||||
|
||||
glReadPixels (0, 0,
|
||||
texture->width, texture->height,
|
||||
gl_read_format,
|
||||
gl_read_type,
|
||||
pixels);
|
||||
|
||||
gdk_memory_convert (download->data,
|
||||
download->stride,
|
||||
download->format,
|
||||
pixels,
|
||||
texture->width * actual_bpp,
|
||||
actual_format,
|
||||
texture->width,
|
||||
texture->height);
|
||||
|
||||
g_free (pixels);
|
||||
}
|
||||
glBindFramebuffer (GL_FRAMEBUFFER, 0);
|
||||
glDeleteFramebuffers (1, &fbo);
|
||||
}
|
||||
|
||||
stride = gdk_memory_format_bytes_per_pixel (texture->format) * texture->width;
|
||||
data = g_malloc_n (stride, texture->height);
|
||||
|
||||
gdk_gl_texture_get_tex_image (texture_,
|
||||
gl_format,
|
||||
gl_type,
|
||||
data);
|
||||
|
||||
bytes = g_bytes_new_take (data, stride * texture->height);
|
||||
*result = gdk_memory_texture_new (texture->width,
|
||||
texture->height,
|
||||
texture->format,
|
||||
bytes,
|
||||
stride);
|
||||
|
||||
g_bytes_unref (bytes);
|
||||
}
|
||||
|
||||
static GdkTexture *
|
||||
gdk_gl_texture_download_texture (GdkTexture *texture)
|
||||
{
|
||||
GdkGLTexture *self = GDK_GL_TEXTURE (texture);
|
||||
GdkTexture *result;
|
||||
|
||||
if (self->saved)
|
||||
return g_object_ref (self->saved);
|
||||
|
||||
gdk_gl_texture_run (self, gdk_gl_texture_do_download_texture, &result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_gl_texture_do_download (gpointer texture,
|
||||
gpointer data)
|
||||
{
|
||||
glGetTexImage (GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_BGRA,
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
#elif G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
GL_UNSIGNED_BYTE,
|
||||
#else
|
||||
#error "Unknown byte order for gdk_gl_texture_download()"
|
||||
#endif
|
||||
data);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_gl_texture_download (GdkTexture *texture,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
gdk_gl_texture_download (GdkTexture *texture,
|
||||
GdkMemoryFormat format,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
GdkGLTexture *self = GDK_GL_TEXTURE (texture);
|
||||
Download download;
|
||||
|
||||
if (self->saved)
|
||||
{
|
||||
gdk_texture_download (self->saved, data, stride);
|
||||
gdk_texture_do_download (self->saved, format, data, stride);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gdk_gl_context_get_use_es (self->context) ||
|
||||
stride != texture->width * 4)
|
||||
{
|
||||
GDK_TEXTURE_CLASS (gdk_gl_texture_parent_class)->download (texture, data, stride);
|
||||
return;
|
||||
}
|
||||
download.format = format;
|
||||
download.data = data;
|
||||
download.stride = stride;
|
||||
|
||||
gdk_gl_texture_run (self, gdk_gl_texture_do_download, data);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_gl_texture_do_download_float (gpointer texture,
|
||||
gpointer data)
|
||||
{
|
||||
glGetTexImage (GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_RGBA,
|
||||
GL_FLOAT,
|
||||
data);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_gl_texture_download_float (GdkTexture *texture,
|
||||
float *data,
|
||||
gsize stride)
|
||||
{
|
||||
GdkGLTexture *self = GDK_GL_TEXTURE (texture);
|
||||
|
||||
if (self->saved)
|
||||
{
|
||||
gdk_texture_download_float (self->saved, data, stride);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gdk_gl_context_get_use_es (self->context) ||
|
||||
stride != texture->width * 4)
|
||||
{
|
||||
GDK_TEXTURE_CLASS (gdk_gl_texture_parent_class)->download_float (texture, data, stride);
|
||||
return;
|
||||
}
|
||||
|
||||
gdk_gl_texture_run (self, gdk_gl_texture_do_download_float, data);
|
||||
gdk_gl_texture_run (self, gdk_gl_texture_do_download, &download);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -273,9 +242,8 @@ gdk_gl_texture_class_init (GdkGLTextureClass *klass)
|
||||
GdkTextureClass *texture_class = GDK_TEXTURE_CLASS (klass);
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (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;
|
||||
}
|
||||
|
||||
@ -309,10 +277,14 @@ gdk_gl_texture_get_id (GdkGLTexture *self)
|
||||
void
|
||||
gdk_gl_texture_release (GdkGLTexture *self)
|
||||
{
|
||||
GdkTexture *texture;
|
||||
|
||||
g_return_if_fail (GDK_IS_GL_TEXTURE (self));
|
||||
g_return_if_fail (self->saved == NULL);
|
||||
|
||||
self->saved = gdk_texture_download_texture (GDK_TEXTURE (self));
|
||||
texture = GDK_TEXTURE (self);
|
||||
self->saved = GDK_TEXTURE (gdk_memory_texture_from_texture (texture,
|
||||
gdk_texture_get_format (texture)));
|
||||
|
||||
if (self->destroy)
|
||||
{
|
||||
@ -326,12 +298,24 @@ gdk_gl_texture_release (GdkGLTexture *self)
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_gl_texture_do_determine_format (gpointer texture_,
|
||||
gpointer unused)
|
||||
gdk_gl_texture_determine_format (GdkGLTexture *self)
|
||||
{
|
||||
GdkTexture *texture = texture_;
|
||||
GdkTexture *texture = GDK_TEXTURE (self);
|
||||
GLint active_texture;
|
||||
GLint internal_format;
|
||||
|
||||
if (self->context != gdk_gl_context_get_current ())
|
||||
{
|
||||
/* Somebody else is GL-ing here, abort! */
|
||||
texture->format = GDK_MEMORY_DEFAULT;
|
||||
return;
|
||||
}
|
||||
|
||||
/* We need to be careful about modifying the GL context, as this is not
|
||||
* expected during construction */
|
||||
glGetIntegerv (GL_TEXTURE_BINDING_2D, &active_texture);
|
||||
glBindTexture (GL_TEXTURE_2D, self->id);
|
||||
|
||||
glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format);
|
||||
|
||||
switch (internal_format)
|
||||
@ -375,6 +359,8 @@ gdk_gl_texture_do_determine_format (gpointer texture_,
|
||||
texture->format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
|
||||
break;
|
||||
}
|
||||
|
||||
glBindTexture (GL_TEXTURE_2D, active_texture);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -420,7 +406,7 @@ gdk_gl_texture_new (GdkGLContext *context,
|
||||
self->destroy = destroy;
|
||||
self->data = data;
|
||||
|
||||
gdk_gl_texture_run (self, gdk_gl_texture_do_determine_format, NULL);
|
||||
gdk_gl_texture_determine_format (self);
|
||||
|
||||
return GDK_TEXTURE (self);
|
||||
}
|
||||
|
@ -308,6 +308,16 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
r16g16b16a16_to_float,
|
||||
r16g16b16a16_from_float,
|
||||
},
|
||||
[GDK_MEMORY_R16G16B16A16] = {
|
||||
GDK_MEMORY_ALPHA_STRAIGHT,
|
||||
8,
|
||||
G_ALIGNOF (guint16),
|
||||
TRUE,
|
||||
TRUE,
|
||||
{ GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT },
|
||||
r16g16b16a16_to_float,
|
||||
r16g16b16a16_from_float,
|
||||
},
|
||||
[GDK_MEMORY_R16G16B16_FLOAT] = {
|
||||
GDK_MEMORY_ALPHA_OPAQUE,
|
||||
6,
|
||||
@ -328,6 +338,16 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
r16g16b16a16_float_to_float,
|
||||
r16g16b16a16_float_from_float,
|
||||
},
|
||||
[GDK_MEMORY_R16G16B16A16_FLOAT] = {
|
||||
GDK_MEMORY_ALPHA_STRAIGHT,
|
||||
8,
|
||||
G_ALIGNOF (guint16),
|
||||
TRUE,
|
||||
TRUE,
|
||||
{ GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT },
|
||||
r16g16b16a16_float_to_float,
|
||||
r16g16b16a16_float_from_float,
|
||||
},
|
||||
[GDK_MEMORY_R32G32B32_FLOAT] = {
|
||||
GDK_MEMORY_ALPHA_OPAQUE,
|
||||
12,
|
||||
@ -347,6 +367,16 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
|
||||
{ GL_RGBA32F, GL_RGBA, GL_FLOAT },
|
||||
r32g32b32a32_float_to_float,
|
||||
r32g32b32a32_float_from_float,
|
||||
},
|
||||
[GDK_MEMORY_R32G32B32A32_FLOAT] = {
|
||||
GDK_MEMORY_ALPHA_STRAIGHT,
|
||||
16,
|
||||
G_ALIGNOF (float),
|
||||
TRUE,
|
||||
TRUE,
|
||||
{ GL_RGBA32F, GL_RGBA, GL_FLOAT },
|
||||
r32g32b32a32_float_to_float,
|
||||
r32g32b32a32_float_from_float,
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -55,38 +55,16 @@ gdk_memory_texture_dispose (GObject *object)
|
||||
G_OBJECT_CLASS (gdk_memory_texture_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static GdkTexture *
|
||||
gdk_memory_texture_download_texture (GdkTexture *texture)
|
||||
{
|
||||
return g_object_ref (texture);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_memory_texture_download (GdkTexture *texture,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
gdk_memory_texture_download (GdkTexture *texture,
|
||||
GdkMemoryFormat format,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (texture);
|
||||
|
||||
gdk_memory_convert (data, stride,
|
||||
GDK_MEMORY_DEFAULT,
|
||||
(guchar *) g_bytes_get_data (self->bytes, NULL),
|
||||
self->stride,
|
||||
texture->format,
|
||||
gdk_texture_get_width (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 ((guchar *) data,
|
||||
stride * sizeof (float),
|
||||
GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
|
||||
format,
|
||||
(guchar *) g_bytes_get_data (self->bytes, NULL),
|
||||
self->stride,
|
||||
texture->format,
|
||||
@ -100,9 +78,8 @@ gdk_memory_texture_class_init (GdkMemoryTextureClass *klass)
|
||||
GdkTextureClass *texture_class = GDK_TEXTURE_CLASS (klass);
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (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;
|
||||
}
|
||||
|
||||
@ -189,6 +166,73 @@ gdk_memory_texture_new (int width,
|
||||
return GDK_TEXTURE (self);
|
||||
}
|
||||
|
||||
GdkTexture *
|
||||
gdk_memory_texture_new_subtexture (GdkMemoryTexture *source,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
GdkTexture *texture, *result;
|
||||
gsize bpp, offset, size;
|
||||
GBytes *bytes;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_MEMORY_TEXTURE (source), NULL);
|
||||
g_return_val_if_fail (x < 0 || x >= GDK_TEXTURE (source)->width, NULL);
|
||||
g_return_val_if_fail (y < 0 || y >= GDK_TEXTURE (source)->height, NULL);
|
||||
g_return_val_if_fail (width <= 0 || x + width > GDK_TEXTURE (source)->width, NULL);
|
||||
g_return_val_if_fail (height <= 0 || y + height > GDK_TEXTURE (source)->height, NULL);
|
||||
|
||||
texture = GDK_TEXTURE (source);
|
||||
bpp = gdk_memory_format_bytes_per_pixel (texture->format);
|
||||
offset = y * source->stride + x * bpp;
|
||||
size = source->stride * (height - 1) + x * bpp;
|
||||
bytes = g_bytes_new_from_bytes (source->bytes, offset, size);
|
||||
|
||||
result = gdk_memory_texture_new (texture->width,
|
||||
texture->height,
|
||||
texture->format,
|
||||
bytes,
|
||||
source->stride);
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GdkMemoryTexture *
|
||||
gdk_memory_texture_from_texture (GdkTexture *texture,
|
||||
GdkMemoryFormat format)
|
||||
{
|
||||
GdkTexture *result;
|
||||
GBytes *bytes;
|
||||
guchar *data;
|
||||
gsize stride;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_TEXTURE (texture), NULL);
|
||||
|
||||
if (GDK_IS_MEMORY_TEXTURE (texture))
|
||||
{
|
||||
GdkMemoryTexture *memtex = GDK_MEMORY_TEXTURE (texture);
|
||||
|
||||
if (gdk_texture_get_format (texture) == format)
|
||||
return g_object_ref (memtex);
|
||||
}
|
||||
|
||||
stride = texture->width * gdk_memory_format_bytes_per_pixel (format);
|
||||
data = g_malloc_n (stride, texture->height);
|
||||
|
||||
gdk_texture_do_download (texture, format, data, stride);
|
||||
bytes = g_bytes_new_take (data, stride);
|
||||
result = gdk_memory_texture_new (texture->width,
|
||||
texture->height,
|
||||
format,
|
||||
bytes,
|
||||
stride);
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
return GDK_MEMORY_TEXTURE (result);
|
||||
}
|
||||
|
||||
const guchar *
|
||||
gdk_memory_texture_get_data (GdkMemoryTexture *self)
|
||||
{
|
||||
|
@ -46,16 +46,22 @@ 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_R16G16B16A16: 4 guint16 values; for red, green, blue, alpha.
|
||||
* 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_R16G16B16A16_FLOAT: 4 half-float values; for red, green,
|
||||
* blue and alpha. Since 4.6
|
||||
* @GDK_MEMORY_B32G32R32_FLOAT: 3 float values; for blue, green, red.
|
||||
* The data is opaque. Since 4.6
|
||||
* @GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: 4 float values; for
|
||||
* red, green, blue and alpha. The color values are premultiplied with
|
||||
* the alpha value. Since 4.6
|
||||
* @GDK_MEMORY_R32G32B32A32_FLOAT: 4 float values; for red, green, blue and
|
||||
* alpha. 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.
|
||||
*
|
||||
@ -83,10 +89,13 @@ typedef enum {
|
||||
GDK_MEMORY_B8G8R8,
|
||||
GDK_MEMORY_R16G16B16,
|
||||
GDK_MEMORY_R16G16B16A16_PREMULTIPLIED,
|
||||
GDK_MEMORY_R16G16B16A16,
|
||||
GDK_MEMORY_R16G16B16_FLOAT,
|
||||
GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED,
|
||||
GDK_MEMORY_R16G16B16A16_FLOAT,
|
||||
GDK_MEMORY_R32G32B32_FLOAT,
|
||||
GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
|
||||
GDK_MEMORY_R32G32B32A32_FLOAT,
|
||||
|
||||
GDK_MEMORY_N_FORMATS
|
||||
} GdkMemoryFormat;
|
||||
|
@ -29,6 +29,14 @@ G_BEGIN_DECLS
|
||||
#define GDK_MEMORY_GDK_PIXBUF_OPAQUE GDK_MEMORY_R8G8B8
|
||||
#define GDK_MEMORY_GDK_PIXBUF_ALPHA GDK_MEMORY_R8G8B8A8
|
||||
|
||||
GdkMemoryTexture * gdk_memory_texture_from_texture (GdkTexture *texture,
|
||||
GdkMemoryFormat format);
|
||||
GdkTexture * gdk_memory_texture_new_subtexture (GdkMemoryTexture *texture,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
const guchar * gdk_memory_texture_get_data (GdkMemoryTexture *self);
|
||||
gsize gdk_memory_texture_get_stride (GdkMemoryTexture *self);
|
||||
|
||||
|
@ -221,35 +221,13 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GdkTexture, gdk_texture, G_TYPE_OBJECT,
|
||||
#define GDK_TEXTURE_WARN_NOT_IMPLEMENTED_METHOD(obj,method) \
|
||||
g_critical ("Texture of type '%s' does not implement GdkTexture::" # method, G_OBJECT_TYPE_NAME (obj))
|
||||
|
||||
static GdkTexture *
|
||||
gdk_texture_real_download_texture (GdkTexture *self)
|
||||
{
|
||||
GDK_TEXTURE_WARN_NOT_IMPLEMENTED_METHOD (self, download_texture);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_texture_real_download (GdkTexture *texture,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
gdk_texture_default_download (GdkTexture *texture,
|
||||
GdkMemoryFormat format,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
GdkTexture *memory_texture;
|
||||
|
||||
memory_texture = gdk_texture_download_texture (texture);
|
||||
gdk_texture_download (memory_texture, data, stride);
|
||||
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);
|
||||
GDK_TEXTURE_WARN_NOT_IMPLEMENTED_METHOD (texture, download);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -315,9 +293,7 @@ gdk_texture_class_init (GdkTextureClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
klass->download_texture = gdk_texture_real_download_texture;
|
||||
klass->download = gdk_texture_real_download;
|
||||
klass->download_float = gdk_texture_real_download_float;
|
||||
klass->download = gdk_texture_default_download;
|
||||
|
||||
gobject_class->set_property = gdk_texture_set_property;
|
||||
gobject_class->get_property = gdk_texture_get_property;
|
||||
@ -692,6 +668,15 @@ gdk_texture_get_height (GdkTexture *texture)
|
||||
return texture->height;
|
||||
}
|
||||
|
||||
void
|
||||
gdk_texture_do_download (GdkTexture *texture,
|
||||
GdkMemoryFormat format,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
GDK_TEXTURE_GET_CLASS (texture)->download (texture, format, data,stride);
|
||||
}
|
||||
|
||||
cairo_surface_t *
|
||||
gdk_texture_download_surface (GdkTexture *texture)
|
||||
{
|
||||
@ -750,7 +735,10 @@ gdk_texture_download (GdkTexture *texture,
|
||||
g_return_if_fail (data != NULL);
|
||||
g_return_if_fail (stride >= gdk_texture_get_width (texture) * 4);
|
||||
|
||||
GDK_TEXTURE_GET_CLASS (texture)->download (texture, data, stride);
|
||||
gdk_texture_do_download (texture,
|
||||
GDK_MEMORY_DEFAULT,
|
||||
data,
|
||||
stride);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -789,23 +777,10 @@ gdk_texture_download_float (GdkTexture *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)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_TEXTURE (texture), NULL);
|
||||
|
||||
g_object_ref (texture);
|
||||
while (!GDK_IS_MEMORY_TEXTURE (texture))
|
||||
{
|
||||
GdkTexture *downloaded = GDK_TEXTURE_GET_CLASS (texture)->download_texture (texture);
|
||||
g_object_unref (texture);
|
||||
texture = downloaded;
|
||||
}
|
||||
|
||||
return texture;
|
||||
gdk_texture_do_download (texture,
|
||||
GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
|
||||
(guchar *) data,
|
||||
stride);
|
||||
}
|
||||
|
||||
GdkMemoryFormat
|
||||
|
@ -27,24 +27,22 @@ struct _GdkTexture
|
||||
struct _GdkTextureClass {
|
||||
GObjectClass parent_class;
|
||||
|
||||
/* mandatory: Download into a GdkMemoryTexture */
|
||||
GdkTexture * (* download_texture) (GdkTexture *texture);
|
||||
/* optional */
|
||||
/* mandatory: Download in the given format into data */
|
||||
void (* download) (GdkTexture *texture,
|
||||
GdkMemoryFormat format,
|
||||
guchar *data,
|
||||
gsize stride);
|
||||
void (* download_float) (GdkTexture *texture,
|
||||
float *data,
|
||||
gsize stride);
|
||||
};
|
||||
|
||||
gboolean gdk_texture_can_load (GBytes *bytes);
|
||||
|
||||
GdkTexture * gdk_texture_new_for_surface (cairo_surface_t *surface);
|
||||
cairo_surface_t * gdk_texture_download_surface (GdkTexture *texture);
|
||||
/* NB: GdkMemoryTexture */
|
||||
GdkTexture * gdk_texture_download_texture (GdkTexture *texture);
|
||||
|
||||
void gdk_texture_do_download (GdkTexture *texture,
|
||||
GdkMemoryFormat format,
|
||||
guchar *data,
|
||||
gsize stride);
|
||||
GdkMemoryFormat gdk_texture_get_format (GdkTexture *self);
|
||||
gboolean gdk_texture_set_render_data (GdkTexture *self,
|
||||
gpointer key,
|
||||
|
@ -127,171 +127,6 @@ png_simple_warning_callback (png_structp png,
|
||||
{
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
/* {{{ Format conversion */
|
||||
|
||||
static void
|
||||
unpremultiply (guchar *data,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
gsize x, y;
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
guchar *b = &data[x * 4];
|
||||
guint32 pixel;
|
||||
guchar alpha;
|
||||
|
||||
memcpy (&pixel, b, sizeof (guint32));
|
||||
alpha = (pixel & 0xff000000) >> 24;
|
||||
if (alpha == 0)
|
||||
{
|
||||
b[0] = 0;
|
||||
b[1] = 0;
|
||||
b[2] = 0;
|
||||
b[3] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
b[0] = (((pixel & 0x00ff0000) >> 16) * 255 + alpha / 2) / alpha;
|
||||
b[1] = (((pixel & 0x0000ff00) >> 8) * 255 + alpha / 2) / alpha;
|
||||
b[2] = (((pixel & 0x000000ff) >> 0) * 255 + alpha / 2) / alpha;
|
||||
b[3] = alpha;
|
||||
}
|
||||
}
|
||||
data += width * 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
unpremultiply_float_to_16bit (guchar *data,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
gsize x, y;
|
||||
float *src = (float *)data;;
|
||||
guint16 *dest = (guint16 *)data;
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
float r, g, b, a;
|
||||
|
||||
r = src[0];
|
||||
g = src[1];
|
||||
b = src[2];
|
||||
a = src[3];
|
||||
if (a == 0)
|
||||
{
|
||||
dest[0] = 0;
|
||||
dest[1] = 0;
|
||||
dest[2] = 0;
|
||||
dest[3] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
dest[0] = (guint16) CLAMP (65536.f * r / a, 0.f, 65535.f);
|
||||
dest[1] = (guint16) CLAMP (65536.f * g / a, 0.f, 65535.f);
|
||||
dest[2] = (guint16) CLAMP (65536.f * b / a, 0.f, 65535.f);
|
||||
dest[3] = (guint16) CLAMP (65536.f * a, 0.f, 65535.f);
|
||||
}
|
||||
|
||||
dest += 4;
|
||||
src += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
multiply_alpha (int alpha, int color)
|
||||
{
|
||||
int temp = (alpha * color) + 0x80;
|
||||
return ((temp + (temp >> 8)) >> 8);
|
||||
}
|
||||
|
||||
static void
|
||||
premultiply_data (png_structp png,
|
||||
png_row_infop row_info,
|
||||
png_bytep data)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < row_info->rowbytes; i += 4)
|
||||
{
|
||||
uint8_t *base = &data[i];
|
||||
uint8_t alpha = base[3];
|
||||
uint32_t p;
|
||||
|
||||
if (alpha == 0)
|
||||
{
|
||||
p = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t red = base[0];
|
||||
uint8_t green = base[1];
|
||||
uint8_t blue = base[2];
|
||||
|
||||
if (alpha != 0xff)
|
||||
{
|
||||
red = multiply_alpha (alpha, red);
|
||||
green = multiply_alpha (alpha, green);
|
||||
blue = multiply_alpha (alpha, blue);
|
||||
}
|
||||
p = ((uint32_t)alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
|
||||
}
|
||||
memcpy (base, &p, sizeof (uint32_t));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
convert_bytes_to_data (png_structp png,
|
||||
png_row_infop row_info,
|
||||
png_bytep data)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < row_info->rowbytes; i += 4)
|
||||
{
|
||||
uint8_t *base = &data[i];
|
||||
uint8_t red = base[0];
|
||||
uint8_t green = base[1];
|
||||
uint8_t blue = base[2];
|
||||
uint32_t pixel;
|
||||
|
||||
pixel = (0xffu << 24) | (red << 16) | (green << 8) | (blue << 0);
|
||||
memcpy (base, &pixel, sizeof (uint32_t));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
premultiply_16bit (guchar *data,
|
||||
int width,
|
||||
int height,
|
||||
int stride)
|
||||
{
|
||||
gsize x, y;
|
||||
guint16 *src;
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
src = (guint16 *)data;
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
float alpha = src[x * 4 + 3] / 65535.f;
|
||||
src[x * 4 ] = (guint16) CLAMP (src[x * 4 ] * alpha, 0.f, 65535.f);
|
||||
src[x * 4 + 1] = (guint16) CLAMP (src[x * 4 + 1] * alpha, 0.f, 65535.f);
|
||||
src[x * 4 + 2] = (guint16) CLAMP (src[x * 4 + 2] * alpha, 0.f, 65535.f);
|
||||
}
|
||||
|
||||
data += stride;
|
||||
}
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
/* {{{ Public API */
|
||||
|
||||
@ -355,9 +190,6 @@ gdk_load_png (GBytes *bytes,
|
||||
if (png_get_valid (png, info, PNG_INFO_tRNS))
|
||||
png_set_tRNS_to_alpha (png);
|
||||
|
||||
if (depth == 8)
|
||||
png_set_filler (png, 0xff, PNG_FILLER_AFTER);
|
||||
|
||||
if (depth < 8)
|
||||
png_set_packing (png);
|
||||
|
||||
@ -368,18 +200,20 @@ gdk_load_png (GBytes *bytes,
|
||||
if (interlace != PNG_INTERLACE_NONE)
|
||||
png_set_interlace_handling (png);
|
||||
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
png_set_swap (png);
|
||||
#endif
|
||||
|
||||
png_read_update_info (png, info);
|
||||
png_get_IHDR (png, info,
|
||||
&width, &height, &depth,
|
||||
&color_type, &interlace, NULL, NULL);
|
||||
if ((depth != 8 && depth != 16) ||
|
||||
!(color_type == PNG_COLOR_TYPE_RGB ||
|
||||
color_type == PNG_COLOR_TYPE_RGB_ALPHA))
|
||||
if (depth != 8 && depth != 16)
|
||||
{
|
||||
png_destroy_read_struct (&png, &info, NULL);
|
||||
g_set_error (error,
|
||||
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED_CONTENT,
|
||||
_("Failed to parse png image"));
|
||||
_("Unsupported depth %u in png image"), depth);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -388,33 +222,37 @@ gdk_load_png (GBytes *bytes,
|
||||
case PNG_COLOR_TYPE_RGB_ALPHA:
|
||||
if (depth == 8)
|
||||
{
|
||||
format = GDK_MEMORY_DEFAULT;
|
||||
png_set_read_user_transform_fn (png, premultiply_data);
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
format = GDK_MEMORY_R8G8B8A8;
|
||||
#elif G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
format = GDK_MEMORY_A8B8G8R8;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
format = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED;
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
png_set_swap (png);
|
||||
#endif
|
||||
format = GDK_MEMORY_R16G16B16A16;
|
||||
}
|
||||
break;
|
||||
case PNG_COLOR_TYPE_RGB:
|
||||
if (depth == 8)
|
||||
{
|
||||
format = GDK_MEMORY_DEFAULT;
|
||||
png_set_read_user_transform_fn (png, convert_bytes_to_data);
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
format = GDK_MEMORY_R8G8B8;
|
||||
#elif G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
format = GDK_MEMORY_B8G8R8;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
else if (depth == 16)
|
||||
{
|
||||
format = GDK_MEMORY_R16G16B16;
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
png_set_swap (png);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
png_destroy_read_struct (&png, &info, NULL);
|
||||
g_set_error (error,
|
||||
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED_CONTENT,
|
||||
_("Unsupportd color type %u in png image"), color_type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bpp = gdk_memory_format_bytes_per_pixel (format);
|
||||
@ -442,9 +280,6 @@ gdk_load_png (GBytes *bytes,
|
||||
png_read_image (png, row_pointers);
|
||||
png_read_end (png, info);
|
||||
|
||||
if (format == GDK_MEMORY_R16G16B16A16_PREMULTIPLIED)
|
||||
premultiply_16bit (buffer, width, height, stride);
|
||||
|
||||
out_bytes = g_bytes_new_take (buffer, height * stride);
|
||||
texture = gdk_memory_texture_new (width, height, format, out_bytes, stride);
|
||||
g_bytes_unref (out_bytes);
|
||||
@ -468,20 +303,18 @@ gdk_save_png (GdkTexture *texture)
|
||||
png_struct *png = NULL;
|
||||
png_info *info;
|
||||
png_io io = { NULL, 0, 0 };
|
||||
guint width, height, stride;
|
||||
guchar *data = NULL;
|
||||
guchar *row;
|
||||
int width, height;
|
||||
gsize stride;
|
||||
const guchar *data;
|
||||
int y;
|
||||
GdkTexture *mtexture;
|
||||
GdkMemoryTexture *memtex;
|
||||
GdkMemoryFormat format;
|
||||
int png_format;
|
||||
int depth;
|
||||
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
|
||||
mtexture = gdk_texture_download_texture (texture);
|
||||
format = gdk_texture_get_format (mtexture);
|
||||
format = gdk_texture_get_format (texture);
|
||||
|
||||
switch (format)
|
||||
{
|
||||
@ -492,29 +325,42 @@ gdk_save_png (GdkTexture *texture)
|
||||
case GDK_MEMORY_A8R8G8B8:
|
||||
case GDK_MEMORY_R8G8B8A8:
|
||||
case GDK_MEMORY_A8B8G8R8:
|
||||
case GDK_MEMORY_R8G8B8:
|
||||
case GDK_MEMORY_B8G8R8:
|
||||
stride = width * 4;
|
||||
data = g_malloc_n (stride, height);
|
||||
gdk_texture_download (mtexture, data, stride);
|
||||
unpremultiply (data, width, height);
|
||||
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
format = GDK_MEMORY_R8G8B8A8;
|
||||
#elif G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
format = GDK_MEMORY_A8B8G8R8;
|
||||
#endif
|
||||
png_format = PNG_COLOR_TYPE_RGB_ALPHA;
|
||||
depth = 8;
|
||||
break;
|
||||
|
||||
case GDK_MEMORY_R16G16B16:
|
||||
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R16G16B16_FLOAT:
|
||||
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R32G32B32_FLOAT:
|
||||
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
|
||||
data = g_malloc_n (width * 16, height);
|
||||
gdk_texture_download_float (mtexture, (float *)data, width * 4);
|
||||
unpremultiply_float_to_16bit (data, width, height);
|
||||
case GDK_MEMORY_R8G8B8:
|
||||
case GDK_MEMORY_B8G8R8:
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
format = GDK_MEMORY_R8G8B8;
|
||||
#elif G_BYTE_ORDER == G_BIG_ENDIAN
|
||||
format = GDK_MEMORY_B8G8R8;
|
||||
#endif
|
||||
png_format = PNG_COLOR_TYPE_RGB;
|
||||
depth = 8;
|
||||
break;
|
||||
|
||||
case GDK_MEMORY_R16G16B16A16:
|
||||
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R16G16B16A16_FLOAT:
|
||||
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R32G32B32A32_FLOAT:
|
||||
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
|
||||
format = GDK_MEMORY_R16G16B16A16;
|
||||
png_format = PNG_COLOR_TYPE_RGB_ALPHA;
|
||||
stride = width * 8;
|
||||
depth = 16;
|
||||
break;
|
||||
|
||||
case GDK_MEMORY_R16G16B16:
|
||||
case GDK_MEMORY_R16G16B16_FLOAT:
|
||||
case GDK_MEMORY_R32G32B32_FLOAT:
|
||||
format = GDK_MEMORY_R16G16B16;
|
||||
png_format = PNG_COLOR_TYPE_RGB;
|
||||
depth = 16;
|
||||
break;
|
||||
|
||||
@ -541,12 +387,14 @@ gdk_save_png (GdkTexture *texture)
|
||||
|
||||
if (sigsetjmp (png_jmpbuf (png), 1))
|
||||
{
|
||||
g_free (data);
|
||||
g_object_unref (memtex);
|
||||
g_free (io.data);
|
||||
png_destroy_read_struct (&png, &info, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memtex = gdk_memory_texture_from_texture (texture, format);
|
||||
|
||||
png_set_write_fn (png, &io, png_write_func, png_flush_func);
|
||||
|
||||
png_set_IHDR (png, info, width, height, depth,
|
||||
@ -561,14 +409,16 @@ gdk_save_png (GdkTexture *texture)
|
||||
png_set_swap (png);
|
||||
#endif
|
||||
|
||||
for (y = 0, row = data; y < height; y++, row += stride)
|
||||
png_write_rows (png, &row, 1);
|
||||
data = gdk_memory_texture_get_data (memtex);
|
||||
stride = gdk_memory_texture_get_stride (memtex);
|
||||
for (y = 0; y < height; y++)
|
||||
png_write_row (png, data + y * stride);
|
||||
|
||||
png_write_end (png, info);
|
||||
|
||||
png_destroy_write_struct (&png, &info);
|
||||
|
||||
g_free (data);
|
||||
g_object_unref (memtex);
|
||||
|
||||
return g_bytes_new_take (io.data, io.size);
|
||||
}
|
||||
|
@ -283,8 +283,8 @@ gdk_save_tiff (GdkTexture *texture)
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
|
||||
memory_texture = gdk_texture_download_texture (texture);
|
||||
format = gdk_texture_get_format (memory_texture);
|
||||
format = gdk_texture_get_format (texture);
|
||||
memory_texture = GDK_TEXTURE (gdk_memory_texture_from_texture (texture, format));
|
||||
|
||||
for (int i = 0; i < G_N_ELEMENTS (format_data); i++)
|
||||
{
|
||||
|
@ -1339,31 +1339,101 @@ gsk_gl_command_queue_create_framebuffer (GskGLCommandQueue *self)
|
||||
return fbo_id;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_command_queue_do_upload_texture (GskGLCommandQueue *self,
|
||||
GdkTexture *texture)
|
||||
{
|
||||
GdkGLContext *context;
|
||||
const guchar *data;
|
||||
gsize stride;
|
||||
GdkMemoryTexture *memtex;
|
||||
GdkMemoryFormat data_format;
|
||||
int width, height;
|
||||
GLenum gl_internalformat;
|
||||
GLenum gl_format;
|
||||
GLenum gl_type;
|
||||
gsize bpp;
|
||||
gboolean use_es;
|
||||
|
||||
context = gdk_gl_context_get_current ();
|
||||
use_es = gdk_gl_context_get_use_es (context);
|
||||
data_format = gdk_texture_get_format (texture);
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
|
||||
if (!gdk_memory_format_gl_format (data_format,
|
||||
use_es,
|
||||
&gl_internalformat,
|
||||
&gl_format,
|
||||
&gl_type))
|
||||
{
|
||||
if (gdk_memory_format_prefers_high_depth (data_format))
|
||||
data_format = GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED;
|
||||
else
|
||||
data_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
|
||||
if (!gdk_memory_format_gl_format (data_format,
|
||||
use_es,
|
||||
&gl_internalformat,
|
||||
&gl_format,
|
||||
&gl_type))
|
||||
{
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
memtex = gdk_memory_texture_from_texture (texture, data_format);
|
||||
data = gdk_memory_texture_get_data (memtex);
|
||||
stride = gdk_memory_texture_get_stride (memtex);
|
||||
bpp = gdk_memory_format_bytes_per_pixel (data_format);
|
||||
|
||||
glPixelStorei (GL_UNPACK_ALIGNMENT, gdk_memory_format_alignment (data_format));
|
||||
|
||||
/* GL_UNPACK_ROW_LENGTH is available on desktop GL, OpenGL ES >= 3.0, or if
|
||||
* the GL_EXT_unpack_subimage extension for OpenGL ES 2.0 is available
|
||||
*/
|
||||
if (stride == width * bpp)
|
||||
{
|
||||
glTexImage2D (GL_TEXTURE_2D, 0, gl_internalformat, width, height, 0, gl_format, gl_type, data);
|
||||
}
|
||||
else if (stride % bpp == 0 &&
|
||||
(!use_es || gdk_gl_context_check_version (context, 3, 0) || gdk_gl_context_has_unpack_subimage (context)))
|
||||
{
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, stride / bpp);
|
||||
|
||||
glTexImage2D (GL_TEXTURE_2D, 0, gl_internalformat, width, height, 0, gl_format, gl_type, data);
|
||||
|
||||
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
glTexImage2D (GL_TEXTURE_2D, 0, gl_internalformat, width, height, 0, gl_format, gl_type, NULL);
|
||||
for (i = 0; i < height; i++)
|
||||
glTexSubImage2D (GL_TEXTURE_2D, 0, 0, i, width, 1, gl_format, gl_type, data + (i * stride));
|
||||
}
|
||||
glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
|
||||
|
||||
g_object_unref (memtex);
|
||||
}
|
||||
|
||||
int
|
||||
gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self,
|
||||
GdkTexture *texture,
|
||||
guint x_offset,
|
||||
guint y_offset,
|
||||
guint width,
|
||||
guint height,
|
||||
int min_filter,
|
||||
int mag_filter)
|
||||
{
|
||||
G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME;
|
||||
cairo_surface_t *surface = NULL;
|
||||
GdkMemoryFormat data_format;
|
||||
const guchar *data;
|
||||
gsize data_stride;
|
||||
gsize bpp;
|
||||
int width, height;
|
||||
int texture_id;
|
||||
|
||||
g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
|
||||
g_assert (!GDK_IS_GL_TEXTURE (texture));
|
||||
g_assert (x_offset + width <= gdk_texture_get_width (texture));
|
||||
g_assert (y_offset + height <= gdk_texture_get_height (texture));
|
||||
g_assert (min_filter == GL_LINEAR || min_filter == GL_NEAREST);
|
||||
g_assert (mag_filter == GL_LINEAR || min_filter == GL_NEAREST);
|
||||
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
if (width > self->max_texture_size || height > self->max_texture_size)
|
||||
{
|
||||
g_warning ("Attempt to create texture of size %ux%u but max size is %d. "
|
||||
@ -1372,40 +1442,17 @@ gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self,
|
||||
width = MAX (width, self->max_texture_size);
|
||||
height = MAX (height, self->max_texture_size);
|
||||
}
|
||||
|
||||
texture_id = gsk_gl_command_queue_create_texture (self, width, height, GL_RGBA8, min_filter, mag_filter);
|
||||
if (texture_id == -1)
|
||||
return texture_id;
|
||||
|
||||
if (GDK_IS_MEMORY_TEXTURE (texture))
|
||||
{
|
||||
GdkMemoryTexture *memory_texture = GDK_MEMORY_TEXTURE (texture);
|
||||
data = gdk_memory_texture_get_data (memory_texture);
|
||||
data_format = gdk_texture_get_format (texture);
|
||||
data_stride = gdk_memory_texture_get_stride (memory_texture);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Fall back to downloading to a surface */
|
||||
surface = gdk_texture_download_surface (texture);
|
||||
cairo_surface_flush (surface);
|
||||
data = cairo_image_surface_get_data (surface);
|
||||
data_format = GDK_MEMORY_DEFAULT;
|
||||
data_stride = cairo_image_surface_get_stride (surface);
|
||||
}
|
||||
|
||||
self->n_uploads++;
|
||||
|
||||
bpp = gdk_memory_format_bytes_per_pixel (data_format);
|
||||
|
||||
/* Switch to texture0 as 2D. We'll restore it later. */
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
glBindTexture (GL_TEXTURE_2D, texture_id);
|
||||
|
||||
gdk_gl_context_upload_texture (gdk_gl_context_get_current (),
|
||||
data + x_offset * bpp + y_offset * data_stride,
|
||||
width, height, data_stride,
|
||||
data_format, GL_TEXTURE_2D);
|
||||
gsk_gl_command_queue_do_upload_texture (self, texture);
|
||||
|
||||
/* Restore previous texture state if any */
|
||||
if (self->attachments->textures[0].id > 0)
|
||||
|
@ -281,10 +281,6 @@ void gsk_gl_command_queue_execute (GskGLCommandQueue
|
||||
const cairo_region_t *scissor);
|
||||
int gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self,
|
||||
GdkTexture *texture,
|
||||
guint x_offset,
|
||||
guint y_offset,
|
||||
guint width,
|
||||
guint height,
|
||||
int min_filter,
|
||||
int mag_filter);
|
||||
int gsk_gl_command_queue_create_texture (GskGLCommandQueue *self,
|
||||
|
@ -23,17 +23,14 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk/gdkglcontextprivate.h>
|
||||
#include <gdk/gdkdisplayprivate.h>
|
||||
#include <gdk/gdktextureprivate.h>
|
||||
#include <gdk/gdkprofilerprivate.h>
|
||||
#include "gskgldriverprivate.h"
|
||||
|
||||
#include <gsk/gskdebugprivate.h>
|
||||
#include <gsk/gskglshaderprivate.h>
|
||||
#include <gsk/gskrendererprivate.h>
|
||||
|
||||
#include "gskglcommandqueueprivate.h"
|
||||
#include "gskglcompilerprivate.h"
|
||||
#include "gskgldriverprivate.h"
|
||||
#include "gskglglyphlibraryprivate.h"
|
||||
#include "gskgliconlibraryprivate.h"
|
||||
#include "gskglprogramprivate.h"
|
||||
@ -41,6 +38,12 @@
|
||||
#include "gskgltextureprivate.h"
|
||||
#include "fp16private.h"
|
||||
|
||||
#include <gdk/gdkglcontextprivate.h>
|
||||
#include <gdk/gdkdisplayprivate.h>
|
||||
#include <gdk/gdkmemorytextureprivate.h>
|
||||
#include <gdk/gdkprofilerprivate.h>
|
||||
#include <gdk/gdktextureprivate.h>
|
||||
|
||||
#define ATLAS_SIZE 512
|
||||
#define MAX_OLD_RATIO 0.5
|
||||
|
||||
@ -746,7 +749,7 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
|
||||
int mag_filter)
|
||||
{
|
||||
GdkGLContext *context;
|
||||
GdkTexture *downloaded_texture;
|
||||
GdkMemoryTexture *downloaded_texture;
|
||||
GskGLTexture *t;
|
||||
guint texture_id;
|
||||
int height;
|
||||
@ -773,7 +776,7 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
|
||||
}
|
||||
else
|
||||
{
|
||||
downloaded_texture = gdk_texture_download_texture (texture);
|
||||
downloaded_texture = gdk_memory_texture_from_texture (texture, gdk_texture_get_format (texture));
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -784,7 +787,7 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
|
||||
return t->texture_id;
|
||||
}
|
||||
|
||||
downloaded_texture = gdk_texture_download_texture (texture);
|
||||
downloaded_texture = gdk_memory_texture_from_texture (texture, gdk_texture_get_format (texture));
|
||||
}
|
||||
|
||||
/* The download_texture() call may have switched the GL context. Make sure
|
||||
@ -794,13 +797,9 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
texture_id = gsk_gl_command_queue_upload_texture (self->command_queue,
|
||||
downloaded_texture,
|
||||
0,
|
||||
0,
|
||||
width,
|
||||
height,
|
||||
min_filter,
|
||||
mag_filter);
|
||||
GDK_TEXTURE (downloaded_texture),
|
||||
min_filter,
|
||||
mag_filter);
|
||||
|
||||
t = gsk_gl_texture_new (texture_id,
|
||||
width, height, format, min_filter, mag_filter,
|
||||
@ -1227,6 +1226,7 @@ gsk_gl_driver_add_texture_slices (GskGLDriver *self,
|
||||
int tex_width;
|
||||
int tex_height;
|
||||
int x = 0, y = 0;
|
||||
GdkMemoryTexture *memtex;
|
||||
|
||||
g_assert (GSK_IS_GL_DRIVER (self));
|
||||
g_assert (GDK_IS_TEXTURE (texture));
|
||||
@ -1250,6 +1250,8 @@ gsk_gl_driver_add_texture_slices (GskGLDriver *self,
|
||||
|
||||
n_slices = cols * rows;
|
||||
slices = g_new0 (GskGLTextureSlice, n_slices);
|
||||
memtex = gdk_memory_texture_from_texture (texture,
|
||||
gdk_texture_get_format (texture));
|
||||
|
||||
for (guint col = 0; col < cols; col ++)
|
||||
{
|
||||
@ -1259,13 +1261,16 @@ gsk_gl_driver_add_texture_slices (GskGLDriver *self,
|
||||
{
|
||||
int slice_height = MIN (max_texture_size, texture->height - y);
|
||||
int slice_index = (col * rows) + row;
|
||||
GdkTexture *subtex;
|
||||
guint texture_id;
|
||||
|
||||
subtex = gdk_memory_texture_new_subtexture (memtex,
|
||||
x, y,
|
||||
slice_width, slice_height);
|
||||
texture_id = gsk_gl_command_queue_upload_texture (self->command_queue,
|
||||
texture,
|
||||
x, y,
|
||||
slice_width, slice_height,
|
||||
subtex,
|
||||
GL_NEAREST, GL_NEAREST);
|
||||
g_object_unref (subtex);
|
||||
|
||||
slices[slice_index].rect.x = x;
|
||||
slices[slice_index].rect.y = y;
|
||||
@ -1280,6 +1285,8 @@ gsk_gl_driver_add_texture_slices (GskGLDriver *self,
|
||||
x += slice_width;
|
||||
}
|
||||
|
||||
g_object_unref (memtex);
|
||||
|
||||
/* Allocate one Texture for the entire thing. */
|
||||
t = gsk_gl_texture_new (0,
|
||||
tex_width, tex_height,
|
||||
|
@ -49,14 +49,17 @@ gdk_memory_format_precsion (GdkMemoryFormat format)
|
||||
|
||||
case GDK_MEMORY_R16G16B16:
|
||||
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R16G16B16A16:
|
||||
return 1/65536.f;
|
||||
|
||||
case GDK_MEMORY_R16G16B16_FLOAT:
|
||||
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R16G16B16A16_FLOAT:
|
||||
return 0.0009765625f;
|
||||
|
||||
case GDK_MEMORY_R32G32B32_FLOAT:
|
||||
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R32G32B32A32_FLOAT:
|
||||
return FLT_EPSILON;
|
||||
|
||||
case GDK_MEMORY_N_FORMATS:
|
||||
@ -89,13 +92,16 @@ gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format)
|
||||
return 6;
|
||||
|
||||
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R16G16B16A16:
|
||||
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R16G16B16A16_FLOAT:
|
||||
return 8;
|
||||
|
||||
case GDK_MEMORY_R32G32B32_FLOAT:
|
||||
return 12;
|
||||
|
||||
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R32G32B32A32_FLOAT:
|
||||
return 16;
|
||||
|
||||
case GDK_MEMORY_N_FORMATS:
|
||||
@ -125,8 +131,11 @@ gdk_memory_format_has_alpha (GdkMemoryFormat format)
|
||||
case GDK_MEMORY_R8G8B8A8:
|
||||
case GDK_MEMORY_A8B8G8R8:
|
||||
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R16G16B16A16:
|
||||
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R16G16B16A16_FLOAT:
|
||||
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R32G32B32A32_FLOAT:
|
||||
return TRUE;
|
||||
|
||||
case GDK_MEMORY_N_FORMATS:
|
||||
@ -296,6 +305,17 @@ texture_builder_set_pixel (TextureBuilder *builder,
|
||||
memcpy (data, pixels, 4 * sizeof (guint16));
|
||||
}
|
||||
break;
|
||||
case GDK_MEMORY_R16G16B16A16:
|
||||
{
|
||||
guint16 pixels[4] = {
|
||||
CLAMP (color->red * 65536.f, 0, 65535.f),
|
||||
CLAMP (color->green * 65536.f, 0, 65535.f),
|
||||
CLAMP (color->blue * 65536.f, 0, 65535.f),
|
||||
CLAMP (color->alpha * 65536.f, 0, 65535.f),
|
||||
};
|
||||
memcpy (data, pixels, 4 * sizeof (guint16));
|
||||
}
|
||||
break;
|
||||
case GDK_MEMORY_R16G16B16_FLOAT:
|
||||
{
|
||||
guint16 pixels[3] = {
|
||||
@ -317,6 +337,17 @@ texture_builder_set_pixel (TextureBuilder *builder,
|
||||
memcpy (data, pixels, 4 * sizeof (guint16));
|
||||
}
|
||||
break;
|
||||
case GDK_MEMORY_R16G16B16A16_FLOAT:
|
||||
{
|
||||
guint16 pixels[4] = {
|
||||
float_to_half (color->red),
|
||||
float_to_half (color->green),
|
||||
float_to_half (color->blue),
|
||||
float_to_half (color->alpha)
|
||||
};
|
||||
memcpy (data, pixels, 4 * sizeof (guint16));
|
||||
}
|
||||
break;
|
||||
case GDK_MEMORY_R32G32B32_FLOAT:
|
||||
{
|
||||
float pixels[3] = {
|
||||
@ -338,6 +369,17 @@ texture_builder_set_pixel (TextureBuilder *builder,
|
||||
memcpy (data, pixels, 4 * sizeof (float));
|
||||
}
|
||||
break;
|
||||
case GDK_MEMORY_R32G32B32A32_FLOAT:
|
||||
{
|
||||
float pixels[4] = {
|
||||
color->red,
|
||||
color->green,
|
||||
color->blue,
|
||||
color->alpha
|
||||
};
|
||||
memcpy (data, pixels, 4 * sizeof (float));
|
||||
}
|
||||
break;
|
||||
case GDK_MEMORY_N_FORMATS:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
|
Loading…
Reference in New Issue
Block a user