|
|
|
@ -17,6 +17,7 @@ |
|
|
|
|
#include <SDL.h> |
|
|
|
|
#include <SDL_vulkan.h> |
|
|
|
|
#include <vulkan/vulkan.h> |
|
|
|
|
//#include <vulkan/vulkan_beta.h>
|
|
|
|
|
|
|
|
|
|
//#define IMGUI_UNLIMITED_FRAME_RATE
|
|
|
|
|
#ifdef _DEBUG |
|
|
|
@ -56,7 +57,40 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debug_report(VkDebugReportFlagsEXT flags, |
|
|
|
|
} |
|
|
|
|
#endif // IMGUI_VULKAN_DEBUG_REPORT
|
|
|
|
|
|
|
|
|
|
static void SetupVulkan(const char** extensions, uint32_t extensions_count) |
|
|
|
|
static bool IsExtensionAvailable(const ImVector<VkExtensionProperties>& properties, const char* extension) |
|
|
|
|
{ |
|
|
|
|
for (const VkExtensionProperties& p : properties) |
|
|
|
|
if (strcmp(p.extensionName, extension) == 0) |
|
|
|
|
return true; |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static VkPhysicalDevice SetupVulkan_SelectPhysicalDevice() |
|
|
|
|
{ |
|
|
|
|
uint32_t gpu_count; |
|
|
|
|
VkResult err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, nullptr); |
|
|
|
|
check_vk_result(err); |
|
|
|
|
IM_ASSERT(gpu_count > 0); |
|
|
|
|
|
|
|
|
|
ImVector<VkPhysicalDevice> gpus; |
|
|
|
|
gpus.resize(gpu_count); |
|
|
|
|
err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, gpus.Data); |
|
|
|
|
check_vk_result(err); |
|
|
|
|
|
|
|
|
|
// If a number >1 of GPUs got reported, find discrete GPU if present, or use first one available. This covers
|
|
|
|
|
// most common cases (multi-gpu/integrated+dedicated graphics). Handling more complicated setups (multiple
|
|
|
|
|
// dedicated GPUs) is out of scope of this sample.
|
|
|
|
|
for (VkPhysicalDevice& device : gpus) |
|
|
|
|
{ |
|
|
|
|
VkPhysicalDeviceProperties properties; |
|
|
|
|
vkGetPhysicalDeviceProperties(device, &properties); |
|
|
|
|
if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) |
|
|
|
|
return device; |
|
|
|
|
} |
|
|
|
|
return VK_NULL_HANDLE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void SetupVulkan(ImVector<const char*> instance_extensions) |
|
|
|
|
{ |
|
|
|
|
VkResult err; |
|
|
|
|
|
|
|
|
@ -64,31 +98,44 @@ static void SetupVulkan(const char** extensions, uint32_t extensions_count) |
|
|
|
|
{ |
|
|
|
|
VkInstanceCreateInfo create_info = {}; |
|
|
|
|
create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; |
|
|
|
|
create_info.enabledExtensionCount = extensions_count; |
|
|
|
|
create_info.ppEnabledExtensionNames = extensions; |
|
|
|
|
#ifdef IMGUI_VULKAN_DEBUG_REPORT |
|
|
|
|
|
|
|
|
|
// Enumerate available extensions
|
|
|
|
|
uint32_t properties_count; |
|
|
|
|
ImVector<VkExtensionProperties> properties; |
|
|
|
|
vkEnumerateInstanceExtensionProperties(nullptr, &properties_count, nullptr); |
|
|
|
|
properties.resize(properties_count); |
|
|
|
|
err = vkEnumerateInstanceExtensionProperties(nullptr, &properties_count, properties.Data); |
|
|
|
|
check_vk_result(err); |
|
|
|
|
|
|
|
|
|
// Enable required extensions
|
|
|
|
|
if (IsExtensionAvailable(properties, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) |
|
|
|
|
instance_extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); |
|
|
|
|
#ifdef VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME |
|
|
|
|
if (IsExtensionAvailable(properties, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME)) |
|
|
|
|
{ |
|
|
|
|
instance_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); |
|
|
|
|
create_info.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
// Enabling validation layers
|
|
|
|
|
#ifdef IMGUI_VULKAN_DEBUG_REPORT |
|
|
|
|
const char* layers[] = { "VK_LAYER_KHRONOS_validation" }; |
|
|
|
|
create_info.enabledLayerCount = 1; |
|
|
|
|
create_info.ppEnabledLayerNames = layers; |
|
|
|
|
|
|
|
|
|
// Enable debug report extension (we need additional storage, so we duplicate the user array to add our new extension to it)
|
|
|
|
|
const char** extensions_ext = (const char**)malloc(sizeof(const char*) * (extensions_count + 1)); |
|
|
|
|
memcpy(extensions_ext, extensions, extensions_count * sizeof(const char*)); |
|
|
|
|
extensions_ext[extensions_count] = "VK_EXT_debug_report"; |
|
|
|
|
create_info.enabledExtensionCount = extensions_count + 1; |
|
|
|
|
create_info.ppEnabledExtensionNames = extensions_ext; |
|
|
|
|
instance_extensions.push_back("VK_EXT_debug_report"); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
// Create Vulkan Instance
|
|
|
|
|
create_info.enabledExtensionCount = (uint32_t)instance_extensions.Size; |
|
|
|
|
create_info.ppEnabledExtensionNames = instance_extensions.Data; |
|
|
|
|
err = vkCreateInstance(&create_info, g_Allocator, &g_Instance); |
|
|
|
|
check_vk_result(err); |
|
|
|
|
free(extensions_ext); |
|
|
|
|
|
|
|
|
|
// Get the function pointer (required for any extensions)
|
|
|
|
|
// Setup the debug report callback
|
|
|
|
|
#ifdef IMGUI_VULKAN_DEBUG_REPORT |
|
|
|
|
auto vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkCreateDebugReportCallbackEXT"); |
|
|
|
|
IM_ASSERT(vkCreateDebugReportCallbackEXT != nullptr); |
|
|
|
|
|
|
|
|
|
// Setup the debug report callback
|
|
|
|
|
VkDebugReportCallbackCreateInfoEXT debug_report_ci = {}; |
|
|
|
|
debug_report_ci.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; |
|
|
|
|
debug_report_ci.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; |
|
|
|
@ -96,43 +143,11 @@ static void SetupVulkan(const char** extensions, uint32_t extensions_count) |
|
|
|
|
debug_report_ci.pUserData = nullptr; |
|
|
|
|
err = vkCreateDebugReportCallbackEXT(g_Instance, &debug_report_ci, g_Allocator, &g_DebugReport); |
|
|
|
|
check_vk_result(err); |
|
|
|
|
#else |
|
|
|
|
// Create Vulkan Instance without any debug feature
|
|
|
|
|
err = vkCreateInstance(&create_info, g_Allocator, &g_Instance); |
|
|
|
|
check_vk_result(err); |
|
|
|
|
IM_UNUSED(g_DebugReport); |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Select GPU
|
|
|
|
|
{ |
|
|
|
|
uint32_t gpu_count; |
|
|
|
|
err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, nullptr); |
|
|
|
|
check_vk_result(err); |
|
|
|
|
IM_ASSERT(gpu_count > 0); |
|
|
|
|
|
|
|
|
|
VkPhysicalDevice* gpus = (VkPhysicalDevice*)malloc(sizeof(VkPhysicalDevice) * gpu_count); |
|
|
|
|
err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, gpus); |
|
|
|
|
check_vk_result(err); |
|
|
|
|
|
|
|
|
|
// If a number >1 of GPUs got reported, find discrete GPU if present, or use first one available. This covers
|
|
|
|
|
// most common cases (multi-gpu/integrated+dedicated graphics). Handling more complicated setups (multiple
|
|
|
|
|
// dedicated GPUs) is out of scope of this sample.
|
|
|
|
|
int use_gpu = 0; |
|
|
|
|
for (int i = 0; i < (int)gpu_count; i++) |
|
|
|
|
{ |
|
|
|
|
VkPhysicalDeviceProperties properties; |
|
|
|
|
vkGetPhysicalDeviceProperties(gpus[i], &properties); |
|
|
|
|
if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) |
|
|
|
|
{ |
|
|
|
|
use_gpu = i; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
g_PhysicalDevice = gpus[use_gpu]; |
|
|
|
|
free(gpus); |
|
|
|
|
} |
|
|
|
|
// Select Physical Device (GPU)
|
|
|
|
|
g_PhysicalDevice = SetupVulkan_SelectPhysicalDevice(); |
|
|
|
|
|
|
|
|
|
// Select graphics queue family
|
|
|
|
|
{ |
|
|
|
@ -152,8 +167,20 @@ static void SetupVulkan(const char** extensions, uint32_t extensions_count) |
|
|
|
|
|
|
|
|
|
// Create Logical Device (with 1 queue)
|
|
|
|
|
{ |
|
|
|
|
int device_extension_count = 1; |
|
|
|
|
const char* device_extensions[] = { "VK_KHR_swapchain" }; |
|
|
|
|
ImVector<const char*> device_extensions; |
|
|
|
|
device_extensions.push_back("VK_KHR_swapchain"); |
|
|
|
|
|
|
|
|
|
// Enumerate physical device extension
|
|
|
|
|
uint32_t properties_count; |
|
|
|
|
ImVector<VkExtensionProperties> properties; |
|
|
|
|
vkEnumerateDeviceExtensionProperties(g_PhysicalDevice, nullptr, &properties_count, nullptr); |
|
|
|
|
properties.resize(properties_count); |
|
|
|
|
vkEnumerateDeviceExtensionProperties(g_PhysicalDevice, nullptr, &properties_count, properties.Data); |
|
|
|
|
#ifdef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME |
|
|
|
|
if (IsExtensionAvailable(properties, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)) |
|
|
|
|
device_extensions.push_back(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
const float queue_priority[] = { 1.0f }; |
|
|
|
|
VkDeviceQueueCreateInfo queue_info[1] = {}; |
|
|
|
|
queue_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; |
|
|
|
@ -164,8 +191,8 @@ static void SetupVulkan(const char** extensions, uint32_t extensions_count) |
|
|
|
|
create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; |
|
|
|
|
create_info.queueCreateInfoCount = sizeof(queue_info) / sizeof(queue_info[0]); |
|
|
|
|
create_info.pQueueCreateInfos = queue_info; |
|
|
|
|
create_info.enabledExtensionCount = device_extension_count; |
|
|
|
|
create_info.ppEnabledExtensionNames = device_extensions; |
|
|
|
|
create_info.enabledExtensionCount = (uint32_t)device_extensions.Size; |
|
|
|
|
create_info.ppEnabledExtensionNames = device_extensions.Data; |
|
|
|
|
err = vkCreateDevice(g_PhysicalDevice, &create_info, g_Allocator, &g_Device); |
|
|
|
|
check_vk_result(err); |
|
|
|
|
vkGetDeviceQueue(g_Device, g_QueueFamily, 0, &g_Queue); |
|
|
|
@ -358,12 +385,13 @@ int main(int, char**) |
|
|
|
|
// Create window with Vulkan graphics context
|
|
|
|
|
SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); |
|
|
|
|
SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+Vulkan example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags); |
|
|
|
|
|
|
|
|
|
ImVector<const char*> extensions; |
|
|
|
|
uint32_t extensions_count = 0; |
|
|
|
|
SDL_Vulkan_GetInstanceExtensions(window, &extensions_count, nullptr); |
|
|
|
|
const char** extensions = new const char*[extensions_count]; |
|
|
|
|
SDL_Vulkan_GetInstanceExtensions(window, &extensions_count, extensions); |
|
|
|
|
SetupVulkan(extensions, extensions_count); |
|
|
|
|
delete[] extensions; |
|
|
|
|
extensions.resize(extensions_count); |
|
|
|
|
SDL_Vulkan_GetInstanceExtensions(window, &extensions_count, extensions.Data); |
|
|
|
|
SetupVulkan(extensions); |
|
|
|
|
|
|
|
|
|
// Create Window Surface
|
|
|
|
|
VkSurfaceKHR surface; |
|
|
|
|