6658fd1584
We've run into drivers a few times now that have bugs where they only expose vkGetInstaneProcAddr and not vkGetDeviceProcAddr. The latest being swiftshader (which is getting fixed). To avoid this issue in the future we can just have our tests use vkGetInstanceProcAddr to get vkGetDeviceProcAddr. Change-Id: I6d73abde507519c145b873042393f50ce6c4527c Reviewed-on: https://skia-review.googlesource.com/c/skia/+/494822 Reviewed-by: Jim Van Verth <jvanverth@google.com> Commit-Queue: Greg Daniel <egdaniel@google.com>
278 lines
12 KiB
C++
278 lines
12 KiB
C++
/*
|
|
* Copyright 2019 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "include/core/SkTypes.h"
|
|
|
|
#if SK_SUPPORT_GPU && defined(SK_VULKAN)
|
|
|
|
#include "include/gpu/vk/GrVkTypes.h"
|
|
#include "src/core/SkAutoMalloc.h"
|
|
#include "tests/Test.h"
|
|
#include "tools/gpu/vk/VkTestUtils.h"
|
|
|
|
#define ACQUIRE_VK_PROC_NOCHECK(name, instance) \
|
|
PFN_vk##name grVk##name = \
|
|
reinterpret_cast<PFN_vk##name>(getProc("vk" #name, instance, VK_NULL_HANDLE))
|
|
|
|
#define ACQUIRE_VK_PROC(name, instance) \
|
|
PFN_vk##name grVk##name = \
|
|
reinterpret_cast<PFN_vk##name>(getProc("vk" #name, instance, VK_NULL_HANDLE)); \
|
|
do { \
|
|
if (grVk##name == nullptr) { \
|
|
if (instance != VK_NULL_HANDLE) { \
|
|
destroy_instance(getProc, instance); \
|
|
} \
|
|
return; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define ACQUIRE_VK_PROC_LOCAL(name, instance) \
|
|
PFN_vk##name grVk##name = \
|
|
reinterpret_cast<PFN_vk##name>(getProc("vk" #name, instance, VK_NULL_HANDLE)); \
|
|
do { \
|
|
if (grVk##name == nullptr) { \
|
|
return; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define GET_PROC_LOCAL(F, inst) PFN_vk ## F F = (PFN_vk ## F) getProc("vk" #F, inst, VK_NULL_HANDLE)
|
|
|
|
static void destroy_instance(GrVkGetProc getProc, VkInstance inst) {
|
|
ACQUIRE_VK_PROC_LOCAL(DestroyInstance, inst);
|
|
grVkDestroyInstance(inst, nullptr);
|
|
}
|
|
|
|
// If the extension VK_EXT_GLOBAL_PRIORITY is supported, this test just tries to create a VkDevice
|
|
// using the various global priorities. The test passes if no errors are reported or the test
|
|
// doesn't crash.
|
|
DEF_GPUTEST(VulkanPriorityExtension, reporter, options) {
|
|
PFN_vkGetInstanceProcAddr instProc;
|
|
if (!sk_gpu_test::LoadVkLibraryAndGetProcAddrFuncs(&instProc)) {
|
|
return;
|
|
}
|
|
// This isn't the most effecient but we just use the instProc to get all ptrs.
|
|
auto getProc = [instProc](const char* proc_name, VkInstance instance, VkDevice) {
|
|
return instProc(instance, proc_name);
|
|
};
|
|
|
|
VkResult err;
|
|
|
|
ACQUIRE_VK_PROC_NOCHECK(EnumerateInstanceVersion, VK_NULL_HANDLE);
|
|
uint32_t instanceVersion = 0;
|
|
if (!grVkEnumerateInstanceVersion) {
|
|
instanceVersion = VK_MAKE_VERSION(1, 0, 0);
|
|
} else {
|
|
err = grVkEnumerateInstanceVersion(&instanceVersion);
|
|
if (err) {
|
|
ERRORF(reporter, "failed ot enumerate instance version. Err: %d", err);
|
|
return;
|
|
}
|
|
}
|
|
SkASSERT(instanceVersion >= VK_MAKE_VERSION(1, 0, 0));
|
|
uint32_t apiVersion = VK_MAKE_VERSION(1, 0, 0);
|
|
if (instanceVersion >= VK_MAKE_VERSION(1, 1, 0)) {
|
|
// If the instance version is 1.0 we must have the apiVersion also be 1.0. However, if the
|
|
// instance version is 1.1 or higher, we can set the apiVersion to be whatever the highest
|
|
// api we may use in skia (technically it can be arbitrary). So for now we set it to 1.1
|
|
// since that is the highest vulkan version.
|
|
apiVersion = VK_MAKE_VERSION(1, 1, 0);
|
|
}
|
|
|
|
instanceVersion = std::min(instanceVersion, apiVersion);
|
|
|
|
VkPhysicalDevice physDev;
|
|
VkDevice device;
|
|
VkInstance inst;
|
|
|
|
const VkApplicationInfo app_info = {
|
|
VK_STRUCTURE_TYPE_APPLICATION_INFO, // sType
|
|
nullptr, // pNext
|
|
"vktest", // pApplicationName
|
|
0, // applicationVersion
|
|
"vktest", // pEngineName
|
|
0, // engineVersion
|
|
apiVersion, // apiVersion
|
|
};
|
|
|
|
const VkInstanceCreateInfo instance_create = {
|
|
VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // sType
|
|
nullptr, // pNext
|
|
0, // flags
|
|
&app_info, // pApplicationInfo
|
|
0, // enabledLayerNameCount
|
|
nullptr, // ppEnabledLayerNames
|
|
0, // enabledExtensionNameCount
|
|
nullptr, // ppEnabledExtensionNames
|
|
};
|
|
|
|
ACQUIRE_VK_PROC(CreateInstance, VK_NULL_HANDLE);
|
|
err = grVkCreateInstance(&instance_create, nullptr, &inst);
|
|
if (err < 0) {
|
|
ERRORF(reporter, "Failed to create VkInstance");
|
|
return;
|
|
}
|
|
|
|
ACQUIRE_VK_PROC(EnumeratePhysicalDevices, inst);
|
|
ACQUIRE_VK_PROC(GetPhysicalDeviceProperties, inst);
|
|
ACQUIRE_VK_PROC(GetPhysicalDeviceQueueFamilyProperties, inst);
|
|
ACQUIRE_VK_PROC(GetPhysicalDeviceFeatures, inst);
|
|
ACQUIRE_VK_PROC(CreateDevice, inst);
|
|
ACQUIRE_VK_PROC(GetDeviceQueue, inst);
|
|
ACQUIRE_VK_PROC(DeviceWaitIdle, inst);
|
|
ACQUIRE_VK_PROC(DestroyDevice, inst);
|
|
|
|
uint32_t gpuCount;
|
|
err = grVkEnumeratePhysicalDevices(inst, &gpuCount, nullptr);
|
|
if (err) {
|
|
ERRORF(reporter, "vkEnumeratePhysicalDevices failed: %d", err);
|
|
destroy_instance(getProc, inst);
|
|
return;
|
|
}
|
|
if (!gpuCount) {
|
|
ERRORF(reporter, "vkEnumeratePhysicalDevices returned no supported devices.");
|
|
destroy_instance(getProc, inst);
|
|
return;
|
|
}
|
|
// Just returning the first physical device instead of getting the whole array.
|
|
// TODO: find best match for our needs
|
|
gpuCount = 1;
|
|
err = grVkEnumeratePhysicalDevices(inst, &gpuCount, &physDev);
|
|
// VK_INCOMPLETE is returned when the count we provide is less than the total device count.
|
|
if (err && VK_INCOMPLETE != err) {
|
|
ERRORF(reporter, "vkEnumeratePhysicalDevices failed: %d", err);
|
|
destroy_instance(getProc, inst);
|
|
return;
|
|
}
|
|
|
|
// query to get the initial queue props size
|
|
uint32_t queueCount;
|
|
grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, nullptr);
|
|
if (!queueCount) {
|
|
ERRORF(reporter, "vkGetPhysicalDeviceQueueFamilyProperties returned no queues.");
|
|
destroy_instance(getProc, inst);
|
|
return;
|
|
}
|
|
|
|
SkAutoMalloc queuePropsAlloc(queueCount * sizeof(VkQueueFamilyProperties));
|
|
// now get the actual queue props
|
|
VkQueueFamilyProperties* queueProps = (VkQueueFamilyProperties*)queuePropsAlloc.get();
|
|
|
|
grVkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueProps);
|
|
|
|
// iterate to find the graphics queue
|
|
uint32_t graphicsQueueIndex = queueCount;
|
|
for (uint32_t i = 0; i < queueCount; i++) {
|
|
if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
|
graphicsQueueIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
if (graphicsQueueIndex == queueCount) {
|
|
ERRORF(reporter, "Could not find any supported graphics queues.");
|
|
destroy_instance(getProc, inst);
|
|
return;
|
|
}
|
|
|
|
GET_PROC_LOCAL(EnumerateDeviceExtensionProperties, inst);
|
|
GET_PROC_LOCAL(EnumerateDeviceLayerProperties, inst);
|
|
|
|
if (!EnumerateDeviceExtensionProperties ||
|
|
!EnumerateDeviceLayerProperties) {
|
|
destroy_instance(getProc, inst);
|
|
return;
|
|
}
|
|
|
|
// device extensions
|
|
// via Vulkan implementation and implicitly enabled layers
|
|
uint32_t extensionCount = 0;
|
|
err = EnumerateDeviceExtensionProperties(physDev, nullptr, &extensionCount, nullptr);
|
|
if (VK_SUCCESS != err) {
|
|
ERRORF(reporter, "Could not enumerate device extension properties.");
|
|
destroy_instance(getProc, inst);
|
|
return;
|
|
}
|
|
VkExtensionProperties* extensions = new VkExtensionProperties[extensionCount];
|
|
err = EnumerateDeviceExtensionProperties(physDev, nullptr, &extensionCount, extensions);
|
|
if (VK_SUCCESS != err) {
|
|
delete[] extensions;
|
|
ERRORF(reporter, "Could not enumerate device extension properties.");
|
|
destroy_instance(getProc, inst);
|
|
return;
|
|
}
|
|
bool hasPriorityExt = false;
|
|
for (uint32_t i = 0; i < extensionCount; ++i) {
|
|
if (!strcmp(extensions[i].extensionName, VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME)) {
|
|
hasPriorityExt = true;
|
|
}
|
|
}
|
|
delete[] extensions;
|
|
|
|
if (!hasPriorityExt) {
|
|
destroy_instance(getProc, inst);
|
|
return;
|
|
}
|
|
|
|
const char* priorityExt = VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME;
|
|
|
|
VkPhysicalDeviceFeatures deviceFeatures;
|
|
grVkGetPhysicalDeviceFeatures(physDev, &deviceFeatures);
|
|
|
|
// this looks like it would slow things down,
|
|
// and we can't depend on it on all platforms
|
|
deviceFeatures.robustBufferAccess = VK_FALSE;
|
|
|
|
float queuePriorities[1] = { 0.0 };
|
|
|
|
VkDeviceQueueGlobalPriorityCreateInfoEXT queuePriorityCreateInfo;
|
|
queuePriorityCreateInfo.sType =
|
|
VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT;
|
|
queuePriorityCreateInfo.pNext = nullptr;
|
|
|
|
VkDeviceQueueCreateInfo queueInfo = {
|
|
VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
|
|
&queuePriorityCreateInfo, // pNext
|
|
0, // VkDeviceQueueCreateFlags
|
|
graphicsQueueIndex, // queueFamilyIndex
|
|
1, // queueCount
|
|
queuePriorities, // pQueuePriorities
|
|
};
|
|
|
|
for (VkQueueGlobalPriorityEXT globalPriority : { VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT,
|
|
VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT,
|
|
VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT,
|
|
VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT }) {
|
|
queuePriorityCreateInfo.globalPriority = globalPriority;
|
|
|
|
const VkDeviceCreateInfo deviceInfo = {
|
|
VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType
|
|
nullptr, // pNext
|
|
0, // VkDeviceCreateFlags
|
|
1, // queueCreateInfoCount
|
|
&queueInfo, // pQueueCreateInfos
|
|
0, // layerCount
|
|
nullptr, // ppEnabledLayerNames
|
|
1, // extensionCount
|
|
&priorityExt, // ppEnabledExtensionNames
|
|
&deviceFeatures // ppEnabledFeatures
|
|
};
|
|
|
|
err = grVkCreateDevice(physDev, &deviceInfo, nullptr, &device);
|
|
|
|
if (err != VK_SUCCESS && err != VK_ERROR_NOT_PERMITTED_EXT) {
|
|
ERRORF(reporter, "CreateDevice failed: %d, priority %d", err, globalPriority);
|
|
destroy_instance(getProc, inst);
|
|
continue;
|
|
}
|
|
if (err != VK_ERROR_NOT_PERMITTED_EXT) {
|
|
grVkDestroyDevice(device, nullptr);
|
|
}
|
|
}
|
|
destroy_instance(getProc, inst);
|
|
}
|
|
|
|
#endif
|