2 * Copyright (c) 2018-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
27 #include "util/platform_set.hpp"
29 #include <vulkan/vulkan.h>
30 #include <vulkan/vk_layer.h>
31 #include <vulkan/vk_icd.h>
34 #include <unordered_set>
38 using scoped_mutex = std::lock_guard<std::mutex>;
43 /* List of device entrypoints in the layer's instance dispatch table.
44 * Note that the Vulkan loader implements some of these entrypoints so the fact that these are non-null doesn't
45 * guarantee than we can safely call them. We still mark the entrypoints with REQUIRED() and OPTIONAL(). The layer
46 * fails if vkGetInstanceProcAddr returns null for entrypoints that are REQUIRED().
48 #define INSTANCE_ENTRYPOINTS_LIST(REQUIRED, OPTIONAL) \
49 REQUIRED(GetInstanceProcAddr) \
50 REQUIRED(DestroyInstance) \
51 REQUIRED(GetPhysicalDeviceProperties) \
52 REQUIRED(GetPhysicalDeviceImageFormatProperties) \
53 REQUIRED(EnumerateDeviceExtensionProperties) \
54 OPTIONAL(GetPhysicalDeviceSurfaceCapabilitiesKHR) \
55 OPTIONAL(GetPhysicalDeviceSurfaceFormatsKHR) \
56 OPTIONAL(GetPhysicalDeviceSurfacePresentModesKHR) \
57 OPTIONAL(GetPhysicalDeviceSurfaceSupportKHR)
59 struct instance_dispatch_table
61 VkResult populate(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc);
63 #define DISPATCH_TABLE_ENTRY(x) PFN_vk##x x{};
64 INSTANCE_ENTRYPOINTS_LIST(DISPATCH_TABLE_ENTRY, DISPATCH_TABLE_ENTRY)
65 #undef DISPATCH_TABLE_ENTRY
68 /* List of device entrypoints in the layer's device dispatch table.
69 * The layer fails initializing a device instance when entrypoints marked with REQUIRED() are retrieved as null.
70 * The layer will instead tolerate retrieving a null for entrypoints marked as OPTIONAL(). Code in the layer needs to
71 * check these entrypoints are non-null before calling them.
73 * Note that we cannot rely on checking whether the physical device supports a particular extension as the Vulkan
74 * loader currently aggregates all extensions advertised by all implicit layers (in their JSON manifests) and adds
75 * them automatically to the output of vkEnumeratePhysicalDeviceProperties.
77 #define DEVICE_ENTRYPOINTS_LIST(REQUIRED, OPTIONAL) \
78 REQUIRED(GetDeviceProcAddr) \
79 REQUIRED(GetDeviceQueue) \
80 REQUIRED(QueueSubmit) \
81 REQUIRED(QueueWaitIdle) \
82 REQUIRED(CreateCommandPool) \
83 REQUIRED(DestroyCommandPool) \
84 REQUIRED(AllocateCommandBuffers) \
85 REQUIRED(FreeCommandBuffers) \
86 REQUIRED(ResetCommandBuffer) \
87 REQUIRED(BeginCommandBuffer) \
88 REQUIRED(EndCommandBuffer) \
89 REQUIRED(CreateImage) \
90 REQUIRED(DestroyImage) \
91 REQUIRED(GetImageMemoryRequirements) \
92 REQUIRED(BindImageMemory) \
93 REQUIRED(AllocateMemory) \
94 REQUIRED(FreeMemory) \
95 REQUIRED(CreateFence) \
96 REQUIRED(DestroyFence) \
97 REQUIRED(ResetFences) \
98 REQUIRED(WaitForFences) \
99 OPTIONAL(CreateSwapchainKHR) \
100 OPTIONAL(DestroySwapchainKHR) \
101 OPTIONAL(GetSwapchainImagesKHR) \
102 OPTIONAL(AcquireNextImageKHR) \
103 OPTIONAL(QueuePresentKHR)
105 struct device_dispatch_table
107 VkResult populate(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc);
109 #define DISPATCH_TABLE_ENTRY(x) PFN_vk##x x{};
110 DEVICE_ENTRYPOINTS_LIST(DISPATCH_TABLE_ENTRY, DISPATCH_TABLE_ENTRY)
111 #undef DISPATCH_TABLE_ENTRY
115 * @brief Layer "mirror object" for VkInstance.
117 class instance_private_data
120 instance_private_data() = delete;
121 instance_private_data(const instance_private_data &) = delete;
122 instance_private_data &operator=(const instance_private_data &) = delete;
124 instance_private_data(const instance_dispatch_table& table,
125 PFN_vkSetInstanceLoaderData set_loader_data,
126 util::wsi_platform_set enabled_layer_platforms);
127 static void set(VkInstance inst, std::unique_ptr<instance_private_data> inst_data);
130 * @brief Get the mirror object that the layer associates to a given Vulkan instance.
132 static instance_private_data &get(VkInstance instance);
135 * @brief Get the layer instance object associated to the VkInstance owning the specified VkPhysicalDevice.
137 static instance_private_data &get(VkPhysicalDevice phys_dev);
140 * @brief Get the set of enabled platforms that are also supported by the layer.
142 const util::wsi_platform_set &get_enabled_platforms()
144 return enabled_layer_platforms;
148 * @brief Check whether a surface command should be handled by the WSI layer.
150 * @param phys_dev Physical device involved in the Vulkan command.
151 * @param surface The surface involved in the Vulkan command.
153 * @retval @c true if the layer should handle commands for the specified surface, which may mean returning an error
154 * if the layer does not support @p surface 's platform.
156 * @retval @c false if the layer should call down to the layers and ICDs below to handle the surface commands.
158 bool should_layer_handle_surface(VkPhysicalDevice phys_dev, VkSurfaceKHR surface);
161 * @brief Check whether the given surface is supported for presentation via the layer.
163 * @param surface A VK_KHR_surface surface.
165 * @return Whether the WSI layer supports this surface.
167 bool does_layer_support_surface(VkSurfaceKHR surface);
169 static void destroy(VkInstance inst);
171 const instance_dispatch_table disp;
175 * @brief Check whether the given surface is already supported for presentation without the layer.
177 bool do_icds_support_surface(VkPhysicalDevice phys_dev, VkSurfaceKHR surface);
179 const PFN_vkSetInstanceLoaderData SetInstanceLoaderData;
180 const util::wsi_platform_set enabled_layer_platforms;
183 class device_private_data
186 device_private_data() = delete;
187 device_private_data(const device_private_data &) = delete;
188 device_private_data &operator=(const device_private_data &) = delete;
190 device_private_data(instance_private_data &inst_data, VkPhysicalDevice phys_dev, VkDevice dev,
191 const device_dispatch_table &table, PFN_vkSetDeviceLoaderData set_loader_data);
192 static void set(VkDevice dev, std::unique_ptr<device_private_data> dev_data);
195 * @brief Get the mirror object that the layer associates to a given Vulkan device.
197 static device_private_data &get(VkDevice device);
200 * @brief Get the layer device object associated to the VkDevice owning the specified VkQueue.
202 static device_private_data &get(VkQueue queue);
204 void add_layer_swapchain(VkSwapchainKHR swapchain);
207 * @brief Return whether all the provided swapchains are owned by us (the WSI Layer).
209 bool layer_owns_all_swapchains(const VkSwapchainKHR *swapchain, uint32_t swapchain_count) const;
212 * @brief Check whether the given swapchain is owned by us (the WSI Layer).
214 bool layer_owns_swapchain(VkSwapchainKHR swapchain) const {
215 return layer_owns_all_swapchains(&swapchain, 1);
219 * @brief Check whether the layer can create a swapchain for the given surface.
221 bool should_layer_create_swapchain(VkSurfaceKHR vk_surface);
224 * @brief Check whether the ICDs or layers below support VK_KHR_swapchain.
226 bool can_icds_create_swapchain(VkSurfaceKHR vk_surface);
228 static void destroy(VkDevice dev);
230 const device_dispatch_table disp;
231 instance_private_data &instance_data;
232 const PFN_vkSetDeviceLoaderData SetDeviceLoaderData;
233 const VkPhysicalDevice physical_device;
234 const VkDevice device;
237 std::unordered_set<VkSwapchainKHR> swapchains;
238 mutable std::mutex swapchains_lock;
241 } /* namespace layer */