From f5af3fe933d7a9dc45ef412b519e018c3df7c21a Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Fri, 13 Oct 2023 03:59:47 +0200 Subject: [PATCH] gpu: Add render_texture() fallback impl for huge sizes This copies over the GLRenderer approach of step-by-step filling a memorytexture. It just adds some extra niceties by respecting the best format. --- gsk/gpu/gskgpurenderer.c | 89 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 2 deletions(-) diff --git a/gsk/gpu/gskgpurenderer.c b/gsk/gpu/gskgpurenderer.c index 7bb0ff096c..7c63d93064 100644 --- a/gsk/gpu/gskgpurenderer.c +++ b/gsk/gpu/gskgpurenderer.c @@ -15,6 +15,7 @@ #include "gdk/gdkdrawcontextprivate.h" #include "gdk/gdkprofilerprivate.h" #include "gdk/gdktextureprivate.h" +#include "gdk/gdktexturedownloaderprivate.h" #include "gdk/gdkdrawcontextprivate.h" #include @@ -182,6 +183,88 @@ gsk_gpu_renderer_unrealize (GskRenderer *renderer) g_clear_object (&priv->device); } +static GdkTexture * +gsk_gpu_renderer_fallback_render_texture (GskGpuRenderer *self, + GskRenderNode *root, + const graphene_rect_t *rounded_viewport) +{ + GskGpuRendererPrivate *priv = gsk_gpu_renderer_get_instance_private (self); + GskGpuImage *image; + gsize width, height, max_size, image_width, image_height; + gsize x, y, size, bpp, stride; + GdkMemoryFormat format; + GdkMemoryDepth depth; + GBytes *bytes; + guchar *data; + GdkTexture *texture; + GdkTextureDownloader downloader; + GskGpuFrame *frame; + + max_size = gsk_gpu_device_get_max_image_size (priv->device); + depth = gsk_render_node_get_preferred_depth (root); + do + { + image = gsk_gpu_device_create_offscreen_image (priv->device, + gsk_render_node_get_preferred_depth (root), + MIN (max_size, rounded_viewport->size.width), + MIN (max_size, rounded_viewport->size.height)); + max_size /= 2; + } + while (image == NULL); + + format = gsk_gpu_image_get_format (image); + bpp = gdk_memory_format_bytes_per_pixel (format); + image_width = gsk_gpu_image_get_width (image); + image_height = gsk_gpu_image_get_height (image); + width = rounded_viewport->size.width; + height = rounded_viewport->size.height; + stride = width * bpp; + size = stride * height; + data = g_malloc_n (stride, height); + + for (y = 0; y < height; y += image_height) + { + for (x = 0; x < width; x += image_width) + { + texture = NULL; + if (image == NULL) + image = gsk_gpu_device_create_offscreen_image (priv->device, + depth, + MIN (image_width, width - x), + MIN (image_height, height - y)); + + frame = gsk_gpu_renderer_create_frame (self); + gsk_gpu_frame_render (frame, + g_get_monotonic_time(), + image, + NULL, + root, + &GRAPHENE_RECT_INIT (rounded_viewport->origin.x + x, + rounded_viewport->origin.y + y, + image_width, + image_height), + &texture); + g_object_unref (frame); + + g_assert (texture); + gdk_texture_downloader_init (&downloader, texture); + gdk_texture_downloader_set_format (&downloader, format); + gdk_texture_downloader_download_into (&downloader, + data + stride * y + x * bpp, + stride); + + gdk_texture_downloader_finish (&downloader); + g_object_unref (texture); + g_clear_object (&image); + } + } + + bytes = g_bytes_new_take (data, size); + texture = gdk_memory_texture_new (width, height, GDK_MEMORY_DEFAULT, bytes, stride); + g_bytes_unref (bytes); + return texture; +} + static GdkTexture * gsk_gpu_renderer_render_texture (GskRenderer *renderer, GskRenderNode *root, @@ -196,8 +279,6 @@ gsk_gpu_renderer_render_texture (GskRenderer *renderer, gsk_gpu_renderer_make_current (self); - frame = gsk_gpu_renderer_create_frame (self); - rounded_viewport = GRAPHENE_RECT_INIT (viewport->origin.x, viewport->origin.y, ceil (viewport->size.width), @@ -206,6 +287,10 @@ gsk_gpu_renderer_render_texture (GskRenderer *renderer, gsk_render_node_get_preferred_depth (root), rounded_viewport.size.width, rounded_viewport.size.height); + if (image == NULL) + return gsk_gpu_renderer_fallback_render_texture (self, root, &rounded_viewport); + + frame = gsk_gpu_renderer_create_frame (self); texture = NULL; gsk_gpu_frame_render (frame,