tests: add test_seat_release() for symmetry
[platform/upstream/weston.git] / tests / presentation-test.c
1 /*
2  * Copyright © 2014 Collabora, Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25
26 #include "config.h"
27
28 #include <stdint.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <assert.h>
33 #include <time.h>
34
35 #include "shared/helpers.h"
36 #include "shared/xalloc.h"
37 #include "shared/timespec-util.h"
38 #include "weston-test-client-helper.h"
39 #include "presentation-time-client-protocol.h"
40
41 static struct wp_presentation *
42 get_presentation(struct client *client)
43 {
44         struct global *g;
45         struct global *global_pres = NULL;
46         static struct wp_presentation *pres;
47
48         if (pres)
49                 return pres;
50
51         wl_list_for_each(g, &client->global_list, link) {
52                 if (strcmp(g->interface, wp_presentation_interface.name))
53                         continue;
54
55                 if (global_pres)
56                         assert(0 && "multiple presentation objects");
57
58                 global_pres = g;
59         }
60
61         assert(global_pres && "no presentation found");
62
63         assert(global_pres->version == 1);
64
65         pres = wl_registry_bind(client->wl_registry, global_pres->name,
66                                 &wp_presentation_interface, 1);
67         assert(pres);
68
69         return pres;
70 }
71
72 struct feedback {
73         struct client *client;
74         struct wp_presentation_feedback *obj;
75
76         enum {
77                 FB_PENDING = 0,
78                 FB_PRESENTED,
79                 FB_DISCARDED
80         } result;
81
82         struct wl_output *sync_output;
83         uint64_t seq;
84         struct timespec time;
85         uint32_t refresh_nsec;
86         uint32_t flags;
87 };
88
89 static void
90 feedback_sync_output(void *data,
91                      struct wp_presentation_feedback *presentation_feedback,
92                      struct wl_output *output)
93 {
94         struct feedback *fb = data;
95
96         assert(fb->result == FB_PENDING);
97
98         if (output)
99                 fb->sync_output = output;
100 }
101
102 static void
103 feedback_presented(void *data,
104                    struct wp_presentation_feedback *presentation_feedback,
105                    uint32_t tv_sec_hi,
106                    uint32_t tv_sec_lo,
107                    uint32_t tv_nsec,
108                    uint32_t refresh_nsec,
109                    uint32_t seq_hi,
110                    uint32_t seq_lo,
111                    uint32_t flags)
112 {
113         struct feedback *fb = data;
114
115         assert(fb->result == FB_PENDING);
116         fb->result = FB_PRESENTED;
117         fb->seq = ((uint64_t)seq_hi << 32) + seq_lo;
118         timespec_from_proto(&fb->time, tv_sec_hi, tv_sec_lo, tv_nsec);
119         fb->refresh_nsec = refresh_nsec;
120         fb->flags = flags;
121 }
122
123 static void
124 feedback_discarded(void *data,
125                    struct wp_presentation_feedback *presentation_feedback)
126 {
127         struct feedback *fb = data;
128
129         assert(fb->result == FB_PENDING);
130         fb->result = FB_DISCARDED;
131 }
132
133 static const struct wp_presentation_feedback_listener feedback_listener = {
134         feedback_sync_output,
135         feedback_presented,
136         feedback_discarded
137 };
138
139 static struct feedback *
140 feedback_create(struct client *client, struct wl_surface *surface)
141 {
142         struct feedback *fb;
143
144         fb = xzalloc(sizeof *fb);
145         fb->client = client;
146         fb->obj = wp_presentation_feedback(get_presentation(client), surface);
147         wp_presentation_feedback_add_listener(fb->obj, &feedback_listener, fb);
148
149         return fb;
150 }
151
152 static void
153 feedback_wait(struct feedback *fb)
154 {
155         while (fb->result == FB_PENDING) {
156                 assert(wl_display_dispatch(fb->client->wl_display) >= 0);
157         }
158 }
159
160 static char *
161 pflags_to_str(uint32_t flags, char *str, unsigned len)
162 {
163         static const struct {
164                 uint32_t flag;
165                 char sym;
166         } desc[] = {
167                 { WP_PRESENTATION_FEEDBACK_KIND_VSYNC, 's' },
168                 { WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK, 'c' },
169                 { WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION, 'e' },
170                 { WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY, 'z' },
171         };
172         unsigned i;
173
174         *str = '\0';
175         if (len < ARRAY_LENGTH(desc) + 1)
176                 return str;
177
178         for (i = 0; i < ARRAY_LENGTH(desc); i++)
179                 str[i] = flags & desc[i].flag ? desc[i].sym : '_';
180         str[ARRAY_LENGTH(desc)] = '\0';
181
182         return str;
183 }
184
185 static void
186 feedback_print(struct feedback *fb)
187 {
188         char str[10];
189
190         switch (fb->result) {
191         case FB_PENDING:
192                 printf("pending");
193                 return;
194         case FB_DISCARDED:
195                 printf("discarded");
196                 return;
197         case FB_PRESENTED:
198                 break;
199         }
200
201         pflags_to_str(fb->flags, str, sizeof str);
202         printf("presented %lld.%09lld, refresh %u us, [%s] seq %" PRIu64,
203                 (long long)fb->time.tv_sec, (long long)fb->time.tv_nsec,
204                 fb->refresh_nsec / 1000, str, fb->seq);
205 }
206
207 static void
208 feedback_destroy(struct feedback *fb)
209 {
210         wp_presentation_feedback_destroy(fb->obj);
211         free(fb);
212 }
213
214 TEST(test_presentation_feedback_simple)
215 {
216         struct client *client;
217         struct feedback *fb;
218
219         client = create_client_and_test_surface(100, 50, 123, 77);
220         assert(client);
221
222         wl_surface_attach(client->surface->wl_surface,
223                           client->surface->buffer->proxy, 0, 0);
224         fb = feedback_create(client, client->surface->wl_surface);
225         wl_surface_damage(client->surface->wl_surface, 0, 0, 100, 100);
226         wl_surface_commit(client->surface->wl_surface);
227
228         client_roundtrip(client);
229
230         feedback_wait(fb);
231
232         printf("%s feedback:", __func__);
233         feedback_print(fb);
234         printf("\n");
235
236         feedback_destroy(fb);
237 }