Path: blob/21.2-virgl/src/vulkan/wsi/wsi_common_wayland.c
7642 views
/*1* Copyright © 2015 Intel Corporation2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS20* IN THE SOFTWARE.21*/2223#include <wayland-client.h>2425#include <assert.h>26#include <stdlib.h>27#include <stdio.h>28#include <unistd.h>29#include <errno.h>30#include <string.h>31#include <pthread.h>32#include <poll.h>33#include <sys/mman.h>3435#include "drm-uapi/drm_fourcc.h"3637#include "vk_util.h"38#include "wsi_common_private.h"39#include "wsi_common_wayland.h"40#include "wayland-drm-client-protocol.h"41#include "linux-dmabuf-unstable-v1-client-protocol.h"4243#include <util/compiler.h>44#include <util/hash_table.h>45#include <util/timespec.h>46#include <util/u_vector.h>47#include <util/anon_file.h>4849struct wsi_wayland;5051struct wsi_wl_display_swrast {52struct wl_shm * wl_shm;53struct u_vector formats;54};5556struct wsi_wl_display_drm {57struct wl_drm * wl_drm;58struct u_vector formats;59uint32_t capabilities;60};6162struct wsi_wl_display_dmabuf {63struct zwp_linux_dmabuf_v1 * wl_dmabuf;64struct u_vector formats;65struct {66struct u_vector argb8888;67struct u_vector xrgb8888;68} modifiers;69};7071struct wsi_wl_display {72/* The real wl_display */73struct wl_display * wl_display;74/* Actually a proxy wrapper around the event queue */75struct wl_display * wl_display_wrapper;76struct wl_event_queue * queue;7778struct wsi_wl_display_swrast swrast;79struct wsi_wl_display_drm drm;80struct wsi_wl_display_dmabuf dmabuf;8182struct wsi_wayland *wsi_wl;8384/* Points to formats in wsi_wl_display_drm or wsi_wl_display_dmabuf */85struct u_vector * formats;8687/* Only used for displays created by wsi_wl_display_create */88uint32_t refcount;8990bool sw;91};9293struct wsi_wayland {94struct wsi_interface base;9596struct wsi_device *wsi;9798const VkAllocationCallbacks *alloc;99VkPhysicalDevice physical_device;100};101102static void103wsi_wl_display_add_vk_format(struct wsi_wl_display *display,104struct u_vector *formats, VkFormat format)105{106/* Don't add a format that's already in the list */107VkFormat *f;108u_vector_foreach(f, formats)109if (*f == format)110return;111112/* Don't add formats that aren't renderable. */113VkFormatProperties props;114115display->wsi_wl->wsi->GetPhysicalDeviceFormatProperties(display->wsi_wl->physical_device,116format, &props);117if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT))118return;119120f = u_vector_add(formats);121if (f)122*f = format;123}124125static void126wsi_wl_display_add_wl_format(struct wsi_wl_display *display,127struct u_vector *formats, uint32_t wl_format)128{129switch (wl_format) {130#if 0131/* TODO: These are only available when VK_EXT_4444_formats is enabled, so132* we probably need to make their use conditional on this extension. */133case WL_DRM_FORMAT_ARGB4444:134case WL_DRM_FORMAT_XRGB4444:135wsi_wl_display_add_vk_format(display, formats,136VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT);137break;138case WL_DRM_FORMAT_ABGR4444:139case WL_DRM_FORMAT_XBGR4444:140wsi_wl_display_add_vk_format(display, formats,141VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT);142break;143#endif144145/* Vulkan _PACKN formats have the same component order as DRM formats146* on little endian systems, on big endian there exists no analog. */147#if MESA_LITTLE_ENDIAN148case WL_DRM_FORMAT_RGBA4444:149case WL_DRM_FORMAT_RGBX4444:150wsi_wl_display_add_vk_format(display, formats,151VK_FORMAT_R4G4B4A4_UNORM_PACK16);152break;153case WL_DRM_FORMAT_BGRA4444:154case WL_DRM_FORMAT_BGRX4444:155wsi_wl_display_add_vk_format(display, formats,156VK_FORMAT_B4G4R4A4_UNORM_PACK16);157break;158case WL_DRM_FORMAT_RGB565:159wsi_wl_display_add_vk_format(display, formats,160VK_FORMAT_R5G6B5_UNORM_PACK16);161break;162case WL_DRM_FORMAT_BGR565:163wsi_wl_display_add_vk_format(display, formats,164VK_FORMAT_B5G6R5_UNORM_PACK16);165break;166case WL_DRM_FORMAT_ARGB1555:167case WL_DRM_FORMAT_XRGB1555:168wsi_wl_display_add_vk_format(display, formats,169VK_FORMAT_A1R5G5B5_UNORM_PACK16);170break;171case WL_DRM_FORMAT_RGBA5551:172case WL_DRM_FORMAT_RGBX5551:173wsi_wl_display_add_vk_format(display, formats,174VK_FORMAT_R5G5B5A1_UNORM_PACK16);175break;176case WL_DRM_FORMAT_BGRA5551:177case WL_DRM_FORMAT_BGRX5551:178wsi_wl_display_add_vk_format(display, formats,179VK_FORMAT_B5G5R5A1_UNORM_PACK16);180break;181case WL_DRM_FORMAT_ARGB2101010:182case WL_DRM_FORMAT_XRGB2101010:183wsi_wl_display_add_vk_format(display, formats,184VK_FORMAT_A2R10G10B10_UNORM_PACK32);185break;186case WL_DRM_FORMAT_ABGR2101010:187case WL_DRM_FORMAT_XBGR2101010:188wsi_wl_display_add_vk_format(display, formats,189VK_FORMAT_A2B10G10R10_UNORM_PACK32);190break;191#endif192193/* Non-packed 8-bit formats have an inverted channel order compared to the194* little endian DRM formats, because the DRM channel ordering is high->low195* but the vulkan channel ordering is in memory byte order196*197* For all UNORM formats which have a SRGB variant, we must support both if198* we can. SRGB in this context means that rendering to it will result in a199* linear -> nonlinear SRGB colorspace conversion before the data is stored.200* The inverse function is applied when sampling from SRGB images.201* From Wayland's perspective nothing changes, the difference is just how202* Vulkan interprets the pixel data. */203case WL_DRM_FORMAT_XBGR8888:204wsi_wl_display_add_vk_format(display, formats,205VK_FORMAT_R8G8B8_SRGB);206wsi_wl_display_add_vk_format(display, formats,207VK_FORMAT_R8G8B8_UNORM);208FALLTHROUGH;209case WL_DRM_FORMAT_ABGR8888:210wsi_wl_display_add_vk_format(display, formats,211VK_FORMAT_R8G8B8A8_SRGB);212wsi_wl_display_add_vk_format(display, formats,213VK_FORMAT_R8G8B8A8_UNORM);214break;215case WL_DRM_FORMAT_XRGB8888:216wsi_wl_display_add_vk_format(display, formats,217VK_FORMAT_B8G8R8_SRGB);218wsi_wl_display_add_vk_format(display, formats,219VK_FORMAT_B8G8R8_UNORM);220FALLTHROUGH;221case WL_DRM_FORMAT_ARGB8888:222wsi_wl_display_add_vk_format(display, formats,223VK_FORMAT_B8G8R8A8_SRGB);224wsi_wl_display_add_vk_format(display, formats,225VK_FORMAT_B8G8R8A8_UNORM);226break;227}228}229230static void231wsi_wl_display_add_wl_shm_format(struct wsi_wl_display *display,232struct u_vector *formats,233uint32_t wl_shm_format)234{235switch (wl_shm_format) {236case WL_SHM_FORMAT_XBGR8888:237wsi_wl_display_add_vk_format(display, formats,238VK_FORMAT_R8G8B8_SRGB);239wsi_wl_display_add_vk_format(display, formats,240VK_FORMAT_R8G8B8_UNORM);241FALLTHROUGH;242case WL_SHM_FORMAT_ABGR8888:243wsi_wl_display_add_vk_format(display, formats,244VK_FORMAT_R8G8B8A8_SRGB);245wsi_wl_display_add_vk_format(display, formats,246VK_FORMAT_R8G8B8A8_UNORM);247break;248case WL_SHM_FORMAT_XRGB8888:249wsi_wl_display_add_vk_format(display, formats,250VK_FORMAT_B8G8R8_SRGB);251wsi_wl_display_add_vk_format(display, formats,252VK_FORMAT_B8G8R8_UNORM);253FALLTHROUGH;254case WL_SHM_FORMAT_ARGB8888:255wsi_wl_display_add_vk_format(display, formats,256VK_FORMAT_B8G8R8A8_SRGB);257wsi_wl_display_add_vk_format(display, formats,258VK_FORMAT_B8G8R8A8_UNORM);259break;260}261}262263264static void265drm_handle_device(void *data, struct wl_drm *drm, const char *name)266{267}268269static uint32_t270wl_drm_format_for_vk_format(VkFormat vk_format, bool alpha)271{272switch (vk_format) {273#if 0274case VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT:275return alpha ? WL_DRM_FORMAT_ARGB4444 : WL_DRM_FORMAT_XRGB4444;276case VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT:277return alpha ? WL_DRM_FORMAT_ABGR4444 : WL_DRM_FORMAT_XBGR4444;278#endif279#if MESA_LITTLE_ENDIAN280case VK_FORMAT_R4G4B4A4_UNORM_PACK16:281return alpha ? WL_DRM_FORMAT_RGBA4444 : WL_DRM_FORMAT_RGBX4444;282case VK_FORMAT_B4G4R4A4_UNORM_PACK16:283return alpha ? WL_DRM_FORMAT_BGRA4444 : WL_DRM_FORMAT_BGRX4444;284case VK_FORMAT_R5G6B5_UNORM_PACK16:285return WL_DRM_FORMAT_RGB565;286case VK_FORMAT_B5G6R5_UNORM_PACK16:287return WL_DRM_FORMAT_BGR565;288case VK_FORMAT_A1R5G5B5_UNORM_PACK16:289return alpha ? WL_DRM_FORMAT_ARGB1555 : WL_DRM_FORMAT_XRGB1555;290case VK_FORMAT_R5G5B5A1_UNORM_PACK16:291return alpha ? WL_DRM_FORMAT_RGBA5551 : WL_DRM_FORMAT_RGBX5551;292case VK_FORMAT_B5G5R5A1_UNORM_PACK16:293return alpha ? WL_DRM_FORMAT_BGRA5551 : WL_DRM_FORMAT_BGRX5551;294case VK_FORMAT_A2R10G10B10_UNORM_PACK32:295return alpha ? WL_DRM_FORMAT_ARGB2101010 : WL_DRM_FORMAT_XRGB2101010;296case VK_FORMAT_A2B10G10R10_UNORM_PACK32:297return alpha ? WL_DRM_FORMAT_ABGR2101010 : WL_DRM_FORMAT_XBGR2101010;298#endif299case VK_FORMAT_R8G8B8_UNORM:300case VK_FORMAT_R8G8B8_SRGB:301return WL_DRM_FORMAT_XBGR8888;302case VK_FORMAT_R8G8B8A8_UNORM:303case VK_FORMAT_R8G8B8A8_SRGB:304return alpha ? WL_DRM_FORMAT_ABGR8888 : WL_DRM_FORMAT_XBGR8888;305case VK_FORMAT_B8G8R8_UNORM:306case VK_FORMAT_B8G8R8_SRGB:307return WL_DRM_FORMAT_BGRX8888;308case VK_FORMAT_B8G8R8A8_UNORM:309case VK_FORMAT_B8G8R8A8_SRGB:310return alpha ? WL_DRM_FORMAT_ARGB8888 : WL_DRM_FORMAT_XRGB8888;311312default:313assert(!"Unsupported Vulkan format");314return 0;315}316}317318static uint32_t319wl_shm_format_for_vk_format(VkFormat vk_format, bool alpha)320{321switch (vk_format) {322case VK_FORMAT_R8G8B8A8_UNORM:323case VK_FORMAT_R8G8B8A8_SRGB:324return alpha ? WL_SHM_FORMAT_ABGR8888 : WL_SHM_FORMAT_XBGR8888;325case VK_FORMAT_B8G8R8A8_UNORM:326case VK_FORMAT_B8G8R8A8_SRGB:327return alpha ? WL_SHM_FORMAT_ARGB8888 : WL_SHM_FORMAT_XRGB8888;328329default:330assert(!"Unsupported Vulkan format");331return 0;332}333}334335static void336drm_handle_format(void *data, struct wl_drm *drm, uint32_t wl_format)337{338struct wsi_wl_display *display = data;339if (display->drm.formats.element_size == 0)340return;341342wsi_wl_display_add_wl_format(display, &display->drm.formats, wl_format);343}344345static void346drm_handle_authenticated(void *data, struct wl_drm *drm)347{348}349350static void351drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t capabilities)352{353struct wsi_wl_display *display = data;354355display->drm.capabilities = capabilities;356}357358static const struct wl_drm_listener drm_listener = {359drm_handle_device,360drm_handle_format,361drm_handle_authenticated,362drm_handle_capabilities,363};364365static void366dmabuf_handle_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,367uint32_t format)368{369/* Formats are implicitly advertised by the modifier event, so we ignore370* them here. */371}372373static void374dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,375uint32_t format, uint32_t modifier_hi,376uint32_t modifier_lo)377{378struct wsi_wl_display *display = data;379struct u_vector *modifiers;380uint64_t *mod = NULL;381382/* If we're not fetching formats, don't fetch modifiers either. */383if (display->dmabuf.formats.element_size == 0)384return;385386switch (format) {387case WL_DRM_FORMAT_ARGB8888:388modifiers = &display->dmabuf.modifiers.argb8888;389break;390case WL_DRM_FORMAT_XRGB8888:391modifiers = &display->dmabuf.modifiers.xrgb8888;392break;393default:394return; /* Unsupported format */395}396397wsi_wl_display_add_wl_format(display, &display->dmabuf.formats, format);398399if (modifier_hi == (DRM_FORMAT_MOD_INVALID >> 32) &&400modifier_lo == (DRM_FORMAT_MOD_INVALID & 0xffffffff))401return;402403mod = u_vector_add(modifiers);404if (!mod)405return;406407*mod = (uint64_t) modifier_hi << 32;408*mod |= (uint64_t) (modifier_lo & 0xffffffff);409}410411static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {412dmabuf_handle_format,413dmabuf_handle_modifier,414};415416static void417shm_handle_format(void *data, struct wl_shm *shm, uint32_t format)418{419struct wsi_wl_display *display = data;420if (display->swrast.formats.element_size == 0)421return;422423wsi_wl_display_add_wl_shm_format(display, &display->swrast.formats, format);424}425426static const struct wl_shm_listener shm_listener = {427.format = shm_handle_format428};429430static void431registry_handle_global(void *data, struct wl_registry *registry,432uint32_t name, const char *interface, uint32_t version)433{434struct wsi_wl_display *display = data;435436if (display->sw) {437if (strcmp(interface, "wl_shm") == 0) {438display->swrast.wl_shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);439wl_shm_add_listener(display->swrast.wl_shm, &shm_listener, display);440}441return;442}443444if (strcmp(interface, "wl_drm") == 0) {445assert(display->drm.wl_drm == NULL);446447assert(version >= 2);448display->drm.wl_drm =449wl_registry_bind(registry, name, &wl_drm_interface, 2);450wl_drm_add_listener(display->drm.wl_drm, &drm_listener, display);451} else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0 && version >= 3) {452display->dmabuf.wl_dmabuf =453wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface, 3);454zwp_linux_dmabuf_v1_add_listener(display->dmabuf.wl_dmabuf,455&dmabuf_listener, display);456}457}458459static void460registry_handle_global_remove(void *data, struct wl_registry *registry,461uint32_t name)462{ /* No-op */ }463464static const struct wl_registry_listener registry_listener = {465registry_handle_global,466registry_handle_global_remove467};468469static void470wsi_wl_display_finish(struct wsi_wl_display *display)471{472assert(display->refcount == 0);473474u_vector_finish(&display->swrast.formats);475u_vector_finish(&display->drm.formats);476u_vector_finish(&display->dmabuf.formats);477u_vector_finish(&display->dmabuf.modifiers.argb8888);478u_vector_finish(&display->dmabuf.modifiers.xrgb8888);479if (display->swrast.wl_shm)480wl_shm_destroy(display->swrast.wl_shm);481if (display->drm.wl_drm)482wl_drm_destroy(display->drm.wl_drm);483if (display->dmabuf.wl_dmabuf)484zwp_linux_dmabuf_v1_destroy(display->dmabuf.wl_dmabuf);485if (display->wl_display_wrapper)486wl_proxy_wrapper_destroy(display->wl_display_wrapper);487if (display->queue)488wl_event_queue_destroy(display->queue);489}490491static VkResult492wsi_wl_display_init(struct wsi_wayland *wsi_wl,493struct wsi_wl_display *display,494struct wl_display *wl_display,495bool get_format_list, bool sw)496{497VkResult result = VK_SUCCESS;498memset(display, 0, sizeof(*display));499500display->wsi_wl = wsi_wl;501display->wl_display = wl_display;502display->sw = sw;503504if (get_format_list) {505if (!u_vector_init(&display->swrast.formats, sizeof(VkFormat), 8) ||506!u_vector_init(&display->drm.formats, sizeof(VkFormat), 8) ||507!u_vector_init(&display->dmabuf.formats, sizeof(VkFormat), 8) ||508!u_vector_init(&display->dmabuf.modifiers.argb8888,509sizeof(uint64_t), 32) ||510!u_vector_init(&display->dmabuf.modifiers.xrgb8888,511sizeof(uint64_t), 32)) {512result = VK_ERROR_OUT_OF_HOST_MEMORY;513goto fail;514}515}516517display->queue = wl_display_create_queue(wl_display);518if (!display->queue) {519result = VK_ERROR_OUT_OF_HOST_MEMORY;520goto fail;521}522523display->wl_display_wrapper = wl_proxy_create_wrapper(wl_display);524if (!display->wl_display_wrapper) {525result = VK_ERROR_OUT_OF_HOST_MEMORY;526goto fail;527}528529wl_proxy_set_queue((struct wl_proxy *) display->wl_display_wrapper,530display->queue);531532struct wl_registry *registry =533wl_display_get_registry(display->wl_display_wrapper);534if (!registry) {535result = VK_ERROR_OUT_OF_HOST_MEMORY;536goto fail;537}538539wl_registry_add_listener(registry, ®istry_listener, display);540541/* Round-trip to get wl_drms and zwp_linux_dmabuf_v1 globals */542wl_display_roundtrip_queue(display->wl_display, display->queue);543544/* Round-trip again to get formats, modifiers and capabilities */545if (display->drm.wl_drm || display->dmabuf.wl_dmabuf || display->swrast.wl_shm)546wl_display_roundtrip_queue(display->wl_display, display->queue);547548if (wsi_wl->wsi->force_bgra8_unorm_first) {549/* Find BGRA8_UNORM in the list and swap it to the first position if we550* can find it. Some apps get confused if SRGB is first in the list.551*/552VkFormat *first_fmt = u_vector_head(display->formats);553VkFormat *iter_fmt;554u_vector_foreach(iter_fmt, display->formats) {555if (*iter_fmt == VK_FORMAT_B8G8R8A8_UNORM) {556*iter_fmt = *first_fmt;557*first_fmt = VK_FORMAT_B8G8R8A8_UNORM;558break;559}560}561}562563/* Prefer the linux-dmabuf protocol if available */564if (display->sw)565display->formats = &display->swrast.formats;566else if (display->dmabuf.wl_dmabuf) {567display->formats = &display->dmabuf.formats;568} else if (display->drm.wl_drm &&569(display->drm.capabilities & WL_DRM_CAPABILITY_PRIME)) {570/* We need prime support for wl_drm */571display->formats = &display->drm.formats;572}573574if (!display->formats) {575result = VK_ERROR_SURFACE_LOST_KHR;576goto fail_registry;577}578579/* We don't need this anymore */580wl_registry_destroy(registry);581582display->refcount = 0;583584return VK_SUCCESS;585586fail_registry:587if (registry)588wl_registry_destroy(registry);589590fail:591wsi_wl_display_finish(display);592return result;593}594595static VkResult596wsi_wl_display_create(struct wsi_wayland *wsi, struct wl_display *wl_display,597bool sw,598struct wsi_wl_display **display_out)599{600struct wsi_wl_display *display =601vk_alloc(wsi->alloc, sizeof(*display), 8,602VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);603if (!display)604return VK_ERROR_OUT_OF_HOST_MEMORY;605606VkResult result = wsi_wl_display_init(wsi, display, wl_display, true,607sw);608if (result != VK_SUCCESS) {609vk_free(wsi->alloc, display);610return result;611}612613display->refcount++;614*display_out = display;615616return result;617}618619static struct wsi_wl_display *620wsi_wl_display_ref(struct wsi_wl_display *display)621{622display->refcount++;623return display;624}625626static void627wsi_wl_display_unref(struct wsi_wl_display *display)628{629if (display->refcount-- > 1)630return;631632struct wsi_wayland *wsi = display->wsi_wl;633wsi_wl_display_finish(display);634vk_free(wsi->alloc, display);635}636637VkBool32638wsi_wl_get_presentation_support(struct wsi_device *wsi_device,639struct wl_display *wl_display)640{641struct wsi_wayland *wsi =642(struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND];643644struct wsi_wl_display display;645VkResult ret = wsi_wl_display_init(wsi, &display, wl_display, false,646wsi_device->sw);647if (ret == VK_SUCCESS)648wsi_wl_display_finish(&display);649650return ret == VK_SUCCESS;651}652653static VkResult654wsi_wl_surface_get_support(VkIcdSurfaceBase *surface,655struct wsi_device *wsi_device,656uint32_t queueFamilyIndex,657VkBool32* pSupported)658{659*pSupported = true;660661return VK_SUCCESS;662}663664static const VkPresentModeKHR present_modes[] = {665VK_PRESENT_MODE_MAILBOX_KHR,666VK_PRESENT_MODE_FIFO_KHR,667};668669static VkResult670wsi_wl_surface_get_capabilities(VkIcdSurfaceBase *surface,671struct wsi_device *wsi_device,672VkSurfaceCapabilitiesKHR* caps)673{674/* For true mailbox mode, we need at least 4 images:675* 1) One to scan out from676* 2) One to have queued for scan-out677* 3) One to be currently held by the Wayland compositor678* 4) One to render to679*/680caps->minImageCount = 4;681/* There is no real maximum */682caps->maxImageCount = 0;683684caps->currentExtent = (VkExtent2D) { UINT32_MAX, UINT32_MAX };685caps->minImageExtent = (VkExtent2D) { 1, 1 };686caps->maxImageExtent = (VkExtent2D) {687wsi_device->maxImageDimension2D,688wsi_device->maxImageDimension2D,689};690691caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;692caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;693caps->maxImageArrayLayers = 1;694695caps->supportedCompositeAlpha =696VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |697VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;698699caps->supportedUsageFlags =700VK_IMAGE_USAGE_TRANSFER_SRC_BIT |701VK_IMAGE_USAGE_SAMPLED_BIT |702VK_IMAGE_USAGE_TRANSFER_DST_BIT |703VK_IMAGE_USAGE_STORAGE_BIT |704VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;705706return VK_SUCCESS;707}708709static VkResult710wsi_wl_surface_get_capabilities2(VkIcdSurfaceBase *surface,711struct wsi_device *wsi_device,712const void *info_next,713VkSurfaceCapabilities2KHR* caps)714{715assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR);716717VkResult result =718wsi_wl_surface_get_capabilities(surface, wsi_device,719&caps->surfaceCapabilities);720721vk_foreach_struct(ext, caps->pNext) {722switch (ext->sType) {723case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: {724VkSurfaceProtectedCapabilitiesKHR *protected = (void *)ext;725protected->supportsProtected = VK_FALSE;726break;727}728729default:730/* Ignored */731break;732}733}734735return result;736}737738static VkResult739wsi_wl_surface_get_formats(VkIcdSurfaceBase *icd_surface,740struct wsi_device *wsi_device,741uint32_t* pSurfaceFormatCount,742VkSurfaceFormatKHR* pSurfaceFormats)743{744VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface;745struct wsi_wayland *wsi =746(struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND];747748struct wsi_wl_display display;749if (wsi_wl_display_init(wsi, &display, surface->display, true,750wsi_device->sw))751return VK_ERROR_SURFACE_LOST_KHR;752753VK_OUTARRAY_MAKE(out, pSurfaceFormats, pSurfaceFormatCount);754755VkFormat *disp_fmt;756u_vector_foreach(disp_fmt, display.formats) {757vk_outarray_append(&out, out_fmt) {758out_fmt->format = *disp_fmt;759out_fmt->colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;760}761}762763wsi_wl_display_finish(&display);764765return vk_outarray_status(&out);766}767768static VkResult769wsi_wl_surface_get_formats2(VkIcdSurfaceBase *icd_surface,770struct wsi_device *wsi_device,771const void *info_next,772uint32_t* pSurfaceFormatCount,773VkSurfaceFormat2KHR* pSurfaceFormats)774{775VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface;776struct wsi_wayland *wsi =777(struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND];778779struct wsi_wl_display display;780if (wsi_wl_display_init(wsi, &display, surface->display, true,781wsi_device->sw))782return VK_ERROR_SURFACE_LOST_KHR;783784VK_OUTARRAY_MAKE(out, pSurfaceFormats, pSurfaceFormatCount);785786VkFormat *disp_fmt;787u_vector_foreach(disp_fmt, display.formats) {788vk_outarray_append(&out, out_fmt) {789out_fmt->surfaceFormat.format = *disp_fmt;790out_fmt->surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;791}792}793794wsi_wl_display_finish(&display);795796return vk_outarray_status(&out);797}798799static VkResult800wsi_wl_surface_get_present_modes(VkIcdSurfaceBase *surface,801uint32_t* pPresentModeCount,802VkPresentModeKHR* pPresentModes)803{804if (pPresentModes == NULL) {805*pPresentModeCount = ARRAY_SIZE(present_modes);806return VK_SUCCESS;807}808809*pPresentModeCount = MIN2(*pPresentModeCount, ARRAY_SIZE(present_modes));810typed_memcpy(pPresentModes, present_modes, *pPresentModeCount);811812if (*pPresentModeCount < ARRAY_SIZE(present_modes))813return VK_INCOMPLETE;814else815return VK_SUCCESS;816}817818static VkResult819wsi_wl_surface_get_present_rectangles(VkIcdSurfaceBase *surface,820struct wsi_device *wsi_device,821uint32_t* pRectCount,822VkRect2D* pRects)823{824VK_OUTARRAY_MAKE(out, pRects, pRectCount);825826vk_outarray_append(&out, rect) {827/* We don't know a size so just return the usual "I don't know." */828*rect = (VkRect2D) {829.offset = { 0, 0 },830.extent = { UINT32_MAX, UINT32_MAX },831};832}833834return vk_outarray_status(&out);835}836837VkResult wsi_create_wl_surface(const VkAllocationCallbacks *pAllocator,838const VkWaylandSurfaceCreateInfoKHR *pCreateInfo,839VkSurfaceKHR *pSurface)840{841VkIcdSurfaceWayland *surface;842843surface = vk_alloc(pAllocator, sizeof *surface, 8,844VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);845if (surface == NULL)846return VK_ERROR_OUT_OF_HOST_MEMORY;847848surface->base.platform = VK_ICD_WSI_PLATFORM_WAYLAND;849surface->display = pCreateInfo->display;850surface->surface = pCreateInfo->surface;851852*pSurface = VkIcdSurfaceBase_to_handle(&surface->base);853854return VK_SUCCESS;855}856857struct wsi_wl_image {858struct wsi_image base;859struct wl_buffer * buffer;860bool busy;861void *data_ptr;862uint32_t data_size;863};864865struct wsi_wl_swapchain {866struct wsi_swapchain base;867868struct wsi_wl_display *display;869870struct wl_surface * surface;871872struct wl_callback * frame;873874VkExtent2D extent;875VkFormat vk_format;876uint32_t drm_format;877uint32_t shm_format;878879uint32_t num_drm_modifiers;880const uint64_t * drm_modifiers;881882VkPresentModeKHR present_mode;883bool fifo_ready;884885struct wsi_wl_image images[0];886};887VK_DEFINE_NONDISP_HANDLE_CASTS(wsi_wl_swapchain, base.base, VkSwapchainKHR,888VK_OBJECT_TYPE_SWAPCHAIN_KHR)889890static struct wsi_image *891wsi_wl_swapchain_get_wsi_image(struct wsi_swapchain *wsi_chain,892uint32_t image_index)893{894struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain;895return &chain->images[image_index].base;896}897898static VkResult899wsi_wl_swapchain_acquire_next_image(struct wsi_swapchain *wsi_chain,900const VkAcquireNextImageInfoKHR *info,901uint32_t *image_index)902{903struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain;904struct timespec start_time, end_time;905struct timespec rel_timeout;906int wl_fd = wl_display_get_fd(chain->display->wl_display);907908timespec_from_nsec(&rel_timeout, info->timeout);909910clock_gettime(CLOCK_MONOTONIC, &start_time);911timespec_add(&end_time, &rel_timeout, &start_time);912913while (1) {914/* Try to dispatch potential events. */915int ret = wl_display_dispatch_queue_pending(chain->display->wl_display,916chain->display->queue);917if (ret < 0)918return VK_ERROR_OUT_OF_DATE_KHR;919920/* Try to find a free image. */921for (uint32_t i = 0; i < chain->base.image_count; i++) {922if (!chain->images[i].busy) {923/* We found a non-busy image */924*image_index = i;925chain->images[i].busy = true;926return VK_SUCCESS;927}928}929930/* Check for timeout. */931struct timespec current_time;932clock_gettime(CLOCK_MONOTONIC, ¤t_time);933if (timespec_after(¤t_time, &end_time))934return VK_NOT_READY;935936/* Try to read events from the server. */937ret = wl_display_prepare_read_queue(chain->display->wl_display,938chain->display->queue);939if (ret < 0) {940/* Another thread might have read events for our queue already. Go941* back to dispatch them.942*/943if (errno == EAGAIN)944continue;945return VK_ERROR_OUT_OF_DATE_KHR;946}947948struct pollfd pollfd = {949.fd = wl_fd,950.events = POLLIN951};952timespec_sub(&rel_timeout, &end_time, ¤t_time);953ret = ppoll(&pollfd, 1, &rel_timeout, NULL);954if (ret <= 0) {955int lerrno = errno;956wl_display_cancel_read(chain->display->wl_display);957if (ret < 0) {958/* If ppoll() was interrupted, try again. */959if (lerrno == EINTR || lerrno == EAGAIN)960continue;961return VK_ERROR_OUT_OF_DATE_KHR;962}963assert(ret == 0);964continue;965}966967ret = wl_display_read_events(chain->display->wl_display);968if (ret < 0)969return VK_ERROR_OUT_OF_DATE_KHR;970}971}972973static void974frame_handle_done(void *data, struct wl_callback *callback, uint32_t serial)975{976struct wsi_wl_swapchain *chain = data;977978chain->frame = NULL;979chain->fifo_ready = true;980981wl_callback_destroy(callback);982}983984static const struct wl_callback_listener frame_listener = {985frame_handle_done,986};987988static VkResult989wsi_wl_swapchain_queue_present(struct wsi_swapchain *wsi_chain,990uint32_t image_index,991const VkPresentRegionKHR *damage)992{993struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain;994995if (chain->display->sw) {996struct wsi_wl_image *image = &chain->images[image_index];997void *dptr = image->data_ptr;998void *sptr;999chain->base.wsi->MapMemory(chain->base.device,1000image->base.memory,10010, 0, 0, &sptr);10021003for (unsigned r = 0; r < chain->extent.height; r++) {1004memcpy(dptr, sptr, image->base.row_pitches[0]);1005dptr += image->base.row_pitches[0];1006sptr += image->base.row_pitches[0];1007}1008chain->base.wsi->UnmapMemory(chain->base.device,1009image->base.memory);10101011}1012if (chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR) {1013while (!chain->fifo_ready) {1014int ret = wl_display_dispatch_queue(chain->display->wl_display,1015chain->display->queue);1016if (ret < 0)1017return VK_ERROR_OUT_OF_DATE_KHR;1018}1019}10201021assert(image_index < chain->base.image_count);1022wl_surface_attach(chain->surface, chain->images[image_index].buffer, 0, 0);10231024if (wl_surface_get_version(chain->surface) >= 4 && damage &&1025damage->pRectangles && damage->rectangleCount > 0) {1026for (unsigned i = 0; i < damage->rectangleCount; i++) {1027const VkRectLayerKHR *rect = &damage->pRectangles[i];1028assert(rect->layer == 0);1029wl_surface_damage_buffer(chain->surface,1030rect->offset.x, rect->offset.y,1031rect->extent.width, rect->extent.height);1032}1033} else {1034wl_surface_damage(chain->surface, 0, 0, INT32_MAX, INT32_MAX);1035}10361037if (chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR) {1038chain->frame = wl_surface_frame(chain->surface);1039wl_callback_add_listener(chain->frame, &frame_listener, chain);1040chain->fifo_ready = false;1041}10421043chain->images[image_index].busy = true;1044wl_surface_commit(chain->surface);1045wl_display_flush(chain->display->wl_display);10461047return VK_SUCCESS;1048}10491050static void1051buffer_handle_release(void *data, struct wl_buffer *buffer)1052{1053struct wsi_wl_image *image = data;10541055assert(image->buffer == buffer);10561057image->busy = false;1058}10591060static const struct wl_buffer_listener buffer_listener = {1061buffer_handle_release,1062};10631064static VkResult1065wsi_wl_image_init(struct wsi_wl_swapchain *chain,1066struct wsi_wl_image *image,1067const VkSwapchainCreateInfoKHR *pCreateInfo,1068const VkAllocationCallbacks* pAllocator)1069{1070struct wsi_wl_display *display = chain->display;1071VkResult result;10721073result = wsi_create_native_image(&chain->base, pCreateInfo,1074chain->num_drm_modifiers > 0 ? 1 : 0,1075&chain->num_drm_modifiers,1076&chain->drm_modifiers, &image->base);10771078if (result != VK_SUCCESS)1079return result;10801081if (display->sw) {1082int fd, stride;10831084stride = image->base.row_pitches[0];1085image->data_size = stride * chain->extent.height;10861087/* Create a shareable buffer */1088fd = os_create_anonymous_file(image->data_size, NULL);1089if (fd < 0)1090goto fail_image;10911092image->data_ptr = mmap(NULL, image->data_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);1093if (image->data_ptr == MAP_FAILED) {1094close(fd);1095goto fail_image;1096}1097/* Share it in a wl_buffer */1098struct wl_shm_pool *pool = wl_shm_create_pool(display->swrast.wl_shm, fd, image->data_size);1099wl_proxy_set_queue((struct wl_proxy *)pool, display->queue);1100image->buffer = wl_shm_pool_create_buffer(pool, 0, chain->extent.width,1101chain->extent.height, stride,1102chain->shm_format);1103wl_shm_pool_destroy(pool);1104close(fd);1105} else if (display->dmabuf.wl_dmabuf) {1106struct zwp_linux_buffer_params_v1 *params =1107zwp_linux_dmabuf_v1_create_params(display->dmabuf.wl_dmabuf);1108if (!params)1109goto fail_image;11101111for (int i = 0; i < image->base.num_planes; i++) {1112zwp_linux_buffer_params_v1_add(params,1113image->base.fds[i],1114i,1115image->base.offsets[i],1116image->base.row_pitches[i],1117image->base.drm_modifier >> 32,1118image->base.drm_modifier & 0xffffffff);1119close(image->base.fds[i]);1120}11211122image->buffer =1123zwp_linux_buffer_params_v1_create_immed(params,1124chain->extent.width,1125chain->extent.height,1126chain->drm_format,11270);1128zwp_linux_buffer_params_v1_destroy(params);1129} else {1130/* Without passing modifiers, we can't have multi-plane RGB images. */1131assert(image->base.num_planes == 1);1132assert(image->base.drm_modifier == DRM_FORMAT_MOD_INVALID);11331134image->buffer =1135wl_drm_create_prime_buffer(display->drm.wl_drm,1136image->base.fds[0], /* name */1137chain->extent.width,1138chain->extent.height,1139chain->drm_format,1140image->base.offsets[0],1141image->base.row_pitches[0],11420, 0, 0, 0 /* unused */);1143close(image->base.fds[0]);1144}11451146if (!image->buffer)1147goto fail_image;11481149wl_buffer_add_listener(image->buffer, &buffer_listener, image);11501151return VK_SUCCESS;11521153fail_image:1154wsi_destroy_image(&chain->base, &image->base);11551156return VK_ERROR_OUT_OF_HOST_MEMORY;1157}11581159static VkResult1160wsi_wl_swapchain_destroy(struct wsi_swapchain *wsi_chain,1161const VkAllocationCallbacks *pAllocator)1162{1163struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain;11641165for (uint32_t i = 0; i < chain->base.image_count; i++) {1166if (chain->images[i].buffer) {1167wl_buffer_destroy(chain->images[i].buffer);1168wsi_destroy_image(&chain->base, &chain->images[i].base);1169if (chain->images[i].data_ptr)1170munmap(chain->images[i].data_ptr, chain->images[i].data_size);1171}1172}11731174if (chain->frame)1175wl_callback_destroy(chain->frame);1176if (chain->surface)1177wl_proxy_wrapper_destroy(chain->surface);11781179if (chain->display)1180wsi_wl_display_unref(chain->display);11811182wsi_swapchain_finish(&chain->base);11831184vk_free(pAllocator, chain);11851186return VK_SUCCESS;1187}11881189static VkResult1190wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,1191VkDevice device,1192struct wsi_device *wsi_device,1193const VkSwapchainCreateInfoKHR* pCreateInfo,1194const VkAllocationCallbacks* pAllocator,1195struct wsi_swapchain **swapchain_out)1196{1197VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface;1198struct wsi_wayland *wsi =1199(struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND];1200struct wsi_wl_swapchain *chain;1201VkResult result;12021203assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);12041205int num_images = pCreateInfo->minImageCount;12061207size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]);1208chain = vk_alloc(pAllocator, size, 8,1209VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);1210if (chain == NULL)1211return VK_ERROR_OUT_OF_HOST_MEMORY;12121213result = wsi_swapchain_init(wsi_device, &chain->base, device,1214pCreateInfo, pAllocator);1215if (result != VK_SUCCESS) {1216vk_free(pAllocator, chain);1217return result;1218}12191220/* Mark a bunch of stuff as NULL. This way we can just call1221* destroy_swapchain for cleanup.1222*/1223for (uint32_t i = 0; i < num_images; i++) {1224chain->images[i].buffer = NULL;1225chain->images[i].data_ptr = NULL;1226}1227chain->surface = NULL;1228chain->frame = NULL;12291230bool alpha = pCreateInfo->compositeAlpha ==1231VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;12321233chain->base.destroy = wsi_wl_swapchain_destroy;1234chain->base.get_wsi_image = wsi_wl_swapchain_get_wsi_image;1235chain->base.acquire_next_image = wsi_wl_swapchain_acquire_next_image;1236chain->base.queue_present = wsi_wl_swapchain_queue_present;1237chain->base.present_mode = wsi_swapchain_get_present_mode(wsi_device, pCreateInfo);1238chain->base.image_count = num_images;1239chain->extent = pCreateInfo->imageExtent;1240chain->vk_format = pCreateInfo->imageFormat;1241if (wsi_device->sw)1242chain->shm_format = wl_shm_format_for_vk_format(chain->vk_format, alpha);1243else1244chain->drm_format = wl_drm_format_for_vk_format(chain->vk_format, alpha);12451246if (pCreateInfo->oldSwapchain) {1247/* If we have an oldSwapchain parameter, copy the display struct over1248* from the old one so we don't have to fully re-initialize it.1249*/1250VK_FROM_HANDLE(wsi_wl_swapchain, old_chain, pCreateInfo->oldSwapchain);1251chain->display = wsi_wl_display_ref(old_chain->display);1252} else {1253chain->display = NULL;1254result = wsi_wl_display_create(wsi, surface->display,1255wsi_device->sw, &chain->display);1256if (result != VK_SUCCESS)1257goto fail;1258}12591260chain->surface = wl_proxy_create_wrapper(surface->surface);1261if (!chain->surface) {1262result = VK_ERROR_OUT_OF_HOST_MEMORY;1263goto fail;1264}1265wl_proxy_set_queue((struct wl_proxy *) chain->surface,1266chain->display->queue);12671268chain->num_drm_modifiers = 0;1269chain->drm_modifiers = 0;12701271/* Use explicit DRM format modifiers when both the server and the driver1272* support them.1273*/1274if (chain->display->dmabuf.wl_dmabuf &&1275chain->base.wsi->supports_modifiers) {1276struct u_vector *modifiers;1277switch (chain->drm_format) {1278case WL_DRM_FORMAT_ARGB8888:1279modifiers = &chain->display->dmabuf.modifiers.argb8888;1280break;1281case WL_DRM_FORMAT_XRGB8888:1282modifiers = &chain->display->dmabuf.modifiers.xrgb8888;1283break;1284default:1285modifiers = NULL;1286break;1287}12881289if (modifiers) {1290chain->drm_modifiers = u_vector_tail(modifiers);1291chain->num_drm_modifiers = u_vector_length(modifiers);1292}1293}12941295chain->fifo_ready = true;12961297for (uint32_t i = 0; i < chain->base.image_count; i++) {1298result = wsi_wl_image_init(chain, &chain->images[i],1299pCreateInfo, pAllocator);1300if (result != VK_SUCCESS)1301goto fail;1302chain->images[i].busy = false;1303}13041305*swapchain_out = &chain->base;13061307return VK_SUCCESS;13081309fail:1310wsi_wl_swapchain_destroy(&chain->base, pAllocator);13111312return result;1313}13141315VkResult1316wsi_wl_init_wsi(struct wsi_device *wsi_device,1317const VkAllocationCallbacks *alloc,1318VkPhysicalDevice physical_device)1319{1320struct wsi_wayland *wsi;1321VkResult result;13221323wsi = vk_alloc(alloc, sizeof(*wsi), 8,1324VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);1325if (!wsi) {1326result = VK_ERROR_OUT_OF_HOST_MEMORY;1327goto fail;1328}13291330wsi->physical_device = physical_device;1331wsi->alloc = alloc;1332wsi->wsi = wsi_device;13331334wsi->base.get_support = wsi_wl_surface_get_support;1335wsi->base.get_capabilities2 = wsi_wl_surface_get_capabilities2;1336wsi->base.get_formats = wsi_wl_surface_get_formats;1337wsi->base.get_formats2 = wsi_wl_surface_get_formats2;1338wsi->base.get_present_modes = wsi_wl_surface_get_present_modes;1339wsi->base.get_present_rectangles = wsi_wl_surface_get_present_rectangles;1340wsi->base.create_swapchain = wsi_wl_surface_create_swapchain;13411342wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND] = &wsi->base;13431344return VK_SUCCESS;13451346fail:1347wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND] = NULL;13481349return result;1350}13511352void1353wsi_wl_finish_wsi(struct wsi_device *wsi_device,1354const VkAllocationCallbacks *alloc)1355{1356struct wsi_wayland *wsi =1357(struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND];1358if (!wsi)1359return;13601361vk_free(alloc, wsi);1362}136313641365