[gtk/wip/chergert/glproto: 298/526] allow for multiple command queues with shared state




commit 5bc57ee7ce720b77930a8312ee2559bea664cb87
Author: Christian Hergert <chergert redhat com>
Date:   Fri Jan 22 14:40:07 2021 -0800

    allow for multiple command queues with shared state
    
    this hoists the attachment/uniforms up a layer from the command queue so
    that we can have multiple while sharing state. Doing so allows us to use
    the driver more for the top-level object and ensure that programs may
    indirectly use the drivers command queue (which can change as we process
    frames for each surface). When a render completes, the queue is reverted
    to the shared command queue for out-of-band operations.

 gsk/next/gskglattachmentstate.c        | 14 ++++++++---
 gsk/next/gskglattachmentstateprivate.h |  2 ++
 gsk/next/gskglcommandqueue.c           | 29 +++++++++++++--------
 gsk/next/gskglcommandqueueprivate.h    |  4 ++-
 gsk/next/gskglcompiler.c               | 23 +++++++++--------
 gsk/next/gskglcompilerprivate.h        |  2 +-
 gsk/next/gskgldriver.c                 | 46 +++++++++++++++++++++++++++++-----
 gsk/next/gskgldriverprivate.h          |  6 ++++-
 gsk/next/gskglprogram.c                | 32 +++++++++++------------
 gsk/next/gskglprogramprivate.h         | 33 ++++++++++++------------
 gsk/next/gskglrenderer.c               | 40 +++++++++++++++++++----------
 gsk/next/gskglrenderjob.c              | 42 ++++++++-----------------------
 gsk/next/gskglrenderjobprivate.h       |  1 -
 gsk/next/gskgluniformstate.c           | 21 +++++++++++++---
 gsk/next/gskgluniformstateprivate.h    |  3 ++-
 15 files changed, 180 insertions(+), 118 deletions(-)
---
diff --git a/gsk/next/gskglattachmentstate.c b/gsk/next/gskglattachmentstate.c
index 404bf3c11c..5cb8f0b2d9 100644
--- a/gsk/next/gskglattachmentstate.c
+++ b/gsk/next/gskglattachmentstate.c
@@ -27,7 +27,7 @@ gsk_gl_attachment_state_new (void)
 {
   GskGLAttachmentState *self;
 
-  self = g_new0 (GskGLAttachmentState, 1);
+  self = g_atomic_rc_box_new0 (GskGLAttachmentState);
 
   self->fbo.changed = FALSE;
   self->fbo.id = 0;
@@ -48,10 +48,16 @@ gsk_gl_attachment_state_new (void)
   return self;
 }
 
+GskGLAttachmentState *
+gsk_gl_attachment_state_ref (GskGLAttachmentState *self)
+{
+  return g_atomic_rc_box_acquire (self);
+}
+
 void
-gsk_gl_attachment_state_free (GskGLAttachmentState *self)
+gsk_gl_attachment_state_unref (GskGLAttachmentState *self)
 {
-  g_free (self);
+  g_atomic_rc_box_release (self);
 }
 
 void
@@ -104,7 +110,7 @@ gsk_gl_attachment_state_bind_framebuffer (GskGLAttachmentState *self,
  * This can be used to restore state later, such as after running
  * various GL commands that are external to the GL renderer.
  *
- * This must be freed by calling either gsk_gl_attachment_state_free()
+ * This must be freed by calling either gsk_gl_attachment_state_unref()
  * or gsk_gl_attachment_state_restore().
  *
  * Returns: (transfer full): a new #GskGLAttachmentState or %NULL
diff --git a/gsk/next/gskglattachmentstateprivate.h b/gsk/next/gskglattachmentstateprivate.h
index 77b0f9bf53..5decdcd615 100644
--- a/gsk/next/gskglattachmentstateprivate.h
+++ b/gsk/next/gskglattachmentstateprivate.h
@@ -56,6 +56,8 @@ struct _GskGLAttachmentState
 };
 
 GskGLAttachmentState *gsk_gl_attachment_state_new              (void);
+GskGLAttachmentState *gsk_gl_attachment_state_ref              (GskGLAttachmentState *self);
+void                  gsk_gl_attachment_state_unref            (GskGLAttachmentState *self);
 GskGLAttachmentState *gsk_gl_attachment_state_save             (GskGLAttachmentState *self);
 void                  gsk_gl_attachment_state_restore          (GskGLAttachmentState *self);
 void                  gsk_gl_attachment_state_free             (GskGLAttachmentState *self);
diff --git a/gsk/next/gskglcommandqueue.c b/gsk/next/gskglcommandqueue.c
index c2653c8c46..88f0c18904 100644
--- a/gsk/next/gskglcommandqueue.c
+++ b/gsk/next/gskglcommandqueue.c
@@ -221,8 +221,8 @@ gsk_gl_command_queue_dispose (GObject *object)
 
   g_clear_object (&self->context);
   g_clear_pointer (&self->batches, g_array_unref);
-  g_clear_pointer (&self->attachments, gsk_gl_attachment_state_free);
-  g_clear_pointer (&self->uniforms, gsk_gl_uniform_state_free);
+  g_clear_pointer (&self->attachments, gsk_gl_attachment_state_unref);
+  g_clear_pointer (&self->uniforms, gsk_gl_uniform_state_unref);
   g_clear_pointer (&self->vertices, gsk_gl_buffer_free);
   g_clear_pointer (&self->batch_draws, g_array_unref);
   g_clear_pointer (&self->batch_binds, g_array_unref);
@@ -249,32 +249,39 @@ gsk_gl_command_queue_init (GskGLCommandQueue *self)
   self->batch_draws = g_array_new (FALSE, FALSE, sizeof (GskGLCommandDraw));
   self->batch_binds = g_array_new (FALSE, FALSE, sizeof (GskGLCommandBind));
   self->batch_uniforms = g_array_new (FALSE, FALSE, sizeof (GskGLCommandUniform));
-  self->attachments = gsk_gl_attachment_state_new ();
   self->vertices = gsk_gl_buffer_new (GL_ARRAY_BUFFER, sizeof (GskGLDrawVertex));
-  self->uniforms = gsk_gl_uniform_state_new ();
-  self->saved_state = g_ptr_array_new_with_free_func ((GDestroyNotify)gsk_gl_attachment_state_free);
+  self->saved_state = g_ptr_array_new_with_free_func ((GDestroyNotify)gsk_gl_attachment_state_unref);
   self->debug_groups = g_string_chunk_new (4096);
 }
 
 GskGLCommandQueue *
-gsk_gl_command_queue_new (GdkGLContext *context)
+gsk_gl_command_queue_new (GdkGLContext         *context,
+                          GskGLUniformState    *uniforms,
+                          GskGLAttachmentState *attachments)
 {
   GskGLCommandQueue *self;
-  GdkGLContext *previous_context;
 
   g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
 
   self = g_object_new (GSK_TYPE_GL_COMMAND_QUEUE, NULL);
   self->context = g_object_ref (context);
 
-  previous_context = gdk_gl_context_get_current ();
+  /* Use shared attachment state if we're provided one */
+  if (attachments != NULL)
+    self->attachments = gsk_gl_attachment_state_ref (attachments);
+  else
+    self->attachments = gsk_gl_attachment_state_new ();
+
+  /* Use shared uniform state if we're provided one */
+  if (uniforms != NULL)
+    self->uniforms = gsk_gl_uniform_state_ref (uniforms);
+  else
+    self->uniforms = gsk_gl_uniform_state_new ();
 
+  /* Determine max texture size immediately and restore context */
   gdk_gl_context_make_current (context);
   glGetIntegerv (GL_MAX_TEXTURE_SIZE, &self->max_texture_size);
 
-  if (previous_context != NULL)
-    gdk_gl_context_make_current (previous_context);
-
   return g_steal_pointer (&self);
 }
 
diff --git a/gsk/next/gskglcommandqueueprivate.h b/gsk/next/gskglcommandqueueprivate.h
index 6e406a274e..c136e0ea58 100644
--- a/gsk/next/gskglcommandqueueprivate.h
+++ b/gsk/next/gskglcommandqueueprivate.h
@@ -110,7 +110,9 @@ struct _GskGLCommandQueue
   guint in_draw : 1;
 };
 
-GskGLCommandQueue *gsk_gl_command_queue_new                  (GdkGLContext             *context);
+GskGLCommandQueue *gsk_gl_command_queue_new                  (GdkGLContext             *context,
+                                                              GskGLUniformState        *uniforms,
+                                                              GskGLAttachmentState     *attachments);
 GdkGLContext      *gsk_gl_command_queue_get_context          (GskGLCommandQueue        *self);
 void               gsk_gl_command_queue_make_current         (GskGLCommandQueue        *self);
 void               gsk_gl_command_queue_begin_frame          (GskGLCommandQueue        *self);
diff --git a/gsk/next/gskglcompiler.c b/gsk/next/gskglcompiler.c
index 9c3038634f..023b469a01 100644
--- a/gsk/next/gskglcompiler.c
+++ b/gsk/next/gskglcompiler.c
@@ -38,7 +38,7 @@ struct _GskGLCompiler
 {
   GObject parent_instance;
 
-  GskGLCommandQueue *command_queue;
+  GskNextDriver *driver;
 
   GBytes *all_preamble;
   GBytes *fragment_preamble;
@@ -81,7 +81,7 @@ gsk_gl_compiler_finalize (GObject *object)
   g_clear_pointer (&self->fragment_suffix, g_bytes_unref);
   g_clear_pointer (&self->vertex_source, g_bytes_unref);
   g_clear_pointer (&self->attrib_locations, g_array_unref);
-  g_clear_object (&self->command_queue);
+  g_clear_object (&self->driver);
 
   G_OBJECT_CLASS (gsk_gl_compiler_parent_class)->finalize (object);
 }
@@ -111,19 +111,20 @@ gsk_gl_compiler_init (GskGLCompiler *self)
 }
 
 GskGLCompiler *
-gsk_gl_compiler_new (GskGLCommandQueue *command_queue,
-                     gboolean           debug_shaders)
+gsk_gl_compiler_new (GskNextDriver *driver,
+                     gboolean       debug_shaders)
 {
   GskGLCompiler *self;
   GdkGLContext *context;
 
-  g_return_val_if_fail (GSK_IS_GL_COMMAND_QUEUE (command_queue), NULL);
+  g_return_val_if_fail (GSK_IS_NEXT_DRIVER (driver), NULL);
+  g_return_val_if_fail (driver->shared_command_queue != NULL, NULL);
 
   self = g_object_new (GSK_TYPE_GL_COMPILER, NULL);
-  self->command_queue = g_object_ref (command_queue);
+  self->driver = g_object_ref (driver);
   self->debug_shaders = !!debug_shaders;
 
-  context = gsk_gl_command_queue_get_context (command_queue);
+  context = gsk_gl_command_queue_get_context (self->driver->shared_command_queue);
 
   if (gdk_gl_context_get_use_es (context))
     {
@@ -149,7 +150,7 @@ gsk_gl_compiler_new (GskGLCommandQueue *command_queue,
       self->gl3 = TRUE;
     }
 
-  gsk_gl_command_queue_make_current (command_queue);
+  gsk_gl_command_queue_make_current (self->driver->shared_command_queue);
 
   return g_steal_pointer (&self);
 }
@@ -541,9 +542,9 @@ gsk_gl_compiler_compile (GskGLCompiler  *self,
   g_return_val_if_fail (self->vertex_preamble != NULL, NULL);
   g_return_val_if_fail (self->fragment_source != NULL, NULL);
   g_return_val_if_fail (self->vertex_source != NULL, NULL);
-  g_return_val_if_fail (self->command_queue != NULL, NULL);
+  g_return_val_if_fail (self->driver != NULL, NULL);
 
-  gsk_gl_command_queue_make_current (self->command_queue);
+  gsk_gl_command_queue_make_current (self->driver->command_queue);
 
   g_snprintf (version, sizeof version, "#version %d\n", self->glsl_version);
 
@@ -674,5 +675,5 @@ gsk_gl_compiler_compile (GskGLCompiler  *self,
       return NULL;
     }
 
-  return gsk_gl_program_new (self->command_queue, name, program_id);
+  return gsk_gl_program_new (self->driver, name, program_id);
 }
diff --git a/gsk/next/gskglcompilerprivate.h b/gsk/next/gskglcompilerprivate.h
index c26ab8563b..6f3a2774b3 100644
--- a/gsk/next/gskglcompilerprivate.h
+++ b/gsk/next/gskglcompilerprivate.h
@@ -36,7 +36,7 @@ typedef enum _GskGLCompilerKind
 
 G_DECLARE_FINAL_TYPE (GskGLCompiler, gsk_gl_compiler, GSK, GL_COMPILER, GObject)
 
-GskGLCompiler *gsk_gl_compiler_new                        (GskGLCommandQueue  *command_queue,
+GskGLCompiler *gsk_gl_compiler_new                        (GskNextDriver      *driver,
                                                            gboolean            debug);
 void           gsk_gl_compiler_set_preamble               (GskGLCompiler      *self,
                                                            GskGLCompilerKind   kind,
diff --git a/gsk/next/gskgldriver.c b/gsk/next/gskgldriver.c
index 77bde80552..d9d4935859 100644
--- a/gsk/next/gskgldriver.c
+++ b/gsk/next/gskgldriver.c
@@ -279,6 +279,9 @@ gsk_next_driver_dispose (GObject *object)
   g_clear_pointer (&self->render_targets, g_ptr_array_unref);
   g_clear_pointer (&self->shader_cache, g_hash_table_unref);
 
+  g_clear_object (&self->command_queue);
+  g_clear_object (&self->shared_command_queue);
+
   G_OBJECT_CLASS (gsk_next_driver_parent_class)->dispose (object);
 }
 
@@ -319,7 +322,7 @@ gsk_next_driver_load_programs (GskNextDriver  *self,
   g_assert (GSK_IS_NEXT_DRIVER (self));
   g_assert (GSK_IS_GL_COMMAND_QUEUE (self->command_queue));
 
-  compiler = gsk_gl_compiler_new (self->command_queue, self->debug);
+  compiler = gsk_gl_compiler_new (self, self->debug);
 
   /* Setup preambles that are shared by all shaders */
   gsk_gl_compiler_set_preamble_from_resource (compiler,
@@ -409,6 +412,7 @@ gsk_next_driver_new (GskGLCommandQueue  *command_queue,
 
   self = g_object_new (GSK_TYPE_NEXT_DRIVER, NULL);
   self->command_queue = g_object_ref (command_queue);
+  self->shared_command_queue = g_object_ref (command_queue);
   self->debug = !!debug_shaders;
 
   if (!gsk_next_driver_load_programs (self, error))
@@ -451,7 +455,13 @@ gsk_next_driver_from_shared_context (GdkGLContext  *context,
 
   gdk_gl_context_make_current (context);
 
-  command_queue = gsk_gl_command_queue_new (context);
+  /* Initially we create a command queue using the shared context. However,
+   * as frames are processed this will be replaced with the command queue
+   * for a given renderer. But since the programs are compiled into the
+   * shared context, all other contexts sharing with it will have access
+   * to those programs.
+   */
+  command_queue = gsk_gl_command_queue_new (context, NULL, NULL);
 
   if (!(driver = gsk_next_driver_new (command_queue, debug_shaders, error)))
     goto failure;
@@ -470,21 +480,27 @@ failure:
 /**
  * gsk_next_driver_begin_frame:
  * @self: a #GskNextDriver
+ * @command_queue: A #GskGLCommandQueue from the renderer
  *
  * Begin a new frame.
  *
- * Texture atlases, pools, and other resources will be prepared to
- * draw the next frame.
+ * Texture atlases, pools, and other resources will be prepared to draw the
+ * next frame. The command queue should be one that was created for the
+ * target context to be drawn into (the context of the renderer's surface).
  */
 void
-gsk_next_driver_begin_frame (GskNextDriver *self)
+gsk_next_driver_begin_frame (GskNextDriver     *self,
+                             GskGLCommandQueue *command_queue)
 {
   g_return_if_fail (GSK_IS_NEXT_DRIVER (self));
+  g_return_if_fail (GSK_IS_GL_COMMAND_QUEUE (command_queue));
   g_return_if_fail (self->in_frame == FALSE);
 
   self->in_frame = TRUE;
   self->current_frame_id++;
 
+  g_set_object (&self->command_queue, command_queue);
+
   gsk_gl_command_queue_make_current (self->command_queue);
   gsk_gl_command_queue_begin_frame (self->command_queue);
 
@@ -543,6 +559,12 @@ gsk_next_driver_end_frame (GskNextDriver *self)
   gsk_gl_texture_pool_clear (&self->texture_pool);
 
   self->in_frame = FALSE;
+
+  /* Reset command queue to our shared queue incase we have operations
+   * that need to be processed outside of a frame (such as callbacks
+   * from external systems such as GDK).
+   */
+  g_set_object (&self->command_queue, self->shared_command_queue);
 }
 
 GdkGLContext *
@@ -1005,7 +1027,7 @@ gsk_next_driver_lookup_shader (GskNextDriver  *self,
           return NULL;
         }
 
-      compiler = gsk_gl_compiler_new (self->command_queue, FALSE);
+      compiler = gsk_gl_compiler_new (self, FALSE);
       suffix = gsk_gl_shader_get_source (shader);
 
       gsk_gl_compiler_set_preamble_from_resource (compiler,
@@ -1084,3 +1106,15 @@ gsk_next_driver_save_atlases_to_png (GskNextDriver *self,
       g_free (filename);
     }
 }
+
+GskGLCommandQueue *
+gsk_next_driver_create_command_queue (GskNextDriver *self,
+                                      GdkGLContext  *context)
+{
+  g_return_val_if_fail (GSK_IS_NEXT_DRIVER (self), NULL);
+  g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
+
+  return gsk_gl_command_queue_new (context,
+                                   self->shared_command_queue->uniforms,
+                                   self->shared_command_queue->attachments);
+}
diff --git a/gsk/next/gskgldriverprivate.h b/gsk/next/gskgldriverprivate.h
index 18b10a66be..b23cbdd649 100644
--- a/gsk/next/gskgldriverprivate.h
+++ b/gsk/next/gskgldriverprivate.h
@@ -83,6 +83,7 @@ struct _GskNextDriver
 {
   GObject parent_instance;
 
+  GskGLCommandQueue *shared_command_queue;
   GskGLCommandQueue *command_queue;
 
   GskGLTexturePool texture_pool;
@@ -119,6 +120,8 @@ struct _GskNextDriver
 GskNextDriver     *gsk_next_driver_from_shared_context   (GdkGLContext         *context,
                                                           gboolean              debug_shaders,
                                                           GError              **error);
+GskGLCommandQueue *gsk_next_driver_create_command_queue  (GskNextDriver        *self,
+                                                          GdkGLContext         *context);
 GdkGLContext      *gsk_next_driver_get_context           (GskNextDriver        *self);
 gboolean           gsk_next_driver_create_render_target  (GskNextDriver        *self,
                                                           int                   width,
@@ -129,7 +132,8 @@ gboolean           gsk_next_driver_create_render_target  (GskNextDriver        *
 guint              gsk_next_driver_release_render_target (GskNextDriver        *self,
                                                           GskGLRenderTarget    *render_target,
                                                           gboolean              release_texture);
-void               gsk_next_driver_begin_frame           (GskNextDriver        *self);
+void               gsk_next_driver_begin_frame           (GskNextDriver        *self,
+                                                          GskGLCommandQueue    *command_queue);
 void               gsk_next_driver_end_frame             (GskNextDriver        *self);
 guint              gsk_next_driver_lookup_texture        (GskNextDriver        *self,
                                                           const GskTextureKey  *key);
diff --git a/gsk/next/gskglprogram.c b/gsk/next/gskglprogram.c
index f577e66be7..ff5e434d1a 100644
--- a/gsk/next/gskglprogram.c
+++ b/gsk/next/gskglprogram.c
@@ -21,25 +21,25 @@
 #include "config.h"
 
 #include "gskglcommandqueueprivate.h"
-#include "gskgldriverprivate.h"
 #include "gskglprogramprivate.h"
 #include "gskgluniformstateprivate.h"
 
 G_DEFINE_TYPE (GskGLProgram, gsk_gl_program, G_TYPE_OBJECT)
 
 GskGLProgram *
-gsk_gl_program_new (GskGLCommandQueue *command_queue,
-                    const char        *name,
-                    int                program_id)
+gsk_gl_program_new (GskNextDriver *driver,
+                    const char    *name,
+                    int            program_id)
 {
   GskGLProgram *self;
 
+  g_return_val_if_fail (GSK_IS_NEXT_DRIVER (driver), NULL);
   g_return_val_if_fail (program_id >= -1, NULL);
 
   self = g_object_new (GSK_TYPE_GL_PROGRAM, NULL);
   self->id = program_id;
   self->name = g_strdup (name);
-  self->command_queue = g_object_ref (command_queue);
+  self->driver = g_object_ref (driver);
 
   return self;
 }
@@ -56,7 +56,7 @@ gsk_gl_program_finalize (GObject *object)
 
   g_clear_pointer (&self->name, g_free);
   g_clear_pointer (&self->uniform_locations, g_array_unref);
-  g_clear_object (&self->command_queue);
+  g_clear_object (&self->driver);
 
   G_OBJECT_CLASS (gsk_gl_program_parent_class)->finalize (object);
 }
@@ -159,9 +159,9 @@ void
 gsk_gl_program_delete (GskGLProgram *self)
 {
   g_return_if_fail (GSK_IS_GL_PROGRAM (self));
-  g_return_if_fail (self->command_queue != NULL);
+  g_return_if_fail (self->driver->command_queue != NULL);
 
-  gsk_gl_command_queue_delete_program (self->command_queue, self->id);
+  gsk_gl_command_queue_delete_program (self->driver->command_queue, self->id);
   self->id = -1;
 }
 
@@ -180,7 +180,7 @@ gsk_gl_program_begin_draw (GskGLProgram            *self,
   g_assert (clip != NULL);
 
   if (self->viewport_location > -1)
-    gsk_gl_command_queue_set_uniform4f (self->command_queue,
+    gsk_gl_command_queue_set_uniform4f (self->driver->command_queue,
                                         self->id,
                                         self->viewport_location,
                                         viewport->origin.x,
@@ -189,13 +189,13 @@ gsk_gl_program_begin_draw (GskGLProgram            *self,
                                         viewport->size.height);
 
   if (self->modelview_location > -1)
-    gsk_gl_command_queue_set_uniform_matrix (self->command_queue,
+    gsk_gl_command_queue_set_uniform_matrix (self->driver->command_queue,
                                              self->id,
                                              self->modelview_location,
                                              modelview);
 
   if (self->projection_location > -1)
-    gsk_gl_command_queue_set_uniform_matrix (self->command_queue,
+    gsk_gl_command_queue_set_uniform_matrix (self->driver->command_queue,
                                              self->id,
                                              self->projection_location,
                                              projection);
@@ -203,12 +203,12 @@ gsk_gl_program_begin_draw (GskGLProgram            *self,
   if (self->clip_rect_location > -1)
     {
       if (clip != NULL)
-        gsk_gl_command_queue_set_uniform_rounded_rect (self->command_queue,
+        gsk_gl_command_queue_set_uniform_rounded_rect (self->driver->command_queue,
                                                        self->id,
                                                        self->clip_rect_location,
                                                        clip);
       else
-        gsk_gl_command_queue_set_uniform_rounded_rect (self->command_queue,
+        gsk_gl_command_queue_set_uniform_rounded_rect (self->driver->command_queue,
                                                        self->id,
                                                        self->clip_rect_location,
                                                        &GSK_ROUNDED_RECT_INIT (0,
@@ -218,12 +218,12 @@ gsk_gl_program_begin_draw (GskGLProgram            *self,
     }
 
   if (self->alpha_location > -1)
-    gsk_gl_command_queue_set_uniform1f (self->command_queue,
+    gsk_gl_command_queue_set_uniform1f (self->driver->command_queue,
                                         self->id,
                                         self->alpha_location,
                                         alpha);
 
-  gsk_gl_command_queue_begin_draw (self->command_queue, self->id, viewport);
+  gsk_gl_command_queue_begin_draw (self->driver->command_queue, self->id, viewport);
 }
 
 void
@@ -231,5 +231,5 @@ gsk_gl_program_end_draw (GskGLProgram *self)
 {
   g_assert (GSK_IS_GL_PROGRAM (self));
 
-  gsk_gl_command_queue_end_draw (self->command_queue);
+  gsk_gl_command_queue_end_draw (self->driver->command_queue);
 }
diff --git a/gsk/next/gskglprogramprivate.h b/gsk/next/gskglprogramprivate.h
index 1149002bfc..fbf7e01fc9 100644
--- a/gsk/next/gskglprogramprivate.h
+++ b/gsk/next/gskglprogramprivate.h
@@ -24,6 +24,7 @@
 #include "gskgltypesprivate.h"
 
 #include "gskglcommandqueueprivate.h"
+#include "gskgldriverprivate.h"
 
 G_BEGIN_DECLS
 
@@ -38,7 +39,7 @@ struct _GskGLProgram
   int id;
   char *name;
   GArray *uniform_locations;
-  GskGLCommandQueue *command_queue;
+  GskNextDriver *driver;
 
   /* Cached shared locations */
   int projection_location;
@@ -53,7 +54,7 @@ struct _GskGLProgram
   int size_location;
 };
 
-GskGLProgram *gsk_gl_program_new         (GskGLCommandQueue       *command_queue,
+GskGLProgram *gsk_gl_program_new         (GskNextDriver           *driver,
                                           const char              *name,
                                           int                      program_id);
 gboolean      gsk_gl_program_add_uniform (GskGLProgram            *self,
@@ -84,7 +85,7 @@ gsk_gl_program_set_uniform1fv (GskGLProgram *self,
                                guint         count,
                                const float  *values)
 {
-  gsk_gl_command_queue_set_uniform1fv (self->command_queue, self->id,
+  gsk_gl_command_queue_set_uniform1fv (self->driver->command_queue, self->id,
                                        gsk_gl_program_get_uniform_location (self, key),
                                        count, values);
 }
@@ -95,7 +96,7 @@ gsk_gl_program_set_uniform4fv (GskGLProgram *self,
                                guint         count,
                                const float  *values)
 {
-  gsk_gl_command_queue_set_uniform4fv (self->command_queue, self->id,
+  gsk_gl_command_queue_set_uniform4fv (self->driver->command_queue, self->id,
                                        gsk_gl_program_get_uniform_location (self, key),
                                        count, values);
 }
@@ -105,7 +106,7 @@ gsk_gl_program_set_uniform_rounded_rect (GskGLProgram         *self,
                                          guint                 key,
                                          const GskRoundedRect *rounded_rect)
 {
-  gsk_gl_command_queue_set_uniform_rounded_rect (self->command_queue, self->id,
+  gsk_gl_command_queue_set_uniform_rounded_rect (self->driver->command_queue, self->id,
                                                  gsk_gl_program_get_uniform_location (self, key),
                                                  rounded_rect);
 }
@@ -115,7 +116,7 @@ gsk_gl_program_set_uniform1i (GskGLProgram *self,
                               guint         key,
                               int           value0)
 {
-  gsk_gl_command_queue_set_uniform1i (self->command_queue,
+  gsk_gl_command_queue_set_uniform1i (self->driver->command_queue,
                                       self->id,
                                       gsk_gl_program_get_uniform_location (self, key),
                                       value0);
@@ -127,7 +128,7 @@ gsk_gl_program_set_uniform2i (GskGLProgram *self,
                               int           value0,
                               int           value1)
 {
-  gsk_gl_command_queue_set_uniform2i (self->command_queue,
+  gsk_gl_command_queue_set_uniform2i (self->driver->command_queue,
                                       self->id,
                                       gsk_gl_program_get_uniform_location (self, key),
                                       value0,
@@ -141,7 +142,7 @@ gsk_gl_program_set_uniform3i (GskGLProgram *self,
                               int           value1,
                               int           value2)
 {
-  gsk_gl_command_queue_set_uniform3i (self->command_queue,
+  gsk_gl_command_queue_set_uniform3i (self->driver->command_queue,
                                       self->id,
                                       gsk_gl_program_get_uniform_location (self, key),
                                       value0,
@@ -157,7 +158,7 @@ gsk_gl_program_set_uniform4i (GskGLProgram *self,
                               int           value2,
                               int           value3)
 {
-  gsk_gl_command_queue_set_uniform4i (self->command_queue,
+  gsk_gl_command_queue_set_uniform4i (self->driver->command_queue,
                                       self->id,
                                       gsk_gl_program_get_uniform_location (self, key),
                                       value0,
@@ -171,7 +172,7 @@ gsk_gl_program_set_uniform1f (GskGLProgram *self,
                               guint         key,
                               float         value0)
 {
-  gsk_gl_command_queue_set_uniform1f (self->command_queue,
+  gsk_gl_command_queue_set_uniform1f (self->driver->command_queue,
                                       self->id,
                                       gsk_gl_program_get_uniform_location (self, key),
                                       value0);
@@ -183,7 +184,7 @@ gsk_gl_program_set_uniform2f (GskGLProgram *self,
                               float         value0,
                               float         value1)
 {
-  gsk_gl_command_queue_set_uniform2f (self->command_queue,
+  gsk_gl_command_queue_set_uniform2f (self->driver->command_queue,
                                       self->id,
                                       gsk_gl_program_get_uniform_location (self, key),
                                       value0,
@@ -197,7 +198,7 @@ gsk_gl_program_set_uniform3f (GskGLProgram *self,
                               float         value1,
                               float         value2)
 {
-  gsk_gl_command_queue_set_uniform3f (self->command_queue,
+  gsk_gl_command_queue_set_uniform3f (self->driver->command_queue,
                                       self->id,
                                       gsk_gl_program_get_uniform_location (self, key),
                                       value0,
@@ -213,7 +214,7 @@ gsk_gl_program_set_uniform4f (GskGLProgram *self,
                               float         value2,
                               float         value3)
 {
-  gsk_gl_command_queue_set_uniform4f (self->command_queue,
+  gsk_gl_command_queue_set_uniform4f (self->driver->command_queue,
                                       self->id,
                                       gsk_gl_program_get_uniform_location (self, key),
                                       value0,
@@ -227,7 +228,7 @@ gsk_gl_program_set_uniform_color (GskGLProgram  *self,
                                   guint          key,
                                   const GdkRGBA *color)
 {
-  gsk_gl_command_queue_set_uniform_color (self->command_queue,
+  gsk_gl_command_queue_set_uniform_color (self->driver->command_queue,
                                           self->id,
                                           gsk_gl_program_get_uniform_location (self, key),
                                           color);
@@ -240,7 +241,7 @@ gsk_gl_program_set_uniform_texture (GskGLProgram *self,
                                     GLenum        texture_slot,
                                     guint         texture_id)
 {
-  gsk_gl_command_queue_set_uniform_texture (self->command_queue,
+  gsk_gl_command_queue_set_uniform_texture (self->driver->command_queue,
                                             self->id,
                                             gsk_gl_program_get_uniform_location (self, key),
                                             texture_target,
@@ -253,7 +254,7 @@ gsk_gl_program_set_uniform_matrix (GskGLProgram            *self,
                                    guint                    key,
                                    const graphene_matrix_t *matrix)
 {
-  gsk_gl_command_queue_set_uniform_matrix (self->command_queue,
+  gsk_gl_command_queue_set_uniform_matrix (self->driver->command_queue,
                                            self->id,
                                            gsk_gl_program_get_uniform_location (self, key),
                                            matrix);
diff --git a/gsk/next/gskglrenderer.c b/gsk/next/gskglrenderer.c
index 59db1fea46..6db031f161 100644
--- a/gsk/next/gskglrenderer.c
+++ b/gsk/next/gskglrenderer.c
@@ -45,6 +45,14 @@ struct _GskNextRenderer
    */
   GdkGLContext *context;
 
+  /* Our command queue is private to this renderer and talks to the GL
+   * context for our target surface. This ensure that framebuffer 0 matches
+   * the surface we care about. Since the context is shared with other
+   * contexts from other renderers on the display, texture atlases,
+   * programs, and other objects are available to them all.
+   */
+  GskGLCommandQueue *command_queue;
+
   /* The driver manages our program state and command queues. It also
    * deals with caching textures, shaders, shadows, glyph, and icon
    * caches through various helpers.
@@ -80,6 +88,7 @@ gsk_next_renderer_realize (GskRenderer  *renderer,
 
   g_assert (self->driver == NULL);
   g_assert (self->context == NULL);
+  g_assert (self->command_queue == NULL);
 
   if (!(context = gdk_surface_create_gl_context (surface, error)) ||
       !gdk_gl_context_realize (context, error))
@@ -102,6 +111,7 @@ gsk_next_renderer_realize (GskRenderer  *renderer,
   if (!(driver = gsk_next_driver_from_shared_context (shared_context, debug_shaders, error)))
     goto failure;
 
+  self->command_queue = gsk_next_driver_create_command_queue (driver, context);
   self->context = g_steal_pointer (&context);
   self->driver = g_steal_pointer (&driver);
 
@@ -122,6 +132,8 @@ gsk_next_renderer_unrealize (GskRenderer *renderer)
   g_assert (GSK_IS_NEXT_RENDERER (renderer));
 
   g_clear_object (&self->driver);
+  g_clear_object (&self->context);
+  g_clear_object (&self->command_queue);
 }
 
 typedef struct _GskGLTextureState
@@ -230,20 +242,19 @@ gsk_gl_renderer_render (GskRenderer          *renderer,
   gdk_gl_context_make_current (self->context);
   gdk_draw_context_begin_frame (GDK_DRAW_CONTEXT (self->context), update_area);
 
-  job = gsk_gl_render_job_new (self->driver, &viewport, scale_factor, render_region, self->context, 0);
-
+  gsk_next_driver_begin_frame (self->driver, self->command_queue);
+  job = gsk_gl_render_job_new (self->driver, &viewport, scale_factor, render_region, 0);
 #ifdef G_ENABLE_DEBUG
   if (GSK_RENDERER_DEBUG_CHECK (GSK_RENDERER (self), FALLBACK))
     gsk_gl_render_job_set_debug_fallback (job, TRUE);
 #endif
-
   gsk_gl_render_job_render (job, root);
+  gsk_next_driver_end_frame (self->driver);
+  gsk_gl_render_job_free (job);
 
   gdk_gl_context_make_current (self->context);
   gdk_draw_context_end_frame (GDK_DRAW_CONTEXT (self->context));
 
-  gsk_gl_render_job_free (job);
-
   cairo_region_destroy (render_region);
 }
 
@@ -255,7 +266,7 @@ gsk_gl_renderer_render_texture (GskRenderer           *renderer,
   GskNextRenderer *self = (GskNextRenderer *)renderer;
   GskGLRenderTarget *render_target;
   GskGLRenderJob *job;
-  GdkGLContext *context;
+  GdkTexture *texture;
   guint texture_id;
   int width;
   int height;
@@ -263,25 +274,28 @@ gsk_gl_renderer_render_texture (GskRenderer           *renderer,
   g_assert (GSK_IS_NEXT_RENDERER (renderer));
   g_assert (root != NULL);
 
-  context = gsk_gl_command_queue_get_context (self->driver->command_queue);
   width = ceilf (viewport->size.width);
   height = ceilf (viewport->size.height);
 
-  gdk_gl_context_make_current (context);
-
   if (!gsk_next_driver_create_render_target (self->driver,
                                              width, height,
                                              GL_NEAREST, GL_NEAREST,
                                              &render_target))
     return NULL;
 
-  job = gsk_gl_render_job_new (self->driver, viewport, 1, NULL, context, render_target->framebuffer_id);
+  gsk_next_driver_begin_frame (self->driver, self->command_queue);
+  job = gsk_gl_render_job_new (self->driver, viewport, 1, NULL, render_target->framebuffer_id);
+#ifdef G_ENABLE_DEBUG
+  if (GSK_RENDERER_DEBUG_CHECK (GSK_RENDERER (self), FALLBACK))
+    gsk_gl_render_job_set_debug_fallback (job, TRUE);
+#endif
   gsk_gl_render_job_render_flipped (job, root);
-  gsk_gl_render_job_free (job);
-
   texture_id = gsk_next_driver_release_render_target (self->driver, render_target, FALSE);
+  texture = create_texture_from_texture (self->context, texture_id, width, height);
+  gsk_next_driver_end_frame (self->driver);
+  gsk_gl_render_job_free (job);
 
-  return create_texture_from_texture (context, texture_id, width, height);
+  return g_steal_pointer (&texture);
 }
 
 static void
diff --git a/gsk/next/gskglrenderjob.c b/gsk/next/gskglrenderjob.c
index a88f411082..cbcbf3e0ef 100644
--- a/gsk/next/gskglrenderjob.c
+++ b/gsk/next/gskglrenderjob.c
@@ -3502,7 +3502,6 @@ gsk_gl_render_job_render_flipped (GskGLRenderJob *job,
                                   GskRenderNode  *root)
 {
   graphene_matrix_t proj;
-  GdkGLContext *context;
   guint framebuffer_id;
   guint texture_id;
   guint surface_height;
@@ -3511,11 +3510,8 @@ gsk_gl_render_job_render_flipped (GskGLRenderJob *job,
   g_return_if_fail (root != NULL);
   g_return_if_fail (GSK_IS_NEXT_DRIVER (job->driver));
 
-  context = gsk_next_driver_get_context (job->driver);
   surface_height = job->viewport.size.height;
 
-  gdk_gl_context_make_current (context);
-
   graphene_matrix_init_ortho (&proj,
                               job->viewport.origin.x,
                               job->viewport.origin.x + job->viewport.size.width,
@@ -3532,16 +3528,14 @@ gsk_gl_render_job_render_flipped (GskGLRenderJob *job,
                                                   &framebuffer_id, &texture_id))
     return;
 
-  gsk_next_driver_begin_frame (job->driver);
-
   /* Setup drawing to our offscreen texture/framebuffer which is flipped */
   gsk_gl_command_queue_bind_framebuffer (job->command_queue, framebuffer_id);
   gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport);
 
   /* Visit all nodes creating batches */
-  gdk_gl_context_push_debug_group (context, "Building command queue");
+  gdk_gl_context_push_debug_group (job->command_queue->context, "Building command queue");
   gsk_gl_render_job_visit_node (job, root);
-  gdk_gl_context_pop_debug_group (context);
+  gdk_gl_context_pop_debug_group (job->command_queue->context);
 
   /* Now draw to our real destination, but flipped */
   gsk_gl_command_queue_bind_framebuffer (job->command_queue, job->framebuffer);
@@ -3560,13 +3554,9 @@ gsk_gl_render_job_render_flipped (GskGLRenderJob *job,
   gsk_gl_render_job_draw_rect (job, &job->viewport);
   gsk_gl_program_end_draw (job->driver->blit);
 
-  gdk_gl_context_push_debug_group (context, "Executing 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, 1, NULL);
-  gdk_gl_context_pop_debug_group (context);
-
-  gsk_next_driver_end_frame (job->driver);
-
-  gdk_gl_context_make_current (context);
+  gdk_gl_context_pop_debug_group (job->command_queue->context);
 
   glDeleteFramebuffers (1, &framebuffer_id);
   glDeleteTextures (1, &texture_id);
@@ -3576,7 +3566,6 @@ void
 gsk_gl_render_job_render (GskGLRenderJob *job,
                           GskRenderNode  *root)
 {
-  GdkGLContext *context;
   guint scale_factor;
   guint surface_height;
 
@@ -3584,22 +3573,18 @@ gsk_gl_render_job_render (GskGLRenderJob *job,
   g_return_if_fail (root != NULL);
   g_return_if_fail (GSK_IS_NEXT_DRIVER (job->driver));
 
-  context = gsk_gl_command_queue_get_context (job->command_queue);
   scale_factor = MAX (job->scale_x, job->scale_y);
   surface_height = job->viewport.size.height;
 
-  /* Do initial frame setup using shared GL context */
-  gsk_next_driver_begin_frame (job->driver);
-
   /* Build the command queue using the shared GL context for all renderers
    * on the same display.
    */
-  gdk_gl_context_push_debug_group (context, "Building command queue");
+  gdk_gl_context_push_debug_group (job->command_queue->context, "Building command queue");
   if (job->framebuffer != 0)
     gsk_gl_command_queue_bind_framebuffer (job->command_queue, job->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 (context);
+  gdk_gl_context_pop_debug_group (job->command_queue->context);
 
 #if 0
   /* At this point the atlases have uploaded content while we processed
@@ -3612,13 +3597,10 @@ gsk_gl_render_job_render (GskGLRenderJob *job,
    * that was provided to us when creating the render job as framebuffer 0
    * is bound to that context.
    */
-  gdk_gl_context_make_current (job->context);
-  gdk_gl_context_push_debug_group (job->context, "Executing command queue");
+  gdk_gl_context_make_current (job->command_queue->context);
+  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);
-  gdk_gl_context_pop_debug_group (job->context);
-
-  /* Do frame cleanup using shared GL context */
-  gsk_next_driver_end_frame (job->driver);
+  gdk_gl_context_pop_debug_group (job->command_queue->context);
 }
 
 void
@@ -3635,7 +3617,6 @@ gsk_gl_render_job_new (GskNextDriver         *driver,
                        const graphene_rect_t *viewport,
                        float                  scale_factor,
                        const cairo_region_t  *region,
-                       GdkGLContext          *context,
                        guint                  framebuffer)
 {
   const graphene_rect_t *clip_rect = viewport;
@@ -3643,14 +3624,12 @@ gsk_gl_render_job_new (GskNextDriver         *driver,
   GskGLRenderJob *job;
 
   g_return_val_if_fail (GSK_IS_NEXT_DRIVER (driver), NULL);
-  g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
   g_return_val_if_fail (viewport != NULL, NULL);
   g_return_val_if_fail (scale_factor > 0, NULL);
 
   job = g_slice_new0 (GskGLRenderJob);
   job->driver = g_object_ref (driver);
-  job->command_queue = driver->command_queue;
-  job->context = g_object_ref (context);
+  job->command_queue = job->driver->command_queue;
   job->clip = g_array_new (FALSE, FALSE, sizeof (GskGLRenderClip));
   job->modelview = g_array_new (FALSE, FALSE, sizeof (GskGLRenderModelview));
   job->framebuffer = framebuffer;
@@ -3704,7 +3683,6 @@ gsk_gl_render_job_free (GskGLRenderJob *job)
     }
 
   g_clear_object (&job->driver);
-  g_clear_object (&job->context);
   g_clear_pointer (&job->region, cairo_region_destroy);
   g_clear_pointer (&job->modelview, g_array_unref);
   g_clear_pointer (&job->clip, g_array_unref);
diff --git a/gsk/next/gskglrenderjobprivate.h b/gsk/next/gskglrenderjobprivate.h
index 02cfee5737..2a8c01fa71 100644
--- a/gsk/next/gskglrenderjobprivate.h
+++ b/gsk/next/gskglrenderjobprivate.h
@@ -27,7 +27,6 @@ GskGLRenderJob *gsk_gl_render_job_new                 (GskNextDriver         *dr
                                                        const graphene_rect_t *viewport,
                                                        float                  scale_factor,
                                                        const cairo_region_t  *region,
-                                                       GdkGLContext          *context,
                                                        guint                  framebuffer);
 void            gsk_gl_render_job_free                (GskGLRenderJob        *job);
 void            gsk_gl_render_job_render              (GskGLRenderJob        *job,
diff --git a/gsk/next/gskgluniformstate.c b/gsk/next/gskgluniformstate.c
index b4e41261df..a75255b4e3 100644
--- a/gsk/next/gskgluniformstate.c
+++ b/gsk/next/gskgluniformstate.c
@@ -86,19 +86,32 @@ gsk_gl_uniform_state_new (void)
 {
   GskGLUniformState *state;
 
-  state = g_new0 (GskGLUniformState, 1);
+  state = g_atomic_rc_box_new0 (GskGLUniformState);
   state->program_info = g_array_new (FALSE, TRUE, sizeof (ProgramInfo));
   state->uniform_data = g_byte_array_new ();
 
   return g_steal_pointer (&state);
 }
 
-void
-gsk_gl_uniform_state_free (GskGLUniformState *state)
+GskGLUniformState *
+gsk_gl_uniform_state_ref (GskGLUniformState *state)
+{
+  return g_atomic_rc_box_acquire (state);
+}
+
+static void
+gsk_gl_uniform_state_finalize (gpointer data)
 {
+  GskGLUniformState *state = data;
+
   g_clear_pointer (&state->program_info, g_array_unref);
   g_clear_pointer (&state->uniform_data, g_byte_array_unref);
-  g_free (state);
+}
+
+void
+gsk_gl_uniform_state_unref (GskGLUniformState *state)
+{
+  g_atomic_rc_box_release_full (state, gsk_gl_uniform_state_finalize);
 }
 
 static inline void
diff --git a/gsk/next/gskgluniformstateprivate.h b/gsk/next/gskgluniformstateprivate.h
index 63bfd84f5f..609bba87d0 100644
--- a/gsk/next/gskgluniformstateprivate.h
+++ b/gsk/next/gskgluniformstateprivate.h
@@ -87,6 +87,8 @@ typedef enum _GskGLUniformKind
 } GskGLUniformFormat;
 
 GskGLUniformState *gsk_gl_uniform_state_new              (void);
+GskGLUniformState *gsk_gl_uniform_state_ref              (GskGLUniformState         *state);
+void               gsk_gl_uniform_state_unref            (GskGLUniformState         *state);
 void               gsk_gl_uniform_state_clear_program    (GskGLUniformState         *state,
                                                           guint                      program);
 void               gsk_gl_uniform_state_end_frame        (GskGLUniformState         *state);
@@ -178,7 +180,6 @@ void               gsk_gl_uniform_state_snapshot         (GskGLUniformState
                                                           guint                      program_id,
                                                           GskGLUniformStateCallback  callback,
                                                           gpointer                   user_data);
-void               gsk_gl_uniform_state_free             (GskGLUniformState         *state);
 
 static inline gconstpointer
 gsk_gl_uniform_state_get_uniform_data (GskGLUniformState *state,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]