]> git.tdb.fi Git - libs/gui.git/commitdiff
Rearrange VulkanContext to share common code between platforms
authorMikko Rasa <tdb@tdb.fi>
Sat, 6 Jan 2024 17:53:57 +0000 (19:53 +0200)
committerMikko Rasa <tdb@tdb.fi>
Sat, 6 Jan 2024 17:55:26 +0000 (19:55 +0200)
source/graphics/vkxlib/vulkancontext.cpp
source/graphics/vkxlib/vulkancontext_platform.h
source/graphics/vulkancontext.cpp
source/graphics/vulkancontext.h
source/graphics/vulkancontext_private.h [new file with mode: 0644]

index c3a7d761a1969601e8fe9ddfdf213b5c158de901..9b147d9715acb70712416886232cb273f5b56e24 100644 (file)
 #include "vulkancontext.h"
-#include "vulkancontext_platform.h"
-#include <stdexcept>
-#include <vector>
-#define VK_USE_PLATFORM_XLIB_KHR
-#include <vulkan/vulkan.h>
-#include <msp/core/application.h>
-#include <msp/debug/debugapi.h>
-#include <msp/io/print.h>
+#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<VkResult>(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<PFN_vkCreateInstance>("vkCreateInstance");
-
-               vector<const char *> layers;
-               if(opts.enable_validation)
-                       layers.push_back("VK_LAYER_KHRONOS_validation");
-
-               vector<const char *> 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<PFN_vkDestroyInstance>("vkDestroyInstance");
-               f.vkEnumeratePhysicalDevices = get_function<PFN_vkEnumeratePhysicalDevices>("vkEnumeratePhysicalDevices");
-               f.vkGetPhysicalDeviceQueueFamilyProperties = get_function<PFN_vkGetPhysicalDeviceQueueFamilyProperties>("vkGetPhysicalDeviceQueueFamilyProperties");
-               f.vkGetPhysicalDeviceSurfaceSupport = get_function<PFN_vkGetPhysicalDeviceSurfaceSupportKHR>("vkGetPhysicalDeviceSurfaceSupportKHR");
-               f.vkCreateDevice = get_function<PFN_vkCreateDevice>("vkCreateDevice");
-               f.vkDestroyDevice = get_function<PFN_vkDestroyDevice>("vkDestroyDevice");
-               f.vkGetDeviceQueue = get_function<PFN_vkGetDeviceQueue>("vkGetDeviceQueue");
-               f.vkCreateXlibSurface = get_function<PFN_vkCreateXlibSurfaceKHR>("vkCreateXlibSurfaceKHR");
-               f.vkDestroySurface = get_function<PFN_vkDestroySurfaceKHR>("vkDestroySurfaceKHR");
-               f.vkCreateDebugReportCallback = get_function<PFN_vkCreateDebugReportCallbackEXT>("vkCreateDebugReportCallbackEXT");
-               f.vkDestroyDebugReportCallback = get_function<PFN_vkDestroyDebugReportCallbackEXT>("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<VkPhysicalDevice> 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<n_phys_devices; ++i)
-               {
-                       VkPhysicalDevice phys_device = phys_devices[i];
-
-                       unsigned n_queue_families = 0;
-                       f.vkGetPhysicalDeviceQueueFamilyProperties(phys_device, &n_queue_families, nullptr);
-                       vector<VkQueueFamilyProperties> queue_family_props(n_queue_families);
-                       f.vkGetPhysicalDeviceQueueFamilyProperties(phys_device, &n_queue_families, queue_family_props.data());
-
-                       for(; gfx_queue_index<n_queue_families; ++gfx_queue_index)
-                               if((queue_family_props[gfx_queue_index].queueFlags&VK_QUEUE_GRAPHICS_BIT))
-                                       break;
-
-                       if(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
-
index 888557e1fe2e39b92ac786d07bd3fc0d7939dfc4..9aaf59d14d8445719c8a4eda070354e547d62292 100644 (file)
@@ -3,39 +3,13 @@
 
 #define VK_USE_PLATFORM_XLIB_KHR
 #include <vulkan/vulkan.h>
-#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
index fcb6ca22d7332ef6f7cb251c2c3d7968a1072ab0..9bd00fa4a2b64156f6e5904a5ffac87a1aeb6d50 100644 (file)
@@ -1,4 +1,9 @@
 #include "vulkancontext.h"
+#include "vulkancontext_private.h"
+#include <vector>
+#include <msp/core/application.h>
+#include <msp/debug/debugapi.h>
+#include <msp/io/print.h>
 #include <msp/strings/format.h>
 #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<VkResult>(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<PFN_vkCreateInstance>("vkCreateInstance");
+
+       vector<const char *> layers;
+       if(opts.enable_validation)
+               layers.push_back("VK_LAYER_KHRONOS_validation");
+
+       vector<const char *> 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<PFN_vkDestroyInstance>("vkDestroyInstance");
+       f.vkEnumeratePhysicalDevices = get_function<PFN_vkEnumeratePhysicalDevices>("vkEnumeratePhysicalDevices");
+       f.vkGetPhysicalDeviceQueueFamilyProperties = get_function<PFN_vkGetPhysicalDeviceQueueFamilyProperties>("vkGetPhysicalDeviceQueueFamilyProperties");
+       f.vkGetPhysicalDeviceSurfaceSupport = get_function<PFN_vkGetPhysicalDeviceSurfaceSupportKHR>("vkGetPhysicalDeviceSurfaceSupportKHR");
+       f.vkCreateDevice = get_function<PFN_vkCreateDevice>("vkCreateDevice");
+       f.vkDestroyDevice = get_function<PFN_vkDestroyDevice>("vkDestroyDevice");
+       f.vkGetDeviceQueue = get_function<PFN_vkGetDeviceQueue>("vkGetDeviceQueue");
+       f.vkCreateXlibSurface = get_function<PFN_vkCreateXlibSurfaceKHR>("vkCreateXlibSurfaceKHR");
+       f.vkDestroySurface = get_function<PFN_vkDestroySurfaceKHR>("vkDestroySurfaceKHR");
+       f.vkCreateDebugReportCallback = get_function<PFN_vkCreateDebugReportCallbackEXT>("vkCreateDebugReportCallbackEXT");
+       f.vkDestroyDebugReportCallback = get_function<PFN_vkDestroyDebugReportCallbackEXT>("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<VkPhysicalDevice> 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<n_phys_devices; ++i)
+       {
+               VkPhysicalDevice phys_device = phys_devices[i];
+
+               unsigned n_queue_families = 0;
+               f.vkGetPhysicalDeviceQueueFamilyProperties(phys_device, &n_queue_families, nullptr);
+               vector<VkQueueFamilyProperties> queue_family_props(n_queue_families);
+               f.vkGetPhysicalDeviceQueueFamilyProperties(phys_device, &n_queue_families, queue_family_props.data());
+
+               for(; gfx_queue_index<n_queue_families; ++gfx_queue_index)
+                       if((queue_family_props[gfx_queue_index].queueFlags&VK_QUEUE_GRAPHICS_BIT))
+                               break;
+
+               if(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<const char *> 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
 
index 6d210e2338f293f68ed4c2b35120072b4d753a46..8bcb459a5543856c218944977553ea90bf2b05ca 100644 (file)
@@ -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 (file)
index 0000000..945f9d6
--- /dev/null
@@ -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