[mutter/wip/garnacho/wayland-emulated-output-transform: 19/27] clutter: Add infrastructure to render ClutterStageViews to offscreen



commit 6302ffe8ac59ab4f41de74449d1c5b188c4a3126
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.
    
    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]