1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
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);
}
|