[gnome-remote-desktop] rdp: Adapt to RDP buffer pool



commit 61b9740d9e417871174c879a446f63595dea97d2
Author: Pascal Nowack <Pascal Nowack gmx de>
Date:   Mon Jan 3 13:41:58 2022 +0100

    rdp: Adapt to RDP buffer pool
    
    Instead of allocating new buffers over and over again, adapt to the
    previously implemented RDP buffer pool.

 src/grd-rdp-buffer-pool.c     |   2 +-
 src/grd-rdp-buffer.c          |  11 +++-
 src/grd-rdp-buffer.h          |   6 +-
 src/grd-rdp-pipewire-stream.c | 128 ++++++++++++++++++++++++++----------------
 src/grd-rdp-surface.c         |  20 ++++++-
 src/grd-rdp-surface.h         |   4 ++
 src/grd-session-rdp.c         |  45 +++++++++++----
 src/grd-session-rdp.h         |   5 +-
 8 files changed, 154 insertions(+), 67 deletions(-)
---
diff --git a/src/grd-rdp-buffer-pool.c b/src/grd-rdp-buffer-pool.c
index d59de088..379e91c6 100644
--- a/src/grd-rdp-buffer-pool.c
+++ b/src/grd-rdp-buffer-pool.c
@@ -53,7 +53,7 @@ add_buffer_to_pool (GrdRdpBufferPool *buffer_pool)
   GrdRdpBuffer *buffer;
   BufferInfo *buffer_info;
 
-  buffer = grd_rdp_buffer_new ();
+  buffer = grd_rdp_buffer_new (buffer_pool);
   buffer_info = g_new0 (BufferInfo, 1);
 
   if (buffer_pool->has_buffer_size)
diff --git a/src/grd-rdp-buffer.c b/src/grd-rdp-buffer.c
index 9d1ffca5..eb33a310 100644
--- a/src/grd-rdp-buffer.c
+++ b/src/grd-rdp-buffer.c
@@ -23,12 +23,15 @@
 
 #include <gio/gio.h>
 
+#include "grd-rdp-buffer-pool.h"
+
 GrdRdpBuffer *
-grd_rdp_buffer_new (void)
+grd_rdp_buffer_new (GrdRdpBufferPool *buffer_pool)
 {
   GrdRdpBuffer *buffer;
 
   buffer = g_new0 (GrdRdpBuffer, 1);
+  buffer->buffer_pool = buffer_pool;
 
   return buffer;
 }
@@ -46,6 +49,12 @@ grd_rdp_buffer_free (GrdRdpBuffer *buffer)
   g_free (buffer);
 }
 
+void
+grd_rdp_buffer_release (GrdRdpBuffer *buffer)
+{
+  grd_rdp_buffer_pool_release_buffer (buffer->buffer_pool, buffer);
+}
+
 void
 grd_rdp_buffer_resize (GrdRdpBuffer *buffer,
                        uint32_t      width,
diff --git a/src/grd-rdp-buffer.h b/src/grd-rdp-buffer.h
index c0e3dee4..aeefa25d 100644
--- a/src/grd-rdp-buffer.h
+++ b/src/grd-rdp-buffer.h
@@ -26,16 +26,20 @@
 
 struct _GrdRdpBuffer
 {
+  GrdRdpBufferPool *buffer_pool;
+
   uint32_t width;
   uint32_t height;
 
   uint8_t *local_data;
 };
 
-GrdRdpBuffer *grd_rdp_buffer_new (void);
+GrdRdpBuffer *grd_rdp_buffer_new (GrdRdpBufferPool *buffer_pool);
 
 void grd_rdp_buffer_free (GrdRdpBuffer *buffer);
 
+void grd_rdp_buffer_release (GrdRdpBuffer *buffer);
+
 void grd_rdp_buffer_resize (GrdRdpBuffer *buffer,
                             uint32_t      width,
                             uint32_t      height,
diff --git a/src/grd-rdp-pipewire-stream.c b/src/grd-rdp-pipewire-stream.c
index da8991a2..92810230 100644
--- a/src/grd-rdp-pipewire-stream.c
+++ b/src/grd-rdp-pipewire-stream.c
@@ -34,7 +34,11 @@
 #include "grd-egl-thread.h"
 #include "grd-pipewire-utils.h"
 #include "grd-rdp-buffer.h"
+#include "grd-rdp-buffer-pool.h"
 #include "grd-rdp-surface.h"
+#include "grd-utils.h"
+
+#define DEFAULT_BUFFER_POOL_SIZE 5
 
 enum
 {
@@ -84,6 +88,8 @@ struct _GrdRdpPipeWireStream
 
   struct spa_hook pipewire_core_listener;
 
+  GrdRdpBufferPool *buffer_pool;
+
   GSource *render_source;
   GMutex frame_mutex;
   GrdRdpFrame *pending_frame;
@@ -134,7 +140,7 @@ grd_rdp_frame_unref (GrdRdpFrame *frame)
 {
   if (g_atomic_ref_count_dec (&frame->refcount))
     {
-      g_clear_pointer (&frame->buffer, grd_rdp_buffer_free);
+      g_clear_pointer (&frame->buffer, grd_rdp_buffer_release);
       g_free (frame->pointer_bitmap);
       g_free (frame);
     }
@@ -148,16 +154,22 @@ do_render (gpointer user_data)
 
   g_mutex_lock (&stream->frame_mutex);
   frame = g_steal_pointer (&stream->pending_frame);
+
+  if (frame && frame->buffer)
+    {
+      g_mutex_lock (&stream->rdp_surface->surface_mutex);
+      g_assert (!stream->rdp_surface->new_framebuffer);
+
+      stream->rdp_surface->new_framebuffer = g_steal_pointer (&frame->buffer);
+      g_mutex_unlock (&stream->rdp_surface->surface_mutex);
+    }
   g_mutex_unlock (&stream->frame_mutex);
 
   if (!frame)
     return G_SOURCE_CONTINUE;
 
-  if (frame->buffer)
-    {
-      grd_session_rdp_take_buffer (stream->session_rdp, stream->rdp_surface,
-                                   g_steal_pointer (&frame->buffer));
-    }
+  grd_session_rdp_maybe_encode_new_frame (stream->session_rdp,
+                                          stream->rdp_surface);
 
   if (frame->pointer_bitmap)
     {
@@ -291,6 +303,45 @@ on_stream_state_changed (void                 *user_data,
     }
 }
 
+static void
+on_sync_complete (gboolean success,
+                  gpointer user_data)
+{
+  GrdSyncPoint *sync_point = user_data;
+
+  grd_sync_point_complete (sync_point, success);
+}
+
+static void
+sync_egl_thread (GrdEglThread *egl_thread)
+{
+  GrdSyncPoint sync_point = {};
+
+  grd_sync_point_init (&sync_point);
+  grd_egl_thread_sync (egl_thread, on_sync_complete, &sync_point, NULL);
+
+  grd_sync_point_wait_for_completion (&sync_point);
+  grd_sync_point_clear (&sync_point);
+}
+
+static void
+release_all_buffers (GrdRdpPipeWireStream *stream)
+{
+  g_mutex_lock (&stream->frame_mutex);
+  if (stream->pending_frame)
+    g_clear_pointer (&stream->pending_frame->buffer, grd_rdp_buffer_release);
+  g_mutex_unlock (&stream->frame_mutex);
+
+  g_mutex_lock (&stream->rdp_surface->surface_mutex);
+  g_clear_pointer (&stream->rdp_surface->new_framebuffer,
+                   grd_rdp_buffer_release);
+  g_clear_pointer (&stream->rdp_surface->last_framebuffer,
+                   grd_rdp_buffer_release);
+  g_clear_pointer (&stream->rdp_surface->pending_framebuffer,
+                   grd_rdp_buffer_release);
+  g_mutex_unlock (&stream->rdp_surface->surface_mutex);
+}
+
 static void
 on_stream_param_changed (void                 *user_data,
                          uint32_t              id,
@@ -299,6 +350,10 @@ on_stream_param_changed (void                 *user_data,
   GrdRdpPipeWireStream *stream = GRD_RDP_PIPEWIRE_STREAM (user_data);
   GrdSession *session = GRD_SESSION (stream->session_rdp);
   GrdContext *context = grd_session_get_context (session);
+  GrdEglThread *egl_thread = grd_context_get_egl_thread (context);
+  uint32_t width;
+  uint32_t height;
+  uint32_t stride;
   uint8_t params_buffer[1024];
   struct spa_pod_builder pod_builder;
   enum spa_data_type allowed_buffer_types;
@@ -308,11 +363,20 @@ on_stream_param_changed (void                 *user_data,
     return;
 
   spa_format_video_raw_parse (format, &stream->spa_format);
+  height = stream->spa_format.size.height;
+  width = stream->spa_format.size.width;
+  stride = grd_session_rdp_get_stride_for_width (stream->session_rdp, width);
+
+  if (egl_thread)
+    sync_egl_thread (egl_thread);
+  release_all_buffers (stream);
+
+  grd_rdp_buffer_pool_resize_buffers (stream->buffer_pool, width, height, stride);
 
   pod_builder = SPA_POD_BUILDER_INIT (params_buffer, sizeof (params_buffer));
 
   allowed_buffer_types = 1 << SPA_DATA_MemFd;
-  if (grd_context_get_egl_thread (context))
+  if (egl_thread)
     allowed_buffer_types |= 1 << SPA_DATA_DmaBuf;
 
   params[0] = spa_pod_builder_add_object (
@@ -458,8 +522,7 @@ process_buffer (GrdRdpPipeWireStream     *stream,
         }
       src_data = SPA_MEMBER (map, buffer->datas[0].mapoffset, uint8_t);
 
-      frame->buffer = grd_rdp_buffer_new ();
-      grd_rdp_buffer_resize (frame->buffer, width, height, dst_stride);
+      frame->buffer = grd_rdp_buffer_pool_acquire (stream->buffer_pool);
 
       copy_frame_data (frame,
                        src_data,
@@ -486,8 +549,7 @@ process_buffer (GrdRdpPipeWireStream     *stream,
       unsigned int i;
       uint8_t *dst_data;
 
-      frame->buffer = grd_rdp_buffer_new ();
-      grd_rdp_buffer_resize (frame->buffer, width, height, dst_stride);
+      frame->buffer = grd_rdp_buffer_pool_acquire (stream->buffer_pool);
 
       row_width = dst_stride / bpp;
 
@@ -526,8 +588,7 @@ process_buffer (GrdRdpPipeWireStream     *stream,
 
       src_data = buffer->datas[0].data;
 
-      frame->buffer = grd_rdp_buffer_new ();
-      grd_rdp_buffer_resize (frame->buffer, width, height, dst_stride);
+      frame->buffer = grd_rdp_buffer_pool_acquire (stream->buffer_pool);
 
       copy_frame_data (frame,
                        src_data,
@@ -836,26 +897,9 @@ grd_rdp_pipewire_stream_new (GrdSessionRdp  *session_rdp,
   if (!connect_to_stream (stream, rdp_surface->refresh_rate, error))
     return NULL;
 
-  return g_steal_pointer (&stream);
-}
-
-typedef struct
-{
-  GMutex mutex;
-  GCond cond;
-  gboolean done;
-} SyncData;
+  stream->buffer_pool = grd_rdp_buffer_pool_new (DEFAULT_BUFFER_POOL_SIZE);
 
-static void
-on_sync_done (gboolean success,
-              gpointer user_data)
-{
-  SyncData *sync_data = user_data;
-
-  g_mutex_lock (&sync_data->mutex);
-  sync_data->done = TRUE;
-  g_cond_signal (&sync_data->cond);
-  g_mutex_unlock (&sync_data->mutex);
+  return g_steal_pointer (&stream);
 }
 
 static void
@@ -873,22 +917,7 @@ grd_rdp_pipewire_stream_finalize (GObject *object)
 
   egl_thread = grd_context_get_egl_thread (context);
   if (egl_thread && stream->pipewire_stream)
-    {
-      SyncData sync_data = {};
-
-      g_mutex_init (&sync_data.mutex);
-      g_cond_init (&sync_data.cond);
-
-      grd_egl_thread_sync (egl_thread, on_sync_done, &sync_data, NULL);
-
-      g_mutex_lock (&sync_data.mutex);
-      while (!sync_data.done)
-        g_cond_wait (&sync_data.cond, &sync_data.mutex);
-      g_mutex_unlock (&sync_data.mutex);
-
-      g_cond_clear (&sync_data.cond);
-      g_mutex_clear (&sync_data.mutex);
-    }
+    sync_egl_thread (egl_thread);
 
   /*
    * We can't clear stream->pipewire_stream before destroying it, as the data
@@ -913,6 +942,9 @@ grd_rdp_pipewire_stream_finalize (GObject *object)
 
   g_clear_pointer (&stream->pending_frame, grd_rdp_frame_unref);
 
+  release_all_buffers (stream);
+  g_clear_object (&stream->buffer_pool);
+
   g_mutex_clear (&stream->frame_mutex);
 
   G_OBJECT_CLASS (grd_rdp_pipewire_stream_parent_class)->finalize (object);
diff --git a/src/grd-rdp-surface.c b/src/grd-rdp-surface.c
index b9f59c7b..ba78c26a 100644
--- a/src/grd-rdp-surface.c
+++ b/src/grd-rdp-surface.c
@@ -23,12 +23,28 @@
 
 #include "grd-rdp-buffer.h"
 
+GrdRdpSurface *
+grd_rdp_surface_new (void)
+{
+  GrdRdpSurface *rdp_surface;
+
+  rdp_surface = g_malloc0 (sizeof (GrdRdpSurface));
+
+  g_mutex_init (&rdp_surface->surface_mutex);
+
+  return rdp_surface;
+}
+
 void
 grd_rdp_surface_free (GrdRdpSurface *rdp_surface)
 {
   g_assert (!rdp_surface->gfx_surface);
-  g_clear_pointer (&rdp_surface->last_framebuffer, grd_rdp_buffer_free);
-  g_clear_pointer (&rdp_surface->pending_framebuffer, grd_rdp_buffer_free);
+
+  g_assert (!rdp_surface->new_framebuffer);
+  g_assert (!rdp_surface->last_framebuffer);
+  g_assert (!rdp_surface->pending_framebuffer);
+
+  g_mutex_clear (&rdp_surface->surface_mutex);
 
   g_free (rdp_surface);
 }
diff --git a/src/grd-rdp-surface.h b/src/grd-rdp-surface.h
index 3d1d18b6..9f20a641 100644
--- a/src/grd-rdp-surface.h
+++ b/src/grd-rdp-surface.h
@@ -32,6 +32,8 @@ struct _GrdRdpSurface
   uint16_t width;
   uint16_t height;
 
+  GMutex surface_mutex;
+  GrdRdpBuffer *new_framebuffer;
   GrdRdpBuffer *last_framebuffer;
   GrdRdpBuffer *pending_framebuffer;
 
@@ -42,6 +44,8 @@ struct _GrdRdpSurface
   gboolean encoding_suspended;
 };
 
+GrdRdpSurface *grd_rdp_surface_new (void);
+
 void grd_rdp_surface_free (GrdRdpSurface *rdp_surface);
 
 #endif /* GRD_RDP_SURFACE_H */
diff --git a/src/grd-session-rdp.c b/src/grd-session-rdp.c
index f3016cf5..027b43f7 100644
--- a/src/grd-session-rdp.c
+++ b/src/grd-session-rdp.c
@@ -246,17 +246,17 @@ maybe_resize_graphics_output_buffer (GrdSessionRdp *session_rdp,
   set_rdp_peer_flag (session_rdp, RDP_PEER_ALL_SURFACES_INVALID);
 }
 
-void
-grd_session_rdp_take_buffer (GrdSessionRdp *session_rdp,
-                             GrdRdpSurface *rdp_surface,
-                             GrdRdpBuffer  *buffer)
+static void
+take_or_encode_frame (GrdSessionRdp *session_rdp,
+                      GrdRdpSurface *rdp_surface,
+                      GrdRdpBuffer  *buffer)
 {
   uint16_t width = buffer->width;
   uint16_t height = buffer->height;
   uint32_t stride;
   cairo_region_t *region;
 
-  g_clear_pointer (&rdp_surface->pending_framebuffer, grd_rdp_buffer_free);
+  g_clear_pointer (&rdp_surface->pending_framebuffer, grd_rdp_buffer_release);
   maybe_resize_graphics_output_buffer (session_rdp, width, height);
 
   if (is_rdp_peer_flag_set (session_rdp, RDP_PEER_ALL_SURFACES_INVALID))
@@ -276,7 +276,7 @@ grd_session_rdp_take_buffer (GrdSessionRdp *session_rdp,
     }
 
   if (!rdp_surface->valid)
-    g_clear_pointer (&rdp_surface->last_framebuffer, grd_rdp_buffer_free);
+    g_clear_pointer (&rdp_surface->last_framebuffer, grd_rdp_buffer_release);
 
   if (is_rdp_peer_flag_set (session_rdp, RDP_PEER_ACTIVATED) &&
       is_rdp_peer_flag_set (session_rdp, RDP_PEER_OUTPUT_ENABLED) &&
@@ -299,7 +299,7 @@ grd_session_rdp_take_buffer (GrdSessionRdp *session_rdp,
       if (!cairo_region_is_empty (region))
         rdp_peer_refresh_region (session_rdp, rdp_surface, region, buffer);
 
-      g_clear_pointer (&rdp_surface->last_framebuffer, grd_rdp_buffer_free);
+      g_clear_pointer (&rdp_surface->last_framebuffer, grd_rdp_buffer_release);
       rdp_surface->last_framebuffer = buffer;
 
       cairo_region_destroy (region);
@@ -310,6 +310,22 @@ grd_session_rdp_take_buffer (GrdSessionRdp *session_rdp,
     }
 }
 
+void
+grd_session_rdp_maybe_encode_new_frame (GrdSessionRdp *session_rdp,
+                                        GrdRdpSurface *rdp_surface)
+{
+  g_mutex_lock (&rdp_surface->surface_mutex);
+  if (!rdp_surface->new_framebuffer)
+    {
+      g_mutex_unlock (&rdp_surface->surface_mutex);
+      return;
+    }
+
+  take_or_encode_frame (session_rdp, rdp_surface,
+                        g_steal_pointer (&rdp_surface->new_framebuffer));
+  g_mutex_unlock (&rdp_surface->surface_mutex);
+}
+
 void
 grd_session_rdp_maybe_encode_pending_frame (GrdSessionRdp *session_rdp,
                                             GrdRdpSurface *rdp_surface)
@@ -321,11 +337,18 @@ grd_session_rdp_maybe_encode_pending_frame (GrdSessionRdp *session_rdp,
       is_rdp_peer_flag_set (session_rdp, RDP_PEER_PENDING_GFX_INIT))
     return;
 
+  g_mutex_lock (&rdp_surface->surface_mutex);
+  g_assert (!rdp_surface->new_framebuffer);
+
   if (!rdp_surface->pending_framebuffer)
-    return;
+    {
+      g_mutex_unlock (&rdp_surface->surface_mutex);
+      return;
+    }
 
-  grd_session_rdp_take_buffer (session_rdp, rdp_surface,
-                               g_steal_pointer (&rdp_surface->pending_framebuffer));
+  take_or_encode_frame (session_rdp, rdp_surface,
+                        g_steal_pointer (&rdp_surface->pending_framebuffer));
+  g_mutex_unlock (&rdp_surface->surface_mutex);
 }
 
 static gboolean
@@ -1631,7 +1654,7 @@ rdp_peer_post_connect (freerdp_peer *peer)
 
   rdp_settings->PointerCacheSize = MIN (rdp_settings->PointerCacheSize, 100);
 
-  session_rdp->rdp_surface = g_malloc0 (sizeof (GrdRdpSurface));
+  session_rdp->rdp_surface = grd_rdp_surface_new ();
   session_rdp->rdp_surface->refresh_rate = rdp_settings->SupportGraphicsPipeline ? 60
                                                                                  : 30;
 
diff --git a/src/grd-session-rdp.h b/src/grd-session-rdp.h
index 2572d329..48deceb6 100644
--- a/src/grd-session-rdp.h
+++ b/src/grd-session-rdp.h
@@ -49,9 +49,8 @@ void grd_session_rdp_notify_graphics_pipeline_ready (GrdSessionRdp *session_rdp)
 int grd_session_rdp_get_stride_for_width (GrdSessionRdp *session_rdp,
                                           int            width);
 
-void grd_session_rdp_take_buffer (GrdSessionRdp *session_rdp,
-                                  GrdRdpSurface *rdp_surface,
-                                  GrdRdpBuffer  *buffer);
+void grd_session_rdp_maybe_encode_new_frame (GrdSessionRdp *session_rdp,
+                                             GrdRdpSurface *rdp_surface);
 
 void grd_session_rdp_maybe_encode_pending_frame (GrdSessionRdp *session_rdp,
                                                  GrdRdpSurface *rdp_surface);


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