egl: Add EGL_WL_bind_wayland_display
[mesa.git] / src / egl / wayland / wayland-egl.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <stdbool.h>
5 #include <errno.h>
6
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <unistd.h>
11
12 #include <dlfcn.h>
13
14 #include <wayland-client.h>
15 #include "wayland-egl.h"
16 #include "wayland-egl-priv.h"
17 #include "wayland-drm-client-protocol.h"
18 #include <xf86drm.h>
19
20 static void
21 drm_handle_device(void *data, struct wl_drm *drm, const char *device)
22 {
23 struct wl_egl_display *egl_display = data;
24 drm_magic_t magic;
25
26 egl_display->device_name = strdup(device);
27
28 egl_display->fd = open(egl_display->device_name, O_RDWR);
29
30 if (egl_display->fd == -1) {
31 fprintf(stderr, "wayland-egl: could not open %s (%s)",
32 egl_display->device_name, strerror(errno));
33 return;
34 }
35 drmGetMagic(egl_display->fd, &magic);
36 wl_drm_authenticate(egl_display->drm, magic);
37 }
38
39 static void
40 drm_handle_authenticated(void *data, struct wl_drm *drm)
41 {
42 struct wl_egl_display *egl_display = data;
43
44 egl_display->authenticated = true;
45 }
46
47 static const struct wl_drm_listener drm_listener = {
48 drm_handle_device,
49 drm_handle_authenticated
50 };
51
52 static void
53 wl_display_handle_global(struct wl_display *display, uint32_t id,
54 const char *interface, uint32_t version, void *data)
55 {
56 struct wl_egl_display *egl_display = data;
57
58 if (strcmp(interface, "drm") == 0) {
59 egl_display->drm = wl_drm_create(display, id);
60 wl_drm_add_listener(egl_display->drm, &drm_listener,
61 egl_display);
62 }
63 }
64
65 /* stolen from egl_dri2:dri2_load() */
66 static void *
67 get_flush_address() {
68 void *handle;
69 void *(*get_proc_address)(const char *procname);
70
71 handle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
72 if (handle) {
73 get_proc_address = (void* (*)(const char *))
74 dlsym(handle, "_glapi_get_proc_address");
75 /* no need to keep a reference */
76 dlclose(handle);
77 }
78
79 /*
80 * If glapi is not available, loading DRI drivers will fail. Ideally, we
81 * should load one of libGL, libGLESv1_CM, or libGLESv2 and go on. But if
82 * the app has loaded another one of them with RTLD_LOCAL, there may be
83 * unexpected behaviors later because there will be two copies of glapi
84 * (with global variables of the same names!) in the memory.
85 */
86 if (!get_proc_address) {
87 fprintf(stderr, "failed to find _glapi_get_proc_address");
88 return NULL;
89 }
90
91 return get_proc_address("glFlush");
92 }
93
94 WL_EGL_EXPORT struct wl_egl_display *
95 wl_egl_display_create(struct wl_display *display)
96 {
97 struct wl_egl_display *egl_display;
98
99 egl_display = malloc(sizeof *egl_display);
100 if (!egl_display)
101 return NULL;
102
103 egl_display->display = display;
104 egl_display->drm = NULL;
105 egl_display->fd = -1;
106 egl_display->device_name = NULL;
107 egl_display->authenticated = false;
108
109 egl_display->glFlush = (void (*)(void)) get_flush_address();
110
111 wl_display_add_global_listener(display, wl_display_handle_global,
112 egl_display);
113
114 return egl_display;
115 }
116
117 WL_EGL_EXPORT void
118 wl_egl_display_destroy(struct wl_egl_display *egl_display)
119 {
120
121 free(egl_display->device_name);
122 close(egl_display->fd);
123
124 wl_drm_destroy(egl_display->drm);
125
126 free(egl_display);
127 }
128
129 WL_EGL_EXPORT void
130 wl_egl_window_resize(struct wl_egl_window *egl_window,
131 int width, int height,
132 int dx, int dy)
133 {
134 egl_window->width = width;
135 egl_window->height = height;
136 egl_window->dx = dx;
137 egl_window->dy = dy;
138 }
139
140 WL_EGL_EXPORT struct wl_egl_window *
141 wl_egl_window_create(struct wl_egl_display *egl_display,
142 struct wl_surface *surface,
143 int width, int height,
144 struct wl_visual *visual)
145 {
146 struct wl_egl_window *egl_window;
147
148 egl_window = malloc(sizeof *egl_window);
149 if (!egl_window)
150 return NULL;
151
152 egl_window->surface = surface;
153 egl_window->visual = visual;
154 wl_egl_window_resize(egl_window, width, height, 0, 0);
155 egl_window->attached_width = 0;
156 egl_window->attached_height = 0;
157
158 return egl_window;
159 }
160
161 WL_EGL_EXPORT void
162 wl_egl_window_destroy(struct wl_egl_window *egl_window)
163 {
164 free(egl_window);
165 }
166
167 WL_EGL_EXPORT void
168 wl_egl_window_get_attached_size(struct wl_egl_window *egl_window,
169 int *width, int *height)
170 {
171 if (width)
172 *width = egl_window->attached_width;
173 if (height)
174 *height = egl_window->attached_height;
175 }
176
177 WL_EGL_EXPORT struct wl_egl_pixmap *
178 wl_egl_pixmap_create(struct wl_egl_display *egl_display,
179 int width, int height,
180 struct wl_visual *visual, uint32_t flags)
181 {
182 struct wl_egl_pixmap *egl_pixmap;
183
184 egl_pixmap = malloc(sizeof *egl_pixmap);
185 if (egl_pixmap == NULL)
186 return NULL;
187
188 egl_pixmap->display = egl_display;
189 egl_pixmap->width = width;
190 egl_pixmap->height = height;
191 egl_pixmap->visual = visual;
192 egl_pixmap->name = 0;
193 egl_pixmap->stride = 0;
194
195 egl_pixmap->destroy = NULL;
196
197 return egl_pixmap;
198 }
199
200 WL_EGL_EXPORT void
201 wl_egl_pixmap_destroy(struct wl_egl_pixmap *egl_pixmap)
202 {
203 if (egl_pixmap->destroy)
204 egl_pixmap->destroy(egl_pixmap);
205 free(egl_pixmap);
206 }
207
208 WL_EGL_EXPORT struct wl_buffer *
209 wl_egl_pixmap_create_buffer(struct wl_egl_display *egl_display,
210 struct wl_egl_pixmap *egl_pixmap)
211 {
212 if (egl_pixmap->name == 0)
213 return NULL;
214
215 return wl_drm_create_buffer(egl_display->drm, egl_pixmap->name,
216 egl_pixmap->width, egl_pixmap->height,
217 egl_pixmap->stride, egl_pixmap->visual);
218 }
219
220 WL_EGL_EXPORT void
221 wl_egl_pixmap_flush(struct wl_egl_display *egl_display,
222 struct wl_egl_pixmap *egl_pixmap)
223 {
224 if (egl_display->glFlush)
225 egl_display->glFlush();
226 }