blob: 68f5374cea50757d156fc879a7ab11104b0d0a5c [file] [log] [blame]
Kristian Høgsbergffd710e2008-12-02 15:15:01 -05001/*
2 * Copyright © 2008 Kristian Høgsberg
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
Kristian Høgsberg5503bf82008-11-06 10:38:17 -050023#include <stdio.h>
24#include <string.h>
25#include <stdlib.h>
26#include <stdint.h>
27#include <i915_drm.h>
28#include <sys/ioctl.h>
29#include <sys/mman.h>
30#include <fcntl.h>
31#include <unistd.h>
32#include <linux/fb.h>
33#include <X11/Xlib.h>
34#include <X11/keysym.h>
35#include <GL/gl.h>
36#include <GL/glx.h>
37
38#include "wayland.h"
39
40#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
41
42struct glx_compositor {
43 struct wl_compositor base;
44 Display *display;
45 GLXContext context;
46 Window window;
47 struct wl_display *wl_display;
48 int gem_fd;
49 struct wl_event_source *x_source;
50};
51
52struct surface_data {
53 GLuint texture;
54 struct wl_map map;
55};
56
57static void
58repaint(void *data)
59{
60 struct glx_compositor *gc = data;
61 struct wl_surface_iterator *iterator;
62 struct wl_surface *surface;
63 struct surface_data *sd;
64 GLint vertices[12];
65 GLint tex_coords[12] = { 0, 0, 0, 1, 1, 0, 1, 1 };
66 GLuint indices[4] = { 0, 1, 2, 3 };
67
68 iterator = wl_surface_iterator_create(gc->wl_display, 0);
69 while (wl_surface_iterator_next(iterator, &surface)) {
70 sd = wl_surface_get_data(surface);
71 if (sd == NULL)
72 continue;
73
74 vertices[0] = sd->map.x;
75 vertices[1] = sd->map.y;
76 vertices[2] = 0;
77
78 vertices[3] = sd->map.x;
79 vertices[4] = sd->map.y + sd->map.height;
80 vertices[5] = 0;
81
82 vertices[6] = sd->map.x + sd->map.width;
83 vertices[7] = sd->map.y;
84 vertices[8] = 0;
85
86 vertices[9] = sd->map.x + sd->map.width;
87 vertices[10] = sd->map.y + sd->map.height;
88 vertices[11] = 0;
89
90 glBindTexture(GL_TEXTURE_2D, sd->texture);
91 glEnable(GL_TEXTURE_2D);
92 glEnable(GL_BLEND);
93 /* Assume pre-multiplied alpha for now, this probably
94 * needs to be a wayland visual type of thing. */
95 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
96
97 glEnableClientState(GL_VERTEX_ARRAY);
98 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
99 glVertexPointer(3, GL_INT, 0, vertices);
100 glTexCoordPointer(2, GL_INT, 0, tex_coords);
101 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, indices);
102 }
103 wl_surface_iterator_destroy(iterator);
104
105 glXSwapBuffers(gc->display, gc->window);
106}
107
108static void
109schedule_repaint(struct glx_compositor *gc)
110{
111 struct wl_event_loop *loop;
112
113 loop = wl_display_get_event_loop(gc->wl_display);
114 wl_event_loop_add_idle(loop, repaint, gc);
115}
116
117static void
118notify_surface_create(struct wl_compositor *compositor,
119 struct wl_surface *surface)
120{
121 struct surface_data *sd;
122
123 sd = malloc(sizeof *sd);
124 if (sd == NULL)
125 return;
126
127 wl_surface_set_data(surface, sd);
128
129 glGenTextures(1, &sd->texture);
130}
131
132static void
133notify_surface_destroy(struct wl_compositor *compositor,
134 struct wl_surface *surface)
135{
136 struct glx_compositor *gc = (struct glx_compositor *) compositor;
137 struct surface_data *sd;
138
139 sd = wl_surface_get_data(surface);
140 if (sd == NULL)
141 return;
142
143 glDeleteTextures(1, &sd->texture);
144
145 free(sd);
146
147 schedule_repaint(gc);
148}
149
150static void
151notify_surface_attach(struct wl_compositor *compositor,
152 struct wl_surface *surface, uint32_t name,
153 uint32_t width, uint32_t height,
154 uint32_t stride)
155{
156 struct glx_compositor *gc = (struct glx_compositor *) compositor;
157 struct surface_data *sd;
158 struct drm_gem_open open_arg;
159 struct drm_gem_close close_arg;
160 struct drm_i915_gem_pread pread;
161 uint32_t size;
162 void *data;
163 int ret;
164
165 sd = wl_surface_get_data(surface);
166 if (sd == NULL)
167 return;
168
169 open_arg.name = name;
170 ret = ioctl(gc->gem_fd, DRM_IOCTL_GEM_OPEN, &open_arg);
171 if (ret != 0) {
172 fprintf(stderr,
173 "failed to gem_open name %d, fd=%d: %m\n",
174 name, gc->gem_fd);
175 return;
176 }
177
178 size = height * stride;
179 data = malloc(size);
180 if (data == NULL) {
181 fprintf(stderr, "malloc for gem_pread failed\n");
182 return;
183 }
184
185 pread.handle = open_arg.handle;
186 pread.pad = 0;
187 pread.offset = 0;
188 pread.size = size;
189 pread.data_ptr = (long) data;
190
191 if (ioctl(gc->gem_fd, DRM_IOCTL_I915_GEM_PREAD, &pread)) {
192 fprintf(stderr, "gem_pread failed");
193 return;
194 }
195
196 close_arg.handle = open_arg.handle;
197 ret = ioctl(gc->gem_fd, DRM_IOCTL_GEM_CLOSE, &close_arg);
198 if (ret != 0) {
199 fprintf(stderr, "failed to gem_close name %d: %m\n", name);
200 return;
201 }
202
203 glBindTexture(GL_TEXTURE_2D, sd->texture);
204 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
205 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
206 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
207 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
208 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
209 GL_BGRA, GL_UNSIGNED_BYTE, data);
210
211 free(data);
212
213 schedule_repaint(gc);
214}
215
216static void
217notify_surface_map(struct wl_compositor *compositor,
218 struct wl_surface *surface, struct wl_map *map)
219{
220 struct glx_compositor *gc = (struct glx_compositor *) compositor;
221 struct surface_data *sd;
222
223 sd = wl_surface_get_data(surface);
224 if (sd == NULL)
225 return;
226
227 sd->map = *map;
228
229 schedule_repaint(gc);
230}
231
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500232static void
233notify_surface_copy(struct wl_compositor *compositor,
234 struct wl_surface *surface,
235 int32_t dst_x, int32_t dst_y,
236 uint32_t name, uint32_t stride,
237 int32_t x, int32_t y, int32_t width, int32_t height)
238{
239}
240
241static void
242notify_surface_damage(struct wl_compositor *compositor,
243 struct wl_surface *surface,
244 int32_t x, int32_t y, int32_t width, int32_t height)
245{
246 struct glx_compositor *gc = (struct glx_compositor *) compositor;
247
248 schedule_repaint(gc);
249}
250
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500251static const struct wl_compositor_interface interface = {
252 notify_surface_create,
253 notify_surface_destroy,
254 notify_surface_attach,
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500255 notify_surface_map,
256 notify_surface_copy,
257 notify_surface_damage
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500258};
259
260static const char gem_device[] = "/dev/dri/card0";
261
262static void
263display_data(int fd, uint32_t mask, void *data)
264{
265 struct glx_compositor *gc = data;
266 XEvent ev;
267
268 while (XPending(gc->display) > 0) {
269 XNextEvent(gc->display, &ev);
270 /* Some day we'll do something useful with these events. */
271 }
272}
273
Kristian Høgsberg122912c2008-12-05 11:13:50 -0500274static struct glx_compositor *
275glx_compositor_create(struct wl_display *display)
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500276{
277 static int attribs[] = {
278 GLX_RGBA,
279 GLX_RED_SIZE, 1,
280 GLX_GREEN_SIZE, 1,
281 GLX_BLUE_SIZE, 1,
282 GLX_DOUBLEBUFFER,
283 GLX_DEPTH_SIZE, 1,
284 None
285 };
286 struct glx_compositor *gc;
287 const int x = 100, y = 100, width = 1024, height = 768;
288 XSetWindowAttributes attr;
289 unsigned long mask;
290 Window root;
291 XVisualInfo *visinfo;
292 int screen;
293 struct wl_event_loop *loop;
294
295 gc = malloc(sizeof *gc);
296 if (gc == NULL)
297 return NULL;
298
299 gc->base.interface = &interface;
300 gc->wl_display = display;
301 gc->display = XOpenDisplay(NULL);
302 if (gc->display == NULL) {
303 free(gc);
304 return NULL;
305 }
306
307 loop = wl_display_get_event_loop(gc->wl_display);
308 gc->x_source = wl_event_loop_add_fd(loop,
309 ConnectionNumber(gc->display),
310 WL_EVENT_READABLE,
311 display_data, gc);
312
313 screen = DefaultScreen(gc->display);
314 root = RootWindow(gc->display, screen);
315
316 visinfo = glXChooseVisual(gc->display, screen, attribs);
317
318 /* window attributes */
319 attr.background_pixel = 0;
320 attr.border_pixel = 0;
321 attr.colormap = XCreateColormap(gc->display,
322 root, visinfo->visual, AllocNone);
323 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
324 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
325 gc->window = XCreateWindow(gc->display, root, x, y, width, height,
326 0, visinfo->depth, InputOutput,
327 visinfo->visual, mask, &attr);
328
329 gc->context = glXCreateContext(gc->display, visinfo, NULL, True);
330
331 XMapWindow(gc->display, gc->window);
332 glXMakeCurrent(gc->display, gc->window, gc->context);
333
334 glViewport(0, 0, width, height);
335 glMatrixMode(GL_PROJECTION);
336 glLoadIdentity();
337 glOrtho(0, width, height, 0, 0, 1000.0);
338 glMatrixMode(GL_MODELVIEW);
339 glClearColor(0.0, 0.05, 0.2, 0.0);
340
341 gc->gem_fd = open(gem_device, O_RDWR);
342 if (gc->gem_fd < 0) {
343 fprintf(stderr, "failed to open drm device\n");
344 return NULL;
345 }
346
347 schedule_repaint(gc);
348
Kristian Høgsberg122912c2008-12-05 11:13:50 -0500349 return gc;
350}
351
352/* The plan here is to generate a random anonymous socket name and
353 * advertise that through a service on the session dbus.
354 */
355static const char socket_name[] = "\0wayland";
356
357int main(int argc, char *argv[])
358{
359 struct wl_display *display;
360 struct glx_compositor *gc;
361
362 display = wl_display_create();
363
364 gc = glx_compositor_create(display);
Kristian Høgsberg841883b2008-12-05 11:19:56 -0500365 if (gc == NULL) {
366 fprintf(stderr, "failed to create compositor\n");
367 exit(EXIT_FAILURE);
368 }
Kristian Høgsberg122912c2008-12-05 11:13:50 -0500369
370 wl_display_set_compositor(display, &gc->base);
371
Kristian Høgsbergdc0f3552008-12-07 15:22:22 -0500372 if (wl_display_add_socket(display, socket_name, sizeof socket_name)) {
Kristian Høgsberg122912c2008-12-05 11:13:50 -0500373 fprintf(stderr, "failed to add socket: %m\n");
374 exit(EXIT_FAILURE);
375 }
376
377 wl_display_run(display);
378
379 return 0;
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500380}