cairo: Improve gdk_texture_download_to_surface()

Previously, we were always downloading into CAIRO_FORMAT_ARGB32.
Now we check the texture depth and pick a suitable format.

This improves rendering for high depth content, but it's slower.

That's why we're not yet making sure the depth is suitable for the
colorspace conversion. That would force all SRGB textures into float
surfaces as we don't consider conversions suitable for U8 in our generic
code.
This commit is contained in:
Benjamin Otte
2024-07-05 01:22:13 +02:00
parent e6cfbc00fc
commit fa33af248e
2 changed files with 81 additions and 14 deletions

View File

@@ -1,8 +1,59 @@
#pragma once
#include "gdk/gdkcolorstateprivate.h"
#include "gdkcolorstateprivate.h"
#include "gdkmemoryformatprivate.h"
#include "gdkmemorytexture.h"
#include <cairo.h>
#include <graphene.h>
static inline cairo_format_t
gdk_cairo_format_for_depth (GdkMemoryDepth depth)
{
switch (depth)
{
case GDK_MEMORY_NONE:
case GDK_MEMORY_U8:
return CAIRO_FORMAT_ARGB32;
case GDK_MEMORY_U8_SRGB:
case GDK_MEMORY_U16:
case GDK_MEMORY_FLOAT16:
case GDK_MEMORY_FLOAT32:
return CAIRO_FORMAT_RGBA128F;
case GDK_N_DEPTHS:
default:
g_return_val_if_reached (CAIRO_FORMAT_ARGB32);
}
}
static inline GdkMemoryDepth
gdk_cairo_depth_for_format (cairo_format_t format)
{
switch (format)
{
case CAIRO_FORMAT_ARGB32:
case CAIRO_FORMAT_RGB24:
case CAIRO_FORMAT_RGB16_565:
case CAIRO_FORMAT_A1:
case CAIRO_FORMAT_A8:
return GDK_MEMORY_U8;
case CAIRO_FORMAT_RGB30:
return GDK_MEMORY_U16;
case CAIRO_FORMAT_RGB96F:
case CAIRO_FORMAT_RGBA128F:
return GDK_MEMORY_FLOAT32;
case CAIRO_FORMAT_INVALID:
default:
g_assert_not_reached ();
return GDK_MEMORY_NONE;
}
}
static GdkMemoryFormat
gdk_cairo_format_to_memory_format (cairo_format_t format)
@@ -76,6 +127,9 @@ gdk_cairo_surface_convert_color_state (cairo_surface_t *surface,
{
cairo_surface_t *image_surface;
if (gdk_color_state_equal (source, target))
return;
image_surface = cairo_surface_map_to_image (surface, NULL);
gdk_memory_convert_color_state (cairo_image_surface_get_data (image_surface),

View File

@@ -40,10 +40,12 @@
#include "gdktextureprivate.h"
#include "gdkcairoprivate.h"
#include "gdkcolorstateprivate.h"
#include "gdkmemorytextureprivate.h"
#include "gdkpaintable.h"
#include "gdksnapshot.h"
#include "gdktexturedownloaderprivate.h"
#include <glib/gi18n-lib.h>
#include <graphene.h>
@@ -921,12 +923,24 @@ cairo_surface_t *
gdk_texture_download_surface (GdkTexture *texture,
GdkColorState *color_state)
{
GdkMemoryDepth depth;
cairo_surface_t *surface;
cairo_status_t surface_status;
guchar *data;
gsize stride;
cairo_format_t surface_format;
GdkTextureDownloader downloader;
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
depth = gdk_texture_get_depth (texture);
#if 0
/* disabled for performance reasons. Enjoy living with some banding. */
if (!gdk_color_state_equal (texture->color_state, color_state))
depth = gdk_memory_depth_merge (depth, gdk_color_state_get_depth (color_state));
#else
if (depth == GDK_MEMORY_U8_SRGB)
depth = GDK_MEMORY_U8;
#endif
surface_format = gdk_cairo_format_for_depth (depth);
surface = cairo_image_surface_create (surface_format,
texture->width, texture->height);
surface_status = cairo_surface_status (surface);
@@ -937,16 +951,15 @@ gdk_texture_download_surface (GdkTexture *texture,
return surface;
}
data = cairo_image_surface_get_data (surface);
stride = cairo_image_surface_get_stride (surface);
gdk_texture_download (texture, data, stride);
gdk_memory_convert_color_state (data,
stride,
GDK_MEMORY_DEFAULT,
GDK_COLOR_STATE_SRGB,
color_state,
texture->width,
texture->height);
gdk_texture_downloader_init (&downloader, texture);
gdk_texture_downloader_set_format (&downloader,
gdk_cairo_format_to_memory_format (surface_format));
gdk_texture_downloader_download_into (&downloader,
cairo_image_surface_get_data (surface),
cairo_image_surface_get_stride (surface));
gdk_texture_downloader_finish (&downloader);
gdk_cairo_surface_convert_color_state (surface, texture->color_state, color_state);
cairo_surface_mark_dirty (surface);
return surface;