blob: 8d723b8223d5d1f3f23adc52aba1cf140fb22f43 [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øgsbergaa5b5be2008-11-21 21:31:54 -050013#include <gdk-pixbuf/gdk-pixbuf.h>
14#include <glib.h>
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -050015#include <png.h>
Kristian Høgsberg54879822008-11-23 17:07:32 -050016#include <math.h>
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040017
18#include "wayland.h"
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -050019#include "cairo-util.h"
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040020
21#include <GL/gl.h>
22#include <eagle.h>
23
24#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
25
26struct egl_compositor {
27 struct wl_compositor base;
28 EGLDisplay display;
29 EGLSurface surface;
30 EGLContext context;
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -050031 EGLConfig config;
Kristian Høgsbergf9212892008-10-11 18:40:23 -040032 struct wl_display *wl_display;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040033 int gem_fd;
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -050034 int width, height;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -050035 struct egl_surface *pointer;
36 struct egl_surface *background;
Kristian Høgsberg54879822008-11-23 17:07:32 -050037 struct egl_surface *overlay;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -040038};
39
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -050040struct egl_surface {
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 void
47die(const char *msg, ...)
48{
49 va_list ap;
50
51 va_start (ap, msg);
52 vfprintf(stderr, msg, ap);
53 va_end (ap);
54
55 exit(EXIT_FAILURE);
56}
57
58static void
59stdio_write_func (png_structp png, png_bytep data, png_size_t size)
60{
61 FILE *fp;
62 size_t ret;
63
64 fp = png_get_io_ptr (png);
65 while (size) {
66 ret = fwrite (data, 1, size, fp);
67 size -= ret;
68 data += ret;
69 if (size && ferror (fp))
70 die("write: %m\n");
71 }
72}
73
74static void
75png_simple_output_flush_fn (png_structp png_ptr)
76{
77}
78
79static void
80png_simple_error_callback (png_structp png,
81 png_const_charp error_msg)
82{
83 die("png error: %s\n", error_msg);
84}
85
86static void
87png_simple_warning_callback (png_structp png,
88 png_const_charp error_msg)
89{
90 fprintf(stderr, "png warning: %s\n", error_msg);
91}
92
93static void
94convert_pixels(png_structp png, png_row_infop row_info, png_bytep data)
95{
96 unsigned int i;
97
98 for (i = 0; i < row_info->rowbytes; i += 4) {
99 uint8_t *b = &data[i];
100 uint32_t pixel;
101
102 memcpy (&pixel, b, sizeof (uint32_t));
103 b[0] = (pixel & 0xff0000) >> 16;
104 b[1] = (pixel & 0x00ff00) >> 8;
105 b[2] = (pixel & 0x0000ff) >> 0;
106 b[3] = 0;
107 }
108}
109
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500110struct screenshooter {
111 struct wl_object base;
112 struct egl_compositor *ec;
113};
114
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500115static void
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500116screenshooter_shoot(struct wl_client *client, struct screenshooter *shooter)
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500117{
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500118 struct egl_compositor *ec = shooter->ec;
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500119 png_struct *png;
120 png_info *info;
121 png_byte **volatile rows = NULL;
122 png_color_16 white;
123 int depth, i;
124 FILE *fp;
125 uint8_t *data;
126 GLuint stride;
127 static const char filename[] = "wayland-screenshot.png";
128
129 data = eglReadBuffer(ec->display, ec->surface, GL_FRONT_LEFT, &stride);
130 if (data == NULL)
131 die("eglReadBuffer failed\n");
132 rows = malloc(ec->height * sizeof rows[0]);
133 if (rows == NULL)
134 die("malloc failed\n");
135
136 for (i = 0; i < ec->height; i++)
137 rows[i] = (png_byte *) data + i * stride;
138
139 png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
140 png_simple_error_callback,
141 png_simple_warning_callback);
142 if (png == NULL)
143 die("png_create_write_struct failed\n");
144
145 info = png_create_info_struct(png);
146 if (info == NULL)
147 die("png_create_info_struct failed\n");
148
149 fp = fopen(filename, "w");
150 if (fp == NULL)
151 die("fopen failed: %m\n");
152
153 png_set_write_fn(png, fp, stdio_write_func, png_simple_output_flush_fn);
154
155 depth = 8;
156 png_set_IHDR(png, info,
157 ec->width,
158 ec->height, depth,
159 PNG_COLOR_TYPE_RGB,
160 PNG_INTERLACE_NONE,
161 PNG_COMPRESSION_TYPE_DEFAULT,
162 PNG_FILTER_TYPE_DEFAULT);
163
164 white.gray = (1 << depth) - 1;
165 white.red = white.blue = white.green = white.gray;
166 png_set_bKGD(png, info, &white);
167 png_write_info (png, info);
168 png_set_write_user_transform_fn(png, convert_pixels);
169
170 png_set_filler(png, 0, PNG_FILLER_AFTER);
171 png_write_image(png, rows);
172 png_write_end(png, info);
173
174 png_destroy_write_struct(&png, &info);
175 fclose(fp);
176 free(rows);
177 free(data);
178}
179
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500180static const struct wl_method screenshooter_methods[] = {
181 { "shoot", screenshooter_shoot, 0, NULL }
182};
183
184static const struct wl_interface screenshooter_interface = {
185 "screenshooter", 1,
186 ARRAY_LENGTH(screenshooter_methods),
187 screenshooter_methods,
188};
189
190static struct screenshooter *
191screenshooter_create(struct egl_compositor *ec)
192{
193 struct screenshooter *shooter;
194
195 shooter = malloc(sizeof *shooter);
196 if (shooter == NULL)
197 return NULL;
198
199 shooter->base.interface = &screenshooter_interface;
200 shooter->ec = ec;
201
202 return shooter;
203};
204
Kristian Høgsberg54879822008-11-23 17:07:32 -0500205static struct egl_surface *
206egl_surface_create_from_cairo_surface(cairo_surface_t *surface,
207 int x, int y, int width, int height)
208{
209 struct egl_surface *es;
210 int stride;
211 void *data;
212
213 stride = cairo_image_surface_get_stride(surface);
214 data = cairo_image_surface_get_data(surface);
215
216 es = malloc(sizeof *es);
217 if (es == NULL)
218 return NULL;
219
220 glGenTextures(1, &es->texture);
221 glBindTexture(GL_TEXTURE_2D, es->texture);
222 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
223 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
224 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
225 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
226 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
227 GL_BGRA, GL_UNSIGNED_BYTE, data);
228
229 es->map.x = x;
230 es->map.y = y;
231 es->map.width = width;
232 es->map.height = height;
233 es->surface = EGL_NO_SURFACE;
234
235 return es;
236}
237
238static void
239egl_surface_destroy(struct egl_surface *es, struct egl_compositor *ec)
240{
241 glDeleteTextures(1, &es->texture);
242 if (es->surface != EGL_NO_SURFACE)
243 eglDestroySurface(ec->display, es->surface);
244 free(es);
245}
246
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400247static void
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500248pointer_path(cairo_t *cr, int x, int y)
249{
250 const int end = 3, tx = 4, ty = 12, dx = 5, dy = 10;
251 const int width = 16, height = 16;
252
253 cairo_move_to(cr, x, y);
254 cairo_line_to(cr, x + tx, y + ty);
255 cairo_line_to(cr, x + dx, y + dy);
256 cairo_line_to(cr, x + width - end, y + height);
257 cairo_line_to(cr, x + width, y + height - end);
258 cairo_line_to(cr, x + dy, y + dx);
259 cairo_line_to(cr, x + ty, y + tx);
260 cairo_close_path(cr);
261}
262
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500263static struct egl_surface *
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500264pointer_create(int x, int y, int width, int height)
265{
Kristian Høgsberg54879822008-11-23 17:07:32 -0500266 struct egl_surface *es;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500267 const int hotspot_x = 16, hotspot_y = 16;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500268 cairo_surface_t *surface;
269 cairo_t *cr;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500270
271 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
272 width, height);
273
274 cr = cairo_create(surface);
275 pointer_path(cr, hotspot_x + 5, hotspot_y + 4);
276 cairo_set_line_width (cr, 2);
277 cairo_set_source_rgb(cr, 0, 0, 0);
278 cairo_stroke_preserve(cr);
279 cairo_fill(cr);
280 blur_surface(surface, width);
281
282 pointer_path(cr, hotspot_x, hotspot_y);
283 cairo_stroke_preserve(cr);
284 cairo_set_source_rgb(cr, 1, 1, 1);
285 cairo_fill(cr);
286 cairo_destroy(cr);
287
Kristian Høgsberg54879822008-11-23 17:07:32 -0500288 es = egl_surface_create_from_cairo_surface(surface, x, y, width, height);
289
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500290 cairo_surface_destroy(surface);
291
Kristian Høgsberg54879822008-11-23 17:07:32 -0500292 return es;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500293}
294
295static struct egl_surface *
296background_create(const char *filename, int width, int height)
297{
298 struct egl_surface *background;
299 GdkPixbuf *pixbuf;
300 GError *error = NULL;
301 int pixbuf_width, pixbuf_height;
302 void *data;
303
304 background = malloc(sizeof *background);
305 if (background == NULL)
306 return NULL;
307
308 g_type_init();
309
310 pixbuf = gdk_pixbuf_new_from_file(filename, &error);
311 if (error != NULL) {
312 free(background);
313 return NULL;
314 }
315
316 pixbuf_width = gdk_pixbuf_get_width(pixbuf);
317 pixbuf_height = gdk_pixbuf_get_height(pixbuf);
318 data = gdk_pixbuf_get_pixels(pixbuf);
319
320 glGenTextures(1, &background->texture);
321 glBindTexture(GL_TEXTURE_2D, background->texture);
322 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
323 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
324 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
325 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
326 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, pixbuf_width, pixbuf_height, 0,
327 GL_BGR, GL_UNSIGNED_BYTE, data);
328
329 background->map.x = 0;
330 background->map.y = 0;
331 background->map.width = width;
332 background->map.height = height;
333 background->surface = EGL_NO_SURFACE;
334
335 return background;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500336}
337
338static void
Kristian Høgsberg54879822008-11-23 17:07:32 -0500339rounded_rect(cairo_t *cr, int x0, int y0, int x1, int y1, int radius)
340{
341 cairo_move_to(cr, x0, y0 + radius);
342 cairo_arc(cr, x0 + radius, y0 + radius, radius, M_PI, 3 * M_PI / 2);
343 cairo_line_to(cr, x1 - radius, y0);
344 cairo_arc(cr, x1 - radius, y0 + radius, radius, 3 * M_PI / 2, 2 * M_PI);
345 cairo_line_to(cr, x1, y1 - radius);
346 cairo_arc(cr, x1 - radius, y1 - radius, radius, 0, M_PI / 2);
347 cairo_line_to(cr, x0 + radius, y1);
348 cairo_arc(cr, x0 + radius, y1 - radius, radius, M_PI / 2, M_PI);
349 cairo_close_path(cr);
350}
351
352static void
353draw_button(cairo_t *cr, int x, int y, int width, int height, const char *text)
354{
355 cairo_pattern_t *gradient;
356 cairo_text_extents_t extents;
357 double bright = 0.15, dim = 0.02;
358 int radius = 10;
359
360 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
361 cairo_set_line_width (cr, 2);
362 rounded_rect(cr, x, y, x + width, y + height, radius);
363 cairo_set_source_rgb(cr, dim, dim, dim);
364 cairo_stroke(cr);
365 rounded_rect(cr, x + 2, y + 2, x + width, y + height, radius);
366 cairo_set_source_rgb(cr, 0.1, 0.1, 0.1);
367 cairo_stroke(cr);
368
369 rounded_rect(cr, x + 1, y + 1, x + width - 1, y + height - 1, radius - 1);
370 cairo_set_source_rgb(cr, bright, bright, bright);
371 cairo_stroke(cr);
372 rounded_rect(cr, x + 3, y + 3, x + width - 1, y + height - 1, radius - 1);
373 cairo_set_source_rgb(cr, dim, dim, dim);
374 cairo_stroke(cr);
375
376 rounded_rect(cr, x + 1, y + 1, x + width - 1, y + height - 1, radius - 1);
377 gradient = cairo_pattern_create_linear (0, y, 0, y + height);
378 cairo_pattern_add_color_stop_rgb(gradient, 0, 0.15, 0.15, 0.15);
379 cairo_pattern_add_color_stop_rgb(gradient, 0.5, 0.08, 0.08, 0.08);
380 cairo_pattern_add_color_stop_rgb(gradient, 0.5, 0.07, 0.07, 0.07);
381 cairo_pattern_add_color_stop_rgb(gradient, 1, 0.1, 0.1, 0.1);
382 cairo_set_source(cr, gradient);
383 cairo_fill(cr);
384
385 cairo_set_font_size(cr, 16);
386 cairo_text_extents(cr, text, &extents);
387 cairo_move_to(cr, x + (width - extents.width) / 2, y + (height - extents.height) / 2 - extents.y_bearing);
388 cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
389 cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
390 cairo_set_line_width (cr, 4);
391 cairo_text_path(cr, text);
392 cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
393 cairo_stroke_preserve(cr);
394 cairo_set_source_rgb(cr, 1, 1, 1);
395 cairo_fill(cr);
396}
397
398static struct egl_surface *
399overlay_create(int x, int y, int width, int height)
400{
401 struct egl_surface *es;
402 cairo_surface_t *surface;
403 cairo_t *cr;
404 int total_width, button_x, button_y;
405 const int button_width = 150;
406 const int button_height = 40;
407 const int spacing = 50;
408
409 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
410 width, height);
411
412 cr = cairo_create(surface);
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500413 cairo_set_source_rgba(cr, 0.1, 0.1, 0.1, 0.8);
Kristian Høgsberg54879822008-11-23 17:07:32 -0500414 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
415 cairo_paint(cr);
416
417 total_width = button_width * 2 + spacing;
418 button_x = (width - total_width) / 2;
419 button_y = height - button_height - 20;
420 draw_button(cr, button_x, button_y, button_width, button_height, "Previous");
421 button_x += button_width + spacing;
422 draw_button(cr, button_x, button_y, button_width, button_height, "Next");
423
424 cairo_destroy(cr);
425
426 es = egl_surface_create_from_cairo_surface(surface, x, y, width, height);
427
428 cairo_surface_destroy(surface);
429
430 return es;
431}
432
433static void
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500434draw_surface(struct egl_surface *es)
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500435{
436 GLint vertices[12];
437 GLint tex_coords[12] = { 0, 0, 0, 1, 1, 0, 1, 1 };
438 GLuint indices[4] = { 0, 1, 2, 3 };
439
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500440 vertices[0] = es->map.x;
441 vertices[1] = es->map.y;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500442 vertices[2] = 0;
443
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500444 vertices[3] = es->map.x;
445 vertices[4] = es->map.y + es->map.height;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500446 vertices[5] = 0;
447
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500448 vertices[6] = es->map.x + es->map.width;
449 vertices[7] = es->map.y;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500450 vertices[8] = 0;
451
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500452 vertices[9] = es->map.x + es->map.width;
453 vertices[10] = es->map.y + es->map.height;
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500454 vertices[11] = 0;
455
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500456 glBindTexture(GL_TEXTURE_2D, es->texture);
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500457 glEnable(GL_TEXTURE_2D);
458 glEnable(GL_BLEND);
459 /* Assume pre-multiplied alpha for now, this probably
460 * needs to be a wayland visual type of thing. */
461 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
462
463 glEnableClientState(GL_VERTEX_ARRAY);
464 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
465 glVertexPointer(3, GL_INT, 0, vertices);
466 glTexCoordPointer(2, GL_INT, 0, tex_coords);
467 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, indices);
468}
469
470static void
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400471repaint(void *data)
472{
473 struct egl_compositor *ec = data;
474 struct wl_surface_iterator *iterator;
475 struct wl_surface *surface;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500476 struct egl_surface *es;
477
478 draw_surface(ec->background);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400479
480 iterator = wl_surface_iterator_create(ec->wl_display, 0);
481 while (wl_surface_iterator_next(iterator, &surface)) {
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500482 es = wl_surface_get_data(surface);
483 if (es == NULL)
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400484 continue;
485
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500486 draw_surface(es);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400487 }
488 wl_surface_iterator_destroy(iterator);
489
Kristian Høgsberg54879822008-11-23 17:07:32 -0500490 draw_surface(ec->overlay);
491
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500492 draw_surface(ec->pointer);
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500493
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400494 eglSwapBuffers(ec->display, ec->surface);
495}
496
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500497static void
498schedule_repaint(struct egl_compositor *ec)
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400499{
500 struct wl_event_loop *loop;
501
502 loop = wl_display_get_event_loop(ec->wl_display);
503 wl_event_loop_add_idle(loop, repaint, ec);
504}
505
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500506static void
507notify_surface_create(struct wl_compositor *compositor,
508 struct wl_surface *surface)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400509{
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500510 struct egl_surface *es;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400511
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500512 es = malloc(sizeof *es);
513 if (es == NULL)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400514 return;
515
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500516 es->surface = EGL_NO_SURFACE;
517 wl_surface_set_data(surface, es);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400518
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500519 glGenTextures(1, &es->texture);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400520}
521
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500522static void
523notify_surface_destroy(struct wl_compositor *compositor,
524 struct wl_surface *surface)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400525{
526 struct egl_compositor *ec = (struct egl_compositor *) compositor;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500527 struct egl_surface *es;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400528
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500529 es = wl_surface_get_data(surface);
530 if (es == NULL)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400531 return;
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500532
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500533 egl_surface_destroy(es, ec);
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400534
535 schedule_repaint(ec);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400536}
537
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500538static void
539notify_surface_attach(struct wl_compositor *compositor,
540 struct wl_surface *surface, uint32_t name,
541 uint32_t width, uint32_t height, uint32_t stride)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400542{
543 struct egl_compositor *ec = (struct egl_compositor *) compositor;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500544 struct egl_surface *es;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400545
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500546 es = wl_surface_get_data(surface);
547 if (es == NULL)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400548 return;
549
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500550 if (es->surface != EGL_NO_SURFACE)
551 eglDestroySurface(ec->display, es->surface);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400552
Kristian Høgsberg56f3c712008-11-05 07:55:45 -0500553 /* FIXME: We need to use a single buffer config without depth
554 * or stencil buffers here to keep egl from creating auxillary
555 * buffers for the pixmap here. */
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500556 es->surface = eglCreateSurfaceForName(ec->display, ec->config,
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500557 name, width, height, stride, NULL);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400558
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500559 glBindTexture(GL_TEXTURE_2D, es->texture);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400560 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
561 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_REPEAT);
562 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
563 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500564 eglBindTexImage(ec->display, es->surface, GL_TEXTURE_2D);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400565
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400566 schedule_repaint(ec);
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400567}
568
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500569static void
570notify_surface_map(struct wl_compositor *compositor,
571 struct wl_surface *surface, struct wl_map *map)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400572{
573 struct egl_compositor *ec = (struct egl_compositor *) compositor;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500574 struct egl_surface *es;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400575
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500576 es = wl_surface_get_data(surface);
577 if (es == NULL)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400578 return;
579
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500580 es->map = *map;
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400581
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400582 schedule_repaint(ec);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400583}
584
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500585static void
586notify_surface_copy(struct wl_compositor *compositor,
587 struct wl_surface *surface,
588 int32_t dst_x, int32_t dst_y,
589 uint32_t name, uint32_t stride,
590 int32_t x, int32_t y, int32_t width, int32_t height)
591{
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500592 struct egl_compositor *ec = (struct egl_compositor *) compositor;
593 EGLSurface src;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500594 struct egl_surface *es;
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500595
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500596 es = wl_surface_get_data(surface);
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500597
598 /* FIXME: glCopyPixels should work, but then we'll have to
599 * call eglMakeCurrent to set up the src and dest surfaces
600 * first. This seems cheaper, but maybe there's a better way
601 * to accomplish this. */
602
603 src = eglCreateSurfaceForName(ec->display, ec->config,
604 name, x + width, y + height, stride, NULL);
605
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500606 eglCopyNativeBuffers(ec->display, es->surface, GL_FRONT_LEFT, dst_x, dst_y,
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500607 src, GL_FRONT_LEFT, x, y, width, height);
608 schedule_repaint(ec);
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500609}
610
611static void
612notify_surface_damage(struct wl_compositor *compositor,
Kristian Høgsberg78231c82008-11-08 15:06:01 -0500613 struct wl_surface *surface,
614 int32_t x, int32_t y, int32_t width, int32_t height)
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500615{
616 struct egl_compositor *ec = (struct egl_compositor *) compositor;
617
618 /* FIXME: This need to take a damage region, of course. */
619 schedule_repaint(ec);
620}
621
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500622static void
623notify_pointer_motion(struct wl_compositor *compositor,
624 struct wl_object *source, int x, int y)
625{
626 struct egl_compositor *ec = (struct egl_compositor *) compositor;
627
628 ec->pointer->map.x = x;
629 ec->pointer->map.y = y;
630 schedule_repaint(ec);
631}
632
Kristian Høgsberg5503bf82008-11-06 10:38:17 -0500633static const struct wl_compositor_interface interface = {
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400634 notify_surface_create,
635 notify_surface_destroy,
636 notify_surface_attach,
Kristian Høgsberg7f77bd82008-11-07 08:39:37 -0500637 notify_surface_map,
638 notify_surface_copy,
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500639 notify_surface_damage,
640 notify_pointer_motion
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400641};
642
643static const char gem_device[] = "/dev/dri/card0";
644
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500645WL_EXPORT struct wl_compositor *
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400646wl_compositor_create(struct wl_display *display)
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400647{
648 EGLConfig configs[64];
649 EGLint major, minor, count;
650 struct egl_compositor *ec;
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500651 const char *filename;
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500652 struct screenshooter *shooter;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400653
654 ec = malloc(sizeof *ec);
655 if (ec == NULL)
656 return NULL;
657
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500658 ec->width = 1280;
659 ec->height = 800;
660
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400661 ec->base.interface = &interface;
Kristian Høgsbergf9212892008-10-11 18:40:23 -0400662 ec->wl_display = display;
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400663
Kristian Høgsbergc508d932008-10-13 22:52:42 -0400664 ec->display = eglCreateDisplayNative(gem_device, "i965");
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400665 if (ec->display == NULL) {
666 fprintf(stderr, "failed to create display\n");
667 return NULL;
668 }
669
670 if (!eglInitialize(ec->display, &major, &minor)) {
671 fprintf(stderr, "failed to initialize display\n");
672 return NULL;
673 }
674
675 if (!eglGetConfigs(ec->display, configs, ARRAY_LENGTH(configs), &count)) {
676 fprintf(stderr, "failed to get configs\n");
677 return NULL;
678 }
679
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500680 ec->config = configs[24];
681 ec->surface = eglCreateSurfaceNative(ec->display, ec->config,
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500682 0, 0, ec->width, ec->height);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400683 if (ec->surface == NULL) {
684 fprintf(stderr, "failed to create surface\n");
685 return NULL;
686 }
687
Kristian Høgsberg2d9cd1e2008-11-03 08:09:34 -0500688 ec->context = eglCreateContext(ec->display, ec->config, NULL, NULL);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400689 if (ec->context == NULL) {
690 fprintf(stderr, "failed to create context\n");
691 return NULL;
692 }
693
694 if (!eglMakeCurrent(ec->display, ec->surface, ec->surface, ec->context)) {
695 fprintf(stderr, "failed to make context current\n");
696 return NULL;
697 }
698
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500699 glViewport(0, 0, ec->width, ec->height);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400700 glMatrixMode(GL_PROJECTION);
701 glLoadIdentity();
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500702 glOrtho(0, ec->width, ec->height, 0, 0, 1000.0);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400703 glMatrixMode(GL_MODELVIEW);
Kristian Høgsberga234e702008-10-11 22:13:51 -0400704 glClearColor(0.0, 0.05, 0.2, 0.0);
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400705
Kristian Høgsbergaa5b5be2008-11-21 21:31:54 -0500706 filename = getenv("WAYLAND_BACKGROUND");
707 if (filename == NULL)
708 filename = "background.jpg";
709 ec->background = background_create(filename, 1280, 800);
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500710 ec->pointer = pointer_create(100, 100, 64, 64);
Kristian Høgsberg54879822008-11-23 17:07:32 -0500711 ec->overlay = overlay_create(0, ec->height - 200, ec->width, 200);
Kristian Høgsberg4c9f2c92008-11-21 19:25:44 -0500712
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400713 ec->gem_fd = open(gem_device, O_RDWR);
714 if (ec->gem_fd < 0) {
715 fprintf(stderr, "failed to open drm device\n");
716 return NULL;
717 }
718
Kristian Høgsberg1e4b86a2008-11-23 23:41:08 -0500719 shooter = screenshooter_create(ec);
720 wl_display_add_object(display, &shooter->base);
721 wl_display_add_global(display, &shooter->base);
Kristian Høgsberg8d7ca6b2008-11-09 00:22:51 -0500722
Kristian Høgsbergef7a9ca2008-10-11 21:21:39 -0400723 schedule_repaint(ec);
724
Kristian Høgsberg16eb6752008-10-08 22:51:32 -0400725 return &ec->base;
726}