blob: f577a18943c1d46368cd233a6dd18ddc0a20fb14 [file] [log] [blame]
Alexandros Frantzis27d7c392018-10-19 12:14:11 +03001/*
2 * Copyright © 2018 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
Alexandros Frantzisacff29b2018-10-19 12:14:11 +030028#include <assert.h>
Alexandros Frantzis27d7c392018-10-19 12:14:11 +030029#include <inttypes.h>
30
31#include "compositor.h"
32#include "linux-explicit-synchronization.h"
33#include "linux-explicit-synchronization-unstable-v1-server-protocol.h"
Alexandros Frantzisacff29b2018-10-19 12:14:11 +030034#include "linux-sync-file.h"
35#include "shared/fd-util.h"
Alexandros Frantzis27d7c392018-10-19 12:14:11 +030036
37static void
38destroy_linux_surface_synchronization(struct wl_resource *resource)
39{
40 struct weston_surface *surface =
41 wl_resource_get_user_data(resource);
42
Alexandros Frantzisacff29b2018-10-19 12:14:11 +030043 if (surface) {
44 fd_clear(&surface->pending.acquire_fence_fd);
Alexandros Frantzis27d7c392018-10-19 12:14:11 +030045 surface->synchronization_resource = NULL;
Alexandros Frantzisacff29b2018-10-19 12:14:11 +030046 }
Alexandros Frantzis27d7c392018-10-19 12:14:11 +030047}
48
49static void
50linux_surface_synchronization_destroy(struct wl_client *client,
51 struct wl_resource *resource)
52{
53 wl_resource_destroy(resource);
54}
55
56static void
57linux_surface_synchronization_set_acquire_fence(struct wl_client *client,
58 struct wl_resource *resource,
59 int32_t fd)
60{
Alexandros Frantzisacff29b2018-10-19 12:14:11 +030061 struct weston_surface *surface = wl_resource_get_user_data(resource);
62
63 if (!surface) {
64 wl_resource_post_error(
65 resource,
66 ZWP_LINUX_SURFACE_SYNCHRONIZATION_V1_ERROR_NO_SURFACE,
67 "surface no longer exists");
68 goto err;
69 }
70
71 if (!linux_sync_file_is_valid(fd)) {
72 wl_resource_post_error(
73 resource,
74 ZWP_LINUX_SURFACE_SYNCHRONIZATION_V1_ERROR_INVALID_FENCE,
75 "invalid fence fd");
76 goto err;
77 }
78
79 if (surface->pending.acquire_fence_fd != -1) {
80 wl_resource_post_error(
81 resource,
82 ZWP_LINUX_SURFACE_SYNCHRONIZATION_V1_ERROR_DUPLICATE_FENCE,
83 "already have a fence fd");
84 goto err;
85 }
86
87 fd_update(&surface->pending.acquire_fence_fd, fd);
88
89 return;
90
91err:
92 close(fd);
Alexandros Frantzis27d7c392018-10-19 12:14:11 +030093}
94
95static void
96linux_surface_synchronization_get_release(struct wl_client *client,
97 struct wl_resource *resource,
98 uint32_t id)
99{
100 wl_client_post_no_memory(client);
101}
102
103const struct zwp_linux_surface_synchronization_v1_interface
104linux_surface_synchronization_implementation = {
105 linux_surface_synchronization_destroy,
106 linux_surface_synchronization_set_acquire_fence,
107 linux_surface_synchronization_get_release,
108};
109
110static void
111linux_explicit_synchronization_destroy(struct wl_client *client,
112 struct wl_resource *resource)
113{
114 wl_resource_destroy(resource);
115}
116
117static void
118linux_explicit_synchronization_get_synchronization(struct wl_client *client,
119 struct wl_resource *resource,
120 uint32_t id,
121 struct wl_resource *surface_resource)
122{
123 struct weston_surface *surface =
124 wl_resource_get_user_data(surface_resource);
125
126 if (surface->synchronization_resource) {
127 wl_resource_post_error(
128 resource,
129 ZWP_LINUX_EXPLICIT_SYNCHRONIZATION_V1_ERROR_SYNCHRONIZATION_EXISTS,
130 "wl_surface@%"PRIu32" already has a synchronization object",
131 wl_resource_get_id(surface_resource));
132 return;
133 }
134
135 surface->synchronization_resource =
136 wl_resource_create(client,
137 &zwp_linux_surface_synchronization_v1_interface,
138 wl_resource_get_version(resource), id);
139 if (!surface->synchronization_resource) {
140 wl_client_post_no_memory(client);
141 return;
142 }
143
144 wl_resource_set_implementation(surface->synchronization_resource,
145 &linux_surface_synchronization_implementation,
146 surface,
147 destroy_linux_surface_synchronization);
148}
149
150static const struct zwp_linux_explicit_synchronization_v1_interface
151linux_explicit_synchronization_implementation = {
152 linux_explicit_synchronization_destroy,
153 linux_explicit_synchronization_get_synchronization
154};
155
156static void
157bind_linux_explicit_synchronization(struct wl_client *client,
158 void *data, uint32_t version,
159 uint32_t id)
160{
161 struct weston_compositor *compositor = data;
162 struct wl_resource *resource;
163
164 resource = wl_resource_create(client,
165 &zwp_linux_explicit_synchronization_v1_interface,
166 version, id);
167 if (resource == NULL) {
168 wl_client_post_no_memory(client);
169 return;
170 }
171
172 wl_resource_set_implementation(resource,
173 &linux_explicit_synchronization_implementation,
174 compositor, NULL);
175}
176
177/** Advertise linux_explicit_synchronization support
178 *
179 * Calling this initializes the zwp_linux_explicit_synchronization_v1
180 * protocol support, so that the interface will be advertised to clients.
181 * Essentially it creates a global. Do not call this function multiple times
182 * in the compositor's lifetime. There is no way to deinit explicitly, globals
183 * will be reaped when the wl_display gets destroyed.
184 *
185 * \param compositor The compositor to init for.
186 * \return Zero on success, -1 on failure.
187 */
188WL_EXPORT int
189linux_explicit_synchronization_setup(struct weston_compositor *compositor)
190{
191 /* TODO: Update to minor version 2 when the next version of
192 * wayland-protocols that contains it is released. */
193 if (!wl_global_create(compositor->wl_display,
194 &zwp_linux_explicit_synchronization_v1_interface,
195 1, compositor,
196 bind_linux_explicit_synchronization))
197 return -1;
198
199 return 0;
200}
Alexandros Frantzisacff29b2018-10-19 12:14:11 +0300201
202/** Resolve an internal compositor error by disconnecting the client.
203 *
204 * This function is used in cases when explicit synchronization
205 * turns out to be unusable and there is no fallback path.
206 *
207 * It is possible the fault is caused by a compositor bug, the underlying
208 * graphics stack bug or normal behaviour, or perhaps a client mistake.
209 * In any case, the options are to either composite garbage or nothing,
210 * or disconnect the client. This is a helper function for the latter.
211 *
212 * The error is sent as an INVALID_OBJECT error on the client's wl_display.
213 *
214 * \param sync The explicit synchronization related resource that is unusable.
215 * \param msg A custom error message attached to the protocol error.
216 */
217WL_EXPORT void
218linux_explicit_synchronization_send_server_error(struct wl_resource *resource,
219 const char *msg)
220{
221 uint32_t id = wl_resource_get_id(resource);
222 const char *class = wl_resource_get_class(resource);
223 struct wl_client *client = wl_resource_get_client(resource);
224 struct wl_resource *display_resource = wl_client_get_object(client, 1);
225
226 assert(display_resource);
227 wl_resource_post_error(display_resource,
228 WL_DISPLAY_ERROR_INVALID_OBJECT,
229 "linux_explicit_synchronization server error "
230 "with %s@%"PRIu32": %s",
231 class, id, msg);
232}