From: Mikko Rasa Date: Sat, 6 Jan 2024 17:53:57 +0000 (+0200) Subject: Rearrange VulkanContext to share common code between platforms X-Git-Url: https://git.tdb.fi/?a=commitdiff_plain;h=928e3eda1200365ebc60179f7cf10f0eb98bac5a;p=libs%2Fgui.git Rearrange VulkanContext to share common code between platforms --- diff --git a/source/graphics/vkxlib/vulkancontext.cpp b/source/graphics/vkxlib/vulkancontext.cpp index c3a7d76..9b147d9 100644 --- a/source/graphics/vkxlib/vulkancontext.cpp +++ b/source/graphics/vkxlib/vulkancontext.cpp @@ -1,252 +1,24 @@ #include "vulkancontext.h" -#include "vulkancontext_platform.h" -#include -#include -#define VK_USE_PLATFORM_XLIB_KHR -#include -#include -#include -#include +#include "vulkancontext_private.h" #include "display_private.h" #include "window_private.h" -using namespace std; - namespace Msp { namespace Graphics { -string vulkan_error::get_error_message(unsigned code) -{ - switch(static_cast(code)) - { - 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 "out of host memory"; - case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "out of device memory"; - case VK_ERROR_INITIALIZATION_FAILED: return "initialization failed"; - case VK_ERROR_DEVICE_LOST: return "device lost"; - case VK_ERROR_MEMORY_MAP_FAILED: return "memory map failed"; - case VK_ERROR_LAYER_NOT_PRESENT: return "layer not present"; - case VK_ERROR_EXTENSION_NOT_PRESENT: return "extension not present"; - case VK_ERROR_FEATURE_NOT_PRESENT: return "feature not present"; - case VK_ERROR_INCOMPATIBLE_DRIVER: return "incompatible driver"; - case VK_ERROR_TOO_MANY_OBJECTS: return "too many objects"; - case VK_ERROR_FORMAT_NOT_SUPPORTED: return "format not supported"; - case VK_ERROR_FRAGMENTED_POOL: return "fragmented pool"; - case VK_ERROR_UNKNOWN: return "unknown"; - case VK_ERROR_OUT_OF_POOL_MEMORY: return "out of pool memory"; - case VK_ERROR_INVALID_EXTERNAL_HANDLE: return "invalidernal handle"; - case VK_ERROR_FRAGMENTATION: return "fragmentation"; - case VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS: return "invalid opaque capture address"; - case VK_ERROR_SURFACE_LOST_KHR: return "surface lost"; - case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "native window in use"; - case VK_SUBOPTIMAL_KHR: return "suboptimal"; - case VK_ERROR_OUT_OF_DATE_KHR: return "out of date"; - case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "incompatible display"; - case VK_ERROR_VALIDATION_FAILED_EXT: return "validation failed"; - case VK_ERROR_INVALID_SHADER_NV: return "invalid shader"; - case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: return "invalid drm format modifier plane layout"; - case VK_ERROR_NOT_PERMITTED_EXT: return "not permitted"; - case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT: return "full screen exclusive mode lost"; - case VK_THREAD_IDLE_KHR: return "thread idle"; - case VK_THREAD_DONE_KHR: return "thread done"; - case VK_OPERATION_DEFERRED_KHR: return "operation deferred"; - case VK_OPERATION_NOT_DEFERRED_KHR: return "operation not deferred"; - case VK_PIPELINE_COMPILE_REQUIRED_EXT: return "pipeline compile required"; - default: return format("VkResult(%d)", code); - } -} - - -void VulkanContext::platform_init(const VulkanOptions &opts) -{ - priv = new Private; - VulkanFunctions &f = priv->functions; - - try - { - f.vkCreateInstance = get_function("vkCreateInstance"); - - vector layers; - if(opts.enable_validation) - layers.push_back("VK_LAYER_KHRONOS_validation"); - - vector extensions; - extensions.push_back("VK_KHR_surface"); - extensions.push_back("VK_KHR_xlib_surface"); - extensions.push_back("VK_EXT_debug_utils"); - if(opts.enable_debug_report) - extensions.push_back("VK_EXT_debug_report"); - - VkApplicationInfo app_info = { }; - app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - app_info.pApplicationName = Application::get_name().c_str(); - app_info.pEngineName = "MSP"; - app_info.apiVersion = (1<<22)|(2<<12); - - VkInstanceCreateInfo instance_create_info = { }; - instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - instance_create_info.pApplicationInfo = &app_info; - instance_create_info.enabledLayerCount = layers.size(); - instance_create_info.ppEnabledLayerNames = layers.data(); - instance_create_info.enabledExtensionCount = extensions.size(); - instance_create_info.ppEnabledExtensionNames = extensions.data(); - - VkResult result = f.vkCreateInstance(&instance_create_info, nullptr, &priv->instance); - if(result!=VK_SUCCESS) - throw vulkan_error(result, "vkCreateInstance"); - - f.vkDestroyInstance = get_function("vkDestroyInstance"); - f.vkEnumeratePhysicalDevices = get_function("vkEnumeratePhysicalDevices"); - f.vkGetPhysicalDeviceQueueFamilyProperties = get_function("vkGetPhysicalDeviceQueueFamilyProperties"); - f.vkGetPhysicalDeviceSurfaceSupport = get_function("vkGetPhysicalDeviceSurfaceSupportKHR"); - f.vkCreateDevice = get_function("vkCreateDevice"); - f.vkDestroyDevice = get_function("vkDestroyDevice"); - f.vkGetDeviceQueue = get_function("vkGetDeviceQueue"); - f.vkCreateXlibSurface = get_function("vkCreateXlibSurfaceKHR"); - f.vkDestroySurface = get_function("vkDestroySurfaceKHR"); - f.vkCreateDebugReportCallback = get_function("vkCreateDebugReportCallbackEXT"); - f.vkDestroyDebugReportCallback = get_function("vkDestroyDebugReportCallbackEXT"); - - if(opts.enable_debug_report) - { - VkDebugReportCallbackCreateInfoEXT debug_report_create_info = { }; - debug_report_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; - debug_report_create_info.flags = VK_DEBUG_REPORT_WARNING_BIT_EXT|VK_DEBUG_REPORT_ERROR_BIT_EXT|VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT|VK_DEBUG_REPORT_INFORMATION_BIT_EXT; - debug_report_create_info.pfnCallback = &Private::debug_report_func; - debug_report_create_info.pUserData = this; - - result = f.vkCreateDebugReportCallback(priv->instance, &debug_report_create_info, nullptr, &priv->debug_report_callback); - if(result!=VK_SUCCESS) - throw vulkan_error(result, "vkCreateDebugReportCallback"); - } - - VkXlibSurfaceCreateInfoKHR surface_create_info = { }; - surface_create_info.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; - surface_create_info.dpy = display.get_private().display; - surface_create_info.window = window.get_private().window; - - result = f.vkCreateXlibSurface(priv->instance, &surface_create_info, nullptr, &priv->surface); - if(result!=VK_SUCCESS) - throw vulkan_error(result, "vkCreateXlibSurface"); - - unsigned n_phys_devices = 0; - result = f.vkEnumeratePhysicalDevices(priv->instance, &n_phys_devices, nullptr); - if(result!=VK_SUCCESS) - throw vulkan_error(result, "vkEnumeratePhysicalDevices"); - else if(!n_phys_devices) - throw runtime_error("no physical device found"); - vector phys_devices(n_phys_devices); - result = f.vkEnumeratePhysicalDevices(priv->instance, &n_phys_devices, &phys_devices[0]); - if(result!=VK_SUCCESS) - throw vulkan_error(result, "vkEnumeratePhysicalDevices"); - - unsigned gfx_queue_index = 0; - for(unsigned i=0; i queue_family_props(n_queue_families); - f.vkGetPhysicalDeviceQueueFamilyProperties(phys_device, &n_queue_families, queue_family_props.data()); - - for(; gfx_queue_index=n_queue_families) - continue; - - VkBool32 supported = VK_FALSE; - result = f.vkGetPhysicalDeviceSurfaceSupport(phys_device, gfx_queue_index, priv->surface, &supported); - if(result!=VK_SUCCESS) - continue; - - if(supported) - { - priv->physical_device = phys_device; - break; - } - } - - if(!priv->physical_device) - throw runtime_error("no usable physical devices found"); - - priv->graphics_queue_family = gfx_queue_index; - - float queue_priority = 1.0f; - VkDeviceQueueCreateInfo queue_create_info = { }; - queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queue_create_info.queueFamilyIndex = gfx_queue_index; - queue_create_info.queueCount = 1; - queue_create_info.pQueuePriorities = &queue_priority; - - extensions.clear(); - extensions.push_back("VK_KHR_swapchain"); - - VkPhysicalDeviceFeatures features = { }; - features.geometryShader = (opts.enable_geometry_shader ? VK_TRUE : VK_FALSE); - features.tessellationShader = (opts.enable_tessellation_shader ? VK_TRUE : VK_FALSE); - - VkDeviceCreateInfo device_create_info = { }; - device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - device_create_info.queueCreateInfoCount = 1; - device_create_info.pQueueCreateInfos = &queue_create_info; - device_create_info.enabledExtensionCount = extensions.size(); - device_create_info.ppEnabledExtensionNames = extensions.data(); - device_create_info.pEnabledFeatures = &features; - - result = f.vkCreateDevice(priv->physical_device, &device_create_info, nullptr, &priv->device); - if(result!=VK_SUCCESS) - throw vulkan_error(result, "vkCreateDevice"); - - f.vkGetDeviceQueue(priv->device, gfx_queue_index, 0, &priv->graphics_queue); - } - catch(...) - { - if(priv->device) - f.vkDestroyDevice(priv->device, nullptr); - if(priv->surface) - f.vkDestroySurface(priv->instance, priv->surface, nullptr); - if(priv->debug_report_callback) - f.vkDestroyDebugReportCallback(priv->instance, priv->debug_report_callback, nullptr); - if(priv->instance) - f.vkDestroyInstance(priv->instance, nullptr); - delete priv; - throw; - } -} - -VulkanContext::~VulkanContext() +void VulkanContext::init_surface() { const VulkanFunctions &f = priv->functions; - f.vkDestroyDevice(priv->device, nullptr); - f.vkDestroySurface(priv->instance, priv->surface, nullptr); - if(priv->debug_report_callback) - f.vkDestroyDebugReportCallback(priv->instance, priv->debug_report_callback, nullptr); - f.vkDestroyInstance(priv->instance, nullptr); - delete priv; -} - -void (*VulkanContext::_get_function(const string &name) const)() -{ - return vkGetInstanceProcAddr(priv->instance, name.c_str()); -} + VkXlibSurfaceCreateInfoKHR surface_create_info = { }; + surface_create_info.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; + surface_create_info.dpy = display.get_private().display; + surface_create_info.window = window.get_private().window; -VkBool32 VulkanContext::Private::debug_report_func(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT, uint64_t, size_t, int32_t, const char *, const char *message, void *) -{ - IO::print(IO::cerr, "%s\n", message); - if((flags&VK_DEBUG_REPORT_ERROR_BIT_EXT) && Debug::check_debugger()==Debug::GDB) - Debug::debug_break(); - return VK_FALSE; + VkResult result = f.vkCreateXlibSurface(priv->instance, &surface_create_info, nullptr, &priv->surface); + if(result!=VK_SUCCESS) + throw vulkan_error(result, "vkCreateXlibSurface"); } } // namespace Graphics } // namespace Msp - diff --git a/source/graphics/vkxlib/vulkancontext_platform.h b/source/graphics/vkxlib/vulkancontext_platform.h index 888557e..9aaf59d 100644 --- a/source/graphics/vkxlib/vulkancontext_platform.h +++ b/source/graphics/vkxlib/vulkancontext_platform.h @@ -3,39 +3,13 @@ #define VK_USE_PLATFORM_XLIB_KHR #include -#include "vulkancontext.h" namespace Msp { namespace Graphics { -struct VulkanFunctions +struct VulkanPlatformFunctions { - PFN_vkCreateInstance vkCreateInstance = nullptr; - PFN_vkDestroyInstance vkDestroyInstance = nullptr; - PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices = nullptr; - PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties = nullptr; - PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupport = nullptr; - PFN_vkCreateDevice vkCreateDevice = nullptr; - PFN_vkDestroyDevice vkDestroyDevice = nullptr; - PFN_vkGetDeviceQueue vkGetDeviceQueue = nullptr; PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurface = nullptr; - PFN_vkDestroySurfaceKHR vkDestroySurface = nullptr; - PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallback = nullptr; - PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallback = nullptr; -}; - -struct VulkanContext::Private -{ - VulkanFunctions functions; - VkInstance instance = nullptr; - VkPhysicalDevice physical_device = nullptr; - VkDevice device = nullptr; - unsigned graphics_queue_family = 0; - VkQueue graphics_queue = nullptr; - VkSurfaceKHR surface = nullptr; - VkDebugReportCallbackEXT debug_report_callback = nullptr; - - static VkBool32 debug_report_func(VkDebugReportFlagsEXT, VkDebugReportObjectTypeEXT, uint64_t, size_t, int32_t, const char *, const char *, void *); }; } // namespace Graphics diff --git a/source/graphics/vulkancontext.cpp b/source/graphics/vulkancontext.cpp index fcb6ca2..9bd00fa 100644 --- a/source/graphics/vulkancontext.cpp +++ b/source/graphics/vulkancontext.cpp @@ -1,4 +1,9 @@ #include "vulkancontext.h" +#include "vulkancontext_private.h" +#include +#include +#include +#include #include #include "window.h" @@ -11,31 +16,271 @@ vulkan_error::vulkan_error(unsigned code, const char *function): runtime_error(format("%s failed: %s", function, get_error_message(code))) { } +#ifdef WITH_VULKAN +string vulkan_error::get_error_message(unsigned code) +{ + switch(static_cast(code)) + { + 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 "out of host memory"; + case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "out of device memory"; + case VK_ERROR_INITIALIZATION_FAILED: return "initialization failed"; + case VK_ERROR_DEVICE_LOST: return "device lost"; + case VK_ERROR_MEMORY_MAP_FAILED: return "memory map failed"; + case VK_ERROR_LAYER_NOT_PRESENT: return "layer not present"; + case VK_ERROR_EXTENSION_NOT_PRESENT: return "extension not present"; + case VK_ERROR_FEATURE_NOT_PRESENT: return "feature not present"; + case VK_ERROR_INCOMPATIBLE_DRIVER: return "incompatible driver"; + case VK_ERROR_TOO_MANY_OBJECTS: return "too many objects"; + case VK_ERROR_FORMAT_NOT_SUPPORTED: return "format not supported"; + case VK_ERROR_FRAGMENTED_POOL: return "fragmented pool"; + case VK_ERROR_UNKNOWN: return "unknown"; + case VK_ERROR_OUT_OF_POOL_MEMORY: return "out of pool memory"; + case VK_ERROR_INVALID_EXTERNAL_HANDLE: return "invalidernal handle"; + case VK_ERROR_FRAGMENTATION: return "fragmentation"; + case VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS: return "invalid opaque capture address"; + case VK_ERROR_SURFACE_LOST_KHR: return "surface lost"; + case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "native window in use"; + case VK_SUBOPTIMAL_KHR: return "suboptimal"; + case VK_ERROR_OUT_OF_DATE_KHR: return "out of date"; + case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "incompatible display"; + case VK_ERROR_VALIDATION_FAILED_EXT: return "validation failed"; + case VK_ERROR_INVALID_SHADER_NV: return "invalid shader"; + case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: return "invalid drm format modifier plane layout"; + case VK_ERROR_NOT_PERMITTED_EXT: return "not permitted"; + case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT: return "full screen exclusive mode lost"; + case VK_THREAD_IDLE_KHR: return "thread idle"; + case VK_THREAD_DONE_KHR: return "thread done"; + case VK_OPERATION_DEFERRED_KHR: return "operation deferred"; + case VK_OPERATION_NOT_DEFERRED_KHR: return "operation not deferred"; + case VK_PIPELINE_COMPILE_REQUIRED_EXT: return "pipeline compile required"; + default: return format("VkResult(%d)", code); + } +} + + VulkanContext::VulkanContext(Window &w, const VulkanOptions &opts): display(w.get_display()), - window(w) + window(w), + priv(new Private) { - platform_init(opts); + VulkanFunctions &f = priv->functions; + + try + { + init_instance(opts); + init_surface(); + init_device(opts); + } + catch(...) + { + if(priv->device) + f.vkDestroyDevice(priv->device, nullptr); + if(priv->surface) + f.vkDestroySurface(priv->instance, priv->surface, nullptr); + if(priv->debug_report_callback) + f.vkDestroyDebugReportCallback(priv->instance, priv->debug_report_callback, nullptr); + if(priv->instance) + f.vkDestroyInstance(priv->instance, nullptr); + delete priv; + throw; + } +} + +void VulkanContext::init_instance(const VulkanOptions &opts) +{ + VulkanFunctions &f = priv->functions; + + f.vkCreateInstance = get_function("vkCreateInstance"); + + vector layers; + if(opts.enable_validation) + layers.push_back("VK_LAYER_KHRONOS_validation"); + + vector extensions; + extensions.push_back("VK_KHR_surface"); + extensions.push_back("VK_KHR_xlib_surface"); + extensions.push_back("VK_EXT_debug_utils"); + if(opts.enable_debug_report) + extensions.push_back("VK_EXT_debug_report"); + + VkApplicationInfo app_info = { }; + app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + app_info.pApplicationName = Application::get_name().c_str(); + app_info.pEngineName = "MSP"; + app_info.apiVersion = (1<<22)|(2<<12); + + VkInstanceCreateInfo instance_create_info = { }; + instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + instance_create_info.pApplicationInfo = &app_info; + instance_create_info.enabledLayerCount = layers.size(); + instance_create_info.ppEnabledLayerNames = layers.data(); + instance_create_info.enabledExtensionCount = extensions.size(); + instance_create_info.ppEnabledExtensionNames = extensions.data(); + + VkResult result = f.vkCreateInstance(&instance_create_info, nullptr, &priv->instance); + if(result!=VK_SUCCESS) + throw vulkan_error(result, "vkCreateInstance"); + + f.vkDestroyInstance = get_function("vkDestroyInstance"); + f.vkEnumeratePhysicalDevices = get_function("vkEnumeratePhysicalDevices"); + f.vkGetPhysicalDeviceQueueFamilyProperties = get_function("vkGetPhysicalDeviceQueueFamilyProperties"); + f.vkGetPhysicalDeviceSurfaceSupport = get_function("vkGetPhysicalDeviceSurfaceSupportKHR"); + f.vkCreateDevice = get_function("vkCreateDevice"); + f.vkDestroyDevice = get_function("vkDestroyDevice"); + f.vkGetDeviceQueue = get_function("vkGetDeviceQueue"); + f.vkCreateXlibSurface = get_function("vkCreateXlibSurfaceKHR"); + f.vkDestroySurface = get_function("vkDestroySurfaceKHR"); + f.vkCreateDebugReportCallback = get_function("vkCreateDebugReportCallbackEXT"); + f.vkDestroyDebugReportCallback = get_function("vkDestroyDebugReportCallbackEXT"); + + if(opts.enable_debug_report) + { + VkDebugReportCallbackCreateInfoEXT debug_report_create_info = { }; + debug_report_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; + debug_report_create_info.flags = VK_DEBUG_REPORT_WARNING_BIT_EXT|VK_DEBUG_REPORT_ERROR_BIT_EXT|VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT|VK_DEBUG_REPORT_INFORMATION_BIT_EXT; + debug_report_create_info.pfnCallback = &Private::debug_report_func; + debug_report_create_info.pUserData = this; + + result = f.vkCreateDebugReportCallback(priv->instance, &debug_report_create_info, nullptr, &priv->debug_report_callback); + if(result!=VK_SUCCESS) + throw vulkan_error(result, "vkCreateDebugReportCallback"); + } } -#ifndef WITH_VULKAN +void VulkanContext::init_device(const VulkanOptions &opts) +{ + const VulkanFunctions &f = priv->functions; + + unsigned n_phys_devices = 0; + VkResult result = f.vkEnumeratePhysicalDevices(priv->instance, &n_phys_devices, nullptr); + if(result!=VK_SUCCESS) + throw vulkan_error(result, "vkEnumeratePhysicalDevices"); + else if(!n_phys_devices) + throw runtime_error("no physical device found"); + vector phys_devices(n_phys_devices); + result = f.vkEnumeratePhysicalDevices(priv->instance, &n_phys_devices, &phys_devices[0]); + if(result!=VK_SUCCESS) + throw vulkan_error(result, "vkEnumeratePhysicalDevices"); + + unsigned gfx_queue_index = 0; + for(unsigned i=0; i queue_family_props(n_queue_families); + f.vkGetPhysicalDeviceQueueFamilyProperties(phys_device, &n_queue_families, queue_family_props.data()); + + for(; gfx_queue_index=n_queue_families) + continue; + + VkBool32 supported = VK_FALSE; + result = f.vkGetPhysicalDeviceSurfaceSupport(phys_device, gfx_queue_index, priv->surface, &supported); + if(result!=VK_SUCCESS) + continue; + + if(supported) + { + priv->physical_device = phys_device; + break; + } + } + + if(!priv->physical_device) + throw runtime_error("no usable physical devices found"); + + priv->graphics_queue_family = gfx_queue_index; + + float queue_priority = 1.0f; + VkDeviceQueueCreateInfo queue_create_info = { }; + queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queue_create_info.queueFamilyIndex = gfx_queue_index; + queue_create_info.queueCount = 1; + queue_create_info.pQueuePriorities = &queue_priority; + + vector extensions; + extensions.push_back("VK_KHR_swapchain"); + + VkPhysicalDeviceFeatures features = { }; + features.geometryShader = (opts.enable_geometry_shader ? VK_TRUE : VK_FALSE); + features.tessellationShader = (opts.enable_tessellation_shader ? VK_TRUE : VK_FALSE); + + VkDeviceCreateInfo device_create_info = { }; + device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + device_create_info.queueCreateInfoCount = 1; + device_create_info.pQueueCreateInfos = &queue_create_info; + device_create_info.enabledExtensionCount = extensions.size(); + device_create_info.ppEnabledExtensionNames = extensions.data(); + device_create_info.pEnabledFeatures = &features; + + result = f.vkCreateDevice(priv->physical_device, &device_create_info, nullptr, &priv->device); + if(result!=VK_SUCCESS) + throw vulkan_error(result, "vkCreateDevice"); + + f.vkGetDeviceQueue(priv->device, gfx_queue_index, 0, &priv->graphics_queue); +} + +VulkanContext::~VulkanContext() +{ + const VulkanFunctions &f = priv->functions; + f.vkDestroyDevice(priv->device, nullptr); + f.vkDestroySurface(priv->instance, priv->surface, nullptr); + if(priv->debug_report_callback) + f.vkDestroyDebugReportCallback(priv->instance, priv->debug_report_callback, nullptr); + f.vkDestroyInstance(priv->instance, nullptr); + delete priv; +} + +void (*VulkanContext::_get_function(const string &name) const)() +{ + return vkGetInstanceProcAddr(priv->instance, name.c_str()); +} + + +VkBool32 VulkanContext::Private::debug_report_func(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT, uint64_t, size_t, int32_t, const char *, const char *message, void *) +{ + IO::print(IO::cerr, "%s\n", message); + if((flags&VK_DEBUG_REPORT_ERROR_BIT_EXT) && Debug::check_debugger()==Debug::GDB) + Debug::debug_break(); + return VK_FALSE; +} + + +#else string vulkan_error::get_error_message(unsigned) { return string(); } -void VulkanContext::platform_init(const VulkanOptions &) +void VulkanContext::init_instance(const VulkanOptions &) { throw runtime_error("no Vulkan support"); } +void VulkanContext::init_surface() +{ } + +void VulkanContext::init_device(const VulkanOptions &) +{ } + VulkanContext::~VulkanContext() { } void (*VulkanContext::_get_function(const string &) const)() { - return 0; + return nullptr; } #endif diff --git a/source/graphics/vulkancontext.h b/source/graphics/vulkancontext.h index 6d210e2..8bcb459 100644 --- a/source/graphics/vulkancontext.h +++ b/source/graphics/vulkancontext.h @@ -40,7 +40,9 @@ private: public: VulkanContext(Window &, const VulkanOptions & = VulkanOptions()); private: - void platform_init(const VulkanOptions &); + void init_instance(const VulkanOptions &); + void init_surface(); + void init_device(const VulkanOptions &); public: ~VulkanContext(); diff --git a/source/graphics/vulkancontext_private.h b/source/graphics/vulkancontext_private.h new file mode 100644 index 0000000..945f9d6 --- /dev/null +++ b/source/graphics/vulkancontext_private.h @@ -0,0 +1,42 @@ +#ifndef MSP_GRAPHICS_VULKANCONTEXT_PRIVATE_H_ +#define MSP_GRAPHICS_VULKANCONTEXT_PRIVATE_H_ + +#include "vulkancontext_platform.h" +#include "vulkancontext.h" + +namespace Msp { +namespace Graphics { + +struct VulkanFunctions: VulkanPlatformFunctions +{ + PFN_vkCreateInstance vkCreateInstance = nullptr; + PFN_vkDestroyInstance vkDestroyInstance = nullptr; + PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices = nullptr; + PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties = nullptr; + PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupport = nullptr; + PFN_vkCreateDevice vkCreateDevice = nullptr; + PFN_vkDestroyDevice vkDestroyDevice = nullptr; + PFN_vkGetDeviceQueue vkGetDeviceQueue = nullptr; + PFN_vkDestroySurfaceKHR vkDestroySurface = nullptr; + PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallback = nullptr; + PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallback = nullptr; +}; + +struct VulkanContext::Private +{ + VulkanFunctions functions; + VkInstance instance = nullptr; + VkPhysicalDevice physical_device = nullptr; + VkDevice device = nullptr; + unsigned graphics_queue_family = 0; + VkQueue graphics_queue = nullptr; + VkSurfaceKHR surface = nullptr; + VkDebugReportCallbackEXT debug_report_callback = nullptr; + + static VkBool32 debug_report_func(VkDebugReportFlagsEXT, VkDebugReportObjectTypeEXT, uint64_t, size_t, int32_t, const char *, const char *, void *); +}; + +} // namespace Graphics +} // namespace Msp + +#endif