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 "vk/GrVkExtensions.h"
9#include "vk/GrVkUtil.h"
10
11#include "SkTSearch.h"
12#include "SkTSort.h"
13
14namespace { // This cannot be static because it is used as a template parameter.
15inline bool extension_compare(const SkString& a, const SkString& b) {
16    return strcmp(a.c_str(), b.c_str()) < 0;
17}
18}
19
20// finds the index of ext in strings or a negative result if ext is not found.
21static int find_string(const SkTArray<SkString>& strings, const char ext[]) {
22    if (strings.empty()) {
23        return -1;
24    }
25    SkString extensionStr(ext);
26    int idx = SkTSearch<SkString, extension_compare>(&strings.front(),
27                                                     strings.count(),
28                                                     extensionStr,
29                                                     sizeof(SkString));
30    return idx;
31}
32
33#define GET_PROC_LOCAL(F, inst, device) PFN_vk ## F F = (PFN_vk ## F) fGetProc("vk" #F, inst, device)
34
35static uint32_t remove_patch_version(uint32_t specVersion) {
36    return (specVersion >> 12) << 12;
37}
38
39bool GrVkExtensions::initInstance(uint32_t specVersion) {
40    if (fGetProc == nullptr) {
41        return false;
42    }
43
44    uint32_t nonPatchVersion = remove_patch_version(specVersion);
45
46    GET_PROC_LOCAL(EnumerateInstanceExtensionProperties, VK_NULL_HANDLE, VK_NULL_HANDLE);
47    GET_PROC_LOCAL(EnumerateInstanceLayerProperties, VK_NULL_HANDLE, VK_NULL_HANDLE);
48
49    SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
50
51    if (!EnumerateInstanceExtensionProperties ||
52        !EnumerateInstanceLayerProperties) {
53        return false;
54    }
55
56    // instance layers
57    uint32_t layerCount = 0;
58    VkResult res = EnumerateInstanceLayerProperties(&layerCount, nullptr);
59    if (VK_SUCCESS != res) {
60        return false;
61    }
62    VkLayerProperties* layers = new VkLayerProperties[layerCount];
63    res = EnumerateInstanceLayerProperties(&layerCount, layers);
64    if (VK_SUCCESS != res) {
65        delete[] layers;
66        return false;
67    }
68    for (uint32_t i = 0; i < layerCount; ++i) {
69        if (nonPatchVersion >= remove_patch_version(layers[i].specVersion)) {
70            fInstanceLayerStrings->push_back() = layers[i].layerName;
71        }
72    }
73    delete[] layers;
74    if (!fInstanceLayerStrings->empty()) {
75        SkTQSort(&fInstanceLayerStrings->front(), &fInstanceLayerStrings->back(), cmp);
76    }
77
78    // instance extensions
79    // via Vulkan implementation and implicitly enabled layers
80    uint32_t extensionCount = 0;
81    res = EnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
82    if (VK_SUCCESS != res) {
83        return false;
84    }
85    VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
86    res = EnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions);
87    if (VK_SUCCESS != res) {
88        delete[] extensions;
89        return false;
90    }
91    for (uint32_t i = 0; i < extensionCount; ++i) {
92        fInstanceExtensionStrings->push_back() = extensions[i].extensionName;
93    }
94    delete [] extensions;
95    // sort so we can search
96    if (!fInstanceExtensionStrings->empty()) {
97        SkTQSort(&fInstanceExtensionStrings->front(), &fInstanceExtensionStrings->back(), cmp);
98    }
99    // via explicitly enabled layers
100    layerCount = fInstanceLayerStrings->count();
101    for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex) {
102        uint32_t extensionCount = 0;
103        res = EnumerateInstanceExtensionProperties((*fInstanceLayerStrings)[layerIndex].c_str(),
104                                                   &extensionCount, nullptr);
105        if (VK_SUCCESS != res) {
106            return false;
107        }
108        VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
109        res = EnumerateInstanceExtensionProperties((*fInstanceLayerStrings)[layerIndex].c_str(),
110                                                   &extensionCount, extensions);
111        if (VK_SUCCESS != res) {
112            delete[] extensions;
113            return false;
114        }
115        for (uint32_t i = 0; i < extensionCount; ++i) {
116            // if not already in the list, add it
117            if (nonPatchVersion >= remove_patch_version(extensions[i].specVersion) &&
118                find_string(*fInstanceExtensionStrings, extensions[i].extensionName) < 0) {
119                fInstanceExtensionStrings->push_back() = extensions[i].extensionName;
120                SkTQSort(&fInstanceExtensionStrings->front(), &fInstanceExtensionStrings->back(),
121                         cmp);
122            }
123        }
124        delete[] extensions;
125    }
126
127    return true;
128}
129
130bool GrVkExtensions::initDevice(uint32_t specVersion, VkInstance inst, VkPhysicalDevice physDev) {
131    if (fGetProc == nullptr) {
132        return false;
133    }
134
135    uint32_t nonPatchVersion = remove_patch_version(specVersion);
136
137    GET_PROC_LOCAL(EnumerateDeviceExtensionProperties, inst, VK_NULL_HANDLE);
138    GET_PROC_LOCAL(EnumerateDeviceLayerProperties, inst, VK_NULL_HANDLE);
139
140    SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
141
142    if (!EnumerateDeviceExtensionProperties ||
143        !EnumerateDeviceLayerProperties) {
144        return false;
145    }
146
147    // device layers
148    uint32_t layerCount = 0;
149    VkResult res = EnumerateDeviceLayerProperties(physDev, &layerCount, nullptr);
150    if (VK_SUCCESS != res) {
151        return false;
152    }
153    VkLayerProperties* layers = new VkLayerProperties[layerCount];
154    res = EnumerateDeviceLayerProperties(physDev, &layerCount, layers);
155    if (VK_SUCCESS != res) {
156        delete[] layers;
157        return false;
158    }
159    for (uint32_t i = 0; i < layerCount; ++i) {
160        if (nonPatchVersion >= remove_patch_version(layers[i].specVersion)) {
161            fDeviceLayerStrings->push_back() = layers[i].layerName;
162        }
163    }
164    delete[] layers;
165    if (!fDeviceLayerStrings->empty()) {
166        SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
167        SkTQSort(&fDeviceLayerStrings->front(), &fDeviceLayerStrings->back(), cmp);
168    }
169
170    // device extensions
171    // via Vulkan implementation and implicitly enabled layers
172    uint32_t extensionCount = 0;
173    res = EnumerateDeviceExtensionProperties(physDev, nullptr, &extensionCount, nullptr);
174    if (VK_SUCCESS != res) {
175        return false;
176    }
177    VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
178    res = EnumerateDeviceExtensionProperties(physDev, nullptr, &extensionCount, extensions);
179    if (VK_SUCCESS != res) {
180        delete[] extensions;
181        return false;
182    }
183    for (uint32_t i = 0; i < extensionCount; ++i) {
184        fDeviceExtensionStrings->push_back() = extensions[i].extensionName;
185    }
186    delete[] extensions;
187    if (!fDeviceExtensionStrings->empty()) {
188        SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
189        SkTQSort(&fDeviceExtensionStrings->front(), &fDeviceExtensionStrings->back(), cmp);
190    }
191    // via explicitly enabled layers
192    layerCount = fDeviceLayerStrings->count();
193    for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex) {
194        uint32_t extensionCount = 0;
195        res = EnumerateDeviceExtensionProperties(physDev,
196            (*fDeviceLayerStrings)[layerIndex].c_str(),
197            &extensionCount, nullptr);
198        if (VK_SUCCESS != res) {
199            return false;
200        }
201        VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
202        res = EnumerateDeviceExtensionProperties(physDev,
203            (*fDeviceLayerStrings)[layerIndex].c_str(),
204            &extensionCount, extensions);
205        if (VK_SUCCESS != res) {
206            delete[] extensions;
207            return false;
208        }
209        for (uint32_t i = 0; i < extensionCount; ++i) {
210            // if not already in the list, add it
211            if (nonPatchVersion >= remove_patch_version(extensions[i].specVersion) &&
212                find_string(*fDeviceExtensionStrings, extensions[i].extensionName) < 0) {
213                fDeviceExtensionStrings->push_back() = extensions[i].extensionName;
214                SkTQSort(&fDeviceExtensionStrings->front(), &fDeviceExtensionStrings->back(), cmp);
215            }
216        }
217        delete[] extensions;
218    }
219
220    return true;
221}
222
223bool GrVkExtensions::hasInstanceExtension(const char ext[]) const {
224    return find_string(*fInstanceExtensionStrings, ext) >= 0;
225}
226
227bool GrVkExtensions::hasDeviceExtension(const char ext[]) const {
228    return find_string(*fDeviceExtensionStrings, ext) >= 0;
229}
230
231bool GrVkExtensions::hasInstanceLayer(const char ext[]) const {
232    return find_string(*fInstanceLayerStrings, ext) >= 0;
233}
234
235bool GrVkExtensions::hasDeviceLayer(const char ext[]) const {
236    return find_string(*fDeviceLayerStrings, ext) >= 0;
237}
238
239void GrVkExtensions::print(const char* sep) const {
240    if (nullptr == sep) {
241        sep = " ";
242    }
243    int cnt = fInstanceExtensionStrings->count();
244    SkDebugf("Instance Extensions: ");
245    for (int i = 0; i < cnt; ++i) {
246        SkDebugf("%s%s", (*fInstanceExtensionStrings)[i].c_str(), (i < cnt - 1) ? sep : "");
247    }
248    cnt = fDeviceExtensionStrings->count();
249    SkDebugf("\nDevice Extensions: ");
250    for (int i = 0; i < cnt; ++i) {
251        SkDebugf("%s%s", (*fDeviceExtensionStrings)[i].c_str(), (i < cnt - 1) ? sep : "");
252    }
253    cnt = fInstanceLayerStrings->count();
254    SkDebugf("\nInstance Layers: ");
255    for (int i = 0; i < cnt; ++i) {
256        SkDebugf("%s%s", (*fInstanceLayerStrings)[i].c_str(), (i < cnt - 1) ? sep : "");
257    }
258    cnt = fDeviceLayerStrings->count();
259    SkDebugf("\nDevice Layers: ");
260    for (int i = 0; i < cnt; ++i) {
261        SkDebugf("%s%s", (*fDeviceLayerStrings)[i].c_str(), (i < cnt - 1) ? sep : "");
262    }
263}
264