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