Merge branch 'wip/matthiasc/gsk-hdr' into 'master'

texture: Add hdr api

See merge request GNOME/gtk!4036
This commit is contained in:
Matthias Clasen 2021-10-07 02:03:48 +00:00
commit 8d9c3920bb
47 changed files with 849 additions and 843 deletions

View File

@ -34,7 +34,7 @@ gdk_broadway_cairo_context_dispose (GObject *object)
static void
gdk_broadway_cairo_context_begin_frame (GdkDrawContext *draw_context,
gboolean request_hdr,
gboolean prefers_high_depth,
cairo_region_t *region)
{
GdkBroadwayCairoContext *self = GDK_BROADWAY_CAIRO_CONTEXT (draw_context);

View File

@ -34,7 +34,7 @@ gdk_broadway_draw_context_dispose (GObject *object)
static void
gdk_broadway_draw_context_begin_frame (GdkDrawContext *draw_context,
gboolean request_hdr,
gboolean prefers_high_depth,
cairo_region_t *region)
{
GdkBroadwayDrawContext *self = GDK_BROADWAY_DRAW_CONTEXT (draw_context);

View File

@ -129,7 +129,7 @@ static const GdkDebugKey gdk_debug_keys[] = {
{ "vulkan-disable", GDK_DEBUG_VULKAN_DISABLE, "Disable Vulkan support" },
{ "vulkan-validate", GDK_DEBUG_VULKAN_VALIDATE, "Load the Vulkan validation layer" },
{ "default-settings",GDK_DEBUG_DEFAULT_SETTINGS, "Force default values for xsettings", TRUE },
{ "hdr", GDK_DEBUG_HDR, "Use HDR rendering if possible", TRUE },
{ "high-depth", GDK_DEBUG_HIGH_DEPTH, "Use high bit depth rendering if possible", TRUE },
};

View File

@ -91,11 +91,7 @@ void
gdk_cairo_surface_paint_pixbuf (cairo_surface_t *surface,
const GdkPixbuf *pixbuf)
{
int width, height;
guchar *gdk_pixels, *cairo_pixels;
int gdk_rowstride, cairo_stride;
int n_channels;
int j;
GdkTexture *texture;
if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
return;
@ -111,71 +107,11 @@ gdk_cairo_surface_paint_pixbuf (cairo_surface_t *surface,
cairo_surface_flush (surface);
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
gdk_pixels = gdk_pixbuf_get_pixels (pixbuf);
gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
n_channels = gdk_pixbuf_get_n_channels (pixbuf);
cairo_stride = cairo_image_surface_get_stride (surface);
cairo_pixels = cairo_image_surface_get_data (surface);
for (j = height; j; j--)
{
guchar *p = gdk_pixels;
guchar *q = cairo_pixels;
if (n_channels == 3)
{
guchar *end = p + 3 * width;
while (p < end)
{
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
q[0] = p[2];
q[1] = p[1];
q[2] = p[0];
q[3] = 0xFF;
#else
q[0] = 0xFF;
q[1] = p[0];
q[2] = p[1];
q[3] = p[2];
#endif
p += 3;
q += 4;
}
}
else
{
guchar *end = p + 4 * width;
guint t1,t2,t3;
#define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x80; d = ((t >> 8) + t) >> 8; } G_STMT_END
while (p < end)
{
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
MULT(q[0], p[2], p[3], t1);
MULT(q[1], p[1], p[3], t2);
MULT(q[2], p[0], p[3], t3);
q[3] = p[3];
#else
q[0] = p[3];
MULT(q[1], p[0], p[3], t1);
MULT(q[2], p[1], p[3], t2);
MULT(q[3], p[2], p[3], t3);
#endif
p += 4;
q += 4;
}
#undef MULT
}
gdk_pixels += gdk_rowstride;
cairo_pixels += cairo_stride;
}
texture = gdk_texture_new_for_pixbuf (GDK_PIXBUF (pixbuf));
gdk_texture_download (texture,
cairo_image_surface_get_data (surface),
cairo_image_surface_get_stride (surface));
g_object_unref (texture);
cairo_surface_mark_dirty (surface);
}

View File

@ -50,7 +50,7 @@ typedef enum {
GDK_DEBUG_VULKAN_DISABLE = 1 << 21,
GDK_DEBUG_VULKAN_VALIDATE = 1 << 22,
GDK_DEBUG_DEFAULT_SETTINGS= 1 << 23,
GDK_DEBUG_HDR = 1 << 24,
GDK_DEBUG_HIGH_DEPTH = 1 << 24,
} GdkDebugFlags;
extern guint _gdk_debug_flags;

View File

@ -93,7 +93,7 @@ struct _GdkDisplayPrivate {
#ifdef HAVE_EGL
EGLDisplay egl_display;
EGLConfig egl_config;
EGLConfig egl_config_hdr;
EGLConfig egl_config_high_depth;
#endif
guint rgba : 1;
@ -1439,11 +1439,11 @@ gdk_display_get_egl_config (GdkDisplay *self)
}
gpointer
gdk_display_get_egl_config_hdr (GdkDisplay *self)
gdk_display_get_egl_config_high_depth (GdkDisplay *self)
{
GdkDisplayPrivate *priv = gdk_display_get_instance_private (self);
return priv->egl_config_hdr;
return priv->egl_config_high_depth;
}
static EGLDisplay
@ -1721,16 +1721,16 @@ gdk_display_init_egl (GdkDisplay *self,
epoxy_has_egl_extension (priv->egl_display, "EGL_EXT_pixel_format_float");
if (self->have_egl_no_config_context)
priv->egl_config_hdr = gdk_display_create_egl_config (self,
priv->egl_config_high_depth = gdk_display_create_egl_config (self,
GDK_EGL_CONFIG_HDR,
error);
if (priv->egl_config_hdr == NULL)
priv->egl_config_hdr = priv->egl_config;
if (priv->egl_config_high_depth == NULL)
priv->egl_config_high_depth = priv->egl_config;
GDK_DISPLAY_NOTE (self, OPENGL, {
char *ext = describe_extensions (priv->egl_display);
char *sdr_cfg = describe_egl_config (priv->egl_display, priv->egl_config);
char *hdr_cfg = describe_egl_config (priv->egl_display, priv->egl_config_hdr);
char *std_cfg = describe_egl_config (priv->egl_display, priv->egl_config);
char *hd_cfg = describe_egl_config (priv->egl_display, priv->egl_config_high_depth);
g_message ("EGL API version %d.%d found\n"
" - Vendor: %s\n"
" - Version: %s\n"
@ -1738,15 +1738,15 @@ gdk_display_init_egl (GdkDisplay *self,
" - Extensions:\n"
"\t%s\n"
" - Selected fbconfig: %s\n"
" HDR fbconfig: %s",
" high depth: %s",
major, minor,
eglQueryString (priv->egl_display, EGL_VENDOR),
eglQueryString (priv->egl_display, EGL_VERSION),
eglQueryString (priv->egl_display, EGL_CLIENT_APIS),
ext, sdr_cfg,
priv->egl_config_hdr == priv->egl_config ? "none" : hdr_cfg);
g_free (hdr_cfg);
g_free (sdr_cfg);
ext, std_cfg,
priv->egl_config_high_depth == priv->egl_config ? "none" : hd_cfg);
g_free (hd_cfg);
g_free (std_cfg);
g_free (ext);
});

View File

@ -226,7 +226,8 @@ gboolean gdk_display_init_egl (GdkDisplay *display
GError **error);
gpointer gdk_display_get_egl_display (GdkDisplay *display);
gpointer gdk_display_get_egl_config (GdkDisplay *display);
gpointer gdk_display_get_egl_config_hdr (GdkDisplay *display);
gpointer gdk_display_get_egl_config_high_depth
(GdkDisplay *display);
void gdk_display_set_rgba (GdkDisplay *display,
gboolean rgba);

View File

@ -315,28 +315,30 @@ gdk_draw_context_begin_frame (GdkDrawContext *context,
}
/*
* @request_hdr: %TRUE to request high dynamic range.
* @prefers_high_depth: %TRUE to request a higher bit depth
*
* If HDR is requested, GDK will see about providing a rendering target
* that supports high dynamic range. Typically this means a target supporting
* 16bit floating point pixels, but that is not guaranteed.
* If high depth is preferred, GDK will see about providing a rendering target
* that supports higher bit depth than 8 bits per channel. Typically this means
* a target supporting 16bit floating point pixels, but that is not guaranteed.
*
* This is only a request and if the GDK backend does not support HDR rendering
* or does not consider it worthwhile, it may choose to not honor the request.
* It may also choose to provide HDR even if it was not requested.
* It may also choose to provide high depth even if it was not requested.
* Typically the steps undertaken by a backend are:
* 1. Check if HDR is supported by this drawing backend.
* 2. Check if the compositor supports HDR.
* 3. Check if the compositor prefers SDR. This is usually the case when the attached
* monitors do not support HDR content or when the system is resource constrained.
* 1. Check if high depth is supported by this drawing backend.
* 2. Check if the compositor supports high depth.
* 3. Check if the compositor prefers regular bit depth. This is usually the case
* when the attached monitors do not support high depth content or when the
* system is resource constrained.
* In either of those cases, the context will usually choose to not honor the request.
*
* The rendering code must be able to deal with HDR and SDR content, no matter if HDR
* was requested. The request is only a hint and GDK is free to choose.
* The rendering code must be able to deal with content in any bit depth, no matter
* the preference. The prefers_high_depth argument is only a hint and GDK is free
* to choose.
*/
void
gdk_draw_context_begin_frame_full (GdkDrawContext *context,
gboolean request_hdr,
gboolean prefers_high_depth,
const cairo_region_t *region)
{
GdkDrawContextPrivate *priv = gdk_draw_context_get_instance_private (context);
@ -362,13 +364,13 @@ gdk_draw_context_begin_frame_full (GdkDrawContext *context,
return;
}
if (GDK_DISPLAY_DEBUG_CHECK (priv->display, HDR))
request_hdr = TRUE;
if (GDK_DISPLAY_DEBUG_CHECK (priv->display, HIGH_DEPTH))
prefers_high_depth = TRUE;
priv->frame_region = cairo_region_copy (region);
priv->surface->paint_context = g_object_ref (context);
GDK_DRAW_CONTEXT_GET_CLASS (context)->begin_frame (context, request_hdr, priv->frame_region);
GDK_DRAW_CONTEXT_GET_CLASS (context)->begin_frame (context, prefers_high_depth, priv->frame_region);
}
#ifdef HAVE_SYSPROF

View File

@ -41,7 +41,7 @@ struct _GdkDrawContextClass
GObjectClass parent_class;
void (* begin_frame) (GdkDrawContext *context,
gboolean request_hdr,
gboolean prefers_high_depth,
cairo_region_t *update_area);
void (* end_frame) (GdkDrawContext *context,
cairo_region_t *painted);
@ -51,7 +51,7 @@ struct _GdkDrawContextClass
void gdk_draw_context_surface_resized (GdkDrawContext *context);
void gdk_draw_context_begin_frame_full (GdkDrawContext *context,
gboolean request_hdr,
gboolean prefers_high_depth,
const cairo_region_t *region);
G_END_DECLS

View File

@ -79,6 +79,7 @@
#include "gdkdebug.h"
#include "gdkdisplayprivate.h"
#include "gdkintl.h"
#include "gdkmemoryformatprivate.h"
#include "gdkmemorytextureprivate.h"
#include "gdkprofilerprivate.h"
@ -238,80 +239,39 @@ gdk_gl_context_upload_texture (GdkGLContext *context,
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
guchar *copy = NULL;
GLint gl_internalformat;
GLint gl_format;
GLint gl_type;
GLenum gl_internalformat;
GLenum gl_format;
GLenum gl_type;
gsize bpp;
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
if (!priv->use_es && data_format == GDK_MEMORY_DEFAULT) /* Cairo surface format */
if (!gdk_memory_format_gl_format (data_format,
priv->use_es,
&gl_internalformat,
&gl_format,
&gl_type))
{
gl_internalformat = GL_RGBA8;
gl_format = GL_BGRA;
gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
}
else if (data_format == GDK_MEMORY_R8G8B8) /* Pixmap non-alpha data */
{
gl_internalformat = GL_RGBA8;
gl_format = GL_RGB;
gl_type = GL_UNSIGNED_BYTE;
}
else if (priv->use_es && data_format == GDK_MEMORY_B8G8R8)
{
gl_internalformat = GL_RGBA8;
gl_format = GL_BGR;
gl_type = GL_UNSIGNED_BYTE;
}
else if (data_format == GDK_MEMORY_R16G16B16)
{
gl_internalformat = GL_RGBA16;
gl_format = GL_RGB;
gl_type = GL_UNSIGNED_SHORT;
}
else if (data_format == GDK_MEMORY_R16G16B16A16_PREMULTIPLIED)
{
gl_internalformat = GL_RGBA16;
gl_format = GL_RGBA;
gl_type = GL_UNSIGNED_SHORT;
}
else if (data_format == GDK_MEMORY_R16G16B16_FLOAT)
{
gl_internalformat = GL_RGB16F;
gl_format = GL_RGB;
gl_type = GL_HALF_FLOAT;
}
else if (data_format == GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED)
{
gl_internalformat = GL_RGBA16F;
gl_format = GL_RGBA;
gl_type = GL_HALF_FLOAT;
}
else if (data_format == GDK_MEMORY_R32G32B32_FLOAT)
{
gl_internalformat = GL_RGB32F;
gl_format = GL_RGB;
gl_type = GL_FLOAT;
}
else if (data_format == GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED)
{
gl_internalformat = GL_RGBA32F;
gl_format = GL_RGBA;
gl_type = GL_FLOAT;
}
else /* Fall-back, convert to GLES format */
{
copy = g_malloc (width * height * 4);
copy = g_malloc_n (width * 4, height);
gdk_memory_convert (copy, width * 4,
GDK_MEMORY_CONVERT_GLES_RGBA,
data, stride, data_format,
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
data, stride,
data_format,
width, height);
data_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
stride = width * 4;
data = copy;
gl_internalformat = GL_RGBA8;
gl_format = GL_RGBA;
gl_type = GL_UNSIGNED_BYTE;
data_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
if (!gdk_memory_format_gl_format (data_format,
priv->use_es,
&gl_internalformat,
&gl_format,
&gl_type))
{
g_assert_not_reached ();
}
}
else
{
copy = NULL;
}
bpp = gdk_memory_format_bytes_per_pixel (data_format);
@ -629,7 +589,7 @@ gdk_gl_context_real_make_current (GdkGLContext *context,
static void
gdk_gl_context_real_begin_frame (GdkDrawContext *draw_context,
gboolean request_hdr,
gboolean prefers_high_depth,
cairo_region_t *region)
{
GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
@ -642,7 +602,7 @@ gdk_gl_context_real_begin_frame (GdkDrawContext *draw_context,
#ifdef HAVE_EGL
if (priv->egl_context)
gdk_surface_ensure_egl_surface (surface, request_hdr);
gdk_surface_ensure_egl_surface (surface, prefers_high_depth);
#endif
damage = GDK_GL_CONTEXT_GET_CLASS (context)->get_damage (context);

View File

@ -21,6 +21,7 @@
#include "gdkgltextureprivate.h"
#include "gdkdisplayprivate.h"
#include "gdkmemoryformatprivate.h"
#include "gdkmemorytextureprivate.h"
#include "gdktextureprivate.h"
@ -139,82 +140,29 @@ gdk_gl_texture_get_tex_image (GdkGLTexture *self,
data);
}
}
static void
gdk_gl_texture_do_download_texture (gpointer texture_,
gpointer result_)
{
GdkTexture *texture = texture_;
GdkTexture **result = result_;
GdkMemoryFormat format;
GLint internal_format, gl_format, gl_type;
guint gl_internalformat, gl_format, gl_type;
guchar *data;
gsize stride;
GBytes *bytes;
glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format);
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))
{
g_assert_not_reached ();
}
switch (internal_format)
{
case GL_RGB8:
format = GDK_MEMORY_R8G8B8;
gl_format = GL_RGB;
gl_type = GL_UNSIGNED_BYTE;
break;
case GL_RGBA8:
format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
gl_format = GL_RGBA;
gl_type = GL_UNSIGNED_BYTE;
break;
case GL_RGB16:
format = GDK_MEMORY_R16G16B16;
gl_format = GL_RGB;
gl_type = GL_UNSIGNED_SHORT;
break;
case GL_RGBA16:
format = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED;
gl_format = GL_RGBA;
gl_type = GL_UNSIGNED_SHORT;
break;
case GL_RGB16F:
format = GDK_MEMORY_R16G16B16_FLOAT;
gl_format = GL_RGB;
gl_type = GL_HALF_FLOAT;
break;
case GL_RGBA16F:
format = GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED;
gl_format = GL_RGBA;
gl_type = GL_HALF_FLOAT;
break;
case GL_RGB32F:
format = GDK_MEMORY_R32G32B32_FLOAT;
gl_format = GL_RGB;
gl_type = GL_FLOAT;
break;
case GL_RGBA32F:
format = GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED;
gl_format = GL_RGBA;
gl_type = GL_FLOAT;
break;
default:
g_warning ("Texture in unexpected format 0x%X (%d). File a bug about adding it to GTK", internal_format, internal_format);
/* fallback to the dumbest possible format
* so that even age old GLES can do it */
format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
gl_format = GL_RGBA;
gl_type = GL_UNSIGNED_BYTE;
break;
}
stride = gdk_memory_format_bytes_per_pixel (format) * texture->width;
data = g_malloc (stride * texture->height);
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,
@ -224,7 +172,7 @@ gdk_gl_texture_do_download_texture (gpointer texture_,
bytes = g_bytes_new_take (data, stride * texture->height);
*result = gdk_memory_texture_new (texture->width,
texture->height,
format,
texture->format,
bytes,
stride);
@ -377,6 +325,58 @@ gdk_gl_texture_release (GdkGLTexture *self)
self->id = 0;
}
static void
gdk_gl_texture_do_determine_format (gpointer texture_,
gpointer unused)
{
GdkTexture *texture = texture_;
GLint internal_format;
glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format);
switch (internal_format)
{
case GL_RGB8:
texture->format = GDK_MEMORY_R8G8B8;
break;
case GL_RGBA8:
texture->format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
break;
case GL_RGB16:
texture->format = GDK_MEMORY_R16G16B16;
break;
case GL_RGBA16:
texture->format = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED;
break;
case GL_RGB16F:
texture->format = GDK_MEMORY_R16G16B16_FLOAT;
break;
case GL_RGBA16F:
texture->format = GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED;
break;
case GL_RGB32F:
texture->format = GDK_MEMORY_R32G32B32_FLOAT;
break;
case GL_RGBA32F:
texture->format = GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED;
break;
default:
g_warning ("Texture in unexpected format 0x%X (%d). File a bug about adding it to GTK", internal_format, internal_format);
/* fallback to the dumbest possible format
* so that even age old GLES can do it */
texture->format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
break;
}
}
/**
* gdk_gl_texture_new:
* @context: a `GdkGLContext`
@ -420,6 +420,8 @@ gdk_gl_texture_new (GdkGLContext *context,
self->destroy = destroy;
self->data = data;
gdk_gl_texture_run (self, gdk_gl_texture_do_determine_format, NULL);
return GDK_TEXTURE (self);
}

467
gdk/gdkmemoryformat.c Normal file
View File

@ -0,0 +1,467 @@
/*
* 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/ngl/fp16private.h"
#include <epoxy/gl.h>
typedef struct _GdkMemoryFormatDescription GdkMemoryFormatDescription;
typedef enum {
GDK_MEMORY_ALPHA_PREMULTIPLIED,
GDK_MEMORY_ALPHA_STRAIGHT,
GDK_MEMORY_ALPHA_OPAQUE
} GdkMemoryAlpha;
#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; \
} \
}
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)
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);
}
struct _GdkMemoryFormatDescription
{
GdkMemoryAlpha alpha;
gsize bytes_per_pixel;
gsize alignment;
gboolean prefers_high_depth;
gboolean supports_gles;
struct {
guint internal_format;
guint format;
guint type;
} 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,
FALSE,
{ GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE },
b8g8r8a8_premultiplied_to_float,
b8g8r8a8_premultiplied_from_float,
},
[GDK_MEMORY_A8R8G8B8_PREMULTIPLIED] = {
GDK_MEMORY_ALPHA_PREMULTIPLIED,
4,
G_ALIGNOF (guchar),
FALSE,
FALSE,
{ GL_RGBA8, GL_BGRA, GDK_GL_UNSIGNED_BYTE_FLIPPED },
a8r8g8b8_premultiplied_to_float,
a8r8g8b8_premultiplied_from_float,
},
[GDK_MEMORY_R8G8B8A8_PREMULTIPLIED] = {
GDK_MEMORY_ALPHA_PREMULTIPLIED,
4,
G_ALIGNOF (guchar),
FALSE,
TRUE,
{ GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE },
r8g8b8a8_premultiplied_to_float,
r8g8b8a8_premultiplied_from_float,
},
[GDK_MEMORY_B8G8R8A8] = {
GDK_MEMORY_ALPHA_STRAIGHT,
4,
G_ALIGNOF (guchar),
FALSE,
FALSE,
{ GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE },
b8g8r8a8_to_float,
b8g8r8a8_from_float,
},
[GDK_MEMORY_A8R8G8B8] = {
GDK_MEMORY_ALPHA_STRAIGHT,
4,
G_ALIGNOF (guchar),
FALSE,
FALSE,
{ GL_RGBA8, GL_RGBA, GDK_GL_UNSIGNED_BYTE_FLIPPED },
a8r8g8b8_to_float,
a8r8g8b8_from_float,
},
[GDK_MEMORY_R8G8B8A8] = {
GDK_MEMORY_ALPHA_STRAIGHT,
4,
G_ALIGNOF (guchar),
FALSE,
TRUE,
{ GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE },
r8g8b8a8_to_float,
r8g8b8a8_from_float,
},
[GDK_MEMORY_A8B8G8R8] = {
GDK_MEMORY_ALPHA_STRAIGHT,
4,
G_ALIGNOF (guchar),
FALSE,
FALSE,
{ GL_RGBA8, GL_BGRA, GDK_GL_UNSIGNED_BYTE_FLIPPED },
a8b8g8r8_to_float,
a8b8g8r8_from_float,
},
[GDK_MEMORY_R8G8B8] = {
GDK_MEMORY_ALPHA_OPAQUE,
3,
G_ALIGNOF (guchar),
FALSE,
TRUE,
{ GL_RGBA8, GL_RGB, GL_UNSIGNED_BYTE },
r8g8b8_to_float,
r8g8b8_from_float,
},
[GDK_MEMORY_B8G8R8] = {
GDK_MEMORY_ALPHA_OPAQUE,
3,
G_ALIGNOF (guchar),
FALSE,
FALSE,
{ GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE },
b8g8r8_to_float,
b8g8r8_from_float,
},
[GDK_MEMORY_R16G16B16] = {
GDK_MEMORY_ALPHA_OPAQUE,
6,
G_ALIGNOF (guint16),
TRUE,
TRUE,
{ GL_RGB16, GL_RGB, GL_UNSIGNED_SHORT },
r16g16b16_to_float,
r16g16b16_from_float,
},
[GDK_MEMORY_R16G16B16A16_PREMULTIPLIED] = {
GDK_MEMORY_ALPHA_PREMULTIPLIED,
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,
G_ALIGNOF (guint16),
TRUE,
TRUE,
{ GL_RGB16F, GL_RGB, GL_HALF_FLOAT },
r16g16b16_float_to_float,
r16g16b16_float_from_float,
},
[GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED] = {
GDK_MEMORY_ALPHA_PREMULTIPLIED,
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,
G_ALIGNOF (float),
TRUE,
TRUE,
{ GL_RGB32F, GL_RGB, GL_FLOAT },
r32g32b32_float_to_float,
r32g32b32_float_from_float,
},
[GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED] = {
GDK_MEMORY_ALPHA_PREMULTIPLIED,
16,
G_ALIGNOF (float),
TRUE,
TRUE,
{ GL_RGBA32F, GL_RGBA, GL_FLOAT },
r32g32b32a32_float_to_float,
r32g32b32a32_float_from_float,
}
};
gsize
gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format)
{
return memory_formats[format].bytes_per_pixel;
}
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 *out_internal_format,
guint *out_format,
guint *out_type)
{
*out_internal_format = memory_formats[format].gl.internal_format;
*out_format = memory_formats[format].gl.format;
*out_type = memory_formats[format].gl.type;
if (memory_formats[format].alpha == GDK_MEMORY_ALPHA_STRAIGHT)
return FALSE;
if (gles && !memory_formats[format].supports_gles)
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;
g_assert (dest_format < GDK_MEMORY_N_FORMATS);
g_assert (src_format < GDK_MEMORY_N_FORMATS);
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);
}

View File

@ -0,0 +1,48 @@
/*
* 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>
*/
#ifndef __GDK_MEMORY_CONVERT_PRIVATE_H__
#define __GDK_MEMORY_CONVERT_PRIVATE_H__
#include "gdkmemorytexture.h"
G_BEGIN_DECLS
gsize gdk_memory_format_alignment (GdkMemoryFormat format) G_GNUC_CONST;
gsize gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format) G_GNUC_CONST;
gboolean gdk_memory_format_prefers_high_depth(GdkMemoryFormat format) G_GNUC_CONST;
gboolean gdk_memory_format_gl_format (GdkMemoryFormat format,
gboolean gles,
guint *out_internal_format,
guint *out_format,
guint *out_type);
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);
G_END_DECLS
#endif /* __GDK_MEMORY_CONVERT_PRIVATE_H__ */

View File

@ -20,6 +20,8 @@
#include "config.h"
#include "gdkmemorytextureprivate.h"
#include "gdkmemoryformatprivate.h"
#include "gsk/ngl/fp16private.h"
/**
@ -32,8 +34,6 @@ struct _GdkMemoryTexture
{
GdkTexture parent_instance;
GdkMemoryFormat format;
GBytes *bytes;
gsize stride;
};
@ -45,80 +45,6 @@ struct _GdkMemoryTextureClass
G_DEFINE_TYPE (GdkMemoryTexture, gdk_memory_texture, GDK_TYPE_TEXTURE)
gsize
gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format)
{
switch (format)
{
case GDK_MEMORY_R8G8B8:
case GDK_MEMORY_B8G8R8:
return 3;
case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
case GDK_MEMORY_B8G8R8A8:
case GDK_MEMORY_A8R8G8B8:
case GDK_MEMORY_R8G8B8A8:
case GDK_MEMORY_A8B8G8R8:
return 4;
case GDK_MEMORY_R16G16B16:
case GDK_MEMORY_R16G16B16_FLOAT:
return 6;
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
return 8;
case GDK_MEMORY_R32G32B32_FLOAT:
return 12;
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
return 16;
case GDK_MEMORY_N_FORMATS:
default:
g_assert_not_reached ();
return 4;
}
}
static gsize
gdk_memory_format_alignment (GdkMemoryFormat format)
{
switch (format)
{
case GDK_MEMORY_R8G8B8:
case GDK_MEMORY_B8G8R8:
case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
case GDK_MEMORY_B8G8R8A8:
case GDK_MEMORY_A8R8G8B8:
case GDK_MEMORY_R8G8B8A8:
case GDK_MEMORY_A8B8G8R8:
return G_ALIGNOF (guchar);
case GDK_MEMORY_R16G16B16:
case GDK_MEMORY_R16G16B16_FLOAT:
return G_ALIGNOF (guint16);
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
return G_ALIGNOF (guint16);
case GDK_MEMORY_R32G32B32_FLOAT:
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
return G_ALIGNOF (float);
case GDK_MEMORY_N_FORMATS:
default:
g_assert_not_reached ();
return G_ALIGNOF (double);
}
}
static void
gdk_memory_texture_dispose (GObject *object)
{
@ -143,10 +69,10 @@ gdk_memory_texture_download (GdkTexture *texture,
GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (texture);
gdk_memory_convert (data, stride,
GDK_MEMORY_CONVERT_DOWNLOAD,
GDK_MEMORY_DEFAULT,
(guchar *) g_bytes_get_data (self->bytes, NULL),
self->stride,
self->format,
texture->format,
gdk_texture_get_width (texture),
gdk_texture_get_height (texture));
}
@ -158,12 +84,14 @@ gdk_memory_texture_download_float (GdkTexture *texture,
{
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));
gdk_memory_convert ((guchar *) data,
stride * sizeof (float),
GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
(guchar *) g_bytes_get_data (self->bytes, NULL),
self->stride,
texture->format,
gdk_texture_get_width (texture),
gdk_texture_get_height (texture));
}
static void
@ -254,19 +182,13 @@ gdk_memory_texture_new (int width,
"height", height,
NULL);
self->format = format;
GDK_TEXTURE (self)->format = format;
self->bytes = bytes;
self->stride = stride;
return GDK_TEXTURE (self);
}
GdkMemoryFormat
gdk_memory_texture_get_format (GdkMemoryTexture *self)
{
return self->format;
}
const guchar *
gdk_memory_texture_get_data (GdkMemoryTexture *self)
{
@ -279,429 +201,3 @@ gdk_memory_texture_get_stride (GdkMemoryTexture *self)
return self->stride;
}
static void
convert_memcpy (guchar *dest_data,
gsize dest_stride,
const guchar *src_data,
gsize src_stride,
gsize width,
gsize height)
{
gsize y;
for (y = 0; y < height; y++)
memcpy (dest_data + y * dest_stride, src_data + y * src_stride, 4 * width);
}
#define SWIZZLE(A,R,G,B) \
static void \
convert_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; \
\
for (y = 0; y < height; y++) \
{ \
for (x = 0; x < width; x++) \
{ \
dest_data[4 * x + A] = src_data[4 * x + 0]; \
dest_data[4 * x + R] = src_data[4 * x + 1]; \
dest_data[4 * x + G] = src_data[4 * x + 2]; \
dest_data[4 * x + B] = src_data[4 * x + 3]; \
} \
\
dest_data += dest_stride; \
src_data += src_stride; \
} \
}
SWIZZLE(3,2,1,0)
SWIZZLE(2,1,0,3)
SWIZZLE(3,0,1,2)
SWIZZLE(1,2,3,0)
#define SWIZZLE_OPAQUE(A,R,G,B) \
static void \
convert_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; \
\
for (y = 0; y < height; y++) \
{ \
for (x = 0; x < width; x++) \
{ \
dest_data[4 * x + A] = 0xFF; \
dest_data[4 * x + R] = src_data[3 * x + 0]; \
dest_data[4 * x + G] = src_data[3 * x + 1]; \
dest_data[4 * x + B] = src_data[3 * x + 2]; \
} \
\
dest_data += dest_stride; \
src_data += src_stride; \
} \
}
SWIZZLE_OPAQUE(3,2,1,0)
SWIZZLE_OPAQUE(3,0,1,2)
SWIZZLE_OPAQUE(0,1,2,3)
SWIZZLE_OPAQUE(0,3,2,1)
#define PREMULTIPLY(d,c,a) G_STMT_START { guint t = c * a + 0x80; d = ((t >> 8) + t) >> 8; } G_STMT_END
#define SWIZZLE_PREMULTIPLY(A,R,G,B, A2,R2,G2,B2) \
static void \
convert_swizzle_premultiply_ ## A ## R ## G ## B ## _ ## A2 ## R2 ## G2 ## B2 \
(guchar *dest_data, \
gsize dest_stride, \
const guchar *src_data, \
gsize src_stride, \
gsize width, \
gsize height) \
{ \
gsize x, y; \
\
for (y = 0; y < height; y++) \
{ \
for (x = 0; x < width; x++) \
{ \
dest_data[4 * x + A] = src_data[4 * x + A2]; \
PREMULTIPLY(dest_data[4 * x + R], src_data[4 * x + R2], src_data[4 * x + A2]); \
PREMULTIPLY(dest_data[4 * x + G], src_data[4 * x + G2], src_data[4 * x + A2]); \
PREMULTIPLY(dest_data[4 * x + B], src_data[4 * x + B2], src_data[4 * x + A2]); \
} \
\
dest_data += dest_stride; \
src_data += src_stride; \
} \
}
SWIZZLE_PREMULTIPLY (3,2,1,0, 3,2,1,0)
SWIZZLE_PREMULTIPLY (0,1,2,3, 3,2,1,0)
SWIZZLE_PREMULTIPLY (3,2,1,0, 0,1,2,3)
SWIZZLE_PREMULTIPLY (0,1,2,3, 0,1,2,3)
SWIZZLE_PREMULTIPLY (3,2,1,0, 3,0,1,2)
SWIZZLE_PREMULTIPLY (0,1,2,3, 3,0,1,2)
SWIZZLE_PREMULTIPLY (3,2,1,0, 0,3,2,1)
SWIZZLE_PREMULTIPLY (0,1,2,3, 0,3,2,1)
SWIZZLE_PREMULTIPLY (3,0,1,2, 3,2,1,0)
SWIZZLE_PREMULTIPLY (3,0,1,2, 0,1,2,3)
SWIZZLE_PREMULTIPLY (3,0,1,2, 3,0,1,2)
SWIZZLE_PREMULTIPLY (3,0,1,2, 0,3,2,1)
#define CONVERT_FUNC(name,suffix,R,G,B,A,step) \
static void \
convert_ ## name ## _to_ ## suffix (guchar *dest_data, \
gsize dest_stride, \
const guchar *src_data, \
gsize src_stride, \
gsize width, \
gsize height) \
{ \
gsize x, y; \
\
for (y = 0; y < height; y++) \
{ \
for (x = 0; x < width; x++) \
{ \
guchar conv[4]; \
convert_pixel_ ## name (conv, src_data + step * x); \
dest_data[4 * x + R] = conv[0]; \
dest_data[4 * x + G] = conv[1]; \
dest_data[4 * x + B] = conv[2]; \
dest_data[4 * x + A] = conv[3]; \
} \
\
dest_data += dest_stride; \
src_data += src_stride; \
} \
}
#define CONVERT_FUNCS(name,step) \
CONVERT_FUNC(name, download_le, 2, 1, 0, 3, step) \
CONVERT_FUNC(name, download_be, 1, 2, 3, 0, step) \
CONVERT_FUNC(name, gles_rgba, 0, 1, 2, 3, step) \
static inline void
convert_pixel_rgb16 (guchar *dest_data, const guchar *src_data)
{
const guint16 *src = (const guint16 *) src_data;
dest_data[0] = (guchar)(src[0] >> 8);
dest_data[1] = (guchar)(src[1] >> 8);
dest_data[2] = (guchar)(src[2] >> 8);
dest_data[3] = 0xFF;
}
CONVERT_FUNCS(rgb16, 3 * sizeof (guint16))
static inline void
convert_pixel_rgba16 (guchar *dest_data, const guchar *src_data)
{
const guint16 *src = (const guint16 *) src_data;
dest_data[0] = (guchar)(src[0] >> 8);
dest_data[1] = (guchar)(src[1] >> 8);
dest_data[2] = (guchar)(src[2] >> 8);
dest_data[3] = (guchar)(src[3] >> 8);
}
CONVERT_FUNCS(rgba16, 4 * sizeof (guint16))
static inline void
convert_pixel_rgb16f (guchar *dest_data, const guchar *src_data)
{
float src[4];
guint16 tmp[4];
memcpy(tmp, src_data, sizeof(guint16) * 3);
half_to_float4(tmp, src);
dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f);
dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f);
dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f);
dest_data[3] = 0xFF;
}
CONVERT_FUNCS(rgb16f, 3 * sizeof (guint16))
static inline void
convert_pixel_rgba16f (guchar *dest_data, const guchar *src_data)
{
float src[4];
half_to_float4((const guint16 *) src_data, src);
dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f);
dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f);
dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f);
dest_data[3] = CLAMP (src[3] * 256.f, 0.f, 255.f);
}
CONVERT_FUNCS(rgba16f, 4 * sizeof (guint16))
static inline void
convert_pixel_rgb32f (guchar *dest_data, const guchar *src_data)
{
float *src = (float *) src_data;
dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f);
dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f);
dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f);
dest_data[3] = 0xFF;
}
CONVERT_FUNCS(rgb32f, 3 * sizeof (float))
static inline void
convert_pixel_rgba32f (guchar *dest_data, const guchar *src_data)
{
float *src = (float *) src_data;
dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f);
dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f);
dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f);
dest_data[3] = CLAMP (src[3] * 256.f, 0.f, 255.f);
}
CONVERT_FUNCS(rgba32f, 4 * sizeof (float))
typedef void (* ConversionFunc) (guchar *dest_data,
gsize dest_stride,
const guchar *src_data,
gsize src_stride,
gsize width,
gsize height);
static ConversionFunc converters[GDK_MEMORY_N_FORMATS][GDK_MEMORY_N_CONVERSIONS] =
{
{ convert_memcpy, convert_swizzle3210, convert_swizzle2103 },
{ convert_swizzle3210, convert_memcpy, convert_swizzle3012 },
{ convert_swizzle2103, convert_swizzle1230, convert_memcpy },
{ convert_swizzle_premultiply_3210_3210, convert_swizzle_premultiply_0123_3210, convert_swizzle_premultiply_3012_3210, },
{ convert_swizzle_premultiply_3210_0123, convert_swizzle_premultiply_0123_0123, convert_swizzle_premultiply_3012_0123 },
{ convert_swizzle_premultiply_3210_3012, convert_swizzle_premultiply_0123_3012, convert_swizzle_premultiply_3012_3012 },
{ convert_swizzle_premultiply_3210_0321, convert_swizzle_premultiply_0123_0321, convert_swizzle_premultiply_3012_0321 },
{ 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_rgb16_to_download_le, convert_rgb16_to_download_be, convert_rgb16_to_gles_rgba },
{ convert_rgba16_to_download_le, convert_rgba16_to_download_be, convert_rgba16_to_gles_rgba },
{ convert_rgb16f_to_download_le, convert_rgb16f_to_download_be, convert_rgb16f_to_gles_rgba },
{ convert_rgba16f_to_download_le, convert_rgba16f_to_download_be, convert_rgba16f_to_gles_rgba },
{ convert_rgb32f_to_download_le, convert_rgb32f_to_download_be, convert_rgb32f_to_gles_rgba },
{ convert_rgba32f_to_download_le, convert_rgba32f_to_download_be, convert_rgba32f_to_gles_rgba }
};
void
gdk_memory_convert (guchar *dest_data,
gsize dest_stride,
GdkMemoryConversion dest_format,
const guchar *src_data,
gsize src_stride,
GdkMemoryFormat src_format,
gsize width,
gsize height)
{
g_assert (dest_format < 3);
g_assert (src_format < GDK_MEMORY_N_FORMATS);
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
#define CONVERT_FLOAT_PIXEL(func,step) G_STMT_START{\
for (y = 0; y < height; y++) \
{ \
for (x = 0; x < width; x++) \
{ \
func (dest_data + 4 * x, src_data + step * x); \
} \
\
dest_data += dest_stride; \
src_data += src_stride; \
} \
}G_STMT_END
static inline void
convert_rgb16_to_float (float *dest, const guchar *src_data)
{
const guint16 *src = (const guint16 *) src_data;
dest[0] = src[0] / 65535.f;
dest[1] = src[1] / 65535.f;
dest[2] = src[2] / 65535.f;
dest[3] = 1.0;
}
static inline void
convert_rgba16_to_float (float *dest, const guchar *src_data)
{
const guint16 *src = (const guint16 *) src_data;
dest[0] = src[0] / 65535.f;
dest[1] = src[1] / 65535.f;
dest[2] = src[2] / 65535.f;
dest[3] = src[3] / 65535.f;
}
static inline void
convert_rgb16f_to_float (float *dest, const guchar *src_data)
{
guint16 tmp[4];
memcpy(tmp, src_data, sizeof(guint16) * 3);
tmp[3] = FP16_ONE;
half_to_float4 (tmp, dest);
}
static inline void
convert_rgba16f_to_float (float *dest, const guchar *src_data)
{
half_to_float4 ((const guint16 *) src_data, dest);
}
static inline void
convert_rgb32f_to_float (float *dest, const guchar *src_data)
{
const float *src = (const float *) src_data;
dest[0] = src[0];
dest[1] = src[1];
dest[2] = src[2];
dest[3] = 1.0;
}
static inline void
convert_rgba32f_to_float (float *dest, const guchar *src_data)
{
const float *src = (const float *) src_data;
dest[0] = src[0];
dest[1] = src[1];
dest[2] = src[2];
dest[3] = src[3];
}
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_R16G16B16:
CONVERT_FLOAT_PIXEL (convert_rgb16_to_float, 3 * sizeof (guint16));
break;
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
CONVERT_FLOAT_PIXEL (convert_rgba16_to_float, 4 * sizeof (guint16));
break;
case GDK_MEMORY_R16G16B16_FLOAT:
CONVERT_FLOAT_PIXEL (convert_rgb16f_to_float, 3 * sizeof (guint16));
break;
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
CONVERT_FLOAT_PIXEL (convert_rgba16f_to_float, 4 * sizeof (guint16));
break;
case GDK_MEMORY_R32G32B32_FLOAT:
CONVERT_FLOAT_PIXEL (convert_rgb32f_to_float, 3 * sizeof (float));
break;
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
CONVERT_FLOAT_PIXEL (convert_rgba32f_to_float, 4 * sizeof (float));
break;
case GDK_MEMORY_N_FORMATS:
default:
g_assert_not_reached();
}
}

View File

@ -29,45 +29,9 @@ G_BEGIN_DECLS
#define GDK_MEMORY_GDK_PIXBUF_OPAQUE GDK_MEMORY_R8G8B8
#define GDK_MEMORY_GDK_PIXBUF_ALPHA GDK_MEMORY_R8G8B8A8
typedef enum {
GDK_MEMORY_CONVERT_DOWNLOAD_LITTLE_ENDIAN,
GDK_MEMORY_CONVERT_DOWNLOAD_BIT_ENDIAN,
GDK_MEMORY_CONVERT_GLES_RGBA,
GDK_MEMORY_N_CONVERSIONS
} GdkMemoryConversion;
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
#define GDK_MEMORY_CONVERT_DOWNLOAD GDK_MEMORY_CONVERT_DOWNLOAD_LITTLE_ENDIAN
#elif G_BYTE_ORDER == G_BIG_ENDIAN
#define GDK_MEMORY_CONVERT_DOWNLOAD GDK_MEMORY_CONVERT_DOWNLOAD_BIG_ENDIAN
#else
#error "Unknown byte order for GDK_MEMORY_CONVERT_DOWNLOAD"
#endif
gsize gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format);
GdkMemoryFormat gdk_memory_texture_get_format (GdkMemoryTexture *self);
const guchar * gdk_memory_texture_get_data (GdkMemoryTexture *self);
gsize gdk_memory_texture_get_stride (GdkMemoryTexture *self);
void gdk_memory_convert (guchar *dest_data,
gsize dest_stride,
GdkMemoryConversion dest_format,
const guchar *src_data,
gsize src_stride,
GdkMemoryFormat src_format,
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

@ -71,7 +71,7 @@ struct _GdkSurfacePrivate
gpointer egl_native_window;
#ifdef HAVE_EGL
EGLSurface egl_surface;
gboolean egl_surface_hdr;
gboolean egl_surface_high_depth;
#endif
gpointer widget;
@ -1109,16 +1109,16 @@ gdk_surface_get_egl_surface (GdkSurface *self)
void
gdk_surface_ensure_egl_surface (GdkSurface *self,
gboolean hdr)
gboolean high_depth)
{
GdkSurfacePrivate *priv = gdk_surface_get_instance_private (self);
GdkDisplay *display = gdk_surface_get_display (self);
g_return_if_fail (priv->egl_native_window != NULL);
if (priv->egl_surface_hdr != hdr &&
if (priv->egl_surface_high_depth != high_depth &&
priv->egl_surface != NULL &&
gdk_display_get_egl_config_hdr (display) != gdk_display_get_egl_config (display))
gdk_display_get_egl_config_high_depth (display) != gdk_display_get_egl_config (display))
{
eglDestroySurface (gdk_surface_get_display (self), priv->egl_surface);
priv->egl_surface = NULL;
@ -1127,11 +1127,11 @@ gdk_surface_ensure_egl_surface (GdkSurface *self,
if (priv->egl_surface == NULL)
{
priv->egl_surface = eglCreateWindowSurface (gdk_display_get_egl_display (display),
hdr ? gdk_display_get_egl_config_hdr (display)
: gdk_display_get_egl_config (display),
high_depth ? gdk_display_get_egl_config_high_depth (display)
: gdk_display_get_egl_config (display),
(EGLNativeWindowType) priv->egl_native_window,
NULL);
priv->egl_surface_hdr = hdr;
priv->egl_surface_high_depth = high_depth;
}
#endif
}

View File

@ -808,6 +808,12 @@ gdk_texture_download_texture (GdkTexture *texture)
return texture;
}
GdkMemoryFormat
gdk_texture_get_format (GdkTexture *self)
{
return self->format;
}
gboolean
gdk_texture_set_render_data (GdkTexture *self,
gpointer key,
@ -972,4 +978,3 @@ gdk_texture_save_to_tiff_bytes (GdkTexture *texture)
return gdk_save_tiff (texture);
}

View File

@ -3,6 +3,8 @@
#include "gdktexture.h"
#include "gdkmemorytexture.h"
G_BEGIN_DECLS
#define GDK_TEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_TEXTURE, GdkTextureClass))
@ -13,6 +15,7 @@ struct _GdkTexture
{
GObject parent_instance;
GdkMemoryFormat format;
int width;
int height;
@ -42,6 +45,7 @@ cairo_surface_t * gdk_texture_download_surface (GdkTexture
/* NB: GdkMemoryTexture */
GdkTexture * gdk_texture_download_texture (GdkTexture *texture);
GdkMemoryFormat gdk_texture_get_format (GdkTexture *self);
gboolean gdk_texture_set_render_data (GdkTexture *self,
gpointer key,
gpointer data,

View File

@ -425,7 +425,7 @@ device_supports_incremental_present (VkPhysicalDevice device)
static void
gdk_vulkan_context_begin_frame (GdkDrawContext *draw_context,
gboolean request_hdr,
gboolean prefers_high_depth,
cairo_region_t *region)
{
GdkVulkanContext *context = GDK_VULKAN_CONTEXT (draw_context);

View File

@ -20,6 +20,7 @@
#include "gdkpngprivate.h"
#include "gdkintl.h"
#include "gdkmemoryformatprivate.h"
#include "gdkmemorytextureprivate.h"
#include "gdkprofilerprivate.h"
#include "gdktexture.h"
@ -480,7 +481,7 @@ gdk_save_png (GdkTexture *texture)
height = gdk_texture_get_height (texture);
mtexture = gdk_texture_download_texture (texture);
format = gdk_memory_texture_get_format (GDK_MEMORY_TEXTURE (mtexture));
format = gdk_texture_get_format (mtexture);
switch (format)
{

View File

@ -20,6 +20,7 @@
#include "gdktiffprivate.h"
#include "gdkintl.h"
#include "gdkmemoryformatprivate.h"
#include "gdkmemorytextureprivate.h"
#include "gdkprofilerprivate.h"
#include "gdktexture.h"
@ -283,7 +284,7 @@ gdk_save_tiff (GdkTexture *texture)
height = gdk_texture_get_height (texture);
memory_texture = gdk_texture_download_texture (texture);
format = gdk_memory_texture_get_format (GDK_MEMORY_TEXTURE (memory_texture));
format = gdk_texture_get_format (memory_texture);
for (int i = 0; i < G_N_ELEMENTS (format_data); i++)
{

View File

@ -82,7 +82,7 @@ _gdk_macos_cairo_context_cairo_create (GdkCairoContext *cairo_context)
static void
_gdk_macos_cairo_context_begin_frame (GdkDrawContext *draw_context,
gboolean request_hdr,
gboolean prefers_high_depth,
cairo_region_t *region)
{
GdkMacosCairoContext *self = (GdkMacosCairoContext *)draw_context;

View File

@ -291,7 +291,7 @@ opaque_region_covers_surface (GdkMacosGLContext *self)
static void
gdk_macos_gl_context_begin_frame (GdkDrawContext *context,
gboolean request_hdr,
gboolean prefers_high_depth,
cairo_region_t *painted)
{
GdkMacosGLContext *self = (GdkMacosGLContext *)context;
@ -345,7 +345,7 @@ gdk_macos_gl_context_begin_frame (GdkDrawContext *context,
[self->gl_context update];
}
GDK_DRAW_CONTEXT_CLASS (gdk_macos_gl_context_parent_class)->begin_frame (context, request_hdr, painted);
GDK_DRAW_CONTEXT_CLASS (gdk_macos_gl_context_parent_class)->begin_frame (context, prefers_high_depth, painted);
if (!self->is_attached)
{

View File

@ -30,6 +30,7 @@ gdk_public_sources = files([
'gdkhsla.c',
'gdkkeys.c',
'gdkkeyuni.c',
'gdkmemoryformat.c',
'gdkmemorytexture.c',
'gdkmonitor.c',
'gdkpaintable.c',

View File

@ -144,7 +144,7 @@ gdk_wayland_cairo_context_create_surface (GdkWaylandCairoContext *self)
static void
gdk_wayland_cairo_context_begin_frame (GdkDrawContext *draw_context,
gboolean request_hdr,
gboolean prefers_high_depth,
cairo_region_t *region)
{
GdkWaylandCairoContext *self = GDK_WAYLAND_CAIRO_CONTEXT (draw_context);

View File

@ -47,12 +47,12 @@ G_DEFINE_TYPE (GdkWaylandGLContext, gdk_wayland_gl_context, GDK_TYPE_GL_CONTEXT)
static void
gdk_wayland_gl_context_begin_frame (GdkDrawContext *draw_context,
gboolean request_hdr,
gboolean prefers_high_depth,
cairo_region_t *region)
{
gdk_wayland_surface_ensure_wl_egl_window (gdk_draw_context_get_surface (draw_context));
GDK_DRAW_CONTEXT_CLASS (gdk_wayland_gl_context_parent_class)->begin_frame (draw_context, request_hdr, region);
GDK_DRAW_CONTEXT_CLASS (gdk_wayland_gl_context_parent_class)->begin_frame (draw_context, prefers_high_depth, region);
glDrawBuffers (1, (GLenum[1]) { GL_BACK });
}

View File

@ -53,7 +53,7 @@ create_cairo_surface_for_surface (GdkSurface *surface,
static void
gdk_win32_cairo_context_begin_frame (GdkDrawContext *draw_context,
gboolean request_hdr,
gboolean prefers_high_depth,
cairo_region_t *region)
{
GdkWin32CairoContext *self = GDK_WIN32_CAIRO_CONTEXT (draw_context);

View File

@ -471,12 +471,12 @@ gdk_win32_gl_context_egl_make_current (GdkGLContext *context,
static void
gdk_win32_gl_context_egl_begin_frame (GdkDrawContext *draw_context,
gboolean request_hdr,
gboolean prefers_high_depth,
cairo_region_t *update_area)
{
gdk_win32_surface_handle_queued_move_resize (draw_context);
GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_egl_parent_class)->begin_frame (draw_context, request_hdr, update_area);
GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_egl_parent_class)->begin_frame (draw_context, prefers_high_depth, update_area);
}
static void

View File

@ -118,12 +118,12 @@ gdk_win32_gl_context_wgl_end_frame (GdkDrawContext *draw_context,
static void
gdk_win32_gl_context_wgl_begin_frame (GdkDrawContext *draw_context,
gboolean request_hdr,
gboolean prefers_high_depth,
cairo_region_t *update_area)
{
gdk_win32_surface_handle_queued_move_resize (draw_context);
GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_wgl_parent_class)->begin_frame (draw_context, request_hdr, update_area);
GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_wgl_parent_class)->begin_frame (draw_context, prefers_high_depth, update_area);
}
static int

View File

@ -68,12 +68,12 @@ gdk_win32_vulkan_context_create_surface (GdkVulkanContext *context,
static void
gdk_win32_vulkan_context_begin_frame (GdkDrawContext *draw_context,
gboolean request_hdr,
gboolean prefers_high_depth,
cairo_region_t *update_area)
{
gdk_win32_surface_handle_queued_move_resize (draw_context);
GDK_DRAW_CONTEXT_CLASS (gdk_win32_vulkan_context_parent_class)->begin_frame (draw_context, request_hdr, update_area);
GDK_DRAW_CONTEXT_CLASS (gdk_win32_vulkan_context_parent_class)->begin_frame (draw_context, prefers_high_depth, update_area);
}
static void

View File

@ -55,7 +55,7 @@ create_cairo_surface_for_surface (GdkSurface *surface)
static void
gdk_x11_cairo_context_begin_frame (GdkDrawContext *draw_context,
gboolean request_hdr,
gboolean prefers_high_depth,
cairo_region_t *region)
{
GdkX11CairoContext *self = GDK_X11_CAIRO_CONTEXT (draw_context);

View File

@ -61,10 +61,10 @@ gdk_x11_display_get_egl_display (GdkDisplay *display)
static void
gdk_x11_gl_context_egl_begin_frame (GdkDrawContext *draw_context,
gboolean request_hdr,
gboolean prefers_high_depth,
cairo_region_t *region)
{
GDK_DRAW_CONTEXT_CLASS (gdk_x11_gl_context_egl_parent_class)->begin_frame (draw_context, request_hdr, region);
GDK_DRAW_CONTEXT_CLASS (gdk_x11_gl_context_egl_parent_class)->begin_frame (draw_context, prefers_high_depth, region);
glDrawBuffers (1, (GLenum[1]) { GL_BACK });
}

View File

@ -725,3 +725,8 @@ gsk_value_dup_render_node (const GValue *value)
return gsk_render_node_ref (value->data[0].v_pointer);
}
gboolean
gsk_render_node_prefers_high_depth (const GskRenderNode *node)
{
return node->prefers_high_depth;
}

View File

@ -28,6 +28,7 @@
#include "gsktransformprivate.h"
#include "gdk/gdktextureprivate.h"
#include "gdk/gdkmemoryformatprivate.h"
#include "gdk/gdk-private.h"
#include <hb-ot.h>
@ -1560,6 +1561,8 @@ gsk_texture_node_new (GdkTexture *texture,
self->texture = g_object_ref (texture);
graphene_rect_init_from_rect (&node->bounds, bounds);
node->prefers_high_depth = gdk_memory_format_prefers_high_depth (gdk_texture_get_format (texture));
return node;
}
@ -2730,11 +2733,13 @@ gsk_container_node_new (GskRenderNode **children,
self->children[0] = gsk_render_node_ref (children[0]);
graphene_rect_init_from_rect (&bounds, &(children[0]->bounds));
node->prefers_high_depth = gsk_render_node_prefers_high_depth (children[0]);
for (guint i = 1; i < n_children; i++)
{
self->children[i] = gsk_render_node_ref (children[i]);
graphene_rect_union (&bounds, &(children[i]->bounds), &bounds);
node->prefers_high_depth |= gsk_render_node_prefers_high_depth (children[i]);
}
graphene_rect_init_from_rect (&node->bounds, &bounds);
@ -2965,6 +2970,8 @@ gsk_transform_node_new (GskRenderNode *child,
&child->bounds,
&node->bounds);
node->prefers_high_depth = gsk_render_node_prefers_high_depth (child);
return node;
}
@ -3100,6 +3107,8 @@ gsk_opacity_node_new (GskRenderNode *child,
graphene_rect_init_from_rect (&node->bounds, &child->bounds);
node->prefers_high_depth = gsk_render_node_prefers_high_depth (child);
return node;
}
@ -3302,6 +3311,8 @@ gsk_color_matrix_node_new (GskRenderNode *child,
graphene_rect_init_from_rect (&node->bounds, &child->bounds);
node->prefers_high_depth = gsk_render_node_prefers_high_depth (child);
return node;
}
@ -3451,6 +3462,8 @@ gsk_repeat_node_new (const graphene_rect_t *bounds,
else
graphene_rect_init_from_rect (&self->child_bounds, &child->bounds);
node->prefers_high_depth = gsk_render_node_prefers_high_depth (child);
return node;
}
@ -3582,6 +3595,8 @@ gsk_clip_node_new (GskRenderNode *child,
graphene_rect_intersection (&self->clip, &child->bounds, &node->bounds);
node->prefers_high_depth = gsk_render_node_prefers_high_depth (child);
return node;
}
@ -3713,6 +3728,8 @@ gsk_rounded_clip_node_new (GskRenderNode *child,
graphene_rect_intersection (&self->clip.bounds, &child->bounds, &node->bounds);
node->prefers_high_depth = gsk_render_node_prefers_high_depth (child);
return node;
}
@ -3932,6 +3949,8 @@ gsk_shadow_node_new (GskRenderNode *child,
gsk_shadow_node_get_bounds (self, &node->bounds);
node->prefers_high_depth = gsk_render_node_prefers_high_depth (child);
return node;
}
@ -4125,6 +4144,8 @@ gsk_blend_node_new (GskRenderNode *bottom,
graphene_rect_union (&bottom->bounds, &top->bounds, &node->bounds);
node->prefers_high_depth = gsk_render_node_prefers_high_depth (bottom) || gsk_render_node_prefers_high_depth (top);
return node;
}
@ -4273,6 +4294,8 @@ gsk_cross_fade_node_new (GskRenderNode *start,
graphene_rect_union (&start->bounds, &end->bounds, &node->bounds);
node->prefers_high_depth = gsk_render_node_prefers_high_depth (start) || gsk_render_node_prefers_high_depth (end);
return node;
}
@ -4864,6 +4887,8 @@ gsk_blur_node_new (GskRenderNode *child,
- clip_radius,
- clip_radius);
node->prefers_high_depth = gsk_render_node_prefers_high_depth (child);
return node;
}
@ -4986,6 +5011,8 @@ gsk_debug_node_new (GskRenderNode *child,
graphene_rect_init_from_rect (&node->bounds, &child->bounds);
node->prefers_high_depth = gsk_render_node_prefers_high_depth (child);
return node;
}
@ -5150,7 +5177,10 @@ gsk_gl_shader_node_new (GskGLShader *shader,
{
self->children = g_malloc_n (n_children, sizeof (GskRenderNode *));
for (guint i = 0; i < n_children; i++)
self->children[i] = gsk_render_node_ref (children[i]);
{
self->children[i] = gsk_render_node_ref (children[i]);
node->prefers_high_depth |= gsk_render_node_prefers_high_depth (children[i]);
}
}
return node;

View File

@ -27,6 +27,8 @@ struct _GskRenderNode
gatomicrefcount ref_count;
graphene_rect_t bounds;
guint prefers_high_depth : 1;
};
struct _GskRenderNodeClass
@ -109,6 +111,7 @@ GskRenderNode ** gsk_container_node_get_children (const GskRenderNode *no
void gsk_transform_node_get_translate (const GskRenderNode *node,
float *dx,
float *dy);
gboolean gsk_render_node_prefers_high_depth (const GskRenderNode *node);
G_END_DECLS

View File

@ -26,6 +26,7 @@
#include <string.h>
#include <gdk/gdkglcontextprivate.h>
#include <gdk/gdkmemoryformatprivate.h>
#include <gdk/gdkmemorytextureprivate.h>
#include <gdk/gdkprofilerprivate.h>
#include <gsk/gskdebugprivate.h>
@ -1231,6 +1232,7 @@ gboolean
gsk_ngl_command_queue_create_render_target (GskNglCommandQueue *self,
int width,
int height,
int format,
int min_filter,
int mag_filter,
guint *out_fbo_id,
@ -1247,6 +1249,7 @@ gsk_ngl_command_queue_create_render_target (GskNglCommandQueue *self,
texture_id = gsk_ngl_command_queue_create_texture (self,
width, height,
format,
min_filter, mag_filter);
if (texture_id == -1)
@ -1272,6 +1275,7 @@ int
gsk_ngl_command_queue_create_texture (GskNglCommandQueue *self,
int width,
int height,
int format,
int min_filter,
int mag_filter)
{
@ -1296,9 +1300,9 @@ gsk_ngl_command_queue_create_texture (GskNglCommandQueue *self,
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (gdk_gl_context_get_use_es (self->context))
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexImage2D (GL_TEXTURE_2D, 0, format, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
else
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
glTexImage2D (GL_TEXTURE_2D, 0, format, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
/* Restore the previous texture if it was set */
if (self->attachments->textures[0].id != 0)
@ -1353,7 +1357,7 @@ gsk_ngl_command_queue_upload_texture (GskNglCommandQueue *self,
height = MAX (height, self->max_texture_size);
}
texture_id = gsk_ngl_command_queue_create_texture (self, width, height, min_filter, mag_filter);
texture_id = gsk_ngl_command_queue_create_texture (self, width, height, GL_RGBA8, min_filter, mag_filter);
if (texture_id == -1)
return texture_id;
@ -1361,7 +1365,7 @@ gsk_ngl_command_queue_upload_texture (GskNglCommandQueue *self,
{
GdkMemoryTexture *memory_texture = GDK_MEMORY_TEXTURE (texture);
data = gdk_memory_texture_get_data (memory_texture);
data_format = gdk_memory_texture_get_format (memory_texture);
data_format = gdk_texture_get_format (texture);
data_stride = gdk_memory_texture_get_stride (memory_texture);
}
else

View File

@ -290,12 +290,14 @@ int gsk_ngl_command_queue_upload_texture (GskNglCommandQue
int gsk_ngl_command_queue_create_texture (GskNglCommandQueue *self,
int width,
int height,
int format,
int min_filter,
int mag_filter);
guint gsk_ngl_command_queue_create_framebuffer (GskNglCommandQueue *self);
gboolean gsk_ngl_command_queue_create_render_target (GskNglCommandQueue *self,
int width,
int height,
int format,
int min_filter,
int mag_filter,
guint *out_fbo_id,

View File

@ -183,6 +183,7 @@ gsk_ngl_driver_create_atlas (GskNglDriver *self)
atlas->texture_id = gsk_ngl_command_queue_create_texture (self->command_queue,
atlas->width,
atlas->height,
GL_RGBA8,
GL_LINEAR,
GL_LINEAR);
@ -750,6 +751,7 @@ gsk_ngl_driver_load_texture (GskNglDriver *self,
guint texture_id;
int height;
int width;
int format;
g_return_val_if_fail (GSK_IS_NGL_DRIVER (self), 0);
g_return_val_if_fail (GDK_IS_TEXTURE (texture), 0);
@ -757,6 +759,8 @@ gsk_ngl_driver_load_texture (GskNglDriver *self,
context = self->command_queue->context;
format = GL_RGBA8;
if (GDK_IS_GL_TEXTURE (texture))
{
GdkGLTexture *gl_texture = (GdkGLTexture *) texture;
@ -799,7 +803,7 @@ gsk_ngl_driver_load_texture (GskNglDriver *self,
mag_filter);
t = gsk_ngl_texture_new (texture_id,
width, height, min_filter, mag_filter,
width, height, format, min_filter, mag_filter,
self->current_frame_id);
g_hash_table_insert (self->textures, GUINT_TO_POINTER (texture_id), t);
@ -820,6 +824,7 @@ gsk_ngl_driver_load_texture (GskNglDriver *self,
* @self: a `GskNglDriver`
* @width: the width of the texture
* @height: the height of the texture
* @format: format for the texture
* @min_filter: GL_NEAREST or GL_LINEAR
* @mag_filter: GL_NEAREST or GL_FILTER
*
@ -827,6 +832,8 @@ gsk_ngl_driver_load_texture (GskNglDriver *self,
* to upload data, map to a framebuffer, or other uses which may
* modify the texture immediately.
*
* Typical examples for @format are GK_RGBA8, GL_RGBA16F or GL_RGBA32F.
*
* Use gsk_ngl_driver_release_texture() to release this texture back into
* the pool so it may be reused later in the pipeline.
*
@ -837,6 +844,7 @@ GskNglTexture *
gsk_ngl_driver_create_texture (GskNglDriver *self,
float width,
float height,
int format,
int min_filter,
int mag_filter)
{
@ -847,9 +855,11 @@ gsk_ngl_driver_create_texture (GskNglDriver *self,
texture_id = gsk_ngl_command_queue_create_texture (self->command_queue,
width, height,
format,
min_filter, mag_filter);
texture = gsk_ngl_texture_new (texture_id,
width, height,
format,
min_filter, mag_filter,
self->current_frame_id);
g_hash_table_insert (self->textures,
@ -896,6 +906,7 @@ gsk_ngl_driver_release_texture (GskNglDriver *self,
* @self: a `GskNglDriver`
* @width: the width for the render target
* @height: the height for the render target
* @format: the format to use
* @min_filter: the min filter to use for the texture
* @mag_filter: the mag filter to use for the texture
* @out_render_target: (out): a location for the render target
@ -904,6 +915,8 @@ gsk_ngl_driver_release_texture (GskNglDriver *self,
* bound to that framebuffer of the size @width x @height and using the
* appropriate filters.
*
* Typical examples for @format are GK_RGBA8, GL_RGBA16F or GL_RGBA32F.
*
* Use gsk_ngl_driver_release_render_target() when you are finished with
* the render target to release it. You may steal the texture from the
* render target when releasing it.
@ -915,6 +928,7 @@ gboolean
gsk_ngl_driver_create_render_target (GskNglDriver *self,
int width,
int height,
int format,
int min_filter,
int mag_filter,
GskNglRenderTarget **out_render_target)
@ -947,6 +961,7 @@ gsk_ngl_driver_create_render_target (GskNglDriver *self,
if (gsk_ngl_command_queue_create_render_target (self->command_queue,
width, height,
format,
min_filter, mag_filter,
&framebuffer_id, &texture_id))
{
@ -955,6 +970,7 @@ gsk_ngl_driver_create_render_target (GskNglDriver *self,
render_target = g_slice_new0 (GskNglRenderTarget);
render_target->min_filter = min_filter;
render_target->mag_filter = mag_filter;
render_target->format = format;
render_target->width = width;
render_target->height = height;
render_target->framebuffer_id = framebuffer_id;
@ -1014,6 +1030,7 @@ gsk_ngl_driver_release_render_target (GskNglDriver *self,
texture = gsk_ngl_texture_new (render_target->texture_id,
render_target->width,
render_target->height,
render_target->format,
render_target->min_filter,
render_target->mag_filter,
self->current_frame_id);
@ -1266,6 +1283,7 @@ gsk_ngl_driver_add_texture_slices (GskNglDriver *self,
/* Allocate one Texture for the entire thing. */
t = gsk_ngl_texture_new (0,
tex_width, tex_height,
GL_RGBA8,
GL_NEAREST, GL_NEAREST,
self->current_frame_id);

View File

@ -88,6 +88,7 @@ struct _GskNglRenderTarget
guint texture_id;
int min_filter;
int mag_filter;
int format;
int width;
int height;
};
@ -144,6 +145,7 @@ GdkGLContext *gsk_ngl_driver_get_context (GskNglDriver
gboolean gsk_ngl_driver_create_render_target (GskNglDriver *self,
int width,
int height,
int format,
int min_filter,
int mag_filter,
GskNglRenderTarget **render_target);
@ -166,6 +168,7 @@ guint gsk_ngl_driver_load_texture (GskNglDriver
GskNglTexture *gsk_ngl_driver_create_texture (GskNglDriver *self,
float width,
float height,
int format,
int min_filter,
int mag_filter);
void gsk_ngl_driver_release_texture (GskNglDriver *self,

View File

@ -21,7 +21,7 @@
#include "config.h"
#include <gdk/gdkglcontextprivate.h>
#include <gdk/gdkmemorytextureprivate.h>
#include <gdk/gdkmemoryformatprivate.h>
#include <gdk/gdkprofilerprivate.h>
#include "gsknglcommandqueueprivate.h"
@ -237,7 +237,7 @@ gsk_ngl_glyph_library_upload_glyph (GskNglGlyphLibrary *self,
pixel_data = free_data = g_malloc (width * height * 4);
gdk_memory_convert (pixel_data,
width * 4,
GDK_MEMORY_CONVERT_GLES_RGBA,
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
cairo_image_surface_get_data (surface),
width * 4,
GDK_MEMORY_DEFAULT,

View File

@ -21,7 +21,7 @@
#include "config.h"
#include <gdk/gdkglcontextprivate.h>
#include <gdk/gdkmemorytextureprivate.h>
#include <gdk/gdkmemoryformatprivate.h>
#include <gdk/gdkprofilerprivate.h>
#include <gdk/gdktextureprivate.h>
@ -115,7 +115,7 @@ gsk_ngl_icon_library_add (GskNglIconLibrary *self,
{
pixel_data = free_data = g_malloc (width * height * 4);
gdk_memory_convert (pixel_data, width * 4,
GDK_MEMORY_CONVERT_GLES_RGBA,
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
surface_data, cairo_image_surface_get_stride (surface),
GDK_MEMORY_DEFAULT, width, height);
gl_format = GL_RGBA;

View File

@ -22,8 +22,11 @@
#include <gdk/gdkprofilerprivate.h>
#include <gdk/gdkdisplayprivate.h>
#include <gdk/gdkglcontextprivate.h>
#include <gdk/gdksurfaceprivate.h>
#include <gsk/gskdebugprivate.h>
#include <gsk/gskrendererprivate.h>
#include <gsk/gskrendernodeprivate.h>
#include "gsknglcommandqueueprivate.h"
#include "gskngldriverprivate.h"
@ -201,7 +204,9 @@ gsk_ngl_renderer_render (GskRenderer *renderer,
viewport.size.height = gdk_surface_get_height (surface) * scale_factor;
gdk_gl_context_make_current (self->context);
gdk_draw_context_begin_frame (GDK_DRAW_CONTEXT (self->context), update_area);
gdk_draw_context_begin_frame_full (GDK_DRAW_CONTEXT (self->context),
gsk_render_node_prefers_high_depth (root),
update_area);
/* Must be called *AFTER* gdk_draw_context_begin_frame() */
render_region = get_render_region (surface, self->context);
@ -236,6 +241,7 @@ gsk_ngl_renderer_render_texture (GskRenderer *renderer,
guint texture_id;
int width;
int height;
int format;
g_assert (GSK_IS_NGL_RENDERER (renderer));
g_assert (root != NULL);
@ -243,8 +249,11 @@ gsk_ngl_renderer_render_texture (GskRenderer *renderer,
width = ceilf (viewport->size.width);
height = ceilf (viewport->size.height);
format = gsk_render_node_prefers_high_depth (root) ? GL_RGBA32F : GL_RGBA8;
if (gsk_ngl_driver_create_render_target (self->driver,
width, height,
format,
GL_NEAREST, GL_NEAREST,
&render_target))
{

View File

@ -162,6 +162,11 @@ struct _GskNglRenderJob
/* If we should be rendering red zones over fallback nodes */
guint debug_fallback : 1;
/* Format we want to use for intermediate textures, determined by
* looking at the format of the framebuffer we are rendering on.
*/
int target_format;
};
typedef struct _GskNglRenderOffscreen
@ -198,6 +203,16 @@ static gboolean gsk_ngl_render_job_visit_node_with_offscreen (GskNglRenderJob
const GskRenderNode *node,
GskNglRenderOffscreen *offscreen);
static inline int
get_target_format (GskNglRenderJob *job,
const GskRenderNode *node)
{
if (gsk_render_node_prefers_high_depth (node))
return job->target_format;
return GL_RGBA8;
}
static inline void
init_full_texture_region (GskNglRenderOffscreen *offscreen)
{
@ -1258,6 +1273,7 @@ blur_offscreen (GskNglRenderJob *job,
if (!gsk_ngl_driver_create_render_target (job->driver,
MAX (texture_to_blur_width, 1),
MAX (texture_to_blur_height, 1),
job->target_format,
GL_NEAREST, GL_NEAREST,
&pass1))
return 0;
@ -1268,6 +1284,7 @@ blur_offscreen (GskNglRenderJob *job,
if (!gsk_ngl_driver_create_render_target (job->driver,
texture_to_blur_width,
texture_to_blur_height,
job->target_format,
GL_NEAREST, GL_NEAREST,
&pass2))
return gsk_ngl_driver_release_render_target (job->driver, pass1, FALSE);
@ -2179,6 +2196,7 @@ gsk_ngl_render_job_visit_blurred_inset_shadow_node (GskNglRenderJob *job,
if (!gsk_ngl_driver_create_render_target (job->driver,
texture_width, texture_height,
get_target_format (job, node),
GL_NEAREST, GL_NEAREST,
&render_target))
g_assert_not_reached ();
@ -2449,6 +2467,7 @@ gsk_ngl_render_job_visit_blurred_outset_shadow_node (GskNglRenderJob *job,
gsk_ngl_driver_create_render_target (job->driver,
texture_width, texture_height,
get_target_format (job, node),
GL_NEAREST, GL_NEAREST,
&render_target);
@ -3856,6 +3875,7 @@ gsk_ngl_render_job_visit_node_with_offscreen (GskNglRenderJob *job,
if (!gsk_ngl_driver_create_render_target (job->driver,
scaled_width, scaled_height,
get_target_format (job, node),
filter, filter,
&render_target))
g_assert_not_reached ();
@ -3954,6 +3974,7 @@ gsk_ngl_render_job_render_flipped (GskNglRenderJob *job,
if (!gsk_ngl_command_queue_create_render_target (job->command_queue,
MAX (1, job->viewport.size.width),
MAX (1, job->viewport.size.height),
job->target_format,
GL_NEAREST, GL_NEAREST,
&framebuffer_id, &texture_id))
return;
@ -4044,6 +4065,22 @@ gsk_ngl_render_job_set_debug_fallback (GskNglRenderJob *job,
job->debug_fallback = !!debug_fallback;
}
static int
get_framebuffer_format (guint framebuffer)
{
int size;
glBindFramebuffer (GL_FRAMEBUFFER, framebuffer);
glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, &size);
if (size >= 32)
return GL_RGBA32F;
else if (size >= 16)
return GL_RGBA16F;
else
return GL_RGBA8;
}
GskNglRenderJob *
gsk_ngl_render_job_new (GskNglDriver *driver,
const graphene_rect_t *viewport,
@ -4070,6 +4107,7 @@ gsk_ngl_render_job_new (GskNglDriver *driver,
job->scale_x = scale_factor;
job->scale_y = scale_factor;
job->viewport = *viewport;
job->target_format = get_framebuffer_format (framebuffer);
gsk_ngl_render_job_set_alpha (job, 1.0f);
gsk_ngl_render_job_set_projection_from_rect (job, viewport, NULL);

View File

@ -59,6 +59,7 @@ GskNglTexture *
gsk_ngl_texture_new (guint texture_id,
int width,
int height,
int format,
int min_filter,
int mag_filter,
gint64 frame_id)
@ -70,6 +71,7 @@ gsk_ngl_texture_new (guint texture_id,
texture->link.data = texture;
texture->min_filter = min_filter;
texture->mag_filter = mag_filter;
texture->format = format;
texture->width = width;
texture->height = height;
texture->last_used_in_frame = frame_id;

View File

@ -228,7 +228,7 @@ gsk_ngl_texture_library_pack_one (GskNglTextureLibrary *self,
height = MIN (height, self->driver->command_queue->max_texture_size);
}
texture = gsk_ngl_driver_create_texture (self->driver, width, height, GL_LINEAR, GL_LINEAR);
texture = gsk_ngl_driver_create_texture (self->driver, width, height, GL_RGBA8, GL_LINEAR, GL_LINEAR);
texture->permanent = TRUE;
return texture;

View File

@ -67,6 +67,7 @@ struct _GskNglTexture
int height;
int min_filter;
int mag_filter;
int format;
/* Set when used by an atlas so we don't drop the texture */
guint permanent : 1;
@ -75,6 +76,7 @@ struct _GskNglTexture
GskNglTexture *gsk_ngl_texture_new (guint texture_id,
int width,
int height,
int format,
int min_filter,
int mag_filter,
gint64 frame_id);

View File

@ -1,6 +1,6 @@
#include <gtk.h>
static gboolean
static void
compare_pixels (int width,
int height,
guchar *data1,
@ -8,15 +8,17 @@ compare_pixels (int width,
guchar *data2,
gsize stride2)
{
int i;
for (i = 0; i < height; i++)
int x, y;
for (y = 0; y < height; y++)
{
gconstpointer p1 = data1 + i * stride1;
gconstpointer p2 = data2 + i * stride2;
if (memcmp (p1, p2, width * 4) != 0)
return FALSE;
const guint32 *p1 = (const guint32*) (data1 + y * stride1);
const guint32 *p2 = (const guint32*) (data2 + y * stride2);
for (x = 0; x < width; x++)
{
g_assert_cmphex (p1[x], ==, p2[x]);
}
}
return TRUE;
}
static void
@ -55,10 +57,10 @@ test_texture_from_pixbuf (void)
cairo_paint (cr);
cairo_destroy (cr);
g_assert_true (compare_pixels (width, height,
data, stride,
cairo_image_surface_get_data (surface),
cairo_image_surface_get_stride (surface)));
compare_pixels (width, height,
data, stride,
cairo_image_surface_get_data (surface),
cairo_image_surface_get_stride (surface));
g_free (data);