2 * Copyright (c) 2021 Arm Limited.
4 * SPDX-License-Identifier: MIT
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * @brief Implementation of a Wayland WSI Surface
29 #include "surface.hpp"
30 #include "swapchain.hpp"
31 #include "surface_properties.hpp"
32 #include "wl_object_owner.hpp"
33 #include "wl_helpers.hpp"
34 #include "util/log.hpp"
43 util::vector<drm_format_pair> *formats{nullptr};
44 bool is_out_of_memory{false};
49 /* Handler for format event of the zwp_linux_dmabuf_v1 interface. */
50 extern "C" void zwp_linux_dmabuf_v1_format_impl(void *data, struct zwp_linux_dmabuf_v1 *dma_buf, uint32_t drm_format)
54 /* Handler for modifier event of the zwp_linux_dmabuf_v1 interface. */
55 extern "C" void zwp_linux_dmabuf_v1_modifier_impl(void *data, struct zwp_linux_dmabuf_v1 *dma_buf, uint32_t drm_format,
56 uint32_t modifier_hi, uint32_t modifier_low)
58 auto *drm_supported_formats = reinterpret_cast<formats_vector *>(data);
60 drm_format_pair format = {};
61 format.fourcc = drm_format;
62 format.modifier = (static_cast<uint64_t>(modifier_hi) << 32) | modifier_low;
64 if (!drm_supported_formats->is_out_of_memory)
66 drm_supported_formats->is_out_of_memory = !drm_supported_formats->formats->try_push_back(format);
72 * @brief Get supported formats and modifiers using the zwp_linux_dmabuf_v1 interface.
74 * @param[in] display The wl_display that is being used.
75 * @param[in] queue The wl_event_queue set for the @p dmabuf_interface
76 * @param[in] dmabuf_interface Object of the zwp_linux_dmabuf_v1 interface.
77 * @param[out] supported_formats Vector which will contain the supported drm
78 * formats and their modifiers.
80 * @retval VK_SUCCESS Indicates success.
81 * @retval VK_ERROR_UNKNOWN Indicates one of the Wayland functions failed.
82 * @retval VK_ERROR_OUT_OF_DEVICE_MEMORY Indicates the host went out of memory.
84 static VkResult get_supported_formats_and_modifiers(wl_display *display, wl_event_queue *queue,
85 zwp_linux_dmabuf_v1 *dmabuf_interface,
86 util::vector<drm_format_pair> &supported_formats)
88 formats_vector drm_supported_formats;
89 drm_supported_formats.formats = &supported_formats;
91 const zwp_linux_dmabuf_v1_listener dma_buf_listener = {
92 .format = zwp_linux_dmabuf_v1_format_impl,
93 .modifier = zwp_linux_dmabuf_v1_modifier_impl,
95 int res = zwp_linux_dmabuf_v1_add_listener(dmabuf_interface, &dma_buf_listener, &drm_supported_formats);
98 WSI_LOG_ERROR("Failed to add zwp_linux_dmabuf_v1 listener.");
99 return VK_ERROR_UNKNOWN;
102 /* Get all modifier events. */
103 res = wl_display_roundtrip_queue(display, queue);
106 WSI_LOG_ERROR("Roundtrip failed.");
107 return VK_ERROR_UNKNOWN;
110 if (drm_supported_formats.is_out_of_memory)
112 WSI_LOG_ERROR("Host got out of memory.");
113 return VK_ERROR_OUT_OF_HOST_MEMORY;
119 struct surface::init_parameters
121 const util::allocator& allocator;
126 surface::surface(const init_parameters ¶ms)
128 , wayland_display(params.display)
129 , wayland_surface(params.surf)
130 , supported_formats(params.allocator)
131 , properties(*this, params.allocator)
132 , surface_queue(nullptr)
136 void surface_registry_handler(void *data, struct wl_registry *wl_registry, uint32_t name, const char *interface,
139 auto wsi_surface = reinterpret_cast<wsi::wayland::surface *>(data);
141 if (!strcmp(interface, zwp_linux_dmabuf_v1_interface.name) && version >= ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION)
143 zwp_linux_dmabuf_v1 *dmabuf_interface_obj = reinterpret_cast<zwp_linux_dmabuf_v1 *>(wl_registry_bind(
144 wl_registry, name, &zwp_linux_dmabuf_v1_interface, ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION));
146 if (dmabuf_interface_obj == nullptr)
148 WSI_LOG_ERROR("Failed to get zwp_linux_dmabuf_v1 interface.");
152 wsi_surface->dmabuf_interface.reset(dmabuf_interface_obj);
154 else if (!strcmp(interface, zwp_linux_explicit_synchronization_v1_interface.name))
156 zwp_linux_explicit_synchronization_v1 *explicit_sync_interface_obj =
157 reinterpret_cast<zwp_linux_explicit_synchronization_v1 *>(
158 wl_registry_bind(wl_registry, name, &zwp_linux_explicit_synchronization_v1_interface, 1));
160 if (explicit_sync_interface_obj == nullptr)
162 WSI_LOG_ERROR("Failed to get zwp_linux_explicit_synchronization_v1 interface.");
166 wsi_surface->explicit_sync_interface.reset(explicit_sync_interface_obj);
172 surface_queue = wl_display_create_queue(wayland_display);
174 if (surface_queue == nullptr)
176 WSI_LOG_ERROR("Failed to create wl surface queue.");
180 auto display_proxy = make_proxy_with_queue(wayland_display, surface_queue);
181 if (display_proxy == nullptr)
183 WSI_LOG_ERROR("Failed to create wl display proxy.");
187 auto registry = wayland_owner<wl_registry>{ wl_display_get_registry(display_proxy.get()) };
188 if (registry == nullptr)
190 WSI_LOG_ERROR("Failed to get wl display registry.");
194 const wl_registry_listener registry_listener = { surface_registry_handler };
195 int res = wl_registry_add_listener(registry.get(), ®istry_listener, this);
198 WSI_LOG_ERROR("Failed to add registry listener.");
202 res = wl_display_roundtrip_queue(wayland_display, surface_queue);
205 WSI_LOG_ERROR("Roundtrip failed.");
209 if (dmabuf_interface.get() == nullptr)
211 WSI_LOG_ERROR("Failed to obtain zwp_linux_dma_buf_v1 interface.");
215 if (explicit_sync_interface.get() == nullptr)
217 WSI_LOG_ERROR("Failed to obtain zwp_linux_explicit_synchronization_v1 interface.");
221 auto surface_sync_obj =
222 zwp_linux_explicit_synchronization_v1_get_synchronization(explicit_sync_interface.get(), wayland_surface);
223 if (surface_sync_obj == nullptr)
225 WSI_LOG_ERROR("Failed to retrieve surface synchronization interface");
229 surface_sync_interface.reset(surface_sync_obj);
232 get_supported_formats_and_modifiers(wayland_display, surface_queue, dmabuf_interface.get(), supported_formats);
233 if (vk_res != VK_SUCCESS)
241 util::unique_ptr<surface> surface::make_surface(const util::allocator &allocator, wl_display *display,
244 init_parameters params {allocator, display, surf};
245 auto wsi_surface = allocator.make_unique<surface>(params);
246 if (wsi_surface != nullptr)
248 if (wsi_surface->init())
258 if (surface_queue != nullptr)
260 wl_event_queue_destroy(surface_queue);
264 wsi::surface_properties &surface::get_properties()
269 util::unique_ptr<swapchain_base> surface::allocate_swapchain(layer::device_private_data &dev_data,
270 const VkAllocationCallbacks *allocator)
272 util::allocator alloc{ dev_data.get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT, allocator };
273 return util::unique_ptr<swapchain_base>(alloc.make_unique<swapchain>(dev_data, allocator, *this));
276 } // namespace wayland