[mutter: 5/13] clutter: Add infrastructure to render ClutterStageViews to offscreen



commit 54dc10f890919b7eab6fc893776fa6cef5aefdc2
Author: Carlos Garnacho <carlosg gnome org>
Date:   Mon Aug 1 02:44:57 2016 +0200

    clutter: Add infrastructure to render ClutterStageViews to offscreen
    
    The offscreen is given through the ::back-buffer property, the ClutterStageView
    will set up the the CoglPipeline used to render it back to the "onscreen"
    framebuffer.
    
    The pipeline can be altered through the setup_pipeline() vfunc, so ClutterStageView
    implementations can alter the default behavior of blitting from offscreen to
    onscreen with no transformations.
    
    All getters of "the framebuffer" that were expecting to get an onscreen have
    been updated to call the right clutter_stage_view_get_onscreen() function.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=745079

 clutter/clutter/clutter-stage-view.c       |  168 +++++++++++++++++++++++++++-
 clutter/clutter/clutter-stage-view.h       |   18 +++
 clutter/clutter/cogl/clutter-stage-cogl.c  |    2 +-
 src/backends/native/meta-renderer-native.c |    8 +-
 src/backends/native/meta-stage-native.c    |    2 +-
 5 files changed, 191 insertions(+), 7 deletions(-)
---
diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c
index 8eb17b8..a8b1d09 100644
--- a/clutter/clutter/clutter-stage-view.c
+++ b/clutter/clutter/clutter-stage-view.c
@@ -27,6 +27,7 @@ enum
 
   PROP_LAYOUT,
   PROP_FRAMEBUFFER,
+  PROP_OFFSCREEN,
 
   PROP_LAST
 };
@@ -37,6 +38,10 @@ typedef struct _ClutterStageViewPrivate
 {
   cairo_rectangle_int_t layout;
   CoglFramebuffer *framebuffer;
+
+  CoglOffscreen *offscreen;
+  CoglPipeline *pipeline;
+
   guint dirty_viewport   : 1;
   guint dirty_projection : 1;
 } ClutterStageViewPrivate;
@@ -59,9 +64,123 @@ clutter_stage_view_get_framebuffer (ClutterStageView *view)
   ClutterStageViewPrivate *priv =
     clutter_stage_view_get_instance_private (view);
 
+  if (priv->offscreen)
+    return priv->offscreen;
+  else
+    return priv->framebuffer;
+}
+
+CoglFramebuffer *
+clutter_stage_view_get_onscreen (ClutterStageView *view)
+{
+  ClutterStageViewPrivate *priv =
+    clutter_stage_view_get_instance_private (view);
+
   return priv->framebuffer;
 }
 
+static void
+clutter_stage_view_ensure_offscreen_blit_pipeline (ClutterStageView *view)
+{
+  ClutterStageViewPrivate *priv =
+    clutter_stage_view_get_instance_private (view);
+  ClutterStageViewClass *view_class =
+    CLUTTER_STAGE_VIEW_GET_CLASS (view);
+
+  g_assert (priv->offscreen != NULL);
+
+  if (priv->pipeline)
+    return;
+
+  priv->pipeline =
+    cogl_pipeline_new (cogl_framebuffer_get_context (priv->offscreen));
+  cogl_pipeline_set_layer_filters (priv->pipeline, 0,
+                                   COGL_PIPELINE_FILTER_NEAREST,
+                                   COGL_PIPELINE_FILTER_NEAREST);
+  cogl_pipeline_set_layer_texture (priv->pipeline, 0,
+                                   cogl_offscreen_get_texture (priv->offscreen));
+  cogl_pipeline_set_layer_wrap_mode (priv->pipeline, 0,
+                                     COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
+
+  if (view_class->setup_offscreen_blit_pipeline)
+    view_class->setup_offscreen_blit_pipeline (view, priv->pipeline);
+}
+
+void
+clutter_stage_view_invalidate_offscreen_blit_pipeline (ClutterStageView *view)
+{
+  ClutterStageViewPrivate *priv =
+    clutter_stage_view_get_instance_private (view);
+
+  g_clear_pointer (&priv->pipeline, cogl_object_unref);
+}
+
+static void
+transform_rect_to_onscreen (ClutterStageView        *view,
+                            const cairo_rectangle_t *rect,
+                            cairo_rectangle_t       *rect_out)
+{
+  float x1, y1, x2, y2;
+
+  x1 = rect->x;
+  y1 = rect->y;
+  clutter_stage_view_transform_to_onscreen (view, &x1, &y1);
+
+  x2 = rect->x + rect->width;
+  y2 = rect->y + rect->height;
+  clutter_stage_view_transform_to_onscreen (view, &x2, &y2);
+
+  *rect_out = (cairo_rectangle_t) {
+    .x = MIN (x1, x2),
+    .y = MIN (y1, y2),
+    .width = ABS (x2 - x1),
+    .height = ABS (y2 - y1)
+  };
+}
+
+void
+clutter_stage_view_blit_offscreen (ClutterStageView            *view,
+                                   const cairo_rectangle_int_t *rect)
+{
+  ClutterStageViewPrivate *priv =
+    clutter_stage_view_get_instance_private (view);
+  cairo_rectangle_t texture_rect, onscreen_rect;
+  CoglMatrix matrix;
+
+  clutter_stage_view_ensure_offscreen_blit_pipeline (view);
+  cogl_framebuffer_push_matrix (priv->framebuffer);
+
+  /* Set transform so 0,0 is on the top left corner and 1,1 on
+   * the bottom right corner.
+   */
+  cogl_matrix_init_identity (&matrix);
+  cogl_matrix_translate (&matrix, -1, 1, 0);
+  cogl_matrix_scale (&matrix, 2, -2, 0);
+  cogl_framebuffer_set_projection_matrix (priv->framebuffer, &matrix);
+
+  texture_rect = (cairo_rectangle_t) {
+    .x = (double) rect->x / cogl_framebuffer_get_width (priv->offscreen),
+    .y = (double) rect->y / cogl_framebuffer_get_height (priv->offscreen),
+    .width = (double) rect->width / cogl_framebuffer_get_width (priv->offscreen),
+    .height = (double) rect->height / cogl_framebuffer_get_height (priv->offscreen)
+  };
+
+  transform_rect_to_onscreen (view, &texture_rect, &onscreen_rect);
+
+  cogl_framebuffer_draw_textured_rectangle (priv->framebuffer,
+                                            priv->pipeline,
+                                            onscreen_rect.x,
+                                            onscreen_rect.y,
+                                            onscreen_rect.x + onscreen_rect.width,
+                                            onscreen_rect.y + onscreen_rect.height,
+                                            texture_rect.x,
+                                            texture_rect.y,
+                                            texture_rect.x + texture_rect.width,
+                                            texture_rect.y + texture_rect.height);
+
+  cogl_framebuffer_pop_matrix (priv->framebuffer);
+}
+
 gboolean
 clutter_stage_view_is_dirty_viewport (ClutterStageView *view)
 {
@@ -100,6 +219,27 @@ clutter_stage_view_set_dirty_projection (ClutterStageView *view,
   priv->dirty_projection = dirty;
 }
 
+void
+clutter_stage_view_transform_to_onscreen (ClutterStageView *view,
+                                          gfloat           *x,
+                                          gfloat           *y)
+{
+  ClutterStageViewClass *view_class = CLUTTER_STAGE_VIEW_GET_CLASS (view);
+  gfloat z = 0, w = 1;
+  CoglMatrix matrix;
+
+  view_class->get_offscreen_transformation_matrix (view, &matrix);
+  cogl_matrix_get_inverse (&matrix, &matrix);
+  cogl_matrix_transform_point (&matrix, x, y, &z, &w);
+}
+
+static void
+clutter_stage_default_get_offscreen_transformation_matrix (ClutterStageView *view,
+                                                           CoglMatrix       *matrix)
+{
+  cogl_matrix_init_identity (matrix);
+}
+
 static void
 clutter_stage_view_get_property (GObject    *object,
                                  guint       prop_id,
@@ -118,6 +258,11 @@ clutter_stage_view_get_property (GObject    *object,
     case PROP_FRAMEBUFFER:
       g_value_set_boxed (value, priv->framebuffer);
       break;
+    case PROP_OFFSCREEN:
+      g_value_set_boxed (value, priv->offscreen);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
 }
 
@@ -141,6 +286,11 @@ clutter_stage_view_set_property (GObject      *object,
     case PROP_FRAMEBUFFER:
       priv->framebuffer = g_value_dup_boxed (value);
       break;
+    case PROP_OFFSCREEN:
+      priv->offscreen = g_value_dup_boxed (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
 }
 
@@ -152,6 +302,10 @@ clutter_stage_view_dispose (GObject *object)
     clutter_stage_view_get_instance_private (view);
 
   g_clear_pointer (&priv->framebuffer, cogl_object_unref);
+  g_clear_pointer (&priv->offscreen, cogl_object_unref);
+  g_clear_pointer (&priv->pipeline, cogl_object_unref);
+
+  G_OBJECT_CLASS (clutter_stage_view_parent_class)->dispose (object);
 }
 
 static void
@@ -169,6 +323,9 @@ clutter_stage_view_class_init (ClutterStageViewClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
+  klass->get_offscreen_transformation_matrix =
+    clutter_stage_default_get_offscreen_transformation_matrix;
+
   object_class->get_property = clutter_stage_view_get_property;
   object_class->set_property = clutter_stage_view_set_property;
   object_class->dispose = clutter_stage_view_dispose;
@@ -184,9 +341,18 @@ clutter_stage_view_class_init (ClutterStageViewClass *klass)
   obj_props[PROP_FRAMEBUFFER] =
     g_param_spec_boxed ("framebuffer",
                         "View framebuffer",
-                        "The framebuffer of the view",
+                        "The front buffer of the view",
+                        COGL_TYPE_HANDLE,
+                        G_PARAM_READWRITE |
+                        G_PARAM_STATIC_STRINGS);
+
+  obj_props[PROP_OFFSCREEN] =
+    g_param_spec_boxed ("offscreen",
+                        "Offscreen buffer",
+                        "Framebuffer used as intermediate buffer",
                         COGL_TYPE_HANDLE,
                         G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT_ONLY |
                         G_PARAM_STATIC_STRINGS);
 
   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
diff --git a/clutter/clutter/clutter-stage-view.h b/clutter/clutter/clutter-stage-view.h
index e9fe3a0..e820e96 100644
--- a/clutter/clutter/clutter-stage-view.h
+++ b/clutter/clutter/clutter-stage-view.h
@@ -33,6 +33,12 @@ G_DECLARE_DERIVABLE_TYPE (ClutterStageView, clutter_stage_view,
 struct _ClutterStageViewClass
 {
   GObjectClass parent_class;
+
+  void (* setup_offscreen_blit_pipeline) (ClutterStageView *view,
+                                          CoglPipeline     *pipeline);
+
+  void (* get_offscreen_transformation_matrix) (ClutterStageView *view,
+                                                CoglMatrix       *matrix);
 };
 
 CLUTTER_AVAILABLE_IN_MUTTER
@@ -41,6 +47,18 @@ void clutter_stage_view_get_layout (ClutterStageView      *view,
 
 CLUTTER_AVAILABLE_IN_MUTTER
 CoglFramebuffer *clutter_stage_view_get_framebuffer (ClutterStageView *view);
+CLUTTER_AVAILABLE_IN_MUTTER
+CoglFramebuffer *clutter_stage_view_get_onscreen (ClutterStageView *view);
+CLUTTER_AVAILABLE_IN_MUTTER
+void             clutter_stage_view_invalidate_offscreen_blit_pipeline (ClutterStageView *view);
+
+CLUTTER_AVAILABLE_IN_MUTTER
+void             clutter_stage_view_transform_to_onscreen (ClutterStageView *view,
+                                                           gfloat           *x,
+                                                           gfloat           *y);
+
+void clutter_stage_view_blit_offscreen (ClutterStageView            *view,
+                                       const cairo_rectangle_int_t *clip);
 
 gboolean clutter_stage_view_is_dirty_viewport (ClutterStageView *view);
 
diff --git a/clutter/clutter/cogl/clutter-stage-cogl.c b/clutter/clutter/cogl/clutter-stage-cogl.c
index 58979f1..6bf2f7b 100644
--- a/clutter/clutter/cogl/clutter-stage-cogl.c
+++ b/clutter/clutter/cogl/clutter-stage-cogl.c
@@ -357,7 +357,7 @@ swap_framebuffer (ClutterStageWindow    *stage_window,
                   cairo_rectangle_int_t *swap_region,
                   gboolean               swap_with_damage)
 {
-  CoglFramebuffer *framebuffer = clutter_stage_view_get_framebuffer (view);
+  CoglFramebuffer *framebuffer = clutter_stage_view_get_onscreen (view);
   int damage[4], ndamage;
 
   damage[0] = swap_region->x;
diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c
index 895f850..bdcfc79 100644
--- a/src/backends/native/meta-renderer-native.c
+++ b/src/backends/native/meta-renderer-native.c
@@ -379,7 +379,7 @@ on_crtc_flipped (GClosure         *closure,
 {
   ClutterStageView *stage_view = CLUTTER_STAGE_VIEW (view);
   CoglFramebuffer *framebuffer =
-    clutter_stage_view_get_framebuffer (stage_view);
+    clutter_stage_view_get_onscreen (stage_view);
   CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
   CoglOnscreenEGL *egl_onscreen =  onscreen->winsys;
   MetaOnscreenNative *onscreen_native = egl_onscreen->platform;
@@ -397,7 +397,7 @@ flip_closure_destroyed (MetaRendererView *view)
 {
   ClutterStageView *stage_view = CLUTTER_STAGE_VIEW (view);
   CoglFramebuffer *framebuffer =
-    clutter_stage_view_get_framebuffer (stage_view);
+    clutter_stage_view_get_onscreen (stage_view);
   CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
   CoglOnscreenEGL *egl_onscreen =  onscreen->winsys;
   MetaOnscreenNative *onscreen_native = egl_onscreen->platform;
@@ -828,7 +828,7 @@ meta_renderer_native_queue_modes_reset (MetaRendererNative *renderer_native)
     {
       ClutterStageView *stage_view = l->data;
       CoglFramebuffer *framebuffer =
-        clutter_stage_view_get_framebuffer (stage_view);
+        clutter_stage_view_get_onscreen (stage_view);
       CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
       CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
       MetaOnscreenNative *onscreen_native = egl_onscreen->platform;
@@ -861,7 +861,7 @@ meta_renderer_native_set_legacy_view_size (MetaRendererNative *renderer_native,
       MetaMonitorManagerKms *monitor_manager_kms =
         META_MONITOR_MANAGER_KMS (monitor_manager);
       CoglFramebuffer *framebuffer =
-        clutter_stage_view_get_framebuffer (stage_view);
+        clutter_stage_view_get_onscreen (stage_view);
       CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
       CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
       MetaOnscreenNative *onscreen_native = egl_onscreen->platform;
diff --git a/src/backends/native/meta-stage-native.c b/src/backends/native/meta-stage-native.c
index 617a707..82ede47 100644
--- a/src/backends/native/meta-stage-native.c
+++ b/src/backends/native/meta-stage-native.c
@@ -127,7 +127,7 @@ ensure_frame_callback (MetaStageNative  *stage_native,
   if (closure)
     return;
 
-  framebuffer = clutter_stage_view_get_framebuffer (stage_view);
+  framebuffer = clutter_stage_view_get_onscreen (stage_view);
   onscreen = COGL_ONSCREEN (framebuffer);
   closure = cogl_onscreen_add_frame_callback (onscreen,
                                               frame_cb,


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