<div dir="ltr">Why isn't this using xdg_shell?<br></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Sep 15, 2014 at 2:16 PM, Louis-Francis Ratté-Boulianne <span dir="ltr"><<a href="mailto:lfrb@collabora.com" target="_blank">lfrb@collabora.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">From: Pekka Paalanen <<a href="mailto:pekka.paalanen@collabora.co.uk">pekka.paalanen@collabora.co.uk</a>><br>
<br>
This started as a copy of simple-shm.c before it was converted to<br>
xdg_shell.<br>
<br>
This demo excercises the presentation feedback interface in five<br>
different modes:<br>
<br>
- A continuous repaint loop triggered by frame callbacks, and using<br>
  immediate commits, just gathering presentation feedback and computing<br>
  some time intervals for statistics.<br>
<br>
- The same as above, except with 1s sleep before actually repainting as<br>
  a response to frame callback. This tests how well the compositor can<br>
  do a repaint from idle state (not continuously repainting), assuming<br>
  nothing else is causing repaints.<br>
<br>
- A continuous repaint loop triggered by 'presented' events rather than<br>
  by frame callbacks. If Weston uses an appropriate scheduling<br>
  algorithm, this mode achieves the smallest possible frame latency<br>
  (below one output refresh period).<br>
<br>
In all modes, all frames are pre-rendered at startup, so no rendering<br>
happens during the animation.<br>
<br>
[Louis-Francis Ratté-Boulianne: split queuing feature]<br>
<br>
Signed-off-by: Pekka Paalanen <<a href="mailto:pekka.paalanen@collabora.co.uk">pekka.paalanen@collabora.co.uk</a>><br>
Signed-off-by: Louis-Francis Ratté-Boulianne <<a href="mailto:lfrb@collabora.com">lfrb@collabora.com</a>><br>
---<br>
 .gitignore                 |   1 +<br>
 Makefile.am                |   8 +<br>
 clients/presentation-shm.c | 866 +++++++++++++++++++++++++++++++++++++++++++++<br>
 3 files changed, 875 insertions(+)<br>
 create mode 100644 clients/presentation-shm.c<br>
<br>
diff --git a/.gitignore b/.gitignore<br>
index fbffaa5..d521bcc 100644<br>
--- a/.gitignore<br>
+++ b/.gitignore<br>
@@ -45,6 +45,7 @@ weston-gears<br>
 weston-image<br>
 weston-nested<br>
 weston-nested-client<br>
+weston-presentation-shm<br>
 weston-resizor<br>
 weston-scaler<br>
 weston-simple-egl<br>
diff --git a/Makefile.am b/Makefile.am<br>
index 87204a6..10be920 100644<br>
--- a/Makefile.am<br>
+++ b/Makefile.am<br>
@@ -393,6 +393,7 @@ demo_clients +=                                     \<br>
        weston-simple-shm                       \<br>
        weston-simple-damage                    \<br>
        weston-simple-touch                     \<br>
+       weston-presentation-shm                 \<br>
        weston-multi-resource<br>
<br>
 weston_simple_shm_SOURCES = clients/simple-shm.c<br>
@@ -419,6 +420,13 @@ weston_simple_touch_SOURCES = clients/simple-touch.c<br>
 weston_simple_touch_CFLAGS = $(AM_CFLAGS) $(SIMPLE_CLIENT_CFLAGS)<br>
 weston_simple_touch_LDADD = $(SIMPLE_CLIENT_LIBS) <a href="http://libshared.la" target="_blank">libshared.la</a><br>
<br>
+weston_presentation_shm_SOURCES = clients/presentation-shm.c<br>
+nodist_weston_presentation_shm_SOURCES =               \<br>
+       protocol/presentation_timing-protocol.c         \<br>
+       protocol/presentation_timing-client-protocol.h<br>
+weston_presentation_shm_CFLAGS = $(AM_CFLAGS) $(SIMPLE_CLIENT_CFLAGS)<br>
+weston_presentation_shm_LDADD = $(SIMPLE_CLIENT_LIBS) <a href="http://libshared.la" target="_blank">libshared.la</a> -lm<br>
+<br>
 weston_multi_resource_SOURCES = clients/multi-resource.c<br>
 weston_multi_resource_CFLAGS = $(AM_CFLAGS) $(SIMPLE_CLIENT_CFLAGS)<br>
 weston_multi_resource_LDADD = $(SIMPLE_CLIENT_LIBS) <a href="http://libshared.la" target="_blank">libshared.la</a> -lm<br>
diff --git a/clients/presentation-shm.c b/clients/presentation-shm.c<br>
new file mode 100644<br>
index 0000000..2976b49<br>
--- /dev/null<br>
+++ b/clients/presentation-shm.c<br>
@@ -0,0 +1,866 @@<br>
+/*<br>
+ * Copyright © 2011 Benjamin Franzke<br>
+ * Copyright © 2010 Intel Corporation<br>
+ * Copyright © 2014 Collabora, Ltd.<br>
+ *<br>
+ * Permission to use, copy, modify, distribute, and sell this software and its<br>
+ * documentation for any purpose is hereby granted without fee, provided that<br>
+ * the above copyright notice appear in all copies and that both that copyright<br>
+ * notice and this permission notice appear in supporting documentation, and<br>
+ * that the name of the copyright holders not be used in advertising or<br>
+ * publicity pertaining to distribution of the software without specific,<br>
+ * written prior permission.  The copyright holders make no representations<br>
+ * about the suitability of this software for any purpose.  It is provided "as<br>
+ * is" without express or implied warranty.<br>
+ *<br>
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,<br>
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO<br>
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR<br>
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,<br>
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER<br>
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE<br>
+ * OF THIS SOFTWARE.<br>
+ */<br>
+<br>
+#include <config.h><br>
+<br>
+#include <stdio.h><br>
+#include <stdlib.h><br>
+#include <string.h><br>
+#include <stdbool.h><br>
+#include <assert.h><br>
+#include <unistd.h><br>
+#include <sys/mman.h><br>
+#include <signal.h><br>
+#include <time.h><br>
+<br>
+#include <wayland-client.h><br>
+#include "../shared/os-compatibility.h"<br>
+#include "presentation_timing-client-protocol.h"<br>
+<br>
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])<br>
+<br>
+enum run_mode {<br>
+       RUN_MODE_FEEDBACK,<br>
+       RUN_MODE_FEEDBACK_IDLE,<br>
+       RUN_MODE_PRESENT,<br>
+};<br>
+<br>
+struct output {<br>
+       struct wl_output *output;<br>
+       uint32_t name;<br>
+       struct wl_list link;<br>
+};<br>
+<br>
+struct display {<br>
+       struct wl_display *display;<br>
+       struct wl_registry *registry;<br>
+       struct wl_compositor *compositor;<br>
+       struct wl_shell *shell;<br>
+<br>
+       struct wl_shm *shm;<br>
+       uint32_t formats;<br>
+<br>
+       struct presentation *presentation;<br>
+       clockid_t clk_id;<br>
+<br>
+       struct wl_list output_list; /* struct output::link */<br>
+};<br>
+<br>
+struct feedback {<br>
+       struct window *window;<br>
+       unsigned frame_no;<br>
+       struct presentation_feedback *feedback;<br>
+       struct timespec commit;<br>
+       struct timespec target;<br>
+       uint32_t frame_stamp;<br>
+       struct wl_list link;<br>
+       struct timespec present;<br>
+};<br>
+<br>
+struct buffer {<br>
+       struct wl_buffer *buffer;<br>
+       void *shm_data;<br>
+       int busy;<br>
+};<br>
+<br>
+struct window {<br>
+       struct display *display;<br>
+       int width, height;<br>
+       enum run_mode mode;<br>
+       struct wl_surface *surface;<br>
+       struct wl_shell_surface *shell_surface;<br>
+<br>
+       struct buffer *buffers;<br>
+       int num_buffers;<br>
+       int next;<br>
+       int refresh_nsec;<br>
+<br>
+       struct wl_callback *callback;<br>
+       struct wl_list feedback_list;<br>
+<br>
+       struct feedback *received_feedback;<br>
+};<br>
+<br>
+#define NSEC_PER_SEC 1000000000<br>
+<br>
+static void<br>
+buffer_release(void *data, struct wl_buffer *buffer)<br>
+{<br>
+       struct buffer *mybuf = data;<br>
+<br>
+       mybuf->busy = 0;<br>
+}<br>
+<br>
+static const struct wl_buffer_listener buffer_listener = {<br>
+       buffer_release<br>
+};<br>
+<br>
+static int<br>
+create_shm_buffers(struct display *display, struct buffer **buffers,<br>
+                  int num_buffers, int width, int height, uint32_t format)<br>
+{<br>
+       struct buffer *bufs;<br>
+       struct wl_shm_pool *pool;<br>
+       int fd, size, stride, offset;<br>
+       void *data;<br>
+       int i;<br>
+<br>
+       stride = width * 4;<br>
+       size = stride * height * num_buffers;<br>
+<br>
+       fd = os_create_anonymous_file(size);<br>
+       if (fd < 0) {<br>
+               fprintf(stderr, "creating a buffer file for %d B failed: %m\n",<br>
+                       size);<br>
+               return -1;<br>
+       }<br>
+<br>
+       data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);<br>
+       if (data == MAP_FAILED) {<br>
+               fprintf(stderr, "mmap failed: %m\n");<br>
+               close(fd);<br>
+               return -1;<br>
+       }<br>
+<br>
+       pool = wl_shm_create_pool(display->shm, fd, size);<br>
+       offset = 0;<br>
+<br>
+       bufs = calloc(num_buffers, sizeof(*bufs));<br>
+       assert(bufs);<br>
+<br>
+       for (i = 0; i < num_buffers; i++) {<br>
+               bufs[i].buffer = wl_shm_pool_create_buffer(pool, offset,<br>
+                                                          width, height,<br>
+                                                          stride, format);<br>
+               assert(bufs[i].buffer);<br>
+               wl_buffer_add_listener(bufs[i].buffer,<br>
+                                      &buffer_listener, &bufs[i]);<br>
+<br>
+               bufs[i].shm_data = (char *)data + offset;<br>
+               offset += stride * height;<br>
+       }<br>
+<br>
+       wl_shm_pool_destroy(pool);<br>
+       close(fd);<br>
+<br>
+       *buffers = bufs;<br>
+<br>
+       return 0;<br>
+}<br>
+<br>
+static void<br>
+handle_ping(void *data, struct wl_shell_surface *shell_surface,<br>
+                                                       uint32_t serial)<br>
+{<br>
+       wl_shell_surface_pong(shell_surface, serial);<br>
+}<br>
+<br>
+static void<br>
+handle_configure(void *data, struct wl_shell_surface *shell_surface,<br>
+                uint32_t edges, int32_t width, int32_t height)<br>
+{<br>
+}<br>
+<br>
+static void<br>
+handle_popup_done(void *data, struct wl_shell_surface *shell_surface)<br>
+{<br>
+}<br>
+<br>
+static const struct wl_shell_surface_listener shell_surface_listener = {<br>
+       handle_ping,<br>
+       handle_configure,<br>
+       handle_popup_done<br>
+};<br>
+<br>
+static struct window *<br>
+create_window(struct display *display, int width, int height,<br>
+             enum run_mode mode)<br>
+{<br>
+       struct window *window;<br>
+       int ret;<br>
+<br>
+       window = calloc(1, sizeof *window);<br>
+       if (!window)<br>
+               return NULL;<br>
+<br>
+       window->mode = mode;<br>
+       window->callback = NULL;<br>
+       wl_list_init(&window->feedback_list);<br>
+       window->display = display;<br>
+       window->width = width;<br>
+       window->height = height;<br>
+       window->surface = wl_compositor_create_surface(display->compositor);<br>
+       window->shell_surface = wl_shell_get_shell_surface(display->shell,<br>
+                                                          window->surface);<br>
+<br>
+       if (window->shell_surface)<br>
+               wl_shell_surface_add_listener(window->shell_surface,<br>
+                                             &shell_surface_listener, window);<br>
+<br>
+       wl_shell_surface_set_title(window->shell_surface, "presentation-shm");<br>
+<br>
+       wl_shell_surface_set_toplevel(window->shell_surface);<br>
+<br>
+       window->num_buffers = 60;<br>
+       window->refresh_nsec = NSEC_PER_SEC / 60; /* 60 Hz guess */<br>
+       window->next = 0;<br>
+       ret = create_shm_buffers(window->display,<br>
+                                &window->buffers, window->num_buffers,<br>
+                                window->width, window->height,<br>
+                                WL_SHM_FORMAT_XRGB8888);<br>
+       assert(ret == 0);<br>
+<br>
+       return window;<br>
+}<br>
+<br>
+static void<br>
+destroy_feedback(struct feedback *feedback)<br>
+{<br>
+       if (feedback->feedback)<br>
+               presentation_feedback_destroy(feedback->feedback);<br>
+<br>
+       wl_list_remove(&feedback->link);<br>
+       free(feedback);<br>
+}<br>
+<br>
+static void<br>
+destroy_window(struct window *window)<br>
+{<br>
+       int i;<br>
+<br>
+       while (!wl_list_empty(&window->feedback_list)) {<br>
+               struct feedback *f;<br>
+<br>
+               f = wl_container_of(window->feedback_list.next, f, link);<br>
+               printf("clean up feedback %u\n", f->frame_no);<br>
+               destroy_feedback(f);<br>
+       }<br>
+<br>
+       if (window->callback)<br>
+               wl_callback_destroy(window->callback);<br>
+<br>
+       wl_shell_surface_destroy(window->shell_surface);<br>
+       wl_surface_destroy(window->surface);<br>
+<br>
+       for (i = 0; i < window->num_buffers; i++)<br>
+               wl_buffer_destroy(window->buffers[i].buffer);<br>
+       /* munmap(window->buffers[0].shm_data, size); */<br>
+       free(window->buffers);<br>
+<br>
+       free(window);<br>
+}<br>
+<br>
+static struct buffer *<br>
+window_next_buffer(struct window *window)<br>
+{<br>
+       struct buffer *buf = &window->buffers[window->next];<br>
+<br>
+       window->next = (window->next + 1) % window->num_buffers;<br>
+<br>
+       return buf;<br>
+}<br>
+<br>
+static void<br>
+paint_pixels(void *image, int width, int height, uint32_t phase)<br>
+{<br>
+       const int halfh = height / 2;<br>
+       const int halfw = width / 2;<br>
+       uint32_t *pixel = image;<br>
+       int y, or;<br>
+       double ang = M_PI * 2.0 / 1000000.0 * phase;<br>
+       double s = sin(ang);<br>
+       double c = cos(ang);<br>
+<br>
+       /* squared radii thresholds */<br>
+       or = (halfw < halfh ? halfw : halfh) - 16;<br>
+       or *= or;<br>
+<br>
+       for (y = 0; y < height; y++) {<br>
+               int x;<br>
+               int oy = y - halfh;<br>
+               int y2 = oy * oy;<br>
+<br>
+               for (x = 0; x < width; x++) {<br>
+                       int ox = x - halfw;<br>
+                       uint32_t v = 0xff000000;<br>
+                       double rx, ry;<br>
+<br>
+                       if (ox * ox + y2 > or) {<br>
+                               if (ox * oy > 0)<br>
+                                       *pixel++ = 0xff000000;<br>
+                               else<br>
+                                       *pixel++ = 0xffffffff;<br>
+                               continue;<br>
+                       }<br>
+<br>
+                       rx = c * ox + s * oy;<br>
+                       ry = -s * ox + c * oy;<br>
+<br>
+                       if (rx < 0.0)<br>
+                               v |= 0x00ff0000;<br>
+                       if (ry < 0.0)<br>
+                               v |= 0x0000ff00;<br>
+                       if ((rx < 0.0) == (ry < 0.0))<br>
+                               v |= 0x000000ff;<br>
+<br>
+                       *pixel++ = v;<br>
+               }<br>
+       }<br>
+}<br>
+<br>
+static void<br>
+feedback_sync_output(void *data,<br>
+                    struct presentation_feedback *presentation_feedback,<br>
+                    struct wl_output *output)<br>
+{<br>
+       /* not interested */<br>
+}<br>
+<br>
+static char *<br>
+pflags_to_str(uint32_t flags, char *str, unsigned len)<br>
+{<br>
+       static const struct {<br>
+               uint32_t flag;<br>
+               char sym;<br>
+       } desc[] = {<br>
+       };<br>
+       unsigned i;<br>
+<br>
+       *str = '\0';<br>
+       if (len < ARRAY_LENGTH(desc) + 1)<br>
+               return str;<br>
+<br>
+       for (i = 0; i < ARRAY_LENGTH(desc); i++)<br>
+               str[i] = flags & desc[i].flag ? desc[i].sym : '_';<br>
+       str[ARRAY_LENGTH(desc)] = '\0';<br>
+<br>
+       return str;<br>
+}<br>
+<br>
+static uint32_t<br>
+timespec_to_ms(const struct timespec *ts)<br>
+{<br>
+       return (uint32_t)ts->tv_sec * 1000 + ts->tv_nsec / 1000000;<br>
+}<br>
+<br>
+static void<br>
+timespec_from_proto(struct timespec *tm, uint32_t tv_sec_hi,<br>
+                   uint32_t tv_sec_lo, uint32_t tv_nsec)<br>
+{<br>
+       tm->tv_sec = ((uint64_t)tv_sec_hi << 32) + tv_sec_lo;<br>
+       tm->tv_nsec = tv_nsec;<br>
+}<br>
+<br>
+static int<br>
+timespec_diff_to_usec(const struct timespec *a, const struct timespec *b)<br>
+{<br>
+       time_t secs = a->tv_sec - b->tv_sec;<br>
+       long nsec = a->tv_nsec - b->tv_nsec;<br>
+<br>
+       return secs * 1000000 + nsec / 1000;<br>
+}<br>
+<br>
+static void<br>
+feedback_presented(void *data,<br>
+                  struct presentation_feedback *presentation_feedback,<br>
+                  uint32_t tv_sec_hi,<br>
+                  uint32_t tv_sec_lo,<br>
+                  uint32_t tv_nsec,<br>
+                  uint32_t refresh_nsec,<br>
+                  uint32_t seq_hi,<br>
+                  uint32_t seq_lo,<br>
+                  uint32_t flags)<br>
+{<br>
+       struct feedback *feedback = data;<br>
+       struct window *window = feedback->window;<br>
+       struct feedback *prev_feedback = window->received_feedback;<br>
+       uint64_t seq = ((uint64_t)seq_hi << 32) + seq_lo;<br>
+       const struct timespec *prevpresent;<br>
+       uint32_t commit, present;<br>
+       uint32_t f2c, c2p, f2p;<br>
+       int p2p, t2p;<br>
+       char flagstr[10];<br>
+<br>
+       timespec_from_proto(&feedback->present, tv_sec_hi, tv_sec_lo, tv_nsec);<br>
+       commit = timespec_to_ms(&feedback->commit);<br>
+       present = timespec_to_ms(&feedback->present);<br>
+<br>
+       if (prev_feedback)<br>
+               prevpresent = &prev_feedback->present;<br>
+       else<br>
+               prevpresent = &feedback->present;<br>
+<br>
+       f2c = commit - feedback->frame_stamp;<br>
+       c2p = present - commit;<br>
+       f2p = present - feedback->frame_stamp;<br>
+       p2p = timespec_diff_to_usec(&feedback->present, prevpresent);<br>
+       t2p = timespec_diff_to_usec(&feedback->present, &feedback->target);<br>
+<br>
+       switch (window->mode) {<br>
+       case RUN_MODE_PRESENT:<br>
+               printf("%6u: c2p %4u ms, p2p %5d us, t2p %6d us, [%s] "<br>
+                       "seq %" PRIu64 "\n", feedback->frame_no, c2p,<br>
+                       p2p, t2p,<br>
+                       pflags_to_str(flags, flagstr, sizeof(flagstr)), seq);<br>
+               break;<br>
+       case RUN_MODE_FEEDBACK:<br>
+       case RUN_MODE_FEEDBACK_IDLE:<br>
+               printf("%6u: f2c %2u ms, c2p %2u ms, f2p %2u ms, p2p %5d us, "<br>
+                       "t2p %6d, [%s], seq %" PRIu64 "\n", feedback->frame_no,<br>
+                       f2c, c2p, f2p, p2p, t2p,<br>
+                       pflags_to_str(flags, flagstr, sizeof(flagstr)), seq);<br>
+       }<br>
+<br>
+       if (window->received_feedback)<br>
+               destroy_feedback(window->received_feedback);<br>
+       window->received_feedback = feedback;<br>
+}<br>
+<br>
+static void<br>
+feedback_discarded(void *data,<br>
+                  struct presentation_feedback *presentation_feedback)<br>
+{<br>
+       struct feedback *feedback = data;<br>
+<br>
+       printf("discarded %u\n", feedback->frame_no);<br>
+<br>
+       destroy_feedback(feedback);<br>
+}<br>
+<br>
+static const struct presentation_feedback_listener feedback_listener = {<br>
+       feedback_sync_output,<br>
+       feedback_presented,<br>
+       feedback_discarded<br>
+};<br>
+<br>
+static void<br>
+window_create_feedback(struct window *window, uint32_t frame_stamp)<br>
+{<br>
+       static unsigned seq;<br>
+       struct presentation *pres = window->display->presentation;<br>
+       struct feedback *feedback;<br>
+<br>
+       seq++;<br>
+<br>
+       if (!pres)<br>
+               return;<br>
+<br>
+       feedback = calloc(1, sizeof *feedback);<br>
+       if (!feedback)<br>
+               return;<br>
+<br>
+       feedback->window = window;<br>
+       feedback->feedback = presentation_feedback(pres, window->surface);<br>
+       presentation_feedback_add_listener(feedback->feedback,<br>
+                                          &feedback_listener, feedback);<br>
+<br>
+       feedback->frame_no = seq;<br>
+       clock_gettime(window->display->clk_id, &feedback->commit);<br>
+       feedback->frame_stamp = frame_stamp;<br>
+       feedback->target = feedback->commit;<br>
+<br>
+       wl_list_insert(&window->feedback_list, &feedback->link);<br>
+}<br>
+<br>
+static void<br>
+window_commit_next(struct window *window)<br>
+{<br>
+       struct buffer *buffer;<br>
+<br>
+       buffer = window_next_buffer(window);<br>
+       assert(buffer);<br>
+<br>
+       wl_surface_attach(window->surface, buffer->buffer, 0, 0);<br>
+       wl_surface_damage(window->surface, 0, 0, window->width, window->height);<br>
+       wl_surface_commit(window->surface);<br>
+       buffer->busy = 1;<br>
+}<br>
+<br>
+static const struct wl_callback_listener frame_listener_mode_feedback;<br>
+<br>
+static void<br>
+redraw_mode_feedback(void *data, struct wl_callback *callback, uint32_t time)<br>
+{<br>
+       struct window *window = data;<br>
+<br>
+       if (callback && window->mode == RUN_MODE_FEEDBACK_IDLE)<br>
+               sleep(1);<br>
+<br>
+       if (callback)<br>
+               wl_callback_destroy(callback);<br>
+<br>
+       window->callback = wl_surface_frame(window->surface);<br>
+       wl_callback_add_listener(window->callback,<br>
+                                &frame_listener_mode_feedback, window);<br>
+<br>
+       window_create_feedback(window, time);<br>
+       window_commit_next(window);<br>
+}<br>
+<br>
+static const struct wl_callback_listener frame_listener_mode_feedback = {<br>
+       redraw_mode_feedback<br>
+};<br>
+<br>
+static const struct presentation_feedback_listener feedkick_listener;<br>
+<br>
+static void<br>
+window_feedkick(struct window *window)<br>
+{<br>
+       struct presentation *pres = window->display->presentation;<br>
+       struct presentation_feedback *fback;<br>
+<br>
+       fback = presentation_feedback(pres, window->surface);<br>
+       presentation_feedback_add_listener(fback, &feedkick_listener, window);<br>
+}<br>
+<br>
+static void<br>
+feedkick_presented(void *data,<br>
+                  struct presentation_feedback *presentation_feedback,<br>
+                  uint32_t tv_sec_hi,<br>
+                  uint32_t tv_sec_lo,<br>
+                  uint32_t tv_nsec,<br>
+                  uint32_t refresh_nsec,<br>
+                  uint32_t seq_hi,<br>
+                  uint32_t seq_lo,<br>
+                  uint32_t flags)<br>
+{<br>
+       struct window *window = data;<br>
+<br>
+       presentation_feedback_destroy(presentation_feedback);<br>
+       window->refresh_nsec = refresh_nsec;<br>
+<br>
+       switch (window->mode) {<br>
+       case RUN_MODE_PRESENT:<br>
+               window_create_feedback(window, 0);<br>
+               window_feedkick(window);<br>
+               window_commit_next(window);<br>
+               break;<br>
+       case RUN_MODE_FEEDBACK:<br>
+       case RUN_MODE_FEEDBACK_IDLE:<br>
+               assert(0 && "bad mode");<br>
+       }<br>
+}<br>
+<br>
+static void<br>
+feedkick_discarded(void *data,<br>
+                  struct presentation_feedback *presentation_feedback)<br>
+{<br>
+       struct window *window = data;<br>
+<br>
+       presentation_feedback_destroy(presentation_feedback);<br>
+<br>
+       switch (window->mode) {<br>
+       case RUN_MODE_PRESENT:<br>
+               window_create_feedback(window, 0);<br>
+               window_feedkick(window);<br>
+               window_commit_next(window);<br>
+               break;<br>
+       case RUN_MODE_FEEDBACK:<br>
+       case RUN_MODE_FEEDBACK_IDLE:<br>
+               assert(0 && "bad mode");<br>
+       }<br>
+}<br>
+<br>
+static const struct presentation_feedback_listener feedkick_listener = {<br>
+       feedback_sync_output,<br>
+       feedkick_presented,<br>
+       feedkick_discarded<br>
+};<br>
+<br>
+static void<br>
+firstdraw_mode_burst(struct window *window)<br>
+{<br>
+       switch (window->mode) {<br>
+       case RUN_MODE_PRESENT:<br>
+               window_create_feedback(window, 0);<br>
+               break;<br>
+       case RUN_MODE_FEEDBACK:<br>
+       case RUN_MODE_FEEDBACK_IDLE:<br>
+               assert(0 && "bad mode");<br>
+       }<br>
+<br>
+       window_feedkick(window);<br>
+       window_commit_next(window);<br>
+}<br>
+<br>
+static void<br>
+window_prerender(struct window *window)<br>
+{<br>
+       int i;<br>
+       int timefactor = 1000000 / window->num_buffers;<br>
+<br>
+       for (i = 0; i < window->num_buffers; i++) {<br>
+               struct buffer *buf = &window->buffers[i];<br>
+<br>
+               if (buf->busy)<br>
+                       fprintf(stderr, "wl_buffer id %u) busy\n",<br>
+                               wl_proxy_get_id(<br>
+                                       (struct wl_proxy *)buf->buffer));<br>
+<br>
+               paint_pixels(buf->shm_data, window->width, window->height,<br>
+                            i * timefactor);<br>
+       }<br>
+}<br>
+<br>
+static void<br>
+output_destroy(struct output *o)<br>
+{<br>
+       wl_output_destroy(o->output);<br>
+       wl_list_remove(&o->link);<br>
+       free(o);<br>
+}<br>
+<br>
+static void<br>
+display_add_output(struct display *d, uint32_t name, uint32_t version)<br>
+{<br>
+       struct output *o;<br>
+<br>
+       o = calloc(1, sizeof(*o));<br>
+       assert(o);<br>
+<br>
+       o->output = wl_registry_bind(d->registry, name,<br>
+                                    &wl_output_interface, 1);<br>
+       o->name = name;<br>
+       wl_list_insert(&d->output_list, &o->link);<br>
+}<br>
+<br>
+static void<br>
+presentation_clock_id(void *data, struct presentation *presentation,<br>
+                     uint32_t clk_id)<br>
+{<br>
+       struct display *d = data;<br>
+<br>
+       d->clk_id = clk_id;<br>
+}<br>
+<br>
+static const struct presentation_listener presentation_listener = {<br>
+       presentation_clock_id<br>
+};<br>
+<br>
+static void<br>
+shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)<br>
+{<br>
+       struct display *d = data;<br>
+<br>
+       d->formats |= (1 << format);<br>
+}<br>
+<br>
+static const struct wl_shm_listener shm_listener = {<br>
+       shm_format<br>
+};<br>
+<br>
+static void<br>
+registry_handle_global(void *data, struct wl_registry *registry,<br>
+                      uint32_t name, const char *interface, uint32_t version)<br>
+{<br>
+       struct display *d = data;<br>
+<br>
+       if (strcmp(interface, "wl_compositor") == 0) {<br>
+               d->compositor =<br>
+                       wl_registry_bind(registry,<br>
+                                        name, &wl_compositor_interface, 1);<br>
+       } else if (strcmp(interface, "wl_shell") == 0) {<br>
+               d->shell = wl_registry_bind(registry,<br>
+                                           name, &wl_shell_interface, 1);<br>
+       } else if (strcmp(interface, "wl_shm") == 0) {<br>
+               d->shm = wl_registry_bind(registry,<br>
+                                         name, &wl_shm_interface, 1);<br>
+               wl_shm_add_listener(d->shm, &shm_listener, d);<br>
+       } else if (strcmp(interface, "wl_output") == 0) {<br>
+               display_add_output(d, name, version);<br>
+       } else if (strcmp(interface, "presentation") == 0) {<br>
+               d->presentation =<br>
+                       wl_registry_bind(registry,<br>
+                                        name, &presentation_interface, 1);<br>
+               presentation_add_listener(d->presentation,<br>
+                                         &presentation_listener, d);<br>
+       }<br>
+}<br>
+<br>
+static void<br>
+registry_handle_global_remove(void *data, struct wl_registry *registry,<br>
+                             uint32_t name)<br>
+{<br>
+       struct display *d = data;<br>
+       struct output *output, *otmp;<br>
+<br>
+       wl_list_for_each_safe(output, otmp, &d->output_list, link) {<br>
+               if (output->name != name)<br>
+                       continue;<br>
+<br>
+               output_destroy(output);<br>
+       }<br>
+}<br>
+<br>
+static const struct wl_registry_listener registry_listener = {<br>
+       registry_handle_global,<br>
+       registry_handle_global_remove<br>
+};<br>
+<br>
+static struct display *<br>
+create_display(void)<br>
+{<br>
+       struct display *display;<br>
+<br>
+       display = malloc(sizeof *display);<br>
+       if (display == NULL) {<br>
+               fprintf(stderr, "out of memory\n");<br>
+               exit(1);<br>
+       }<br>
+       display->display = wl_display_connect(NULL);<br>
+       assert(display->display);<br>
+<br>
+       display->formats = 0;<br>
+       display->clk_id = -1;<br>
+       wl_list_init(&display->output_list);<br>
+       display->registry = wl_display_get_registry(display->display);<br>
+       wl_registry_add_listener(display->registry,<br>
+                                &registry_listener, display);<br>
+       wl_display_roundtrip(display->display);<br>
+       if (display->shm == NULL) {<br>
+               fprintf(stderr, "No wl_shm global\n");<br>
+               exit(1);<br>
+       }<br>
+<br>
+       wl_display_roundtrip(display->display);<br>
+<br>
+       if (!(display->formats & (1 << WL_SHM_FORMAT_XRGB8888))) {<br>
+               fprintf(stderr, "WL_SHM_FORMAT_XRGB32 not available\n");<br>
+               exit(1);<br>
+       }<br>
+<br>
+       wl_display_get_fd(display->display);<br>
+<br>
+       return display;<br>
+}<br>
+<br>
+static void<br>
+destroy_display(struct display *display)<br>
+{<br>
+       while (!wl_list_empty(&display->output_list)) {<br>
+               struct output *o;<br>
+<br>
+               o = wl_container_of(display->output_list.next, o, link);<br>
+               output_destroy(o);<br>
+       }<br>
+<br>
+       if (display->shm)<br>
+               wl_shm_destroy(display->shm);<br>
+<br>
+       if (display->shell)<br>
+               wl_shell_destroy(display->shell);<br>
+<br>
+       if (display->compositor)<br>
+               wl_compositor_destroy(display->compositor);<br>
+<br>
+       wl_registry_destroy(display->registry);<br>
+       wl_display_flush(display->display);<br>
+       wl_display_disconnect(display->display);<br>
+       free(display);<br>
+}<br>
+<br>
+static int running = 1;<br>
+<br>
+static void<br>
+signal_int(int signum)<br>
+{<br>
+       running = 0;<br>
+}<br>
+<br>
+static void<br>
+usage(const char *prog, int exit_code)<br>
+{<br>
+       fprintf(stderr, "Usage: %s [mode] [options]\n"<br>
+               "where 'mode' is one of\n"<br>
+               "  -f\trun in feedback mode (default)\n"<br>
+               "  -i\trun in feedback-idle mode; sleep 1s between frames\n"<br>
+               "  -p\trun in low-latency presentation mode\n"<br>
+               "and 'options' may include\n",<br>
+               prog);<br>
+<br>
+       fprintf(stderr, "Printed timing statistics, depending on mode:\n"<br>
+               "  commit sequence number\n"<br>
+               "  f2c: time from frame callback timestamp to commit\n"<br>
+               "  c2p: time from commit to presentation\n"<br>
+               "  f2p: time from frame callback timestamp to presentation\n"<br>
+               "  p2p: time from previous presentation to this one\n"<br>
+               "  t2p: time from target timestamp to presentation\n"<br>
+               "  seq: MSC\n");<br>
+<br>
+<br>
+       exit(exit_code);<br>
+}<br>
+<br>
+int<br>
+main(int argc, char **argv)<br>
+{<br>
+       struct sigaction sigint;<br>
+       struct display *display;<br>
+       struct window *window;<br>
+       int ret = 0;<br>
+       enum run_mode mode = RUN_MODE_FEEDBACK;<br>
+       int i;<br>
+<br>
+       for (i = 1; i < argc; i++) {<br>
+               if (strcmp("-f", argv[i]) == 0)<br>
+                       mode = RUN_MODE_FEEDBACK;<br>
+               else if (strcmp("-i", argv[i]) == 0)<br>
+                       mode = RUN_MODE_FEEDBACK_IDLE;<br>
+               else if (strcmp("-p", argv[i]) == 0)<br>
+                       mode = RUN_MODE_PRESENT;<br>
+               else<br>
+                       usage(argv[0], EXIT_FAILURE);<br>
+       }<br>
+<br>
+       display = create_display();<br>
+       window = create_window(display, 250, 250, mode);<br>
+       if (!window)<br>
+               return 1;<br>
+<br>
+       sigint.sa_handler = signal_int;<br>
+       sigemptyset(&sigint.sa_mask);<br>
+       sigint.sa_flags = SA_RESETHAND;<br>
+       sigaction(SIGINT, &sigint, NULL);<br>
+<br>
+       window_prerender(window);<br>
+<br>
+       switch (mode) {<br>
+       case RUN_MODE_FEEDBACK:<br>
+       case RUN_MODE_FEEDBACK_IDLE:<br>
+               redraw_mode_feedback(window, NULL, 0);<br>
+               break;<br>
+       case RUN_MODE_PRESENT:<br>
+               firstdraw_mode_burst(window);<br>
+               break;<br>
+       }<br>
+<br>
+       while (running && ret != -1)<br>
+               ret = wl_display_dispatch(display->display);<br>
+<br>
+       fprintf(stderr, "presentation-shm exiting\n");<br>
+       destroy_window(window);<br>
+       destroy_display(display);<br>
+<br>
+       return 0;<br>
+}<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.9.3<br>
<br>
_______________________________________________<br>
wayland-devel mailing list<br>
<a href="mailto:wayland-devel@lists.freedesktop.org">wayland-devel@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/wayland-devel" target="_blank">http://lists.freedesktop.org/mailman/listinfo/wayland-devel</a><br>
</font></span></blockquote></div><br><br clear="all"><br>-- <br>  Jasper<br>
</div>