Professional Documents
Culture Documents
NVVK RTX On
NVVK RTX On
* are met:
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
*/
#include <algorithm>
#include <nvh/nvprint.hpp>
#include <regex>
#include "context_vk.hpp"
#include "error_vk.hpp"
#include "extensions_vk.hpp"
#include <nvvk/debug_util_vk.hpp>
namespace nvvk {
switch(value)
case VK_OBJECT_TYPE_UNKNOWN:
return "Unknown";
case VK_OBJECT_TYPE_INSTANCE:
return "Instance";
case VK_OBJECT_TYPE_PHYSICAL_DEVICE:
return "PhysicalDevice";
case VK_OBJECT_TYPE_DEVICE:
return "Device";
case VK_OBJECT_TYPE_QUEUE:
return "Queue";
case VK_OBJECT_TYPE_SEMAPHORE:
return "Semaphore";
case VK_OBJECT_TYPE_COMMAND_BUFFER:
return "CommandBuffer";
case VK_OBJECT_TYPE_FENCE:
return "Fence";
case VK_OBJECT_TYPE_DEVICE_MEMORY:
return "DeviceMemory";
case VK_OBJECT_TYPE_BUFFER:
return "Buffer";
case VK_OBJECT_TYPE_IMAGE:
return "Image";
case VK_OBJECT_TYPE_EVENT:
return "Event";
case VK_OBJECT_TYPE_QUERY_POOL:
return "QueryPool";
case VK_OBJECT_TYPE_BUFFER_VIEW:
return "BufferView";
case VK_OBJECT_TYPE_IMAGE_VIEW:
return "ImageView";
case VK_OBJECT_TYPE_SHADER_MODULE:
return "ShaderModule";
case VK_OBJECT_TYPE_PIPELINE_CACHE:
return "PipelineCache";
case VK_OBJECT_TYPE_PIPELINE_LAYOUT:
return "PipelineLayout";
case VK_OBJECT_TYPE_RENDER_PASS:
return "RenderPass";
case VK_OBJECT_TYPE_PIPELINE:
return "Pipeline";
case VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT:
return "DescriptorSetLayout";
case VK_OBJECT_TYPE_SAMPLER:
return "Sampler";
case VK_OBJECT_TYPE_DESCRIPTOR_POOL:
return "DescriptorPool";
case VK_OBJECT_TYPE_DESCRIPTOR_SET:
return "DescriptorSet";
case VK_OBJECT_TYPE_FRAMEBUFFER:
return "Framebuffer";
case VK_OBJECT_TYPE_COMMAND_POOL:
return "CommandPool";
case VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION:
return "SamplerYcbcrConversion";
case VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE:
return "DescriptorUpdateTemplate";
case VK_OBJECT_TYPE_SURFACE_KHR:
return "SurfaceKHR";
case VK_OBJECT_TYPE_SWAPCHAIN_KHR:
return "SwapchainKHR";
case VK_OBJECT_TYPE_DISPLAY_KHR:
return "DisplayKHR";
case VK_OBJECT_TYPE_DISPLAY_MODE_KHR:
return "DisplayModeKHR";
case VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT:
return "DebugReportCallbackEXT";
#if VK_NV_device_generated_commands
case VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NV:
return "IndirectCommandsLayoutNV";
#endif
case VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT:
return "DebugUtilsMessengerEXT";
case VK_OBJECT_TYPE_VALIDATION_CACHE_EXT:
return "ValidationCacheEXT";
#if VK_NV_ray_tracing
case VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV:
return "AccelerationStructureNV";
#endif
default:
return "invalid";
VkDebugUtilsMessageTypeFlagsEXT messageType,
void* userData)
if(ctx->m_dbgIgnoreMessages.find(callbackData->messageIdNumber) != ctx-
>m_dbgIgnoreMessages.end())
return VK_FALSE;
// repeating nvprintfLevel to help with breakpoints : so we can selectively break right after the print
{
nvprintfLevel(level, "VERBOSE: %s \n --> %s\n", callbackData->pMessageIdName, callbackData-
>pMessage);
level = LOGLEVEL_WARNING;
level = LOGLEVEL_ERROR;
else
}
// this seems redundant with the info already in callbackData->pMessage
#if 0
if(callbackData->objectCount > 0)
LOGI(" Object[%d] - Type %s, Value %p, Name \"%s\"\n", object, otype.c_str(),
(void*)(callbackData->pObjects[object].objectHandle), callbackData-
>pObjects[object].pObjectName);
if(callbackData->cmdBufLabelCount > 0)
callbackData->pCmdBufLabels[label].color[0], callbackData->pCmdBufLabels[label].color[1],
callbackData->pCmdBufLabels[label].color[2], callbackData->pCmdBufLabels[label].color[3]);
#endif
return VK_FALSE;
//--------------------------------------------------------------------------------------------------
// Create the Vulkan instance and then first compatible device based on \p info
//
if(!initInstance(info))
return false;
if(compatibleDevices.empty())
return false;
//--------------------------------------------------------------------------------------------------
//
VkApplicationInfo applicationInfo{VK_STRUCTURE_TYPE_APPLICATION_INFO};
applicationInfo.pApplicationName = info.appTitle;
applicationInfo.pEngineName = info.appEngine;
uint32_t count = 0;
if(info.verboseUsed)
uint32_t version;
NVVK_CHECK(result);
LOGI("_______________\n");
LOGI("Vulkan Version:\n");
return false;
if(info.verboseAvailable)
LOGI("___________________________\n");
for(auto it : layerProperties)
std::vector<void*> featureStructs;
return false;
if(info.verboseAvailable)
LOGI("\n");
for(auto it : extensionProperties)
}
if(info.verboseUsed)
LOGI("______________________\n");
for(auto it : m_usedInstanceLayers)
LOGI("%s\n", it);
LOGI("\n");
for(auto it : m_usedInstanceExtensions)
LOGI("%s\n", it);
VkInstanceCreateInfo instanceCreateInfo{VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO};
instanceCreateInfo.pApplicationInfo = &applicationInfo;
instanceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(m_usedInstanceExtensions.size());
instanceCreateInfo.ppEnabledExtensionNames = m_usedInstanceExtensions.data();
instanceCreateInfo.enabledLayerCount = static_cast<uint32_t>(m_usedInstanceLayers.size());
instanceCreateInfo.ppEnabledLayerNames = m_usedInstanceLayers.data();
instanceCreateInfo.pNext = info.instanceCreateInfoExt;
if(strcmp(it, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0)
{
initDebugUtils();
break;
return true;
//--------------------------------------------------------------------------------------------------
assert(m_instance != nullptr);
VkPhysicalDeviceGroupProperties physicalGroup;
if(info.useDeviceGroups)
physicalGroup = groups[deviceIndex];
m_physicalDevice = physicalGroup.physicalDevices[0];
else
m_physicalDevice = physicalDevices[deviceIndex];
}
// features
VkPhysicalDeviceFeatures2 features2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
Features11Old features11old;
features2.features = m_physicalInfo.features10;
features11old.read(m_physicalInfo.features11);
features2.pNext = &features11old.multiview;
features2.pNext = &m_physicalInfo.features11;
m_physicalInfo.features11.pNext = &m_physicalInfo.features12;
m_physicalInfo.features12.pNext = nullptr;
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
std::vector<float> priorities;
std::vector<void*> featureStructs;
{
for(auto& it : m_physicalInfo.queueProperties)
queueFamilyGeneralPurpose = true;
priorities.resize(it.queueCount, 1.0f);
VkDeviceQueueCreateInfo queueInfo{VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO};
queueInfo.queueFamilyIndex = i;
queueInfo.queueCount = m_physicalInfo.queueProperties[i].queueCount;
queueInfo.pQueuePriorities = priorities.data();
queueCreateInfos.push_back(queueInfo);
if(!queueFamilyGeneralPurpose)
LOGW("could not find queue that supports graphics, compute and transfer");
}
// allow all queues
VkDeviceCreateInfo deviceCreateInfo{VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO};
deviceCreateInfo.queueCreateInfoCount = (uint32_t)queueCreateInfos.size();
deviceCreateInfo.pQueueCreateInfos = queueCreateInfos.data();
if(info.verboseAvailable)
LOGI("_____________________________\n");
for(auto it : extensionProperties)
deinit();
return false;
if(info.verboseUsed)
LOGI("________________________\n");
LOGI("Used Device Extensions :\n");
for(auto it : m_usedDeviceExtensions)
LOGI("%s\n", it);
LOGI("\n");
VkStructureType sType;
void* pNext;
};
if(!featureStructs.empty())
while(lastCoreFeature->pNext != nullptr)
lastCoreFeature = (ExtensionHeader*)lastCoreFeature->pNext;
}
lastCoreFeature->pNext = featureStructs[0];
// query support
vkGetPhysicalDeviceFeatures2(m_physicalDevice, &features2);
if(info.disableRobustBufferAccess)
features2.features.robustBufferAccess = VK_FALSE;
deviceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(m_usedDeviceExtensions.size());
deviceCreateInfo.ppEnabledExtensionNames = m_usedDeviceExtensions.data();
// Vulkan >= 1.1 uses pNext to enable features, and not pEnabledFeatures
deviceCreateInfo.pEnabledFeatures = nullptr;
deviceCreateInfo.pNext = &features2;
VkDeviceGroupDeviceCreateInfo
deviceGroupCreateInfo{VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO};
if(info.useDeviceGroups)
deviceGroupCreateInfo.pNext = deviceCreateInfo.pNext;
deviceGroupCreateInfo.physicalDeviceCount = uint32_t(physicalGroup.physicalDeviceCount);
deviceGroupCreateInfo.pPhysicalDevices = physicalGroup.physicalDevices;
deviceCreateInfo.pNext = &deviceGroupCreateInfo;
if(info.deviceCreateInfoExt)
deviceCreateChain = (ExtensionHeader*)info.deviceCreateInfoExt;
while(deviceCreateChain->pNext != nullptr)
deviceCreateChain = (ExtensionHeader*)deviceCreateChain->pNext;
deviceCreateChain->pNext = (void*)deviceCreateInfo.pNext;
deviceCreateInfo.pNext = info.deviceCreateInfoExt;
if(deviceCreateChain)
deviceCreateChain->pNext = nullptr;
if(result != VK_SUCCESS)
deinit();
return false;
}
load_VK_EXTENSION_SUBSET(m_instance, vkGetInstanceProcAddr, m_device, vkGetDeviceProcAddr);
nvvk::DebugUtil::setEnabled(has_VK_EXT_debug_utils != 0);
// Now we have the device and instance, we can initialize the debug tool
nvvk::DebugUtil debugUtil(m_device);
// Now pick 3 distinct queues for graphics, compute and transfer operations
struct QueueScore
uint32_t familyIndex;
uint32_t queueIndex;
};
std::vector<QueueScore> queueScores;
score.score++;
score.score++;
}
score.score++;
score.queueIndex = qI;
queueScores.emplace_back(score);
// Sort the queues for specialization, highest specialization has lowest score
return true;
return false;
});
{
Queue queue;
queue.familyIndex = score.familyIndex;
queue.queueIndex = score.queueIndex;
debugUtil.setObjectName(queue.queue, name);
queueScores.erase(queueScores.begin() + q);
return queue;
return Queue();
};
assert(m_queueGCT.familyIndex != ~uint32_t(0));
return true;
//--------------------------------------------------------------------------------------------------
//
{
VkQueueFlags bits = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT |
VK_QUEUE_TRANSFER_BIT;
VkBool32 supportsPresent;
vkGetDeviceQueue(m_device, i, 0, &m_queueGCT.queue);
m_queueGCT.familyIndex = i;
nvvk::DebugUtil(m_device).setObjectName(m_queueGCT.queue, "queueGCT");
return true;
return false;
// #UNSUED
uint32_t queueFamilyIndex = 0;
for(auto& it : m_physicalInfo.queueProperties)
supportsPresent = VK_FALSE;
return queueFamilyIndex;
queueFamilyIndex++;
return ~0;
//--------------------------------------------------------------------------------------------------
// Destructor
//
void Context::deinit()
if(m_device)
{
exit(-1);
vkDestroyDevice(m_device, nullptr);
m_device = VK_NULL_HANDLE;
if(m_destroyDebugUtilsMessengerEXT)
if(m_instance)
vkDestroyInstance(m_instance, nullptr);
m_instance = VK_NULL_HANDLE;
m_usedInstanceExtensions.clear();
m_usedInstanceLayers.clear();
m_usedDeviceExtensions.clear();
m_createDebugUtilsMessengerEXT = nullptr;
m_destroyDebugUtilsMessengerEXT = nullptr;
m_dbgMessenger = nullptr;
reset_VK_EXTENSION_SUBSET();
nvvk::DebugUtil::setEnabled(false);
}
if(strcmp(name, usedDeviceExtension) == 0)
return true;
return false;
if(strcmp(name, usedInstanceExtension) == 0)
return true;
return false;
//--------------------------------------------------------------------------------------------------
//
//
ContextCreateInfo::ContextCreateInfo(bool bUseValidation)
#ifdef _DEBUG
instanceExtensions.push_back({VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true});
if(bUseValidation)
instanceLayers.push_back({"VK_LAYER_KHRONOS_validation", true});
#endif
instanceExtensions.emplace_back(name, optional);
instanceLayers.emplace_back(name, optional);
//--------------------------------------------------------------------------------------------------
//
}
void ContextCreateInfo::removeInstanceExtension(const char* name)
if(strcmp(instanceExtensions[i].name, name) == 0)
instanceExtensions.erase(instanceExtensions.begin() + i);
if(strcmp(instanceLayers[i].name, name) == 0)
instanceLayers.erase(instanceLayers.begin() + i);
if(strcmp(deviceExtensions[i].name, name) == 0)
deviceExtensions.erase(deviceExtensions.begin() + i);
}
apiMajor = major;
apiMinor = minor;
if(strcmp(itr.name, property.layerName) == 0)
found = true;
break;
{
LOGW("VK_ERROR_LAYER_NOT_PRESENT: %s\n", itr.name);
return VK_ERROR_LAYER_NOT_PRESENT;
used.push_back(itr.name);
return VK_SUCCESS;
std::vector<void*>& featureStructs)
found = true;
break;
}
if(found)
used.push_back(itr.name);
if(itr.pFeatureStruct)
featureStructs.push_back(itr.pFeatureStruct);
else if(!itr.optional)
return VK_ERROR_EXTENSION_NOT_PRESENT;
return VK_SUCCESS;
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &info.memoryProperties);
uint32_t count;
info.queueProperties.resize(count);
VkPhysicalDeviceFeatures2 features2{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
VkPhysicalDeviceProperties2 properties2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
Properties11Old properties11old;
Features11Old features11old;
features2.pNext = &features11old.multiview;
properties2.pNext = &properties11old.maintenance3;
features2.pNext = &info.features11;
info.features11.pNext = &info.features12;
info.features12.pNext = nullptr;
info.properties12.driverID = VK_DRIVER_ID_NVIDIA_PROPRIETARY;
info.properties12.supportedDepthResolveModes = VK_RESOLVE_MODE_MAX_BIT;
info.properties12.supportedStencilResolveModes = VK_RESOLVE_MODE_MAX_BIT;
properties2.pNext = &info.properties11;
info.properties11.pNext = &info.properties12;
info.properties12.pNext = nullptr;
vkGetPhysicalDeviceFeatures2(physicalDevice, &features2);
vkGetPhysicalDeviceProperties2(physicalDevice, &properties2);
info.properties10 = properties2.properties;
info.features10 = features2.features;
if(versionMajor == 1 && versionMinor == 1)
properties11old.write(info.properties11);
features11old.write(info.features11);
void Context::initDebugUtils()
m_createDebugUtilsMessengerEXT =
(PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(m_instance,
"vkCreateDebugUtilsMessengerEXT");
m_destroyDebugUtilsMessengerEXT =
(PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(m_instance,
"vkDestroyDebugUtilsMessengerEXT");
// Create a Debug Utils Messenger that will trigger our callback for any warning
// or error.
if(m_createDebugUtilsMessengerEXT != nullptr)
VkDebugUtilsMessengerCreateInfoEXT dbg_messenger_create_info;
dbg_messenger_create_info.sType =
VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
dbg_messenger_create_info.pNext = nullptr;
dbg_messenger_create_info.flags = 0;
dbg_messenger_create_info.messageSeverity =
VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
| VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
dbg_messenger_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT
| VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
dbg_messenger_create_info.pfnUserCallback = debugMessengerCallback;
dbg_messenger_create_info.pUserData = this;
//--------------------------------------------------------------------------------------------------
// Returns the list of devices or groups compatible with the mandatory extensions
//
assert(m_instance != nullptr);
std::vector<int> compatibleDevices;
std::vector<VkPhysicalDeviceGroupProperties> groups;
std::vector<VkPhysicalDevice> physicalDevices;
uint32_t nbElems;
if(info.useDeviceGroups)
groups = getPhysicalDeviceGroups();
nbElems = static_cast<uint32_t>(groups.size());
else
{
physicalDevices = getPhysicalDevices();
nbElems = static_cast<uint32_t>(physicalDevices.size());
if(info.verboseCompatibleDevices)
LOGI("____________________\n");
uint32_t compatible = 0;
compatibleDevices.push_back(elemId);
if(info.verboseCompatibleDevices)
VkPhysicalDeviceProperties props;
vkGetPhysicalDeviceProperties(physicalDevice, &props);
compatible++;
else if(info.verboseCompatibleDevices)
{
VkPhysicalDeviceProperties props;
vkGetPhysicalDeviceProperties(physicalDevice, &props);
if(info.verboseCompatibleDevices)
if(compatible > 0)
LOGI("%d\n", compatible);
else
return compatibleDevices;
//--------------------------------------------------------------------------------------------------
// Return true if all extensions in info, marked as required are available on the physicalDevice
//
std::vector<VkExtensionProperties> extensionProperties;
uint32_t count;
extensionProperties.resize(count);
extensionProperties.resize(std::min(extensionProperties.size(), size_t(count)));
if(strcmp(itr.name, property.extensionName) == 0)
found = true;
break;
if(bVerbose)
{
return false;
return true;
std::vector<VkPhysicalDevice> Context::getPhysicalDevices()
uint32_t nbElems;
std::vector<VkPhysicalDevice> physicalDevices;
physicalDevices.resize(nbElems);
return physicalDevices;
std::vector<VkPhysicalDeviceGroupProperties> Context::getPhysicalDeviceGroups()
uint32_t deviceGroupCount;
std::vector<VkPhysicalDeviceGroupProperties> groups;
groups.resize(deviceGroupCount);
return groups;
}
std::vector<VkLayerProperties> Context::getInstanceLayers()
uint32_t count;
std::vector<VkLayerProperties> layerProperties;
NVVK_CHECK(vkEnumerateInstanceLayerProperties(&count, nullptr));
layerProperties.resize(count);
NVVK_CHECK(vkEnumerateInstanceLayerProperties(&count, layerProperties.data()));
layerProperties.resize(std::min(layerProperties.size(), size_t(count)));
return layerProperties;
std::vector<VkExtensionProperties> Context::getInstanceExtensions()
uint32_t count;
std::vector<VkExtensionProperties> extensionProperties;
extensionProperties.resize(count);
extensionProperties.resize(std::min(extensionProperties.size(), size_t(count)));
return extensionProperties;
uint32_t count;
std::vector<VkExtensionProperties> extensionProperties;
extensionProperties.resize(count);
NVVK_CHECK(vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &count,
extensionProperties.data()));
extensionProperties.resize(std::min(extensionProperties.size(), size_t(count)));
return extensionProperties;
} // namespace nvvk