gpu: Implement tiling for texture nodes

Use the new cache feature to split oversized textures into tiles the
size given by the new device API.

Then number those tiles from left to right and top to bottom and use
that number as the tile id.
This commit is contained in:
Benjamin Otte 2024-07-12 11:32:58 +02:00
parent 392f6855ca
commit 39f5c5bf49

View File

@ -43,8 +43,10 @@
#include "gskprivate.h"
#include "gdk/gdkcolorstateprivate.h"
#include "gdk/gdkmemorytextureprivate.h"
#include "gdk/gdkrgbaprivate.h"
#include "gdk/gdksubsurfaceprivate.h"
#include "gdk/gdktextureprivate.h"
/* the epsilon we allow pixels to be off due to rounding errors.
* Chosen rather randomly.
@ -1725,6 +1727,110 @@ gsk_gpu_lookup_texture (GskGpuFrame *frame,
return image;
}
static GskGpuImage *
gsk_gpu_get_texture_tiles_as_image (GskGpuFrame *frame,
GdkColorState *ccs,
const graphene_rect_t *clip_bounds,
const graphene_vec2_t *scale,
const graphene_rect_t *texture_bounds,
GdkTexture *texture)
{
GskGpuNodeProcessor self;
GskGpuCache *cache;
GskGpuDevice *device;
gint64 timestamp;
GskGpuImage *image, *tile;
GdkColorState *tile_cs;
GdkMemoryTexture *memtex;
GdkTexture *subtex;
float scaled_tile_width, scaled_tile_height;
gsize tile_size, width, height, n_width, n_height, x, y;
device = gsk_gpu_frame_get_device (frame);
cache = gsk_gpu_device_get_cache (device);
timestamp = gsk_gpu_frame_get_timestamp (frame);
tile_size = gsk_gpu_device_get_tile_size (device);
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
n_width = (width + tile_size - 1) / tile_size;
n_height = (height + tile_size - 1) / tile_size;
scaled_tile_width = texture_bounds->size.width * tile_size / width;
scaled_tile_height = texture_bounds->size.height * tile_size / height;
image = gsk_gpu_node_processor_init_draw (&self,
frame,
ccs,
gdk_texture_get_depth (texture),
scale,
clip_bounds);
if (image == NULL)
return NULL;
self.blend = GSK_GPU_BLEND_ADD;
self.pending_globals |= GSK_GPU_GLOBAL_BLEND;
gsk_gpu_node_processor_sync_globals (&self, 0);
memtex = NULL;
for (y = 0; y < n_height; y++)
{
for (x = 0; x < n_width; x++)
{
graphene_rect_t tile_rect = GRAPHENE_RECT_INIT (texture_bounds->origin.x + scaled_tile_width * x,
texture_bounds->origin.y + scaled_tile_height * y,
scaled_tile_width,
scaled_tile_height);
if (!gsk_rect_intersection (&tile_rect, texture_bounds, &tile_rect) ||
!gsk_rect_intersects (clip_bounds, &tile_rect))
continue;
tile = gsk_gpu_cache_lookup_tile (cache, texture, y * n_width + x, timestamp);
if (tile == NULL)
{
if (memtex == NULL)
memtex = gdk_memory_texture_from_texture (texture);
subtex = gdk_memory_texture_new_subtexture (memtex,
x * tile_size,
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);
g_object_unref (subtex);
if (tile == NULL)
{
g_warning ("failed to create %zux%zu tile for %zux%zu texture. Out of memory?",
tile_size, tile_size, width, height);
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_node_processor_image_op (&self,
tile,
tile_cs,
GSK_GPU_SAMPLER_DEFAULT,
&tile_rect,
&tile_rect);
g_object_unref (tile);
}
}
out:
gsk_gpu_node_processor_finish_draw (&self, image);
g_clear_object (&memtex);
return image;
}
static void
gsk_gpu_node_processor_add_texture_node (GskGpuNodeProcessor *self,
GskRenderNode *node)
@ -1741,11 +1847,25 @@ gsk_gpu_node_processor_add_texture_node (GskGpuNodeProcessor *self,
if (image == NULL)
{
GSK_DEBUG (FALLBACK, "Unsupported texture format %u for size %dx%d",
gdk_texture_get_format (texture),
gdk_texture_get_width (texture),
gdk_texture_get_height (texture));
gsk_gpu_node_processor_add_cairo_node (self, node);
graphene_rect_t clip, rounded_clip;
if (!gsk_gpu_node_processor_clip_node_bounds (self, node, &clip))
return;
rect_round_to_pixels (&clip, &self->scale, &self->offset, &rounded_clip);
image = gsk_gpu_get_texture_tiles_as_image (self->frame,
self->ccs,
&rounded_clip,
&self->scale,
&node->bounds,
texture);
gsk_gpu_node_processor_image_op (self,
image,
self->ccs,
GSK_GPU_SAMPLER_DEFAULT,
&clip,
&rounded_clip);
g_object_unref (image);
return;
}
@ -1803,9 +1923,17 @@ gsk_gpu_get_texture_node_as_image (GskGpuFrame *frame,
image = gsk_gpu_lookup_texture (frame, ccs, texture, FALSE, &image_cs);
/* Happens ie for oversized textures */
if (image == NULL)
return gsk_gpu_get_node_as_image_via_offscreen (frame, ccs, clip_bounds, scale, node, out_bounds);
{
image = gsk_gpu_get_texture_tiles_as_image (frame,
ccs,
clip_bounds,
scale,
&node->bounds,
gsk_texture_node_get_texture (node));
*out_bounds = *clip_bounds;
return image;
}
if (!gdk_color_state_equal (ccs, image_cs) ||
gsk_gpu_image_get_flags (image) & GSK_GPU_IMAGE_STRAIGHT_ALPHA)