egl: Implement libwayland-egl
[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 <xf86drm.h>
16
17 #include "wayland-egl.h"
18 #include "wayland-egl-priv.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->device_name = NULL;
106 egl_display->authenticated = false;
107
108 egl_display->glFlush = (void (*)(void)) get_flush_address();
109
110 wl_display_add_global_listener(display, wl_display_handle_global,
111 egl_display);
112
113 return egl_display;
114 }
115
116 WL_EGL_EXPORT void
117 wl_egl_display_destroy(struct wl_egl_display *egl_display)
118 {
119
120 free(egl_display->device_name);
121 close(egl_display->fd);
122
123 wl_drm_destroy(egl_display->drm);
124
125 free(egl_display);
126 }
127
128 WL_EGL_EXPORT void
129 wl_egl_window_resize(struct wl_egl_window *egl_window,
130 int width, int height,
131 int dx, int dy)
132 {
133 egl_window->width = width;
134 egl_window->height = height;
135 egl_window->dx = dx;
136 egl_window->dy = dy;
137 }
138
139 WL_EGL_EXPORT struct wl_egl_window *
140 wl_egl_window_create(struct wl_surface *surface,
141 int width, int height,
142 struct wl_visual *visual)
143 {
144 struct wl_egl_window *egl_window;
145
146 egl_window = malloc(sizeof *egl_window);
147 if (!egl_window)
148 return NULL;
149
150 egl_window->surface = surface;
151 egl_window->visual = visual;
152 wl_egl_window_resize(egl_window, width, height, 0, 0);
153 egl_window->attached_width = 0;
154 egl_window->attached_height = 0;
155
156 return egl_window;
157 }
158
159 WL_EGL_EXPORT void
160 wl_egl_window_destroy(struct wl_egl_window *egl_window)
161 {
162 free(egl_window);
163 }
164
165 WL_EGL_EXPORT void
166 wl_egl_window_get_attached_size(struct wl_egl_window *egl_window,
167 int *width, int *height)
168 {
169 if (width)
170 *width = egl_window->attached_width;
171 if (height)
172 *height = egl_window->attached_height;
173 }
174
175 WL_EGL_EXPORT struct wl_egl_pixmap *
176 wl_egl_pixmap_create(struct wl_egl_display *egl_display,
177 int width, int height,
178 struct wl_visual *visual, uint32_t flags)
179 {
180 struct wl_egl_pixmap *egl_pixmap;
181
182 egl_pixmap = malloc(sizeof *egl_pixmap);
183 if (egl_pixmap == NULL)
184 return NULL;
185
186 egl_pixmap->display = egl_display;
187 egl_pixmap->width = width;
188 egl_pixmap->height = height;
189 egl_pixmap->visual = visual;
190 egl_pixmap->name = 0;
191 egl_pixmap->stride = 0;
192
193 egl_pixmap->destroy = NULL;
194
195 return egl_pixmap;
196 }
197
198 WL_EGL_EXPORT void
199 wl_egl_pixmap_destroy(struct wl_egl_pixmap *egl_pixmap)
200 {
201 if (egl_pixmap->destroy)
202 egl_pixmap->destroy(egl_pixmap);
203 free(egl_pixmap);
204 }
205
206 WL_EGL_EXPORT struct wl_buffer *
207 wl_egl_pixmap_create_buffer(struct wl_egl_display *egl_display,
208 struct wl_egl_pixmap *egl_pixmap)
209 {
210 if (egl_pixmap->name == 0)
211 return NULL;
212
213 return wl_drm_create_buffer(egl_display->drm, egl_pixmap->name,
214 egl_pixmap->width, egl_pixmap->height,
215 egl_pixmap->stride, egl_pixmap->visual);
216 }
217
218 WL_EGL_EXPORT void
219 wl_egl_pixmap_flush(struct wl_egl_display *egl_display,
220 struct wl_egl_pixmap *egl_pixmap)
221 {
222 if (egl_display->glFlush)
223 egl_display->glFlush();
224 }