blob: 5c90a670a2a10ff41a9723efb9ffd52eceae297f [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øgsberg2d9cd1e2008-11-03 08:09:34 -050024 EGLConfig config;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040025 struct wl_display *wl_display;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040026 int gem_fd;
27};
28
29struct surface_data {
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040030 GLuint texture;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040031 struct wl_map map;
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -050032 EGLSurface surface;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040033};
34
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -040035static void
36repaint(void *data)
37{
38 struct egl_compositor *ec = data;
39 struct wl_surface_iterator *iterator;
40 struct wl_surface *surface;
41 struct surface_data *sd;
42 GLint vertices[12];
Kristian Høgsberg5a27f3e2008-11-02 10:55:25 -050043 GLint tex_coords[12] = { 0, 0, 0, 1, 1, 0, 1, 1 };
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -040044 GLuint indices[4] = { 0, 1, 2, 3 };
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -040045
46 iterator = wl_surface_iterator_create(ec->wl_display, 0);
47 while (wl_surface_iterator_next(iterator, &surface)) {
48 sd = wl_surface_get_data(surface);
49 if (sd == NULL)
50 continue;
51
52 vertices[0] = sd->map.x;
53 vertices[1] = sd->map.y;
54 vertices[2] = 0;
55
56 vertices[3] = sd->map.x;
57 vertices[4] = sd->map.y + sd->map.height;
58 vertices[5] = 0;
59
60 vertices[6] = sd->map.x + sd->map.width;
Kristian Høgsberg48a33ba2008-10-12 12:56:11 -040061 vertices[7] = sd->map.y;
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -040062 vertices[8] = 0;
63
64 vertices[9] = sd->map.x + sd->map.width;
Kristian Høgsberg48a33ba2008-10-12 12:56:11 -040065 vertices[10] = sd->map.y + sd->map.height;
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -040066 vertices[11] = 0;
67
68 glBindTexture(GL_TEXTURE_2D, sd->texture);
69 glEnable(GL_TEXTURE_2D);
70 glEnable(GL_BLEND);
Kristian Høgsberg3f59e822008-11-03 06:35:46 -050071 /* Assume pre-multiplied alpha for now, this probably
72 * needs to be a wayland visual type of thing. */
73 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -040074
75 glEnableClientState(GL_VERTEX_ARRAY);
76 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
77 glVertexPointer(3, GL_INT, 0, vertices);
78 glTexCoordPointer(2, GL_INT, 0, tex_coords);
Kristian Høgsberg48a33ba2008-10-12 12:56:11 -040079 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, indices);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -040080 }
81 wl_surface_iterator_destroy(iterator);
82
83 glFlush();
84
85 eglSwapBuffers(ec->display, ec->surface);
86}
87
Kristian Høgsberg5503bf82008-11-06 10:38:17 -050088static void
89schedule_repaint(struct egl_compositor *ec)
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -040090{
91 struct wl_event_loop *loop;
92
93 loop = wl_display_get_event_loop(ec->wl_display);
94 wl_event_loop_add_idle(loop, repaint, ec);
95}
96
Kristian Høgsberg5503bf82008-11-06 10:38:17 -050097static void
98notify_surface_create(struct wl_compositor *compositor,
99 struct wl_surface *surface)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400100{
101 struct surface_data *sd;
102
103 sd = malloc(sizeof *sd);
104 if (sd == NULL)
105 return;
106
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500107 sd->surface = EGL_NO_SURFACE;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400108 wl_surface_set_data(surface, sd);
109
110 glGenTextures(1, &sd->texture);
111}
112
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500113static void
114notify_surface_destroy(struct wl_compositor *compositor,
115 struct wl_surface *surface)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400116{
117 struct egl_compositor *ec = (struct egl_compositor *) compositor;
118 struct surface_data *sd;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400119
120 sd = wl_surface_get_data(surface);
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500121 if (sd == NULL)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400122 return;
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500123
124 if (sd->surface != EGL_NO_SURFACE)
125 eglDestroySurface(ec->display, sd->surface);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400126
127 glDeleteTextures(1, &sd->texture);
128
129 free(sd);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400130
131 schedule_repaint(ec);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400132}
133
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500134static void
135notify_surface_attach(struct wl_compositor *compositor,
136 struct wl_surface *surface, uint32_t name,
137 uint32_t width, uint32_t height, uint32_t stride)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400138{
139 struct egl_compositor *ec = (struct egl_compositor *) compositor;
140 struct surface_data *sd;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400141
142 sd = wl_surface_get_data(surface);
143 if (sd == NULL)
144 return;
145
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500146 if (sd->surface != EGL_NO_SURFACE)
147 eglDestroySurface(ec->display, sd->surface);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400148
Kristian Høgsberg56f3c712008-11-05 07:55:45 -0500149 /* FIXME: We need to use a single buffer config without depth
150 * or stencil buffers here to keep egl from creating auxillary
151 * buffers for the pixmap here. */
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500152 sd->surface = eglCreateSurfaceForName(ec->display, ec->config,
153 name, width, height, stride, NULL);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400154
155 glBindTexture(GL_TEXTURE_2D, sd->texture);
156 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
157 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
158 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
159 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500160 eglBindTexImage(ec->display, sd->surface, GL_TEXTURE_2D);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400161
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400162 schedule_repaint(ec);
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400163}
164
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500165static void
166notify_surface_map(struct wl_compositor *compositor,
167 struct wl_surface *surface, struct wl_map *map)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400168{
169 struct egl_compositor *ec = (struct egl_compositor *) compositor;
170 struct surface_data *sd;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400171
172 sd = wl_surface_get_data(surface);
173 if (sd == NULL)
174 return;
175
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400176 sd->map = *map;
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400177
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400178 schedule_repaint(ec);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400179}
180
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500181static void
182notify_surface_copy(struct wl_compositor *compositor,
183 struct wl_surface *surface,
184 int32_t dst_x, int32_t dst_y,
185 uint32_t name, uint32_t stride,
186 int32_t x, int32_t y, int32_t width, int32_t height)
187{
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500188 struct egl_compositor *ec = (struct egl_compositor *) compositor;
189 EGLSurface src;
190 struct surface_data *sd;
191
192 sd = wl_surface_get_data(surface);
193
194 /* FIXME: glCopyPixels should work, but then we'll have to
195 * call eglMakeCurrent to set up the src and dest surfaces
196 * first. This seems cheaper, but maybe there's a better way
197 * to accomplish this. */
198
199 src = eglCreateSurfaceForName(ec->display, ec->config,
200 name, x + width, y + height, stride, NULL);
201
202 eglCopyNativeBuffers(ec->display, sd->surface, GL_FRONT_LEFT, dst_x, dst_y,
203 src, GL_FRONT_LEFT, x, y, width, height);
204 schedule_repaint(ec);
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500205}
206
207static void
208notify_surface_damage(struct wl_compositor *compositor,
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500209 struct wl_surface *surface,
210 int32_t x, int32_t y, int32_t width, int32_t height)
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500211{
212 struct egl_compositor *ec = (struct egl_compositor *) compositor;
213
214 /* FIXME: This need to take a damage region, of course. */
215 schedule_repaint(ec);
216}
217
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500218static const struct wl_compositor_interface interface = {
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400219 notify_surface_create,
220 notify_surface_destroy,
221 notify_surface_attach,
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500222 notify_surface_map,
223 notify_surface_copy,
224 notify_surface_damage
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400225};
226
227static const char gem_device[] = "/dev/dri/card0";
228
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500229WL_EXPORT struct wl_compositor *
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400230wl_compositor_create(struct wl_display *display)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400231{
232 EGLConfig configs[64];
233 EGLint major, minor, count;
234 struct egl_compositor *ec;
Kristian Høgsberge4feb562008-11-08 18:53:37 -0500235 const int width = 1280, height = 800;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400236
237 ec = malloc(sizeof *ec);
238 if (ec == NULL)
239 return NULL;
240
241 ec->base.interface = &interface;
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400242 ec->wl_display = display;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400243
Kristian Høgsbergc508d932008-10-13 22:52:42 -0400244 ec->display = eglCreateDisplayNative(gem_device, "i965");
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400245 if (ec->display == NULL) {
246 fprintf(stderr, "failed to create display\n");
247 return NULL;
248 }
249
250 if (!eglInitialize(ec->display, &major, &minor)) {
251 fprintf(stderr, "failed to initialize display\n");
252 return NULL;
253 }
254
255 if (!eglGetConfigs(ec->display, configs, ARRAY_LENGTH(configs), &count)) {
256 fprintf(stderr, "failed to get configs\n");
257 return NULL;
258 }
259
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500260 ec->config = configs[24];
261 ec->surface = eglCreateSurfaceNative(ec->display, ec->config,
Kristian Høgsbergc508d932008-10-13 22:52:42 -0400262 0, 0, width, height);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400263 if (ec->surface == NULL) {
264 fprintf(stderr, "failed to create surface\n");
265 return NULL;
266 }
267
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500268 ec->context = eglCreateContext(ec->display, ec->config, NULL, NULL);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400269 if (ec->context == NULL) {
270 fprintf(stderr, "failed to create context\n");
271 return NULL;
272 }
273
274 if (!eglMakeCurrent(ec->display, ec->surface, ec->surface, ec->context)) {
275 fprintf(stderr, "failed to make context current\n");
276 return NULL;
277 }
278
279 glViewport(0, 0, width, height);
280 glMatrixMode(GL_PROJECTION);
281 glLoadIdentity();
282 glOrtho(0, width, height, 0, 0, 1000.0);
283 glMatrixMode(GL_MODELVIEW);
Kristian Høgsberga234e702008-10-11 22:13:51 -0400284 glClearColor(0.0, 0.05, 0.2, 0.0);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400285
286 ec->gem_fd = open(gem_device, O_RDWR);
287 if (ec->gem_fd < 0) {
288 fprintf(stderr, "failed to open drm device\n");
289 return NULL;
290 }
291
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400292 schedule_repaint(ec);
293
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400294 return &ec->base;
295}