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, ®istry_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