From cdb2308ddd375031bf3f5d90d0a52ea111d31afc Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Fri, 12 Jul 2024 16:38:56 +0200 Subject: [PATCH] gpu: Add filter support to tiled images This allows mipmapping if downscaled a lot, like we do for non-tiled images. A side effect is that due to the simpler caching for tiles, we can only cache the mipmapped images in one colorstate. But we need to pick a potentially non-default one, because we want to mipmap in a linear colorstate. So this is somewhat suboptimal. Patches with improvements accepted. --- gsk/gpu/gskgpucache.c | 30 ++++++++++++------- gsk/gpu/gskgpucacheprivate.h | 6 ++-- gsk/gpu/gskgpunodeprocessor.c | 54 ++++++++++++++++++++++++----------- 3 files changed, 61 insertions(+), 29 deletions(-) diff --git a/gsk/gpu/gskgpucache.c b/gsk/gpu/gskgpucache.c index 0cebeafe57..3e65f44fa3 100644 --- a/gsk/gpu/gskgpucache.c +++ b/gsk/gpu/gskgpucache.c @@ -417,6 +417,7 @@ struct _GskGpuCachedTile gsize *dead_pixels_counter; GskGpuImage *image; + GdkColorState *color_state; }; static void @@ -427,6 +428,7 @@ gsk_gpu_cached_tile_free (GskGpuCache *cache, gpointer key, value; g_clear_object (&self->image); + g_clear_pointer (&self->color_state, gdk_color_state_unref); if (g_hash_table_steal_extended (cache->tile_cache, self, &key, &value)) { @@ -512,7 +514,8 @@ static GskGpuCachedTile * gsk_gpu_cached_tile_new (GskGpuCache *cache, GdkTexture *texture, guint tile_id, - GskGpuImage *image) + GskGpuImage *image, + GdkColorState *color_state) { GskGpuCachedTile *self; @@ -520,6 +523,7 @@ gsk_gpu_cached_tile_new (GskGpuCache *cache, self->texture = texture; self->tile_id = tile_id; self->image = g_object_ref (image); + self->color_state = gdk_color_state_ref (color_state); ((GskGpuCached *)self)->pixels = gsk_gpu_image_get_width (image) * gsk_gpu_image_get_height (image); self->dead_pixels_counter = &cache->dead_texture_pixels; self->use_count = 2; @@ -534,10 +538,11 @@ gsk_gpu_cached_tile_new (GskGpuCache *cache, } GskGpuImage * -gsk_gpu_cache_lookup_tile (GskGpuCache *self, - GdkTexture *texture, - gsize tile_id, - gint64 timestamp) +gsk_gpu_cache_lookup_tile (GskGpuCache *self, + GdkTexture *texture, + gsize tile_id, + gint64 timestamp, + GdkColorState **out_color_state) { GskGpuCachedTile *tile; GskGpuCachedTile lookup = { @@ -554,19 +559,22 @@ gsk_gpu_cache_lookup_tile (GskGpuCache *self, gsk_gpu_cached_use (self, (GskGpuCached *) tile, timestamp); + *out_color_state = tile->color_state; + return g_object_ref (tile->image); } void -gsk_gpu_cache_cache_tile (GskGpuCache *self, - gint64 timestamp, - GdkTexture *texture, - guint tile_id, - GskGpuImage *image) +gsk_gpu_cache_cache_tile (GskGpuCache *self, + gint64 timestamp, + GdkTexture *texture, + guint tile_id, + GskGpuImage *image, + GdkColorState *color_state) { GskGpuCachedTile *tile; - tile = gsk_gpu_cached_tile_new (self, texture, tile_id, image); + tile = gsk_gpu_cached_tile_new (self, texture, tile_id, image, color_state); gsk_gpu_cached_use (self, (GskGpuCached *) tile, timestamp); } diff --git a/gsk/gpu/gskgpucacheprivate.h b/gsk/gpu/gskgpucacheprivate.h index b5dcc85805..6f448040dc 100644 --- a/gsk/gpu/gskgpucacheprivate.h +++ b/gsk/gpu/gskgpucacheprivate.h @@ -42,12 +42,14 @@ void gsk_gpu_cache_cache_texture_image (GskGpuC GskGpuImage * gsk_gpu_cache_lookup_tile (GskGpuCache *self, GdkTexture *texture, gsize tile_id, - gint64 timestamp); + gint64 timestamp, + GdkColorState **out_color_state); void gsk_gpu_cache_cache_tile (GskGpuCache *self, gint64 timestamp, GdkTexture *texture, guint tile_id, - GskGpuImage *image); + GskGpuImage *image, + GdkColorState *color_state); typedef enum { diff --git a/gsk/gpu/gskgpunodeprocessor.c b/gsk/gpu/gskgpunodeprocessor.c index 2f0dfa284d..2907236b79 100644 --- a/gsk/gpu/gskgpunodeprocessor.c +++ b/gsk/gpu/gskgpunodeprocessor.c @@ -1751,13 +1751,16 @@ gsk_gpu_sampler_for_scaling_filter (GskScalingFilter scaling_filter) static void gsk_gpu_node_processor_draw_texture_tiles (GskGpuNodeProcessor *self, const graphene_rect_t *texture_bounds, - GdkTexture *texture) + GdkTexture *texture, + GskScalingFilter scaling_filter) { GskGpuCache *cache; GskGpuDevice *device; gint64 timestamp; GskGpuImage *tile; GdkColorState *tile_cs; + GskGpuSampler sampler; + gboolean need_mipmap; GdkMemoryTexture *memtex; GdkTexture *subtex; float scaled_tile_width, scaled_tile_height; @@ -1767,6 +1770,8 @@ gsk_gpu_node_processor_draw_texture_tiles (GskGpuNodeProcessor *self, device = gsk_gpu_frame_get_device (self->frame); cache = gsk_gpu_device_get_cache (device); timestamp = gsk_gpu_frame_get_timestamp (self->frame); + sampler = gsk_gpu_sampler_for_scaling_filter (scaling_filter); + need_mipmap = scaling_filter == GSK_SCALING_FILTER_TRILINEAR; gsk_gpu_node_processor_get_clip_bounds (self, &clip_bounds); tile_size = gsk_gpu_device_get_tile_size (device); width = gdk_texture_get_width (texture); @@ -1789,7 +1794,8 @@ gsk_gpu_node_processor_draw_texture_tiles (GskGpuNodeProcessor *self, !gsk_rect_intersects (&clip_bounds, &tile_rect)) continue; - tile = gsk_gpu_cache_lookup_tile (cache, texture, y * n_width + x, timestamp); + tile = gsk_gpu_cache_lookup_tile (cache, texture, y * n_width + x, timestamp, &tile_cs); + if (tile == NULL) { if (memtex == NULL) @@ -1799,7 +1805,7 @@ gsk_gpu_node_processor_draw_texture_tiles (GskGpuNodeProcessor *self, y * tile_size, MIN (tile_size, width - x * tile_size), MIN (tile_size, height - y * tile_size)); - tile = gsk_gpu_upload_texture_op_try (self->frame, FALSE, subtex); + tile = gsk_gpu_upload_texture_op_try (self->frame, need_mipmap, subtex); g_object_unref (subtex); if (tile == NULL) { @@ -1808,20 +1814,30 @@ gsk_gpu_node_processor_draw_texture_tiles (GskGpuNodeProcessor *self, goto out; } - gsk_gpu_cache_cache_tile (cache, timestamp, texture, y * n_width + x, tile); + tile_cs = gdk_texture_get_color_state (texture); + if (gsk_gpu_image_get_flags (tile) & GSK_GPU_IMAGE_SRGB) + { + tile_cs = gdk_color_state_get_no_srgb_tf (tile_cs); + g_assert (tile_cs); + } + + gsk_gpu_cache_cache_tile (cache, timestamp, texture, y * n_width + x, tile, tile_cs); } - tile_cs = gdk_texture_get_color_state (texture); - if (gsk_gpu_image_get_flags (tile) & GSK_GPU_IMAGE_SRGB) + if (need_mipmap && + (gsk_gpu_image_get_flags (tile) & (GSK_GPU_IMAGE_STRAIGHT_ALPHA | GSK_GPU_IMAGE_CAN_MIPMAP)) != GSK_GPU_IMAGE_CAN_MIPMAP) { - tile_cs = gdk_color_state_get_no_srgb_tf (tile_cs); - g_assert (tile_cs); + tile = gsk_gpu_copy_image (self->frame, self->ccs, tile, tile_cs, TRUE); + tile_cs = self->ccs; + gsk_gpu_cache_cache_tile (cache, timestamp, texture, y * n_width + x, tile, tile_cs); } + if (need_mipmap && !(gsk_gpu_image_get_flags (tile) & GSK_GPU_IMAGE_MIPMAP)) + gsk_gpu_mipmap_op (self->frame, tile); gsk_gpu_node_processor_image_op (self, tile, tile_cs, - GSK_GPU_SAMPLER_DEFAULT, + sampler, &tile_rect, &tile_rect); @@ -1839,7 +1855,8 @@ gsk_gpu_get_texture_tiles_as_image (GskGpuFrame *frame, const graphene_rect_t *clip_bounds, const graphene_vec2_t *scale, const graphene_rect_t *texture_bounds, - GdkTexture *texture) + GdkTexture *texture, + GskScalingFilter scaling_filter) { GskGpuNodeProcessor self; GskGpuImage *image; @@ -1859,7 +1876,8 @@ gsk_gpu_get_texture_tiles_as_image (GskGpuFrame *frame, gsk_gpu_node_processor_draw_texture_tiles (&self, texture_bounds, - texture); + texture, + scaling_filter); gsk_gpu_node_processor_finish_draw (&self, image); @@ -1893,7 +1911,8 @@ gsk_gpu_node_processor_add_texture_node (GskGpuNodeProcessor *self, &rounded_clip, &self->scale, &node->bounds, - texture); + texture, + should_mipmap ? GSK_SCALING_FILTER_TRILINEAR : GSK_SCALING_FILTER_LINEAR); gsk_gpu_node_processor_image_op (self, image, self->ccs, @@ -1952,10 +1971,9 @@ gsk_gpu_get_texture_node_as_image (GskGpuFrame *frame, GdkTexture *texture = gsk_texture_node_get_texture (node); GdkColorState *image_cs; GskGpuImage *image; + gboolean should_mipmap; - if (texture_node_should_mipmap (node, frame, scale)) - return gsk_gpu_get_node_as_image_via_offscreen (frame, ccs, clip_bounds, scale, node, out_bounds); - + should_mipmap = texture_node_should_mipmap (node, frame, scale); image = gsk_gpu_lookup_texture (frame, ccs, texture, FALSE, &image_cs); if (image == NULL) @@ -1965,11 +1983,15 @@ gsk_gpu_get_texture_node_as_image (GskGpuFrame *frame, clip_bounds, scale, &node->bounds, - gsk_texture_node_get_texture (node)); + gsk_texture_node_get_texture (node), + should_mipmap ? GSK_SCALING_FILTER_TRILINEAR : GSK_SCALING_FILTER_LINEAR); *out_bounds = *clip_bounds; return image; } + if (should_mipmap) + return gsk_gpu_get_node_as_image_via_offscreen (frame, ccs, clip_bounds, scale, node, out_bounds); + if (!gdk_color_state_equal (ccs, image_cs) || gsk_gpu_image_get_flags (image) & GSK_GPU_IMAGE_STRAIGHT_ALPHA) {