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:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user