gsk gl: Handle subsurfaces during rendering

During rendering, restack offloaded subsurfaces below the main
surface, and clear the area so they peek through. After rendering,
raise the last subsurface if we haven't drawn over it.
This commit is contained in:
Matthias Clasen 2023-10-27 21:50:19 -04:00
parent c636baf6f5
commit 904d44074f
3 changed files with 57 additions and 7 deletions

View File

@ -24,10 +24,13 @@
#include <gdk/gdkdisplayprivate.h>
#include <gdk/gdkglcontextprivate.h>
#include <gdk/gdksurfaceprivate.h>
#include <gdk/gdksubsurfaceprivate.h>
#include <glib/gi18n-lib.h>
#include <gsk/gskdebugprivate.h>
#include <gsk/gskrendererprivate.h>
#include <gsk/gskrendernodeprivate.h>
#include <gsk/gskroundedrectprivate.h>
#include <gsk/gskrectprivate.h>
#include "gskglcommandqueueprivate.h"
#include "gskgldriverprivate.h"
@ -289,6 +292,12 @@ gsk_gl_renderer_render (GskRenderer *renderer,
surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (self->context));
scale = gdk_gl_context_get_scale (self->context);
if (cairo_region_is_empty (update_area))
{
gdk_draw_context_empty_frame (GDK_DRAW_CONTEXT (self->context));
return;
}
viewport.origin.x = 0;
viewport.origin.y = 0;
viewport.size.width = gdk_surface_get_width (surface) * scale;
@ -305,7 +314,7 @@ gsk_gl_renderer_render (GskRenderer *renderer,
clear_framebuffer = update_area_requires_clear (surface, render_region);
gsk_gl_driver_begin_frame (self->driver, self->command_queue);
job = gsk_gl_render_job_new (self->driver, &viewport, scale, render_region, 0, clear_framebuffer);
job = gsk_gl_render_job_new (self->driver, &viewport, scale, render_region, 0, clear_framebuffer, offload);
if (GSK_RENDERER_DEBUG_CHECK (GSK_RENDERER (self), FALLBACK))
gsk_gl_render_job_set_debug_fallback (job, TRUE);
gsk_gl_render_job_render (job, root);
@ -377,7 +386,7 @@ gsk_gl_renderer_render_texture (GskRenderer *renderer,
gdk_format = GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED;
format = GL_RGBA32F;
}
else
else
{
format = GL_RGBA8;
gdk_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
@ -391,7 +400,7 @@ gsk_gl_renderer_render_texture (GskRenderer *renderer,
&render_target))
{
gsk_gl_driver_begin_frame (self->driver, self->command_queue);
job = gsk_gl_render_job_new (self->driver, viewport, 1, NULL, render_target->framebuffer_id, TRUE);
job = gsk_gl_render_job_new (self->driver, viewport, 1, NULL, render_target->framebuffer_id, TRUE, NULL);
if (GSK_RENDERER_DEBUG_CHECK (GSK_RENDERER (self), FALLBACK))
gsk_gl_render_job_set_debug_fallback (job, TRUE);
gsk_gl_render_job_render_flipped (job, root);

View File

@ -31,9 +31,13 @@
#include <gdk/gdktextureprivate.h>
#include <gdk/gdkmemorytextureprivate.h>
#include <gdk/gdkdmabuftexture.h>
#include <gdk/gdksurfaceprivate.h>
#include <gdk/gdksubsurfaceprivate.h>
#include <gsk/gsktransformprivate.h>
#include <gsk/gskroundedrectprivate.h>
#include <gsk/gskrectprivate.h>
#include <gsk/gskrendererprivate.h>
#include <gsk/gskoffloadprivate.h>
#include <math.h>
#include <string.h>
@ -44,10 +48,12 @@
#include "gskglprogramprivate.h"
#include "gskglrenderjobprivate.h"
#include "gskglshadowlibraryprivate.h"
#include "gskdebugprivate.h"
#include "ninesliceprivate.h"
#include "fp16private.h"
#define ALLOW_OFFLOAD_FOR_ANY_TEXTURE 1
#define ORTHO_NEAR_PLANE -10000
#define ORTHO_FAR_PLANE 10000
@ -174,6 +180,8 @@ struct _GskGLRenderJob
* looking at the format of the framebuffer we are rendering on.
*/
int target_format;
GskOffload *offload;
};
typedef struct _GskGLRenderOffscreen
@ -3998,6 +4006,36 @@ gsk_gl_render_job_visit_repeat_node (GskGLRenderJob *job,
}
}
static inline void
gsk_gl_render_job_visit_subsurface_node (GskGLRenderJob *job,
const GskRenderNode *node)
{
GdkSubsurface *subsurface;
subsurface = (GdkSubsurface *) gsk_subsurface_node_get_subsurface (node);
if (job->offload &&
gsk_offload_subsurface_is_offloaded (job->offload, subsurface))
{
/* Clear the area so we can see through */
if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, color)))
{
GskGLCommandBatch *batch;
guint16 color[4];
rgba_to_half (&(GdkRGBA){0,0,0,0}, color);
batch = gsk_gl_command_queue_get_batch (job->command_queue);
batch->draw.blend = 0;
gsk_gl_render_job_draw_rect_with_color (job, &node->bounds, color);
gsk_gl_render_job_end_draw (job);
}
}
else
{
gsk_gl_render_job_visit_node (job, gsk_subsurface_node_get_child (node));
}
}
static void
gsk_gl_render_job_visit_node (GskGLRenderJob *job,
const GskRenderNode *node)
@ -4195,8 +4233,7 @@ gsk_gl_render_job_visit_node (GskGLRenderJob *job,
break;
case GSK_SUBSURFACE_NODE:
// FIXME do something here
gsk_gl_render_job_visit_node (job, gsk_subsurface_node_get_child (node));
gsk_gl_render_job_visit_subsurface_node (job, node);
break;
case GSK_NOT_A_RENDER_NODE:
@ -4520,6 +4557,7 @@ gsk_gl_render_job_render (GskGLRenderJob *job,
gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport);
gsk_gl_render_job_visit_node (job, root);
gdk_gl_context_pop_debug_group (job->command_queue->context);
gdk_profiler_add_mark (start_time, GDK_PROFILER_CURRENT_TIME-start_time, "Build GL command queue", "");
#if 0
@ -4580,7 +4618,8 @@ gsk_gl_render_job_new (GskGLDriver *driver,
float scale,
const cairo_region_t *region,
guint framebuffer,
gboolean clear_framebuffer)
gboolean clear_framebuffer,
GskOffload *offload)
{
const graphene_rect_t *clip_rect = viewport;
graphene_rect_t transformed_extents;
@ -4616,6 +4655,7 @@ gsk_gl_render_job_new (GskGLDriver *driver,
job->scale_y = scale;
job->viewport = *viewport;
job->target_format = get_framebuffer_format (job->command_queue->context, framebuffer);
job->offload = offload;
gsk_gl_render_job_set_alpha (job, 1.0f);
gsk_gl_render_job_set_projection_from_rect (job, viewport, NULL);

View File

@ -27,7 +27,8 @@ GskGLRenderJob *gsk_gl_render_job_new (GskGLDriver *dri
float scale,
const cairo_region_t *region,
guint framebuffer,
gboolean clear_framebuffer);
gboolean clear_framebuffer,
GskOffload *offload);
void gsk_gl_render_job_free (GskGLRenderJob *job);
void gsk_gl_render_job_render (GskGLRenderJob *job,
GskRenderNode *root);