788b91678f
Use std::min and std::max everywhere. SkTPin still exists. We can't use std::clamp yet, and even when we can, it has undefined behavior with NaN. SkTPin is written to ensure that we return a value in the [lo, hi] range. Change-Id: I506852a36e024ae405358d5078a872e2c77fa71e Docs-Preview: https://skia.org/?cl=269357 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/269357 Commit-Queue: Brian Osman <brianosman@google.com> Reviewed-by: Mike Reed <reed@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com>
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 "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, 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 = 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, 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
|