[gnome-remote-desktop] rdp: Add classes for damage region detection



commit 65040791538a5245d64f29e487b275a6607827ed
Author: Pascal Nowack <Pascal Nowack gmx de>
Date:   Wed Jan 5 18:03:34 2022 +0100

    rdp: Add classes for damage region detection
    
    Currently, the damage detection in gnome-remote-desktop is done using
    memcmp.
    When a frame is not completely different than its previous frame, which
    is usually the case, then the damage detection using memcmp can take
    several milliseconds.
    Comparing frame buffers on the GPU is much faster, even when an upload
    of the frame data to the GPU is required, but this method is not always
    available.
    
    To take care of this problem, add a new abstract class, which provides
    function pointers of an implementation.
    Also provide one fallback implementation using memcmp.
    
    This allows, in the future, the implementation of other region
    detection classes without requiring additional changes in the graphics
    thread.

 src/grd-rdp-damage-detector-memcmp.c | 246 +++++++++++++++++++++++++++++++++++
 src/grd-rdp-damage-detector-memcmp.h |  31 +++++
 src/grd-rdp-damage-detector.c        |  82 ++++++++++++
 src/grd-rdp-damage-detector.h        |  60 +++++++++
 src/grd-types.h                      |   1 +
 src/meson.build                      |   4 +
 6 files changed, 424 insertions(+)
---
diff --git a/src/grd-rdp-damage-detector-memcmp.c b/src/grd-rdp-damage-detector-memcmp.c
new file mode 100644
index 00000000..e28d5153
--- /dev/null
+++ b/src/grd-rdp-damage-detector-memcmp.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2022 Pascal Nowack
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "grd-rdp-damage-detector-memcmp.h"
+
+#include "grd-damage-utils.h"
+#include "grd-rdp-buffer.h"
+
+#define TILE_WIDTH 64
+#define TILE_HEIGHT 64
+
+typedef struct _GrdRdpDamageDetectorMemcmp
+{
+  GrdRdpDamageDetector parent;
+
+  uint32_t surface_width;
+  uint32_t surface_height;
+
+  uint32_t cols;
+  uint32_t rows;
+
+  GrdRdpBuffer *last_framebuffer;
+
+  gboolean region_is_damaged;
+  uint8_t *damage_array;
+} GrdRdpDamageDetectorMemcmp;
+
+G_DEFINE_TYPE (GrdRdpDamageDetectorMemcmp,
+               grd_rdp_damage_detector_memcmp,
+               GRD_TYPE_RDP_DAMAGE_DETECTOR)
+
+static gboolean
+invalidate_surface (GrdRdpDamageDetector *detector)
+{
+  GrdRdpDamageDetectorMemcmp *detector_memcmp =
+    GRD_RDP_DAMAGE_DETECTOR_MEMCMP (detector);
+  uint32_t cols = detector_memcmp->cols;
+  uint32_t rows = detector_memcmp->rows;
+
+  g_clear_pointer (&detector_memcmp->last_framebuffer, grd_rdp_buffer_release);
+
+  if (!detector_memcmp->damage_array)
+    return TRUE;
+
+  memset (detector_memcmp->damage_array, 1, cols * rows);
+  detector_memcmp->region_is_damaged = TRUE;
+
+  return TRUE;
+}
+
+static gboolean
+resize_surface (GrdRdpDamageDetector *detector,
+                uint32_t              width,
+                uint32_t              height)
+{
+  GrdRdpDamageDetectorMemcmp *detector_memcmp =
+    GRD_RDP_DAMAGE_DETECTOR_MEMCMP (detector);
+  uint32_t cols;
+  uint32_t rows;
+
+  g_clear_pointer (&detector_memcmp->last_framebuffer, grd_rdp_buffer_release);
+  g_clear_pointer (&detector_memcmp->damage_array, g_free);
+
+  detector_memcmp->surface_width = width;
+  detector_memcmp->surface_height = height;
+
+  cols = width / TILE_WIDTH + (width % TILE_WIDTH ? 1 : 0);
+  rows = height / TILE_HEIGHT + (height % TILE_HEIGHT ? 1 : 0);
+  detector_memcmp->damage_array = g_malloc0 (cols * rows * sizeof (uint8_t));
+
+  memset (detector_memcmp->damage_array, 1, cols * rows);
+  detector_memcmp->region_is_damaged = TRUE;
+
+  detector_memcmp->cols = cols;
+  detector_memcmp->rows = rows;
+
+  return TRUE;
+}
+
+static gboolean
+submit_new_framebuffer (GrdRdpDamageDetector *detector,
+                        GrdRdpBuffer         *buffer)
+{
+  GrdRdpDamageDetectorMemcmp *detector_memcmp =
+    GRD_RDP_DAMAGE_DETECTOR_MEMCMP (detector);
+  uint32_t surface_width = detector_memcmp->surface_width;
+  uint32_t surface_height = detector_memcmp->surface_height;
+  uint32_t cols = detector_memcmp->cols;
+  uint32_t rows = detector_memcmp->rows;
+  gboolean region_is_damaged = FALSE;
+  uint32_t x, y;
+
+  g_assert (detector_memcmp->damage_array);
+
+  if (!detector_memcmp->last_framebuffer)
+    {
+      detector_memcmp->last_framebuffer = buffer;
+
+      memset (detector_memcmp->damage_array, 1, cols * rows);
+      detector_memcmp->region_is_damaged = TRUE;
+      return TRUE;
+    }
+
+  for (y = 0; y < detector_memcmp->rows; ++y)
+    {
+      for (x = 0; x < detector_memcmp->cols; ++x)
+        {
+          cairo_rectangle_int_t tile;
+          uint8_t tile_damaged = 0;
+
+          tile.x = x * TILE_WIDTH;
+          tile.y = y * TILE_HEIGHT;
+          tile.width = surface_width - tile.x < TILE_WIDTH ? surface_width - tile.x
+                                                           : TILE_WIDTH;
+          tile.height = surface_height - tile.y < TILE_HEIGHT ? surface_height - tile.y
+                                                              : TILE_HEIGHT;
+
+          if (grd_is_tile_dirty (&tile,
+                                 buffer->local_data,
+                                 detector_memcmp->last_framebuffer->local_data,
+                                 surface_width * 4, 4))
+            {
+              tile_damaged = 1;
+              region_is_damaged = TRUE;
+            }
+
+          detector_memcmp->damage_array[y * detector_memcmp->cols + x] = tile_damaged;
+        }
+    }
+
+  g_clear_pointer (&detector_memcmp->last_framebuffer, grd_rdp_buffer_release);
+  detector_memcmp->last_framebuffer = buffer;
+  detector_memcmp->region_is_damaged = region_is_damaged;
+
+  return TRUE;
+}
+
+static gboolean
+is_region_damaged (GrdRdpDamageDetector *detector)
+{
+  GrdRdpDamageDetectorMemcmp *detector_memcmp =
+    GRD_RDP_DAMAGE_DETECTOR_MEMCMP (detector);
+
+  g_assert (detector_memcmp->damage_array);
+  g_assert (detector_memcmp->last_framebuffer);
+
+  return detector_memcmp->region_is_damaged;
+}
+
+static cairo_region_t *
+get_damage_region (GrdRdpDamageDetector *detector)
+{
+  GrdRdpDamageDetectorMemcmp *detector_memcmp =
+    GRD_RDP_DAMAGE_DETECTOR_MEMCMP (detector);
+  uint32_t surface_width = detector_memcmp->surface_width;
+  uint32_t surface_height = detector_memcmp->surface_height;
+  cairo_region_t *damage_region;
+  cairo_rectangle_int_t tile;
+  uint32_t x, y;
+
+  g_assert (detector_memcmp->damage_array);
+  g_assert (detector_memcmp->last_framebuffer);
+
+  damage_region = cairo_region_create ();
+  for (y = 0; y < detector_memcmp->rows; ++y)
+    {
+      for (x = 0; x < detector_memcmp->cols; ++x)
+        {
+          if (detector_memcmp->damage_array[y * detector_memcmp->cols + x])
+            {
+              tile.x = x * TILE_WIDTH;
+              tile.y = y * TILE_HEIGHT;
+              tile.width = surface_width - tile.x < TILE_WIDTH ? surface_width - tile.x
+                                                               : TILE_WIDTH;
+              tile.height = surface_height - tile.y < TILE_HEIGHT ? surface_height - tile.y
+                                                                  : TILE_HEIGHT;
+
+              cairo_region_union_rectangle (damage_region, &tile);
+            }
+        }
+    }
+
+  return damage_region;
+}
+
+GrdRdpDamageDetectorMemcmp *
+grd_rdp_damage_detector_memcmp_new (void)
+{
+  GrdRdpDamageDetectorMemcmp *detector_memcmp;
+
+  detector_memcmp = g_object_new (GRD_TYPE_RDP_DAMAGE_DETECTOR_MEMCMP, NULL);
+
+  return detector_memcmp;
+}
+
+static void
+grd_rdp_damage_detector_memcmp_dispose (GObject *object)
+{
+  GrdRdpDamageDetectorMemcmp *detector_memcmp =
+    GRD_RDP_DAMAGE_DETECTOR_MEMCMP (object);
+
+  g_assert (!detector_memcmp->last_framebuffer);
+
+  g_clear_pointer (&detector_memcmp->damage_array, g_free);
+
+  G_OBJECT_CLASS (grd_rdp_damage_detector_memcmp_parent_class)->dispose (object);
+}
+
+static void
+grd_rdp_damage_detector_memcmp_init (GrdRdpDamageDetectorMemcmp *detector_memcmp)
+{
+}
+
+static void
+grd_rdp_damage_detector_memcmp_class_init (GrdRdpDamageDetectorMemcmpClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GrdRdpDamageDetectorClass *detector_class =
+    GRD_RDP_DAMAGE_DETECTOR_CLASS (klass);
+
+  object_class->dispose = grd_rdp_damage_detector_memcmp_dispose;
+
+  detector_class->invalidate_surface = invalidate_surface;
+  detector_class->resize_surface = resize_surface;
+  detector_class->submit_new_framebuffer = submit_new_framebuffer;
+  detector_class->is_region_damaged = is_region_damaged;
+  detector_class->get_damage_region = get_damage_region;
+}
diff --git a/src/grd-rdp-damage-detector-memcmp.h b/src/grd-rdp-damage-detector-memcmp.h
new file mode 100644
index 00000000..63283c13
--- /dev/null
+++ b/src/grd-rdp-damage-detector-memcmp.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 Pascal Nowack
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef GRD_RDP_DAMAGE_DETECTOR_MEMCMP_H
+#define GRD_RDP_DAMAGE_DETECTOR_MEMCMP_H
+
+#include "grd-rdp-damage-detector.h"
+
+#define GRD_TYPE_RDP_DAMAGE_DETECTOR_MEMCMP (grd_rdp_damage_detector_memcmp_get_type ())
+G_DECLARE_FINAL_TYPE (GrdRdpDamageDetectorMemcmp, grd_rdp_damage_detector_memcmp,
+                      GRD, RDP_DAMAGE_DETECTOR_MEMCMP, GrdRdpDamageDetector)
+
+GrdRdpDamageDetectorMemcmp *grd_rdp_damage_detector_memcmp_new (void);
+
+#endif /* GRD_RDP_DAMAGE_DETECTOR_MEMCMP_H */
diff --git a/src/grd-rdp-damage-detector.c b/src/grd-rdp-damage-detector.c
new file mode 100644
index 00000000..664b0622
--- /dev/null
+++ b/src/grd-rdp-damage-detector.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2022 Pascal Nowack
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "grd-rdp-damage-detector.h"
+
+G_DEFINE_TYPE (GrdRdpDamageDetector, grd_rdp_damage_detector, G_TYPE_OBJECT);
+
+gboolean
+grd_rdp_damage_detector_invalidate_surface (GrdRdpDamageDetector *detector)
+{
+  GrdRdpDamageDetectorClass *klass =
+    GRD_RDP_DAMAGE_DETECTOR_GET_CLASS (detector);
+
+  return klass->invalidate_surface (detector);
+}
+
+gboolean
+grd_rdp_damage_detector_resize_surface (GrdRdpDamageDetector *detector,
+                                        uint32_t              width,
+                                        uint32_t              height)
+{
+  GrdRdpDamageDetectorClass *klass =
+    GRD_RDP_DAMAGE_DETECTOR_GET_CLASS (detector);
+
+  return klass->resize_surface (detector, width, height);
+}
+
+gboolean
+grd_rdp_damage_detector_submit_new_framebuffer (GrdRdpDamageDetector *detector,
+                                                GrdRdpBuffer         *buffer)
+{
+  GrdRdpDamageDetectorClass *klass =
+    GRD_RDP_DAMAGE_DETECTOR_GET_CLASS (detector);
+
+  return klass->submit_new_framebuffer (detector, buffer);
+}
+
+gboolean
+grd_rdp_damage_detector_is_region_damaged (GrdRdpDamageDetector *detector)
+{
+  GrdRdpDamageDetectorClass *klass =
+    GRD_RDP_DAMAGE_DETECTOR_GET_CLASS (detector);
+
+  return klass->is_region_damaged (detector);
+}
+
+cairo_region_t *
+grd_rdp_damage_detector_get_damage_region (GrdRdpDamageDetector *detector)
+{
+  GrdRdpDamageDetectorClass *klass =
+    GRD_RDP_DAMAGE_DETECTOR_GET_CLASS (detector);
+
+  return klass->get_damage_region (detector);
+}
+
+static void
+grd_rdp_damage_detector_init (GrdRdpDamageDetector *detector)
+{
+}
+
+static void
+grd_rdp_damage_detector_class_init (GrdRdpDamageDetectorClass *klass)
+{
+}
diff --git a/src/grd-rdp-damage-detector.h b/src/grd-rdp-damage-detector.h
new file mode 100644
index 00000000..bfba3bd8
--- /dev/null
+++ b/src/grd-rdp-damage-detector.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 Pascal Nowack
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef GRD_RDP_DAMAGE_DETECTOR_H
+#define GRD_RDP_DAMAGE_DETECTOR_H
+
+#include <cairo/cairo.h>
+#include <glib-object.h>
+#include <stdint.h>
+
+#include "grd-types.h"
+
+#define GRD_TYPE_RDP_DAMAGE_DETECTOR (grd_rdp_damage_detector_get_type ())
+G_DECLARE_DERIVABLE_TYPE (GrdRdpDamageDetector, grd_rdp_damage_detector,
+                          GRD, RDP_DAMAGE_DETECTOR, GObject)
+
+struct _GrdRdpDamageDetectorClass
+{
+  GObjectClass parent_class;
+
+  gboolean (* invalidate_surface) (GrdRdpDamageDetector *detector);
+  gboolean (* resize_surface) (GrdRdpDamageDetector *detector,
+                               uint32_t              width,
+                               uint32_t              height);
+  gboolean (* submit_new_framebuffer) (GrdRdpDamageDetector *detector,
+                                       GrdRdpBuffer         *buffer);
+  gboolean (* is_region_damaged) (GrdRdpDamageDetector *detector);
+  cairo_region_t *(* get_damage_region) (GrdRdpDamageDetector *detector);
+};
+
+gboolean grd_rdp_damage_detector_invalidate_surface (GrdRdpDamageDetector *detector);
+
+gboolean grd_rdp_damage_detector_resize_surface (GrdRdpDamageDetector *detector,
+                                                 uint32_t              width,
+                                                 uint32_t              height);
+
+gboolean grd_rdp_damage_detector_submit_new_framebuffer (GrdRdpDamageDetector *detector,
+                                                         GrdRdpBuffer         *buffer);
+
+gboolean grd_rdp_damage_detector_is_region_damaged (GrdRdpDamageDetector *detector);
+
+cairo_region_t *grd_rdp_damage_detector_get_damage_region (GrdRdpDamageDetector *detector);
+
+#endif /* GRD_RDP_DAMAGE_DETECTOR_H */
diff --git a/src/grd-types.h b/src/grd-types.h
index abd922e1..b67474a8 100644
--- a/src/grd-types.h
+++ b/src/grd-types.h
@@ -29,6 +29,7 @@ typedef struct _GrdClipboardRdp GrdClipboardRdp;
 typedef struct _GrdClipboardVnc GrdClipboardVnc;
 typedef struct _GrdEglThread GrdEglThread;
 typedef struct _GrdHwAccelNvidia GrdHwAccelNvidia;
+typedef struct _GrdRdpDamageDetector GrdRdpDamageDetector;
 typedef struct _GrdRdpEventQueue GrdRdpEventQueue;
 typedef struct _GrdRdpBuffer GrdRdpBuffer;
 typedef struct _GrdRdpBufferPool GrdRdpBufferPool;
diff --git a/src/meson.build b/src/meson.build
index abd8277a..ff1f2894 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -51,6 +51,10 @@ if have_rdp
     'grd-rdp-buffer.h',
     'grd-rdp-buffer-pool.c',
     'grd-rdp-buffer-pool.h',
+    'grd-rdp-damage-detector.c',
+    'grd-rdp-damage-detector.h',
+    'grd-rdp-damage-detector-memcmp.c',
+    'grd-rdp-damage-detector-memcmp.h',
     'grd-rdp-event-queue.c',
     'grd-rdp-event-queue.h',
     'grd-rdp-frame-info.h',


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