blob: a212eec1d9fa1d26d3f8641a1980cab186c42a8e [file] [log] [blame]
Pekka Paalanenef2b5922014-09-23 22:08:49 -04001/*
2 * Copyright © 2011 Benjamin Franzke
3 * Copyright © 2010 Intel Corporation
4 * Copyright © 2014 Collabora, Ltd.
5 *
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that copyright
9 * notice and this permission notice appear in supporting documentation, and
10 * that the name of the copyright holders not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. The copyright holders make no representations
13 * about the suitability of this software for any purpose. It is provided "as
14 * is" without express or implied warranty.
15 *
16 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22 * OF THIS SOFTWARE.
23 */
24
25#include <config.h>
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <stdbool.h>
31#include <assert.h>
32#include <unistd.h>
33#include <sys/mman.h>
34#include <signal.h>
35#include <time.h>
36
37#include <wayland-client.h>
38#include "../shared/os-compatibility.h"
39#include "presentation_timing-client-protocol.h"
40
41#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
42
43enum run_mode {
44 RUN_MODE_FEEDBACK,
45 RUN_MODE_FEEDBACK_IDLE,
46 RUN_MODE_PRESENT,
47};
48
49struct output {
50 struct wl_output *output;
51 uint32_t name;
52 struct wl_list link;
53};
54
55struct display {
56 struct wl_display *display;
57 struct wl_registry *registry;
58 struct wl_compositor *compositor;
59 struct wl_shell *shell;
60
61 struct wl_shm *shm;
62 uint32_t formats;
63
64 struct presentation *presentation;
65 clockid_t clk_id;
66
67 struct wl_list output_list; /* struct output::link */
68};
69
70struct feedback {
71 struct window *window;
72 unsigned frame_no;
73 struct presentation_feedback *feedback;
74 struct timespec commit;
75 struct timespec target;
76 uint32_t frame_stamp;
77 struct wl_list link;
78 struct timespec present;
79};
80
81struct buffer {
82 struct wl_buffer *buffer;
83 void *shm_data;
84 int busy;
85};
86
87struct window {
88 struct display *display;
89 int width, height;
90 enum run_mode mode;
91 struct wl_surface *surface;
92 struct wl_shell_surface *shell_surface;
93
94 struct buffer *buffers;
95 int num_buffers;
96 int next;
97 int refresh_nsec;
98
99 struct wl_callback *callback;
100 struct wl_list feedback_list;
101
102 struct feedback *received_feedback;
103};
104
105#define NSEC_PER_SEC 1000000000
106
107static void
108buffer_release(void *data, struct wl_buffer *buffer)
109{
110 struct buffer *mybuf = data;
111
112 mybuf->busy = 0;
113}
114
115static const struct wl_buffer_listener buffer_listener = {
116 buffer_release
117};
118
119static int
120create_shm_buffers(struct display *display, struct buffer **buffers,
121 int num_buffers, int width, int height, uint32_t format)
122{
123 struct buffer *bufs;
124 struct wl_shm_pool *pool;
125 int fd, size, stride, offset;
126 void *data;
127 int i;
128
129 stride = width * 4;
130 size = stride * height * num_buffers;
131
132 fd = os_create_anonymous_file(size);
133 if (fd < 0) {
134 fprintf(stderr, "creating a buffer file for %d B failed: %m\n",
135 size);
136 return -1;
137 }
138
139 data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
140 if (data == MAP_FAILED) {
141 fprintf(stderr, "mmap failed: %m\n");
142 close(fd);
143 return -1;
144 }
145
146 pool = wl_shm_create_pool(display->shm, fd, size);
147 offset = 0;
148
149 bufs = calloc(num_buffers, sizeof(*bufs));
150 assert(bufs);
151
152 for (i = 0; i < num_buffers; i++) {
153 bufs[i].buffer = wl_shm_pool_create_buffer(pool, offset,
154 width, height,
155 stride, format);
156 assert(bufs[i].buffer);
157 wl_buffer_add_listener(bufs[i].buffer,
158 &buffer_listener, &bufs[i]);
159
160 bufs[i].shm_data = (char *)data + offset;
161 offset += stride * height;
162 }
163
164 wl_shm_pool_destroy(pool);
165 close(fd);
166
167 *buffers = bufs;
168
169 return 0;
170}
171
172static void
173handle_ping(void *data, struct wl_shell_surface *shell_surface,
174 uint32_t serial)
175{
176 wl_shell_surface_pong(shell_surface, serial);
177}
178
179static void
180handle_configure(void *data, struct wl_shell_surface *shell_surface,
181 uint32_t edges, int32_t width, int32_t height)
182{
183}
184
185static void
186handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
187{
188}
189
190static const struct wl_shell_surface_listener shell_surface_listener = {
191 handle_ping,
192 handle_configure,
193 handle_popup_done
194};
195
196static struct window *
197create_window(struct display *display, int width, int height,
198 enum run_mode mode)
199{
200 struct window *window;
201 int ret;
202
203 window = calloc(1, sizeof *window);
204 if (!window)
205 return NULL;
206
207 window->mode = mode;
208 window->callback = NULL;
209 wl_list_init(&window->feedback_list);
210 window->display = display;
211 window->width = width;
212 window->height = height;
213 window->surface = wl_compositor_create_surface(display->compositor);
214 window->shell_surface = wl_shell_get_shell_surface(display->shell,
215 window->surface);
216
217 if (window->shell_surface)
218 wl_shell_surface_add_listener(window->shell_surface,
219 &shell_surface_listener, window);
220
221 wl_shell_surface_set_title(window->shell_surface, "presentation-shm");
222
223 wl_shell_surface_set_toplevel(window->shell_surface);
224
225 window->num_buffers = 60;
226 window->refresh_nsec = NSEC_PER_SEC / 60; /* 60 Hz guess */
227 window->next = 0;
228 ret = create_shm_buffers(window->display,
229 &window->buffers, window->num_buffers,
230 window->width, window->height,
231 WL_SHM_FORMAT_XRGB8888);
232 assert(ret == 0);
233
234 return window;
235}
236
237static void
238destroy_feedback(struct feedback *feedback)
239{
240 if (feedback->feedback)
241 presentation_feedback_destroy(feedback->feedback);
242
243 wl_list_remove(&feedback->link);
244 free(feedback);
245}
246
247static void
248destroy_window(struct window *window)
249{
250 int i;
251
252 while (!wl_list_empty(&window->feedback_list)) {
253 struct feedback *f;
254
255 f = wl_container_of(window->feedback_list.next, f, link);
256 printf("clean up feedback %u\n", f->frame_no);
257 destroy_feedback(f);
258 }
259
260 if (window->callback)
261 wl_callback_destroy(window->callback);
262
263 wl_shell_surface_destroy(window->shell_surface);
264 wl_surface_destroy(window->surface);
265
266 for (i = 0; i < window->num_buffers; i++)
267 wl_buffer_destroy(window->buffers[i].buffer);
268 /* munmap(window->buffers[0].shm_data, size); */
269 free(window->buffers);
270
271 free(window);
272}
273
274static struct buffer *
275window_next_buffer(struct window *window)
276{
277 struct buffer *buf = &window->buffers[window->next];
278
279 window->next = (window->next + 1) % window->num_buffers;
280
281 return buf;
282}
283
284static void
285paint_pixels(void *image, int width, int height, uint32_t phase)
286{
287 const int halfh = height / 2;
288 const int halfw = width / 2;
289 uint32_t *pixel = image;
290 int y, or;
291 double ang = M_PI * 2.0 / 1000000.0 * phase;
292 double s = sin(ang);
293 double c = cos(ang);
294
295 /* squared radii thresholds */
296 or = (halfw < halfh ? halfw : halfh) - 16;
297 or *= or;
298
299 for (y = 0; y < height; y++) {
300 int x;
301 int oy = y - halfh;
302 int y2 = oy * oy;
303
304 for (x = 0; x < width; x++) {
305 int ox = x - halfw;
306 uint32_t v = 0xff000000;
307 double rx, ry;
308
309 if (ox * ox + y2 > or) {
310 if (ox * oy > 0)
311 *pixel++ = 0xff000000;
312 else
313 *pixel++ = 0xffffffff;
314 continue;
315 }
316
317 rx = c * ox + s * oy;
318 ry = -s * ox + c * oy;
319
320 if (rx < 0.0)
321 v |= 0x00ff0000;
322 if (ry < 0.0)
323 v |= 0x0000ff00;
324 if ((rx < 0.0) == (ry < 0.0))
325 v |= 0x000000ff;
326
327 *pixel++ = v;
328 }
329 }
330}
331
332static void
333feedback_sync_output(void *data,
334 struct presentation_feedback *presentation_feedback,
335 struct wl_output *output)
336{
337 /* not interested */
338}
339
340static char *
341pflags_to_str(uint32_t flags, char *str, unsigned len)
342{
343 static const struct {
344 uint32_t flag;
345 char sym;
346 } desc[] = {
347 { 1, '1' }, /* dummy placeholder */
348 };
349 unsigned i;
350
351 *str = '\0';
352 if (len < ARRAY_LENGTH(desc) + 1)
353 return str;
354
355 for (i = 0; i < ARRAY_LENGTH(desc); i++)
356 str[i] = flags & desc[i].flag ? desc[i].sym : '_';
357 str[ARRAY_LENGTH(desc)] = '\0';
358
359 return str;
360}
361
362static uint32_t
363timespec_to_ms(const struct timespec *ts)
364{
365 return (uint32_t)ts->tv_sec * 1000 + ts->tv_nsec / 1000000;
366}
367
368static void
369timespec_from_proto(struct timespec *tm, uint32_t tv_sec_hi,
370 uint32_t tv_sec_lo, uint32_t tv_nsec)
371{
372 tm->tv_sec = ((uint64_t)tv_sec_hi << 32) + tv_sec_lo;
373 tm->tv_nsec = tv_nsec;
374}
375
376static int
377timespec_diff_to_usec(const struct timespec *a, const struct timespec *b)
378{
379 time_t secs = a->tv_sec - b->tv_sec;
380 long nsec = a->tv_nsec - b->tv_nsec;
381
382 return secs * 1000000 + nsec / 1000;
383}
384
385static void
386feedback_presented(void *data,
387 struct presentation_feedback *presentation_feedback,
388 uint32_t tv_sec_hi,
389 uint32_t tv_sec_lo,
390 uint32_t tv_nsec,
391 uint32_t refresh_nsec,
392 uint32_t seq_hi,
393 uint32_t seq_lo,
394 uint32_t flags)
395{
396 struct feedback *feedback = data;
397 struct window *window = feedback->window;
398 struct feedback *prev_feedback = window->received_feedback;
399 uint64_t seq = ((uint64_t)seq_hi << 32) + seq_lo;
400 const struct timespec *prevpresent;
401 uint32_t commit, present;
402 uint32_t f2c, c2p, f2p;
403 int p2p, t2p;
404 char flagstr[10];
405
406 timespec_from_proto(&feedback->present, tv_sec_hi, tv_sec_lo, tv_nsec);
407 commit = timespec_to_ms(&feedback->commit);
408 present = timespec_to_ms(&feedback->present);
409
410 if (prev_feedback)
411 prevpresent = &prev_feedback->present;
412 else
413 prevpresent = &feedback->present;
414
415 f2c = commit - feedback->frame_stamp;
416 c2p = present - commit;
417 f2p = present - feedback->frame_stamp;
418 p2p = timespec_diff_to_usec(&feedback->present, prevpresent);
419 t2p = timespec_diff_to_usec(&feedback->present, &feedback->target);
420
421 switch (window->mode) {
422 case RUN_MODE_PRESENT:
423 printf("%6u: c2p %4u ms, p2p %5d us, t2p %6d us, [%s] "
424 "seq %" PRIu64 "\n", feedback->frame_no, c2p,
425 p2p, t2p,
426 pflags_to_str(flags, flagstr, sizeof(flagstr)), seq);
427 break;
428 case RUN_MODE_FEEDBACK:
429 case RUN_MODE_FEEDBACK_IDLE:
430 printf("%6u: f2c %2u ms, c2p %2u ms, f2p %2u ms, p2p %5d us, "
431 "t2p %6d, [%s], seq %" PRIu64 "\n", feedback->frame_no,
432 f2c, c2p, f2p, p2p, t2p,
433 pflags_to_str(flags, flagstr, sizeof(flagstr)), seq);
434 }
435
436 if (window->received_feedback)
437 destroy_feedback(window->received_feedback);
438 window->received_feedback = feedback;
439}
440
441static void
442feedback_discarded(void *data,
443 struct presentation_feedback *presentation_feedback)
444{
445 struct feedback *feedback = data;
446
447 printf("discarded %u\n", feedback->frame_no);
448
449 destroy_feedback(feedback);
450}
451
452static const struct presentation_feedback_listener feedback_listener = {
453 feedback_sync_output,
454 feedback_presented,
455 feedback_discarded
456};
457
458static void
459window_create_feedback(struct window *window, uint32_t frame_stamp)
460{
461 static unsigned seq;
462 struct presentation *pres = window->display->presentation;
463 struct feedback *feedback;
464
465 seq++;
466
467 if (!pres)
468 return;
469
470 feedback = calloc(1, sizeof *feedback);
471 if (!feedback)
472 return;
473
474 feedback->window = window;
475 feedback->feedback = presentation_feedback(pres, window->surface);
476 presentation_feedback_add_listener(feedback->feedback,
477 &feedback_listener, feedback);
478
479 feedback->frame_no = seq;
480 clock_gettime(window->display->clk_id, &feedback->commit);
481 feedback->frame_stamp = frame_stamp;
482 feedback->target = feedback->commit;
483
484 wl_list_insert(&window->feedback_list, &feedback->link);
485}
486
487static void
488window_commit_next(struct window *window)
489{
490 struct buffer *buffer;
491
492 buffer = window_next_buffer(window);
493 assert(buffer);
494
495 wl_surface_attach(window->surface, buffer->buffer, 0, 0);
496 wl_surface_damage(window->surface, 0, 0, window->width, window->height);
497 wl_surface_commit(window->surface);
498 buffer->busy = 1;
499}
500
501static const struct wl_callback_listener frame_listener_mode_feedback;
502
503static void
504redraw_mode_feedback(void *data, struct wl_callback *callback, uint32_t time)
505{
506 struct window *window = data;
507
508 if (callback && window->mode == RUN_MODE_FEEDBACK_IDLE)
509 sleep(1);
510
511 if (callback)
512 wl_callback_destroy(callback);
513
514 window->callback = wl_surface_frame(window->surface);
515 wl_callback_add_listener(window->callback,
516 &frame_listener_mode_feedback, window);
517
518 window_create_feedback(window, time);
519 window_commit_next(window);
520}
521
522static const struct wl_callback_listener frame_listener_mode_feedback = {
523 redraw_mode_feedback
524};
525
526static const struct presentation_feedback_listener feedkick_listener;
527
528static void
529window_feedkick(struct window *window)
530{
531 struct presentation *pres = window->display->presentation;
532 struct presentation_feedback *fback;
533
534 fback = presentation_feedback(pres, window->surface);
535 presentation_feedback_add_listener(fback, &feedkick_listener, window);
536}
537
538static void
539feedkick_presented(void *data,
540 struct presentation_feedback *presentation_feedback,
541 uint32_t tv_sec_hi,
542 uint32_t tv_sec_lo,
543 uint32_t tv_nsec,
544 uint32_t refresh_nsec,
545 uint32_t seq_hi,
546 uint32_t seq_lo,
547 uint32_t flags)
548{
549 struct window *window = data;
550
551 presentation_feedback_destroy(presentation_feedback);
552 window->refresh_nsec = refresh_nsec;
553
554 switch (window->mode) {
555 case RUN_MODE_PRESENT:
556 window_create_feedback(window, 0);
557 window_feedkick(window);
558 window_commit_next(window);
559 break;
560 case RUN_MODE_FEEDBACK:
561 case RUN_MODE_FEEDBACK_IDLE:
562 assert(0 && "bad mode");
563 }
564}
565
566static void
567feedkick_discarded(void *data,
568 struct presentation_feedback *presentation_feedback)
569{
570 struct window *window = data;
571
572 presentation_feedback_destroy(presentation_feedback);
573
574 switch (window->mode) {
575 case RUN_MODE_PRESENT:
576 window_create_feedback(window, 0);
577 window_feedkick(window);
578 window_commit_next(window);
579 break;
580 case RUN_MODE_FEEDBACK:
581 case RUN_MODE_FEEDBACK_IDLE:
582 assert(0 && "bad mode");
583 }
584}
585
586static const struct presentation_feedback_listener feedkick_listener = {
587 feedback_sync_output,
588 feedkick_presented,
589 feedkick_discarded
590};
591
592static void
593firstdraw_mode_burst(struct window *window)
594{
595 switch (window->mode) {
596 case RUN_MODE_PRESENT:
597 window_create_feedback(window, 0);
598 break;
599 case RUN_MODE_FEEDBACK:
600 case RUN_MODE_FEEDBACK_IDLE:
601 assert(0 && "bad mode");
602 }
603
604 window_feedkick(window);
605 window_commit_next(window);
606}
607
608static void
609window_prerender(struct window *window)
610{
611 int i;
612 int timefactor = 1000000 / window->num_buffers;
613
614 for (i = 0; i < window->num_buffers; i++) {
615 struct buffer *buf = &window->buffers[i];
616
617 if (buf->busy)
618 fprintf(stderr, "wl_buffer id %u) busy\n",
619 wl_proxy_get_id(
620 (struct wl_proxy *)buf->buffer));
621
622 paint_pixels(buf->shm_data, window->width, window->height,
623 i * timefactor);
624 }
625}
626
627static void
628output_destroy(struct output *o)
629{
630 wl_output_destroy(o->output);
631 wl_list_remove(&o->link);
632 free(o);
633}
634
635static void
636display_add_output(struct display *d, uint32_t name, uint32_t version)
637{
638 struct output *o;
639
640 o = calloc(1, sizeof(*o));
641 assert(o);
642
643 o->output = wl_registry_bind(d->registry, name,
644 &wl_output_interface, 1);
645 o->name = name;
646 wl_list_insert(&d->output_list, &o->link);
647}
648
649static void
650presentation_clock_id(void *data, struct presentation *presentation,
651 uint32_t clk_id)
652{
653 struct display *d = data;
654
655 d->clk_id = clk_id;
656}
657
658static const struct presentation_listener presentation_listener = {
659 presentation_clock_id
660};
661
662static void
663shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
664{
665 struct display *d = data;
666
667 d->formats |= (1 << format);
668}
669
670static const struct wl_shm_listener shm_listener = {
671 shm_format
672};
673
674static void
675registry_handle_global(void *data, struct wl_registry *registry,
676 uint32_t name, const char *interface, uint32_t version)
677{
678 struct display *d = data;
679
680 if (strcmp(interface, "wl_compositor") == 0) {
681 d->compositor =
682 wl_registry_bind(registry,
683 name, &wl_compositor_interface, 1);
684 } else if (strcmp(interface, "wl_shell") == 0) {
685 d->shell = wl_registry_bind(registry,
686 name, &wl_shell_interface, 1);
687 } else if (strcmp(interface, "wl_shm") == 0) {
688 d->shm = wl_registry_bind(registry,
689 name, &wl_shm_interface, 1);
690 wl_shm_add_listener(d->shm, &shm_listener, d);
691 } else if (strcmp(interface, "wl_output") == 0) {
692 display_add_output(d, name, version);
693 } else if (strcmp(interface, "presentation") == 0) {
694 d->presentation =
695 wl_registry_bind(registry,
696 name, &presentation_interface, 1);
697 presentation_add_listener(d->presentation,
698 &presentation_listener, d);
699 }
700}
701
702static void
703registry_handle_global_remove(void *data, struct wl_registry *registry,
704 uint32_t name)
705{
706 struct display *d = data;
707 struct output *output, *otmp;
708
709 wl_list_for_each_safe(output, otmp, &d->output_list, link) {
710 if (output->name != name)
711 continue;
712
713 output_destroy(output);
714 }
715}
716
717static const struct wl_registry_listener registry_listener = {
718 registry_handle_global,
719 registry_handle_global_remove
720};
721
722static struct display *
723create_display(void)
724{
725 struct display *display;
726
727 display = malloc(sizeof *display);
728 if (display == NULL) {
729 fprintf(stderr, "out of memory\n");
730 exit(1);
731 }
732 display->display = wl_display_connect(NULL);
733 assert(display->display);
734
735 display->formats = 0;
736 display->clk_id = -1;
737 wl_list_init(&display->output_list);
738 display->registry = wl_display_get_registry(display->display);
739 wl_registry_add_listener(display->registry,
740 &registry_listener, display);
741 wl_display_roundtrip(display->display);
742 if (display->shm == NULL) {
743 fprintf(stderr, "No wl_shm global\n");
744 exit(1);
745 }
746
747 wl_display_roundtrip(display->display);
748
749 if (!(display->formats & (1 << WL_SHM_FORMAT_XRGB8888))) {
750 fprintf(stderr, "WL_SHM_FORMAT_XRGB32 not available\n");
751 exit(1);
752 }
753
754 wl_display_get_fd(display->display);
755
756 return display;
757}
758
759static void
760destroy_display(struct display *display)
761{
762 while (!wl_list_empty(&display->output_list)) {
763 struct output *o;
764
765 o = wl_container_of(display->output_list.next, o, link);
766 output_destroy(o);
767 }
768
769 if (display->shm)
770 wl_shm_destroy(display->shm);
771
772 if (display->shell)
773 wl_shell_destroy(display->shell);
774
775 if (display->compositor)
776 wl_compositor_destroy(display->compositor);
777
778 wl_registry_destroy(display->registry);
779 wl_display_flush(display->display);
780 wl_display_disconnect(display->display);
781 free(display);
782}
783
784static int running = 1;
785
786static void
787signal_int(int signum)
788{
789 running = 0;
790}
791
792static void
793usage(const char *prog, int exit_code)
794{
795 fprintf(stderr, "Usage: %s [mode] [options]\n"
796 "where 'mode' is one of\n"
797 " -f\trun in feedback mode (default)\n"
798 " -i\trun in feedback-idle mode; sleep 1s between frames\n"
799 " -p\trun in low-latency presentation mode\n"
800 "and 'options' may include\n",
801 prog);
802
803 fprintf(stderr, "Printed timing statistics, depending on mode:\n"
804 " commit sequence number\n"
805 " f2c: time from frame callback timestamp to commit\n"
806 " c2p: time from commit to presentation\n"
807 " f2p: time from frame callback timestamp to presentation\n"
808 " p2p: time from previous presentation to this one\n"
809 " t2p: time from target timestamp to presentation\n"
810 " seq: MSC\n");
811
812
813 exit(exit_code);
814}
815
816int
817main(int argc, char **argv)
818{
819 struct sigaction sigint;
820 struct display *display;
821 struct window *window;
822 int ret = 0;
823 enum run_mode mode = RUN_MODE_FEEDBACK;
824 int i;
825
826 for (i = 1; i < argc; i++) {
827 if (strcmp("-f", argv[i]) == 0)
828 mode = RUN_MODE_FEEDBACK;
829 else if (strcmp("-i", argv[i]) == 0)
830 mode = RUN_MODE_FEEDBACK_IDLE;
831 else if (strcmp("-p", argv[i]) == 0)
832 mode = RUN_MODE_PRESENT;
833 else
834 usage(argv[0], EXIT_FAILURE);
835 }
836
837 display = create_display();
838 window = create_window(display, 250, 250, mode);
839 if (!window)
840 return 1;
841
842 sigint.sa_handler = signal_int;
843 sigemptyset(&sigint.sa_mask);
844 sigint.sa_flags = SA_RESETHAND;
845 sigaction(SIGINT, &sigint, NULL);
846
847 window_prerender(window);
848
849 switch (mode) {
850 case RUN_MODE_FEEDBACK:
851 case RUN_MODE_FEEDBACK_IDLE:
852 redraw_mode_feedback(window, NULL, 0);
853 break;
854 case RUN_MODE_PRESENT:
855 firstdraw_mode_burst(window);
856 break;
857 }
858
859 while (running && ret != -1)
860 ret = wl_display_dispatch(display->display);
861
862 fprintf(stderr, "presentation-shm exiting\n");
863 destroy_window(window);
864 destroy_display(display);
865
866 return 0;
867}