update parallel rdp

This commit is contained in:
Logan McNaughton
2021-08-09 15:51:33 -06:00
parent 6705d5e44e
commit 19445a0df4
62 changed files with 110819 additions and 53611 deletions
+232 -112
View File
@@ -21,6 +21,7 @@
*/
#include "context.hpp"
#include "small_vector.hpp"
#include <vector>
#include <mutex>
#include <algorithm>
@@ -136,12 +137,14 @@ bool Context::init_from_instance_and_device(VkInstance instance_, VkPhysicalDevi
device = device_;
instance = instance_;
gpu = gpu_;
graphics_queue = queue_;
compute_queue = queue_;
transfer_queue = queue_;
graphics_queue_family = queue_family_;
compute_queue_family = queue_family_;
transfer_queue_family = queue_family_;
queue_info = {};
queue_info.queues[QUEUE_INDEX_GRAPHICS] = queue_;
queue_info.queues[QUEUE_INDEX_COMPUTE] = queue_;
queue_info.queues[QUEUE_INDEX_TRANSFER] = queue_;
queue_info.family_indices[QUEUE_INDEX_GRAPHICS] = queue_family_;
queue_info.family_indices[QUEUE_INDEX_COMPUTE] = queue_family_;
queue_info.family_indices[QUEUE_INDEX_TRANSFER] = queue_family_;
owned_instance = false;
owned_device = true;
@@ -455,6 +458,29 @@ bool Context::create_instance(const char **instance_ext, uint32_t instance_ext_c
return true;
}
static unsigned device_score(VkPhysicalDevice &gpu)
{
VkPhysicalDeviceProperties props = {};
vkGetPhysicalDeviceProperties(gpu, &props);
switch (props.deviceType)
{
case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
return 3;
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
return 2;
case VK_PHYSICAL_DEVICE_TYPE_CPU:
return 1;
default:
return 0;
}
}
QueueInfo::QueueInfo()
{
for (auto &index : family_indices)
index = VK_QUEUE_FAMILY_IGNORED;
}
bool Context::create_device(VkPhysicalDevice gpu_, VkSurfaceKHR surface, const char **required_device_extensions,
unsigned num_required_device_extensions, const char **required_device_layers,
unsigned num_required_device_layers, const VkPhysicalDeviceFeatures *required_features,
@@ -498,7 +524,19 @@ bool Context::create_device(VkPhysicalDevice gpu_, VkSurfaceKHR surface, const c
}
if (gpu == VK_NULL_HANDLE)
gpu = gpus.front();
{
unsigned max_score = 0;
// Prefer earlier entries in list.
for (size_t i = gpus.size(); i; i--)
{
unsigned score = device_score(gpus[i - 1]);
if (score >= max_score)
{
max_score = score;
gpu = gpus[i - 1];
}
}
}
}
uint32_t ext_count = 0;
@@ -551,123 +589,145 @@ bool Context::create_device(VkPhysicalDevice gpu_, VkSurfaceKHR surface, const c
LOGI("GPU supports Vulkan 1.0.\n");
}
uint32_t queue_count;
vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_count, nullptr);
vector<VkQueueFamilyProperties> queue_props(queue_count);
vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_count, queue_props.data());
uint32_t queue_family_count = 0;
if (ext.supports_vulkan_11_instance && ext.supports_vulkan_11_device)
vkGetPhysicalDeviceQueueFamilyProperties2(gpu, &queue_family_count, nullptr);
else if (ext.supports_physical_device_properties2)
vkGetPhysicalDeviceQueueFamilyProperties2KHR(gpu, &queue_family_count, nullptr);
else
vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_family_count, nullptr);
for (unsigned i = 0; i < queue_count; i++)
Util::SmallVector<VkQueueFamilyProperties> queue_props(queue_family_count);
Util::SmallVector<VkQueueFamilyProperties2> queue_props2(queue_family_count);
#ifdef GRANITE_VULKAN_BETA
Util::SmallVector<VkVideoQueueFamilyProperties2KHR> video_queue_props2(queue_family_count);
if (has_extension(VK_KHR_VIDEO_QUEUE_EXTENSION_NAME))
ext.supports_video_queue = true;
#endif
for (uint32_t i = 0; i < queue_family_count; i++)
{
VkBool32 supported = surface == VK_NULL_HANDLE;
if (surface != VK_NULL_HANDLE)
vkGetPhysicalDeviceSurfaceSupportKHR(gpu, i, surface, &supported);
static const VkQueueFlags required = VK_QUEUE_COMPUTE_BIT | VK_QUEUE_GRAPHICS_BIT;
if (supported && ((queue_props[i].queueFlags & required) == required))
queue_props2[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2;
#ifdef GRANITE_VULKAN_BETA
if (ext.supports_video_queue)
{
graphics_queue_family = i;
// XXX: This assumes timestamp valid bits is the same for all queue types.
timestamp_valid_bits = queue_props[i].timestampValidBits;
break;
queue_props2[i].pNext = &video_queue_props2[i];
video_queue_props2[i].sType = VK_STRUCTURE_TYPE_VIDEO_QUEUE_FAMILY_PROPERTIES_2_KHR;
}
#endif
}
for (unsigned i = 0; i < queue_count; i++)
{
static const VkQueueFlags required = VK_QUEUE_COMPUTE_BIT;
if (i != graphics_queue_family && (queue_props[i].queueFlags & required) == required)
{
compute_queue_family = i;
break;
}
}
Util::SmallVector<uint32_t> queue_offsets(queue_family_count);
Util::SmallVector<Util::SmallVector<float, QUEUE_INDEX_COUNT>> queue_priorities(queue_family_count);
for (unsigned i = 0; i < queue_count; i++)
{
static const VkQueueFlags required = VK_QUEUE_TRANSFER_BIT;
if (i != graphics_queue_family && i != compute_queue_family && (queue_props[i].queueFlags & required) == required)
{
transfer_queue_family = i;
break;
}
}
if (ext.supports_vulkan_11_instance && ext.supports_vulkan_11_device)
vkGetPhysicalDeviceQueueFamilyProperties2(gpu, &queue_family_count, queue_props2.data());
else if (ext.supports_physical_device_properties2)
vkGetPhysicalDeviceQueueFamilyProperties2KHR(gpu, &queue_family_count, queue_props2.data());
else
vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queue_family_count, queue_props.data());
if (transfer_queue_family == VK_QUEUE_FAMILY_IGNORED)
{
for (unsigned i = 0; i < queue_count; i++)
if ((ext.supports_vulkan_11_instance && ext.supports_vulkan_11_device) || ext.supports_physical_device_properties2)
for (uint32_t i = 0; i < queue_family_count; i++)
queue_props[i] = queue_props2[i].queueFamilyProperties;
queue_info = {};
uint32_t queue_indices[QUEUE_INDEX_COUNT] = {};
const auto find_vacant_queue = [&](uint32_t &family, uint32_t &index,
VkQueueFlags required, VkQueueFlags ignore_flags,
float priority) -> bool {
for (unsigned family_index = 0; family_index < queue_family_count; family_index++)
{
static const VkQueueFlags required = VK_QUEUE_TRANSFER_BIT;
if (i != graphics_queue_family && (queue_props[i].queueFlags & required) == required)
if ((queue_props[family_index].queueFlags & ignore_flags) != 0)
continue;
// A graphics queue candidate must support present for us to select it.
if ((required & VK_QUEUE_GRAPHICS_BIT) != 0 && surface != VK_NULL_HANDLE)
{
transfer_queue_family = i;
break;
VkBool32 supported = VK_FALSE;
if (vkGetPhysicalDeviceSurfaceSupportKHR(gpu, family_index, surface, &supported) != VK_SUCCESS || !supported)
continue;
}
if (queue_props[family_index].queueCount && (queue_props[family_index].queueFlags & required) == required)
{
family = family_index;
queue_props[family_index].queueCount--;
index = queue_offsets[family_index]++;
queue_priorities[family_index].push_back(priority);
return true;
}
}
}
if (graphics_queue_family == VK_QUEUE_FAMILY_IGNORED)
return false;
};
unsigned universal_queue_index = 1;
uint32_t graphics_queue_index = 0;
uint32_t compute_queue_index = 0;
uint32_t transfer_queue_index = 0;
if (compute_queue_family == VK_QUEUE_FAMILY_IGNORED)
if (!find_vacant_queue(queue_info.family_indices[QUEUE_INDEX_GRAPHICS],
queue_indices[QUEUE_INDEX_GRAPHICS],
VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, 0, 0.5f))
{
compute_queue_family = graphics_queue_family;
compute_queue_index = std::min(queue_props[graphics_queue_family].queueCount - 1, universal_queue_index);
universal_queue_index++;
LOGE("Could not find suitable graphics queue.\n");
return false;
}
if (transfer_queue_family == VK_QUEUE_FAMILY_IGNORED)
// XXX: This assumes timestamp valid bits is the same for all queue types.
queue_info.timestamp_valid_bits = queue_props[queue_info.family_indices[QUEUE_INDEX_GRAPHICS]].timestampValidBits;
// Prefer another graphics queue since we can do async graphics that way.
// The compute queue is to be treated as high priority since we also do async graphics on it.
if (!find_vacant_queue(queue_info.family_indices[QUEUE_INDEX_COMPUTE], queue_indices[QUEUE_INDEX_COMPUTE],
VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, 0, 1.0f) &&
!find_vacant_queue(queue_info.family_indices[QUEUE_INDEX_COMPUTE], queue_indices[QUEUE_INDEX_COMPUTE],
VK_QUEUE_COMPUTE_BIT, 0, 1.0f))
{
transfer_queue_family = graphics_queue_family;
transfer_queue_index = std::min(queue_props[graphics_queue_family].queueCount - 1, universal_queue_index);
universal_queue_index++;
// Fallback to the graphics queue if we must.
queue_info.family_indices[QUEUE_INDEX_COMPUTE] = queue_info.family_indices[QUEUE_INDEX_GRAPHICS];
queue_indices[QUEUE_INDEX_COMPUTE] = queue_indices[QUEUE_INDEX_GRAPHICS];
}
else if (transfer_queue_family == compute_queue_family)
transfer_queue_index = std::min(queue_props[compute_queue_family].queueCount - 1, 1u);
static const float graphics_queue_prio = 0.5f;
static const float compute_queue_prio = 1.0f;
static const float transfer_queue_prio = 1.0f;
float prio[3] = { graphics_queue_prio, compute_queue_prio, transfer_queue_prio };
// For transfer, try to find a queue which only supports transfer, e.g. DMA queue.
// If not, fallback to a dedicated compute queue.
// Finally, fallback to same queue as compute.
if (!find_vacant_queue(queue_info.family_indices[QUEUE_INDEX_TRANSFER], queue_indices[QUEUE_INDEX_TRANSFER],
VK_QUEUE_TRANSFER_BIT, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT, 0.5f) &&
!find_vacant_queue(queue_info.family_indices[QUEUE_INDEX_TRANSFER], queue_indices[QUEUE_INDEX_TRANSFER],
VK_QUEUE_COMPUTE_BIT, VK_QUEUE_GRAPHICS_BIT, 0.5f))
{
queue_info.family_indices[QUEUE_INDEX_TRANSFER] = queue_info.family_indices[QUEUE_INDEX_COMPUTE];
queue_indices[QUEUE_INDEX_TRANSFER] = queue_indices[QUEUE_INDEX_COMPUTE];
}
unsigned queue_family_count = 0;
VkDeviceQueueCreateInfo queue_info[3] = {};
#ifdef GRANITE_VULKAN_BETA
if (ext.supports_video_queue)
{
if (!find_vacant_queue(queue_info.family_indices[QUEUE_INDEX_VIDEO_DECODE], queue_indices[QUEUE_INDEX_VIDEO_DECODE],
VK_QUEUE_VIDEO_DECODE_BIT_KHR, 0, 0.5f))
{
queue_info.family_indices[QUEUE_INDEX_VIDEO_DECODE] = VK_QUEUE_FAMILY_IGNORED;
queue_indices[QUEUE_INDEX_VIDEO_DECODE] = UINT32_MAX;
}
}
#endif
VkDeviceCreateInfo device_info = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
device_info.pQueueCreateInfos = queue_info;
queue_info[queue_family_count].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_info[queue_family_count].queueFamilyIndex = graphics_queue_family;
queue_info[queue_family_count].queueCount = std::min(universal_queue_index,
queue_props[graphics_queue_family].queueCount);
queue_info[queue_family_count].pQueuePriorities = prio;
queue_family_count++;
if (compute_queue_family != graphics_queue_family)
Util::SmallVector<VkDeviceQueueCreateInfo> queue_infos;
for (uint32_t family_index = 0; family_index < queue_family_count; family_index++)
{
queue_info[queue_family_count].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_info[queue_family_count].queueFamilyIndex = compute_queue_family;
queue_info[queue_family_count].queueCount = std::min(transfer_queue_family == compute_queue_family ? 2u : 1u,
queue_props[compute_queue_family].queueCount);
queue_info[queue_family_count].pQueuePriorities = prio + 1;
queue_family_count++;
}
if (queue_offsets[family_index] == 0)
continue;
if (transfer_queue_family != graphics_queue_family && transfer_queue_family != compute_queue_family)
{
queue_info[queue_family_count].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_info[queue_family_count].queueFamilyIndex = transfer_queue_family;
queue_info[queue_family_count].queueCount = 1;
queue_info[queue_family_count].pQueuePriorities = prio + 2;
queue_family_count++;
VkDeviceQueueCreateInfo info = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO };
info.queueFamilyIndex = family_index;
info.queueCount = queue_offsets[family_index];
info.pQueuePriorities = queue_priorities[family_index].data();
queue_infos.push_back(info);
}
device_info.queueCreateInfoCount = queue_family_count;
device_info.pQueueCreateInfos = queue_infos.data();
device_info.queueCreateInfoCount = uint32_t(queue_infos.size());
vector<const char *> enabled_extensions;
vector<const char *> enabled_layers;
@@ -806,6 +866,32 @@ bool Context::create_device(VkPhysicalDevice gpu_, VkSurfaceKHR surface, const c
ext.supports_conservative_rasterization = true;
}
#ifdef GRANITE_VULKAN_BETA
if (has_extension(VK_KHR_VIDEO_QUEUE_EXTENSION_NAME))
{
enabled_extensions.push_back(VK_KHR_VIDEO_QUEUE_EXTENSION_NAME);
ext.supports_video_queue = true;
if (has_extension(VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME))
{
enabled_extensions.push_back(VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME);
ext.supports_video_decode_queue = true;
if (has_extension(VK_EXT_VIDEO_DECODE_H264_EXTENSION_NAME))
{
enabled_extensions.push_back(VK_EXT_VIDEO_DECODE_H264_EXTENSION_NAME);
if (queue_info.family_indices[QUEUE_INDEX_VIDEO_DECODE] != VK_QUEUE_FAMILY_IGNORED)
{
ext.supports_video_decode_h264 =
(video_queue_props2[queue_info.family_indices[QUEUE_INDEX_VIDEO_DECODE]].videoCodecOperations &
VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_EXT) != 0;
}
}
}
}
#endif
VkPhysicalDeviceFeatures2KHR features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR };
ext.storage_8bit_features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR };
ext.storage_16bit_features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR };
@@ -822,6 +908,9 @@ bool Context::create_device(VkPhysicalDevice gpu_, VkSurfaceKHR surface, const c
ext.performance_query_features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR };
ext.sampler_ycbcr_conversion_features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR };
ext.memory_priority_features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT };
ext.astc_decode_features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT };
ext.astc_hdr_features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES_EXT };
ext.sync2_features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR };
void **ppNext = &features.pNext;
bool has_pdf2 = ext.supports_physical_device_properties2 ||
@@ -899,19 +988,7 @@ bool Context::create_device(VkPhysicalDevice gpu_, VkSurfaceKHR surface, const c
ppNext = &ext.ubo_std430_features.pNext;
}
#ifdef VULKAN_DEBUG
bool use_timeline_semaphore = force_no_validation;
if (const char *use_timeline = getenv("GRANITE_VULKAN_FORCE_TIMELINE_SEMAPHORE"))
{
if (strtol(use_timeline, nullptr, 0) != 0)
use_timeline_semaphore = true;
}
#elif defined(ANDROID)
constexpr bool use_timeline_semaphore = false;
#else
constexpr bool use_timeline_semaphore = true;
#endif
if (use_timeline_semaphore && has_extension(VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME))
if (has_extension(VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME))
{
enabled_extensions.push_back(VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME);
*ppNext = &ext.timeline_semaphore_features;
@@ -955,6 +1032,29 @@ bool Context::create_device(VkPhysicalDevice gpu_, VkSurfaceKHR surface, const c
enabled_extensions.push_back(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME);
ext.supports_memory_budget = true;
}
if (has_extension(VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME))
{
ext.supports_astc_decode_mode = true;
enabled_extensions.push_back(VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME);
*ppNext = &ext.astc_decode_features;
ppNext = &ext.astc_decode_features.pNext;
}
if (has_extension(VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_EXTENSION_NAME))
{
enabled_extensions.push_back(VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_EXTENSION_NAME);
*ppNext = &ext.astc_hdr_features;
ppNext = &ext.astc_hdr_features.pNext;
}
if (has_extension(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME))
{
ext.supports_sync2 = true;
enabled_extensions.push_back(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME);
*ppNext = &ext.sync2_features;
ppNext = &ext.sync2_features.pNext;
}
}
if (ext.supports_vulkan_11_device && ext.supports_vulkan_11_instance)
@@ -1007,6 +1107,9 @@ bool Context::create_device(VkPhysicalDevice gpu_, VkSurfaceKHR surface, const c
if (features.features.shaderStorageImageArrayDynamicIndexing)
enabled_features.shaderStorageImageArrayDynamicIndexing = VK_TRUE;
if (features.features.samplerAnisotropy)
enabled_features.samplerAnisotropy = VK_TRUE;
features.features = enabled_features;
ext.enabled_features = enabled_features;
}
@@ -1090,9 +1193,26 @@ bool Context::create_device(VkPhysicalDevice gpu_, VkSurfaceKHR surface, const c
return false;
volkLoadDeviceTable(&device_table, device);
device_table.vkGetDeviceQueue(device, graphics_queue_family, graphics_queue_index, &graphics_queue);
device_table.vkGetDeviceQueue(device, compute_queue_family, compute_queue_index, &compute_queue);
device_table.vkGetDeviceQueue(device, transfer_queue_family, transfer_queue_index, &transfer_queue);
for (int i = 0; i < QUEUE_INDEX_COUNT; i++)
{
if (queue_info.family_indices[i] != VK_QUEUE_FAMILY_IGNORED)
{
device_table.vkGetDeviceQueue(device, queue_info.family_indices[i], queue_indices[i],
&queue_info.queues[i]);
}
else
{
queue_info.queues[i] = VK_NULL_HANDLE;
}
}
#ifdef VULKAN_DEBUG
static const char *family_names[QUEUE_INDEX_COUNT] = { "Graphics", "Compute", "Transfer", "Video decode" };
for (int i = 0; i < QUEUE_INDEX_COUNT; i++)
if (queue_info.family_indices[i] != VK_QUEUE_FAMILY_IGNORED)
LOGI("%s queue: family %u, index %u.\n", family_names[i], queue_info.family_indices[i], queue_indices[i]);
#endif
check_descriptor_indexing_features();