gsk: Synchronize when using textures
authorMatthias Clasen <mclasen@redhat.com>
Sat, 28 Jan 2023 20:20:26 +0000 (15:20 -0500)
committerBenjamin Otte <otte@redhat.com>
Thu, 27 Apr 2023 04:57:02 +0000 (06:57 +0200)
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.

gsk/gl/gskglcommandqueue.c
gsk/gl/gskglcommandqueueprivate.h
gsk/gl/gskglprogramprivate.h
gsk/gl/gskglrenderjob.c

index d5aa01a5f8a978ae0867daefe99daf907e34967c..cf8acc5da26f699965962b460044b93aef26691a 100644 (file)
@@ -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;
index fd72f68aff554e42f5d3683b91b934f3207bd782..df3afb1eeaa5c304674671183676a21d12b01207 100644 (file)
@@ -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
 
index 50c191eb4bc70b1ff64e58414a827c90c282313d..6bfbe48f024cc0c615e0c9ace115d91aa5401331 100644 (file)
@@ -285,6 +285,22 @@ gsk_gl_program_set_uniform_texture (GskGLProgram *self,
                                                   GL_LINEAR);
 }
 
+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,
index 1eb82e80da33e4f5fdee7c9065277c8afb6ac387..051619528c5de2747c14fbf96e4cc11a7ec4a570 100644 (file)
@@ -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,