From: Christian Hergert Date: Fri, 11 Feb 2022 05:51:15 +0000 (-0800) Subject: gsk/gl: support non-standard default framebuffer X-Git-Tag: archive/raspbian/4.6.5+ds-1+rpi1~1^2~19^2~3^2~72^2~8 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=f9268e813778edf6d2d15655686aa5bcd9a0dfb8;p=gtk4.git gsk/gl: support non-standard default framebuffer There are situations where our "default framebuffer" is not actually zero, yet we still want to apply a scissor rect. Generally, 0 is the default framebuffer. But on platforms where we need to bind a platform-specific feature to a GL_FRAMEBUFFER, we might have a default that is not 0. For example, on macOS we bind an IOSurfaceRef to a GL_TEXTURE_RECTANGLE which then is assigned as the backing store for a framebuffer. This is different than using gsk_gl_renderer_render_texture() in that we don't want to incur an extra copy to the destination surface nor do we even have a way to pass a texture_id into render_texture(). --- diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c index 373f2fefd5..be514c0ac6 100644 --- a/gdk/gdkglcontext.c +++ b/gdk/gdkglcontext.c @@ -648,6 +648,12 @@ gdk_gl_context_surface_resized (GdkDrawContext *draw_context) gdk_gl_context_clear_old_updated_area (context); } +static guint +gdk_gl_context_real_get_default_framebuffer (GdkGLContext *self) +{ + return 0; +} + static void gdk_gl_context_class_init (GdkGLContextClass *klass) { @@ -659,6 +665,7 @@ gdk_gl_context_class_init (GdkGLContextClass *klass) klass->is_shared = gdk_gl_context_real_is_shared; klass->make_current = gdk_gl_context_real_make_current; klass->clear_current = gdk_gl_context_real_clear_current; + klass->get_default_framebuffer = gdk_gl_context_real_get_default_framebuffer; draw_context_class->begin_frame = gdk_gl_context_real_begin_frame; draw_context_class->end_frame = gdk_gl_context_real_end_frame; diff --git a/gdk/gdkglcontextprivate.h b/gdk/gdkglcontextprivate.h index ff11349b3e..0a3739f090 100644 --- a/gdk/gdkglcontextprivate.h +++ b/gdk/gdkglcontextprivate.h @@ -71,6 +71,8 @@ struct _GdkGLContextClass gboolean (* is_shared) (GdkGLContext *self, GdkGLContext *other); + + guint (* get_default_framebuffer) (GdkGLContext *self); }; typedef struct { diff --git a/gsk/gl/gskglcommandqueue.c b/gsk/gl/gskglcommandqueue.c index 3af8c1eb09..b7640edf87 100644 --- a/gsk/gl/gskglcommandqueue.c +++ b/gsk/gl/gskglcommandqueue.c @@ -675,9 +675,9 @@ gsk_gl_command_queue_split_draw (GskGLCommandQueue *self) } void -gsk_gl_command_queue_clear (GskGLCommandQueue *self, - guint clear_bits, - const graphene_rect_t *viewport) +gsk_gl_command_queue_clear (GskGLCommandQueue *self, + guint clear_bits, + const graphene_rect_t *viewport) { GskGLCommandBatch *batch; @@ -750,11 +750,12 @@ static inline void apply_scissor (gboolean *state, guint framebuffer, const graphene_rect_t *scissor, - gboolean has_scissor) + gboolean has_scissor, + guint default_framebuffer) { g_assert (framebuffer != (guint)-1); - if (framebuffer != 0 || !has_scissor) + if (framebuffer != default_framebuffer || !has_scissor) { if (*state != FALSE) { @@ -935,15 +936,24 @@ gsk_gl_command_queue_sort_batches (GskGLCommandQueue *self) * @self: a `GskGLCommandQueue` * @surface_height: the height of the backing surface * @scale_factor: the scale factor of the backing surface - * #scissor: (nullable): the scissor clip if any + * @scissor: (nullable): the scissor clip if any + * @default_framebuffer: the default framebuffer id if not zero * * Executes all of the batches in the command queue. + * + * Typically, the scissor rect is only applied when rendering to the default + * framebuffer (zero in most cases). However, if @default_framebuffer is not + * zero, it will be checked to see if the rendering target matches so that + * the scissor rect is applied. This should be used in cases where rendering + * to the backbuffer for display is not the default GL framebuffer of zero. + * Currently, this happens when rendering on macOS using IOSurface. */ void gsk_gl_command_queue_execute (GskGLCommandQueue *self, guint surface_height, guint scale_factor, - const cairo_region_t *scissor) + const cairo_region_t *scissor, + guint default_framebuffer) { G_GNUC_UNUSED guint count = 0; graphene_rect_t scissor_test; @@ -1049,7 +1059,7 @@ gsk_gl_command_queue_execute (GskGLCommandQueue *self, case GSK_GL_COMMAND_KIND_CLEAR: if (apply_framebuffer (&framebuffer, batch->clear.framebuffer)) { - apply_scissor (&scissor_state, framebuffer, &scissor_test, has_scissor); + apply_scissor (&scissor_state, framebuffer, &scissor_test, has_scissor, default_framebuffer); n_fbos++; } @@ -1073,7 +1083,7 @@ gsk_gl_command_queue_execute (GskGLCommandQueue *self, if (apply_framebuffer (&framebuffer, batch->draw.framebuffer)) { - apply_scissor (&scissor_state, framebuffer, &scissor_test, has_scissor); + apply_scissor (&scissor_state, framebuffer, &scissor_test, has_scissor, default_framebuffer); n_fbos++; } diff --git a/gsk/gl/gskglcommandqueueprivate.h b/gsk/gl/gskglcommandqueueprivate.h index 4147283e6d..48911305a8 100644 --- a/gsk/gl/gskglcommandqueueprivate.h +++ b/gsk/gl/gskglcommandqueueprivate.h @@ -278,7 +278,8 @@ void gsk_gl_command_queue_end_frame (GskGLCommandQueue void gsk_gl_command_queue_execute (GskGLCommandQueue *self, guint surface_height, guint scale_factor, - const cairo_region_t *scissor); + const cairo_region_t *scissor, + guint default_framebuffer); int gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self, GdkTexture *texture, int min_filter, diff --git a/gsk/gl/gskglrenderjob.c b/gsk/gl/gskglrenderjob.c index 65b5adf84d..afefe7a018 100644 --- a/gsk/gl/gskglrenderjob.c +++ b/gsk/gl/gskglrenderjob.c @@ -123,6 +123,7 @@ struct _GskGLRenderJob * GL context. */ guint framebuffer; + guint default_framebuffer; /* The viewport we are using. This state is updated as we process render * nodes in the specific visitor callbacks. @@ -4058,7 +4059,7 @@ gsk_gl_render_job_render_flipped (GskGLRenderJob *job, gsk_gl_render_job_end_draw (job); gdk_gl_context_push_debug_group (job->command_queue->context, "Executing command queue"); - gsk_gl_command_queue_execute (job->command_queue, surface_height, 1, NULL); + gsk_gl_command_queue_execute (job->command_queue, surface_height, 1, NULL, job->default_framebuffer); gdk_gl_context_pop_debug_group (job->command_queue->context); glDeleteFramebuffers (1, &framebuffer_id); @@ -4108,7 +4109,7 @@ gsk_gl_render_job_render (GskGLRenderJob *job, start_time = GDK_PROFILER_CURRENT_TIME; gsk_gl_command_queue_make_current (job->command_queue); gdk_gl_context_push_debug_group (job->command_queue->context, "Executing command queue"); - gsk_gl_command_queue_execute (job->command_queue, surface_height, scale_factor, job->region); + gsk_gl_command_queue_execute (job->command_queue, surface_height, scale_factor, job->region, job->default_framebuffer); gdk_gl_context_pop_debug_group (job->command_queue->context); gdk_profiler_add_mark (start_time, GDK_PROFILER_CURRENT_TIME-start_time, "Execute GL command queue", ""); } @@ -4157,11 +4158,23 @@ gsk_gl_render_job_new (GskGLDriver *driver, const graphene_rect_t *clip_rect = viewport; graphene_rect_t transformed_extents; GskGLRenderJob *job; + GdkGLContext *context; + GLint default_framebuffer = 0; g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), NULL); g_return_val_if_fail (viewport != NULL, NULL); g_return_val_if_fail (scale_factor > 0, NULL); + /* Check for non-standard framebuffer binding as we might not be using + * the default framebuffer on systems like macOS where we've bound an + * IOSurface to a GL_TEXTURE_RECTANGLE. Otherwise, no scissor clip will + * be applied in the command queue causing overdrawing. + */ + context = driver->command_queue->context; + default_framebuffer = GDK_GL_CONTEXT_GET_CLASS (context)->get_default_framebuffer (context); + if (framebuffer == 0 && default_framebuffer != 0) + framebuffer = default_framebuffer; + job = g_slice_new0 (GskGLRenderJob); job->driver = g_object_ref (driver); job->command_queue = job->driver->command_queue; @@ -4169,6 +4182,7 @@ gsk_gl_render_job_new (GskGLDriver *driver, job->modelview = g_array_sized_new (FALSE, FALSE, sizeof (GskGLRenderModelview), 16); job->framebuffer = framebuffer; job->clear_framebuffer = !!clear_framebuffer; + job->default_framebuffer = default_framebuffer; job->offset_x = 0; job->offset_y = 0; job->scale_x = scale_factor;