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,
graphene_rect_t viewport;
GskGLRenderJob *job;
GdkSurface *surface;
+ gboolean clear_framebuffer;
float scale_factor;
g_assert (GSK_IS_GL_RENDERER (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);
&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);
/* 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.
*/
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", "");
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;
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;