1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-09 13:22:24 +03:00
Files
occt/src/Vulkan/Vulkan_Device.cxx

853 lines
32 KiB
C++

// Copyright (c) 2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#if defined(_WIN32)
#include <windows.h>
#define VK_USE_PLATFORM_WIN32_KHR 1
#endif
#include <Vulkan_Device.hxx>
#include <Message.hxx>
#include <Message_Messenger.hxx>
#include <NCollection_Map.hxx>
#include <Vulkan_Caps.hxx>
#include <Vulkan_FrameStats.hxx>
#include <TColStd_PackedMapOfInteger.hxx>
#include <vulkan/vulkan.h>
#include <vector>
IMPLEMENT_STANDARD_RTTIEXT(Vulkan_Device, Standard_Transient)
namespace
{
//! Return object type.
static TCollection_AsciiString debugVkObjectType (VkDebugReportObjectTypeEXT theObjectType)
{
switch (theObjectType)
{
case VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT:
return "UNKNOWN";
case VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT:
return "Instance";
case VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT:
return "Physical device";
case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT:
return "Device";
case VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT:
return "Queue";
case VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT:
return "Semaphore";
case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT:
return "Command Buffer";
case VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT:
return "Fence";
case VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT:
return "Device memory";
case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT:
return "Buffer";
case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT:
return "Image";
case VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT:
return "Event";
case VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT:
return "Query pool";
case VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT:
return "Buffer view";
case VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT:
return "Image view";
case VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT:
return "Shader module";
case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT:
return "Pipeline cache";
case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT:
return "Pipeline layout";
case VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT:
return "Render pass";
case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT:
return "Pipeline";
case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT:
return "Descriptor set layout";
case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT:
return "Sampler";
case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT:
return "Descriptor pool";
case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT:
return "Descriptor set";
case VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT:
return "Framebuffer";
case VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT:
return "Command pool";
case VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT:
return "Surface";
case VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT:
return "Swapchain";
case VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT:
return "Debug report";
case VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT:
return "Display";
case VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT:
return "Display mode";
case VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT:
return "Object table";
case VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT:
return "Indirect commands layout";
case VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT:
return "Validation cache";
case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT:
return "Sampler YCBCR conversion";
case VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT:
return "Descriptor update template";
case VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT:
return "Acceleration structure";
default:
return TCollection_AsciiString ("Unknown #") + (int )theObjectType;
}
}
//! Format physical device type.
static const char* formatVkDeviceType (VkPhysicalDeviceType theType)
{
switch (theType)
{
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: return "Integrated GPU";
case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: return "Discrete GPU";
case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: return "Virtual GPU";
case VK_PHYSICAL_DEVICE_TYPE_CPU: return "CPU";
default:
return "UNKNOWN";
}
}
//! Return physical device priority.
static int fastestVkDeviceType (VkPhysicalDeviceType theType)
{
switch (theType)
{
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: return 2;
case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: return 3;
case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: return 1;
case VK_PHYSICAL_DEVICE_TYPE_CPU: return 0;
default:
return 0;
}
}
//! Return message type.
static const char* debugVkMessageType (VkDebugReportFlagsEXT theFlags)
{
if ((theFlags & VkDebugReportFlagBitsEXT::VK_DEBUG_REPORT_ERROR_BIT_EXT) != 0)
{
return "Error";
}
if ((theFlags & VkDebugReportFlagBitsEXT::VK_DEBUG_REPORT_WARNING_BIT_EXT) != 0)
{
return "Warning";
}
if ((theFlags & VkDebugReportFlagBitsEXT::VK_DEBUG_REPORT_INFORMATION_BIT_EXT) != 0)
{
return "Info";
}
if ((theFlags & VkDebugReportFlagBitsEXT::VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) != 0)
{
return "Performance";
}
if ((theFlags & VkDebugReportFlagBitsEXT::VK_DEBUG_REPORT_DEBUG_BIT_EXT) != 0)
{
return "Debug";
}
return "";
}
//! Vulkan debug callback redirection to Message::DefaultMessenger().
static VkBool32 VKAPI_CALL debugVkCallback (VkDebugReportFlagsEXT theFlags,
VkDebugReportObjectTypeEXT theObjectType,
uint64_t theObject,
size_t theLocation,
int32_t theMessageCode,
const char* theLayerPrefix,
const char* theMessage,
void* theUserData)
{
(void )theUserData;
(void )theObject;
(void )theLocation;
Message_Gravity aGrav = (theFlags & VkDebugReportFlagBitsEXT::VK_DEBUG_REPORT_ERROR_BIT_EXT) != 0
? Message_Alarm
: ((theFlags & VkDebugReportFlagBitsEXT::VK_DEBUG_REPORT_WARNING_BIT_EXT) != 0
? Message_Warning
: Message_Info);
const TCollection_AsciiString aLayer = theLayerPrefix;
if (aLayer == "Loader Message"
&& theObjectType == VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT
&& (theFlags & VkDebugReportFlagBitsEXT::VK_DEBUG_REPORT_INFORMATION_BIT_EXT) != 0)
{
return VK_FALSE;
}
TCollection_AsciiString aMsg;
aMsg += "TKVulkan."; aMsg += aLayer;
aMsg += " | Type: "; aMsg += debugVkMessageType (theFlags);
aMsg += " | ID: "; aMsg += theMessageCode;
//aMsg += " | Location: "; aMsg += (int )theLocation;
aMsg += " | Object: "; aMsg += debugVkObjectType (theObjectType);
aMsg += " | Message:\n ";
aMsg += theMessage;
Message::DefaultMessenger()->Send (aMsg, aGrav);
return VK_FALSE;
}
//! Add key-value pair to the dictionary.
static void addInfo (TColStd_IndexedDataMapOfStringString& theDict,
const TCollection_AsciiString& theKey,
const TCollection_AsciiString& theValue)
{
theDict.ChangeFromIndex (theDict.Add (theKey, theValue)) = theValue;
}
}
// =======================================================================
// function : FormatVkError
// purpose :
// =======================================================================
TCollection_AsciiString Vulkan_Device::FormatVkError (int theErr)
{
switch (theErr)
{
case VK_SUCCESS:
return "Success";
case VK_NOT_READY:
return "Not ready";
case VK_TIMEOUT:
return "Timeout";
case VK_EVENT_SET:
return "Event set";
case VK_EVENT_RESET:
return "Event reset";
case VK_INCOMPLETE:
return "Incomplete";
case VK_ERROR_OUT_OF_HOST_MEMORY:
return "Error, out of host memory";
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
return "Error, out of device memory";
case VK_ERROR_INITIALIZATION_FAILED:
return "Error, initialization failed";
case VK_ERROR_DEVICE_LOST:
return "Error, device lost";
case VK_ERROR_MEMORY_MAP_FAILED:
return "Error, memory map failed";
case VK_ERROR_LAYER_NOT_PRESENT:
return "Error, layer not present";
case VK_ERROR_EXTENSION_NOT_PRESENT:
return "Error, extension not present";
case VK_ERROR_FEATURE_NOT_PRESENT:
return "Error, feature not present";
case VK_ERROR_INCOMPATIBLE_DRIVER:
return "Error, incompatible driver";
case VK_ERROR_TOO_MANY_OBJECTS:
return "Error, too many objects";
case VK_ERROR_FORMAT_NOT_SUPPORTED:
return "Error, format not supported";
case VK_ERROR_FRAGMENTED_POOL:
return "Error, fragmented pool";
case VK_ERROR_OUT_OF_POOL_MEMORY:
return "Error, out of pool memory";
case VK_ERROR_INVALID_EXTERNAL_HANDLE:
return "Error, invalid external handle";
case VK_ERROR_SURFACE_LOST_KHR:
return "Error, surface lost";
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
return "Error, native window in use";
case VK_SUBOPTIMAL_KHR:
return "Error, suboptimal";
case VK_ERROR_OUT_OF_DATE_KHR:
return "Error, out of date";
case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
return "Error, incompatible display";
case VK_ERROR_VALIDATION_FAILED_EXT:
return "Error, validation failed";
case VK_ERROR_INVALID_SHADER_NV:
return "Error, invalid shader";
case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT:
return "Error, invalid DRM format";
case VK_ERROR_FRAGMENTATION_EXT:
return "Error, fragmentation";
case VK_ERROR_NOT_PERMITTED_EXT:
return "Error, not permitted";
case VK_ERROR_INVALID_DEVICE_ADDRESS_EXT:
return "Error, invalid device address";
default:
return TCollection_AsciiString("Error #") + theErr;
}
}
// =======================================================================
// function : Vulkan_Device
// purpose :
// =======================================================================
Vulkan_Device::Vulkan_Device (const TCollection_AsciiString& theAppName,
const uint32_t theAppVersion,
const TCollection_AsciiString& theEngineName,
const uint32_t theEngineVersion)
: myAppName (theAppName),
myEngineName (theEngineName),
myAppVersion (theAppVersion),
myEngineVersion (theEngineVersion),
myVkInstance (NULL),
myVkDevice (NULL),
myVkDeviceMemory (new VkPhysicalDeviceMemoryProperties()),
myFrameStats (new Vulkan_FrameStats()),
myIsOwnContext (false)
{
memset (myVkDeviceMemory.get(), 0, sizeof(VkPhysicalDeviceMemoryProperties));
}
// =======================================================================
// function : ~Vulkan_Device
// purpose :
// =======================================================================
Vulkan_Device::~Vulkan_Device()
{
Release();
}
// =======================================================================
// function : Release
// purpose :
// =======================================================================
void Vulkan_Device::Release()
{
myIsOwnContext = Standard_False;
memset (myVkDeviceMemory.get(), 0, sizeof(VkPhysicalDeviceMemoryProperties));
}
// =======================================================================
// function : Init
// purpose :
// =======================================================================
bool Vulkan_Device::Init (const Handle(Vulkan_Caps)& theCaps)
{
Release();
myIsOwnContext = true;
Handle(Vulkan_Caps) aCaps = theCaps;
if (aCaps.IsNull())
{
aCaps = new Vulkan_Caps();
}
NCollection_Map<TCollection_AsciiString, TCollection_AsciiString> anAllLayers;
{
uint32_t aNbLayers = 0;
if (vkEnumerateInstanceLayerProperties (&aNbLayers, NULL) == VK_SUCCESS
&& aNbLayers != 0)
{
std::vector<VkLayerProperties> aLayers (aNbLayers);
if (vkEnumerateInstanceLayerProperties (&aNbLayers, aLayers.data()) == VK_SUCCESS)
{
for (uint32_t aLayerIter = 0; aLayerIter < aNbLayers; ++aLayerIter)
{
const VkLayerProperties& aLayerProps = aLayers[aLayerIter];
anAllLayers.Add (aLayerProps.layerName);
}
}
}
}
NCollection_Map<TCollection_AsciiString, TCollection_AsciiString> anAllInstExtensions;
{
uint32_t aNbExts = 0;
if (vkEnumerateInstanceExtensionProperties (NULL, &aNbExts, NULL) == VK_SUCCESS
&& aNbExts != 0)
{
std::vector<VkExtensionProperties> anExts (aNbExts);
if (vkEnumerateInstanceExtensionProperties (NULL, &aNbExts, anExts.data()) == VK_SUCCESS)
{
for (uint32_t anExtIter = 0; anExtIter < aNbExts; ++anExtIter)
{
const VkExtensionProperties& anExtProps = anExts[anExtIter];
anAllInstExtensions.Add (anExtProps.extensionName);
}
}
}
}
// layers should be the same for instance and for device, while extensions may differ
std::vector<const char*> aLayers, anInstExtensions;
anInstExtensions.push_back (VK_KHR_SURFACE_EXTENSION_NAME);
#ifdef _WIN32
anInstExtensions.push_back (VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#endif
if (aCaps->contextDebug)
{
if (anAllInstExtensions.Contains (VK_EXT_DEBUG_REPORT_EXTENSION_NAME))
{
anInstExtensions.push_back (VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
}
// VK_LAYER_LUNARG_standard_validation is a meta layer enabling several standard validation layers (LunarG SDK):
// - VK_LAYER_GOOGLE_threading, VK_LAYER_GOOGLE_unique_objects,
// VK_LAYER_LUNARG_parameter_validation, VK_LAYER_LUNARG_core_validation,
// VK_LAYER_LUNARG_device_limits, VK_LAYER_LUNARG_image,
// VK_LAYER_LUNARG_object_tracker, VK_LAYER_LUNARG_swapchain
if (anAllLayers.Contains ("VK_LAYER_LUNARG_standard_validation"))
{
aLayers.push_back ("VK_LAYER_LUNARG_standard_validation");
}
//aLayers.push_back ("VK_LAYER_GOOGLE_threading"); // validate usage from multiple threads
//aLayers.push_back ("VK_LAYER_GOOGLE_unique_objects");
//aLayers.push_back ("VK_LAYER_LUNARG_parameter_validation"); // validate API parameter values
//aLayers.push_back ("VK_LAYER_LUNARG_core_validation");
//aLayers.push_back ("VK_LAYER_LUNARG_device_limits"); // detects missing device limits checks
//aLayers.push_back ("VK_LAYER_LUNARG_image"); // validate texture/render formats
//aLayers.push_back ("VK_LAYER_LUNARG_object_tracker"); // detect usage of invalid objects
//aLayers.push_back ("VK_LAYER_LUNARG_swapchain"); // validate usage of swapchain extensions
// trace API calls
//if (anAllLayers.Contains ("VK_LAYER_LUNARG_api_dump"))
//{
// aLayers.push_back ("VK_LAYER_LUNARG_api_dump");
//}
// dump frames to image files
//if (anAllLayers.Contains ("VK_LAYER_LUNARG_screenshot"))
//{
// aLayers.push_back ("VK_LAYER_LUNARG_screenshot");
//}
}
//aLayers.push_back ("VK_LAYER_NV_optimus");
//aLayers.push_back ("VK_LAYER_VALVE_steam_overlay");
VkApplicationInfo anAppInfo;
anAppInfo.sType = VkStructureType::VK_STRUCTURE_TYPE_APPLICATION_INFO;
anAppInfo.pNext = NULL;
anAppInfo.pApplicationName = myAppName.ToCString();
anAppInfo.applicationVersion = myAppVersion;
anAppInfo.pEngineName = myEngineName.ToCString();
anAppInfo.engineVersion = myEngineVersion;
anAppInfo.apiVersion = VK_MAKE_VERSION(1, 0, 21);
VkInstanceCreateInfo anInstInfo;
anInstInfo.sType = VkStructureType::VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
anInstInfo.pNext = NULL;
anInstInfo.flags = 0;
anInstInfo.pApplicationInfo = &anAppInfo;
anInstInfo.enabledLayerCount = (uint32_t )aLayers.size();
anInstInfo.ppEnabledLayerNames = aLayers.data();
anInstInfo.enabledExtensionCount = (uint32_t )anInstExtensions.size();
anInstInfo.ppEnabledExtensionNames = anInstExtensions.data();
VkResult aRes = vkCreateInstance (&anInstInfo, NULL, &myVkInstance);
if (aRes != VkResult::VK_SUCCESS)
{
Message::DefaultMessenger()->Send (TCollection_AsciiString ("Vulkan_Device, unable creating Vulkan instance: ") + FormatVkError (aRes), Message_Fail);
return false;
}
if (aCaps->contextDebug)
{
if (PFN_vkCreateDebugReportCallbackEXT aVkCreateDebugCallback = (PFN_vkCreateDebugReportCallbackEXT )vkGetInstanceProcAddr (myVkInstance, "vkCreateDebugReportCallbackEXT"))
{
VkDebugReportCallbackCreateInfoEXT aCallbackInfo;
aCallbackInfo.sType = VkStructureType::VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
aCallbackInfo.pNext = NULL;
aCallbackInfo.flags = VkDebugReportFlagBitsEXT::VK_DEBUG_REPORT_INFORMATION_BIT_EXT
| VkDebugReportFlagBitsEXT::VK_DEBUG_REPORT_WARNING_BIT_EXT
| VkDebugReportFlagBitsEXT::VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT
| VkDebugReportFlagBitsEXT::VK_DEBUG_REPORT_ERROR_BIT_EXT
| VkDebugReportFlagBitsEXT::VK_DEBUG_REPORT_DEBUG_BIT_EXT;
aCallbackInfo.pfnCallback = debugVkCallback;
aCallbackInfo.pUserData = NULL;
VkDebugReportCallbackEXT aDebReportObj = NULL;
aRes = aVkCreateDebugCallback (myVkInstance, &aCallbackInfo, NULL, &aDebReportObj);
if (aRes != VkResult::VK_SUCCESS)
{
Message::DefaultMessenger()->Send (TCollection_AsciiString ("Vulkan_Device, unable registering debug report callback: ") + FormatVkError (aRes), Message_Warning);
}
}
}
{
uint32_t aNbDevices = 0;
aRes = vkEnumeratePhysicalDevices (myVkInstance, &aNbDevices, NULL);
if (aRes != VkResult::VK_SUCCESS
|| aNbDevices == 0)
{
Message::DefaultMessenger()->Send (TCollection_AsciiString ("Vulkan_Device, unable to list physical devices: ") + FormatVkError (aRes), Message_Warning);
return false;
}
std::vector<VkPhysicalDevice> aDevices (aNbDevices);
aRes = vkEnumeratePhysicalDevices (myVkInstance, &aNbDevices, aDevices.data());
if (aRes != VkResult::VK_SUCCESS)
{
Message::DefaultMessenger()->Send (TCollection_AsciiString ("Vulkan_Device, unable to list physical devices: ") + FormatVkError (aRes), Message_Warning);
return false;
}
myVkPhysDevice = aDevices[0];
int aSelPriority = aCaps->contextNoAccel ? IntegerLast() : -IntegerLast();
TCollection_AsciiString aDevNameToFind = aCaps->contextDevice;
aDevNameToFind.LowerCase();
if (aDevNameToFind.IsIntegerValue()
&& aDevNameToFind.IntegerValue() >= 0
&& aDevNameToFind.IntegerValue() < (int )aNbDevices)
{
myVkPhysDevice = aDevices[aDevNameToFind.IntegerValue()];
}
else
{
uint32_t aVendorToFind = 0;
if (aDevNameToFind == "amd")
{
aVendorToFind = VendorId_AMD;
aDevNameToFind.Clear();
}
else if (aDevNameToFind == "nvidia")
{
aVendorToFind = VendorId_NVIDIA;
aDevNameToFind.Clear();
}
else if (aDevNameToFind == "intel")
{
aVendorToFind = VendorId_INTEL;
aDevNameToFind.Clear();
}
for (uint32_t aDevIter = 0; aDevIter < aNbDevices; ++aDevIter)
{
const VkPhysicalDevice& aPhysDev = aDevices[aDevIter];
VkPhysicalDeviceProperties aDevProps;
memset (&aDevProps, 0, sizeof(aDevProps));
vkGetPhysicalDeviceProperties (aPhysDev, &aDevProps);
if (!aDevNameToFind.IsEmpty())
{
TCollection_AsciiString aName (aDevProps.deviceName);
aName.LowerCase();
if (aName.Search (aDevNameToFind) != -1)
{
myVkPhysDevice = aDevices[aDevIter];
break;
}
}
else if (aVendorToFind != 0
&& aDevProps.vendorID == aVendorToFind)
{
myVkPhysDevice = aDevices[aDevIter];
break;
}
const int aPriority = fastestVkDeviceType (aDevProps.deviceType);
if (aCaps->contextNoAccel)
{
if (aPriority < aSelPriority)
{
aSelPriority = aPriority;
myVkPhysDevice = aDevices[aDevIter];
}
}
else
{
if (aPriority > aSelPriority)
{
aSelPriority = aPriority;
myVkPhysDevice = aDevices[aDevIter];
}
}
}
}
}
NCollection_Map<TCollection_AsciiString, TCollection_AsciiString> anAllDevExtensions;
{
uint32_t aNbExts = 0;
if (vkEnumerateDeviceExtensionProperties (myVkPhysDevice, NULL, &aNbExts, NULL) == VK_SUCCESS
&& aNbExts != 0)
{
std::vector<VkExtensionProperties> anExts (aNbExts);
if (vkEnumerateDeviceExtensionProperties (myVkPhysDevice, NULL, &aNbExts, anExts.data()) == VK_SUCCESS)
{
for (uint32_t anExtIter = 0; anExtIter < aNbExts; ++anExtIter)
{
const VkExtensionProperties& anExtProps = anExts[anExtIter];
anAllDevExtensions.Add (anExtProps.extensionName);
}
}
}
}
std::vector<const char*> aDevExtensions;
aDevExtensions.push_back (VK_KHR_SWAPCHAIN_EXTENSION_NAME);
std::vector<VkQueueFamilyProperties> aPhysDevQueueFamilyProps;
{
uint32_t aNbProps = 0;
vkGetPhysicalDeviceQueueFamilyProperties (myVkPhysDevice, &aNbProps, NULL);
if (aNbProps != 0)
{
aPhysDevQueueFamilyProps.resize (aNbProps);
vkGetPhysicalDeviceQueueFamilyProperties (myVkPhysDevice, &aNbProps, aPhysDevQueueFamilyProps.data());
}
}
{
std::vector<VkDeviceQueueCreateInfo> aDevQueueInfos (1);
std::vector< std::vector<float> > aDevQueuesPriorities (aDevQueueInfos.size(), std::vector<float> (1, 0.0f));
for (uint32_t aQueueIter = 0; aQueueIter < (uint32_t )aDevQueueInfos.size(); ++aQueueIter)
{
std::vector<float>& aDevQueuePriorities = aDevQueuesPriorities[aQueueIter];
VkDeviceQueueCreateInfo& aDevQueueInfo = aDevQueueInfos[aQueueIter];
aDevQueueInfo.sType = VkStructureType::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
aDevQueueInfo.pNext = NULL;
aDevQueueInfo.flags = 0;
aDevQueueInfo.queueFamilyIndex = aQueueIter;
aDevQueueInfo.queueCount = (uint32_t )aDevQueuePriorities.size();
aDevQueueInfo.pQueuePriorities = aDevQueuePriorities.data();
}
VkPhysicalDeviceFeatures aPhysDevFeatures;
memset (&aPhysDevFeatures, 0, sizeof(aPhysDevFeatures));
VkDeviceCreateInfo aDevInfo;
aDevInfo.sType = VkStructureType::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
aDevInfo.pNext = NULL;
aDevInfo.flags = 0;
aDevInfo.queueCreateInfoCount = (uint32_t )aDevQueueInfos.size();
aDevInfo.pQueueCreateInfos = aDevQueueInfos.data();
aDevInfo.enabledLayerCount = (uint32_t )aLayers.size();
aDevInfo.ppEnabledLayerNames = aLayers.data();
aDevInfo.enabledExtensionCount = (uint32_t )aDevExtensions.size();
aDevInfo.ppEnabledExtensionNames = aDevExtensions.data();
aDevInfo.pEnabledFeatures = &aPhysDevFeatures;
aRes = vkCreateDevice (myVkPhysDevice, &aDevInfo, NULL, &myVkDevice);
if (aRes != VkResult::VK_SUCCESS)
{
Message::DefaultMessenger()->Send (TCollection_AsciiString ("Vulkan_Device, unable to create device: ") + FormatVkError (aRes), Message_Warning);
return false;
}
}
vkGetPhysicalDeviceMemoryProperties (myVkPhysDevice, myVkDeviceMemory.get());
return true;
}
// =======================================================================
// function : AllocateDeviceMemory
// purpose :
// =======================================================================
VkDeviceMemory Vulkan_Device::AllocateDeviceMemory (const VkMemoryRequirements& theReqs)
{
if (myVkInstance == NULL)
{
return NULL;
}
VkMemoryAllocateInfo aVkAllocInfo;
aVkAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
aVkAllocInfo.pNext = NULL;
aVkAllocInfo.allocationSize = theReqs.size;
aVkAllocInfo.memoryTypeIndex = uint32_t(-1);
for (uint32_t aTypeIter = 0; aTypeIter < myVkDeviceMemory->memoryTypeCount; ++aTypeIter)
{
const uint32_t aBit = (uint32_t(1) << aTypeIter);
if ((theReqs.memoryTypeBits & aBit) != 0)
{
if ((myVkDeviceMemory->memoryTypes[aTypeIter].propertyFlags & VkMemoryPropertyFlagBits::VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
{
aVkAllocInfo.memoryTypeIndex = aTypeIter;
break;
}
}
}
if (aVkAllocInfo.memoryTypeIndex == uint32_t(-1))
{
Message::DefaultMessenger()->Send (TCollection_AsciiString ("Vulkan_Device, failed to get correct memory type"), Message_Fail);
return NULL;
}
VkDeviceMemory aVkDevMem = NULL;
VkResult aRes = vkAllocateMemory (myVkDevice, &aVkAllocInfo, myVkHostAllocator.get(), &aVkDevMem);
if (aRes != VkResult::VK_SUCCESS)
{
Message::DefaultMessenger()->Send (TCollection_AsciiString ("Vulkan_Device, failed to allocate device memory [")
+ int(theReqs.size) + "]:" + FormatVkError (aRes), Message_Fail);
return NULL;
}
return aVkDevMem;
}
// =======================================================================
// function : DiagnosticInformation
// purpose :
// =======================================================================
void Vulkan_Device::DiagnosticInformation (TColStd_IndexedDataMapOfStringString& theDict,
Graphic3d_DiagnosticInfo theFlags) const
{
if (myVkInstance == NULL)
{
return;
}
uint32_t aNbDevices = 0;
if (vkEnumeratePhysicalDevices (myVkInstance, &aNbDevices, NULL) == VkResult::VK_SUCCESS
&& aNbDevices > 1)
{
std::vector<VkPhysicalDevice> aDevices (aNbDevices);
if (vkEnumeratePhysicalDevices (myVkInstance, &aNbDevices, aDevices.data()) == VkResult::VK_SUCCESS)
{
TCollection_AsciiString aDevListStr;
for (uint32_t aDevIter = 0; aDevIter < aNbDevices; ++aDevIter)
{
const VkPhysicalDevice& aPhysDev = aDevices[aDevIter];
VkPhysicalDeviceProperties aDevProps;
memset (&aDevProps, 0, sizeof(aDevProps));
vkGetPhysicalDeviceProperties (aPhysDev, &aDevProps);
aDevListStr += aDevProps.deviceName;
aDevListStr += " ";
}
addInfo (theDict, "VKDeviceList", aDevListStr);
}
}
if (myVkPhysDevice != NULL
&& (theFlags & Graphic3d_DiagnosticInfo_Device) != 0)
{
VkPhysicalDeviceProperties aDevProps;
memset (&aDevProps, 0, sizeof(aDevProps));
vkGetPhysicalDeviceProperties (myVkPhysDevice, &aDevProps);
addInfo (theDict, "VKDevice", aDevProps.deviceName);
addInfo (theDict, "VKDeviceType", formatVkDeviceType (aDevProps.deviceType));
TCollection_AsciiString aVendor (int(aDevProps.vendorID));
switch ((int )aDevProps.vendorID)
{
case VendorId_AMD: aVendor = "AMD"; break;
case VendorId_NVIDIA: aVendor = "NVIDIA"; break;
case VendorId_INTEL: aVendor = "INTEL"; break;
}
addInfo (theDict, "VKDeviceVendor", aVendor);
}
if ((theFlags & Graphic3d_DiagnosticInfo_Extensions) != 0)
{
TCollection_AsciiString aLayerStr;
uint32_t aNbLayers = 0;
if ((theFlags & Graphic3d_DiagnosticInfo_NativePlatform) != 0
&& vkEnumerateInstanceLayerProperties (&aNbLayers, NULL) == VK_SUCCESS
&& aNbLayers != 0)
{
std::vector<VkLayerProperties> aLayers (aNbLayers);
if (vkEnumerateInstanceLayerProperties (&aNbLayers, aLayers.data()) == VK_SUCCESS)
{
for (uint32_t aLayerIter = 0; aLayerIter < aNbLayers; ++aLayerIter)
{
const VkLayerProperties& aLayerProps = aLayers[aLayerIter];
aLayerStr += aLayerProps.layerName;
aLayerStr += " ";
}
addInfo (theDict, "VKLayers", aLayerStr);
}
}
TCollection_AsciiString anInstExtsStr;
uint32_t aNbExts = 0;
if ((theFlags & Graphic3d_DiagnosticInfo_NativePlatform) != 0
&& vkEnumerateInstanceExtensionProperties (NULL, &aNbExts, NULL) == VK_SUCCESS
&& aNbExts != 0)
{
std::vector<VkExtensionProperties> anExts (aNbExts);
if (vkEnumerateInstanceExtensionProperties (NULL, &aNbExts, anExts.data()) == VK_SUCCESS)
{
for (uint32_t anExtIter = 0; anExtIter < aNbExts; ++anExtIter)
{
const VkExtensionProperties& anExtProps = anExts[anExtIter];
anInstExtsStr += anExtProps.extensionName;
anInstExtsStr += " ";
}
addInfo (theDict, "VKExtensions", anInstExtsStr);
}
}
TCollection_AsciiString aDevExtsStr;
if (myVkPhysDevice != NULL
&& (theFlags & Graphic3d_DiagnosticInfo_Device) != 0
&& vkEnumerateDeviceExtensionProperties (myVkPhysDevice, NULL, &aNbExts, NULL) == VK_SUCCESS
&& aNbExts != 0)
{
std::vector<VkExtensionProperties> anExts (aNbExts);
if (vkEnumerateDeviceExtensionProperties (myVkPhysDevice, NULL, &aNbExts, anExts.data()) == VK_SUCCESS)
{
for (uint32_t anExtIter = 0; anExtIter < aNbExts; ++anExtIter)
{
const VkExtensionProperties& anExtProps = anExts[anExtIter];
aDevExtsStr += anExtProps.extensionName;
aDevExtsStr += " ";
}
addInfo (theDict, "VKDeviceExtensions", aDevExtsStr);
}
}
}
if (myVkPhysDevice != NULL
&& (theFlags & Graphic3d_DiagnosticInfo_Limits) != 0)
{
VkPhysicalDeviceProperties aProps;
memset (&aProps, 0, sizeof(aProps));
vkGetPhysicalDeviceProperties (myVkPhysDevice, &aProps);
const VkPhysicalDeviceLimits& aLimits = aProps.limits;
addInfo (theDict, "Max texture size", TCollection_AsciiString((int )aLimits.maxImageDimension2D));
addInfo (theDict, "Max FBO dump size", TCollection_AsciiString() + int(aLimits.maxFramebufferWidth) + "x" + int(aLimits.maxFramebufferHeight));
}
if (myVkPhysDevice != NULL
&& (theFlags & Graphic3d_DiagnosticInfo_Memory) != 0)
{
uint64_t aDedicated = 0;
int aNbDedicatedHeaps = 0;
TCollection_AsciiString aDedicatedHeaps;
TColStd_PackedMapOfInteger aDedicatedHeapsMap;
for (uint32_t aTypeIter = 0; aTypeIter < myVkDeviceMemory->memoryTypeCount; ++aTypeIter)
{
const VkMemoryType& aMemInfo = myVkDeviceMemory->memoryTypes[aTypeIter];
if ((aMemInfo.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == 0)
{
continue;
}
if (aDedicatedHeapsMap.Add (aMemInfo.heapIndex))
{
const VkMemoryHeap& aHeap = myVkDeviceMemory->memoryHeaps[aMemInfo.heapIndex];
aDedicated += aHeap.size;
if (!aDedicatedHeaps.IsEmpty())
{
aDedicatedHeaps += ", ";
}
aDedicatedHeaps += TCollection_AsciiString(int(aHeap.size / (1024 * 1024))) + " MiB";
++aNbDedicatedHeaps;
}
}
if (aDedicated != 0)
{
addInfo (theDict, "GPU memory", TCollection_AsciiString() + int(aDedicated / (1024 * 1024)) + " MiB");
if (aNbDedicatedHeaps > 1)
{
addInfo (theDict, "GPU heaps", aDedicatedHeaps);
}
}
}
}