[gtk/wip/chergert/glproto] remove state save/restore semantics



commit abe39e2e96bff1e0ee8e4054e4312f3919ee8a14
Author: Christian Hergert <chergert redhat com>
Date:   Fri Feb 12 14:09:51 2021 -0800

    remove state save/restore semantics
    
    too hard to optimize this when instead we can use stamps and
    be more specific about our state changes like the GL renderer
    did.
    
    although this does try hard to add a few more variants based
    on usage so that we avoid intermediate structs in most cases
    thereby saving some copies.

 gsk/next/gskgldriver.c        |   1 -
 gsk/next/gskgldriverprivate.h |   4 +-
 gsk/next/gskglrenderjob.c     | 270 +++++++++++++++++++++---------------------
 3 files changed, 139 insertions(+), 136 deletions(-)
---
diff --git a/gsk/next/gskgldriver.c b/gsk/next/gskgldriver.c
index bd60570393..2e1dfba79b 100644
--- a/gsk/next/gskgldriver.c
+++ b/gsk/next/gskgldriver.c
@@ -315,7 +315,6 @@ gsk_next_driver_class_init (GskNextDriverClass *klass)
 static void
 gsk_next_driver_init (GskNextDriver *self)
 {
-  self->last_shared_state = 1;
   self->autorelease_framebuffers = g_array_new (FALSE, FALSE, sizeof (guint));
   self->textures = g_hash_table_new_full (NULL, NULL, NULL,
                                           (GDestroyNotify)gsk_gl_texture_free);
diff --git a/gsk/next/gskgldriverprivate.h b/gsk/next/gskgldriverprivate.h
index f09b42e69f..6531fc9c6c 100644
--- a/gsk/next/gskgldriverprivate.h
+++ b/gsk/next/gskgldriverprivate.h
@@ -114,8 +114,8 @@ struct _GskNextDriver
 
   gint64 current_frame_id;
 
-  /* Monotonic counter to reduce shared state changes */
-  guint last_shared_state;
+  /* Used to reduce number of comparisons */
+  guint stamps[UNIFORM_SHARED_LAST];
 
   guint debug : 1;
   guint in_frame : 1;
diff --git a/gsk/next/gskglrenderjob.c b/gsk/next/gskglrenderjob.c
index 0f88ce9d37..ebe07af591 100644
--- a/gsk/next/gskglrenderjob.c
+++ b/gsk/next/gskglrenderjob.c
@@ -156,18 +156,6 @@ struct _GskGLRenderJob
   guint debug_fallback : 1;
 };
 
-typedef struct GskGLRenderState
-{
-  graphene_rect_t   viewport;
-  graphene_matrix_t projection;
-  guint             framebuffer;
-  float             alpha;
-  float             offset_x;
-  float             offset_y;
-  float             scale_x;
-  float             scale_y;
-} GskGLRenderState;
-
 typedef struct _GskGLRenderOffscreen
 {
   const graphene_rect_t *bounds;
@@ -195,25 +183,13 @@ static inline void
 gsk_gl_render_job_begin_draw (GskGLRenderJob *job,
                               GskGLProgram   *program)
 {
-  /* If the program is up to our shared state value, then we can ignore callign
-   * gsk_gl_program_begin_draw() with the initial values saving a bunch of
-   * compares. Last checked this saves about 25-35% of the compares when
-   * running widget-factory on the first page.
-   */
-  if G_LIKELY (program->last_shared_state == job->driver->last_shared_state)
-    {
-      gsk_gl_command_queue_begin_draw (job->command_queue, program->program_info, &job->viewport);
-    }
-  else
-    {
-      gsk_gl_program_begin_draw (program,
-                                 &job->viewport,
-                                 &job->projection,
-                                 &job->current_modelview->matrix,
-                                 &job->current_clip->rect,
-                                 job->alpha);
-      program->last_shared_state = job->driver->last_shared_state;
-    }
+  /* TODO: Use stamps */
+  gsk_gl_program_begin_draw (program,
+                             &job->viewport,
+                             &job->projection,
+                             &job->current_modelview->matrix,
+                             &job->current_clip->rect,
+                             job->alpha);
 }
 
 static inline void
@@ -423,6 +399,21 @@ init_projection_matrix (graphene_matrix_t     *projection,
   graphene_matrix_scale (projection, 1, -1, 1);
 }
 
+static inline float
+gsk_gl_render_job_set_alpha (GskGLRenderJob *job,
+                             float           alpha)
+{
+  if (job->alpha != alpha)
+    {
+      float ret = job->alpha;
+      job->alpha = alpha;
+      job->driver->stamps[UNIFORM_SHARED_ALPHA]++;
+      return ret;
+    }
+
+  return alpha;
+}
+
 static void
 extract_matrix_metadata (GskGLRenderModelview *modelview)
 {
@@ -484,7 +475,7 @@ gsk_gl_render_job_set_modelview (GskGLRenderJob *job,
   g_assert (job != NULL);
   g_assert (job->modelview != NULL);
 
-  job->driver->last_shared_state++;
+  job->driver->stamps[UNIFORM_SHARED_MODELVIEW]++;
 
   g_array_set_size (job->modelview, job->modelview->len + 1);
 
@@ -517,7 +508,7 @@ gsk_gl_render_job_push_modelview (GskGLRenderJob *job,
   g_assert (job->modelview != NULL);
   g_assert (transform != NULL);
 
-  job->driver->last_shared_state++;
+  job->driver->stamps[UNIFORM_SHARED_MODELVIEW]++;
 
   g_array_set_size (job->modelview, job->modelview->len + 1);
 
@@ -570,7 +561,7 @@ gsk_gl_render_job_pop_modelview (GskGLRenderJob *job)
   g_assert (job->modelview);
   g_assert (job->modelview->len > 0);
 
-  job->driver->last_shared_state++;
+  job->driver->stamps[UNIFORM_SHARED_MODELVIEW]++;
 
   head = job->current_modelview;
 
@@ -606,7 +597,7 @@ gsk_gl_render_job_push_clip (GskGLRenderJob       *job,
   g_assert (job->clip != NULL);
   g_assert (rect != NULL);
 
-  job->driver->last_shared_state++;
+  job->driver->stamps[UNIFORM_SHARED_CLIP_RECT]++;
 
   g_array_set_size (job->clip, job->clip->len + 1);
 
@@ -624,11 +615,9 @@ gsk_gl_render_job_pop_clip (GskGLRenderJob *job)
   g_assert (job->clip != NULL);
   g_assert (job->clip->len > 0);
 
-  job->driver->last_shared_state++;
-
+  job->driver->stamps[UNIFORM_SHARED_CLIP_RECT]++;
+  job->current_clip--;
   job->clip->len--;
-
-  job->current_clip = &g_array_index (job->clip, GskGLRenderClip, job->clip->len - 1);
 }
 
 static inline void
@@ -638,52 +627,67 @@ gsk_gl_render_job_offset (GskGLRenderJob *job,
 {
   if (offset_x || offset_y)
     {
-      job->driver->last_shared_state++;
-
       job->offset_x += offset_x;
       job->offset_y += offset_y;
     }
 }
 
-static void
-gsk_gl_render_state_save (GskGLRenderState *state,
-                          GskGLRenderJob   *job)
+static inline void
+gsk_gl_render_job_set_projection (GskGLRenderJob          *job,
+                                  const graphene_matrix_t *projection)
 {
-  g_assert (state != NULL);
-  g_assert (job != NULL);
-
-  job->driver->last_shared_state++;
-
-  memcpy (&state->viewport, &job->viewport, sizeof state->viewport);
-  memcpy (&state->projection, &job->projection, sizeof state->projection);
-
-  state->framebuffer = job->command_queue->attachments->fbo.id;
-  state->alpha = job->alpha;
-  state->offset_x = job->offset_x;
-  state->offset_y = job->offset_y;
-  state->scale_x = job->scale_x;
-  state->scale_y = job->scale_y;
+  memcpy (&job->projection, projection, sizeof job->projection);
+  job->driver->stamps[UNIFORM_SHARED_PROJECTION]++;
 }
 
-static void
-gsk_gl_render_state_restore (GskGLRenderState *state,
-                             GskGLRenderJob   *job)
+static inline void
+gsk_gl_render_job_set_projection_from_rect (GskGLRenderJob        *job,
+                                            const graphene_rect_t *rect,
+                                            graphene_matrix_t     *prev_projection)
 {
-  g_assert (state != NULL);
-  g_assert (job != NULL);
-
-  job->driver->last_shared_state++;
+  if (prev_projection)
+    memcpy (prev_projection, &job->projection, sizeof *prev_projection);
+  init_projection_matrix (&job->projection, rect);
+  job->driver->stamps[UNIFORM_SHARED_PROJECTION]++;
+}
 
-  memcpy (&job->viewport, &state->viewport, sizeof state->viewport);
-  memcpy (&job->projection, &state->projection, sizeof state->projection);
+static inline void
+gsk_gl_render_job_set_projection_for_size (GskGLRenderJob    *job,
+                                           float              width,
+                                           float              height,
+                                           graphene_matrix_t *prev_projection)
+{
+  if (prev_projection)
+    memcpy (prev_projection, &job->projection, sizeof *prev_projection);
+  graphene_matrix_init_ortho (&job->projection, 0, width, 0, height, ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE);
+  graphene_matrix_scale (&job->projection, 1, -1, 1);
+  job->driver->stamps[UNIFORM_SHARED_PROJECTION]++;
+}
 
-  gsk_gl_command_queue_bind_framebuffer (job->command_queue, state->framebuffer);
+static inline void
+gsk_gl_render_job_set_viewport (GskGLRenderJob        *job,
+                                const graphene_rect_t *viewport,
+                                graphene_rect_t       *prev_viewport)
+{
+  if (prev_viewport)
+    memcpy (prev_viewport, &job->viewport, sizeof *prev_viewport);
+  memcpy (&job->viewport, viewport, sizeof job->viewport);
+  job->driver->stamps[UNIFORM_SHARED_VIEWPORT]++;
+}
 
-  job->alpha = state->alpha;
-  job->offset_x = state->offset_x;
-  job->offset_y = state->offset_y;
-  job->scale_x = state->scale_x;
-  job->scale_y = state->scale_y;
+static inline void
+gsk_gl_render_job_set_viewport_for_size (GskGLRenderJob  *job,
+                                         float            width,
+                                         float            height,
+                                         graphene_rect_t *prev_viewport)
+{
+  if (prev_viewport)
+    memcpy (prev_viewport, &job->viewport, sizeof *prev_viewport);
+  job->viewport.origin.x = 0;
+  job->viewport.origin.y = 0;
+  job->viewport.size.width = width;
+  job->viewport.size.height = height;
+  job->driver->stamps[UNIFORM_SHARED_VIEWPORT]++;
 }
 
 static inline void
@@ -1053,7 +1057,9 @@ blur_offscreen (GskGLRenderJob       *job,
   const GskRoundedRect new_clip = GSK_ROUNDED_RECT_INIT (0, 0, texture_to_blur_width, 
texture_to_blur_height);
   GskGLRenderTarget *pass1;
   GskGLRenderTarget *pass2;
-  GskGLRenderState state;
+  graphene_matrix_t prev_projection;
+  graphene_rect_t prev_viewport;
+  guint prev_fbo;
 
   g_assert (blur_radius_x > 0);
   g_assert (blur_radius_y > 0);
@@ -1078,15 +1084,13 @@ blur_offscreen (GskGLRenderJob       *job,
                                              &pass2))
     return gsk_next_driver_release_render_target (job->driver, pass1, FALSE);
 
-  gsk_gl_render_state_save (&state, job);
-
-  init_projection_matrix (&job->projection, &new_clip.bounds);
+  gsk_gl_render_job_set_viewport (job, &new_clip.bounds, &prev_viewport);
+  gsk_gl_render_job_set_projection_from_rect (job, &new_clip.bounds, &prev_projection);
   gsk_gl_render_job_set_modelview (job, NULL);
-  job->viewport = new_clip.bounds;
   gsk_gl_render_job_push_clip (job, &new_clip);
 
   /* Bind new framebuffer and clear it */
-  gsk_gl_command_queue_bind_framebuffer (job->command_queue, pass1->framebuffer_id);
+  prev_fbo = gsk_gl_command_queue_bind_framebuffer (job->command_queue, pass1->framebuffer_id);
   gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport);
 
   /* Begin drawing the first horizontal pass, using offscreen as the
@@ -1137,8 +1141,9 @@ blur_offscreen (GskGLRenderJob       *job,
 
   gsk_gl_render_job_pop_modelview (job);
   gsk_gl_render_job_pop_clip (job);
-
-  gsk_gl_render_state_restore (&state, job);
+  gsk_gl_render_job_set_viewport (job, &prev_viewport, NULL);
+  gsk_gl_render_job_set_projection (job, &prev_projection);
+  gsk_gl_command_queue_bind_framebuffer (job->command_queue, prev_fbo);
 
   gsk_next_driver_release_render_target (job->driver, pass1, TRUE);
 
@@ -1865,7 +1870,9 @@ gsk_gl_render_job_visit_blurred_inset_shadow_node (GskGLRenderJob      *job,
       GskRoundedRect transformed_outline;
       GskRoundedRect outline_to_blur;
       GskGLRenderTarget *render_target;
-      GskGLRenderState state;
+      graphene_matrix_t prev_projection;
+      graphene_rect_t prev_viewport;
+      guint prev_fbo;
 
       /* TODO: In the following code, we have to be careful about where we apply the scale.
        * We're manually scaling stuff (e.g. the outline) so we can later use texture_width
@@ -1900,19 +1907,12 @@ gsk_gl_render_job_visit_blurred_inset_shadow_node (GskGLRenderJob      *job,
                                                  &render_target))
         g_assert_not_reached ();
 
-      gsk_gl_render_state_save (&state, job);
-
-      job->viewport.origin.x = 0;
-      job->viewport.origin.y = 0;
-      job->viewport.size.width = texture_width;
-      job->viewport.size.height = texture_height;
-
-      init_projection_matrix (&job->projection,
-                              &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height));
+      gsk_gl_render_job_set_viewport_for_size (job, texture_width, texture_height, &prev_viewport);
+      gsk_gl_render_job_set_projection_for_size (job, texture_width, texture_height, &prev_projection);
       gsk_gl_render_job_set_modelview (job, NULL);
       gsk_gl_render_job_push_clip (job, &GSK_ROUNDED_RECT_INIT (0, 0, texture_width, texture_height));
 
-      gsk_gl_command_queue_bind_framebuffer (job->command_queue, render_target->framebuffer_id);
+      prev_fbo = gsk_gl_command_queue_bind_framebuffer (job->command_queue, render_target->framebuffer_id);
       gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport);
 
       gsk_gl_render_job_transform_rounded_rect (job, &outline_to_blur, &transformed_outline);
@@ -1937,8 +1937,9 @@ gsk_gl_render_job_visit_blurred_inset_shadow_node (GskGLRenderJob      *job,
 
       gsk_gl_render_job_pop_modelview (job);
       gsk_gl_render_job_pop_clip (job);
-
-      gsk_gl_render_state_restore (&state, job);
+      gsk_gl_render_job_set_projection (job, &prev_projection);
+      gsk_gl_render_job_set_viewport (job, &prev_viewport, NULL);
+      gsk_gl_command_queue_bind_framebuffer (job->command_queue, prev_fbo);
 
       offscreen.texture_id = render_target->texture_id;
       init_full_texture_region (&offscreen);
@@ -2148,7 +2149,9 @@ gsk_gl_render_job_visit_blurred_outset_shadow_node (GskGLRenderJob      *job,
     {
       GdkGLContext *context = job->command_queue->context;
       GskGLRenderTarget *render_target;
-      GskGLRenderState state;
+      graphene_matrix_t prev_projection;
+      graphene_rect_t prev_viewport;
+      guint prev_fbo;
 
       gsk_next_driver_create_render_target (job->driver,
                                             texture_width, texture_height,
@@ -2170,16 +2173,13 @@ gsk_gl_render_job_visit_blurred_outset_shadow_node (GskGLRenderJob      *job,
         }
 
       /* Change state for offscreen */
-      gsk_gl_render_state_save (&state, job);
-      init_projection_matrix (&job->projection,
-                              &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height));
-      job->viewport = GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height);
+      gsk_gl_render_job_set_projection_for_size (job, texture_width, texture_height, &prev_projection);
+      gsk_gl_render_job_set_viewport_for_size (job, texture_width, texture_height, &prev_viewport);
       gsk_gl_render_job_set_modelview (job, NULL);
       gsk_gl_render_job_push_clip (job, &scaled_outline);
 
       /* Bind render target and clear it */
-      gsk_gl_command_queue_bind_framebuffer (job->command_queue,
-                                             render_target->framebuffer_id);
+      prev_fbo = gsk_gl_command_queue_bind_framebuffer (job->command_queue, render_target->framebuffer_id);
       gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport);
 
       /* Draw the outline using color program */
@@ -2193,7 +2193,8 @@ gsk_gl_render_job_visit_blurred_outset_shadow_node (GskGLRenderJob      *job,
       /* Reset state from offscreen */
       gsk_gl_render_job_pop_clip (job);
       gsk_gl_render_job_pop_modelview (job);
-      gsk_gl_render_state_restore (&state, job);
+      gsk_gl_render_job_set_viewport (job, &prev_viewport, NULL);
+      gsk_gl_render_job_set_projection (job, &prev_projection);
 
       /* Now blur the outline */
       init_full_texture_region (&offscreen);
@@ -2209,6 +2210,8 @@ gsk_gl_render_job_visit_blurred_outset_shadow_node (GskGLRenderJob      *job,
                                     &scaled_outline,
                                     blur_radius,
                                     blurred_texture_id);
+
+      gsk_gl_command_queue_bind_framebuffer (job->command_queue, prev_fbo);
     }
   else
     {
@@ -2448,12 +2451,9 @@ gsk_gl_render_job_visit_cross_fade_node (GskGLRenderJob      *job,
 
   if (!gsk_gl_render_job_visit_node_with_offscreen (job, end_node, &offscreen_end))
     {
-      float prev_alpha = job->alpha;
-
-      job->alpha = job->alpha * progress;
+      float prev_alpha = gsk_gl_render_job_set_alpha (job, job->alpha * progress);
       gsk_gl_render_job_visit_node (job, start_node);
-      job->alpha = prev_alpha;
-
+      gsk_gl_render_job_set_alpha (job, prev_alpha);
       return;
     }
 
@@ -2483,14 +2483,12 @@ gsk_gl_render_job_visit_opacity_node (GskGLRenderJob      *job,
 {
   const GskRenderNode *child = gsk_opacity_node_get_child (node);
   float opacity = gsk_opacity_node_get_opacity (node);
-  float prev_alpha = job->alpha;
   float new_alpha = job->alpha * opacity;
 
-  job->alpha = new_alpha;
-  job->driver->last_shared_state++;
-
   if (!ALPHA_IS_CLEAR (new_alpha))
     {
+      float prev_alpha = gsk_gl_render_job_set_alpha (job, new_alpha);
+
       if (gsk_render_node_get_node_type (child) == GSK_CONTAINER_NODE)
         {
           GskGLRenderOffscreen offscreen = {0};
@@ -2520,10 +2518,9 @@ gsk_gl_render_job_visit_opacity_node (GskGLRenderJob      *job,
         {
           gsk_gl_render_job_visit_node (job, child);
         }
-    }
 
-  job->alpha = prev_alpha;
-  job->driver->last_shared_state++;
+      gsk_gl_render_job_set_alpha (job, prev_alpha);
+    }
 }
 
 static inline void
@@ -3481,9 +3478,12 @@ gsk_gl_render_job_visit_node_with_offscreen (GskGLRenderJob       *job,
   }
 
   GskGLRenderTarget *render_target;
-  GskGLRenderState state;
-
-  gsk_gl_render_state_save (&state, job);
+  graphene_matrix_t prev_projection;
+  graphene_rect_t prev_viewport;
+  float offset_x = job->offset_x;
+  float offset_y = job->offset_y;
+  float prev_alpha;
+  guint prev_fbo;
 
   if (!gsk_next_driver_create_render_target (job->driver,
                                              width, height,
@@ -3507,32 +3507,35 @@ gsk_gl_render_job_visit_node_with_offscreen (GskGLRenderJob       *job,
                                           render_target->framebuffer_id);
     }
 
-  job->viewport.origin.x = offscreen->bounds->origin.x * scale_x;
-  job->viewport.origin.y = offscreen->bounds->origin.y * scale_y;
-  job->viewport.size.width = width;
-  job->viewport.size.height = height;
+  gsk_gl_render_job_set_viewport (job,
+                                  &GRAPHENE_RECT_INIT (offscreen->bounds->origin.x * scale_x,
+                                                       offscreen->bounds->origin.y * scale_y,
+                                                       width, height),
+                                  &prev_viewport);
+  gsk_gl_render_job_set_projection_from_rect (job, &job->viewport, &prev_projection);
+  gsk_gl_render_job_set_modelview (job, gsk_transform_scale (NULL, scale_x, scale_y));
+  prev_alpha = gsk_gl_render_job_set_alpha (job, 1.0f);
+  job->offset_x = 0;
+  job->offset_y = 0;
 
-  gsk_gl_command_queue_bind_framebuffer (job->command_queue, render_target->framebuffer_id);
+  prev_fbo = gsk_gl_command_queue_bind_framebuffer (job->command_queue, render_target->framebuffer_id);
   gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport);
 
-  init_projection_matrix (&job->projection, &job->viewport);
-  gsk_gl_render_job_set_modelview (job, gsk_transform_scale (NULL, scale_x, scale_y));
-
   if (offscreen->reset_clip)
     gsk_gl_render_job_push_clip (job, &GSK_ROUNDED_RECT_INIT_FROM_RECT (job->viewport));
 
-  job->offset_x = 0;
-  job->offset_y = 0;
-  job->alpha = 1.0f;
-
   gsk_gl_render_job_visit_node (job, node);
 
   if (offscreen->reset_clip)
     gsk_gl_render_job_pop_clip (job);
 
   gsk_gl_render_job_pop_modelview (job);
+  gsk_gl_render_job_set_viewport (job, &prev_viewport, NULL);
+  gsk_gl_render_job_set_projection (job, &prev_projection);
+  gsk_gl_command_queue_bind_framebuffer (job->command_queue, prev_fbo);
 
-  gsk_gl_render_state_restore (&state, job);
+  job->offset_x = offset_x;
+  job->offset_y = offset_y;
 
   offscreen->was_offscreen = TRUE;
   offscreen->texture_id = gsk_next_driver_release_render_target (job->driver,
@@ -3588,6 +3591,7 @@ gsk_gl_render_job_render_flipped (GskGLRenderJob *job,
   gdk_gl_context_pop_debug_group (job->command_queue->context);
 
   /* Now draw to our real destination, but flipped */
+  gsk_gl_render_job_set_alpha (job, 1.0f);
   gsk_gl_command_queue_bind_framebuffer (job->command_queue, job->framebuffer);
   gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport);
   gsk_gl_program_begin_draw (job->driver->blit,
@@ -3595,7 +3599,7 @@ gsk_gl_render_job_render_flipped (GskGLRenderJob *job,
                              &proj,
                              &job->current_modelview->matrix,
                              &job->current_clip->rect,
-                             1.0);
+                             job->alpha);
   gsk_gl_program_set_uniform_texture (job->driver->blit,
                                       UNIFORM_SHARED_SOURCE,
                                       GL_TEXTURE_2D,
@@ -3694,9 +3698,9 @@ gsk_gl_render_job_new (GskNextDriver         *driver,
   job->scale_x = scale_factor;
   job->scale_y = scale_factor;
   job->viewport = *viewport;
-  job->alpha = 1.0;
 
-  init_projection_matrix (&job->projection, viewport);
+  gsk_gl_render_job_set_alpha (job, 1.0);
+  gsk_gl_render_job_set_projection_from_rect (job, viewport, NULL);
   gsk_gl_render_job_set_modelview (job, gsk_transform_scale (NULL, scale_factor, scale_factor));
 
   /* Setup our initial clip. If region is NULL then we are drawing the


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