blob: 2c3e7e3d884735d9d9421b0bb0b934b94ce6e71a [file] [log] [blame]
Kristian Høgsberg5503bf82008-11-06 10:38:17 -05001#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#include <X11/Xlib.h>
12#include <X11/keysym.h>
13#include <GL/gl.h>
14#include <GL/glx.h>
15
16#include "wayland.h"
17
18#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
19
20struct glx_compositor {
21 struct wl_compositor base;
22 Display *display;
23 GLXContext context;
24 Window window;
25 struct wl_display *wl_display;
26 int gem_fd;
27 struct wl_event_source *x_source;
28};
29
30struct surface_data {
31 GLuint texture;
32 struct wl_map map;
33};
34
35static void
36repaint(void *data)
37{
38 struct glx_compositor *gc = data;
39 struct wl_surface_iterator *iterator;
40 struct wl_surface *surface;
41 struct surface_data *sd;
42 GLint vertices[12];
43 GLint tex_coords[12] = { 0, 0, 0, 1, 1, 0, 1, 1 };
44 GLuint indices[4] = { 0, 1, 2, 3 };
45
46 iterator = wl_surface_iterator_create(gc->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;
61 vertices[7] = sd->map.y;
62 vertices[8] = 0;
63
64 vertices[9] = sd->map.x + sd->map.width;
65 vertices[10] = sd->map.y + sd->map.height;
66 vertices[11] = 0;
67
68 glBindTexture(GL_TEXTURE_2D, sd->texture);
69 glEnable(GL_TEXTURE_2D);
70 glEnable(GL_BLEND);
71 /* 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);
74
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);
79 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, indices);
80 }
81 wl_surface_iterator_destroy(iterator);
82
83 glXSwapBuffers(gc->display, gc->window);
84}
85
86static void
87schedule_repaint(struct glx_compositor *gc)
88{
89 struct wl_event_loop *loop;
90
91 loop = wl_display_get_event_loop(gc->wl_display);
92 wl_event_loop_add_idle(loop, repaint, gc);
93}
94
95static void
96notify_surface_create(struct wl_compositor *compositor,
97 struct wl_surface *surface)
98{
99 struct surface_data *sd;
100
101 sd = malloc(sizeof *sd);
102 if (sd == NULL)
103 return;
104
105 wl_surface_set_data(surface, sd);
106
107 glGenTextures(1, &sd->texture);
108}
109
110static void
111notify_surface_destroy(struct wl_compositor *compositor,
112 struct wl_surface *surface)
113{
114 struct glx_compositor *gc = (struct glx_compositor *) compositor;
115 struct surface_data *sd;
116
117 sd = wl_surface_get_data(surface);
118 if (sd == NULL)
119 return;
120
121 glDeleteTextures(1, &sd->texture);
122
123 free(sd);
124
125 schedule_repaint(gc);
126}
127
128static void
129notify_surface_attach(struct wl_compositor *compositor,
130 struct wl_surface *surface, uint32_t name,
131 uint32_t width, uint32_t height,
132 uint32_t stride)
133{
134 struct glx_compositor *gc = (struct glx_compositor *) compositor;
135 struct surface_data *sd;
136 struct drm_gem_open open_arg;
137 struct drm_gem_close close_arg;
138 struct drm_i915_gem_pread pread;
139 uint32_t size;
140 void *data;
141 int ret;
142
143 sd = wl_surface_get_data(surface);
144 if (sd == NULL)
145 return;
146
147 open_arg.name = name;
148 ret = ioctl(gc->gem_fd, DRM_IOCTL_GEM_OPEN, &open_arg);
149 if (ret != 0) {
150 fprintf(stderr,
151 "failed to gem_open name %d, fd=%d: %m\n",
152 name, gc->gem_fd);
153 return;
154 }
155
156 size = height * stride;
157 data = malloc(size);
158 if (data == NULL) {
159 fprintf(stderr, "malloc for gem_pread failed\n");
160 return;
161 }
162
163 pread.handle = open_arg.handle;
164 pread.pad = 0;
165 pread.offset = 0;
166 pread.size = size;
167 pread.data_ptr = (long) data;
168
169 if (ioctl(gc->gem_fd, DRM_IOCTL_I915_GEM_PREAD, &pread)) {
170 fprintf(stderr, "gem_pread failed");
171 return;
172 }
173
174 close_arg.handle = open_arg.handle;
175 ret = ioctl(gc->gem_fd, DRM_IOCTL_GEM_CLOSE, &close_arg);
176 if (ret != 0) {
177 fprintf(stderr, "failed to gem_close name %d: %m\n", name);
178 return;
179 }
180
181 glBindTexture(GL_TEXTURE_2D, sd->texture);
182 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
183 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
184 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
185 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
186 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
187 GL_BGRA, GL_UNSIGNED_BYTE, data);
188
189 free(data);
190
191 schedule_repaint(gc);
192}
193
194static void
195notify_surface_map(struct wl_compositor *compositor,
196 struct wl_surface *surface, struct wl_map *map)
197{
198 struct glx_compositor *gc = (struct glx_compositor *) compositor;
199 struct surface_data *sd;
200
201 sd = wl_surface_get_data(surface);
202 if (sd == NULL)
203 return;
204
205 sd->map = *map;
206
207 schedule_repaint(gc);
208}
209
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500210static void
211notify_surface_copy(struct wl_compositor *compositor,
212 struct wl_surface *surface,
213 int32_t dst_x, int32_t dst_y,
214 uint32_t name, uint32_t stride,
215 int32_t x, int32_t y, int32_t width, int32_t height)
216{
217}
218
219static void
220notify_surface_damage(struct wl_compositor *compositor,
221 struct wl_surface *surface,
222 int32_t x, int32_t y, int32_t width, int32_t height)
223{
224 struct glx_compositor *gc = (struct glx_compositor *) compositor;
225
226 schedule_repaint(gc);
227}
228
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500229static const struct wl_compositor_interface interface = {
230 notify_surface_create,
231 notify_surface_destroy,
232 notify_surface_attach,
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500233 notify_surface_map,
234 notify_surface_copy,
235 notify_surface_damage
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500236};
237
238static const char gem_device[] = "/dev/dri/card0";
239
240static void
241display_data(int fd, uint32_t mask, void *data)
242{
243 struct glx_compositor *gc = data;
244 XEvent ev;
245
246 while (XPending(gc->display) > 0) {
247 XNextEvent(gc->display, &ev);
248 /* Some day we'll do something useful with these events. */
249 }
250}
251
252struct wl_compositor *
253wl_compositor_create(struct wl_display *display)
254{
255 static int attribs[] = {
256 GLX_RGBA,
257 GLX_RED_SIZE, 1,
258 GLX_GREEN_SIZE, 1,
259 GLX_BLUE_SIZE, 1,
260 GLX_DOUBLEBUFFER,
261 GLX_DEPTH_SIZE, 1,
262 None
263 };
264 struct glx_compositor *gc;
265 const int x = 100, y = 100, width = 1024, height = 768;
266 XSetWindowAttributes attr;
267 unsigned long mask;
268 Window root;
269 XVisualInfo *visinfo;
270 int screen;
271 struct wl_event_loop *loop;
272
273 gc = malloc(sizeof *gc);
274 if (gc == NULL)
275 return NULL;
276
277 gc->base.interface = &interface;
278 gc->wl_display = display;
279 gc->display = XOpenDisplay(NULL);
280 if (gc->display == NULL) {
281 free(gc);
282 return NULL;
283 }
284
285 loop = wl_display_get_event_loop(gc->wl_display);
286 gc->x_source = wl_event_loop_add_fd(loop,
287 ConnectionNumber(gc->display),
288 WL_EVENT_READABLE,
289 display_data, gc);
290
291 screen = DefaultScreen(gc->display);
292 root = RootWindow(gc->display, screen);
293
294 visinfo = glXChooseVisual(gc->display, screen, attribs);
295
296 /* window attributes */
297 attr.background_pixel = 0;
298 attr.border_pixel = 0;
299 attr.colormap = XCreateColormap(gc->display,
300 root, visinfo->visual, AllocNone);
301 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
302 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
303 gc->window = XCreateWindow(gc->display, root, x, y, width, height,
304 0, visinfo->depth, InputOutput,
305 visinfo->visual, mask, &attr);
306
307 gc->context = glXCreateContext(gc->display, visinfo, NULL, True);
308
309 XMapWindow(gc->display, gc->window);
310 glXMakeCurrent(gc->display, gc->window, gc->context);
311
312 glViewport(0, 0, width, height);
313 glMatrixMode(GL_PROJECTION);
314 glLoadIdentity();
315 glOrtho(0, width, height, 0, 0, 1000.0);
316 glMatrixMode(GL_MODELVIEW);
317 glClearColor(0.0, 0.05, 0.2, 0.0);
318
319 gc->gem_fd = open(gem_device, O_RDWR);
320 if (gc->gem_fd < 0) {
321 fprintf(stderr, "failed to open drm device\n");
322 return NULL;
323 }
324
325 schedule_repaint(gc);
326
327 return &gc->base;
328}