[gnome-remote-desktop] rdp: Allocate and register GL resources for each RDP buffer



commit 46a9167621139f28e0f7838681ce01822c1fc67d
Author: Pascal Nowack <Pascal Nowack gmx de>
Date:   Tue Jan 4 12:54:02 2022 +0100

    rdp: Allocate and register GL resources for each RDP buffer
    
    When uploading or mapping frame data on the GPU later, the buffer for
    the frame on the GPU is usually supposed to be already allocated and
    registered at the external API, which makes use of the mapped buffer.
    
    To ensure this, allocate and register the GL resources, when the size
    of the framebuffers in the pipewire stream is known.
    When the pipewire stream is resized, these framebuffers are resized
    too.
    This is relatively easy, as all framebuffers are tracked.
    
    When a new buffer is added to the buffer pool, due to all buffers of
    the buffer pool already being used, do not allocate any GL resources.
    
    This has two reasons:
    First, the EGL thread is about to take care of the framebuffer anyway,
    so adding additional synchronization for the allocation can impact the
    performance.
    The additional synchronization is still required, as the allocation can
    fail, which is a situation, that needs to be handled.
    
    Second, the submission of the allocation task and synchronization would
    happen on the PipeWire realtime thread, instead of the main thread,
    which can lead to a deadlock, where the buffer pool mutex won't be
    unlocked any more, since the EGL thread would wait on the PipeWire
    realtime thread to unlock it and the PipeWire realtime thread would
    wait on the EGL thread to finish the allocation task.

 src/grd-rdp-buffer-pool.c     | 111 ++++++++++++++++++++++++++++--------
 src/grd-rdp-buffer-pool.h     |  14 +++--
 src/grd-rdp-buffer.c          | 129 ++++++++++++++++++++++++++++++++++++++++--
 src/grd-rdp-buffer.h          |  24 ++++++--
 src/grd-rdp-pipewire-stream.c |  49 +++++++++++++---
 src/grd-rdp-pipewire-stream.h |  11 ++--
 src/grd-rdp-surface.c         |  20 ++++++-
 src/grd-rdp-surface.h         |   6 +-
 src/grd-session-rdp.c         |  15 ++++-
 9 files changed, 322 insertions(+), 57 deletions(-)
---
diff --git a/src/grd-rdp-buffer-pool.c b/src/grd-rdp-buffer-pool.c
index 379e91c6..42597d82 100644
--- a/src/grd-rdp-buffer-pool.c
+++ b/src/grd-rdp-buffer-pool.c
@@ -21,7 +21,9 @@
 
 #include "grd-rdp-buffer-pool.h"
 
+#include "grd-egl-thread.h"
 #include "grd-rdp-buffer.h"
+#include "grd-utils.h"
 
 typedef struct _BufferInfo
 {
@@ -32,6 +34,11 @@ struct _GrdRdpBufferPool
 {
   GObject parent;
 
+  GrdEglThread *egl_thread;
+  GrdHwAccelNvidia *hwaccel_nvidia;
+
+  CUstream cuda_stream;
+
   gboolean has_buffer_size;
   uint32_t buffer_width;
   uint32_t buffer_height;
@@ -47,37 +54,47 @@ struct _GrdRdpBufferPool
 
 G_DEFINE_TYPE (GrdRdpBufferPool, grd_rdp_buffer_pool, G_TYPE_OBJECT)
 
-static void
-add_buffer_to_pool (GrdRdpBufferPool *buffer_pool)
+static gboolean
+add_buffer_to_pool (GrdRdpBufferPool *buffer_pool,
+                    gboolean          preallocate_on_gpu)
 {
   GrdRdpBuffer *buffer;
   BufferInfo *buffer_info;
 
-  buffer = grd_rdp_buffer_new (buffer_pool);
-  buffer_info = g_new0 (BufferInfo, 1);
-
-  if (buffer_pool->has_buffer_size)
+  buffer = grd_rdp_buffer_new (buffer_pool,
+                               buffer_pool->egl_thread,
+                               buffer_pool->hwaccel_nvidia,
+                               buffer_pool->cuda_stream);
+  if (buffer_pool->has_buffer_size &&
+      !grd_rdp_buffer_resize (buffer,
+                              buffer_pool->buffer_width,
+                              buffer_pool->buffer_height,
+                              buffer_pool->buffer_stride,
+                              preallocate_on_gpu))
     {
-      grd_rdp_buffer_resize (buffer,
-                             buffer_pool->buffer_width,
-                             buffer_pool->buffer_height,
-                             buffer_pool->buffer_stride);
+      grd_rdp_buffer_free (buffer);
+      return FALSE;
     }
 
+  buffer_info = g_new0 (BufferInfo, 1);
+
   g_hash_table_insert (buffer_pool->buffer_table, buffer, buffer_info);
+
+  return TRUE;
 }
 
-void
+gboolean
 grd_rdp_buffer_pool_resize_buffers (GrdRdpBufferPool *buffer_pool,
                                     uint32_t          buffer_width,
                                     uint32_t          buffer_height,
                                     uint32_t          buffer_stride)
 {
+  g_autoptr (GMutexLocker) locker = NULL;
   GHashTableIter iter;
   GrdRdpBuffer *buffer;
   BufferInfo *buffer_info;
 
-  g_mutex_lock (&buffer_pool->pool_mutex);
+  locker = g_mutex_locker_new (&buffer_pool->pool_mutex);
   g_assert (buffer_pool->buffers_taken == 0);
 
   buffer_pool->buffer_width = buffer_width;
@@ -90,21 +107,26 @@ grd_rdp_buffer_pool_resize_buffers (GrdRdpBufferPool *buffer_pool,
                                         (gpointer *) &buffer_info))
     {
       g_assert (!buffer_info->buffer_taken);
-      grd_rdp_buffer_resize (buffer, buffer_width, buffer_height, buffer_stride);
+      if (!grd_rdp_buffer_resize (buffer, buffer_width, buffer_height,
+                                 buffer_stride, TRUE))
+        return FALSE;
     }
-  g_mutex_unlock (&buffer_pool->pool_mutex);
+
+  return TRUE;
 }
 
 GrdRdpBuffer *
 grd_rdp_buffer_pool_acquire (GrdRdpBufferPool *buffer_pool)
 {
+  g_autoptr (GMutexLocker) locker = NULL;
   GHashTableIter iter;
   GrdRdpBuffer *buffer;
   BufferInfo *buffer_info;
 
-  g_mutex_lock (&buffer_pool->pool_mutex);
-  if (g_hash_table_size (buffer_pool->buffer_table) <= buffer_pool->buffers_taken)
-    add_buffer_to_pool (buffer_pool);
+  locker = g_mutex_locker_new (&buffer_pool->pool_mutex);
+  if (g_hash_table_size (buffer_pool->buffer_table) <= buffer_pool->buffers_taken &&
+      !add_buffer_to_pool (buffer_pool, FALSE))
+    return NULL;
 
   g_hash_table_iter_init (&iter, buffer_pool->buffer_table);
   while (g_hash_table_iter_next (&iter, (gpointer *) &buffer,
@@ -116,7 +138,6 @@ grd_rdp_buffer_pool_acquire (GrdRdpBufferPool *buffer_pool)
 
   buffer_info->buffer_taken = TRUE;
   ++buffer_pool->buffers_taken;
-  g_mutex_unlock (&buffer_pool->pool_mutex);
 
   return buffer;
 }
@@ -196,21 +217,32 @@ static GSourceFuncs resize_pool_source_funcs =
   .dispatch = resize_pool_source_dispatch,
 };
 
-static void
+static gboolean
 fill_buffer_pool (GrdRdpBufferPool *buffer_pool)
 {
   uint32_t minimum_size = buffer_pool->minimum_pool_size;
 
   while (g_hash_table_size (buffer_pool->buffer_table) < minimum_size)
-    add_buffer_to_pool (buffer_pool);
+    {
+      if (!add_buffer_to_pool (buffer_pool, TRUE))
+        return FALSE;
+    }
+
+  return TRUE;
 }
 
 GrdRdpBufferPool *
-grd_rdp_buffer_pool_new (uint32_t minimum_size)
+grd_rdp_buffer_pool_new (GrdEglThread     *egl_thread,
+                         GrdHwAccelNvidia *hwaccel_nvidia,
+                         CUstream          cuda_stream,
+                         uint32_t          minimum_size)
 {
-  GrdRdpBufferPool *buffer_pool;
+  g_autoptr (GrdRdpBufferPool) buffer_pool = NULL;
 
   buffer_pool = g_object_new (GRD_TYPE_RDP_BUFFER_POOL, NULL);
+  buffer_pool->egl_thread = egl_thread;
+  buffer_pool->hwaccel_nvidia = hwaccel_nvidia;
+  buffer_pool->cuda_stream = cuda_stream;
   buffer_pool->minimum_pool_size = minimum_size;
 
   buffer_pool->resize_pool_source = g_source_new (&resize_pool_source_funcs,
@@ -220,9 +252,32 @@ grd_rdp_buffer_pool_new (uint32_t minimum_size)
   g_source_set_ready_time (buffer_pool->resize_pool_source, -1);
   g_source_attach (buffer_pool->resize_pool_source, NULL);
 
-  fill_buffer_pool (buffer_pool);
+  if (!fill_buffer_pool (buffer_pool))
+    return NULL;
+
+  return g_steal_pointer (&buffer_pool);
+}
+
+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 (GrdRdpBufferPool *buffer_pool)
+{
+  GrdSyncPoint sync_point = {};
 
-  return buffer_pool;
+  grd_sync_point_init (&sync_point);
+  grd_egl_thread_sync (buffer_pool->egl_thread, on_sync_complete,
+                       &sync_point, NULL);
+
+  grd_sync_point_wait_for_completion (&sync_point);
+  grd_sync_point_clear (&sync_point);
 }
 
 static void
@@ -250,6 +305,14 @@ grd_rdp_buffer_pool_finalize (GObject *object)
 
   g_clear_pointer (&buffer_pool->buffer_table, g_hash_table_unref);
 
+  /*
+   * All buffers need to be destroyed, before the pool is freed to avoid use
+   * after free by the EGL thread, when the RDP server is shut down and with it
+   * the GrdHwAccelNvidia instance
+   */
+  if (buffer_pool->egl_thread)
+    sync_egl_thread (buffer_pool);
+
   G_OBJECT_CLASS (grd_rdp_buffer_pool_parent_class)->finalize (object);
 }
 
diff --git a/src/grd-rdp-buffer-pool.h b/src/grd-rdp-buffer-pool.h
index 121c86f5..afe55bd9 100644
--- a/src/grd-rdp-buffer-pool.h
+++ b/src/grd-rdp-buffer-pool.h
@@ -20,6 +20,7 @@
 #ifndef GRD_RDP_BUFFER_POOL_H
 #define GRD_RDP_BUFFER_POOL_H
 
+#include <ffnvcodec/dynlink_cuda.h>
 #include <glib-object.h>
 #include <stdint.h>
 
@@ -29,12 +30,15 @@
 G_DECLARE_FINAL_TYPE (GrdRdpBufferPool, grd_rdp_buffer_pool,
                       GRD, RDP_BUFFER_POOL, GObject)
 
-GrdRdpBufferPool *grd_rdp_buffer_pool_new (uint32_t minimum_size);
+GrdRdpBufferPool *grd_rdp_buffer_pool_new (GrdEglThread     *egl_thread,
+                                           GrdHwAccelNvidia *hwaccel_nvidia,
+                                           CUstream          cuda_stream,
+                                           uint32_t          minimum_size);
 
-void grd_rdp_buffer_pool_resize_buffers (GrdRdpBufferPool *buffer_pool,
-                                         uint32_t          buffer_width,
-                                         uint32_t          buffer_height,
-                                         uint32_t          buffer_stride);
+gboolean grd_rdp_buffer_pool_resize_buffers (GrdRdpBufferPool *buffer_pool,
+                                             uint32_t          buffer_width,
+                                             uint32_t          buffer_height,
+                                             uint32_t          buffer_stride);
 
 GrdRdpBuffer *grd_rdp_buffer_pool_acquire (GrdRdpBufferPool *buffer_pool);
 
diff --git a/src/grd-rdp-buffer.c b/src/grd-rdp-buffer.c
index eb33a310..a48a28c7 100644
--- a/src/grd-rdp-buffer.c
+++ b/src/grd-rdp-buffer.c
@@ -21,24 +21,84 @@
 
 #include "grd-rdp-buffer.h"
 
-#include <gio/gio.h>
+#include <ffnvcodec/dynlink_cuda.h>
 
+#include "grd-egl-thread.h"
+#include "grd-hwaccel-nvidia.h"
 #include "grd-rdp-buffer-pool.h"
+#include "grd-utils.h"
+
+typedef struct
+{
+  GrdHwAccelNvidia *hwaccel_nvidia;
+  CUgraphicsResource cuda_resource;
+  CUstream cuda_stream;
+  gboolean is_mapped;
+} ClearBufferData;
+
+typedef struct
+{
+  GrdHwAccelNvidia *hwaccel_nvidia;
+  GrdRdpBuffer *buffer;
+} AllocateBufferData;
 
 GrdRdpBuffer *
-grd_rdp_buffer_new (GrdRdpBufferPool *buffer_pool)
+grd_rdp_buffer_new (GrdRdpBufferPool *buffer_pool,
+                    GrdEglThread     *egl_thread,
+                    GrdHwAccelNvidia *hwaccel_nvidia,
+                    CUstream          cuda_stream)
 {
   GrdRdpBuffer *buffer;
 
   buffer = g_new0 (GrdRdpBuffer, 1);
   buffer->buffer_pool = buffer_pool;
+  buffer->egl_thread = egl_thread;
+  buffer->hwaccel_nvidia = hwaccel_nvidia;
+
+  buffer->cuda_stream = cuda_stream;
 
   return buffer;
 }
 
+static void
+cuda_deallocate_buffer (gpointer user_data)
+{
+  ClearBufferData *data = user_data;
+
+  if (data->is_mapped)
+    {
+      grd_hwaccel_nvidia_unmap_cuda_resource (data->hwaccel_nvidia,
+                                              data->cuda_resource,
+                                              data->cuda_stream);
+    }
+
+  grd_hwaccel_nvidia_unregister_cuda_resource (data->hwaccel_nvidia,
+                                               data->cuda_resource,
+                                               data->cuda_stream);
+}
+
 static void
 clear_buffers (GrdRdpBuffer *buffer)
 {
+  if (buffer->cuda_resource)
+    {
+      ClearBufferData *data;
+
+      data = g_new0 (ClearBufferData, 1);
+      data->hwaccel_nvidia = buffer->hwaccel_nvidia;
+      data->cuda_resource = buffer->cuda_resource;
+      data->cuda_stream = buffer->cuda_stream;
+      data->is_mapped = FALSE;
+      grd_egl_thread_deallocate (buffer->egl_thread,
+                                 buffer->pbo,
+                                 cuda_deallocate_buffer,
+                                 data,
+                                 NULL, data, g_free);
+
+      buffer->cuda_resource = NULL;
+      buffer->pbo = 0;
+    }
+
   g_clear_pointer (&buffer->local_data, g_free);
 }
 
@@ -55,15 +115,76 @@ grd_rdp_buffer_release (GrdRdpBuffer *buffer)
   grd_rdp_buffer_pool_release_buffer (buffer->buffer_pool, buffer);
 }
 
-void
+static gboolean
+cuda_allocate_buffer (gpointer user_data,
+                      uint32_t pbo)
+{
+  AllocateBufferData *data = user_data;
+  GrdRdpBuffer *buffer = data->buffer;
+  gboolean success;
+
+  success = grd_hwaccel_nvidia_register_read_only_gl_buffer (data->hwaccel_nvidia,
+                                                             &buffer->cuda_resource,
+                                                             pbo);
+  if (success)
+    buffer->pbo = pbo;
+
+  return success;
+}
+
+static void
+resources_ready (gboolean success,
+                 gpointer user_data)
+{
+  GrdSyncPoint *sync_point = user_data;
+
+  if (success)
+    g_debug ("[RDP] Allocating GL resources was successful");
+  else
+    g_warning ("[RDP] Failed to allocate GL resources");
+
+  grd_sync_point_complete (sync_point, success);
+}
+
+gboolean
 grd_rdp_buffer_resize (GrdRdpBuffer *buffer,
                        uint32_t      width,
                        uint32_t      height,
-                       uint32_t      stride)
+                       uint32_t      stride,
+                       gboolean      preallocate_on_gpu)
 {
+  gboolean success = TRUE;
+
   clear_buffers (buffer);
 
   buffer->width = width;
   buffer->height = height;
   buffer->local_data = g_malloc0 (stride * height * sizeof (uint8_t));
+
+  if (preallocate_on_gpu &&
+      buffer->hwaccel_nvidia)
+    {
+      AllocateBufferData data = {};
+      GrdSyncPoint sync_point = {};
+
+      g_assert (buffer->egl_thread);
+
+      grd_sync_point_init (&sync_point);
+      data.hwaccel_nvidia = buffer->hwaccel_nvidia;
+      data.buffer = buffer;
+
+      grd_egl_thread_allocate (buffer->egl_thread,
+                               buffer->height,
+                               stride,
+                               cuda_allocate_buffer,
+                               &data,
+                               resources_ready,
+                               &sync_point,
+                               NULL);
+
+      success = grd_sync_point_wait_for_completion (&sync_point);
+      grd_sync_point_clear (&sync_point);
+    }
+
+  return success;
 }
diff --git a/src/grd-rdp-buffer.h b/src/grd-rdp-buffer.h
index aeefa25d..8b376f3f 100644
--- a/src/grd-rdp-buffer.h
+++ b/src/grd-rdp-buffer.h
@@ -20,6 +20,8 @@
 #ifndef GRD_RDP_BUFFER_H
 #define GRD_RDP_BUFFER_H
 
+#include <ffnvcodec/dynlink_cuda.h>
+#include <gio/gio.h>
 #include <stdint.h>
 
 #include "grd-types.h"
@@ -28,21 +30,33 @@ struct _GrdRdpBuffer
 {
   GrdRdpBufferPool *buffer_pool;
 
+  GrdEglThread *egl_thread;
+  GrdHwAccelNvidia *hwaccel_nvidia;
+
   uint32_t width;
   uint32_t height;
 
   uint8_t *local_data;
+
+  uint32_t pbo;
+
+  CUgraphicsResource cuda_resource;
+  CUstream cuda_stream;
 };
 
-GrdRdpBuffer *grd_rdp_buffer_new (GrdRdpBufferPool *buffer_pool);
+GrdRdpBuffer *grd_rdp_buffer_new (GrdRdpBufferPool *buffer_pool,
+                                  GrdEglThread     *egl_thread,
+                                  GrdHwAccelNvidia *hwaccel_nvidia,
+                                  CUstream          cuda_stream);
 
 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,
-                            uint32_t      stride);
+gboolean grd_rdp_buffer_resize (GrdRdpBuffer *buffer,
+                                uint32_t      width,
+                                uint32_t      height,
+                                uint32_t      stride,
+                                gboolean      preallocate_on_gpu);
 
 #endif /* GRD_RDP_BUFFER_H */
diff --git a/src/grd-rdp-pipewire-stream.c b/src/grd-rdp-pipewire-stream.c
index d623f804..fd53d40a 100644
--- a/src/grd-rdp-pipewire-stream.c
+++ b/src/grd-rdp-pipewire-stream.c
@@ -371,13 +371,14 @@ on_stream_param_changed (void                 *user_data,
   release_all_buffers (stream);
 
   if (!grd_rdp_damage_detector_resize_surface (stream->rdp_surface->detector,
-                                               width, height))
+                                               width, height) ||
+      !grd_rdp_buffer_pool_resize_buffers (stream->buffer_pool,
+                                           width, height, stride))
     {
       grd_session_rdp_notify_error (
         stream->session_rdp, GRD_SESSION_RDP_ERROR_GRAPHICS_SUBSYSTEM_FAILED);
       return;
     }
-  grd_rdp_buffer_pool_resize_buffers (stream->buffer_pool, width, height, stride);
 
   pod_builder = SPA_POD_BUILDER_INIT (params_buffer, sizeof (params_buffer));
 
@@ -529,6 +530,13 @@ process_buffer (GrdRdpPipeWireStream     *stream,
       src_data = SPA_MEMBER (map, buffer->datas[0].mapoffset, uint8_t);
 
       frame->buffer = grd_rdp_buffer_pool_acquire (stream->buffer_pool);
+      if (!frame->buffer)
+        {
+          grd_session_rdp_notify_error (stream->session_rdp,
+                                        GRD_SESSION_RDP_ERROR_GRAPHICS_SUBSYSTEM_FAILED);
+          callback (stream, g_steal_pointer (&frame), FALSE, user_data);
+          return;
+        }
 
       copy_frame_data (frame,
                        src_data,
@@ -556,6 +564,13 @@ process_buffer (GrdRdpPipeWireStream     *stream,
       uint8_t *dst_data;
 
       frame->buffer = grd_rdp_buffer_pool_acquire (stream->buffer_pool);
+      if (!frame->buffer)
+        {
+          grd_session_rdp_notify_error (stream->session_rdp,
+                                        GRD_SESSION_RDP_ERROR_GRAPHICS_SUBSYSTEM_FAILED);
+          callback (stream, g_steal_pointer (&frame), FALSE, user_data);
+          return;
+        }
 
       row_width = dst_stride / bpp;
 
@@ -595,6 +610,13 @@ process_buffer (GrdRdpPipeWireStream     *stream,
       src_data = buffer->datas[0].data;
 
       frame->buffer = grd_rdp_buffer_pool_acquire (stream->buffer_pool);
+      if (!frame->buffer)
+        {
+          grd_session_rdp_notify_error (stream->session_rdp,
+                                        GRD_SESSION_RDP_ERROR_GRAPHICS_SUBSYSTEM_FAILED);
+          callback (stream, g_steal_pointer (&frame), FALSE, user_data);
+          return;
+        }
 
       copy_frame_data (frame,
                        src_data,
@@ -851,12 +873,16 @@ static const struct pw_core_events core_events = {
 };
 
 GrdRdpPipeWireStream *
-grd_rdp_pipewire_stream_new (GrdSessionRdp  *session_rdp,
-                             GMainContext   *render_context,
-                             GrdRdpSurface  *rdp_surface,
-                             uint32_t        src_node_id,
-                             GError        **error)
-{
+grd_rdp_pipewire_stream_new (GrdSessionRdp     *session_rdp,
+                             GrdHwAccelNvidia  *hwaccel_nvidia,
+                             GMainContext      *render_context,
+                             GrdRdpSurface     *rdp_surface,
+                             uint32_t           src_node_id,
+                             GError           **error)
+{
+  GrdSession *session = GRD_SESSION (session_rdp);
+  GrdContext *context = grd_session_get_context (session);
+  GrdEglThread *egl_thread = grd_context_get_egl_thread (context);
   g_autoptr (GrdRdpPipeWireStream) stream = NULL;
   GrdPipeWireSource *pipewire_source;
 
@@ -903,7 +929,12 @@ grd_rdp_pipewire_stream_new (GrdSessionRdp  *session_rdp,
   if (!connect_to_stream (stream, rdp_surface->refresh_rate, error))
     return NULL;
 
-  stream->buffer_pool = grd_rdp_buffer_pool_new (DEFAULT_BUFFER_POOL_SIZE);
+  stream->buffer_pool = grd_rdp_buffer_pool_new (egl_thread,
+                                                 hwaccel_nvidia,
+                                                 rdp_surface->cuda_stream,
+                                                 DEFAULT_BUFFER_POOL_SIZE);
+  if (!stream->buffer_pool)
+    return NULL;
 
   return g_steal_pointer (&stream);
 }
diff --git a/src/grd-rdp-pipewire-stream.h b/src/grd-rdp-pipewire-stream.h
index a9eec267..936e2901 100644
--- a/src/grd-rdp-pipewire-stream.h
+++ b/src/grd-rdp-pipewire-stream.h
@@ -30,10 +30,11 @@ G_DECLARE_FINAL_TYPE (GrdRdpPipeWireStream, grd_rdp_pipewire_stream,
                       GRD, RDP_PIPEWIRE_STREAM,
                       GObject)
 
-GrdRdpPipeWireStream *grd_rdp_pipewire_stream_new (GrdSessionRdp  *session_rdp,
-                                                   GMainContext   *render_context,
-                                                   GrdRdpSurface  *rdp_surface,
-                                                   uint32_t        src_node_id,
-                                                   GError        **error);
+GrdRdpPipeWireStream *grd_rdp_pipewire_stream_new (GrdSessionRdp     *session_rdp,
+                                                   GrdHwAccelNvidia  *hwaccel_nvidia,
+                                                   GMainContext      *render_context,
+                                                   GrdRdpSurface     *rdp_surface,
+                                                   uint32_t           src_node_id,
+                                                   GError           **error);
 
 #endif /* GRD_RDP_PIPEWIRE_STREAM_H */
diff --git a/src/grd-rdp-surface.c b/src/grd-rdp-surface.c
index e555e180..2c2f753d 100644
--- a/src/grd-rdp-surface.c
+++ b/src/grd-rdp-surface.c
@@ -21,21 +21,29 @@
 
 #include "grd-rdp-surface.h"
 
+#include "grd-hwaccel-nvidia.h"
 #include "grd-rdp-buffer.h"
 #include "grd-rdp-damage-detector-memcmp.h"
 
 GrdRdpSurface *
-grd_rdp_surface_new (void)
+grd_rdp_surface_new (GrdHwAccelNvidia *hwaccel_nvidia)
 {
-  GrdRdpSurface *rdp_surface;
+  g_autofree GrdRdpSurface *rdp_surface = NULL;
 
   rdp_surface = g_malloc0 (sizeof (GrdRdpSurface));
+  rdp_surface->hwaccel_nvidia = hwaccel_nvidia;
+
+  if (hwaccel_nvidia &&
+      !grd_hwaccel_nvidia_create_cuda_stream (hwaccel_nvidia,
+                                              &rdp_surface->cuda_stream))
+    return NULL;
+
   rdp_surface->detector = (GrdRdpDamageDetector *)
     grd_rdp_damage_detector_memcmp_new ();
 
   g_mutex_init (&rdp_surface->surface_mutex);
 
-  return rdp_surface;
+  return g_steal_pointer (&rdp_surface);
 }
 
 void
@@ -49,6 +57,12 @@ grd_rdp_surface_free (GrdRdpSurface *rdp_surface)
   g_mutex_clear (&rdp_surface->surface_mutex);
 
   g_clear_object (&rdp_surface->detector);
+  if (rdp_surface->cuda_stream)
+    {
+      grd_hwaccel_nvidia_destroy_cuda_stream (rdp_surface->hwaccel_nvidia,
+                                              rdp_surface->cuda_stream);
+      rdp_surface->cuda_stream = NULL;
+    }
 
   g_free (rdp_surface);
 }
diff --git a/src/grd-rdp-surface.h b/src/grd-rdp-surface.h
index 1feabf23..d6878544 100644
--- a/src/grd-rdp-surface.h
+++ b/src/grd-rdp-surface.h
@@ -20,6 +20,7 @@
 #ifndef GRD_RDP_SURFACE_H
 #define GRD_RDP_SURFACE_H
 
+#include <ffnvcodec/dynlink_cuda.h>
 #include <gio/gio.h>
 #include <stdint.h>
 
@@ -37,6 +38,9 @@ struct _GrdRdpSurface
   GrdRdpBuffer *pending_framebuffer;
   GrdRdpDamageDetector *detector;
 
+  GrdHwAccelNvidia *hwaccel_nvidia;
+  CUstream cuda_stream;
+
   gboolean valid;
 
   GrdRdpGfxSurface *gfx_surface;
@@ -44,7 +48,7 @@ struct _GrdRdpSurface
   gboolean encoding_suspended;
 };
 
-GrdRdpSurface *grd_rdp_surface_new (void);
+GrdRdpSurface *grd_rdp_surface_new (GrdHwAccelNvidia *hwaccel_nvidia);
 
 void grd_rdp_surface_free (GrdRdpSurface *rdp_surface);
 
diff --git a/src/grd-session-rdp.c b/src/grd-session-rdp.c
index 0435257c..cde858f2 100644
--- a/src/grd-session-rdp.c
+++ b/src/grd-session-rdp.c
@@ -1671,7 +1671,13 @@ rdp_peer_post_connect (freerdp_peer *peer)
 
   rdp_settings->PointerCacheSize = MIN (rdp_settings->PointerCacheSize, 100);
 
-  session_rdp->rdp_surface = grd_rdp_surface_new ();
+  session_rdp->rdp_surface = grd_rdp_surface_new (session_rdp->hwaccel_nvidia);
+  if (!session_rdp->rdp_surface)
+    {
+      g_warning ("[RDP] Failed to create RDP surface");
+      return FALSE;
+    }
+
   session_rdp->rdp_surface->refresh_rate = rdp_settings->SupportGraphicsPipeline ? 60
                                                                                  : 30;
 
@@ -1893,6 +1899,9 @@ socket_thread_func (gpointer data)
   uint32_t n_events;
   uint32_t n_freerdp_handles;
 
+  if (session_rdp->hwaccel_nvidia)
+    grd_hwaccel_nvidia_push_cuda_context (session_rdp->hwaccel_nvidia);
+
   WaitForSingleObject (session_rdp->start_event, INFINITE);
 
   peer = session_rdp->peer;
@@ -1965,6 +1974,9 @@ socket_thread_func (gpointer data)
         }
     }
 
+  if (session_rdp->hwaccel_nvidia)
+    grd_hwaccel_nvidia_pop_cuda_context (session_rdp->hwaccel_nvidia);
+
   return NULL;
 }
 
@@ -2176,6 +2188,7 @@ grd_session_rdp_stream_ready (GrdSession *session,
   rdp_surface = session_rdp->rdp_surface;
   pipewire_node_id = grd_stream_get_pipewire_node_id (stream);
   session_rdp->pipewire_stream = grd_rdp_pipewire_stream_new (session_rdp,
+                                                              session_rdp->hwaccel_nvidia,
                                                               graphics_context,
                                                               rdp_surface,
                                                               pipewire_node_id,


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