From 7df22b338bba09e40d14608d78d82c719c691def Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Mon, 18 Sep 2023 14:38:23 -0400 Subject: [PATCH] GstShmAllocator: New shared memory allocator This makes Wayland's allocator public. It is generally useful to have a shared memory allocator that can create memfd on Linux. Sponsored-by: Netflix Inc. Part-of: --- .../ext/gtk/gstgtkwaylandsink.c | 8 +- .../ext/wayland/gstwaylandsink.c | 8 +- .../gst-libs/gst/wayland/gstwldisplay.c | 2 +- .../gst-libs/gst/wayland/gstwlshmallocator.c | 131 -------------- .../gst-libs/gst/wayland/gstwlshmallocator.h | 21 --- .../gst-libs/gst/wayland/gstwlwindow.c | 2 +- .../gst-libs/gst/allocators/allocators.h | 1 + .../gst-libs/gst/allocators/gstshmallocator.c | 162 ++++++++++++++++++ .../gst-libs/gst/allocators/gstshmallocator.h | 39 +++++ .../gst-libs/gst/allocators/meson.build | 25 ++- 10 files changed, 235 insertions(+), 164 deletions(-) create mode 100644 subprojects/gst-plugins-base/gst-libs/gst/allocators/gstshmallocator.c create mode 100644 subprojects/gst-plugins-base/gst-libs/gst/allocators/gstshmallocator.h diff --git a/subprojects/gst-plugins-bad/ext/gtk/gstgtkwaylandsink.c b/subprojects/gst-plugins-bad/ext/gtk/gstgtkwaylandsink.c index 8ee077e7e2..cc51b0328b 100644 --- a/subprojects/gst-plugins-bad/ext/gtk/gstgtkwaylandsink.c +++ b/subprojects/gst-plugins-bad/ext/gtk/gstgtkwaylandsink.c @@ -889,7 +889,7 @@ gst_gtk_wayland_activate_shm_pool (GstGtkWaylandSink * self) gboolean is_shm = FALSE; if (gst_buffer_pool_config_get_allocator (config, &alloc, NULL) && alloc) - is_shm = GST_IS_WL_SHM_ALLOCATOR (alloc); + is_shm = GST_IS_SHM_ALLOCATOR (alloc); gst_structure_free (config); @@ -897,7 +897,7 @@ gst_gtk_wayland_activate_shm_pool (GstGtkWaylandSink * self) return TRUE; } - alloc = gst_wl_shm_allocator_get (); + alloc = gst_shm_allocator_get (); gst_gtk_wayland_update_pool (self, alloc); gst_object_unref (alloc); @@ -1059,7 +1059,7 @@ gst_gtk_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) gst_buffer_pool_config_set_params (config, caps, priv->video_info.size, 2, 0); gst_buffer_pool_config_set_allocator (config, - gst_wl_shm_allocator_get (), NULL); + gst_shm_allocator_get (), NULL); gst_buffer_pool_set_config (pool, config); } @@ -1067,7 +1067,7 @@ gst_gtk_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) if (pool) g_object_unref (pool); - alloc = gst_wl_shm_allocator_get (); + alloc = gst_shm_allocator_get (); gst_query_add_allocation_param (query, alloc, NULL); gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); g_object_unref (alloc); diff --git a/subprojects/gst-plugins-bad/ext/wayland/gstwaylandsink.c b/subprojects/gst-plugins-bad/ext/wayland/gstwaylandsink.c index bdeca63a15..a9c6f670ea 100644 --- a/subprojects/gst-plugins-bad/ext/wayland/gstwaylandsink.c +++ b/subprojects/gst-plugins-bad/ext/wayland/gstwaylandsink.c @@ -637,7 +637,7 @@ gst_wayland_activate_shm_pool (GstWaylandSink * self) gboolean is_shm = FALSE; if (gst_buffer_pool_config_get_allocator (config, &alloc, NULL) && alloc) - is_shm = GST_IS_WL_SHM_ALLOCATOR (alloc); + is_shm = GST_IS_SHM_ALLOCATOR (alloc); gst_structure_free (config); @@ -645,7 +645,7 @@ gst_wayland_activate_shm_pool (GstWaylandSink * self) return TRUE; } - alloc = gst_wl_shm_allocator_get (); + alloc = gst_shm_allocator_get (); gst_wayland_update_pool (self, alloc); gst_object_unref (alloc); @@ -779,7 +779,7 @@ gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) gst_buffer_pool_config_set_params (config, caps, self->video_info.size, 2, 0); gst_buffer_pool_config_set_allocator (config, - gst_wl_shm_allocator_get (), NULL); + gst_shm_allocator_get (), NULL); gst_buffer_pool_set_config (pool, config); } @@ -787,7 +787,7 @@ gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) if (pool) g_object_unref (pool); - alloc = gst_wl_shm_allocator_get (); + alloc = gst_shm_allocator_get (); gst_query_add_allocation_param (query, alloc, NULL); gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); g_object_unref (alloc); diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwldisplay.c b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwldisplay.c index f0f6d0c206..1550f11bd8 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwldisplay.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwldisplay.c @@ -93,7 +93,7 @@ gst_wl_display_init (GstWlDisplay * self) g_mutex_init (&priv->buffers_mutex); gst_wl_linux_dmabuf_init_once (); - gst_wl_shm_allocator_init_once (); + gst_shm_allocator_init_once (); gst_wl_videoformat_init_once (); } diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlshmallocator.c b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlshmallocator.c index ce623d6134..fb2fdb9a5e 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlshmallocator.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlshmallocator.c @@ -26,137 +26,6 @@ #include "gstwlshmallocator.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define GST_CAT_DEFAULT gst_wl_shm_debug -GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); - -G_DEFINE_TYPE_WITH_CODE (GstWlShmAllocator, gst_wl_shm_allocator, - GST_TYPE_FD_ALLOCATOR, - GST_DEBUG_CATEGORY_INIT (gst_wl_shm_debug, "wlshm", 0, "wlshm library"); - ); - -static GstMemory * -gst_wl_shm_allocator_alloc (GstAllocator * allocator, gsize size, - GstAllocationParams * params) -{ - GstWlShmAllocator *self = GST_WL_SHM_ALLOCATOR (allocator); - char filename[1024]; - static int init = 0; - int fd; - GstMemory *mem; - GstMapInfo info; - - /* TODO: make use of the allocation params, if necessary */ - -#ifdef HAVE_MEMFD_CREATE - fd = memfd_create ("gst-wayland-shm", MFD_CLOEXEC | MFD_ALLOW_SEALING); - if (fd >= 0) { - /* We can add this seal before calling posix_fallocate(), as - * the file is currently zero-sized anyway. - * - * There is also no need to check for the return value, we - * couldn't do anything with it anyway. - */ - fcntl (fd, F_ADD_SEALS, F_SEAL_SHRINK); - } else -#endif - { - /* allocate shm pool */ - snprintf (filename, 1024, "%s/%s-%d-%s", g_get_user_runtime_dir (), - "wayland-shm", init++, "XXXXXX"); - - fd = g_mkstemp (filename); - if (fd < 0) { - GST_ERROR_OBJECT (self, "opening temp file %s failed: %s", filename, - strerror (errno)); - return NULL; - } - - unlink (filename); - } - - if (ftruncate (fd, size) < 0) { - GST_ERROR_OBJECT (self, "ftruncate failed: %s", strerror (errno)); - close (fd); - return NULL; - } - - mem = gst_fd_allocator_alloc (allocator, fd, size, - GST_FD_MEMORY_FLAG_KEEP_MAPPED); - if (G_UNLIKELY (!mem)) { - GST_ERROR_OBJECT (self, "GstFdMemory allocation failed"); - close (fd); - return NULL; - } - - /* we need to map the memory in order to unlink the file without losing it */ - if (!gst_memory_map (mem, &info, GST_MAP_READWRITE)) { - GST_ERROR_OBJECT (self, "GstFdMemory map failed"); - close (fd); - return NULL; - } - - /* unmap will not really munmap(), we just - * need it to release the miniobject lock */ - gst_memory_unmap (mem, &info); - - return mem; -} - -static void -gst_wl_shm_allocator_class_init (GstWlShmAllocatorClass * klass) -{ - GstAllocatorClass *alloc_class = (GstAllocatorClass *) klass; - - alloc_class->alloc = GST_DEBUG_FUNCPTR (gst_wl_shm_allocator_alloc); -} - -static void -gst_wl_shm_allocator_init (GstWlShmAllocator * self) -{ - GstAllocator *alloc = GST_ALLOCATOR_CAST (self); - - alloc->mem_type = GST_ALLOCATOR_WL_SHM; - - GST_OBJECT_FLAG_UNSET (self, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC); -} - -void -gst_wl_shm_allocator_init_once (void) -{ - static gsize _init = 0; - - if (g_once_init_enter (&_init)) { - GstAllocator *alloc; - - alloc = g_object_new (GST_TYPE_WL_SHM_ALLOCATOR, NULL); - gst_object_ref_sink (alloc); - gst_allocator_register (GST_ALLOCATOR_WL_SHM, alloc); - - g_once_init_leave (&_init, 1); - } -} - -GstAllocator * -gst_wl_shm_allocator_get (void) -{ - return gst_allocator_find (GST_ALLOCATOR_WL_SHM); -} - -gboolean -gst_is_wl_shm_memory (GstMemory * mem) -{ - return gst_memory_is_type (mem, GST_ALLOCATOR_WL_SHM); -} static gboolean gst_wl_shm_validate_video_info (const GstVideoInfo * vinfo) diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlshmallocator.h b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlshmallocator.h index edf60a9fcc..b57b85c04a 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlshmallocator.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlshmallocator.h @@ -29,27 +29,6 @@ G_BEGIN_DECLS -#define GST_TYPE_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get_type ()) - -GST_WL_API -G_DECLARE_FINAL_TYPE (GstWlShmAllocator, gst_wl_shm_allocator, GST, WL_SHM_ALLOCATOR, GstFdAllocator); - -#define GST_ALLOCATOR_WL_SHM "wl_shm" - -struct _GstWlShmAllocator -{ - GstFdAllocator parent_instance; -}; - -GST_WL_API -void gst_wl_shm_allocator_init_once (void); - -GST_WL_API -GstAllocator * gst_wl_shm_allocator_get (void); - -GST_WL_API -gboolean gst_is_wl_shm_memory (GstMemory * mem); - GST_WL_API struct wl_buffer * gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem, GstWlDisplay * display, const GstVideoInfo * info); diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlwindow.c b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlwindow.c index 699d25ef33..08f53fe4e0 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlwindow.c +++ b/subprojects/gst-plugins-bad/gst-libs/gst/wayland/gstwlwindow.c @@ -580,7 +580,7 @@ gst_wl_window_update_borders (GstWlWindow * self) /* draw the area_subsurface */ gst_video_info_set_format (&info, format, width, height); - alloc = gst_wl_shm_allocator_get (); + alloc = gst_shm_allocator_get (); buf = gst_buffer_new_allocate (alloc, info.size, NULL); gst_buffer_memset (buf, 0, 0, info.size); diff --git a/subprojects/gst-plugins-base/gst-libs/gst/allocators/allocators.h b/subprojects/gst-plugins-base/gst-libs/gst/allocators/allocators.h index 65e7e81f57..48676e36c5 100644 --- a/subprojects/gst-plugins-base/gst-libs/gst/allocators/allocators.h +++ b/subprojects/gst-plugins-base/gst-libs/gst/allocators/allocators.h @@ -28,6 +28,7 @@ #include #include #include +#include #endif /* __GST_ALLOCATORS_H__ */ diff --git a/subprojects/gst-plugins-base/gst-libs/gst/allocators/gstshmallocator.c b/subprojects/gst-plugins-base/gst-libs/gst/allocators/gstshmallocator.c new file mode 100644 index 0000000000..9d2fa1e63c --- /dev/null +++ b/subprojects/gst-plugins-base/gst-libs/gst/allocators/gstshmallocator.c @@ -0,0 +1,162 @@ +/* GStreamer shared memory allocator + * + * Copyright (C) 2012 Intel Corporation + * Copyright (C) 2012 Sreerenj Balachandran + * Copyright (C) 2023 Netflix Inc. + * Author: Xavier Claessens + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstshmallocator.h" + +#ifdef HAVE_MMAP +#include +#include +#include +#include +#endif + +struct _GstShmAllocator +{ + GstFdAllocator parent; +}; + +#define GST_CAT_DEFAULT gst_shm_debug +GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); + +G_DEFINE_TYPE_WITH_CODE (GstShmAllocator, gst_shm_allocator, + GST_TYPE_FD_ALLOCATOR, + GST_DEBUG_CATEGORY_INIT (gst_shm_debug, "shmallocator", 0, + "Shared memory allocator"); + ); + +static GstMemory * +gst_shm_allocator_alloc (GstAllocator * allocator, gsize size, + GstAllocationParams * params) +{ +#ifdef HAVE_MMAP + GstShmAllocator *self = GST_SHM_ALLOCATOR (allocator); + int fd; + GstMemory *mem; + GstMapInfo info; + + /* TODO: make use of the allocation params, if necessary */ + +#ifdef HAVE_MEMFD_CREATE + fd = memfd_create ("gst-shm", MFD_CLOEXEC | MFD_ALLOW_SEALING); + if (fd >= 0) { + /* We can add this seal before calling posix_fallocate(), as + * the file is currently zero-sized anyway. + * + * There is also no need to check for the return value, we + * couldn't do anything with it anyway. + */ + fcntl (fd, F_ADD_SEALS, F_SEAL_SHRINK); + } else +#endif + { + char filename[1024]; + static int init = 0; + + /* allocate shm pool */ + snprintf (filename, 1024, "%s/%s-%d-%s", g_get_user_runtime_dir (), + "gst-shm", init++, "XXXXXX"); + + fd = g_mkstemp (filename); + if (fd < 0) { + GST_ERROR_OBJECT (self, "opening temp file %s failed: %s", filename, + strerror (errno)); + return NULL; + } + + unlink (filename); + } + + if (ftruncate (fd, size) < 0) { + GST_ERROR_OBJECT (self, "ftruncate failed: %s", strerror (errno)); + close (fd); + return NULL; + } + + mem = gst_fd_allocator_alloc (allocator, fd, size, + GST_FD_MEMORY_FLAG_KEEP_MAPPED); + if (G_UNLIKELY (!mem)) { + GST_ERROR_OBJECT (self, "GstFdMemory allocation failed"); + close (fd); + return NULL; + } + + /* we need to map the memory in order to unlink the file without losing it */ + if (!gst_memory_map (mem, &info, GST_MAP_READWRITE)) { + GST_ERROR_OBJECT (self, "GstFdMemory map failed"); + close (fd); + return NULL; + } + + /* unmap will not really munmap(), we just + * need it to release the miniobject lock */ + gst_memory_unmap (mem, &info); + + return mem; +#else + return NULL; +#endif +} + +static void +gst_shm_allocator_class_init (GstShmAllocatorClass * klass) +{ + GstAllocatorClass *alloc_class = (GstAllocatorClass *) klass; + + alloc_class->alloc = GST_DEBUG_FUNCPTR (gst_shm_allocator_alloc); +} + +static void +gst_shm_allocator_init (GstShmAllocator * self) +{ + GstAllocator *alloc = GST_ALLOCATOR_CAST (self); + + alloc->mem_type = GST_ALLOCATOR_SHM; + + GST_OBJECT_FLAG_SET (self, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC); +} + +void +gst_shm_allocator_init_once (void) +{ + static gsize _init = 0; + + if (g_once_init_enter (&_init)) { + GstAllocator *alloc; + + alloc = (GstAllocator *) g_object_new (GST_TYPE_SHM_ALLOCATOR, NULL); + gst_object_ref_sink (alloc); + gst_allocator_register (GST_ALLOCATOR_SHM, alloc); + + g_once_init_leave (&_init, 1); + } +} + +GstAllocator * +gst_shm_allocator_get (void) +{ + return gst_allocator_find (GST_ALLOCATOR_SHM); +} diff --git a/subprojects/gst-plugins-base/gst-libs/gst/allocators/gstshmallocator.h b/subprojects/gst-plugins-base/gst-libs/gst/allocators/gstshmallocator.h new file mode 100644 index 0000000000..97ab832934 --- /dev/null +++ b/subprojects/gst-plugins-base/gst-libs/gst/allocators/gstshmallocator.h @@ -0,0 +1,39 @@ +/* GStreamer shared memory allocator + * + * Copyright (C) 2012 Intel Corporation + * Copyright (C) 2012 Sreerenj Balachandran + * Copyright (C) 2023 Netflix Inc. + * Author: Xavier Claessens + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define GST_ALLOCATOR_SHM "shm" + +#define GST_TYPE_SHM_ALLOCATOR gst_shm_allocator_get_type () +GST_ALLOCATORS_API +G_DECLARE_FINAL_TYPE (GstShmAllocator, gst_shm_allocator, GST, SHM_ALLOCATOR, GstFdAllocator) + +GST_ALLOCATORS_API void gst_shm_allocator_init_once (void); +GST_ALLOCATORS_API GstAllocator* gst_shm_allocator_get (void); + +G_END_DECLS diff --git a/subprojects/gst-plugins-base/gst-libs/gst/allocators/meson.build b/subprojects/gst-plugins-base/gst-libs/gst/allocators/meson.build index f9984b7b53..95860ae575 100644 --- a/subprojects/gst-plugins-base/gst-libs/gst/allocators/meson.build +++ b/subprojects/gst-plugins-base/gst-libs/gst/allocators/meson.build @@ -5,13 +5,34 @@ gst_allocators_headers = files([ 'gstphysmemory.h', 'gstdmabuf.h', 'gstdrmdumb.h', + 'gstshmallocator.h', ]) install_headers(gst_allocators_headers, subdir : 'gstreamer-1.0/gst/allocators/') -gst_allocators_sources = files([ 'gstdrmdumb.c', 'gstdmabuf.c', 'gstfdmemory.c', 'gstphysmemory.c']) +gst_allocators_sources = files([ + 'gstdrmdumb.c', + 'gstdmabuf.c', + 'gstfdmemory.c', + 'gstphysmemory.c', + 'gstshmallocator.c', +]) + +gst_allocators_cargs = [ + gst_plugins_base_args, + '-DBUILDING_GST_ALLOCATORS', + '-DG_LOG_DOMAIN="GStreamer-Allocators"', +] + +if cc.has_function('memfd_create') + gst_allocators_cargs += [ + '-DHAVE_MEMFD_CREATE', + '-D_GNU_SOURCE', + ] +endif + gstallocators = library('gstallocators-@0@'.format(api_version), gst_allocators_sources, - c_args : gst_plugins_base_args + ['-DBUILDING_GST_ALLOCATORS', '-DG_LOG_DOMAIN="GStreamer-Allocators"'], + c_args : gst_allocators_cargs, include_directories: [configinc, libsinc], version : libversion, soversion : soversion,