/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "vk/GrVkExtensions.h"
#include "vk/GrVkUtil.h"
#include "SkTSearch.h"
#include "SkTSort.h"
namespace { // This cannot be static because it is used as a template parameter.
inline bool extension_compare(const SkString& a, const SkString& b) {
return strcmp(a.c_str(), b.c_str()) < 0;
}
}
// finds the index of ext in strings or a negative result if ext is not found.
static int find_string(const SkTArray<SkString>& strings, const char ext[]) {
if (strings.empty()) {
return -1;
}
SkString extensionStr(ext);
int idx = SkTSearch<SkString, extension_compare>(&strings.front(),
strings.count(),
extensionStr,
sizeof(SkString));
return idx;
}
#define GET_PROC_LOCAL(inst, F) PFN_vk ## F F = (PFN_vk ## F) vkGetInstanceProcAddr(inst, "vk" #F)
static uint32_t remove_patch_version(uint32_t specVersion) {
return (specVersion >> 12) << 12;
}
bool GrVkExtensions::initInstance(uint32_t specVersion) {
uint32_t nonPatchVersion = remove_patch_version(specVersion);
GET_PROC_LOCAL(nullptr, EnumerateInstanceExtensionProperties);
GET_PROC_LOCAL(nullptr, EnumerateInstanceLayerProperties);
SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
if (!EnumerateInstanceExtensionProperties ||
!EnumerateInstanceLayerProperties) {
return false;
}
// instance layers
uint32_t layerCount = 0;
VkResult res = EnumerateInstanceLayerProperties(&layerCount, nullptr);
if (VK_SUCCESS != res) {
return false;
}
VkLayerProperties* layers = new VkLayerProperties[layerCount];
res = EnumerateInstanceLayerProperties(&layerCount, layers);
if (VK_SUCCESS != res) {
delete[] layers;
return false;
}
for (uint32_t i = 0; i < layerCount; ++i) {
if (nonPatchVersion >= remove_patch_version(layers[i].specVersion)) {
fInstanceLayerStrings->push_back() = layers[i].layerName;
}
}
delete[] layers;
if (!fInstanceLayerStrings->empty()) {
SkTQSort(&fInstanceLayerStrings->front(), &fInstanceLayerStrings->back(), cmp);
}
// instance extensions
// via Vulkan implementation and implicitly enabled layers
uint32_t extensionCount = 0;
res = EnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
if (VK_SUCCESS != res) {
return false;
}
VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
res = EnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions);
if (VK_SUCCESS != res) {
delete[] extensions;
return false;
}
for (uint32_t i = 0; i < extensionCount; ++i) {
if (nonPatchVersion >= remove_patch_version(extensions[i].specVersion)) {
fInstanceExtensionStrings->push_back() = extensions[i].extensionName;
}
}
delete [] extensions;
// sort so we can search
if (!fInstanceExtensionStrings->empty()) {
SkTQSort(&fInstanceExtensionStrings->front(), &fInstanceExtensionStrings->back(), cmp);
}
// via explicitly enabled layers
layerCount = fInstanceLayerStrings->count();
for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex) {
uint32_t extensionCount = 0;
res = EnumerateInstanceExtensionProperties((*fInstanceLayerStrings)[layerIndex].c_str(),
&extensionCount, nullptr);
if (VK_SUCCESS != res) {
return false;
}
VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
res = EnumerateInstanceExtensionProperties((*fInstanceLayerStrings)[layerIndex].c_str(),
&extensionCount, extensions);
if (VK_SUCCESS != res) {
delete[] extensions;
return false;
}
for (uint32_t i = 0; i < extensionCount; ++i) {
// if not already in the list, add it
if (nonPatchVersion >= remove_patch_version(extensions[i].specVersion) &&
find_string(*fInstanceExtensionStrings, extensions[i].extensionName) < 0) {
fInstanceExtensionStrings->push_back() = extensions[i].extensionName;
SkTQSort(&fInstanceExtensionStrings->front(), &fInstanceExtensionStrings->back(),
cmp);
}
}
delete[] extensions;
}
return true;
}
bool GrVkExtensions::initDevice(uint32_t specVersion, VkInstance inst, VkPhysicalDevice physDev) {
uint32_t nonPatchVersion = remove_patch_version(specVersion);
GET_PROC_LOCAL(inst, EnumerateDeviceExtensionProperties);
GET_PROC_LOCAL(inst, EnumerateDeviceLayerProperties);
SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
if (!EnumerateDeviceExtensionProperties ||
!EnumerateDeviceLayerProperties) {
return false;
}
// device layers
uint32_t layerCount = 0;
VkResult res = EnumerateDeviceLayerProperties(physDev, &layerCount, nullptr);
if (VK_SUCCESS != res) {
return false;
}
VkLayerProperties* layers = new VkLayerProperties[layerCount];
res = EnumerateDeviceLayerProperties(physDev, &layerCount, layers);
if (VK_SUCCESS != res) {
delete[] layers;
return false;
}
for (uint32_t i = 0; i < layerCount; ++i) {
if (nonPatchVersion >= remove_patch_version(layers[i].specVersion)) {
fDeviceLayerStrings->push_back() = layers[i].layerName;
}
}
delete[] layers;
if (!fDeviceLayerStrings->empty()) {
SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
SkTQSort(&fDeviceLayerStrings->front(), &fDeviceLayerStrings->back(), cmp);
}
// device extensions
// via Vulkan implementation and implicitly enabled layers
uint32_t extensionCount = 0;
res = EnumerateDeviceExtensionProperties(physDev, nullptr, &extensionCount, nullptr);
if (VK_SUCCESS != res) {
return false;
}
VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
res = EnumerateDeviceExtensionProperties(physDev, nullptr, &extensionCount, extensions);
if (VK_SUCCESS != res) {
delete[] extensions;
return false;
}
for (uint32_t i = 0; i < extensionCount; ++i) {
if (nonPatchVersion >= remove_patch_version(extensions[i].specVersion)) {
fDeviceExtensionStrings->push_back() = extensions[i].extensionName;
}
}
delete[] extensions;
if (!fDeviceExtensionStrings->empty()) {
SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
SkTQSort(&fDeviceExtensionStrings->front(), &fDeviceExtensionStrings->back(), cmp);
}
// via explicitly enabled layers
layerCount = fDeviceLayerStrings->count();
for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex) {
uint32_t extensionCount = 0;
res = EnumerateDeviceExtensionProperties(physDev,
(*fDeviceLayerStrings)[layerIndex].c_str(),
&extensionCount, nullptr);
if (VK_SUCCESS != res) {
return false;
}
VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
res = EnumerateDeviceExtensionProperties(physDev,
(*fDeviceLayerStrings)[layerIndex].c_str(),
&extensionCount, extensions);
if (VK_SUCCESS != res) {
delete[] extensions;
return false;
}
for (uint32_t i = 0; i < extensionCount; ++i) {
// if not already in the list, add it
if (nonPatchVersion >= remove_patch_version(extensions[i].specVersion) &&
find_string(*fDeviceExtensionStrings, extensions[i].extensionName) < 0) {
fDeviceExtensionStrings->push_back() = extensions[i].extensionName;
SkTQSort(&fDeviceExtensionStrings->front(), &fDeviceExtensionStrings->back(), cmp);
}
}
delete[] extensions;
}
return true;
}
bool GrVkExtensions::hasInstanceExtension(const char ext[]) const {
return find_string(*fInstanceExtensionStrings, ext) >= 0;
}
bool GrVkExtensions::hasDeviceExtension(const char ext[]) const {
return find_string(*fDeviceExtensionStrings, ext) >= 0;
}
bool GrVkExtensions::hasInstanceLayer(const char ext[]) const {
return find_string(*fInstanceLayerStrings, ext) >= 0;
}
bool GrVkExtensions::hasDeviceLayer(const char ext[]) const {
return find_string(*fDeviceLayerStrings, ext) >= 0;
}
void GrVkExtensions::print(const char* sep) const {
if (nullptr == sep) {
sep = " ";
}
int cnt = fInstanceExtensionStrings->count();
SkDebugf("Instance Extensions: ");
for (int i = 0; i < cnt; ++i) {
SkDebugf("%s%s", (*fInstanceExtensionStrings)[i].c_str(), (i < cnt - 1) ? sep : "");
}
cnt = fDeviceExtensionStrings->count();
SkDebugf("\nDevice Extensions: ");
for (int i = 0; i < cnt; ++i) {
SkDebugf("%s%s", (*fDeviceExtensionStrings)[i].c_str(), (i < cnt - 1) ? sep : "");
}
cnt = fInstanceLayerStrings->count();
SkDebugf("\nInstance Layers: ");
for (int i = 0; i < cnt; ++i) {
SkDebugf("%s%s", (*fInstanceLayerStrings)[i].c_str(), (i < cnt - 1) ? sep : "");
}
cnt = fDeviceLayerStrings->count();
SkDebugf("\nDevice Layers: ");
for (int i = 0; i < cnt; ++i) {
SkDebugf("%s%s", (*fDeviceLayerStrings)[i].c_str(), (i < cnt - 1) ? sep : "");
}
}