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