diff options
author | Matthias Clasen <mclasen@redhat.com> | 2023-01-28 15:20:26 -0500 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2023-04-27 06:57:02 +0200 |
commit | 8292b846d58a09295e4e30c25c4e19c3ea4be8e1 (patch) | |
tree | f88bf88215d5eedcafb49180f0802c7319a2b0ce /gsk | |
parent | 6efaa79e3c1b9b17a99f93de2e8a76705f3409ff (diff) | |
download | gtk+-8292b846d58a09295e4e30c25c4e19c3ea4be8e1.tar.gz |
gsk: Synchronize when using textures
Pass the GLsync object from texture into our
command queue, and when executing the queue,
wait on the sync object the first time we
use its associated texture.
Diffstat (limited to 'gsk')
-rw-r--r-- | gsk/gl/gskglcommandqueue.c | 13 | ||||
-rw-r--r-- | gsk/gl/gskglcommandqueueprivate.h | 41 | ||||
-rw-r--r-- | gsk/gl/gskglprogramprivate.h | 16 | ||||
-rw-r--r-- | gsk/gl/gskglrenderjob.c | 42 |
4 files changed, 97 insertions, 15 deletions
diff --git a/gsk/gl/gskglcommandqueue.c b/gsk/gl/gskglcommandqueue.c index d5aa01a5f8..cf8acc5da2 100644 --- a/gsk/gl/gskglcommandqueue.c +++ b/gsk/gl/gskglcommandqueue.c @@ -427,6 +427,7 @@ gsk_gl_command_queue_dispose (GObject *object) gsk_gl_command_batches_clear (&self->batches); gsk_gl_command_binds_clear (&self->batch_binds); gsk_gl_command_uniforms_clear (&self->batch_uniforms); + gsk_gl_syncs_clear (&self->syncs); gsk_gl_buffer_destroy (&self->vertices); @@ -449,6 +450,7 @@ gsk_gl_command_queue_init (GskGLCommandQueue *self) gsk_gl_command_batches_init (&self->batches, 128); gsk_gl_command_binds_init (&self->batch_binds, 1024); gsk_gl_command_uniforms_init (&self->batch_uniforms, 2048); + gsk_gl_syncs_init (&self->syncs, 10); gsk_gl_buffer_init (&self->vertices, GL_ARRAY_BUFFER, sizeof (GskGLDrawVertex)); } @@ -1159,17 +1161,25 @@ gsk_gl_command_queue_execute (GskGLCommandQueue *self, if G_UNLIKELY (batch->draw.bind_count > 0) { const GskGLCommandBind *bind = &self->batch_binds.items[batch->draw.bind_offset]; - for (guint i = 0; i < batch->draw.bind_count; i++) { if (textures[bind->texture] != bind->id) { + GskGLSync *s; + if (active != bind->texture) { active = bind->texture; glActiveTexture (GL_TEXTURE0 + bind->texture); } + s = gsk_gl_syncs_get_sync (&self->syncs, bind->id); + if (s && s->sync) + { + glWaitSync ((GLsync) s->sync, 0, GL_TIMEOUT_IGNORED); + s->sync = NULL; + } + glBindTexture (GL_TEXTURE_2D, bind->id); textures[bind->texture] = bind->id; if (!self->has_samplers) @@ -1315,6 +1325,7 @@ gsk_gl_command_queue_end_frame (GskGLCommandQueue *self) self->batches.len = 0; self->batch_binds.len = 0; self->batch_uniforms.len = 0; + self->syncs.len = 0; self->n_uploads = 0; self->tail_batch_index = -1; self->in_frame = FALSE; diff --git a/gsk/gl/gskglcommandqueueprivate.h b/gsk/gl/gskglcommandqueueprivate.h index fd72f68aff..df3afb1eea 100644 --- a/gsk/gl/gskglcommandqueueprivate.h +++ b/gsk/gl/gskglcommandqueueprivate.h @@ -168,9 +168,15 @@ typedef union _GskGLCommandBatch G_STATIC_ASSERT (sizeof (GskGLCommandBatch) == 32); +typedef struct _GskGLSync { + guint id; + gpointer sync; +} GskGLSync; + DEFINE_INLINE_ARRAY (GskGLCommandBatches, gsk_gl_command_batches, GskGLCommandBatch) DEFINE_INLINE_ARRAY (GskGLCommandBinds, gsk_gl_command_binds, GskGLCommandBind) DEFINE_INLINE_ARRAY (GskGLCommandUniforms, gsk_gl_command_uniforms, GskGLCommandUniform) +DEFINE_INLINE_ARRAY (GskGLSyncs, gsk_gl_syncs, GskGLSync) struct _GskGLCommandQueue { @@ -233,6 +239,10 @@ struct _GskGLCommandQueue */ GLuint samplers[GSK_GL_N_FILTERS * GSK_GL_N_FILTERS]; + /* Array of sync objects to wait on. + */ + GskGLSyncs syncs; + /* Discovered max texture size when loading the command queue so that we * can either scale down or slice textures to fit within this size. Assumed * to be both height and width. @@ -371,5 +381,36 @@ gsk_gl_command_queue_bind_framebuffer (GskGLCommandQueue *self, return ret; } +static inline GskGLSync * +gsk_gl_syncs_get_sync (GskGLSyncs *syncs, + guint id) +{ + for (unsigned int i = 0; i < syncs->len; i++) + { + GskGLSync *sync = &syncs->items[i]; + if (sync->id == id) + return sync; + } + return NULL; +} + +static inline void +gsk_gl_syncs_add_sync (GskGLSyncs *syncs, + guint id, + gpointer sync) +{ + GskGLSync *s; + + s = gsk_gl_syncs_get_sync (syncs, id); + if (s) + g_assert (s->sync == sync); + else + { + s = gsk_gl_syncs_append (syncs); + s->id = id; + s->sync = sync; + } +} + G_END_DECLS diff --git a/gsk/gl/gskglprogramprivate.h b/gsk/gl/gskglprogramprivate.h index 50c191eb4b..6bfbe48f02 100644 --- a/gsk/gl/gskglprogramprivate.h +++ b/gsk/gl/gskglprogramprivate.h @@ -286,6 +286,22 @@ gsk_gl_program_set_uniform_texture (GskGLProgram *self, } static inline void +gsk_gl_program_set_uniform_texture_with_sync (GskGLProgram *self, + guint key, + guint stamp, + GLenum texture_target, + GLenum texture_slot, + guint texture_id, + GLint min_filter, + GLint max_filter, + gpointer sync) +{ + gsk_gl_program_set_uniform_texture_with_filter (self, key, stamp, texture_target, texture_slot, texture_id, + min_filter, max_filter); + gsk_gl_syncs_add_sync (&self->driver->command_queue->syncs, texture_id, sync); +} + +static inline void gsk_gl_program_set_uniform_matrix (GskGLProgram *self, guint key, guint stamp, diff --git a/gsk/gl/gskglrenderjob.c b/gsk/gl/gskglrenderjob.c index 1eb82e80da..051619528c 100644 --- a/gsk/gl/gskglrenderjob.c +++ b/gsk/gl/gskglrenderjob.c @@ -191,6 +191,7 @@ typedef struct _GskGLRenderOffscreen /* Return location for texture ID */ guint texture_id; + gpointer sync; /* Whether to force creating a new texture, even if the * input already is a texture @@ -3570,6 +3571,9 @@ gsk_gl_render_job_upload_texture (GskGLRenderJob *job, offscreen->texture_id = gsk_gl_driver_load_texture (job->driver, texture, ensure_mipmap); init_full_texture_region (offscreen); offscreen->has_mipmap = ensure_mipmap; + + if (gl_texture && offscreen->texture_id == gdk_gl_texture_get_id (gl_texture)) + offscreen->sync = gdk_gl_texture_get_sync (gl_texture); } } @@ -3597,13 +3601,15 @@ gsk_gl_render_job_visit_texture (GskGLRenderJob *job, g_assert (offscreen.was_offscreen == FALSE); gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit)); - gsk_gl_program_set_uniform_texture_with_filter (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - offscreen.texture_id, - offscreen.has_mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR, - GL_LINEAR); + + gsk_gl_program_set_uniform_texture_with_sync (job->current_program, + UNIFORM_SHARED_SOURCE, 0, + GL_TEXTURE_2D, + GL_TEXTURE0, + offscreen.texture_id, + offscreen.has_mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR, + GL_LINEAR, + offscreen.sync); gsk_gl_render_job_draw_offscreen (job, bounds, &offscreen); gsk_gl_render_job_end_draw (job); } @@ -3733,21 +3739,29 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job, if G_LIKELY (texture->width <= max_texture_size && texture->height <= max_texture_size) { + gpointer sync; + texture_id = gsk_gl_driver_load_texture (job->driver, texture, filter == GSK_SCALING_FILTER_TRILINEAR); + if (GDK_IS_GL_TEXTURE (texture) && texture_id == gdk_gl_texture_get_id (GDK_GL_TEXTURE (texture))) + sync = gdk_gl_texture_get_sync (GDK_GL_TEXTURE (texture)); + else + sync = NULL; + u0 = (clip_rect.origin.x - bounds->origin.x) / bounds->size.width; v0 = (clip_rect.origin.y - bounds->origin.y) / bounds->size.height; u1 = (clip_rect.origin.x + clip_rect.size.width - bounds->origin.x) / bounds->size.width; v1 = (clip_rect.origin.y + clip_rect.size.height - bounds->origin.y) / bounds->size.height; gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit)); - gsk_gl_program_set_uniform_texture_with_filter (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - texture_id, - min_filter, - mag_filter); + gsk_gl_program_set_uniform_texture_with_sync (job->current_program, + UNIFORM_SHARED_SOURCE, 0, + GL_TEXTURE_2D, + GL_TEXTURE0, + texture_id, + min_filter, + mag_filter, + sync); gsk_gl_render_job_draw_coords (job, 0, 0, clip_rect.size.width, clip_rect.size.height, u0, v0, u1, v1, |