blob: ff18757ede14627e7e2b62ecf97f569faf70e7a0 [file] [log] [blame]
Pekka Paalanen8c492b12012-09-11 17:02:04 +03001/*
2 * Copyright © 2012 Collabora, Ltd.
3 * Copyright © 2012 Rob Clark
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that copyright
8 * notice and this permission notice appear in supporting documentation, and
9 * that the name of the copyright holders not be used in advertising or
10 * publicity pertaining to distribution of the software without specific,
11 * written prior permission. The copyright holders make no representations
12 * about the suitability of this software for any purpose. It is provided "as
13 * is" without express or implied warranty.
14 *
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21 * OF THIS SOFTWARE.
22 */
23
24/* cliptest: for debugging calculate_edges() function, which is copied
25 * from compositor.c.
26 * controls:
27 * clip box position: mouse left drag, keys: w a s d
28 * clip box size: mouse right drag, keys: i j k l
29 * surface orientation: mouse wheel, keys: n m
30 * surface transform disable key: r
31 */
32
33#include <stdint.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <fcntl.h>
38#include <libgen.h>
39#include <unistd.h>
40#include <math.h>
41#include <time.h>
42#include <pixman.h>
43#include <cairo.h>
44#include <float.h>
45#include <assert.h>
46
47#include <linux/input.h>
48#include <wayland-client.h>
49
50#include "window.h"
51
52typedef float GLfloat;
53
54struct geometry {
55 pixman_box32_t clip;
56
57 pixman_box32_t surf;
58 float s; /* sin phi */
59 float c; /* cos phi */
60 float phi;
61};
62
63struct weston_surface {
64 struct {
65 int enabled;
66 } transform;
67
68 struct geometry *geometry;
69};
70
71static void
72weston_surface_to_global_float(struct weston_surface *surface,
73 GLfloat sx, GLfloat sy, GLfloat *x, GLfloat *y)
74{
75 struct geometry *g = surface->geometry;
76
77 /* pure rotation around origin by sine and cosine */
78 *x = g->c * sx + g->s * sy;
79 *y = -g->s * sx + g->c * sy;
80}
81
82/* ---------------------- copied begins -----------------------*/
83
84#define max(a, b) (((a) > (b)) ? (a) : (b))
85#define min(a, b) (((a) > (b)) ? (b) : (a))
86#define clip(x, a, b) min(max(x, a), b)
87#define sign(x) ((x) >= 0)
88
89static int
90calculate_edges(struct weston_surface *es, pixman_box32_t *rect,
91 pixman_box32_t *surf_rect, GLfloat *ex, GLfloat *ey)
92{
93 int i, n = 0;
94 GLfloat min_x, max_x, min_y, max_y;
95 GLfloat x[4] = {
96 surf_rect->x1, surf_rect->x2, surf_rect->x2, surf_rect->x1,
97 };
98 GLfloat y[4] = {
99 surf_rect->y1, surf_rect->y1, surf_rect->y2, surf_rect->y2,
100 };
101 GLfloat cx1 = rect->x1;
102 GLfloat cx2 = rect->x2;
103 GLfloat cy1 = rect->y1;
104 GLfloat cy2 = rect->y2;
105
106 GLfloat dist_squared(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
107 {
108 GLfloat dx = (x1 - x2);
109 GLfloat dy = (y1 - y2);
110 return dx * dx + dy * dy;
111 }
112
113 void append_vertex(GLfloat x, GLfloat y)
114 {
115 /* don't emit duplicate vertices: */
116 if ((n > 0) && (ex[n-1] == x) && (ey[n-1] == y))
117 return;
118 ex[n] = x;
119 ey[n] = y;
120 n++;
121 }
122
123 /* transform surface to screen space: */
124 for (i = 0; i < 4; i++)
125 weston_surface_to_global_float(es, x[i], y[i], &x[i], &y[i]);
126
127 /* find bounding box: */
128 min_x = max_x = x[0];
129 min_y = max_y = y[0];
130
131 for (i = 1; i < 4; i++) {
132 min_x = min(min_x, x[i]);
133 max_x = max(max_x, x[i]);
134 min_y = min(min_y, y[i]);
135 max_y = max(max_y, y[i]);
136 }
137
138 /* First, simple bounding box check to discard early transformed
139 * surface rects that do not intersect with the clip region:
140 */
141 if ((min_x > cx2) || (max_x < cx1) ||
142 (min_y > cy2) || (max_y < cy1))
143 return 0;
144
145 /* Simple case, bounding box edges are parallel to surface edges,
146 * there will be only four edges. We just need to clip the surface
147 * vertices to the clip rect bounds:
148 */
149 if (!es->transform.enabled) {
150 for (i = 0; i < 4; i++) {
151 ex[n] = clip(x[i], cx1, cx2);
152 ey[n] = clip(y[i], cy1, cy2);
153 n++;
154 }
155 return 4;
156 }
157
158 /* Hard case, transformation applied. We need to find the vertices
159 * of the shape that is the intersection of the clip rect and
160 * transformed surface. This can be anything from 3 to 8 sides.
161 *
162 * Observation: all the resulting vertices will be the intersection
163 * points of the transformed surface and the clip rect, plus the
164 * vertices of the clip rect which are enclosed by the transformed
165 * surface and the vertices of the transformed surface which are
166 * enclosed by the clip rect.
167 *
168 * Observation: there will be zero, one, or two resulting vertices
169 * for each edge of the src rect.
170 *
171 * Loop over four edges of the transformed rect:
172 */
173 for (i = 0; i < 4; i++) {
174 GLfloat x1, y1, x2, y2;
175 int last_n = n;
176
177 x1 = x[i];
178 y1 = y[i];
179
180 /* if this vertex is contained in the clip rect, use it as-is: */
181 if ((cx1 <= x1) && (x1 <= cx2) &&
182 (cy1 <= y1) && (y1 <= cy2))
183 append_vertex(x1, y1);
184
185 /* for remaining, we consider the point as part of a line: */
186 x2 = x[(i+1) % 4];
187 y2 = y[(i+1) % 4];
188
189 if (x1 == x2) {
190 append_vertex(clip(x1, cx1, cx2), clip(y1, cy1, cy2));
191 append_vertex(clip(x2, cx1, cx2), clip(y2, cy1, cy2));
192 } else if (y1 == y2) {
193 append_vertex(clip(x1, cx1, cx2), clip(y1, cy1, cy2));
194 append_vertex(clip(x2, cx1, cx2), clip(y2, cy1, cy2));
195 } else {
196 GLfloat m, c, p;
197 GLfloat tx[2], ty[2];
198 int tn = 0;
199
200 int intersect_horiz(GLfloat y, GLfloat *p)
201 {
202 GLfloat x;
203
204 /* if y does not lie between y1 and y2, no
205 * intersection possible
206 */
207 if (sign(y-y1) == sign(y-y2))
208 return 0;
209
210 x = (y - c) / m;
211
212 /* if x does not lie between cx1 and cx2, no
213 * intersection:
214 */
215 if (sign(x-cx1) == sign(x-cx2))
216 return 0;
217
218 *p = x;
219 return 1;
220 }
221
222 int intersect_vert(GLfloat x, GLfloat *p)
223 {
224 GLfloat y;
225
226 if (sign(x-x1) == sign(x-x2))
227 return 0;
228
229 y = m * x + c;
230
231 if (sign(y-cy1) == sign(y-cy2))
232 return 0;
233
234 *p = y;
235 return 1;
236 }
237
238 /* y = mx + c */
239 m = (y2 - y1) / (x2 - x1);
240 c = y1 - m * x1;
241
242 /* check for up to two intersections with the four edges
243 * of the clip rect. Note that we don't know the orientation
244 * of the transformed surface wrt. the clip rect. So if when
245 * there are two intersection points, we need to put the one
246 * closest to x1,y1 first:
247 */
248
249 /* check top clip rect edge: */
250 if (intersect_horiz(cy1, &p)) {
251 ty[tn] = cy1;
252 tx[tn] = p;
253 tn++;
254 }
255
256 /* check right clip rect edge: */
257 if (intersect_vert(cx2, &p)) {
258 ty[tn] = p;
259 tx[tn] = cx2;
260 tn++;
261 if (tn == 2)
262 goto edge_check_done;
263 }
264
265 /* check bottom clip rect edge: */
266 if (intersect_horiz(cy2, &p)) {
267 ty[tn] = cy2;
268 tx[tn] = p;
269 tn++;
270 if (tn == 2)
271 goto edge_check_done;
272 }
273
274 /* check left clip rect edge: */
275 if (intersect_vert(cx1, &p)) {
276 ty[tn] = p;
277 tx[tn] = cx1;
278 tn++;
279 }
280
281edge_check_done:
282 if (tn == 1) {
283 append_vertex(tx[0], ty[0]);
284 } else if (tn == 2) {
285 if (dist_squared(x1, y1, tx[0], ty[0]) <
286 dist_squared(x1, y1, tx[1], ty[1])) {
287 append_vertex(tx[0], ty[0]);
288 append_vertex(tx[1], ty[1]);
289 } else {
290 append_vertex(tx[1], ty[1]);
291 append_vertex(tx[0], ty[0]);
292 }
293 }
294
295 if (n == last_n) {
296 GLfloat best_x=0, best_y=0;
297 uint32_t d, best_d = (unsigned int)-1; /* distance squared */
298 uint32_t max_d = dist_squared(x2, y2,
299 x[(i+2) % 4], y[(i+2) % 4]);
300
301 /* if there are no vertices on this line, it could be that
302 * there is a vertex of the clip rect that is enclosed by
303 * the transformed surface. Find the vertex of the clip
304 * rect that is reached by the shortest line perpendicular
305 * to the current edge, if any.
306 *
307 * slope of perpendicular is 1/m, so
308 *
309 * cy = -cx/m + c2
310 * c2 = cy + cx/m
311 *
312 */
313
314 int perp_intersect(GLfloat cx, GLfloat cy, uint32_t *d)
315 {
316 GLfloat c2 = cy + cx/m;
317 GLfloat x = (c2 - c) / (m + 1/m);
318
319 /* if the x position of the intersection of the
320 * perpendicular with the transformed edge does
321 * not lie within the bounds of the edge, then
322 * no intersection:
323 */
324 if (sign(x-x1) == sign(x-x2))
325 return 0;
326
327 *d = dist_squared(cx, cy, x, (m * x) + c);
328
329 /* if intersection distance is further away than
330 * opposite edge of surface region, it is invalid:
331 */
332 if (*d > max_d)
333 return 0;
334
335 return 1;
336 }
337
338 if (perp_intersect(cx1, cy1, &d)) {
339 best_x = cx1;
340 best_y = cy1;
341 best_d = d;
342 }
343
344 if (perp_intersect(cx1, cy2, &d) && (d < best_d)) {
345 best_x = cx1;
346 best_y = cy2;
347 best_d = d;
348 }
349
350 if (perp_intersect(cx2, cy2, &d) && (d < best_d)) {
351 best_x = cx2;
352 best_y = cy2;
353 best_d = d;
354 }
355
356 if (perp_intersect(cx2, cy1, &d) && (d < best_d)) {
357 best_x = cx2;
358 best_y = cy1;
359 best_d = d;
360 }
361
362 if (best_d != (unsigned int)-1) // XXX can this happen?
363 append_vertex(best_x, best_y);
364 }
365 }
366
367 }
368
369 return n;
370}
371
372/* ---------------------- copied ends -----------------------*/
373
374static void
375geometry_set_phi(struct geometry *g, float phi)
376{
377 g->phi = phi;
378 g->s = sin(phi);
379 g->c = cos(phi);
380}
381
382static void
383geometry_init(struct geometry *g)
384{
385 g->clip.x1 = -50;
386 g->clip.y1 = -50;
387 g->clip.x2 = -10;
388 g->clip.y2 = -10;
389
390 g->surf.x1 = -20;
391 g->surf.y1 = -20;
392 g->surf.x2 = 20;
393 g->surf.y2 = 20;
394
395 geometry_set_phi(g, 0.0);
396}
397
398struct ui_state {
399 uint32_t button;
400 int down;
401
402 int down_pos[2];
403 struct geometry geometry;
404};
405
406struct cliptest {
407 struct window *window;
408 struct widget *widget;
409 struct display *display;
410 int fullscreen;
411
412 struct ui_state ui;
413
414 struct geometry geometry;
415 struct weston_surface surface;
416};
417
418static void
419draw_polygon_closed(cairo_t *cr, GLfloat *x, GLfloat *y, int n)
420{
421 int i;
422
423 cairo_move_to(cr, x[0], y[0]);
424 for (i = 1; i < n; i++)
425 cairo_line_to(cr, x[i], y[i]);
426 cairo_line_to(cr, x[0], y[0]);
427}
428
429static void
430draw_polygon_labels(cairo_t *cr, GLfloat *x, GLfloat *y, int n)
431{
432 char str[16];
433 int i;
434
435 for (i = 0; i < n; i++) {
436 snprintf(str, 16, "%d", i);
437 cairo_move_to(cr, x[i], y[i]);
438 cairo_show_text(cr, str);
439 }
440}
441
442static void
443draw_coordinates(cairo_t *cr, double ox, double oy, GLfloat *x, GLfloat *y, int n)
444{
445 char str[64];
446 int i;
447 cairo_font_extents_t ext;
448
449 cairo_font_extents(cr, &ext);
450 for (i = 0; i < n; i++) {
451 snprintf(str, 64, "%d: %14.9f, %14.9f", i, x[i], y[i]);
452 cairo_move_to(cr, ox, oy + ext.height * (i + 1));
453 cairo_show_text(cr, str);
454 }
455}
456
457static void
458draw_box(cairo_t *cr, pixman_box32_t *box, struct weston_surface *surface)
459{
460 GLfloat x[4], y[4];
461
462 if (surface) {
463 weston_surface_to_global_float(surface, box->x1, box->y1, &x[0], &y[0]);
464 weston_surface_to_global_float(surface, box->x2, box->y1, &x[1], &y[1]);
465 weston_surface_to_global_float(surface, box->x2, box->y2, &x[2], &y[2]);
466 weston_surface_to_global_float(surface, box->x1, box->y2, &x[3], &y[3]);
467 } else {
468 x[0] = box->x1; y[0] = box->y1;
469 x[1] = box->x2; y[1] = box->y1;
470 x[2] = box->x2; y[2] = box->y2;
471 x[3] = box->x1; y[3] = box->y2;
472 }
473
474 draw_polygon_closed(cr, x, y, 4);
475}
476
477static void
478draw_geometry(cairo_t *cr, struct weston_surface *surface,
479 GLfloat *ex, GLfloat *ey, int n)
480{
481 struct geometry *g = surface->geometry;
482 GLfloat cx, cy;
483
484 draw_box(cr, &g->surf, surface);
485 cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.4);
486 cairo_fill(cr);
487 weston_surface_to_global_float(surface, g->surf.x1 - 4, g->surf.y1 - 4, &cx, &cy);
488 cairo_arc(cr, cx, cy, 1.5, 0.0, 2.0 * M_PI);
489 if (surface->transform.enabled == 0)
490 cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.8);
491 cairo_fill(cr);
492
493 draw_box(cr, &g->clip, NULL);
494 cairo_set_source_rgba(cr, 0.0, 0.0, 1.0, 0.4);
495 cairo_fill(cr);
496
497 draw_polygon_closed(cr, ex, ey, n);
498 cairo_set_source_rgb(cr, 0.0, 1.0, 0.0);
499 cairo_stroke(cr);
500
501 cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 0.5);
502 draw_polygon_labels(cr, ex, ey, n);
503}
504
505static void
506redraw_handler(struct widget *widget, void *data)
507{
508 struct cliptest *cliptest = data;
509 struct geometry *g = cliptest->surface.geometry;
510 struct rectangle allocation;
511 cairo_t *cr;
512 cairo_surface_t *surface;
513 GLfloat ex[8];
514 GLfloat ey[8];
515 int n;
516
517 n = calculate_edges(&cliptest->surface, &g->clip, &g->surf, ex, ey);
518
519 widget_get_allocation(cliptest->widget, &allocation);
520
521 surface = window_get_surface(cliptest->window);
522 cr = cairo_create(surface);
523 widget_get_allocation(cliptest->widget, &allocation);
524 cairo_rectangle(cr, allocation.x, allocation.y,
525 allocation.width, allocation.height);
526 cairo_clip(cr);
527
528 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
529 cairo_set_source_rgba(cr, 0, 0, 0, 1);
530 cairo_paint(cr);
531
532 cairo_translate(cr, allocation.x, allocation.y);
533 cairo_set_line_width(cr, 1.0);
534 cairo_move_to(cr, allocation.width / 2.0, 0.0);
535 cairo_line_to(cr, allocation.width / 2.0, allocation.height);
536 cairo_move_to(cr, 0.0, allocation.height / 2.0);
537 cairo_line_to(cr, allocation.width, allocation.height / 2.0);
538 cairo_set_source_rgba(cr, 0.5, 0.5, 0.5, 1.0);
539 cairo_stroke(cr);
540
541 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
542 cairo_push_group(cr);
543 cairo_translate(cr, allocation.width / 2.0,
544 allocation.height / 2.0);
545 cairo_scale(cr, 4.0, 4.0);
546 cairo_set_line_width(cr, 0.5);
547 cairo_set_line_join(cr, CAIRO_LINE_JOIN_BEVEL);
548 cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL,
549 CAIRO_FONT_WEIGHT_BOLD);
550 cairo_set_font_size(cr, 5.0);
551 draw_geometry(cr, &cliptest->surface, ex, ey, n);
552 cairo_pop_group_to_source(cr);
553 cairo_paint(cr);
554
555 cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 1.0);
556 cairo_select_font_face(cr, "monospace", CAIRO_FONT_SLANT_NORMAL,
557 CAIRO_FONT_WEIGHT_NORMAL);
558 cairo_set_font_size(cr, 12.0);
559 draw_coordinates(cr, 10.0, 10.0, ex, ey, n);
560
561 cairo_destroy(cr);
562
563 cairo_surface_destroy(surface);
564}
565
566static int
567motion_handler(struct widget *widget, struct input *input,
568 uint32_t time, float x, float y, void *data)
569{
570 struct cliptest *cliptest = data;
571 struct ui_state *ui = &cliptest->ui;
572 struct geometry *ref = &ui->geometry;
573 struct geometry *geom = &cliptest->geometry;
574 float dx, dy;
575
576 if (!ui->down)
577 return CURSOR_LEFT_PTR;
578
579 dx = (x - ui->down_pos[0]) * 0.25;
580 dy = (y - ui->down_pos[1]) * 0.25;
581
582 switch (ui->button) {
583 case BTN_LEFT:
584 geom->clip.x1 = ref->clip.x1 + dx;
585 geom->clip.y1 = ref->clip.y1 + dy;
586 /* fall through */
587 case BTN_RIGHT:
588 geom->clip.x2 = ref->clip.x2 + dx;
589 geom->clip.y2 = ref->clip.y2 + dy;
590 break;
591 default:
592 return CURSOR_LEFT_PTR;
593 }
594
595 widget_schedule_redraw(cliptest->widget);
596 return CURSOR_BLANK;
597}
598
599static void
600button_handler(struct widget *widget, struct input *input,
601 uint32_t time, uint32_t button,
602 enum wl_pointer_button_state state, void *data)
603{
604 struct cliptest *cliptest = data;
605 struct ui_state *ui = &cliptest->ui;
606
607 ui->button = button;
608
609 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
610 ui->down = 1;
611 input_get_position(input, &ui->down_pos[0], &ui->down_pos[1]);
612 } else {
613 ui->down = 0;
614 ui->geometry = cliptest->geometry;
615 }
616}
617
618static void
619axis_handler(struct widget *widget, struct input *input, uint32_t time,
620 uint32_t axis, wl_fixed_t value, void *data)
621{
622 struct cliptest *cliptest = data;
623 struct geometry *geom = &cliptest->geometry;
624
625 if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL)
626 return;
627
628 geometry_set_phi(geom, geom->phi +
629 (M_PI / 12.0) * wl_fixed_to_double(value));
630 cliptest->surface.transform.enabled = 1;
631
632 widget_schedule_redraw(cliptest->widget);
633}
634
635static void
636key_handler(struct window *window, struct input *input, uint32_t time,
637 uint32_t key, uint32_t sym,
638 enum wl_keyboard_key_state state, void *data)
639{
640 struct cliptest *cliptest = data;
641 struct geometry *g = &cliptest->geometry;
642
643 if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
644 return;
645
646 switch (sym) {
647 case XKB_KEY_Escape:
648 display_exit(cliptest->display);
649 return;
650 case XKB_KEY_w:
651 g->clip.y1 -= 1;
652 g->clip.y2 -= 1;
653 break;
654 case XKB_KEY_a:
655 g->clip.x1 -= 1;
656 g->clip.x2 -= 1;
657 break;
658 case XKB_KEY_s:
659 g->clip.y1 += 1;
660 g->clip.y2 += 1;
661 break;
662 case XKB_KEY_d:
663 g->clip.x1 += 1;
664 g->clip.x2 += 1;
665 break;
666 case XKB_KEY_i:
667 g->clip.y2 -= 1;
668 break;
669 case XKB_KEY_j:
670 g->clip.x2 -= 1;
671 break;
672 case XKB_KEY_k:
673 g->clip.y2 += 1;
674 break;
675 case XKB_KEY_l:
676 g->clip.x2 += 1;
677 break;
678 case XKB_KEY_n:
679 geometry_set_phi(g, g->phi + (M_PI / 24.0));
680 cliptest->surface.transform.enabled = 1;
681 break;
682 case XKB_KEY_m:
683 geometry_set_phi(g, g->phi - (M_PI / 24.0));
684 cliptest->surface.transform.enabled = 1;
685 break;
686 case XKB_KEY_r:
687 geometry_set_phi(g, 0.0);
688 cliptest->surface.transform.enabled = 0;
689 break;
690 default:
691 return;
692 }
693
694 widget_schedule_redraw(cliptest->widget);
695}
696
697static void
698keyboard_focus_handler(struct window *window,
699 struct input *device, void *data)
700{
701 struct cliptest *cliptest = data;
702
703 window_schedule_redraw(cliptest->window);
704}
705
706static void
707fullscreen_handler(struct window *window, void *data)
708{
709 struct cliptest *cliptest = data;
710
711 cliptest->fullscreen ^= 1;
712 window_set_fullscreen(window, cliptest->fullscreen);
713}
714
715static struct cliptest *
716cliptest_create(struct display *display)
717{
718 struct cliptest *cliptest;
719
720 cliptest = malloc(sizeof *cliptest);
721 if (cliptest == NULL)
722 return cliptest;
723 memset(cliptest, 0, sizeof *cliptest);
724
725 cliptest->surface.geometry = &cliptest->geometry;
726 cliptest->surface.transform.enabled = 0;
727 geometry_init(&cliptest->geometry);
728 geometry_init(&cliptest->ui.geometry);
729
730 cliptest->window = window_create(display);
731 cliptest->widget = frame_create(cliptest->window, cliptest);
732 window_set_title(cliptest->window, "cliptest");
733 cliptest->display = display;
734
735 window_set_user_data(cliptest->window, cliptest);
736 widget_set_redraw_handler(cliptest->widget, redraw_handler);
737 widget_set_button_handler(cliptest->widget, button_handler);
738 widget_set_motion_handler(cliptest->widget, motion_handler);
739 widget_set_axis_handler(cliptest->widget, axis_handler);
740
741 window_set_keyboard_focus_handler(cliptest->window,
742 keyboard_focus_handler);
743 window_set_key_handler(cliptest->window, key_handler);
744 window_set_fullscreen_handler(cliptest->window, fullscreen_handler);
745
746 /* set minimum size */
747 widget_schedule_resize(cliptest->widget, 200, 100);
748
749 /* set current size */
750 widget_schedule_resize(cliptest->widget, 500, 400);
751
752 return cliptest;
753}
754
755static struct timespec begin_time;
756
757static void
758reset_timer(void)
759{
760 clock_gettime(CLOCK_MONOTONIC, &begin_time);
761}
762
763static double
764read_timer(void)
765{
766 struct timespec t;
767
768 clock_gettime(CLOCK_MONOTONIC, &t);
769 return (double)(t.tv_sec - begin_time.tv_sec) +
770 1e-9 * (t.tv_nsec - begin_time.tv_nsec);
771}
772
773static int
774benchmark(void)
775{
776 struct weston_surface surface;
777 struct geometry geom;
778 GLfloat ex[8], ey[8];
779 int i;
780 double t;
781 const int N = 1000000;
782
783 geom.clip.x1 = -19;
784 geom.clip.y1 = -19;
785 geom.clip.x2 = 19;
786 geom.clip.y2 = 19;
787
788 geom.surf.x1 = -20;
789 geom.surf.y1 = -20;
790 geom.surf.x2 = 20;
791 geom.surf.y2 = 20;
792
793 geometry_set_phi(&geom, 0.0);
794
795 surface.transform.enabled = 1;
796 surface.geometry = &geom;
797
798 reset_timer();
799 for (i = 0; i < N; i++) {
800 geometry_set_phi(&geom, (float)i / 360.0f);
801 calculate_edges(&surface, &geom.clip, &geom.surf, ex, ey);
802 }
803 t = read_timer();
804
805 printf("%d calls took %g s, average %g us/call\n", N, t, t / N * 1e6);
806
807 return 0;
808}
809
810int
811main(int argc, char *argv[])
812{
813 struct display *d;
814 struct cliptest *cliptest;
815
816 if (argc > 1)
817 return benchmark();
818
819 d = display_create(argc, argv);
820 if (d == NULL) {
821 fprintf(stderr, "failed to create display: %m\n");
822 return -1;
823 }
824
825 cliptest = cliptest_create(d);
826 display_run(d);
827
828 widget_destroy(cliptest->widget);
829 window_destroy(cliptest->window);
830 free(cliptest);
831
832 return 0;
833}