[mutter/wip/garnacho/wayland-emulated-output-transform: 4/13] clutter: Add infrastructure to render ClutterStageViews to an intermediate texture



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

    clutter: Add infrastructure to render ClutterStageViews to an intermediate texture
    
    The texture is given through the ::back-texture property, the ClutterStageView
    sets up the CoglOffscreen necessary to render into it, and the CoglPipeline used
    to render it back to the framebuffer.
    
    The pipeline can be altered through the setup_pipeline() vfunc, so ClutterStageView
    implementations can alter the default behavior of rendering the texture onto the
    framebuffer with no transformations.

 clutter/clutter/clutter-stage-view.c |  151 +++++++++++++++++++++++++++++++++-
 clutter/clutter/clutter-stage-view.h |   18 ++++
 2 files changed, 168 insertions(+), 1 deletions(-)
---
diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c
index 87d6102..25a231a 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_BACK_TEXTURE,
 
   PROP_LAST
 };
@@ -37,6 +38,11 @@ typedef struct _ClutterStageViewPrivate
 {
   cairo_rectangle_int_t layout;
   CoglFramebuffer *framebuffer;
+
+  CoglFramebuffer *back_buffer;
+  CoglTexture *back_texture;
+  CoglPipeline *pipeline;
+
   guint dirty_viewport   : 1;
   guint dirty_projection : 1;
 } ClutterStageViewPrivate;
@@ -62,6 +68,111 @@ clutter_stage_view_get_framebuffer (ClutterStageView *view)
   return priv->framebuffer;
 }
 
+static void
+clutter_stage_view_ensure_pipeline (ClutterStageView *view)
+{
+  ClutterStageViewPrivate *priv =
+    clutter_stage_view_get_instance_private (view);
+  ClutterStageViewClass *view_class =
+    CLUTTER_STAGE_VIEW_GET_CLASS (view);
+
+  g_clear_pointer (&priv->pipeline, cogl_object_unref);
+
+  if (!priv->back_texture)
+    return;
+
+  priv->pipeline =
+    cogl_pipeline_new (cogl_framebuffer_get_context (priv->back_buffer));
+  cogl_pipeline_set_layer_filters (priv->pipeline, 0,
+                                   COGL_PIPELINE_FILTER_NEAREST,
+                                   COGL_PIPELINE_FILTER_NEAREST);
+  cogl_pipeline_set_layer_texture (priv->pipeline, 0, priv->back_texture);
+  cogl_pipeline_set_layer_wrap_mode (priv->pipeline, 0,
+                                     COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
+
+  if (view_class->setup_pipeline)
+    view_class->setup_pipeline (view, priv->pipeline);
+}
+
+void
+clutter_stage_view_invalidate_pipeline (ClutterStageView *view)
+{
+  ClutterStageViewPrivate *priv =
+    clutter_stage_view_get_instance_private (view);
+
+  g_clear_pointer (&priv->pipeline, cogl_object_unref);
+}
+
+void
+clutter_stage_view_set_back_texture (ClutterStageView *view,
+                                    CoglTexture2D    *texture)
+{
+  ClutterStageViewPrivate *priv =
+    clutter_stage_view_get_instance_private (view);
+  GError *error = NULL;
+
+  g_clear_pointer (&priv->pipeline, cogl_object_unref);
+  g_clear_pointer (&priv->back_buffer, cogl_object_unref);
+  g_clear_pointer (&priv->back_texture, cogl_object_unref);
+
+  priv->back_texture = texture;
+
+  if (priv->back_texture)
+    {
+      cogl_object_ref (priv->back_texture);
+      priv->back_buffer = cogl_offscreen_new_with_texture (priv->back_texture);
+
+      if (priv->back_buffer &&
+          !cogl_framebuffer_allocate (priv->back_buffer, &error))
+        {
+          g_critical ("Failed to allocate back buffer: %s\n", error->message);
+          g_error_free (error);
+          g_clear_pointer (&priv->back_texture, cogl_object_unref);
+          g_clear_pointer (&priv->back_buffer, cogl_object_unref);
+        }
+    }
+
+  clutter_stage_view_invalidate_pipeline (view);
+}
+
+CoglTexture2D *
+clutter_stage_view_get_back_texture (ClutterStageView *view)
+{
+  ClutterStageViewPrivate *priv =
+    clutter_stage_view_get_instance_private (view);
+
+  return priv->back_texture;
+}
+
+CoglFramebuffer *
+clutter_stage_view_get_back_buffer (ClutterStageView *view)
+{
+  ClutterStageViewPrivate *priv =
+    clutter_stage_view_get_instance_private (view);
+
+  if (!priv->back_buffer)
+    {
+      /* There's no back buffer, use the framebuffer directly */
+      return priv->framebuffer;
+    }
+
+  return priv->back_buffer;
+}
+
+void
+clutter_stage_view_blit_back_buffer (ClutterStageView            *view,
+                                     const cairo_rectangle_int_t *rect)
+{
+  ClutterStageViewPrivate *priv =
+    clutter_stage_view_get_instance_private (view);
+
+  if (!priv->back_buffer)
+    return;
+
+  clutter_stage_view_ensure_pipeline (view);
+  CLUTTER_STAGE_VIEW_GET_CLASS (view)->blit_back_buffer (view, rect);
+}
+
 gboolean
 clutter_stage_view_is_dirty_viewport (ClutterStageView *view)
 {
@@ -101,6 +212,19 @@ clutter_stage_view_set_dirty_projection (ClutterStageView *view,
 }
 
 static void
+clutter_stage_view_default_blit_back_buffer (ClutterStageView            *view,
+                                             const cairo_rectangle_int_t *rect)
+{
+  ClutterStageViewPrivate *priv =
+    clutter_stage_view_get_instance_private (view);
+
+  /* FIXME: Use rect */
+  cogl_framebuffer_draw_rectangle (priv->framebuffer,
+                                   priv->pipeline,
+                                   -1, 1, 1, -1);
+}
+
+static void
 clutter_stage_view_get_property (GObject    *object,
                                  guint       prop_id,
                                  GValue     *value,
@@ -118,6 +242,11 @@ clutter_stage_view_get_property (GObject    *object,
     case PROP_FRAMEBUFFER:
       g_value_set_boxed (value, priv->framebuffer);
       break;
+    case PROP_BACK_TEXTURE:
+      g_value_set_boxed (value, priv->back_texture);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
 }
 
@@ -141,6 +270,11 @@ clutter_stage_view_set_property (GObject      *object,
     case PROP_FRAMEBUFFER:
       priv->framebuffer = g_value_dup_boxed (value);
       break;
+    case PROP_BACK_TEXTURE:
+      clutter_stage_view_set_back_texture (view, g_value_get_boxed (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
 }
 
@@ -152,6 +286,11 @@ 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->back_buffer, cogl_object_unref);
+  g_clear_pointer (&priv->back_texture, cogl_object_unref);
+  g_clear_pointer (&priv->pipeline, cogl_object_unref);
+
+  G_OBJECT_CLASS (clutter_stage_view_parent_class)->dispose (object);
 }
 
 static void
@@ -164,6 +303,8 @@ clutter_stage_view_class_init (ClutterStageViewClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
+  klass->blit_back_buffer = clutter_stage_view_default_blit_back_buffer;
+
   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;
@@ -179,7 +320,15 @@ 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_BACK_TEXTURE] =
+    g_param_spec_boxed ("back-texture",
+                        "Back texture",
+                        "Texture used as back buffer",
                         COGL_TYPE_HANDLE,
                         G_PARAM_READWRITE |
                         G_PARAM_STATIC_STRINGS);
diff --git a/clutter/clutter/clutter-stage-view.h b/clutter/clutter/clutter-stage-view.h
index e9fe3a0..2fdc7e1 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_pipeline) (ClutterStageView *view,
+                           CoglPipeline     *pipeline);
+
+  void (* blit_back_buffer) (ClutterStageView            *view,
+                             const cairo_rectangle_int_t *rect);
 };
 
 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_back_buffer (ClutterStageView *view);
+CLUTTER_AVAILABLE_IN_MUTTER
+CoglTexture2D   *clutter_stage_view_get_back_texture (ClutterStageView *view);
+CLUTTER_AVAILABLE_IN_MUTTER
+void             clutter_stage_view_set_back_texture (ClutterStageView *view,
+                                                      CoglTexture2D    *texture);
+CLUTTER_AVAILABLE_IN_MUTTER
+void             clutter_stage_view_invalidate_pipeline (ClutterStageView *view);
+
+void clutter_stage_view_blit_back_buffer (ClutterStageView            *view,
+                                          const cairo_rectangle_int_t *rect);
 
 gboolean clutter_stage_view_is_dirty_viewport (ClutterStageView *view);
 


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