summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrediano Ziglio <fziglio@redhat.com>2016-09-23 14:28:43 +0100
committerFrediano Ziglio <fziglio@redhat.com>2016-09-23 14:28:43 +0100
commit47cff41d650677e3ed3f37baf495fd52da135158 (patch)
treede207551fa3544c7b2d81cc7d3d82573320abb07
Setup EGL display without changing Qemu codeHEADmaster
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
-rw-r--r--.gitignore1
-rw-r--r--Makefile2
-rw-r--r--main.c108
3 files changed, 111 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9d5b507
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+qxl_setup.so
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..8c1dba5
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,2 @@
+qxl_setup.so: main.c Makefile
+ gcc -s -O2 $(CPPFLAGS) $(shell pkg-config --cflags spice-protocol) -Wall -Werror --shared -fPIC -DPIC -o $@ $< -ldl -lepoxy -lgdm
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..2a74d11
--- /dev/null
+++ b/main.c
@@ -0,0 +1,108 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <spice-server/spice.h>
+
+// definitions
+//
+struct gbm_device;
+
+typedef void *EGLNativeDisplayType;
+typedef void *EGLDisplay;
+
+typedef void spice_qxl_gl_setup_p(QXLInstance *instance, EGLDisplay egl_display);
+typedef EGLDisplay epoxy_eglGetDisplay_p(EGLNativeDisplayType display_id);
+typedef int spice_server_add_interface_p(SpiceServer *reds, SpiceBaseInstance *sin);
+typedef struct gbm_device *gbm_create_device_p(int fd);
+
+extern epoxy_eglGetDisplay_p *epoxy_eglGetDisplay;
+
+//variables
+//
+static epoxy_eglGetDisplay_p *old_epoxy_eglGetDisplay = NULL;
+static EGLDisplay saved_display = NULL;
+#define MAX_INSTANCES 4
+static QXLInstance *instances[MAX_INSTANCES];
+
+#define GET_FUNC(name, ptr, dl) name ## _p *ptr = (name ## _p *) dlsym(dl, #name)
+#define GET_FUNC_DEFAULT(name, ptr) GET_FUNC(name, ptr, RTLD_DEFAULT)
+#define GET_FUNC_NEXT(name, ptr) GET_FUNC(name, ptr, RTLD_NEXT)
+
+// implementation
+//
+static void
+add_display(QXLInstance *qxl)
+{
+ int i;
+ for (i = 0; i < MAX_INSTANCES; ++i) {
+ if (!instances[i]) {
+ instances[i] = qxl;
+ break;
+ }
+ }
+}
+
+static void
+set_saved_display(EGLDisplay display)
+{
+ if (!display || display == saved_display)
+ return;
+
+ saved_display = display;
+ GET_FUNC_DEFAULT(spice_qxl_gl_setup, qxl_setup);
+ // send to all instances saved
+ int i;
+ for (i = 0; i < MAX_INSTANCES; ++i) {
+ if (!instances[i])
+ continue;
+ qxl_setup(instances[i], saved_display);
+ instances[i] = NULL;
+ }
+}
+
+// capture QXL interface creations
+int
+spice_server_add_interface(SpiceServer *reds, SpiceBaseInstance *sin)
+{
+ const SpiceBaseInterface *interface = sin->sif;
+ GET_FUNC_NEXT(spice_server_add_interface, add_interface);
+ if (strcmp(interface->type, SPICE_INTERFACE_QXL) != 0)
+ return add_interface(reds, sin);
+
+ int res = add_interface(reds, sin);
+ if (res >= 0 && saved_display) {
+ GET_FUNC_DEFAULT(spice_qxl_gl_setup, qxl_setup);
+ qxl_setup((QXLInstance *) sin, saved_display);
+ return res;
+ }
+ if (res >= 0)
+ add_display((QXLInstance *) sin);
+ return res;
+}
+
+static EGLDisplay
+epoxy_eglGetDisplay_replace(EGLNativeDisplayType display_id)
+{
+ // save last display we got
+ EGLDisplay display = old_epoxy_eglGetDisplay(display_id);
+ set_saved_display(display);
+ return display;
+}
+
+struct gbm_device *
+gbm_create_device(int fd)
+{
+ // replace epoxy_eglGetDisplay
+ if (!old_epoxy_eglGetDisplay) {
+ old_epoxy_eglGetDisplay = epoxy_eglGetDisplay;
+ epoxy_eglGetDisplay = epoxy_eglGetDisplay_replace;
+ }
+
+ // get old function
+ GET_FUNC_NEXT(gbm_create_device, create_device);
+
+ // call old function
+ return create_device(fd);
+}