mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-25 21:21:21 +00:00
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().
This commit is contained in:
parent
b4b282dc81
commit
f9268e8137
@ -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;
|
||||
|
@ -71,6 +71,8 @@ struct _GdkGLContextClass
|
||||
|
||||
gboolean (* is_shared) (GdkGLContext *self,
|
||||
GdkGLContext *other);
|
||||
|
||||
guint (* get_default_framebuffer) (GdkGLContext *self);
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
@ -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++;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user