[gnome-remote-desktop] egl-thread: Add methods to upload data to the GPU
- From: Jonas Ådahl <jadahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-remote-desktop] egl-thread: Add methods to upload data to the GPU
- Date: Thu, 3 Mar 2022 14:23:08 +0000 (UTC)
commit 309ff5164fca199cebc18a034251fae86df84d6f
Author: Pascal Nowack <Pascal Nowack gmx de>
Date: Tue Jan 4 14:34:11 2022 +0100
egl-thread: Add methods to upload data to the GPU
As not all drivers support dma-bufs, but support some sort of hardware
acceleration, that gnome-remote-desktop can make use of, add some
methods to manage pixel buffer objects on the GPU, including uploading
them.
src/grd-egl-thread.c | 247 +++++++++++++++++++++++++++++++++++++++++++++++++++
src/grd-egl-thread.h | 35 ++++++++
2 files changed, 282 insertions(+)
---
diff --git a/src/grd-egl-thread.c b/src/grd-egl-thread.c
index 17fb7dac..2bcbdd3a 100644
--- a/src/grd-egl-thread.c
+++ b/src/grd-egl-thread.c
@@ -75,6 +75,46 @@ typedef struct _GrdEglTaskSync
GrdEglTask base;
} GrdEglTaskSync;
+typedef struct _GrdEglTaskUpload
+{
+ GrdEglTask base;
+
+ GLuint pbo;
+
+ uint32_t height;
+ uint32_t stride;
+ uint8_t *src_data;
+
+ GrdEglThreadAllocBufferFunc allocate_func;
+ gpointer allocate_user_data;
+ GDestroyNotify allocate_user_data_destroy;
+
+ GrdEglThreadCustomFunc realize_func;
+ gpointer realize_user_data;
+ GDestroyNotify realize_user_data_destroy;
+} GrdEglTaskUpload;
+
+typedef struct _GrdEglTaskDeallocateMemory
+{
+ GrdEglTask base;
+
+ GLuint pbo;
+
+ GrdEglThreadDeallocBufferFunc deallocate_func;
+ gpointer deallocate_user_data;
+} GrdEglTaskDeallocateMemory;
+
+typedef struct _GrdEglTaskAllocateMemory
+{
+ GrdEglTask base;
+
+ uint32_t height;
+ uint32_t stride;
+
+ GrdEglThreadAllocBufferFunc allocate_func;
+ gpointer allocate_user_data;
+} GrdEglTaskAllocateMemory;
+
typedef struct _GrdEglTaskDownload
{
GrdEglTask base;
@@ -367,6 +407,17 @@ grd_egl_task_download_free (GrdEglTask *task_base)
grd_egl_task_free (task_base);
}
+static void
+grd_egl_task_upload_free (GrdEglTask *task_base)
+{
+ GrdEglTaskUpload *task = (GrdEglTaskUpload *) task_base;
+
+ task->allocate_user_data_destroy (task->allocate_user_data);
+ task->realize_user_data_destroy (task->realize_user_data);
+
+ grd_egl_task_free (task_base);
+}
+
static void
grd_thread_dispatch_in_impl (GrdEglThread *egl_thread)
{
@@ -737,6 +788,101 @@ out:
task->base.callback (success, task->base.callback_user_data);
}
+static void
+allocate_in_impl (gpointer data,
+ gpointer user_data)
+{
+ GrdEglTaskAllocateMemory *task = user_data;
+ gboolean success = FALSE;
+ uint32_t buffer_size;
+ GLuint pbo = 0;
+
+ buffer_size = task->stride * task->height * sizeof (uint8_t);
+
+ glGenBuffers (1, &pbo);
+ glBindBuffer (GL_PIXEL_PACK_BUFFER, pbo);
+ glBufferData (GL_PIXEL_PACK_BUFFER, buffer_size, NULL, GL_DYNAMIC_DRAW);
+ glBindBuffer (GL_PIXEL_PACK_BUFFER, 0);
+
+ if (task->allocate_func (task->allocate_user_data, pbo))
+ success = TRUE;
+
+ if (!success && pbo)
+ {
+ glDeleteBuffers (1, &pbo);
+ pbo = 0;
+ }
+
+ task->base.callback (success, task->base.callback_user_data);
+}
+
+static void
+deallocate_in_impl (gpointer data,
+ gpointer user_data)
+{
+ GrdEglTaskDeallocateMemory *task = user_data;
+
+ task->deallocate_func (task->deallocate_user_data);
+
+ if (task->pbo)
+ glDeleteBuffers (1, &task->pbo);
+
+ if (task->base.callback)
+ task->base.callback (TRUE, task->base.callback_user_data);
+}
+
+static void
+upload_in_impl (gpointer data,
+ gpointer user_data)
+{
+ GrdEglTaskUpload *task = user_data;
+ gboolean success = FALSE;
+ uint32_t buffer_size;
+ GLenum error;
+
+ buffer_size = task->stride * task->height * sizeof (uint8_t);
+
+ if (!task->pbo)
+ {
+ GLuint pbo = 0;
+
+ glGenBuffers (1, &pbo);
+ glBindBuffer (GL_PIXEL_PACK_BUFFER, pbo);
+ glBufferData (GL_PIXEL_PACK_BUFFER, buffer_size, NULL, GL_DYNAMIC_DRAW);
+ glBindBuffer (GL_PIXEL_PACK_BUFFER, 0);
+
+ if (!task->allocate_func (task->allocate_user_data, pbo))
+ {
+ g_warning ("[EGL Thread] Failed to allocate GL resources");
+ glDeleteBuffers (1, &pbo);
+ goto out;
+ }
+
+ g_debug ("[EGL Thread] Allocating GL resources was successful");
+ task->pbo = pbo;
+ }
+
+ glBindBuffer (GL_PIXEL_PACK_BUFFER, task->pbo);
+ glBufferData (GL_PIXEL_PACK_BUFFER, buffer_size, NULL, GL_DYNAMIC_DRAW);
+ glBufferSubData (GL_PIXEL_PACK_BUFFER, 0, buffer_size, task->src_data);
+ error = glGetError ();
+ if (error != GL_NO_ERROR)
+ {
+ g_warning ("[EGL Thread] Failed to update buffer data: %u", error);
+ goto out;
+ }
+
+ if (!task->realize_func (task->realize_user_data))
+ goto out;
+
+ success = TRUE;
+
+out:
+ glBindBuffer (GL_PIXEL_PACK_BUFFER, 0);
+
+ task->base.callback (success, task->base.callback_user_data);
+}
+
static void
sync_in_impl (gpointer data,
gpointer user_data)
@@ -800,6 +946,107 @@ grd_egl_thread_download (GrdEglThread *egl_thread,
g_main_context_wakeup (egl_thread->impl.main_context);
}
+void
+grd_egl_thread_allocate (GrdEglThread *egl_thread,
+ uint32_t height,
+ uint32_t stride,
+ GrdEglThreadAllocBufferFunc allocate_func,
+ gpointer allocate_user_data,
+ GrdEglThreadCallback callback,
+ gpointer user_data,
+ GDestroyNotify destroy)
+{
+ GrdEglTaskAllocateMemory *task;
+
+ task = g_new0 (GrdEglTaskAllocateMemory, 1);
+
+ task->height = height;
+ task->stride = stride;
+ task->allocate_func = allocate_func;
+ task->allocate_user_data = allocate_user_data;
+
+ task->base.func = allocate_in_impl;
+ task->base.destroy = (GDestroyNotify) grd_egl_task_free;
+ task->base.callback = callback;
+ task->base.callback_user_data = user_data;
+ task->base.callback_destroy = destroy;
+
+ g_async_queue_push (egl_thread->task_queue, task);
+ g_main_context_wakeup (egl_thread->impl.main_context);
+}
+
+void
+grd_egl_thread_deallocate (GrdEglThread *egl_thread,
+ uint32_t pbo,
+ GrdEglThreadDeallocBufferFunc deallocate_func,
+ gpointer deallocate_user_data,
+ GrdEglThreadCallback callback,
+ gpointer user_data,
+ GDestroyNotify destroy)
+{
+ GrdEglTaskDeallocateMemory *task;
+
+ task = g_new0 (GrdEglTaskDeallocateMemory, 1);
+
+ task->pbo = pbo;
+
+ task->deallocate_func = deallocate_func;
+ task->deallocate_user_data = deallocate_user_data;
+
+ task->base.func = deallocate_in_impl;
+ task->base.destroy = (GDestroyNotify) grd_egl_task_free;
+ task->base.callback = callback;
+ task->base.callback_user_data = user_data;
+ task->base.callback_destroy = destroy;
+
+ g_async_queue_push (egl_thread->task_queue, task);
+ g_main_context_wakeup (egl_thread->impl.main_context);
+}
+
+void
+grd_egl_thread_upload (GrdEglThread *egl_thread,
+ uint32_t pbo,
+ uint32_t height,
+ uint32_t stride,
+ uint8_t *src_data,
+ GrdEglThreadAllocBufferFunc allocate_func,
+ gpointer allocate_user_data,
+ GDestroyNotify allocate_user_data_destroy,
+ GrdEglThreadCustomFunc realize_func,
+ gpointer realize_user_data,
+ GDestroyNotify realize_user_data_destroy,
+ GrdEglThreadCallback callback,
+ gpointer user_data,
+ GDestroyNotify destroy)
+{
+ GrdEglTaskUpload *task;
+
+ task = g_new0 (GrdEglTaskUpload, 1);
+
+ task->pbo = pbo;
+
+ task->height = height;
+ task->stride = stride;
+ task->src_data = src_data;
+
+ task->allocate_func = allocate_func;
+ task->allocate_user_data = allocate_user_data;
+ task->allocate_user_data_destroy = allocate_user_data_destroy;
+
+ task->realize_func = realize_func;
+ task->realize_user_data = realize_user_data;
+ task->realize_user_data_destroy = realize_user_data_destroy;
+
+ task->base.func = upload_in_impl;
+ task->base.destroy = (GDestroyNotify) grd_egl_task_upload_free;
+ task->base.callback = callback;
+ task->base.callback_user_data = user_data;
+ task->base.callback_destroy = destroy;
+
+ g_async_queue_push (egl_thread->task_queue, task);
+ g_main_context_wakeup (egl_thread->impl.main_context);
+}
+
void
grd_egl_thread_sync (GrdEglThread *egl_thread,
GrdEglThreadCallback callback,
diff --git a/src/grd-egl-thread.h b/src/grd-egl-thread.h
index 2e032513..860f0296 100644
--- a/src/grd-egl-thread.h
+++ b/src/grd-egl-thread.h
@@ -29,6 +29,9 @@
typedef void (* GrdEglThreadCallback) (gboolean success,
gpointer user_data);
typedef gboolean (* GrdEglThreadCustomFunc) (gpointer user_data);
+typedef gboolean (* GrdEglThreadAllocBufferFunc) (gpointer user_data,
+ uint32_t pbo);
+typedef void (* GrdEglThreadDeallocBufferFunc) (gpointer user_data);
GrdEglThread * grd_egl_thread_new (GError **error);
@@ -49,6 +52,38 @@ void grd_egl_thread_download (GrdEglThread *egl_thread,
gpointer user_data,
GDestroyNotify destroy);
+void grd_egl_thread_allocate (GrdEglThread *egl_thread,
+ uint32_t height,
+ uint32_t stride,
+ GrdEglThreadAllocBufferFunc allocate_func,
+ gpointer allocate_user_data,
+ GrdEglThreadCallback callback,
+ gpointer user_data,
+ GDestroyNotify destroy);
+
+void grd_egl_thread_deallocate (GrdEglThread *egl_thread,
+ uint32_t pbo,
+ GrdEglThreadDeallocBufferFunc deallocate_func,
+ gpointer deallocate_user_data,
+ GrdEglThreadCallback callback,
+ gpointer user_data,
+ GDestroyNotify destroy);
+
+void grd_egl_thread_upload (GrdEglThread *egl_thread,
+ uint32_t pbo,
+ uint32_t height,
+ uint32_t stride,
+ uint8_t *src_data,
+ GrdEglThreadAllocBufferFunc allocate_func,
+ gpointer allocate_user_data,
+ GDestroyNotify allocate_user_data_destroy,
+ GrdEglThreadCustomFunc realize_func,
+ gpointer realize_user_data,
+ GDestroyNotify realize_user_data_destroy,
+ GrdEglThreadCallback callback,
+ gpointer user_data,
+ GDestroyNotify destroy);
+
void grd_egl_thread_sync (GrdEglThread *egl_thread,
GrdEglThreadCallback callback,
gpointer user_data,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]