[gnome-remote-desktop] rdp: Add classes for damage region detection
- From: Jonas Ådahl <jadahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-remote-desktop] rdp: Add classes for damage region detection
- Date: Thu, 3 Mar 2022 14:23:07 +0000 (UTC)
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]