[mutter/gnome-3-36] clutter/stage: Add API to paint to a custom target



commit c7ad9b33c2b5e3f755109ce39edf9824e53b6de9
Author: Jonas Ådahl <jadahl gmail com>
Date:   Mon Apr 20 22:29:50 2020 +0200

    clutter/stage: Add API to paint to a custom target
    
    Either onto a framebuffer, or into a CPU memory buffer. The latter will
    use an former API and then copy the result to CPU memory. The former
    allocates an offscreen framebuffer, sets up the relevant framebuffer
    matrices and paints part of the stage defined by the passed rectangle.
    
    This will be used by a RecordArea screen cast API. The former to paint
    directly onto PipeWire handled dma-buf framebuffers, and the latter for
    PipeWire handled shared memory buffers.
    
    https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1222

 clutter/clutter/clutter-mutter.h | 18 ++++++++
 clutter/clutter/clutter-stage.c  | 94 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 112 insertions(+)
---
diff --git a/clutter/clutter/clutter-mutter.h b/clutter/clutter/clutter-mutter.h
index 2e3af31f1..d61746d5f 100644
--- a/clutter/clutter/clutter-mutter.h
+++ b/clutter/clutter/clutter-mutter.h
@@ -30,6 +30,7 @@
 #include "clutter-input-device-private.h"
 #include "clutter-input-pointer-a11y-private.h"
 #include "clutter-macros.h"
+#include "clutter-paint-context-private.h"
 #include "clutter-private.h"
 #include "clutter-stage-private.h"
 #include "clutter-stage-view.h"
@@ -48,6 +49,23 @@ void clutter_stage_capture_into (ClutterStage          *stage,
                                  cairo_rectangle_int_t *rect,
                                  uint8_t               *data);
 
+CLUTTER_EXPORT
+void clutter_stage_paint_to_framebuffer (ClutterStage                *stage,
+                                         CoglFramebuffer             *framebuffer,
+                                         const cairo_rectangle_int_t *rect,
+                                         float                        scale,
+                                         ClutterPaintFlag             paint_flags);
+
+CLUTTER_EXPORT
+gboolean clutter_stage_paint_to_buffer (ClutterStage                 *stage,
+                                        const cairo_rectangle_int_t  *rect,
+                                        float                         scale,
+                                        uint8_t                      *data,
+                                        int                           stride,
+                                        CoglPixelFormat               format,
+                                        ClutterPaintFlag              paint_flags,
+                                        GError                      **error);
+
 CLUTTER_EXPORT
 void clutter_stage_freeze_updates (ClutterStage *stage);
 
diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c
index a123eae73..92f3dd759 100644
--- a/clutter/clutter/clutter-stage.c
+++ b/clutter/clutter/clutter-stage.c
@@ -4473,6 +4473,100 @@ clutter_stage_get_capture_final_size (ClutterStage          *stage,
   return TRUE;
 }
 
+/**
+ * clutter_stage_paint_to_framebuffer: (skip)
+ */
+void
+clutter_stage_paint_to_framebuffer (ClutterStage                *stage,
+                                    CoglFramebuffer             *framebuffer,
+                                    const cairo_rectangle_int_t *rect,
+                                    float                        scale,
+                                    ClutterPaintFlag             paint_flags)
+{
+  ClutterStagePrivate *priv = stage->priv;
+  ClutterPaintContext *paint_context;
+  cairo_region_t *redraw_clip;
+
+  redraw_clip = cairo_region_create_rectangle (rect);
+  paint_context = clutter_paint_context_new_for_framebuffer (framebuffer);
+  cairo_region_destroy (redraw_clip);
+
+  cogl_framebuffer_push_matrix (framebuffer);
+  cogl_framebuffer_set_projection_matrix (framebuffer, &priv->projection);
+  cogl_framebuffer_set_viewport (framebuffer,
+                                 -(rect->x * scale),
+                                 -(rect->y * scale),
+                                 priv->viewport[2] * scale,
+                                 priv->viewport[3] * scale);
+  clutter_actor_paint (CLUTTER_ACTOR (stage), paint_context);
+  cogl_framebuffer_pop_matrix (framebuffer);
+
+  clutter_paint_context_destroy (paint_context);
+}
+
+/**
+ * clutter_stage_paint_to_buffer: (skip)
+ */
+gboolean
+clutter_stage_paint_to_buffer (ClutterStage                 *stage,
+                               const cairo_rectangle_int_t  *rect,
+                               float                         scale,
+                               uint8_t                      *data,
+                               int                           stride,
+                               CoglPixelFormat               format,
+                               ClutterPaintFlag              paint_flags,
+                               GError                      **error)
+{
+  ClutterBackend *clutter_backend = clutter_get_default_backend ();
+  CoglContext *cogl_context =
+    clutter_backend_get_cogl_context (clutter_backend);
+  int texture_width, texture_height;
+  CoglTexture2D *texture;
+  CoglOffscreen *offscreen;
+  CoglFramebuffer *framebuffer;
+  CoglBitmap *bitmap;
+
+  texture_width = (int) ceilf (rect->width * scale);
+  texture_height = (int) ceilf (rect->height * scale);
+  texture = cogl_texture_2d_new_with_size (cogl_context,
+                                           texture_width,
+                                           texture_height);
+  if (!texture)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "Failed to create %dx%d texture",
+                   texture_width, texture_height);
+      return FALSE;
+    }
+
+  offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (texture));
+  framebuffer = COGL_FRAMEBUFFER (offscreen);
+
+  cogl_object_unref (texture);
+
+  if (!cogl_framebuffer_allocate (framebuffer, error))
+    return FALSE;
+
+  clutter_stage_paint_to_framebuffer (stage, framebuffer,
+                                      rect, scale, paint_flags);
+
+  bitmap = cogl_bitmap_new_for_data (cogl_context,
+                                     texture_width, texture_height,
+                                     format,
+                                     stride,
+                                     data);
+
+  cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
+                                            0, 0,
+                                            COGL_READ_PIXELS_COLOR_BUFFER,
+                                            bitmap);
+
+  cogl_object_unref (bitmap);
+  cogl_object_unref (framebuffer);
+
+  return TRUE;
+}
+
 static void
 capture_view_into (ClutterStage          *stage,
                    gboolean               paint,


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