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        if (nonPatchVersion >= remove_patch_version(extensions[i].specVersion)) {
93            fInstanceExtensionStrings->push_back() = extensions[i].extensionName;
94        }
95    }
96    delete [] extensions;
97    // sort so we can search
98    if (!fInstanceExtensionStrings->empty()) {
99        SkTQSort(&fInstanceExtensionStrings->front(), &fInstanceExtensionStrings->back(), cmp);
100    }
101    // via explicitly enabled layers
102    layerCount = fInstanceLayerStrings->count();
103    for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex) {
104        uint32_t extensionCount = 0;
105        res = EnumerateInstanceExtensionProperties((*fInstanceLayerStrings)[layerIndex].c_str(),
106                                                   &extensionCount, nullptr);
107        if (VK_SUCCESS != res) {
108            return false;
109        }
110        VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
111        res = EnumerateInstanceExtensionProperties((*fInstanceLayerStrings)[layerIndex].c_str(),
112                                                   &extensionCount, extensions);
113        if (VK_SUCCESS != res) {
114            delete[] extensions;
115            return false;
116        }
117        for (uint32_t i = 0; i < extensionCount; ++i) {
118            // if not already in the list, add it
119            if (nonPatchVersion >= remove_patch_version(extensions[i].specVersion) &&
120                find_string(*fInstanceExtensionStrings, extensions[i].extensionName) < 0) {
121                fInstanceExtensionStrings->push_back() = extensions[i].extensionName;
122                SkTQSort(&fInstanceExtensionStrings->front(), &fInstanceExtensionStrings->back(),
123                         cmp);
124            }
125        }
126        delete[] extensions;
127    }
128
129    return true;
130}
131
132bool GrVkExtensions::initDevice(uint32_t specVersion, VkInstance inst, VkPhysicalDevice physDev) {
133    if (fGetProc == nullptr) {
134        return false;
135    }
136
137    uint32_t nonPatchVersion = remove_patch_version(specVersion);
138
139    GET_PROC_LOCAL(EnumerateDeviceExtensionProperties, inst, VK_NULL_HANDLE);
140    GET_PROC_LOCAL(EnumerateDeviceLayerProperties, inst, VK_NULL_HANDLE);
141
142    SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
143
144    if (!EnumerateDeviceExtensionProperties ||
145        !EnumerateDeviceLayerProperties) {
146        return false;
147    }
148
149    // device layers
150    uint32_t layerCount = 0;
151    VkResult res = EnumerateDeviceLayerProperties(physDev, &layerCount, nullptr);
152    if (VK_SUCCESS != res) {
153        return false;
154    }
155    VkLayerProperties* layers = new VkLayerProperties[layerCount];
156    res = EnumerateDeviceLayerProperties(physDev, &layerCount, layers);
157    if (VK_SUCCESS != res) {
158        delete[] layers;
159        return false;
160    }
161    for (uint32_t i = 0; i < layerCount; ++i) {
162        if (nonPatchVersion >= remove_patch_version(layers[i].specVersion)) {
163            fDeviceLayerStrings->push_back() = layers[i].layerName;
164        }
165    }
166    delete[] layers;
167    if (!fDeviceLayerStrings->empty()) {
168        SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
169        SkTQSort(&fDeviceLayerStrings->front(), &fDeviceLayerStrings->back(), cmp);
170    }
171
172    // device extensions
173    // via Vulkan implementation and implicitly enabled layers
174    uint32_t extensionCount = 0;
175    res = EnumerateDeviceExtensionProperties(physDev, nullptr, &extensionCount, nullptr);
176    if (VK_SUCCESS != res) {
177        return false;
178    }
179    VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
180    res = EnumerateDeviceExtensionProperties(physDev, nullptr, &extensionCount, extensions);
181    if (VK_SUCCESS != res) {
182        delete[] extensions;
183        return false;
184    }
185    for (uint32_t i = 0; i < extensionCount; ++i) {
186        if (nonPatchVersion >= remove_patch_version(extensions[i].specVersion)) {
187            fDeviceExtensionStrings->push_back() = extensions[i].extensionName;
188        }
189    }
190    delete[] extensions;
191    if (!fDeviceExtensionStrings->empty()) {
192        SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
193        SkTQSort(&fDeviceExtensionStrings->front(), &fDeviceExtensionStrings->back(), cmp);
194    }
195    // via explicitly enabled layers
196    layerCount = fDeviceLayerStrings->count();
197    for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex) {
198        uint32_t extensionCount = 0;
199        res = EnumerateDeviceExtensionProperties(physDev,
200            (*fDeviceLayerStrings)[layerIndex].c_str(),
201            &extensionCount, nullptr);
202        if (VK_SUCCESS != res) {
203            return false;
204        }
205        VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
206        res = EnumerateDeviceExtensionProperties(physDev,
207            (*fDeviceLayerStrings)[layerIndex].c_str(),
208            &extensionCount, extensions);
209        if (VK_SUCCESS != res) {
210            delete[] extensions;
211            return false;
212        }
213        for (uint32_t i = 0; i < extensionCount; ++i) {
214            // if not already in the list, add it
215            if (nonPatchVersion >= remove_patch_version(extensions[i].specVersion) &&
216                find_string(*fDeviceExtensionStrings, extensions[i].extensionName) < 0) {
217                fDeviceExtensionStrings->push_back() = extensions[i].extensionName;
218                SkTQSort(&fDeviceExtensionStrings->front(), &fDeviceExtensionStrings->back(), cmp);
219            }
220        }
221        delete[] extensions;
222    }
223
224    return true;
225}
226
227bool GrVkExtensions::hasInstanceExtension(const char ext[]) const {
228    return find_string(*fInstanceExtensionStrings, ext) >= 0;
229}
230
231bool GrVkExtensions::hasDeviceExtension(const char ext[]) const {
232    return find_string(*fDeviceExtensionStrings, ext) >= 0;
233}
234
235bool GrVkExtensions::hasInstanceLayer(const char ext[]) const {
236    return find_string(*fInstanceLayerStrings, ext) >= 0;
237}
238
239bool GrVkExtensions::hasDeviceLayer(const char ext[]) const {
240    return find_string(*fDeviceLayerStrings, ext) >= 0;
241}
242
243void GrVkExtensions::print(const char* sep) const {
244    if (nullptr == sep) {
245        sep = " ";
246    }
247    int cnt = fInstanceExtensionStrings->count();
248    SkDebugf("Instance Extensions: ");
249    for (int i = 0; i < cnt; ++i) {
250        SkDebugf("%s%s", (*fInstanceExtensionStrings)[i].c_str(), (i < cnt - 1) ? sep : "");
251    }
252    cnt = fDeviceExtensionStrings->count();
253    SkDebugf("\nDevice Extensions: ");
254    for (int i = 0; i < cnt; ++i) {
255        SkDebugf("%s%s", (*fDeviceExtensionStrings)[i].c_str(), (i < cnt - 1) ? sep : "");
256    }
257    cnt = fInstanceLayerStrings->count();
258    SkDebugf("\nInstance Layers: ");
259    for (int i = 0; i < cnt; ++i) {
260        SkDebugf("%s%s", (*fInstanceLayerStrings)[i].c_str(), (i < cnt - 1) ? sep : "");
261    }
262    cnt = fDeviceLayerStrings->count();
263    SkDebugf("\nDevice Layers: ");
264    for (int i = 0; i < cnt; ++i) {
265        SkDebugf("%s%s", (*fDeviceLayerStrings)[i].c_str(), (i < cnt - 1) ? sep : "");
266    }
267}
268