Implement WSI layer swapchain functions for Tizen:
[platform/core/uifw/vulkan-wsi-tizen.git] / wsi / wsi_factory.cpp
1 /*
2  * Copyright (c) 2019-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 /**
26  * @file
27  * @brief Implements factory methods for obtaining the specific surface and swapchain implementations.
28  */
29
30 #include "wsi_factory.hpp"
31
32 #include <cassert>
33 #include <cstdlib>
34 #include <cstring>
35 #include <new>
36
37 #include <vulkan/vk_icd.h>
38
39 #if BUILD_WSI_TIZEN
40 #include <vulkan/vulkan_wayland.h>
41 #include "tizen/surface_properties.hpp"
42 #include "tizen/swapchain.hpp"
43 #else
44 #include "headless/surface_properties.hpp"
45 #include "headless/swapchain.hpp"
46 #if BUILD_WSI_WAYLAND
47 #include <vulkan/vulkan_wayland.h>
48 #include "wayland/surface_properties.hpp"
49 #include "wayland/swapchain.hpp"
50 #endif
51 #endif
52
53 namespace wsi
54 {
55
56 static struct wsi_extension
57 {
58    VkExtensionProperties extension;
59    VkIcdWsiPlatform platform;
60 } const supported_wsi_extensions[] = {
61 #if BUILD_WSI_TIZEN
62    { { VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_SPEC_VERSION }, VK_ICD_WSI_PLATFORM_WAYLAND },
63 #else
64    { { VK_EXT_HEADLESS_SURFACE_EXTENSION_NAME, VK_EXT_HEADLESS_SURFACE_SPEC_VERSION }, VK_ICD_WSI_PLATFORM_HEADLESS },
65 #if BUILD_WSI_WAYLAND
66    { { VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, VK_KHR_WAYLAND_SURFACE_SPEC_VERSION }, VK_ICD_WSI_PLATFORM_WAYLAND },
67 #endif
68 #endif
69 };
70
71 static surface_properties *get_surface_properties(VkIcdWsiPlatform platform)
72 {
73    switch (platform)
74    {
75 #if BUILD_WSI_TIZEN
76    case VK_ICD_WSI_PLATFORM_WAYLAND:
77       return &tizen::surface_properties::get_instance();
78 #else
79    case VK_ICD_WSI_PLATFORM_HEADLESS:
80       return &headless::surface_properties::get_instance();
81 #if BUILD_WSI_WAYLAND
82    case VK_ICD_WSI_PLATFORM_WAYLAND:
83       return &wayland::surface_properties::get_instance();
84 #endif
85 #endif
86    default:
87       return nullptr;
88    }
89 }
90
91 surface_properties *get_surface_properties(VkSurfaceKHR surface)
92 {
93    VkIcdSurfaceBase *surface_base = reinterpret_cast<VkIcdSurfaceBase *>(surface);
94
95    return get_surface_properties(surface_base->platform);
96 }
97
98 template <typename swapchain_type>
99 static swapchain_base *allocate_swapchain(layer::device_private_data &dev_data, const VkAllocationCallbacks *pAllocator)
100 {
101    if (!pAllocator)
102    {
103       return new swapchain_type(dev_data, pAllocator);
104    }
105    void *memory = pAllocator->pfnAllocation(pAllocator->pUserData, sizeof(swapchain_type), alignof(swapchain_type),
106                                             VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
107    return new (memory) swapchain_type(dev_data, pAllocator);
108 }
109
110 swapchain_base *allocate_surface_swapchain(VkSurfaceKHR surface, layer::device_private_data &dev_data,
111                                            const VkAllocationCallbacks *pAllocator)
112 {
113    VkIcdSurfaceBase *surface_base = reinterpret_cast<VkIcdSurfaceBase *>(surface);
114
115    switch (surface_base->platform)
116    {
117 #if BUILD_WSI_TIZEN
118    case VK_ICD_WSI_PLATFORM_WAYLAND:
119                  return allocate_swapchain<wsi::tizen::swapchain>(dev_data, pAllocator);
120 #else
121    case VK_ICD_WSI_PLATFORM_HEADLESS:
122       return allocate_swapchain<wsi::headless::swapchain>(dev_data, pAllocator);
123 #if BUILD_WSI_WAYLAND
124    case VK_ICD_WSI_PLATFORM_WAYLAND:
125       return allocate_swapchain<wsi::wayland::swapchain>(dev_data, pAllocator);
126 #endif
127 #endif
128    default:
129       return nullptr;
130    }
131 }
132
133 util::wsi_platform_set find_enabled_layer_platforms(const VkInstanceCreateInfo *pCreateInfo)
134 {
135    util::wsi_platform_set ret;
136    for (const auto &ext_provided_by_layer : supported_wsi_extensions)
137    {
138       for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++)
139       {
140          const char* ext_requested_by_user = pCreateInfo->ppEnabledExtensionNames[i];
141          if (strcmp(ext_requested_by_user, ext_provided_by_layer.extension.extensionName) == 0)
142          {
143             ret.add(ext_provided_by_layer.platform);
144          }
145       }
146    }
147    return ret;
148 }
149
150 VkResult add_extensions_required_by_layer(VkPhysicalDevice phys_dev, const util::wsi_platform_set enabled_platforms,
151                                           util::extension_list &extensions_to_enable)
152 {
153 #if 0
154    util::allocator allocator{extensions_to_enable.get_allocator(), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND};
155    util::extension_list device_extensions{allocator};
156    VkResult res = device_extensions.add(phys_dev);
157    if (res != VK_SUCCESS)
158    {
159       return res;
160    }
161 #else
162    VkResult res;
163 #endif
164    for (const auto &wsi_ext : supported_wsi_extensions)
165    {
166       /* Skip iterating over platforms not enabled in the instance. */
167       if (!enabled_platforms.contains(wsi_ext.platform))
168       {
169          continue;
170       }
171
172       surface_properties *props = get_surface_properties(wsi_ext.platform);
173       const auto &extensions_required_by_layer = props->get_required_device_extensions();
174 #if 0
175       bool supported = device_extensions.contains(extensions_required_by_layer);
176       if (!supported)
177       {
178          /* Can we accept failure? The layer unconditionally advertises support for this platform and the loader uses
179           * this information to enable its own support of the vkCreate*SurfaceKHR entrypoints. The rest of the Vulkan
180           * stack may not support this extension so we cannot blindly fall back to it.
181           * For now treat this as an error.
182           */
183          return VK_ERROR_INITIALIZATION_FAILED;
184       }
185 #endif
186
187       res = extensions_to_enable.add(extensions_required_by_layer);
188       if (res != VK_SUCCESS)
189       {
190          return res;
191       }
192    }
193    return VK_SUCCESS;
194 }
195
196 void destroy_surface_swapchain(swapchain_base *swapchain, const VkAllocationCallbacks *pAllocator)
197 {
198    assert(swapchain);
199
200    if (!pAllocator)
201    {
202       delete swapchain;
203    }
204    else
205    {
206       swapchain->~swapchain_base();
207       pAllocator->pfnFree(pAllocator->pUserData, reinterpret_cast<void *>(swapchain));
208    }
209 }
210
211 PFN_vkVoidFunction get_proc_addr(const char *name)
212 {
213    /*
214     * Note that we here assume that there are no two get_proc_addr implementations
215     * that handle the same function name.
216     */
217    for (const auto &wsi_ext : supported_wsi_extensions)
218    {
219       PFN_vkVoidFunction func = get_surface_properties(wsi_ext.platform)->get_proc_addr(name);
220       if (func)
221       {
222          return func;
223       }
224    }
225    return nullptr;
226 }
227
228 } // namespace wsi