281 lines
12 KiB
C++
281 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 "SkTypes.h"
|
||
|
|
||
|
#if SK_SUPPORT_GPU && defined(SK_VULKAN)
|
||
|
|
||
|
#include "SkAutoMalloc.h"
|
||
|
#include "Test.h"
|
||
|
#include "vk/GrVkTypes.h"
|
||
|
#include "../tools/gpu/vk/VkTestUtils.h"
|
||
|
|
||
|
#define ACQUIRE_VK_PROC_NOCHECK(name, instance, device) \
|
||
|
PFN_vk##name grVk##name = reinterpret_cast<PFN_vk##name>(getProc("vk" #name, instance, device))
|
||
|
|
||
|
#define ACQUIRE_VK_PROC(name, instance, device) \
|
||
|
PFN_vk##name grVk##name = \
|
||
|
reinterpret_cast<PFN_vk##name>(getProc("vk" #name, instance, device)); \
|
||
|
do { \
|
||
|
if (grVk##name == nullptr) { \
|
||
|
if (device != VK_NULL_HANDLE) { \
|
||
|
destroy_instance(getProc, inst); \
|
||
|
} \
|
||
|
return; \
|
||
|
} \
|
||
|
} while (0)
|
||
|
|
||
|
#define ACQUIRE_VK_PROC_LOCAL(name, instance, device) \
|
||
|
PFN_vk##name grVk##name = \
|
||
|
reinterpret_cast<PFN_vk##name>(getProc("vk" #name, instance, device)); \
|
||
|
do { \
|
||
|
if (grVk##name == nullptr) { \
|
||
|
return; \
|
||
|
} \
|
||
|
} while (0)
|
||
|
|
||
|
#define GET_PROC_LOCAL(F, inst, device) PFN_vk ## F F = (PFN_vk ## F) getProc("vk" #F, inst, device)
|
||
|
|
||
|
static void destroy_instance(GrVkGetProc getProc, VkInstance inst) {
|
||
|
ACQUIRE_VK_PROC_LOCAL(DestroyInstance, inst, VK_NULL_HANDLE);
|
||
|
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;
|
||
|
PFN_vkGetDeviceProcAddr devProc;
|
||
|
if (!sk_gpu_test::LoadVkLibraryAndGetProcAddrFuncs(&instProc, &devProc)) {
|
||
|
return;
|
||
|
}
|
||
|
auto getProc = [instProc, devProc](const char* proc_name,
|
||
|
VkInstance instance, VkDevice device) {
|
||
|
if (device != VK_NULL_HANDLE) {
|
||
|
return devProc(device, proc_name);
|
||
|
}
|
||
|
return instProc(instance, proc_name);
|
||
|
};
|
||
|
|
||
|
VkResult err;
|
||
|
|
||
|
ACQUIRE_VK_PROC_NOCHECK(EnumerateInstanceVersion, VK_NULL_HANDLE, 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 = SkTMin(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, VK_NULL_HANDLE);
|
||
|
err = grVkCreateInstance(&instance_create, nullptr, &inst);
|
||
|
if (err < 0) {
|
||
|
ERRORF(reporter, "Failed to create VkInstance");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ACQUIRE_VK_PROC(EnumeratePhysicalDevices, inst, VK_NULL_HANDLE);
|
||
|
ACQUIRE_VK_PROC(GetPhysicalDeviceProperties, inst, VK_NULL_HANDLE);
|
||
|
ACQUIRE_VK_PROC(GetPhysicalDeviceQueueFamilyProperties, inst, VK_NULL_HANDLE);
|
||
|
ACQUIRE_VK_PROC(GetPhysicalDeviceFeatures, inst, VK_NULL_HANDLE);
|
||
|
ACQUIRE_VK_PROC(CreateDevice, inst, VK_NULL_HANDLE);
|
||
|
ACQUIRE_VK_PROC(GetDeviceQueue, inst, VK_NULL_HANDLE);
|
||
|
ACQUIRE_VK_PROC(DeviceWaitIdle, inst, VK_NULL_HANDLE);
|
||
|
ACQUIRE_VK_PROC(DestroyDevice, inst, VK_NULL_HANDLE);
|
||
|
|
||
|
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, VK_NULL_HANDLE);
|
||
|
GET_PROC_LOCAL(EnumerateDeviceLayerProperties, inst, VK_NULL_HANDLE);
|
||
|
|
||
|
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
|