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