1b8e80941Smrg/*
2b8e80941Smrg * Copyright © 2015 Intel Corporation
3b8e80941Smrg *
4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5b8e80941Smrg * copy of this software and associated documentation files (the "Software"),
6b8e80941Smrg * to deal in the Software without restriction, including without limitation
7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the
9b8e80941Smrg * Software is furnished to do so, subject to the following conditions:
10b8e80941Smrg *
11b8e80941Smrg * The above copyright notice and this permission notice (including the next
12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the
13b8e80941Smrg * Software.
14b8e80941Smrg *
15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21b8e80941Smrg * IN THE SOFTWARE.
22b8e80941Smrg */
23b8e80941Smrg
24b8e80941Smrg#include <wayland-client.h>
25b8e80941Smrg
26b8e80941Smrg#include <assert.h>
27b8e80941Smrg#include <stdlib.h>
28b8e80941Smrg#include <stdio.h>
29b8e80941Smrg#include <unistd.h>
30b8e80941Smrg#include <errno.h>
31b8e80941Smrg#include <string.h>
32b8e80941Smrg#include <pthread.h>
33b8e80941Smrg
34b8e80941Smrg#include "drm-uapi/drm_fourcc.h"
35b8e80941Smrg
36b8e80941Smrg#include "vk_util.h"
37b8e80941Smrg#include "wsi_common_private.h"
38b8e80941Smrg#include "wsi_common_wayland.h"
39b8e80941Smrg#include "wayland-drm-client-protocol.h"
40b8e80941Smrg#include "linux-dmabuf-unstable-v1-client-protocol.h"
41b8e80941Smrg
42b8e80941Smrg#include <util/hash_table.h>
43b8e80941Smrg#include <util/u_vector.h>
44b8e80941Smrg
45b8e80941Smrg#define typed_memcpy(dest, src, count) ({ \
46b8e80941Smrg   STATIC_ASSERT(sizeof(*src) == sizeof(*dest)); \
47b8e80941Smrg   memcpy((dest), (src), (count) * sizeof(*(src))); \
48b8e80941Smrg})
49b8e80941Smrg
50b8e80941Smrgstruct wsi_wayland;
51b8e80941Smrg
52b8e80941Smrgstruct wsi_wl_display_drm {
53b8e80941Smrg   struct wl_drm *                              wl_drm;
54b8e80941Smrg   struct u_vector                              formats;
55b8e80941Smrg   uint32_t                                     capabilities;
56b8e80941Smrg};
57b8e80941Smrg
58b8e80941Smrgstruct wsi_wl_display_dmabuf {
59b8e80941Smrg   struct zwp_linux_dmabuf_v1 *                 wl_dmabuf;
60b8e80941Smrg   struct u_vector                              formats;
61b8e80941Smrg   struct {
62b8e80941Smrg      struct u_vector                           argb8888;
63b8e80941Smrg      struct u_vector                           xrgb8888;
64b8e80941Smrg   } modifiers;
65b8e80941Smrg};
66b8e80941Smrg
67b8e80941Smrgstruct wsi_wl_display {
68b8e80941Smrg   /* The real wl_display */
69b8e80941Smrg   struct wl_display *                          wl_display;
70b8e80941Smrg   /* Actually a proxy wrapper around the event queue */
71b8e80941Smrg   struct wl_display *                          wl_display_wrapper;
72b8e80941Smrg   struct wl_event_queue *                      queue;
73b8e80941Smrg
74b8e80941Smrg   struct wsi_wl_display_drm                    drm;
75b8e80941Smrg   struct wsi_wl_display_dmabuf                 dmabuf;
76b8e80941Smrg
77b8e80941Smrg   struct wsi_wayland *wsi_wl;
78b8e80941Smrg
79b8e80941Smrg   /* Points to formats in wsi_wl_display_drm or wsi_wl_display_dmabuf */
80b8e80941Smrg   struct u_vector *                            formats;
81b8e80941Smrg
82b8e80941Smrg   /* Only used for displays created by wsi_wl_display_create */
83b8e80941Smrg   uint32_t                                     refcount;
84b8e80941Smrg};
85b8e80941Smrg
86b8e80941Smrgstruct wsi_wayland {
87b8e80941Smrg   struct wsi_interface                     base;
88b8e80941Smrg
89b8e80941Smrg   struct wsi_device *wsi;
90b8e80941Smrg
91b8e80941Smrg   const VkAllocationCallbacks *alloc;
92b8e80941Smrg   VkPhysicalDevice physical_device;
93b8e80941Smrg};
94b8e80941Smrg
95b8e80941Smrgstatic void
96b8e80941Smrgwsi_wl_display_add_vk_format(struct wsi_wl_display *display,
97b8e80941Smrg                             struct u_vector *formats, VkFormat format)
98b8e80941Smrg{
99b8e80941Smrg   /* Don't add a format that's already in the list */
100b8e80941Smrg   VkFormat *f;
101b8e80941Smrg   u_vector_foreach(f, formats)
102b8e80941Smrg      if (*f == format)
103b8e80941Smrg         return;
104b8e80941Smrg
105b8e80941Smrg   /* Don't add formats that aren't renderable. */
106b8e80941Smrg   VkFormatProperties props;
107b8e80941Smrg
108b8e80941Smrg   display->wsi_wl->wsi->GetPhysicalDeviceFormatProperties(display->wsi_wl->physical_device,
109b8e80941Smrg                                                           format, &props);
110b8e80941Smrg   if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT))
111b8e80941Smrg      return;
112b8e80941Smrg
113b8e80941Smrg   f = u_vector_add(formats);
114b8e80941Smrg   if (f)
115b8e80941Smrg      *f = format;
116b8e80941Smrg}
117b8e80941Smrg
118b8e80941Smrgstatic void
119b8e80941Smrgwsi_wl_display_add_wl_format(struct wsi_wl_display *display,
120b8e80941Smrg                             struct u_vector *formats, uint32_t wl_format)
121b8e80941Smrg{
122b8e80941Smrg   switch (wl_format) {
123b8e80941Smrg#if 0
124b8e80941Smrg   case WL_DRM_FORMAT_ABGR4444:
125b8e80941Smrg   case WL_DRM_FORMAT_XBGR4444:
126b8e80941Smrg      wsi_wl_display_add_vk_format(display, formats,
127b8e80941Smrg                                   VK_FORMAT_R4G4B4A4_UNORM);
128b8e80941Smrg      break;
129b8e80941Smrg   case WL_DRM_FORMAT_BGR565:
130b8e80941Smrg      wsi_wl_display_add_vk_format(display, formats,
131b8e80941Smrg                                   VK_FORMAT_R5G6B5_UNORM);
132b8e80941Smrg      break;
133b8e80941Smrg   case WL_DRM_FORMAT_ABGR1555:
134b8e80941Smrg   case WL_DRM_FORMAT_XBGR1555:
135b8e80941Smrg      wsi_wl_display_add_vk_format(display, formats,
136b8e80941Smrg                                   VK_FORMAT_R5G5B5A1_UNORM);
137b8e80941Smrg      break;
138b8e80941Smrg   case WL_DRM_FORMAT_XBGR8888:
139b8e80941Smrg      wsi_wl_display_add_vk_format(display, formats,
140b8e80941Smrg                                   VK_FORMAT_R8G8B8_UNORM);
141b8e80941Smrg      /* fallthrough */
142b8e80941Smrg   case WL_DRM_FORMAT_ABGR8888:
143b8e80941Smrg      wsi_wl_display_add_vk_format(display, formats,
144b8e80941Smrg                                   VK_FORMAT_R8G8B8A8_UNORM);
145b8e80941Smrg      break;
146b8e80941Smrg   case WL_DRM_FORMAT_ABGR2101010:
147b8e80941Smrg   case WL_DRM_FORMAT_XBGR2101010:
148b8e80941Smrg      wsi_wl_display_add_vk_format(display, formats,
149b8e80941Smrg                                   VK_FORMAT_R10G10B10A2_UNORM);
150b8e80941Smrg      break;
151b8e80941Smrg   case WL_DRM_FORMAT_ARGB4444:
152b8e80941Smrg   case WL_DRM_FORMAT_XRGB4444:
153b8e80941Smrg      wsi_wl_display_add_vk_format(display, formats,
154b8e80941Smrg                                   VK_FORMAT_B4G4R4A4_UNORM);
155b8e80941Smrg      break;
156b8e80941Smrg   case WL_DRM_FORMAT_RGB565:
157b8e80941Smrg      wsi_wl_display_add_vk_format(display, formats,
158b8e80941Smrg                                   VK_FORMAT_B5G6R5_UNORM);
159b8e80941Smrg      break;
160b8e80941Smrg   case WL_DRM_FORMAT_ARGB1555:
161b8e80941Smrg   case WL_DRM_FORMAT_XRGB1555:
162b8e80941Smrg      wsi_wl_display_add_vk_format(display, formats,
163b8e80941Smrg                                   VK_FORMAT_B5G5R5A1_UNORM);
164b8e80941Smrg      break;
165b8e80941Smrg#endif
166b8e80941Smrg   case WL_DRM_FORMAT_XRGB8888:
167b8e80941Smrg      wsi_wl_display_add_vk_format(display, formats,
168b8e80941Smrg                                   VK_FORMAT_B8G8R8_SRGB);
169b8e80941Smrg      wsi_wl_display_add_vk_format(display, formats,
170b8e80941Smrg                                   VK_FORMAT_B8G8R8_UNORM);
171b8e80941Smrg      /* fallthrough */
172b8e80941Smrg   case WL_DRM_FORMAT_ARGB8888:
173b8e80941Smrg      wsi_wl_display_add_vk_format(display, formats,
174b8e80941Smrg                                   VK_FORMAT_B8G8R8A8_SRGB);
175b8e80941Smrg      wsi_wl_display_add_vk_format(display, formats,
176b8e80941Smrg                                   VK_FORMAT_B8G8R8A8_UNORM);
177b8e80941Smrg      break;
178b8e80941Smrg#if 0
179b8e80941Smrg   case WL_DRM_FORMAT_ARGB2101010:
180b8e80941Smrg   case WL_DRM_FORMAT_XRGB2101010:
181b8e80941Smrg      wsi_wl_display_add_vk_format(display, formats,
182b8e80941Smrg                                   VK_FORMAT_B10G10R10A2_UNORM);
183b8e80941Smrg      break;
184b8e80941Smrg#endif
185b8e80941Smrg   }
186b8e80941Smrg}
187b8e80941Smrg
188b8e80941Smrgstatic void
189b8e80941Smrgdrm_handle_device(void *data, struct wl_drm *drm, const char *name)
190b8e80941Smrg{
191b8e80941Smrg}
192b8e80941Smrg
193b8e80941Smrgstatic uint32_t
194b8e80941Smrgwl_drm_format_for_vk_format(VkFormat vk_format, bool alpha)
195b8e80941Smrg{
196b8e80941Smrg   switch (vk_format) {
197b8e80941Smrg   /* TODO: Figure out what all the formats mean and make this table
198b8e80941Smrg    * correct.
199b8e80941Smrg    */
200b8e80941Smrg#if 0
201b8e80941Smrg   case VK_FORMAT_R4G4B4A4_UNORM:
202b8e80941Smrg      return alpha ? WL_DRM_FORMAT_ABGR4444 : WL_DRM_FORMAT_XBGR4444;
203b8e80941Smrg   case VK_FORMAT_R5G6B5_UNORM:
204b8e80941Smrg      return WL_DRM_FORMAT_BGR565;
205b8e80941Smrg   case VK_FORMAT_R5G5B5A1_UNORM:
206b8e80941Smrg      return alpha ? WL_DRM_FORMAT_ABGR1555 : WL_DRM_FORMAT_XBGR1555;
207b8e80941Smrg   case VK_FORMAT_R8G8B8_UNORM:
208b8e80941Smrg      return WL_DRM_FORMAT_XBGR8888;
209b8e80941Smrg   case VK_FORMAT_R8G8B8A8_UNORM:
210b8e80941Smrg      return alpha ? WL_DRM_FORMAT_ABGR8888 : WL_DRM_FORMAT_XBGR8888;
211b8e80941Smrg   case VK_FORMAT_R10G10B10A2_UNORM:
212b8e80941Smrg      return alpha ? WL_DRM_FORMAT_ABGR2101010 : WL_DRM_FORMAT_XBGR2101010;
213b8e80941Smrg   case VK_FORMAT_B4G4R4A4_UNORM:
214b8e80941Smrg      return alpha ? WL_DRM_FORMAT_ARGB4444 : WL_DRM_FORMAT_XRGB4444;
215b8e80941Smrg   case VK_FORMAT_B5G6R5_UNORM:
216b8e80941Smrg      return WL_DRM_FORMAT_RGB565;
217b8e80941Smrg   case VK_FORMAT_B5G5R5A1_UNORM:
218b8e80941Smrg      return alpha ? WL_DRM_FORMAT_XRGB1555 : WL_DRM_FORMAT_XRGB1555;
219b8e80941Smrg#endif
220b8e80941Smrg   case VK_FORMAT_B8G8R8_UNORM:
221b8e80941Smrg   case VK_FORMAT_B8G8R8_SRGB:
222b8e80941Smrg      return WL_DRM_FORMAT_BGRX8888;
223b8e80941Smrg   case VK_FORMAT_B8G8R8A8_UNORM:
224b8e80941Smrg   case VK_FORMAT_B8G8R8A8_SRGB:
225b8e80941Smrg      return alpha ? WL_DRM_FORMAT_ARGB8888 : WL_DRM_FORMAT_XRGB8888;
226b8e80941Smrg#if 0
227b8e80941Smrg   case VK_FORMAT_B10G10R10A2_UNORM:
228b8e80941Smrg      return alpha ? WL_DRM_FORMAT_ARGB2101010 : WL_DRM_FORMAT_XRGB2101010;
229b8e80941Smrg#endif
230b8e80941Smrg
231b8e80941Smrg   default:
232b8e80941Smrg      assert(!"Unsupported Vulkan format");
233b8e80941Smrg      return 0;
234b8e80941Smrg   }
235b8e80941Smrg}
236b8e80941Smrg
237b8e80941Smrgstatic void
238b8e80941Smrgdrm_handle_format(void *data, struct wl_drm *drm, uint32_t wl_format)
239b8e80941Smrg{
240b8e80941Smrg   struct wsi_wl_display *display = data;
241b8e80941Smrg   if (display->drm.formats.element_size == 0)
242b8e80941Smrg      return;
243b8e80941Smrg
244b8e80941Smrg   wsi_wl_display_add_wl_format(display, &display->drm.formats, wl_format);
245b8e80941Smrg}
246b8e80941Smrg
247b8e80941Smrgstatic void
248b8e80941Smrgdrm_handle_authenticated(void *data, struct wl_drm *drm)
249b8e80941Smrg{
250b8e80941Smrg}
251b8e80941Smrg
252b8e80941Smrgstatic void
253b8e80941Smrgdrm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t capabilities)
254b8e80941Smrg{
255b8e80941Smrg   struct wsi_wl_display *display = data;
256b8e80941Smrg
257b8e80941Smrg   display->drm.capabilities = capabilities;
258b8e80941Smrg}
259b8e80941Smrg
260b8e80941Smrgstatic const struct wl_drm_listener drm_listener = {
261b8e80941Smrg   drm_handle_device,
262b8e80941Smrg   drm_handle_format,
263b8e80941Smrg   drm_handle_authenticated,
264b8e80941Smrg   drm_handle_capabilities,
265b8e80941Smrg};
266b8e80941Smrg
267b8e80941Smrgstatic void
268b8e80941Smrgdmabuf_handle_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
269b8e80941Smrg                     uint32_t format)
270b8e80941Smrg{
271b8e80941Smrg   /* Formats are implicitly advertised by the modifier event, so we ignore
272b8e80941Smrg    * them here. */
273b8e80941Smrg}
274b8e80941Smrg
275b8e80941Smrgstatic void
276b8e80941Smrgdmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
277b8e80941Smrg                       uint32_t format, uint32_t modifier_hi,
278b8e80941Smrg                       uint32_t modifier_lo)
279b8e80941Smrg{
280b8e80941Smrg   struct wsi_wl_display *display = data;
281b8e80941Smrg   uint64_t *mod = NULL;
282b8e80941Smrg
283b8e80941Smrg   /* If we're not fetching formats, don't fetch modifiers either. */
284b8e80941Smrg   if (display->dmabuf.formats.element_size == 0)
285b8e80941Smrg      return;
286b8e80941Smrg
287b8e80941Smrg   if (modifier_hi == (DRM_FORMAT_MOD_INVALID >> 32) &&
288b8e80941Smrg       modifier_lo == (DRM_FORMAT_MOD_INVALID & 0xffffffff))
289b8e80941Smrg      return;
290b8e80941Smrg
291b8e80941Smrg   switch (format) {
292b8e80941Smrg   case WL_DRM_FORMAT_ARGB8888:
293b8e80941Smrg      wsi_wl_display_add_wl_format(display, &display->dmabuf.formats, format);
294b8e80941Smrg      mod = u_vector_add(&display->dmabuf.modifiers.argb8888);
295b8e80941Smrg      break;
296b8e80941Smrg   case WL_DRM_FORMAT_XRGB8888:
297b8e80941Smrg      wsi_wl_display_add_wl_format(display, &display->dmabuf.formats, format);
298b8e80941Smrg      mod = u_vector_add(&display->dmabuf.modifiers.xrgb8888);
299b8e80941Smrg      break;
300b8e80941Smrg   default:
301b8e80941Smrg      break;
302b8e80941Smrg   }
303b8e80941Smrg
304b8e80941Smrg   if (!mod)
305b8e80941Smrg      return;
306b8e80941Smrg
307b8e80941Smrg   *mod = (uint64_t) modifier_hi << 32;
308b8e80941Smrg   *mod |= (uint64_t) (modifier_lo & 0xffffffff);
309b8e80941Smrg}
310b8e80941Smrg
311b8e80941Smrgstatic const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
312b8e80941Smrg   dmabuf_handle_format,
313b8e80941Smrg   dmabuf_handle_modifier,
314b8e80941Smrg};
315b8e80941Smrg
316b8e80941Smrgstatic void
317b8e80941Smrgregistry_handle_global(void *data, struct wl_registry *registry,
318b8e80941Smrg                       uint32_t name, const char *interface, uint32_t version)
319b8e80941Smrg{
320b8e80941Smrg   struct wsi_wl_display *display = data;
321b8e80941Smrg
322b8e80941Smrg   if (strcmp(interface, "wl_drm") == 0) {
323b8e80941Smrg      assert(display->drm.wl_drm == NULL);
324b8e80941Smrg
325b8e80941Smrg      assert(version >= 2);
326b8e80941Smrg      display->drm.wl_drm =
327b8e80941Smrg         wl_registry_bind(registry, name, &wl_drm_interface, 2);
328b8e80941Smrg      wl_drm_add_listener(display->drm.wl_drm, &drm_listener, display);
329b8e80941Smrg   } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0 && version >= 3 &&
330b8e80941Smrg              display->wsi_wl->wsi->supports_modifiers) {
331b8e80941Smrg      display->dmabuf.wl_dmabuf =
332b8e80941Smrg         wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface, 3);
333b8e80941Smrg      zwp_linux_dmabuf_v1_add_listener(display->dmabuf.wl_dmabuf,
334b8e80941Smrg                                       &dmabuf_listener, display);
335b8e80941Smrg   }
336b8e80941Smrg}
337b8e80941Smrg
338b8e80941Smrgstatic void
339b8e80941Smrgregistry_handle_global_remove(void *data, struct wl_registry *registry,
340b8e80941Smrg                              uint32_t name)
341b8e80941Smrg{ /* No-op */ }
342b8e80941Smrg
343b8e80941Smrgstatic const struct wl_registry_listener registry_listener = {
344b8e80941Smrg   registry_handle_global,
345b8e80941Smrg   registry_handle_global_remove
346b8e80941Smrg};
347b8e80941Smrg
348b8e80941Smrgstatic void
349b8e80941Smrgwsi_wl_display_finish(struct wsi_wl_display *display)
350b8e80941Smrg{
351b8e80941Smrg   assert(display->refcount == 0);
352b8e80941Smrg
353b8e80941Smrg   u_vector_finish(&display->drm.formats);
354b8e80941Smrg   u_vector_finish(&display->dmabuf.formats);
355b8e80941Smrg   u_vector_finish(&display->dmabuf.modifiers.argb8888);
356b8e80941Smrg   u_vector_finish(&display->dmabuf.modifiers.xrgb8888);
357b8e80941Smrg   if (display->drm.wl_drm)
358b8e80941Smrg      wl_drm_destroy(display->drm.wl_drm);
359b8e80941Smrg   if (display->dmabuf.wl_dmabuf)
360b8e80941Smrg      zwp_linux_dmabuf_v1_destroy(display->dmabuf.wl_dmabuf);
361b8e80941Smrg   if (display->wl_display_wrapper)
362b8e80941Smrg      wl_proxy_wrapper_destroy(display->wl_display_wrapper);
363b8e80941Smrg   if (display->queue)
364b8e80941Smrg      wl_event_queue_destroy(display->queue);
365b8e80941Smrg}
366b8e80941Smrg
367b8e80941Smrgstatic VkResult
368b8e80941Smrgwsi_wl_display_init(struct wsi_wayland *wsi_wl,
369b8e80941Smrg                    struct wsi_wl_display *display,
370b8e80941Smrg                    struct wl_display *wl_display,
371b8e80941Smrg                    bool get_format_list)
372b8e80941Smrg{
373b8e80941Smrg   VkResult result = VK_SUCCESS;
374b8e80941Smrg   memset(display, 0, sizeof(*display));
375b8e80941Smrg
376b8e80941Smrg   display->wsi_wl = wsi_wl;
377b8e80941Smrg   display->wl_display = wl_display;
378b8e80941Smrg
379b8e80941Smrg   if (get_format_list) {
380b8e80941Smrg      if (!u_vector_init(&display->drm.formats, sizeof(VkFormat), 8) ||
381b8e80941Smrg          !u_vector_init(&display->dmabuf.formats, sizeof(VkFormat), 8) ||
382b8e80941Smrg          !u_vector_init(&display->dmabuf.modifiers.argb8888,
383b8e80941Smrg                         sizeof(uint64_t), 32) ||
384b8e80941Smrg          !u_vector_init(&display->dmabuf.modifiers.xrgb8888,
385b8e80941Smrg                         sizeof(uint64_t), 32)) {
386b8e80941Smrg         result = VK_ERROR_OUT_OF_HOST_MEMORY;
387b8e80941Smrg         goto fail;
388b8e80941Smrg      }
389b8e80941Smrg   }
390b8e80941Smrg
391b8e80941Smrg   display->queue = wl_display_create_queue(wl_display);
392b8e80941Smrg   if (!display->queue) {
393b8e80941Smrg      result = VK_ERROR_OUT_OF_HOST_MEMORY;
394b8e80941Smrg      goto fail;
395b8e80941Smrg   }
396b8e80941Smrg
397b8e80941Smrg   display->wl_display_wrapper = wl_proxy_create_wrapper(wl_display);
398b8e80941Smrg   if (!display->wl_display_wrapper) {
399b8e80941Smrg      result = VK_ERROR_OUT_OF_HOST_MEMORY;
400b8e80941Smrg      goto fail;
401b8e80941Smrg   }
402b8e80941Smrg
403b8e80941Smrg   wl_proxy_set_queue((struct wl_proxy *) display->wl_display_wrapper,
404b8e80941Smrg                      display->queue);
405b8e80941Smrg
406b8e80941Smrg   struct wl_registry *registry =
407b8e80941Smrg      wl_display_get_registry(display->wl_display_wrapper);
408b8e80941Smrg   if (!registry) {
409b8e80941Smrg      result = VK_ERROR_OUT_OF_HOST_MEMORY;
410b8e80941Smrg      goto fail;
411b8e80941Smrg   }
412b8e80941Smrg
413b8e80941Smrg   wl_registry_add_listener(registry, &registry_listener, display);
414b8e80941Smrg
415b8e80941Smrg   /* Round-trip to get wl_drms and zwp_linux_dmabuf_v1 globals */
416b8e80941Smrg   wl_display_roundtrip_queue(display->wl_display, display->queue);
417b8e80941Smrg
418b8e80941Smrg   /* Round-trip again to get formats, modifiers and capabilities */
419b8e80941Smrg   if (display->drm.wl_drm || display->dmabuf.wl_dmabuf)
420b8e80941Smrg      wl_display_roundtrip_queue(display->wl_display, display->queue);
421b8e80941Smrg
422b8e80941Smrg   /* We need prime support for wl_drm */
423b8e80941Smrg   if (display->drm.wl_drm &&
424b8e80941Smrg       (display->drm.capabilities & WL_DRM_CAPABILITY_PRIME)) {
425b8e80941Smrg      display->formats = &display->drm.formats;
426b8e80941Smrg   } else if (display->dmabuf.wl_dmabuf) {
427b8e80941Smrg      display->formats = &display->dmabuf.formats;
428b8e80941Smrg   }
429b8e80941Smrg
430b8e80941Smrg   if (!display->formats) {
431b8e80941Smrg      result = VK_ERROR_SURFACE_LOST_KHR;
432b8e80941Smrg      goto fail_registry;
433b8e80941Smrg   }
434b8e80941Smrg
435b8e80941Smrg   /* We don't need this anymore */
436b8e80941Smrg   wl_registry_destroy(registry);
437b8e80941Smrg
438b8e80941Smrg   display->refcount = 0;
439b8e80941Smrg
440b8e80941Smrg   return VK_SUCCESS;
441b8e80941Smrg
442b8e80941Smrgfail_registry:
443b8e80941Smrg   if (registry)
444b8e80941Smrg      wl_registry_destroy(registry);
445b8e80941Smrg
446b8e80941Smrgfail:
447b8e80941Smrg   wsi_wl_display_finish(display);
448b8e80941Smrg   return result;
449b8e80941Smrg}
450b8e80941Smrg
451b8e80941Smrgstatic VkResult
452b8e80941Smrgwsi_wl_display_create(struct wsi_wayland *wsi, struct wl_display *wl_display,
453b8e80941Smrg                      struct wsi_wl_display **display_out)
454b8e80941Smrg{
455b8e80941Smrg   struct wsi_wl_display *display =
456b8e80941Smrg      vk_alloc(wsi->alloc, sizeof(*display), 8,
457b8e80941Smrg               VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
458b8e80941Smrg   if (!display)
459b8e80941Smrg      return VK_ERROR_OUT_OF_HOST_MEMORY;
460b8e80941Smrg
461b8e80941Smrg   VkResult result = wsi_wl_display_init(wsi, display, wl_display, true);
462b8e80941Smrg   if (result != VK_SUCCESS) {
463b8e80941Smrg      vk_free(wsi->alloc, display);
464b8e80941Smrg      return result;
465b8e80941Smrg   }
466b8e80941Smrg
467b8e80941Smrg   display->refcount++;
468b8e80941Smrg   *display_out = display;
469b8e80941Smrg
470b8e80941Smrg   return result;
471b8e80941Smrg}
472b8e80941Smrg
473b8e80941Smrgstatic struct wsi_wl_display *
474b8e80941Smrgwsi_wl_display_ref(struct wsi_wl_display *display)
475b8e80941Smrg{
476b8e80941Smrg   display->refcount++;
477b8e80941Smrg   return display;
478b8e80941Smrg}
479b8e80941Smrg
480b8e80941Smrgstatic void
481b8e80941Smrgwsi_wl_display_unref(struct wsi_wl_display *display)
482b8e80941Smrg{
483b8e80941Smrg   if (display->refcount-- > 1)
484b8e80941Smrg      return;
485b8e80941Smrg
486b8e80941Smrg   struct wsi_wayland *wsi = display->wsi_wl;
487b8e80941Smrg   wsi_wl_display_finish(display);
488b8e80941Smrg   vk_free(wsi->alloc, display);
489b8e80941Smrg}
490b8e80941Smrg
491b8e80941SmrgVkBool32
492b8e80941Smrgwsi_wl_get_presentation_support(struct wsi_device *wsi_device,
493b8e80941Smrg				struct wl_display *wl_display)
494b8e80941Smrg{
495b8e80941Smrg   struct wsi_wayland *wsi =
496b8e80941Smrg      (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND];
497b8e80941Smrg
498b8e80941Smrg   struct wsi_wl_display display;
499b8e80941Smrg   VkResult ret = wsi_wl_display_init(wsi, &display, wl_display, false);
500b8e80941Smrg   if (ret == VK_SUCCESS)
501b8e80941Smrg      wsi_wl_display_finish(&display);
502b8e80941Smrg
503b8e80941Smrg   return ret == VK_SUCCESS;
504b8e80941Smrg}
505b8e80941Smrg
506b8e80941Smrgstatic VkResult
507b8e80941Smrgwsi_wl_surface_get_support(VkIcdSurfaceBase *surface,
508b8e80941Smrg                           struct wsi_device *wsi_device,
509b8e80941Smrg                           uint32_t queueFamilyIndex,
510b8e80941Smrg                           VkBool32* pSupported)
511b8e80941Smrg{
512b8e80941Smrg   *pSupported = true;
513b8e80941Smrg
514b8e80941Smrg   return VK_SUCCESS;
515b8e80941Smrg}
516b8e80941Smrg
517b8e80941Smrgstatic const VkPresentModeKHR present_modes[] = {
518b8e80941Smrg   VK_PRESENT_MODE_MAILBOX_KHR,
519b8e80941Smrg   VK_PRESENT_MODE_FIFO_KHR,
520b8e80941Smrg};
521b8e80941Smrg
522b8e80941Smrgstatic VkResult
523b8e80941Smrgwsi_wl_surface_get_capabilities(VkIcdSurfaceBase *surface,
524b8e80941Smrg                                struct wsi_device *wsi_device,
525b8e80941Smrg                                VkSurfaceCapabilitiesKHR* caps)
526b8e80941Smrg{
527b8e80941Smrg   /* For true mailbox mode, we need at least 4 images:
528b8e80941Smrg    *  1) One to scan out from
529b8e80941Smrg    *  2) One to have queued for scan-out
530b8e80941Smrg    *  3) One to be currently held by the Wayland compositor
531b8e80941Smrg    *  4) One to render to
532b8e80941Smrg    */
533b8e80941Smrg   caps->minImageCount = 4;
534b8e80941Smrg   /* There is no real maximum */
535b8e80941Smrg   caps->maxImageCount = 0;
536b8e80941Smrg
537b8e80941Smrg   caps->currentExtent = (VkExtent2D) { -1, -1 };
538b8e80941Smrg   caps->minImageExtent = (VkExtent2D) { 1, 1 };
539b8e80941Smrg   caps->maxImageExtent = (VkExtent2D) {
540b8e80941Smrg      wsi_device->maxImageDimension2D,
541b8e80941Smrg      wsi_device->maxImageDimension2D,
542b8e80941Smrg   };
543b8e80941Smrg
544b8e80941Smrg   caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
545b8e80941Smrg   caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
546b8e80941Smrg   caps->maxImageArrayLayers = 1;
547b8e80941Smrg
548b8e80941Smrg   caps->supportedCompositeAlpha =
549b8e80941Smrg      VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |
550b8e80941Smrg      VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
551b8e80941Smrg
552b8e80941Smrg   caps->supportedUsageFlags =
553b8e80941Smrg      VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
554b8e80941Smrg      VK_IMAGE_USAGE_SAMPLED_BIT |
555b8e80941Smrg      VK_IMAGE_USAGE_TRANSFER_DST_BIT |
556b8e80941Smrg      VK_IMAGE_USAGE_STORAGE_BIT |
557b8e80941Smrg      VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
558b8e80941Smrg
559b8e80941Smrg   return VK_SUCCESS;
560b8e80941Smrg}
561b8e80941Smrg
562b8e80941Smrgstatic VkResult
563b8e80941Smrgwsi_wl_surface_get_capabilities2(VkIcdSurfaceBase *surface,
564b8e80941Smrg                                 struct wsi_device *wsi_device,
565b8e80941Smrg                                 const void *info_next,
566b8e80941Smrg                                 VkSurfaceCapabilities2KHR* caps)
567b8e80941Smrg{
568b8e80941Smrg   assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR);
569b8e80941Smrg
570b8e80941Smrg   VkResult result =
571b8e80941Smrg      wsi_wl_surface_get_capabilities(surface, wsi_device,
572b8e80941Smrg                                      &caps->surfaceCapabilities);
573b8e80941Smrg
574b8e80941Smrg   vk_foreach_struct(ext, caps->pNext) {
575b8e80941Smrg      switch (ext->sType) {
576b8e80941Smrg      case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: {
577b8e80941Smrg         VkSurfaceProtectedCapabilitiesKHR *protected = (void *)ext;
578b8e80941Smrg         protected->supportsProtected = VK_FALSE;
579b8e80941Smrg         break;
580b8e80941Smrg      }
581b8e80941Smrg
582b8e80941Smrg      default:
583b8e80941Smrg         /* Ignored */
584b8e80941Smrg         break;
585b8e80941Smrg      }
586b8e80941Smrg   }
587b8e80941Smrg
588b8e80941Smrg   return result;
589b8e80941Smrg}
590b8e80941Smrg
591b8e80941Smrgstatic VkResult
592b8e80941Smrgwsi_wl_surface_get_formats(VkIcdSurfaceBase *icd_surface,
593b8e80941Smrg			   struct wsi_device *wsi_device,
594b8e80941Smrg                           uint32_t* pSurfaceFormatCount,
595b8e80941Smrg                           VkSurfaceFormatKHR* pSurfaceFormats)
596b8e80941Smrg{
597b8e80941Smrg   VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface;
598b8e80941Smrg   struct wsi_wayland *wsi =
599b8e80941Smrg      (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND];
600b8e80941Smrg
601b8e80941Smrg   struct wsi_wl_display display;
602b8e80941Smrg   if (wsi_wl_display_init(wsi, &display, surface->display, true))
603b8e80941Smrg      return VK_ERROR_SURFACE_LOST_KHR;
604b8e80941Smrg
605b8e80941Smrg   VK_OUTARRAY_MAKE(out, pSurfaceFormats, pSurfaceFormatCount);
606b8e80941Smrg
607b8e80941Smrg   VkFormat *disp_fmt;
608b8e80941Smrg   u_vector_foreach(disp_fmt, display.formats) {
609b8e80941Smrg      vk_outarray_append(&out, out_fmt) {
610b8e80941Smrg         out_fmt->format = *disp_fmt;
611b8e80941Smrg         out_fmt->colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
612b8e80941Smrg      }
613b8e80941Smrg   }
614b8e80941Smrg
615b8e80941Smrg   wsi_wl_display_finish(&display);
616b8e80941Smrg
617b8e80941Smrg   return vk_outarray_status(&out);
618b8e80941Smrg}
619b8e80941Smrg
620b8e80941Smrgstatic VkResult
621b8e80941Smrgwsi_wl_surface_get_formats2(VkIcdSurfaceBase *icd_surface,
622b8e80941Smrg			    struct wsi_device *wsi_device,
623b8e80941Smrg                            const void *info_next,
624b8e80941Smrg                            uint32_t* pSurfaceFormatCount,
625b8e80941Smrg                            VkSurfaceFormat2KHR* pSurfaceFormats)
626b8e80941Smrg{
627b8e80941Smrg   VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface;
628b8e80941Smrg   struct wsi_wayland *wsi =
629b8e80941Smrg      (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND];
630b8e80941Smrg
631b8e80941Smrg   struct wsi_wl_display display;
632b8e80941Smrg   if (wsi_wl_display_init(wsi, &display, surface->display, true))
633b8e80941Smrg      return VK_ERROR_SURFACE_LOST_KHR;
634b8e80941Smrg
635b8e80941Smrg   VK_OUTARRAY_MAKE(out, pSurfaceFormats, pSurfaceFormatCount);
636b8e80941Smrg
637b8e80941Smrg   VkFormat *disp_fmt;
638b8e80941Smrg   u_vector_foreach(disp_fmt, display.formats) {
639b8e80941Smrg      vk_outarray_append(&out, out_fmt) {
640b8e80941Smrg         out_fmt->surfaceFormat.format = *disp_fmt;
641b8e80941Smrg         out_fmt->surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
642b8e80941Smrg      }
643b8e80941Smrg   }
644b8e80941Smrg
645b8e80941Smrg   wsi_wl_display_finish(&display);
646b8e80941Smrg
647b8e80941Smrg   return vk_outarray_status(&out);
648b8e80941Smrg}
649b8e80941Smrg
650b8e80941Smrgstatic VkResult
651b8e80941Smrgwsi_wl_surface_get_present_modes(VkIcdSurfaceBase *surface,
652b8e80941Smrg                                 uint32_t* pPresentModeCount,
653b8e80941Smrg                                 VkPresentModeKHR* pPresentModes)
654b8e80941Smrg{
655b8e80941Smrg   if (pPresentModes == NULL) {
656b8e80941Smrg      *pPresentModeCount = ARRAY_SIZE(present_modes);
657b8e80941Smrg      return VK_SUCCESS;
658b8e80941Smrg   }
659b8e80941Smrg
660b8e80941Smrg   *pPresentModeCount = MIN2(*pPresentModeCount, ARRAY_SIZE(present_modes));
661b8e80941Smrg   typed_memcpy(pPresentModes, present_modes, *pPresentModeCount);
662b8e80941Smrg
663b8e80941Smrg   if (*pPresentModeCount < ARRAY_SIZE(present_modes))
664b8e80941Smrg      return VK_INCOMPLETE;
665b8e80941Smrg   else
666b8e80941Smrg      return VK_SUCCESS;
667b8e80941Smrg}
668b8e80941Smrg
669b8e80941Smrgstatic VkResult
670b8e80941Smrgwsi_wl_surface_get_present_rectangles(VkIcdSurfaceBase *surface,
671b8e80941Smrg                                      struct wsi_device *wsi_device,
672b8e80941Smrg                                      uint32_t* pRectCount,
673b8e80941Smrg                                      VkRect2D* pRects)
674b8e80941Smrg{
675b8e80941Smrg   VK_OUTARRAY_MAKE(out, pRects, pRectCount);
676b8e80941Smrg
677b8e80941Smrg   vk_outarray_append(&out, rect) {
678b8e80941Smrg      /* We don't know a size so just return the usual "I don't know." */
679b8e80941Smrg      *rect = (VkRect2D) {
680b8e80941Smrg         .offset = { 0, 0 },
681b8e80941Smrg         .extent = { -1, -1 },
682b8e80941Smrg      };
683b8e80941Smrg   }
684b8e80941Smrg
685b8e80941Smrg   return vk_outarray_status(&out);
686b8e80941Smrg}
687b8e80941Smrg
688b8e80941SmrgVkResult wsi_create_wl_surface(const VkAllocationCallbacks *pAllocator,
689b8e80941Smrg			       const VkWaylandSurfaceCreateInfoKHR *pCreateInfo,
690b8e80941Smrg			       VkSurfaceKHR *pSurface)
691b8e80941Smrg{
692b8e80941Smrg   VkIcdSurfaceWayland *surface;
693b8e80941Smrg
694b8e80941Smrg   surface = vk_alloc(pAllocator, sizeof *surface, 8,
695b8e80941Smrg                      VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
696b8e80941Smrg   if (surface == NULL)
697b8e80941Smrg      return VK_ERROR_OUT_OF_HOST_MEMORY;
698b8e80941Smrg
699b8e80941Smrg   surface->base.platform = VK_ICD_WSI_PLATFORM_WAYLAND;
700b8e80941Smrg   surface->display = pCreateInfo->display;
701b8e80941Smrg   surface->surface = pCreateInfo->surface;
702b8e80941Smrg
703b8e80941Smrg   *pSurface = VkIcdSurfaceBase_to_handle(&surface->base);
704b8e80941Smrg
705b8e80941Smrg   return VK_SUCCESS;
706b8e80941Smrg}
707b8e80941Smrg
708b8e80941Smrgstruct wsi_wl_image {
709b8e80941Smrg   struct wsi_image                             base;
710b8e80941Smrg   struct wl_buffer *                           buffer;
711b8e80941Smrg   bool                                         busy;
712b8e80941Smrg};
713b8e80941Smrg
714b8e80941Smrgstruct wsi_wl_swapchain {
715b8e80941Smrg   struct wsi_swapchain                        base;
716b8e80941Smrg
717b8e80941Smrg   struct wsi_wl_display                        *display;
718b8e80941Smrg
719b8e80941Smrg   struct wl_surface *                          surface;
720b8e80941Smrg   uint32_t                                     surface_version;
721b8e80941Smrg
722b8e80941Smrg   /* non-NULL when wl_drm should be used for wl_buffer creation; otherwise,
723b8e80941Smrg    * zwp_linux_dmabuf_v1 should be used.
724b8e80941Smrg    */
725b8e80941Smrg   struct wl_drm *                              drm_wrapper;
726b8e80941Smrg
727b8e80941Smrg   struct wl_callback *                         frame;
728b8e80941Smrg
729b8e80941Smrg   VkExtent2D                                   extent;
730b8e80941Smrg   VkFormat                                     vk_format;
731b8e80941Smrg   uint32_t                                     drm_format;
732b8e80941Smrg
733b8e80941Smrg   uint32_t                                     num_drm_modifiers;
734b8e80941Smrg   const uint64_t *                             drm_modifiers;
735b8e80941Smrg
736b8e80941Smrg   VkPresentModeKHR                             present_mode;
737b8e80941Smrg   bool                                         fifo_ready;
738b8e80941Smrg
739b8e80941Smrg   struct wsi_wl_image                          images[0];
740b8e80941Smrg};
741b8e80941SmrgWSI_DEFINE_NONDISP_HANDLE_CASTS(wsi_wl_swapchain, VkSwapchainKHR)
742b8e80941Smrg
743b8e80941Smrgstatic struct wsi_image *
744b8e80941Smrgwsi_wl_swapchain_get_wsi_image(struct wsi_swapchain *wsi_chain,
745b8e80941Smrg                               uint32_t image_index)
746b8e80941Smrg{
747b8e80941Smrg   struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain;
748b8e80941Smrg   return &chain->images[image_index].base;
749b8e80941Smrg}
750b8e80941Smrg
751b8e80941Smrgstatic VkResult
752b8e80941Smrgwsi_wl_swapchain_acquire_next_image(struct wsi_swapchain *wsi_chain,
753b8e80941Smrg                                    const VkAcquireNextImageInfoKHR *info,
754b8e80941Smrg                                    uint32_t *image_index)
755b8e80941Smrg{
756b8e80941Smrg   struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain;
757b8e80941Smrg
758b8e80941Smrg#ifdef DEBUG
759b8e80941Smrg   /*
760b8e80941Smrg    * TODO: We need to implement this
761b8e80941Smrg    */
762b8e80941Smrg   if (info->timeout != 0 && info->timeout != UINT64_MAX)
763b8e80941Smrg   {
764b8e80941Smrg      fprintf(stderr, "timeout not supported; ignoring");
765b8e80941Smrg   }
766b8e80941Smrg#endif
767b8e80941Smrg
768b8e80941Smrg   int ret = wl_display_dispatch_queue_pending(chain->display->wl_display,
769b8e80941Smrg                                               chain->display->queue);
770b8e80941Smrg   /* XXX: I'm not sure if out-of-date is the right error here.  If
771b8e80941Smrg    * wl_display_dispatch_queue_pending fails it most likely means we got
772b8e80941Smrg    * kicked by the server so this seems more-or-less correct.
773b8e80941Smrg    */
774b8e80941Smrg   if (ret < 0)
775b8e80941Smrg      return VK_ERROR_OUT_OF_DATE_KHR;
776b8e80941Smrg
777b8e80941Smrg   while (1) {
778b8e80941Smrg      for (uint32_t i = 0; i < chain->base.image_count; i++) {
779b8e80941Smrg         if (!chain->images[i].busy) {
780b8e80941Smrg            /* We found a non-busy image */
781b8e80941Smrg            *image_index = i;
782b8e80941Smrg            chain->images[i].busy = true;
783b8e80941Smrg            return VK_SUCCESS;
784b8e80941Smrg         }
785b8e80941Smrg      }
786b8e80941Smrg
787b8e80941Smrg      /* We now have to do a blocking dispatch, because all our images
788b8e80941Smrg       * are in use and we cannot return one until the server does. However,
789b8e80941Smrg       * if the client has requested non-blocking ANI, then we tell it up front
790b8e80941Smrg       * that we have nothing to return.
791b8e80941Smrg       */
792b8e80941Smrg      if (info->timeout == 0)
793b8e80941Smrg         return VK_NOT_READY;
794b8e80941Smrg
795b8e80941Smrg      int ret = wl_display_roundtrip_queue(chain->display->wl_display,
796b8e80941Smrg                                           chain->display->queue);
797b8e80941Smrg      if (ret < 0)
798b8e80941Smrg         return VK_ERROR_OUT_OF_DATE_KHR;
799b8e80941Smrg   }
800b8e80941Smrg}
801b8e80941Smrg
802b8e80941Smrgstatic void
803b8e80941Smrgframe_handle_done(void *data, struct wl_callback *callback, uint32_t serial)
804b8e80941Smrg{
805b8e80941Smrg   struct wsi_wl_swapchain *chain = data;
806b8e80941Smrg
807b8e80941Smrg   chain->frame = NULL;
808b8e80941Smrg   chain->fifo_ready = true;
809b8e80941Smrg
810b8e80941Smrg   wl_callback_destroy(callback);
811b8e80941Smrg}
812b8e80941Smrg
813b8e80941Smrgstatic const struct wl_callback_listener frame_listener = {
814b8e80941Smrg   frame_handle_done,
815b8e80941Smrg};
816b8e80941Smrg
817b8e80941Smrgstatic VkResult
818b8e80941Smrgwsi_wl_swapchain_queue_present(struct wsi_swapchain *wsi_chain,
819b8e80941Smrg                               uint32_t image_index,
820b8e80941Smrg                               const VkPresentRegionKHR *damage)
821b8e80941Smrg{
822b8e80941Smrg   struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain;
823b8e80941Smrg
824b8e80941Smrg   if (chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR) {
825b8e80941Smrg      while (!chain->fifo_ready) {
826b8e80941Smrg         int ret = wl_display_dispatch_queue(chain->display->wl_display,
827b8e80941Smrg                                             chain->display->queue);
828b8e80941Smrg         if (ret < 0)
829b8e80941Smrg            return VK_ERROR_OUT_OF_DATE_KHR;
830b8e80941Smrg      }
831b8e80941Smrg   }
832b8e80941Smrg
833b8e80941Smrg   assert(image_index < chain->base.image_count);
834b8e80941Smrg   wl_surface_attach(chain->surface, chain->images[image_index].buffer, 0, 0);
835b8e80941Smrg
836b8e80941Smrg   if (chain->surface_version >= 4 && damage &&
837b8e80941Smrg       damage->pRectangles && damage->rectangleCount > 0) {
838b8e80941Smrg      for (unsigned i = 0; i < damage->rectangleCount; i++) {
839b8e80941Smrg         const VkRectLayerKHR *rect = &damage->pRectangles[i];
840b8e80941Smrg         assert(rect->layer == 0);
841b8e80941Smrg         wl_surface_damage_buffer(chain->surface,
842b8e80941Smrg                                  rect->offset.x, rect->offset.y,
843b8e80941Smrg                                  rect->extent.width, rect->extent.height);
844b8e80941Smrg      }
845b8e80941Smrg   } else {
846b8e80941Smrg      wl_surface_damage(chain->surface, 0, 0, INT32_MAX, INT32_MAX);
847b8e80941Smrg   }
848b8e80941Smrg
849b8e80941Smrg   if (chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR) {
850b8e80941Smrg      chain->frame = wl_surface_frame(chain->surface);
851b8e80941Smrg      wl_callback_add_listener(chain->frame, &frame_listener, chain);
852b8e80941Smrg      chain->fifo_ready = false;
853b8e80941Smrg   }
854b8e80941Smrg
855b8e80941Smrg   chain->images[image_index].busy = true;
856b8e80941Smrg   wl_surface_commit(chain->surface);
857b8e80941Smrg   wl_display_flush(chain->display->wl_display);
858b8e80941Smrg
859b8e80941Smrg   return VK_SUCCESS;
860b8e80941Smrg}
861b8e80941Smrg
862b8e80941Smrgstatic void
863b8e80941Smrgbuffer_handle_release(void *data, struct wl_buffer *buffer)
864b8e80941Smrg{
865b8e80941Smrg   struct wsi_wl_image *image = data;
866b8e80941Smrg
867b8e80941Smrg   assert(image->buffer == buffer);
868b8e80941Smrg
869b8e80941Smrg   image->busy = false;
870b8e80941Smrg}
871b8e80941Smrg
872b8e80941Smrgstatic const struct wl_buffer_listener buffer_listener = {
873b8e80941Smrg   buffer_handle_release,
874b8e80941Smrg};
875b8e80941Smrg
876b8e80941Smrgstatic VkResult
877b8e80941Smrgwsi_wl_image_init(struct wsi_wl_swapchain *chain,
878b8e80941Smrg                  struct wsi_wl_image *image,
879b8e80941Smrg                  const VkSwapchainCreateInfoKHR *pCreateInfo,
880b8e80941Smrg                  const VkAllocationCallbacks* pAllocator)
881b8e80941Smrg{
882b8e80941Smrg   struct wsi_wl_display *display = chain->display;
883b8e80941Smrg   VkResult result;
884b8e80941Smrg
885b8e80941Smrg   result = wsi_create_native_image(&chain->base, pCreateInfo,
886b8e80941Smrg                                    chain->num_drm_modifiers > 0 ? 1 : 0,
887b8e80941Smrg                                    &chain->num_drm_modifiers,
888b8e80941Smrg                                    &chain->drm_modifiers, &image->base);
889b8e80941Smrg
890b8e80941Smrg   if (result != VK_SUCCESS)
891b8e80941Smrg      return result;
892b8e80941Smrg
893b8e80941Smrg   if (!chain->drm_wrapper) {
894b8e80941Smrg      /* Only request modifiers if we have dmabuf, else it must be implicit. */
895b8e80941Smrg      assert(display->dmabuf.wl_dmabuf);
896b8e80941Smrg      assert(image->base.drm_modifier != DRM_FORMAT_MOD_INVALID);
897b8e80941Smrg
898b8e80941Smrg      struct zwp_linux_buffer_params_v1 *params =
899b8e80941Smrg         zwp_linux_dmabuf_v1_create_params(display->dmabuf.wl_dmabuf);
900b8e80941Smrg      wl_proxy_set_queue((struct wl_proxy *) params, chain->display->queue);
901b8e80941Smrg
902b8e80941Smrg      for (int i = 0; i < image->base.num_planes; i++) {
903b8e80941Smrg         zwp_linux_buffer_params_v1_add(params,
904b8e80941Smrg                                        image->base.fds[i],
905b8e80941Smrg                                        i,
906b8e80941Smrg                                        image->base.offsets[i],
907b8e80941Smrg                                        image->base.row_pitches[i],
908b8e80941Smrg                                        image->base.drm_modifier >> 32,
909b8e80941Smrg                                        image->base.drm_modifier & 0xffffffff);
910b8e80941Smrg         close(image->base.fds[i]);
911b8e80941Smrg      }
912b8e80941Smrg
913b8e80941Smrg      image->buffer =
914b8e80941Smrg         zwp_linux_buffer_params_v1_create_immed(params,
915b8e80941Smrg                                                 chain->extent.width,
916b8e80941Smrg                                                 chain->extent.height,
917b8e80941Smrg                                                 chain->drm_format,
918b8e80941Smrg                                                 0);
919b8e80941Smrg      zwp_linux_buffer_params_v1_destroy(params);
920b8e80941Smrg   } else {
921b8e80941Smrg      /* Without passing modifiers, we can't have multi-plane RGB images. */
922b8e80941Smrg      assert(image->base.num_planes == 1);
923b8e80941Smrg      assert(image->base.drm_modifier == DRM_FORMAT_MOD_INVALID);
924b8e80941Smrg
925b8e80941Smrg      image->buffer =
926b8e80941Smrg         wl_drm_create_prime_buffer(chain->drm_wrapper,
927b8e80941Smrg                                    image->base.fds[0], /* name */
928b8e80941Smrg                                    chain->extent.width,
929b8e80941Smrg                                    chain->extent.height,
930b8e80941Smrg                                    chain->drm_format,
931b8e80941Smrg                                    image->base.offsets[0],
932b8e80941Smrg                                    image->base.row_pitches[0],
933b8e80941Smrg                                    0, 0, 0, 0 /* unused */);
934b8e80941Smrg      close(image->base.fds[0]);
935b8e80941Smrg   }
936b8e80941Smrg
937b8e80941Smrg   if (!image->buffer)
938b8e80941Smrg      goto fail_image;
939b8e80941Smrg
940b8e80941Smrg   wl_buffer_add_listener(image->buffer, &buffer_listener, image);
941b8e80941Smrg
942b8e80941Smrg   return VK_SUCCESS;
943b8e80941Smrg
944b8e80941Smrgfail_image:
945b8e80941Smrg   wsi_destroy_image(&chain->base, &image->base);
946b8e80941Smrg
947b8e80941Smrg   return result;
948b8e80941Smrg}
949b8e80941Smrg
950b8e80941Smrgstatic VkResult
951b8e80941Smrgwsi_wl_swapchain_destroy(struct wsi_swapchain *wsi_chain,
952b8e80941Smrg                         const VkAllocationCallbacks *pAllocator)
953b8e80941Smrg{
954b8e80941Smrg   struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain;
955b8e80941Smrg
956b8e80941Smrg   for (uint32_t i = 0; i < chain->base.image_count; i++) {
957b8e80941Smrg      if (chain->images[i].buffer) {
958b8e80941Smrg         wl_buffer_destroy(chain->images[i].buffer);
959b8e80941Smrg         wsi_destroy_image(&chain->base, &chain->images[i].base);
960b8e80941Smrg      }
961b8e80941Smrg   }
962b8e80941Smrg
963b8e80941Smrg   if (chain->frame)
964b8e80941Smrg      wl_callback_destroy(chain->frame);
965b8e80941Smrg   if (chain->surface)
966b8e80941Smrg      wl_proxy_wrapper_destroy(chain->surface);
967b8e80941Smrg   if (chain->drm_wrapper)
968b8e80941Smrg      wl_proxy_wrapper_destroy(chain->drm_wrapper);
969b8e80941Smrg
970b8e80941Smrg   if (chain->display)
971b8e80941Smrg      wsi_wl_display_unref(chain->display);
972b8e80941Smrg
973b8e80941Smrg   wsi_swapchain_finish(&chain->base);
974b8e80941Smrg
975b8e80941Smrg   vk_free(pAllocator, chain);
976b8e80941Smrg
977b8e80941Smrg   return VK_SUCCESS;
978b8e80941Smrg}
979b8e80941Smrg
980b8e80941Smrgstatic VkResult
981b8e80941Smrgwsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
982b8e80941Smrg                                VkDevice device,
983b8e80941Smrg                                struct wsi_device *wsi_device,
984b8e80941Smrg                                const VkSwapchainCreateInfoKHR* pCreateInfo,
985b8e80941Smrg                                const VkAllocationCallbacks* pAllocator,
986b8e80941Smrg                                struct wsi_swapchain **swapchain_out)
987b8e80941Smrg{
988b8e80941Smrg   VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface;
989b8e80941Smrg   struct wsi_wayland *wsi =
990b8e80941Smrg      (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND];
991b8e80941Smrg   struct wsi_wl_swapchain *chain;
992b8e80941Smrg   VkResult result;
993b8e80941Smrg
994b8e80941Smrg   assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
995b8e80941Smrg
996b8e80941Smrg   int num_images = pCreateInfo->minImageCount;
997b8e80941Smrg
998b8e80941Smrg   size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]);
999b8e80941Smrg   chain = vk_alloc(pAllocator, size, 8,
1000b8e80941Smrg                      VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1001b8e80941Smrg   if (chain == NULL)
1002b8e80941Smrg      return VK_ERROR_OUT_OF_HOST_MEMORY;
1003b8e80941Smrg
1004b8e80941Smrg   result = wsi_swapchain_init(wsi_device, &chain->base, device,
1005b8e80941Smrg                               pCreateInfo, pAllocator);
1006b8e80941Smrg   if (result != VK_SUCCESS) {
1007b8e80941Smrg      vk_free(pAllocator, chain);
1008b8e80941Smrg      return result;
1009b8e80941Smrg   }
1010b8e80941Smrg
1011b8e80941Smrg   /* Mark a bunch of stuff as NULL.  This way we can just call
1012b8e80941Smrg    * destroy_swapchain for cleanup.
1013b8e80941Smrg    */
1014b8e80941Smrg   for (uint32_t i = 0; i < num_images; i++)
1015b8e80941Smrg      chain->images[i].buffer = NULL;
1016b8e80941Smrg   chain->surface = NULL;
1017b8e80941Smrg   chain->drm_wrapper = NULL;
1018b8e80941Smrg   chain->frame = NULL;
1019b8e80941Smrg
1020b8e80941Smrg   bool alpha = pCreateInfo->compositeAlpha ==
1021b8e80941Smrg                      VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
1022b8e80941Smrg
1023b8e80941Smrg   chain->base.destroy = wsi_wl_swapchain_destroy;
1024b8e80941Smrg   chain->base.get_wsi_image = wsi_wl_swapchain_get_wsi_image;
1025b8e80941Smrg   chain->base.acquire_next_image = wsi_wl_swapchain_acquire_next_image;
1026b8e80941Smrg   chain->base.queue_present = wsi_wl_swapchain_queue_present;
1027b8e80941Smrg   chain->base.present_mode = wsi_swapchain_get_present_mode(wsi_device, pCreateInfo);
1028b8e80941Smrg   chain->base.image_count = num_images;
1029b8e80941Smrg   chain->extent = pCreateInfo->imageExtent;
1030b8e80941Smrg   chain->vk_format = pCreateInfo->imageFormat;
1031b8e80941Smrg   chain->drm_format = wl_drm_format_for_vk_format(chain->vk_format, alpha);
1032b8e80941Smrg
1033b8e80941Smrg   if (pCreateInfo->oldSwapchain) {
1034b8e80941Smrg      /* If we have an oldSwapchain parameter, copy the display struct over
1035b8e80941Smrg       * from the old one so we don't have to fully re-initialize it.
1036b8e80941Smrg       */
1037b8e80941Smrg      WSI_FROM_HANDLE(wsi_wl_swapchain, old_chain, pCreateInfo->oldSwapchain);
1038b8e80941Smrg      chain->display = wsi_wl_display_ref(old_chain->display);
1039b8e80941Smrg   } else {
1040b8e80941Smrg      chain->display = NULL;
1041b8e80941Smrg      result = wsi_wl_display_create(wsi, surface->display, &chain->display);
1042b8e80941Smrg      if (result != VK_SUCCESS)
1043b8e80941Smrg         goto fail;
1044b8e80941Smrg   }
1045b8e80941Smrg
1046b8e80941Smrg   chain->surface = wl_proxy_create_wrapper(surface->surface);
1047b8e80941Smrg   if (!chain->surface) {
1048b8e80941Smrg      result = VK_ERROR_OUT_OF_HOST_MEMORY;
1049b8e80941Smrg      goto fail;
1050b8e80941Smrg   }
1051b8e80941Smrg   wl_proxy_set_queue((struct wl_proxy *) chain->surface,
1052b8e80941Smrg                      chain->display->queue);
1053b8e80941Smrg   chain->surface_version = wl_proxy_get_version((void *)surface->surface);
1054b8e80941Smrg
1055b8e80941Smrg   chain->num_drm_modifiers = 0;
1056b8e80941Smrg   chain->drm_modifiers = 0;
1057b8e80941Smrg
1058b8e80941Smrg   /* Use explicit DRM format modifiers when both the server and the driver
1059b8e80941Smrg    * support them.
1060b8e80941Smrg    */
1061b8e80941Smrg   if (chain->display->dmabuf.wl_dmabuf &&
1062b8e80941Smrg       chain->base.wsi->supports_modifiers) {
1063b8e80941Smrg      struct u_vector *modifiers;
1064b8e80941Smrg      switch (chain->drm_format) {
1065b8e80941Smrg      case WL_DRM_FORMAT_ARGB8888:
1066b8e80941Smrg         modifiers = &chain->display->dmabuf.modifiers.argb8888;
1067b8e80941Smrg         break;
1068b8e80941Smrg      case WL_DRM_FORMAT_XRGB8888:
1069b8e80941Smrg         modifiers = &chain->display->dmabuf.modifiers.xrgb8888;
1070b8e80941Smrg         break;
1071b8e80941Smrg      default:
1072b8e80941Smrg         modifiers = NULL;
1073b8e80941Smrg         break;
1074b8e80941Smrg      }
1075b8e80941Smrg
1076b8e80941Smrg      if (modifiers) {
1077b8e80941Smrg         chain->drm_modifiers = u_vector_tail(modifiers);
1078b8e80941Smrg         chain->num_drm_modifiers = u_vector_length(modifiers);
1079b8e80941Smrg      }
1080b8e80941Smrg   }
1081b8e80941Smrg
1082b8e80941Smrg   /* When there are explicit DRM format modifiers, we must use
1083b8e80941Smrg    * zwp_linux_dmabuf_v1 for wl_buffer creation.  Otherwise, we must use
1084b8e80941Smrg    * wl_drm.
1085b8e80941Smrg    */
1086b8e80941Smrg   if (!chain->num_drm_modifiers) {
1087b8e80941Smrg      assert(chain->display->drm.wl_drm);
1088b8e80941Smrg
1089b8e80941Smrg      chain->drm_wrapper =
1090b8e80941Smrg         wl_proxy_create_wrapper(chain->display->drm.wl_drm);
1091b8e80941Smrg      if (!chain->drm_wrapper) {
1092b8e80941Smrg         result = VK_ERROR_OUT_OF_HOST_MEMORY;
1093b8e80941Smrg         goto fail;
1094b8e80941Smrg      }
1095b8e80941Smrg      wl_proxy_set_queue((struct wl_proxy *) chain->drm_wrapper,
1096b8e80941Smrg                         chain->display->queue);
1097b8e80941Smrg   }
1098b8e80941Smrg
1099b8e80941Smrg   chain->fifo_ready = true;
1100b8e80941Smrg
1101b8e80941Smrg   for (uint32_t i = 0; i < chain->base.image_count; i++) {
1102b8e80941Smrg      result = wsi_wl_image_init(chain, &chain->images[i],
1103b8e80941Smrg                                 pCreateInfo, pAllocator);
1104b8e80941Smrg      if (result != VK_SUCCESS)
1105b8e80941Smrg         goto fail;
1106b8e80941Smrg      chain->images[i].busy = false;
1107b8e80941Smrg   }
1108b8e80941Smrg
1109b8e80941Smrg   *swapchain_out = &chain->base;
1110b8e80941Smrg
1111b8e80941Smrg   return VK_SUCCESS;
1112b8e80941Smrg
1113b8e80941Smrgfail:
1114b8e80941Smrg   wsi_wl_swapchain_destroy(&chain->base, pAllocator);
1115b8e80941Smrg
1116b8e80941Smrg   return result;
1117b8e80941Smrg}
1118b8e80941Smrg
1119b8e80941SmrgVkResult
1120b8e80941Smrgwsi_wl_init_wsi(struct wsi_device *wsi_device,
1121b8e80941Smrg                const VkAllocationCallbacks *alloc,
1122b8e80941Smrg                VkPhysicalDevice physical_device)
1123b8e80941Smrg{
1124b8e80941Smrg   struct wsi_wayland *wsi;
1125b8e80941Smrg   VkResult result;
1126b8e80941Smrg
1127b8e80941Smrg   wsi = vk_alloc(alloc, sizeof(*wsi), 8,
1128b8e80941Smrg                   VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1129b8e80941Smrg   if (!wsi) {
1130b8e80941Smrg      result = VK_ERROR_OUT_OF_HOST_MEMORY;
1131b8e80941Smrg      goto fail;
1132b8e80941Smrg   }
1133b8e80941Smrg
1134b8e80941Smrg   wsi->physical_device = physical_device;
1135b8e80941Smrg   wsi->alloc = alloc;
1136b8e80941Smrg   wsi->wsi = wsi_device;
1137b8e80941Smrg
1138b8e80941Smrg   wsi->base.get_support = wsi_wl_surface_get_support;
1139b8e80941Smrg   wsi->base.get_capabilities2 = wsi_wl_surface_get_capabilities2;
1140b8e80941Smrg   wsi->base.get_formats = wsi_wl_surface_get_formats;
1141b8e80941Smrg   wsi->base.get_formats2 = wsi_wl_surface_get_formats2;
1142b8e80941Smrg   wsi->base.get_present_modes = wsi_wl_surface_get_present_modes;
1143b8e80941Smrg   wsi->base.get_present_rectangles = wsi_wl_surface_get_present_rectangles;
1144b8e80941Smrg   wsi->base.create_swapchain = wsi_wl_surface_create_swapchain;
1145b8e80941Smrg
1146b8e80941Smrg   wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND] = &wsi->base;
1147b8e80941Smrg
1148b8e80941Smrg   return VK_SUCCESS;
1149b8e80941Smrg
1150b8e80941Smrgfail:
1151b8e80941Smrg   wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND] = NULL;
1152b8e80941Smrg
1153b8e80941Smrg   return result;
1154b8e80941Smrg}
1155b8e80941Smrg
1156b8e80941Smrgvoid
1157b8e80941Smrgwsi_wl_finish_wsi(struct wsi_device *wsi_device,
1158b8e80941Smrg                  const VkAllocationCallbacks *alloc)
1159b8e80941Smrg{
1160b8e80941Smrg   struct wsi_wayland *wsi =
1161b8e80941Smrg      (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND];
1162b8e80941Smrg   if (!wsi)
1163b8e80941Smrg      return;
1164b8e80941Smrg
1165b8e80941Smrg   vk_free(alloc, wsi);
1166b8e80941Smrg}
1167