Merge branch 'wip/chergert/gsk-gl-less-glClear' into 'main'

gsk/gl: avoid clearing opaque regions

See merge request GNOME/gtk!4504
This commit is contained in:
Matthias Clasen
2022-02-22 17:56:40 +00:00
3 changed files with 75 additions and 5 deletions

View File

@@ -188,6 +188,65 @@ get_render_region (GdkSurface *surface,
return cairo_region_create_rectangle (&extents);
}
static gboolean
update_area_requires_clear (GdkSurface *surface,
const cairo_region_t *update_area)
{
cairo_rectangle_int_t rect;
guint n_rects;
g_assert (GDK_IS_SURFACE (surface));
/* No opaque region, assume we have to clear */
if (surface->opaque_region == NULL)
return TRUE;
/* If the update_area is the whole surface, then clear it
* because many drivers optimize for this by avoiding extra
* work to reload any contents.
*/
if (update_area == NULL)
return TRUE;
if (cairo_region_num_rectangles (update_area) == 1)
{
cairo_region_get_rectangle (update_area, 0, &rect);
if (rect.x == 0 &&
rect.y == 0 &&
rect.width == surface->width &&
rect.height == surface->height)
return TRUE;
}
/* If the entire surface is opaque, then we can skip clearing
* (with the exception of full surface clearing above).
*/
if (cairo_region_num_rectangles (surface->opaque_region) == 1)
{
cairo_region_get_rectangle (surface->opaque_region, 0, &rect);
if (rect.x == 0 &&
rect.y == 0 &&
rect.width == surface->width &&
rect.height == surface->height)
return FALSE;
}
/* If any update_area rectangle overlaps our transparent
* regions, then we need to clear the area.
*/
n_rects = cairo_region_num_rectangles (update_area);
for (guint i = 0; i < n_rects; i++)
{
cairo_region_get_rectangle (update_area, i, &rect);
if (cairo_region_contains_rectangle (surface->opaque_region, &rect) != CAIRO_REGION_OVERLAP_IN)
return TRUE;
}
return FALSE;
}
static void
gsk_gl_renderer_render (GskRenderer *renderer,
GskRenderNode *root,
@@ -198,6 +257,7 @@ gsk_gl_renderer_render (GskRenderer *renderer,
graphene_rect_t viewport;
GskGLRenderJob *job;
GdkSurface *surface;
gboolean clear_framebuffer;
float scale_factor;
g_assert (GSK_IS_GL_RENDERER (renderer));
@@ -219,9 +279,10 @@ gsk_gl_renderer_render (GskRenderer *renderer,
/* Must be called *AFTER* gdk_draw_context_begin_frame() */
render_region = get_render_region (surface, self->context);
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_factor, render_region, 0);
job = gsk_gl_render_job_new (self->driver, &viewport, scale_factor, render_region, 0, clear_framebuffer);
#ifdef G_ENABLE_DEBUG
if (GSK_RENDERER_DEBUG_CHECK (GSK_RENDERER (self), FALLBACK))
gsk_gl_render_job_set_debug_fallback (job, TRUE);
@@ -268,7 +329,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);
job = gsk_gl_render_job_new (self->driver, viewport, 1, NULL, render_target->framebuffer_id, TRUE);
#ifdef G_ENABLE_DEBUG
if (GSK_RENDERER_DEBUG_CHECK (GSK_RENDERER (self), FALLBACK))
gsk_gl_render_job_set_debug_fallback (job, TRUE);

View File

@@ -163,6 +163,11 @@ struct _GskGLRenderJob
/* If we should be rendering red zones over fallback nodes */
guint debug_fallback : 1;
/* In some cases we might want to avoid clearing the framebuffer
* because we're going to render over the existing contents.
*/
guint clear_framebuffer : 1;
/* Format we want to use for intermediate textures, determined by
* looking at the format of the framebuffer we are rendering on.
*/
@@ -4083,7 +4088,8 @@ gsk_gl_render_job_render (GskGLRenderJob *job,
start_time = GDK_PROFILER_CURRENT_TIME;
gdk_gl_context_push_debug_group (job->command_queue->context, "Building command queue");
gsk_gl_command_queue_bind_framebuffer (job->command_queue, job->framebuffer);
gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport);
if (job->clear_framebuffer)
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", "");
@@ -4145,7 +4151,8 @@ gsk_gl_render_job_new (GskGLDriver *driver,
const graphene_rect_t *viewport,
float scale_factor,
const cairo_region_t *region,
guint framebuffer)
guint framebuffer,
gboolean clear_framebuffer)
{
const graphene_rect_t *clip_rect = viewport;
graphene_rect_t transformed_extents;
@@ -4161,6 +4168,7 @@ gsk_gl_render_job_new (GskGLDriver *driver,
job->clip = g_array_sized_new (FALSE, FALSE, sizeof (GskGLRenderClip), 16);
job->modelview = g_array_sized_new (FALSE, FALSE, sizeof (GskGLRenderModelview), 16);
job->framebuffer = framebuffer;
job->clear_framebuffer = !!clear_framebuffer;
job->offset_x = 0;
job->offset_y = 0;
job->scale_x = scale_factor;

View File

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