blob: c6180155af9b741c56cc454b718450cd30c23ea4 [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>
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -05005#include <stdarg.h>
Kristian Høgsberg16eb6752008-10-08 22:51:32 -04006#include <i915_drm.h>
7#include <sys/ioctl.h>
8#include <sys/mman.h>
9#include <fcntl.h>
10#include <unistd.h>
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -050011#include <signal.h>
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -050012#include <cairo.h>
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -050013#include <png.h>
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040014
15#include "wayland.h"
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -050016#include "cairo-util.h"
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040017
18#include <GL/gl.h>
19#include <eagle.h>
20
21#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
22
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -050023struct pointer {
24 struct wl_map map;
25 GLuint texture;
26};
27
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040028struct egl_compositor {
29 struct wl_compositor base;
30 EGLDisplay display;
31 EGLSurface surface;
32 EGLContext context;
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -050033 EGLConfig config;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040034 struct wl_display *wl_display;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040035 int gem_fd;
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -050036 int width, height;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -050037 struct pointer *pointer;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040038};
39
40struct surface_data {
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040041 GLuint texture;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040042 struct wl_map map;
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -050043 EGLSurface surface;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040044};
45
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -050046static int do_screenshot;
47
48static void
49handle_sigusr1(int s)
50{
51 do_screenshot = 1;
52}
53
54static void
55die(const char *msg, ...)
56{
57 va_list ap;
58
59 va_start (ap, msg);
60 vfprintf(stderr, msg, ap);
61 va_end (ap);
62
63 exit(EXIT_FAILURE);
64}
65
66static void
67stdio_write_func (png_structp png, png_bytep data, png_size_t size)
68{
69 FILE *fp;
70 size_t ret;
71
72 fp = png_get_io_ptr (png);
73 while (size) {
74 ret = fwrite (data, 1, size, fp);
75 size -= ret;
76 data += ret;
77 if (size && ferror (fp))
78 die("write: %m\n");
79 }
80}
81
82static void
83png_simple_output_flush_fn (png_structp png_ptr)
84{
85}
86
87static void
88png_simple_error_callback (png_structp png,
89 png_const_charp error_msg)
90{
91 die("png error: %s\n", error_msg);
92}
93
94static void
95png_simple_warning_callback (png_structp png,
96 png_const_charp error_msg)
97{
98 fprintf(stderr, "png warning: %s\n", error_msg);
99}
100
101static void
102convert_pixels(png_structp png, png_row_infop row_info, png_bytep data)
103{
104 unsigned int i;
105
106 for (i = 0; i < row_info->rowbytes; i += 4) {
107 uint8_t *b = &data[i];
108 uint32_t pixel;
109
110 memcpy (&pixel, b, sizeof (uint32_t));
111 b[0] = (pixel & 0xff0000) >> 16;
112 b[1] = (pixel & 0x00ff00) >> 8;
113 b[2] = (pixel & 0x0000ff) >> 0;
114 b[3] = 0;
115 }
116}
117
118static void
119screenshot(struct egl_compositor *ec)
120{
121 png_struct *png;
122 png_info *info;
123 png_byte **volatile rows = NULL;
124 png_color_16 white;
125 int depth, i;
126 FILE *fp;
127 uint8_t *data;
128 GLuint stride;
129 static const char filename[] = "wayland-screenshot.png";
130
131 data = eglReadBuffer(ec->display, ec->surface, GL_FRONT_LEFT, &stride);
132 if (data == NULL)
133 die("eglReadBuffer failed\n");
134 rows = malloc(ec->height * sizeof rows[0]);
135 if (rows == NULL)
136 die("malloc failed\n");
137
138 for (i = 0; i < ec->height; i++)
139 rows[i] = (png_byte *) data + i * stride;
140
141 png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
142 png_simple_error_callback,
143 png_simple_warning_callback);
144 if (png == NULL)
145 die("png_create_write_struct failed\n");
146
147 info = png_create_info_struct(png);
148 if (info == NULL)
149 die("png_create_info_struct failed\n");
150
151 fp = fopen(filename, "w");
152 if (fp == NULL)
153 die("fopen failed: %m\n");
154
155 png_set_write_fn(png, fp, stdio_write_func, png_simple_output_flush_fn);
156
157 depth = 8;
158 png_set_IHDR(png, info,
159 ec->width,
160 ec->height, depth,
161 PNG_COLOR_TYPE_RGB,
162 PNG_INTERLACE_NONE,
163 PNG_COMPRESSION_TYPE_DEFAULT,
164 PNG_FILTER_TYPE_DEFAULT);
165
166 white.gray = (1 << depth) - 1;
167 white.red = white.blue = white.green = white.gray;
168 png_set_bKGD(png, info, &white);
169 png_write_info (png, info);
170 png_set_write_user_transform_fn(png, convert_pixels);
171
172 png_set_filler(png, 0, PNG_FILLER_AFTER);
173 png_write_image(png, rows);
174 png_write_end(png, info);
175
176 png_destroy_write_struct(&png, &info);
177 fclose(fp);
178 free(rows);
179 free(data);
180}
181
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400182static void
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500183pointer_path(cairo_t *cr, int x, int y)
184{
185 const int end = 3, tx = 4, ty = 12, dx = 5, dy = 10;
186 const int width = 16, height = 16;
187
188 cairo_move_to(cr, x, y);
189 cairo_line_to(cr, x + tx, y + ty);
190 cairo_line_to(cr, x + dx, y + dy);
191 cairo_line_to(cr, x + width - end, y + height);
192 cairo_line_to(cr, x + width, y + height - end);
193 cairo_line_to(cr, x + dy, y + dx);
194 cairo_line_to(cr, x + ty, y + tx);
195 cairo_close_path(cr);
196}
197
198static struct pointer *
199pointer_create(int x, int y, int width, int height)
200{
201 const int hotspot_x = 16, hotspot_y = 16;
202 struct pointer *pointer;
203 cairo_surface_t *surface;
204 cairo_t *cr;
205 int stride;
206 void *data;
207
208 pointer = malloc(sizeof *pointer);
209 if (pointer == NULL)
210 return NULL;
211
212 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
213 width, height);
214
215 cr = cairo_create(surface);
216 pointer_path(cr, hotspot_x + 5, hotspot_y + 4);
217 cairo_set_line_width (cr, 2);
218 cairo_set_source_rgb(cr, 0, 0, 0);
219 cairo_stroke_preserve(cr);
220 cairo_fill(cr);
221 blur_surface(surface, width);
222
223 pointer_path(cr, hotspot_x, hotspot_y);
224 cairo_stroke_preserve(cr);
225 cairo_set_source_rgb(cr, 1, 1, 1);
226 cairo_fill(cr);
227 cairo_destroy(cr);
228
229 stride = cairo_image_surface_get_stride(surface);
230 data = cairo_image_surface_get_data(surface);
231
232 glGenTextures(1, &pointer->texture);
233 glBindTexture(GL_TEXTURE_2D, pointer->texture);
234 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
235 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
236 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
237 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
238 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
239 GL_BGRA, GL_UNSIGNED_BYTE, data);
240
241 cairo_surface_destroy(surface);
242
243 pointer->map.x = x;
244 pointer->map.y = y;
245 pointer->map.width = width;
246 pointer->map.height = height;
247
248 return pointer;
249}
250
251static void
252pointer_destroy(struct pointer *pointer)
253{
254 glDeleteTextures(1, &pointer->texture);
255 free(pointer);
256}
257
258static void
259draw_surface(struct wl_map *map, GLuint texture)
260{
261 GLint vertices[12];
262 GLint tex_coords[12] = { 0, 0, 0, 1, 1, 0, 1, 1 };
263 GLuint indices[4] = { 0, 1, 2, 3 };
264
265 vertices[0] = map->x;
266 vertices[1] = map->y;
267 vertices[2] = 0;
268
269 vertices[3] = map->x;
270 vertices[4] = map->y + map->height;
271 vertices[5] = 0;
272
273 vertices[6] = map->x + map->width;
274 vertices[7] = map->y;
275 vertices[8] = 0;
276
277 vertices[9] = map->x + map->width;
278 vertices[10] = map->y + map->height;
279 vertices[11] = 0;
280
281 glBindTexture(GL_TEXTURE_2D, texture);
282 glEnable(GL_TEXTURE_2D);
283 glEnable(GL_BLEND);
284 /* Assume pre-multiplied alpha for now, this probably
285 * needs to be a wayland visual type of thing. */
286 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
287
288 glEnableClientState(GL_VERTEX_ARRAY);
289 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
290 glVertexPointer(3, GL_INT, 0, vertices);
291 glTexCoordPointer(2, GL_INT, 0, tex_coords);
292 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, indices);
293}
294
295static void
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400296repaint(void *data)
297{
298 struct egl_compositor *ec = data;
299 struct wl_surface_iterator *iterator;
300 struct wl_surface *surface;
301 struct surface_data *sd;
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400302
303 iterator = wl_surface_iterator_create(ec->wl_display, 0);
304 while (wl_surface_iterator_next(iterator, &surface)) {
305 sd = wl_surface_get_data(surface);
306 if (sd == NULL)
307 continue;
308
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500309 draw_surface(&sd->map, sd->texture);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400310 }
311 wl_surface_iterator_destroy(iterator);
312
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500313 draw_surface(&ec->pointer->map, ec->pointer->texture);
314
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400315 eglSwapBuffers(ec->display, ec->surface);
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500316
317 if (do_screenshot) {
318 glFinish();
319 /* FIXME: There's a bug somewhere so that glFinish()
320 * doesn't actually wait for all rendering to finish.
321 * I *think* it's fixed in upstream drm, but for my
322 * kernel I need this sleep now... */
323 sleep(1);
324 screenshot(ec);
325 do_screenshot = 0;
326 }
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400327}
328
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500329static void
330schedule_repaint(struct egl_compositor *ec)
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400331{
332 struct wl_event_loop *loop;
333
334 loop = wl_display_get_event_loop(ec->wl_display);
335 wl_event_loop_add_idle(loop, repaint, ec);
336}
337
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500338static void
339notify_surface_create(struct wl_compositor *compositor,
340 struct wl_surface *surface)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400341{
342 struct surface_data *sd;
343
344 sd = malloc(sizeof *sd);
345 if (sd == NULL)
346 return;
347
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500348 sd->surface = EGL_NO_SURFACE;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400349 wl_surface_set_data(surface, sd);
350
351 glGenTextures(1, &sd->texture);
352}
353
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500354static void
355notify_surface_destroy(struct wl_compositor *compositor,
356 struct wl_surface *surface)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400357{
358 struct egl_compositor *ec = (struct egl_compositor *) compositor;
359 struct surface_data *sd;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400360
361 sd = wl_surface_get_data(surface);
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500362 if (sd == NULL)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400363 return;
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500364
365 if (sd->surface != EGL_NO_SURFACE)
366 eglDestroySurface(ec->display, sd->surface);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400367
368 glDeleteTextures(1, &sd->texture);
369
370 free(sd);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400371
372 schedule_repaint(ec);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400373}
374
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500375static void
376notify_surface_attach(struct wl_compositor *compositor,
377 struct wl_surface *surface, uint32_t name,
378 uint32_t width, uint32_t height, uint32_t stride)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400379{
380 struct egl_compositor *ec = (struct egl_compositor *) compositor;
381 struct surface_data *sd;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400382
383 sd = wl_surface_get_data(surface);
384 if (sd == NULL)
385 return;
386
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500387 if (sd->surface != EGL_NO_SURFACE)
388 eglDestroySurface(ec->display, sd->surface);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400389
Kristian Høgsberg56f3c712008-11-05 07:55:45 -0500390 /* FIXME: We need to use a single buffer config without depth
391 * or stencil buffers here to keep egl from creating auxillary
392 * buffers for the pixmap here. */
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500393 sd->surface = eglCreateSurfaceForName(ec->display, ec->config,
394 name, width, height, stride, NULL);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400395
396 glBindTexture(GL_TEXTURE_2D, sd->texture);
397 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
398 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
399 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
400 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500401 eglBindTexImage(ec->display, sd->surface, GL_TEXTURE_2D);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400402
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400403 schedule_repaint(ec);
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400404}
405
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500406static void
407notify_surface_map(struct wl_compositor *compositor,
408 struct wl_surface *surface, struct wl_map *map)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400409{
410 struct egl_compositor *ec = (struct egl_compositor *) compositor;
411 struct surface_data *sd;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400412
413 sd = wl_surface_get_data(surface);
414 if (sd == NULL)
415 return;
416
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400417 sd->map = *map;
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400418
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400419 schedule_repaint(ec);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400420}
421
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500422static void
423notify_surface_copy(struct wl_compositor *compositor,
424 struct wl_surface *surface,
425 int32_t dst_x, int32_t dst_y,
426 uint32_t name, uint32_t stride,
427 int32_t x, int32_t y, int32_t width, int32_t height)
428{
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500429 struct egl_compositor *ec = (struct egl_compositor *) compositor;
430 EGLSurface src;
431 struct surface_data *sd;
432
433 sd = wl_surface_get_data(surface);
434
435 /* FIXME: glCopyPixels should work, but then we'll have to
436 * call eglMakeCurrent to set up the src and dest surfaces
437 * first. This seems cheaper, but maybe there's a better way
438 * to accomplish this. */
439
440 src = eglCreateSurfaceForName(ec->display, ec->config,
441 name, x + width, y + height, stride, NULL);
442
443 eglCopyNativeBuffers(ec->display, sd->surface, GL_FRONT_LEFT, dst_x, dst_y,
444 src, GL_FRONT_LEFT, x, y, width, height);
445 schedule_repaint(ec);
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500446}
447
448static void
449notify_surface_damage(struct wl_compositor *compositor,
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500450 struct wl_surface *surface,
451 int32_t x, int32_t y, int32_t width, int32_t height)
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500452{
453 struct egl_compositor *ec = (struct egl_compositor *) compositor;
454
455 /* FIXME: This need to take a damage region, of course. */
456 schedule_repaint(ec);
457}
458
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500459static void
460notify_pointer_motion(struct wl_compositor *compositor,
461 struct wl_object *source, int x, int y)
462{
463 struct egl_compositor *ec = (struct egl_compositor *) compositor;
464
465 ec->pointer->map.x = x;
466 ec->pointer->map.y = y;
467 schedule_repaint(ec);
468}
469
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500470static const struct wl_compositor_interface interface = {
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400471 notify_surface_create,
472 notify_surface_destroy,
473 notify_surface_attach,
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500474 notify_surface_map,
475 notify_surface_copy,
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500476 notify_surface_damage,
477 notify_pointer_motion
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400478};
479
480static const char gem_device[] = "/dev/dri/card0";
481
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500482WL_EXPORT struct wl_compositor *
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400483wl_compositor_create(struct wl_display *display)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400484{
485 EGLConfig configs[64];
486 EGLint major, minor, count;
487 struct egl_compositor *ec;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400488
489 ec = malloc(sizeof *ec);
490 if (ec == NULL)
491 return NULL;
492
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500493 ec->width = 1280;
494 ec->height = 800;
495
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400496 ec->base.interface = &interface;
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400497 ec->wl_display = display;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400498
Kristian Høgsbergc508d932008-10-13 22:52:42 -0400499 ec->display = eglCreateDisplayNative(gem_device, "i965");
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400500 if (ec->display == NULL) {
501 fprintf(stderr, "failed to create display\n");
502 return NULL;
503 }
504
505 if (!eglInitialize(ec->display, &major, &minor)) {
506 fprintf(stderr, "failed to initialize display\n");
507 return NULL;
508 }
509
510 if (!eglGetConfigs(ec->display, configs, ARRAY_LENGTH(configs), &count)) {
511 fprintf(stderr, "failed to get configs\n");
512 return NULL;
513 }
514
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500515 ec->config = configs[24];
516 ec->surface = eglCreateSurfaceNative(ec->display, ec->config,
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500517 0, 0, ec->width, ec->height);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400518 if (ec->surface == NULL) {
519 fprintf(stderr, "failed to create surface\n");
520 return NULL;
521 }
522
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500523 ec->context = eglCreateContext(ec->display, ec->config, NULL, NULL);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400524 if (ec->context == NULL) {
525 fprintf(stderr, "failed to create context\n");
526 return NULL;
527 }
528
529 if (!eglMakeCurrent(ec->display, ec->surface, ec->surface, ec->context)) {
530 fprintf(stderr, "failed to make context current\n");
531 return NULL;
532 }
533
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500534 glViewport(0, 0, ec->width, ec->height);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400535 glMatrixMode(GL_PROJECTION);
536 glLoadIdentity();
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500537 glOrtho(0, ec->width, ec->height, 0, 0, 1000.0);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400538 glMatrixMode(GL_MODELVIEW);
Kristian Høgsberga234e702008-10-11 22:13:51 -0400539 glClearColor(0.0, 0.05, 0.2, 0.0);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400540
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500541 ec->pointer = pointer_create(100, 100, 64, 64);
542
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400543 ec->gem_fd = open(gem_device, O_RDWR);
544 if (ec->gem_fd < 0) {
545 fprintf(stderr, "failed to open drm device\n");
546 return NULL;
547 }
548
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500549 signal(SIGUSR1, handle_sigusr1);
550
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400551 schedule_repaint(ec);
552
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400553 return &ec->base;
554}