Fix formatting issues
[platform/core/uifw/vulkan-wsi-tizen.git] / wsi / wayland / surface.cpp
1 /*
2  * Copyright (c) 2021 Arm Limited.
3  *
4  * SPDX-License-Identifier: MIT
5  *
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:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
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
22  * SOFTWARE.
23  */
24
25 /** @file
26  * @brief Implementation of a Wayland WSI Surface
27  */
28
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"
35
36 namespace wsi
37 {
38 namespace wayland
39 {
40
41 struct formats_vector
42 {
43    util::vector<drm_format_pair> *formats{nullptr};
44    bool is_out_of_memory{false};
45 };
46
47 namespace
48 {
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)
51 {
52 }
53
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)
57 {
58    auto *drm_supported_formats = reinterpret_cast<formats_vector *>(data);
59
60    drm_format_pair format = {};
61    format.fourcc = drm_format;
62    format.modifier = (static_cast<uint64_t>(modifier_hi) << 32) | modifier_low;
63
64    if (!drm_supported_formats->is_out_of_memory)
65    {
66       drm_supported_formats->is_out_of_memory = !drm_supported_formats->formats->try_push_back(format);
67    }
68 }
69 } // namespace
70
71 /*
72  * @brief Get supported formats and modifiers using the zwp_linux_dmabuf_v1 interface.
73  *
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.
79  *
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.
83  */
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)
87 {
88    formats_vector drm_supported_formats;
89    drm_supported_formats.formats = &supported_formats;
90
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,
94    };
95    int res = zwp_linux_dmabuf_v1_add_listener(dmabuf_interface, &dma_buf_listener, &drm_supported_formats);
96    if (res < 0)
97    {
98       WSI_LOG_ERROR("Failed to add zwp_linux_dmabuf_v1 listener.");
99       return VK_ERROR_UNKNOWN;
100    }
101
102    /* Get all modifier events. */
103    res = wl_display_roundtrip_queue(display, queue);
104    if (res < 0)
105    {
106       WSI_LOG_ERROR("Roundtrip failed.");
107       return VK_ERROR_UNKNOWN;
108    }
109
110    if (drm_supported_formats.is_out_of_memory)
111    {
112       WSI_LOG_ERROR("Host got out of memory.");
113       return VK_ERROR_OUT_OF_HOST_MEMORY;
114    }
115
116    return VK_SUCCESS;
117 }
118
119 struct surface::init_parameters
120 {
121    const util::allocator& allocator;
122    wl_display *display;
123    wl_surface *surf;
124 };
125
126 surface::surface(const init_parameters &params)
127    : wsi::surface()
128    , wayland_display(params.display)
129    , wayland_surface(params.surf)
130    , supported_formats(params.allocator)
131    , properties(*this, params.allocator)
132    , surface_queue(nullptr)
133 {
134 }
135
136 void surface_registry_handler(void *data, struct wl_registry *wl_registry, uint32_t name, const char *interface,
137                               uint32_t version)
138 {
139    auto wsi_surface = reinterpret_cast<wsi::wayland::surface *>(data);
140
141    if (!strcmp(interface, zwp_linux_dmabuf_v1_interface.name) && version >= ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION)
142    {
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));
145
146       if (dmabuf_interface_obj == nullptr)
147       {
148          WSI_LOG_ERROR("Failed to get zwp_linux_dmabuf_v1 interface.");
149          return;
150       }
151
152       wsi_surface->dmabuf_interface.reset(dmabuf_interface_obj);
153    }
154    else if (!strcmp(interface, zwp_linux_explicit_synchronization_v1_interface.name))
155    {
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));
159
160       if (explicit_sync_interface_obj == nullptr)
161       {
162          WSI_LOG_ERROR("Failed to get zwp_linux_explicit_synchronization_v1 interface.");
163          return;
164       }
165
166       wsi_surface->explicit_sync_interface.reset(explicit_sync_interface_obj);
167    }
168 }
169
170 bool surface::init()
171 {
172    surface_queue = wl_display_create_queue(wayland_display);
173
174    if (surface_queue == nullptr)
175    {
176       WSI_LOG_ERROR("Failed to create wl surface queue.");
177       return false;
178    }
179
180    auto display_proxy = make_proxy_with_queue(wayland_display, surface_queue);
181    if (display_proxy == nullptr)
182    {
183       WSI_LOG_ERROR("Failed to create wl display proxy.");
184       return false;
185    };
186
187    auto registry = wayland_owner<wl_registry>{ wl_display_get_registry(display_proxy.get()) };
188    if (registry == nullptr)
189    {
190       WSI_LOG_ERROR("Failed to get wl display registry.");
191       return false;
192    }
193
194    const wl_registry_listener registry_listener = { surface_registry_handler };
195    int res = wl_registry_add_listener(registry.get(), &registry_listener, this);
196    if (res < 0)
197    {
198       WSI_LOG_ERROR("Failed to add registry listener.");
199       return false;
200    }
201
202    res = wl_display_roundtrip_queue(wayland_display, surface_queue);
203    if (res < 0)
204    {
205       WSI_LOG_ERROR("Roundtrip failed.");
206       return false;
207    }
208
209    if (dmabuf_interface.get() == nullptr)
210    {
211       WSI_LOG_ERROR("Failed to obtain zwp_linux_dma_buf_v1 interface.");
212       return false;
213    }
214
215    if (explicit_sync_interface.get() == nullptr)
216    {
217       WSI_LOG_ERROR("Failed to obtain zwp_linux_explicit_synchronization_v1 interface.");
218       return false;
219    }
220
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)
224    {
225       WSI_LOG_ERROR("Failed to retrieve surface synchronization interface");
226       return false;
227    }
228
229    surface_sync_interface.reset(surface_sync_obj);
230
231    VkResult vk_res =
232       get_supported_formats_and_modifiers(wayland_display, surface_queue, dmabuf_interface.get(), supported_formats);
233    if (vk_res != VK_SUCCESS)
234    {
235       return false;
236    }
237
238    return true;
239 }
240
241 util::unique_ptr<surface> surface::make_surface(const util::allocator &allocator, wl_display *display,
242                                                 wl_surface *surf)
243 {
244    init_parameters params {allocator, display, surf};
245    auto wsi_surface = allocator.make_unique<surface>(params);
246    if (wsi_surface != nullptr)
247    {
248       if (wsi_surface->init())
249       {
250          return wsi_surface;
251       }
252    }
253    return nullptr;
254 }
255
256 surface::~surface()
257 {
258    if (surface_queue != nullptr)
259    {
260       wl_event_queue_destroy(surface_queue);
261    }
262 }
263
264 wsi::surface_properties &surface::get_properties()
265 {
266    return properties;
267 }
268
269 util::unique_ptr<swapchain_base> surface::allocate_swapchain(layer::device_private_data &dev_data,
270                                                              const VkAllocationCallbacks *allocator)
271 {
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));
274 }
275
276 } // namespace wayland
277 } // namespace wsi