• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "dawn_native/vulkan/VulkanExtensions.h"
16 
17 #include "common/Assert.h"
18 #include "common/vulkan_platform.h"
19 
20 #include <array>
21 #include <limits>
22 
23 namespace dawn_native { namespace vulkan {
24 
25     static constexpr uint32_t VulkanVersion_1_1 = VK_MAKE_VERSION(1, 1, 0);
26     static constexpr uint32_t VulkanVersion_1_2 = VK_MAKE_VERSION(1, 2, 0);
27     static constexpr uint32_t NeverPromoted = std::numeric_limits<uint32_t>::max();
28 
29     // A static array for InstanceExtInfo that can be indexed with InstanceExts.
30     // GetInstanceExtInfo checks that "index" matches the index used to access this array so an
31     // assert will fire if it isn't in the correct order.
32     static constexpr size_t kInstanceExtCount = static_cast<size_t>(InstanceExt::EnumCount);
33     static constexpr std::array<InstanceExtInfo, kInstanceExtCount> sInstanceExtInfos{{
34         //
35         {InstanceExt::GetPhysicalDeviceProperties2, "VK_KHR_get_physical_device_properties2",
36          VulkanVersion_1_1},
37         {InstanceExt::ExternalMemoryCapabilities, "VK_KHR_external_memory_capabilities",
38          VulkanVersion_1_1},
39         {InstanceExt::ExternalSemaphoreCapabilities, "VK_KHR_external_semaphore_capabilities",
40          VulkanVersion_1_1},
41 
42         {InstanceExt::Surface, "VK_KHR_surface", NeverPromoted},
43         {InstanceExt::FuchsiaImagePipeSurface, "VK_FUCHSIA_imagepipe_surface", NeverPromoted},
44         {InstanceExt::MetalSurface, "VK_EXT_metal_surface", NeverPromoted},
45         {InstanceExt::WaylandSurface, "VK_KHR_wayland_surface", NeverPromoted},
46         {InstanceExt::Win32Surface, "VK_KHR_win32_surface", NeverPromoted},
47         {InstanceExt::XcbSurface, "VK_KHR_xcb_surface", NeverPromoted},
48         {InstanceExt::XlibSurface, "VK_KHR_xlib_surface", NeverPromoted},
49 
50         {InstanceExt::DebugUtils, "VK_EXT_debug_utils", NeverPromoted},
51         {InstanceExt::ValidationFeatures, "VK_EXT_validation_features", NeverPromoted},
52         //
53     }};
54 
GetInstanceExtInfo(InstanceExt ext)55     const InstanceExtInfo& GetInstanceExtInfo(InstanceExt ext) {
56         uint32_t index = static_cast<uint32_t>(ext);
57         ASSERT(index < sInstanceExtInfos.size());
58         ASSERT(sInstanceExtInfos[index].index == ext);
59         return sInstanceExtInfos[index];
60     }
61 
CreateInstanceExtNameMap()62     std::unordered_map<std::string, InstanceExt> CreateInstanceExtNameMap() {
63         std::unordered_map<std::string, InstanceExt> result;
64         for (const InstanceExtInfo& info : sInstanceExtInfos) {
65             result[info.name] = info.index;
66         }
67         return result;
68     }
69 
EnsureDependencies(const InstanceExtSet & advertisedExts)70     InstanceExtSet EnsureDependencies(const InstanceExtSet& advertisedExts) {
71         // We need to check that all transitive dependencies of extensions are advertised.
72         // To do that in a single pass and no data structures, the extensions are topologically
73         // sorted in the definition of InstanceExt.
74         // To ensure the order is correct, we mark visited extensions in `visitedSet` and each
75         // dependency check will first assert all its dependents have been visited.
76         InstanceExtSet visitedSet;
77         InstanceExtSet trimmedSet;
78 
79         auto HasDep = [&](InstanceExt ext) -> bool {
80             ASSERT(visitedSet[ext]);
81             return trimmedSet[ext];
82         };
83 
84         for (uint32_t i = 0; i < sInstanceExtInfos.size(); i++) {
85             InstanceExt ext = static_cast<InstanceExt>(i);
86 
87             bool hasDependencies = false;
88             switch (ext) {
89                 case InstanceExt::GetPhysicalDeviceProperties2:
90                 case InstanceExt::Surface:
91                 case InstanceExt::DebugUtils:
92                 case InstanceExt::ValidationFeatures:
93                     hasDependencies = true;
94                     break;
95 
96                 case InstanceExt::ExternalMemoryCapabilities:
97                 case InstanceExt::ExternalSemaphoreCapabilities:
98                     hasDependencies = HasDep(InstanceExt::GetPhysicalDeviceProperties2);
99                     break;
100 
101                 case InstanceExt::FuchsiaImagePipeSurface:
102                 case InstanceExt::MetalSurface:
103                 case InstanceExt::WaylandSurface:
104                 case InstanceExt::Win32Surface:
105                 case InstanceExt::XcbSurface:
106                 case InstanceExt::XlibSurface:
107                     hasDependencies = HasDep(InstanceExt::Surface);
108                     break;
109 
110                 case InstanceExt::EnumCount:
111                     UNREACHABLE();
112             }
113 
114             trimmedSet.set(ext, hasDependencies && advertisedExts[ext]);
115             visitedSet.set(ext, true);
116         }
117 
118         return trimmedSet;
119     }
120 
MarkPromotedExtensions(InstanceExtSet * extensions,uint32_t version)121     void MarkPromotedExtensions(InstanceExtSet* extensions, uint32_t version) {
122         for (const InstanceExtInfo& info : sInstanceExtInfos) {
123             if (info.versionPromoted <= version) {
124                 extensions->set(info.index, true);
125             }
126         }
127     }
128 
129     static constexpr size_t kDeviceExtCount = static_cast<size_t>(DeviceExt::EnumCount);
130     static constexpr std::array<DeviceExtInfo, kDeviceExtCount> sDeviceExtInfos{{
131         //
132         {DeviceExt::BindMemory2, "VK_KHR_bind_memory2", VulkanVersion_1_1},
133         {DeviceExt::Maintenance1, "VK_KHR_maintenance1", VulkanVersion_1_1},
134         {DeviceExt::StorageBufferStorageClass, "VK_KHR_storage_buffer_storage_class",
135          VulkanVersion_1_1},
136         {DeviceExt::GetPhysicalDeviceProperties2, "VK_KHR_get_physical_device_properties2",
137          VulkanVersion_1_1},
138         {DeviceExt::GetMemoryRequirements2, "VK_KHR_get_memory_requirements2", VulkanVersion_1_1},
139         {DeviceExt::ExternalMemoryCapabilities, "VK_KHR_external_memory_capabilities",
140          VulkanVersion_1_1},
141         {DeviceExt::ExternalSemaphoreCapabilities, "VK_KHR_external_semaphore_capabilities",
142          VulkanVersion_1_1},
143         {DeviceExt::ExternalMemory, "VK_KHR_external_memory", VulkanVersion_1_1},
144         {DeviceExt::ExternalSemaphore, "VK_KHR_external_semaphore", VulkanVersion_1_1},
145         {DeviceExt::_16BitStorage, "VK_KHR_16bit_storage", VulkanVersion_1_1},
146         {DeviceExt::SamplerYCbCrConversion, "VK_KHR_sampler_ycbcr_conversion", VulkanVersion_1_1},
147 
148         {DeviceExt::DriverProperties, "VK_KHR_driver_properties", VulkanVersion_1_2},
149         {DeviceExt::ImageFormatList, "VK_KHR_image_format_list", VulkanVersion_1_2},
150         {DeviceExt::ShaderFloat16Int8, "VK_KHR_shader_float16_int8", VulkanVersion_1_2},
151 
152         {DeviceExt::ExternalMemoryFD, "VK_KHR_external_memory_fd", NeverPromoted},
153         {DeviceExt::ExternalMemoryDmaBuf, "VK_EXT_external_memory_dma_buf", NeverPromoted},
154         {DeviceExt::ExternalMemoryZirconHandle, "VK_FUCHSIA_external_memory", NeverPromoted},
155         {DeviceExt::ExternalSemaphoreFD, "VK_KHR_external_semaphore_fd", NeverPromoted},
156         {DeviceExt::ExternalSemaphoreZirconHandle, "VK_FUCHSIA_external_semaphore", NeverPromoted},
157 
158         {DeviceExt::ImageDrmFormatModifier, "VK_EXT_image_drm_format_modifier", NeverPromoted},
159         {DeviceExt::Swapchain, "VK_KHR_swapchain", NeverPromoted},
160         {DeviceExt::SubgroupSizeControl, "VK_EXT_subgroup_size_control", NeverPromoted},
161         //
162     }};
163 
GetDeviceExtInfo(DeviceExt ext)164     const DeviceExtInfo& GetDeviceExtInfo(DeviceExt ext) {
165         uint32_t index = static_cast<uint32_t>(ext);
166         ASSERT(index < sDeviceExtInfos.size());
167         ASSERT(sDeviceExtInfos[index].index == ext);
168         return sDeviceExtInfos[index];
169     }
170 
CreateDeviceExtNameMap()171     std::unordered_map<std::string, DeviceExt> CreateDeviceExtNameMap() {
172         std::unordered_map<std::string, DeviceExt> result;
173         for (const DeviceExtInfo& info : sDeviceExtInfos) {
174             result[info.name] = info.index;
175         }
176         return result;
177     }
178 
EnsureDependencies(const DeviceExtSet & advertisedExts,const InstanceExtSet & instanceExts,uint32_t icdVersion)179     DeviceExtSet EnsureDependencies(const DeviceExtSet& advertisedExts,
180                                     const InstanceExtSet& instanceExts,
181                                     uint32_t icdVersion) {
182         // This is very similar to EnsureDependencies for instanceExtSet. See comment there for
183         // an explanation of what happens.
184         DeviceExtSet visitedSet;
185         DeviceExtSet trimmedSet;
186 
187         auto HasDep = [&](DeviceExt ext) -> bool {
188             ASSERT(visitedSet[ext]);
189             return trimmedSet[ext];
190         };
191 
192         for (uint32_t i = 0; i < sDeviceExtInfos.size(); i++) {
193             DeviceExt ext = static_cast<DeviceExt>(i);
194 
195             bool hasDependencies = false;
196             switch (ext) {
197                 // Happy extensions don't need anybody else!
198                 case DeviceExt::BindMemory2:
199                 case DeviceExt::GetMemoryRequirements2:
200                 case DeviceExt::Maintenance1:
201                 case DeviceExt::ImageFormatList:
202                 case DeviceExt::StorageBufferStorageClass:
203                     hasDependencies = true;
204                     break;
205 
206                 // Physical device extensions technically don't require the instance to support
207                 // them but VulkanFunctions only loads the function pointers if the instance
208                 // advertises the extension. So if we didn't have this check, we'd risk a calling
209                 // a nullptr.
210                 case DeviceExt::GetPhysicalDeviceProperties2:
211                     hasDependencies = instanceExts[InstanceExt::GetPhysicalDeviceProperties2];
212                     break;
213                 case DeviceExt::ExternalMemoryCapabilities:
214                     hasDependencies = instanceExts[InstanceExt::ExternalMemoryCapabilities] &&
215                                       HasDep(DeviceExt::GetPhysicalDeviceProperties2);
216                     break;
217                 case DeviceExt::ExternalSemaphoreCapabilities:
218                     hasDependencies = instanceExts[InstanceExt::ExternalSemaphoreCapabilities] &&
219                                       HasDep(DeviceExt::GetPhysicalDeviceProperties2);
220                     break;
221 
222                 case DeviceExt::ImageDrmFormatModifier:
223                     hasDependencies = HasDep(DeviceExt::BindMemory2) &&
224                                       HasDep(DeviceExt::GetPhysicalDeviceProperties2) &&
225                                       HasDep(DeviceExt::ImageFormatList) &&
226                                       HasDep(DeviceExt::SamplerYCbCrConversion);
227                     break;
228 
229                 case DeviceExt::Swapchain:
230                     hasDependencies = instanceExts[InstanceExt::Surface];
231                     break;
232 
233                 case DeviceExt::SamplerYCbCrConversion:
234                     hasDependencies = HasDep(DeviceExt::Maintenance1) &&
235                                       HasDep(DeviceExt::BindMemory2) &&
236                                       HasDep(DeviceExt::GetMemoryRequirements2) &&
237                                       HasDep(DeviceExt::GetPhysicalDeviceProperties2);
238                     break;
239 
240                 case DeviceExt::DriverProperties:
241                 case DeviceExt::ShaderFloat16Int8:
242                     hasDependencies = HasDep(DeviceExt::GetPhysicalDeviceProperties2);
243                     break;
244 
245                 case DeviceExt::ExternalMemory:
246                     hasDependencies = HasDep(DeviceExt::ExternalMemoryCapabilities);
247                     break;
248 
249                 case DeviceExt::ExternalSemaphore:
250                     hasDependencies = HasDep(DeviceExt::ExternalSemaphoreCapabilities);
251                     break;
252 
253                 case DeviceExt::ExternalMemoryFD:
254                 case DeviceExt::ExternalMemoryZirconHandle:
255                     hasDependencies = HasDep(DeviceExt::ExternalMemory);
256                     break;
257 
258                 case DeviceExt::ExternalMemoryDmaBuf:
259                     hasDependencies = HasDep(DeviceExt::ExternalMemoryFD);
260                     break;
261 
262                 case DeviceExt::ExternalSemaphoreFD:
263                 case DeviceExt::ExternalSemaphoreZirconHandle:
264                     hasDependencies = HasDep(DeviceExt::ExternalSemaphore);
265                     break;
266 
267                 case DeviceExt::_16BitStorage:
268                     hasDependencies = HasDep(DeviceExt::GetPhysicalDeviceProperties2) &&
269                                       HasDep(DeviceExt::StorageBufferStorageClass);
270                     break;
271 
272                 case DeviceExt::SubgroupSizeControl:
273                     // Using the extension requires DeviceExt::GetPhysicalDeviceProperties2, but we
274                     // don't need to check for it as it also requires Vulkan 1.1 in which
275                     // VK_KHR_get_physical_device_properties2 was promoted.
276                     hasDependencies = icdVersion >= VulkanVersion_1_1;
277                     break;
278 
279                 case DeviceExt::EnumCount:
280                     UNREACHABLE();
281             }
282 
283             trimmedSet.set(ext, hasDependencies && advertisedExts[ext]);
284             visitedSet.set(ext, true);
285         }
286 
287         return trimmedSet;
288     }
289 
MarkPromotedExtensions(DeviceExtSet * extensions,uint32_t version)290     void MarkPromotedExtensions(DeviceExtSet* extensions, uint32_t version) {
291         for (const DeviceExtInfo& info : sDeviceExtInfos) {
292             if (info.versionPromoted <= version) {
293                 extensions->set(info.index, true);
294             }
295         }
296     }
297 
298     // A static array for VulkanLayerInfo that can be indexed with VulkanLayers.
299     // GetVulkanLayerInfo checks that "index" matches the index used to access this array so an
300     // assert will fire if it isn't in the correct order.
301     static constexpr size_t kVulkanLayerCount = static_cast<size_t>(VulkanLayer::EnumCount);
302     static constexpr std::array<VulkanLayerInfo, kVulkanLayerCount> sVulkanLayerInfos{{
303         //
304         {VulkanLayer::Validation, "VK_LAYER_KHRONOS_validation"},
305         {VulkanLayer::LunargVkTrace, "VK_LAYER_LUNARG_vktrace"},
306         {VulkanLayer::RenderDocCapture, "VK_LAYER_RENDERDOC_Capture"},
307         {VulkanLayer::FuchsiaImagePipeSwapchain, "VK_LAYER_FUCHSIA_imagepipe_swapchain"},
308         //
309     }};
310 
GetVulkanLayerInfo(VulkanLayer layer)311     const VulkanLayerInfo& GetVulkanLayerInfo(VulkanLayer layer) {
312         uint32_t index = static_cast<uint32_t>(layer);
313         ASSERT(index < sVulkanLayerInfos.size());
314         ASSERT(sVulkanLayerInfos[index].layer == layer);
315         return sVulkanLayerInfos[index];
316     }
317 
CreateVulkanLayerNameMap()318     std::unordered_map<std::string, VulkanLayer> CreateVulkanLayerNameMap() {
319         std::unordered_map<std::string, VulkanLayer> result;
320         for (const VulkanLayerInfo& info : sVulkanLayerInfos) {
321             result[info.name] = info.layer;
322         }
323         return result;
324     }
325 
326 }}  // namespace dawn_native::vulkan
327