1 /*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "include/gpu/vk/VulkanExtensions.h"
9
10 #include "include/private/base/SkAssert.h"
11 #include "src/base/SkTSearch.h"
12 #include "src/base/SkTSort.h"
13
14 #include <utility>
15
16 using namespace skia_private;
17
18 namespace skgpu {
19
20 // finds the index of ext in infos or a negative result if ext is not found.
find_info(const TArray<VulkanExtensions::Info> & infos,const char ext[])21 static int find_info(const TArray<VulkanExtensions::Info>& infos, const char ext[]) {
22 if (infos.empty()) {
23 return -1;
24 }
25 SkString extensionStr(ext);
26 VulkanExtensions::Info::Less less;
27 int idx = SkTSearch<VulkanExtensions::Info, SkString, VulkanExtensions::Info::Less>(
28 &infos.front(), infos.size(), extensionStr, sizeof(VulkanExtensions::Info),
29 less);
30 return idx;
31 }
32
33 namespace { // This cannot be static because it is used as a template parameter.
extension_compare(const VulkanExtensions::Info & a,const VulkanExtensions::Info & b)34 inline bool extension_compare(const VulkanExtensions::Info& a, const VulkanExtensions::Info& b) {
35 return strcmp(a.fName.c_str(), b.fName.c_str()) < 0;
36 }
37 } // namespace
38
init(VulkanGetProc getProc,VkInstance instance,VkPhysicalDevice physDev,uint32_t instanceExtensionCount,const char * const * instanceExtensions,uint32_t deviceExtensionCount,const char * const * deviceExtensions)39 void VulkanExtensions::init(VulkanGetProc getProc,
40 VkInstance instance,
41 VkPhysicalDevice physDev,
42 uint32_t instanceExtensionCount,
43 const char* const* instanceExtensions,
44 uint32_t deviceExtensionCount,
45 const char* const* deviceExtensions) {
46 for (uint32_t i = 0; i < instanceExtensionCount; ++i) {
47 const char* extension = instanceExtensions[i];
48 // if not already in the list, add it
49 if (find_info(fExtensions, extension) < 0) {
50 fExtensions.push_back() = Info(extension);
51 SkTQSort(fExtensions.begin(), fExtensions.end(), extension_compare);
52 }
53 }
54 for (uint32_t i = 0; i < deviceExtensionCount; ++i) {
55 const char* extension = deviceExtensions[i];
56 // if not already in the list, add it
57 if (find_info(fExtensions, extension) < 0) {
58 fExtensions.push_back() = Info(extension);
59 SkTQSort(fExtensions.begin(), fExtensions.end(), extension_compare);
60 }
61 }
62 this->getSpecVersions(std::move(getProc), instance, physDev);
63 }
64
65 #define GET_PROC(F, inst) \
66 PFN_vk##F grVk##F = (PFN_vk ## F) getProc("vk" #F, inst, VK_NULL_HANDLE)
67
getSpecVersions(const VulkanGetProc & getProc,VkInstance instance,VkPhysicalDevice physDevice)68 void VulkanExtensions::getSpecVersions(const VulkanGetProc& getProc,
69 VkInstance instance,
70 VkPhysicalDevice physDevice) {
71 // We grab all the extensions for the VkInstance and VkDevice so we can look up what spec
72 // version each of the supported extensions are. We do not grab the extensions for layers
73 // because we don't know what layers the client has enabled and in general we don't do anything
74 // special for those extensions.
75
76 if (instance == VK_NULL_HANDLE) {
77 return;
78 }
79 GET_PROC(EnumerateInstanceExtensionProperties, VK_NULL_HANDLE);
80 SkASSERT(grVkEnumerateInstanceExtensionProperties);
81
82 VkResult res;
83 // instance extensions
84 uint32_t extensionCount = 0;
85 res = grVkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
86 if (VK_SUCCESS != res) {
87 return;
88 }
89 VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
90 res = grVkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions);
91 if (VK_SUCCESS != res) {
92 delete[] extensions;
93 return;
94 }
95 for (uint32_t i = 0; i < extensionCount; ++i) {
96 int idx = find_info(fExtensions, extensions[i].extensionName);
97 if (idx >= 0) {
98 fExtensions[idx].fSpecVersion = extensions[i].specVersion;
99 }
100 }
101 delete[] extensions;
102
103 if (physDevice == VK_NULL_HANDLE) {
104 return;
105 }
106 GET_PROC(EnumerateDeviceExtensionProperties, instance);
107 SkASSERT(grVkEnumerateDeviceExtensionProperties);
108
109 // device extensions
110 extensionCount = 0;
111 res = grVkEnumerateDeviceExtensionProperties(physDevice, nullptr, &extensionCount, nullptr);
112 if (VK_SUCCESS != res) {
113 return;
114 }
115 extensions = new VkExtensionProperties[extensionCount];
116 res = grVkEnumerateDeviceExtensionProperties(physDevice, nullptr, &extensionCount, extensions);
117 if (VK_SUCCESS != res) {
118 delete[] extensions;
119 return;
120 }
121 for (uint32_t i = 0; i < extensionCount; ++i) {
122 int idx = find_info(fExtensions, extensions[i].extensionName);
123 if (idx >= 0) {
124 fExtensions[idx].fSpecVersion = extensions[i].specVersion;
125 }
126 }
127 delete[] extensions;
128 }
129
hasExtension(const char ext[],uint32_t minVersion) const130 bool VulkanExtensions::hasExtension(const char ext[], uint32_t minVersion) const {
131 int idx = find_info(fExtensions, ext);
132 return idx >= 0 && fExtensions[idx].fSpecVersion >= minVersion;
133 }
134
135 } // namespace skgpu
136