#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
-
#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
#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"
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
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();
--- /dev/null
+#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