blob: 6d8404e297370f42daa7317e7defe8524773756a [file] [log] [blame]
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04001#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <stdint.h>
5#include <i915_drm.h>
6#include <sys/ioctl.h>
7#include <sys/mman.h>
8#include <fcntl.h>
9#include <unistd.h>
10#include <linux/fb.h>
11
12#include "wayland.h"
13
14#include <GL/gl.h>
15#include <eagle.h>
16
17#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
18
19struct egl_compositor {
20 struct wl_compositor base;
21 EGLDisplay display;
22 EGLSurface surface;
23 EGLContext context;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040024 struct wl_display *wl_display;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040025 int gem_fd;
26};
27
28struct surface_data {
29 uint32_t handle;
30 int32_t width, height, stride;
31 GLuint texture;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040032 struct wl_map map;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040033};
34
35void notify_surface_create(struct wl_compositor *compositor,
36 struct wl_surface *surface)
37{
38 struct surface_data *sd;
39
40 sd = malloc(sizeof *sd);
41 if (sd == NULL)
42 return;
43
44 sd->handle = 0;
45 wl_surface_set_data(surface, sd);
46
47 glGenTextures(1, &sd->texture);
48}
49
50void notify_surface_destroy(struct wl_compositor *compositor,
51 struct wl_surface *surface)
52{
53 struct egl_compositor *ec = (struct egl_compositor *) compositor;
54 struct surface_data *sd;
55 struct drm_gem_close close_arg;
56 int ret;
57
58 sd = wl_surface_get_data(surface);
59 if (sd == NULL || sd->handle == 0)
60 return;
61
62 close_arg.handle = sd->handle;
63 ret = ioctl(ec->gem_fd, DRM_IOCTL_GEM_CLOSE, &close_arg);
64 if (ret != 0) {
65 fprintf(stderr, "failed to gem_close handle %d: %m\n", sd->handle);
66 }
67
68 glDeleteTextures(1, &sd->texture);
69
70 free(sd);
71}
72
73void notify_surface_attach(struct wl_compositor *compositor,
74 struct wl_surface *surface, uint32_t name,
75 uint32_t width, uint32_t height, uint32_t stride)
76{
77 struct egl_compositor *ec = (struct egl_compositor *) compositor;
78 struct surface_data *sd;
79 struct drm_gem_open open_arg;
80 struct drm_gem_close close_arg;
81 struct drm_i915_gem_pread pread;
82 void *data;
83 uint32_t size;
84 int ret;
85
86 sd = wl_surface_get_data(surface);
87 if (sd == NULL)
88 return;
89
90 if (sd->handle != 0) {
91 close_arg.handle = sd->handle;
92 ret = ioctl(ec->gem_fd, DRM_IOCTL_GEM_CLOSE, &close_arg);
93 if (ret != 0) {
94 fprintf(stderr, "failed to gem_close name %d: %m\n", name);
95 }
96 }
97
98 open_arg.name = name;
99 ret = ioctl(ec->gem_fd, DRM_IOCTL_GEM_OPEN, &open_arg);
100 if (ret != 0) {
101 fprintf(stderr, "failed to gem_open name %d, fd=%d: %m\n", name, ec->gem_fd);
102 return;
103 }
104
105 sd->handle = open_arg.handle;
106 sd->width = width;
107 sd->height = height;
108 sd->stride = stride;
109
110 size = sd->height * sd->stride;
111 data = malloc(size);
112 if (data == NULL) {
113 fprintf(stderr, "swap buffers malloc failed\n");
114 return;
115 }
116
117 pread.handle = sd->handle;
118 pread.pad = 0;
119 pread.offset = 0;
120 pread.size = size;
121 pread.data_ptr = (long) data;
122
123 if (ioctl(ec->gem_fd, DRM_IOCTL_I915_GEM_PREAD, &pread)) {
124 fprintf(stderr, "gem pread failed");
125 return;
126 }
127
128 glBindTexture(GL_TEXTURE_2D, sd->texture);
129 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
130 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
131 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
132 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
133 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
134 GL_BGRA, GL_UNSIGNED_BYTE, data);
135
136 free(data);
137}
138
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400139static void
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400140repaint(void *data)
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400141{
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400142 struct egl_compositor *ec = data;
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400143 struct wl_surface_iterator *iterator;
144 struct wl_surface *surface;
145 struct surface_data *sd;
146 GLint vertices[12];
147 GLint tex_coords[8] = { 1, 0, 1, 1, 0, 1, 0, 0 };
148 GLuint indices[4] = { 0, 1, 2, 3 };
149
150 /* This part is where we actually copy the buffer to screen.
151 * Needs to be part of the repaint loop, not called from the
152 * notify_map handler. */
153
154 glClear(GL_COLOR_BUFFER_BIT);
155
156 iterator = wl_surface_iterator_create(ec->wl_display, 0);
157 while (wl_surface_iterator_next(iterator, &surface)) {
158 sd = wl_surface_get_data(surface);
159 if (sd == NULL)
160 continue;
161
162 vertices[0] = sd->map.x;
163 vertices[1] = sd->map.y;
164 vertices[2] = 0;
165
166 vertices[3] = sd->map.x;
167 vertices[4] = sd->map.y + sd->map.height;
168 vertices[5] = 0;
169
170 vertices[6] = sd->map.x + sd->map.width;
171 vertices[7] = sd->map.y + sd->map.height;
172 vertices[8] = 0;
173
174 vertices[9] = sd->map.x + sd->map.width;
175 vertices[10] = sd->map.y;
176 vertices[11] = 0;
177
178 glBindTexture(GL_TEXTURE_2D, sd->texture);
179 glEnable(GL_TEXTURE_2D);
180 glEnable(GL_BLEND);
181 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
182
183 glEnableClientState(GL_VERTEX_ARRAY);
184 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
185 glVertexPointer(3, GL_INT, 0, vertices);
186 glTexCoordPointer(2, GL_INT, 0, tex_coords);
187 glDrawElements(GL_QUADS, 4, GL_UNSIGNED_INT, indices);
188 }
189 wl_surface_iterator_destroy(iterator);
190
191 glFlush();
192
193 eglSwapBuffers(ec->display, ec->surface);
194}
195
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400196void notify_surface_map(struct wl_compositor *compositor,
197 struct wl_surface *surface, struct wl_map *map)
198{
199 struct egl_compositor *ec = (struct egl_compositor *) compositor;
200 struct surface_data *sd;
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400201 struct wl_event_loop *loop;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400202
203 sd = wl_surface_get_data(surface);
204 if (sd == NULL)
205 return;
206
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400207 sd->map = *map;
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400208
209 loop = wl_display_get_event_loop(ec->wl_display);
210 wl_event_loop_add_idle(loop, repaint, ec);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400211}
212
213struct wl_compositor_interface interface = {
214 notify_surface_create,
215 notify_surface_destroy,
216 notify_surface_attach,
217 notify_surface_map
218};
219
220static const char gem_device[] = "/dev/dri/card0";
221
222struct wl_compositor *
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400223wl_compositor_create(struct wl_display *display)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400224{
225 EGLConfig configs[64];
226 EGLint major, minor, count;
227 struct egl_compositor *ec;
228 const int width = 800, height = 600;
229
230 ec = malloc(sizeof *ec);
231 if (ec == NULL)
232 return NULL;
233
234 ec->base.interface = &interface;
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400235 ec->wl_display = display;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400236
237 ec->display = eglCreateDisplay(gem_device, "i965");
238 if (ec->display == NULL) {
239 fprintf(stderr, "failed to create display\n");
240 return NULL;
241 }
242
243 if (!eglInitialize(ec->display, &major, &minor)) {
244 fprintf(stderr, "failed to initialize display\n");
245 return NULL;
246 }
247
248 if (!eglGetConfigs(ec->display, configs, ARRAY_LENGTH(configs), &count)) {
249 fprintf(stderr, "failed to get configs\n");
250 return NULL;
251 }
252
253 ec->surface = eglCreateSurface(ec->display, configs[24], 0, 0, width, height);
254 if (ec->surface == NULL) {
255 fprintf(stderr, "failed to create surface\n");
256 return NULL;
257 }
258
259 ec->context = eglCreateContext(ec->display, configs[24], NULL, NULL);
260 if (ec->context == NULL) {
261 fprintf(stderr, "failed to create context\n");
262 return NULL;
263 }
264
265 if (!eglMakeCurrent(ec->display, ec->surface, ec->surface, ec->context)) {
266 fprintf(stderr, "failed to make context current\n");
267 return NULL;
268 }
269
270 glViewport(0, 0, width, height);
271 glMatrixMode(GL_PROJECTION);
272 glLoadIdentity();
273 glOrtho(0, width, height, 0, 0, 1000.0);
274 glMatrixMode(GL_MODELVIEW);
275 glClearColor(0.0, 0.1, 0.3, 0.0);
276
277 ec->gem_fd = open(gem_device, O_RDWR);
278 if (ec->gem_fd < 0) {
279 fprintf(stderr, "failed to open drm device\n");
280 return NULL;
281 }
282
283 return &ec->base;
284}