[mutter/gbsneto/more-screencast: 1/7] cogl/scanout: Add new vfunc to blit to framebuffer
- From: Georges Basile Stavracas Neto <gbsneto src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/gbsneto/more-screencast: 1/7] cogl/scanout: Add new vfunc to blit to framebuffer
- Date: Mon, 31 Aug 2020 14:09:32 +0000 (UTC)
commit dd288ab74e37aaba32e8501aaacd80078a1fe971
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date: Fri Aug 28 22:50:39 2020 -0300
cogl/scanout: Add new vfunc to blit to framebuffer
This will be used when screencasting monitors so that if
there's scanout in place, it'll still be possible to blit
it to a PipeWire-owned framebuffer, and stream is.
Add a new 'blit_to_framebuffer' vfunc to CoglScanout, and
implement it in MetaDrmBufferGbm.
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1421
cogl/cogl/cogl-scanout.c | 19 +++++
cogl/cogl/cogl-scanout.h | 14 ++++
src/backends/native/meta-drm-buffer-gbm.c | 118 ++++++++++++++++++++++++++++++
3 files changed, 151 insertions(+)
---
diff --git a/cogl/cogl/cogl-scanout.c b/cogl/cogl/cogl-scanout.c
index 759cd62a4c..fcc14181dd 100644
--- a/cogl/cogl/cogl-scanout.c
+++ b/cogl/cogl/cogl-scanout.c
@@ -25,3 +25,22 @@ static void
cogl_scanout_default_init (CoglScanoutInterface *iface)
{
}
+
+gboolean
+cogl_scanout_blit_to_framebuffer (CoglScanout *scanout,
+ CoglFramebuffer *framebuffer,
+ int x,
+ int y,
+ GError **error)
+{
+ CoglScanoutInterface *iface;
+
+ g_return_val_if_fail (COGL_IS_SCANOUT (scanout), FALSE);
+
+ iface = COGL_SCANOUT_GET_IFACE (scanout);
+
+ if (iface->blit_to_framebuffer)
+ return iface->blit_to_framebuffer (scanout, framebuffer, x, y, error);
+ else
+ return FALSE;
+}
diff --git a/cogl/cogl/cogl-scanout.h b/cogl/cogl/cogl-scanout.h
index 5f2f7e9076..79d053827c 100644
--- a/cogl/cogl/cogl-scanout.h
+++ b/cogl/cogl/cogl-scanout.h
@@ -19,6 +19,7 @@
#define COGL_SCANOUT_H
#include "cogl/cogl-types.h"
+#include "cogl/cogl-framebuffer.h"
#include <glib-object.h>
@@ -30,6 +31,19 @@ G_DECLARE_INTERFACE (CoglScanout, cogl_scanout,
struct _CoglScanoutInterface
{
GTypeInterface parent_iface;
+
+ gboolean (*blit_to_framebuffer) (CoglScanout *scanout,
+ CoglFramebuffer *framebuffer,
+ int x,
+ int y,
+ GError **error);
};
+COGL_EXPORT
+gboolean cogl_scanout_blit_to_framebuffer (CoglScanout *scanout,
+ CoglFramebuffer *framebuffer,
+ int x,
+ int y,
+ GError **error);
+
#endif /* COGL_SCANOUT_H */
diff --git a/src/backends/native/meta-drm-buffer-gbm.c b/src/backends/native/meta-drm-buffer-gbm.c
index 3985e26bc7..f5f51fb716 100644
--- a/src/backends/native/meta-drm-buffer-gbm.c
+++ b/src/backends/native/meta-drm-buffer-gbm.c
@@ -23,6 +23,7 @@
#include "config.h"
+#include "backends/native/meta-cogl-utils.h"
#include "backends/native/meta-drm-buffer-gbm.h"
#include <drm_fourcc.h>
@@ -166,9 +167,126 @@ meta_drm_buffer_gbm_get_fb_id (MetaDrmBuffer *buffer)
return META_DRM_BUFFER_GBM (buffer)->fb_id;
}
+static gboolean
+meta_drm_buffer_gbm_blit_to_framebuffer (CoglScanout *scanout,
+ CoglFramebuffer *framebuffer,
+ int x,
+ int y,
+ GError **error)
+{
+ MetaDrmBufferGbm *buffer_gbm = META_DRM_BUFFER_GBM (scanout);
+ MetaBackend *backend = meta_get_backend ();
+ MetaEgl *egl = meta_backend_get_egl (backend);
+ ClutterBackend *clutter_backend =
+ meta_backend_get_clutter_backend (backend);
+ CoglContext *cogl_context =
+ clutter_backend_get_cogl_context (clutter_backend);
+ CoglDisplay *cogl_display = cogl_context->display;
+ CoglRenderer *cogl_renderer = cogl_display->renderer;
+ CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
+ EGLDisplay egl_display = cogl_renderer_egl->edpy;
+ EGLImageKHR egl_image;
+ CoglPixelFormat cogl_format;
+ CoglEglImageFlags flags;
+ CoglOffscreen *cogl_fbo = NULL;
+ CoglTexture2D *cogl_tex;
+ uint64_t modifiers[1];
+ uint32_t strides[1];
+ uint32_t offsets[1];
+ uint32_t width;
+ uint32_t height;
+ uint32_t drm_format;
+ gboolean result;
+ int dmabuf_fd = -1;
+
+ if (!buffer_gbm->bo)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ "No gbm_bo available");
+ return FALSE;
+ }
+
+ dmabuf_fd = gbm_bo_get_fd (buffer_gbm->bo);
+ if (dmabuf_fd == -1)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS,
+ "Failed to export buffer's DMA fd: %s",
+ g_strerror (errno));
+ return FALSE;
+ }
+
+ drm_format = gbm_bo_get_format (buffer_gbm->bo);
+ result = meta_cogl_pixel_format_from_drm_format (drm_format,
+ &cogl_format,
+ NULL);
+ g_assert (result);
+
+ width = gbm_bo_get_width (buffer_gbm->bo);
+ height = gbm_bo_get_height (buffer_gbm->bo);
+ strides[0] = gbm_bo_get_stride (buffer_gbm->bo);
+ offsets[0] = gbm_bo_get_offset (buffer_gbm->bo, 0);
+ modifiers[0] = gbm_bo_get_modifier (buffer_gbm->bo);
+ egl_image = meta_egl_create_dmabuf_image (egl,
+ egl_display,
+ width,
+ height,
+ drm_format,
+ 1 /* n_planes */,
+ &dmabuf_fd,
+ strides,
+ offsets,
+ modifiers,
+ error);
+ if (egl_image == EGL_NO_IMAGE_KHR)
+ {
+ result = FALSE;
+ goto out;
+ }
+
+ flags = COGL_EGL_IMAGE_FLAG_NO_GET_DATA;
+ cogl_tex = cogl_egl_texture_2d_new_from_image (cogl_context,
+ width,
+ height,
+ cogl_format,
+ egl_image,
+ flags,
+ error);
+
+ meta_egl_destroy_image (egl, egl_display, egl_image, NULL);
+
+ if (!cogl_tex)
+ {
+ result = FALSE;
+ goto out;
+ }
+
+ cogl_fbo = cogl_offscreen_new_with_texture (COGL_TEXTURE (cogl_tex));
+ cogl_object_unref (cogl_tex);
+
+ if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (cogl_fbo), error))
+ {
+ result = FALSE;
+ goto out;
+ }
+
+ result = cogl_blit_framebuffer (COGL_FRAMEBUFFER (cogl_fbo),
+ framebuffer,
+ 0, 0,
+ x, y,
+ width, height,
+ error);
+
+out:
+ cogl_clear_object (&cogl_fbo);
+ close (dmabuf_fd);
+
+ return result;
+}
+
static void
cogl_scanout_iface_init (CoglScanoutInterface *iface)
{
+ iface->blit_to_framebuffer = meta_drm_buffer_gbm_blit_to_framebuffer;
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]