[gtk/wip/chergert/glproto: 546/920] start bringing over some of the modelview bits




commit ebcd0967e2acf14bac43993676615d09ee54b317
Author: Christian Hergert <chergert redhat com>
Date:   Sat Dec 19 15:59:07 2020 -0800

    start bringing over some of the modelview bits

 gsk/next/gskglrenderjob.c | 252 +++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 226 insertions(+), 26 deletions(-)
---
diff --git a/gsk/next/gskglrenderjob.c b/gsk/next/gskglrenderjob.c
index f32477d123..1e6e865e1d 100644
--- a/gsk/next/gskglrenderjob.c
+++ b/gsk/next/gskglrenderjob.c
@@ -1,5 +1,8 @@
 /* gskglrenderjob.c
  *
+ * Copyright 2017 Timm Bäder <mail baedert org>
+ * Copyright 2018 Matthias Clasen <mclasen redhat com>
+ * Copyright 2018 Alexander Larsson <alexl redhat com>
  * Copyright 2020 Christian Hergert <chergert redhat com>
  *
  * This library is free software; you can redistribute it and/or
@@ -35,11 +38,14 @@ struct _GskGLRenderJob
   GskRenderNode     *root;
   cairo_region_t    *region;
   guint              framebuffer;
-  float              scale_factor;
   graphene_rect_t    viewport;
   graphene_matrix_t  projection;
   GArray            *modelview;
   GArray            *clip;
+  float              dx;
+  float              dy;
+  float              scale_x;
+  float              scale_y;
   guint              flip_y : 1;
 };
 
@@ -52,7 +58,10 @@ typedef struct _GskGLRenderClip
 typedef struct _GskGLRenderModelview
 {
   GskTransform *transform;
-  guint         n_repeated;
+  float scale_x;
+  float scale_y;
+  float dx_before;
+  float dy_before;
 } GskGLRenderModelview;
 
 static void
@@ -80,53 +89,215 @@ init_projection_matrix (graphene_matrix_t     *projection,
     graphene_matrix_scale (projection, 1, -1, 1);
 }
 
+static inline GskGLRenderModelview *
+gsk_gl_render_job_get_modelview (GskGLRenderJob *job)
+{
+  return &g_array_index (job->modelview,
+                         GskGLRenderModelview,
+                         job->modelview->len - 1);
+}
+
+static void
+extract_matrix_metadata (GskGLRenderModelview *modelview)
+{
+  float dummy;
+
+  switch (gsk_transform_get_category (modelview->transform))
+    {
+    case GSK_TRANSFORM_CATEGORY_IDENTITY:
+    case GSK_TRANSFORM_CATEGORY_2D_TRANSLATE:
+      modelview->scale_x = 1;
+      modelview->scale_y = 1;
+      break;
+
+    case GSK_TRANSFORM_CATEGORY_2D_AFFINE:
+      gsk_transform_to_affine (modelview->transform,
+                               &modelview->scale_x, &modelview->scale_y,
+                               &dummy, &dummy);
+      break;
+
+    case GSK_TRANSFORM_CATEGORY_UNKNOWN:
+    case GSK_TRANSFORM_CATEGORY_ANY:
+    case GSK_TRANSFORM_CATEGORY_3D:
+    case GSK_TRANSFORM_CATEGORY_2D:
+      {
+        graphene_vec3_t col1;
+        graphene_vec3_t col2;
+        graphene_matrix_t m;
+
+        gsk_transform_to_matrix (modelview->transform, &m);
+
+        /* TODO: 90% sure this is incorrect. But we should never hit this code
+         * path anyway. */
+        graphene_vec3_init (&col1,
+                            graphene_matrix_get_value (&m, 0, 0),
+                            graphene_matrix_get_value (&m, 1, 0),
+                            graphene_matrix_get_value (&m, 2, 0));
+
+        graphene_vec3_init (&col2,
+                            graphene_matrix_get_value (&m, 0, 1),
+                            graphene_matrix_get_value (&m, 1, 1),
+                            graphene_matrix_get_value (&m, 2, 1));
+
+        modelview->scale_x = graphene_vec3_length (&col1);
+        modelview->scale_y = graphene_vec3_length (&col2);
+      }
+      break;
+
+    default:
+      {}
+    }
+}
+
+static void
+gsk_gl_render_job_set_modelview (GskGLRenderJob *job,
+                                 GskTransform   *transform)
+{
+  GskGLRenderModelview *modelview;
+
+  g_assert (job != NULL);
+  g_assert (job->modelview != NULL);
+  g_assert (transform != NULL);
+
+  g_array_set_size (job->modelview, job->modelview->len + 1);
+
+  modelview = &g_array_index (job->modelview,
+                              GskGLRenderModelview,
+                              job->modelview->len - 1);
+
+  modelview->transform = transform;
+
+  modelview->dx_before = job->dx;
+  modelview->dy_before = job->dy;
+
+  extract_matrix_metadata (modelview);
+
+  job->dx = 0;
+  job->dy = 0;
+  job->scale_x = modelview->scale_x;
+  job->scale_y = modelview->scale_y;
+}
+
 static void
 gsk_gl_render_job_push_modelview (GskGLRenderJob *job,
                                   GskTransform   *transform)
 {
-  GskGLRenderModelview modelview = { transform, 0 };
+  GskGLRenderModelview *modelview;
 
   g_assert (job != NULL);
   g_assert (job->modelview != NULL);
-  g_assert (transform != NULL || job->modelview->len > 0);
+  g_assert (transform != NULL);
+
+  g_array_set_size (job->modelview, job->modelview->len + 1);
 
-  if G_LIKELY (job->modelview->len > 0)
+  modelview = &g_array_index (job->modelview,
+                              GskGLRenderModelview,
+                              job->modelview->len - 1);
+
+  if G_LIKELY (job->modelview->len > 1)
     {
       GskGLRenderModelview *last;
+      GskTransform *t = NULL;
 
       last = &g_array_index (job->modelview,
                              GskGLRenderModelview,
-                             job->modelview->len - 1);
+                             job->modelview->len - 2);
 
-      if (transform == NULL || gsk_transform_equal (transform, last->transform))
-        {
-          last->n_repeated++;
-          return;
-        }
+      /* Multiply given matrix with our previews modelview */
+      t = gsk_transform_translate (gsk_transform_ref (last->transform),
+                                   &(graphene_point_t) { job->dx, job->dy});
+      t = gsk_transform_transform (t, transform);
+      modelview->transform = t;
+    }
+  else
+    {
+      modelview->transform = gsk_transform_ref (transform);
     }
 
-  g_assert (transform != NULL);
+  modelview->dx_before = job->dx;
+  modelview->dy_before = job->dy;
 
-  g_array_append_val (job->modelview, modelview);
+  extract_matrix_metadata (modelview);
+
+  job->dx = 0;
+  job->dy = 0;
+  job->scale_x = job->scale_x;
+  job->scale_y = job->scale_y;
 }
 
 static void
 gsk_gl_render_job_pop_modelview (GskGLRenderJob *job)
 {
-  GskGLRenderModelview *modelview;
+  const GskGLRenderModelview *head;
 
   g_assert (job != NULL);
-  g_assert (job->modelview != NULL);
+  g_assert (job->modelview);
   g_assert (job->modelview->len > 0);
 
-  modelview = &g_array_index (job->modelview,
-                              GskGLRenderModelview,
-                              job->modelview->len - 1);
+  head = gsk_gl_render_job_get_modelview (job);
 
-  if (modelview->n_repeated == 0)
-    job->modelview->len--;
-  else
-    modelview->n_repeated--;
+  job->dx = head->dx_before;
+  job->dy = head->dy_before;
+
+  gsk_transform_unref (head->transform);
+
+  job->modelview->len--;
+
+  if (job->modelview->len >= 1)
+    {
+      head = &g_array_index (job->modelview, GskGLRenderModelview, job->modelview->len - 1);
+
+      job->scale_x = head->scale_x;
+      job->scale_y = head->scale_y;
+    }
+}
+
+
+static void
+gsk_gl_render_job_push_clip (GskGLRenderJob       *job,
+                             const GskRoundedRect *rect)
+{
+  GskGLRenderClip clip;
+
+  g_assert (job != NULL);
+  g_assert (job->clip != NULL);
+  g_assert (rect != NULL);
+
+  clip.rect = *rect;
+  clip.is_rectilinear = gsk_rounded_rect_is_rectilinear (rect);
+
+  g_array_append_val (job->clip, clip);
+}
+
+static void
+gsk_gl_render_job_pop_clip (GskGLRenderJob *job)
+{
+  g_assert (job != NULL);
+  g_assert (job->clip != NULL);
+  g_assert (job->clip->len > 0);
+
+  job->clip->len--;
+}
+
+static void
+gsk_gl_render_job_transform_bounds (GskGLRenderJob        *job,
+                                    const graphene_rect_t *rect,
+                                    graphene_rect_t       *out_rect)
+{
+  GskGLRenderModelview *modelview;
+  graphene_rect_t r;
+
+  g_assert (job != NULL);
+  g_assert (rect != NULL);
+
+  r.origin.x = rect->origin.x + job->dx;
+  r.origin.y = rect->origin.y + job->dy;
+  r.size.width = rect->size.width;
+  r.size.height = rect->size.width;
+
+  modelview = gsk_gl_render_job_get_modelview (job);
+
+  gsk_transform_transform_bounds (modelview->transform, &r, out_rect);
 }
 
 GskGLRenderJob *
@@ -138,6 +309,8 @@ gsk_gl_render_job_new (GskNextDriver         *driver,
                        guint                  framebuffer,
                        gboolean               flip_y)
 {
+  const graphene_rect_t *clip_rect = viewport;
+  graphene_rect_t transformed_extents;
   GskGLRenderJob *job;
 
   g_return_val_if_fail (GSK_IS_NEXT_DRIVER (driver), NULL);
@@ -149,17 +322,44 @@ gsk_gl_render_job_new (GskNextDriver         *driver,
   job->driver = g_object_ref (driver);
   job->root = gsk_render_node_ref (root);
   job->clip = g_array_new (FALSE, FALSE, sizeof (GskGLRenderClip));
+  job->modelview = g_array_new (FALSE, FALSE, sizeof (GskGLRenderModelview));
   job->framebuffer = framebuffer;
-  job->scale_factor = scale_factor;
+  job->scale_x = scale_factor;
+  job->scale_y = scale_factor;
   job->viewport = *viewport;
   job->region = region ? cairo_region_copy (region) : NULL;
+  job->dx = 0;
+  job->dy = 0;
   job->flip_y = !!flip_y;
 
   init_projection_matrix (&job->projection, viewport, flip_y);
 
-  job->modelview = g_array_new (FALSE, FALSE, sizeof (GskGLRenderModelview));
-  g_array_set_clear_func (job->modelview, gsk_gl_render_modelview_clear);
-  gsk_gl_render_job_push_modelview (job, gsk_transform_scale (NULL, scale_factor, scale_factor));
+  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
+   * whole viewport. Otherwise, we need to convert the region to a
+   * bounding box and clip based on that.
+   */
+
+  if (region != NULL)
+    {
+      cairo_rectangle_int_t extents;
+
+      cairo_region_get_extents (region, &extents);
+      gsk_gl_render_job_transform_bounds (job,
+                                          &GRAPHENE_RECT_INIT (extents.x,
+                                                               extents.y,
+                                                               extents.width,
+                                                               extents.height),
+                                          &transformed_extents);
+      clip_rect = &transformed_extents;
+    }
+
+  gsk_gl_render_job_push_clip (job,
+                               &GSK_ROUNDED_RECT_INIT (clip_rect->origin.x,
+                                                       clip_rect->origin.y,
+                                                       clip_rect->size.width,
+                                                       clip_rect->size.height));
 
   return job;
 }


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