3 #define VK_USE_PLATFORM_XLIB_KHR
4 #include <vulkan/vulkan.h>
5 #include <msp/core/application.h>
6 #include <msp/io/print.h>
7 #include "display_private.h"
8 #include "vulkancontext.h"
9 #include "vulkancontext_platform.h"
10 #include "window_private.h"
17 string vulkan_error::get_error_message(unsigned code)
19 switch(static_cast<VkResult>(code))
21 case VK_SUCCESS: return "success";
22 case VK_NOT_READY: return "not ready";
23 case VK_TIMEOUT: return "timeout";
24 case VK_EVENT_SET: return "event set";
25 case VK_EVENT_RESET: return "event reset";
26 case VK_INCOMPLETE: return "incomplete";
27 case VK_ERROR_OUT_OF_HOST_MEMORY: return "out of host memory";
28 case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "out of device memory";
29 case VK_ERROR_INITIALIZATION_FAILED: return "initialization failed";
30 case VK_ERROR_DEVICE_LOST: return "device lost";
31 case VK_ERROR_MEMORY_MAP_FAILED: return "memory map failed";
32 case VK_ERROR_LAYER_NOT_PRESENT: return "layer not present";
33 case VK_ERROR_EXTENSION_NOT_PRESENT: return "extension not present";
34 case VK_ERROR_FEATURE_NOT_PRESENT: return "feature not present";
35 case VK_ERROR_INCOMPATIBLE_DRIVER: return "incompatible driver";
36 case VK_ERROR_TOO_MANY_OBJECTS: return "too many objects";
37 case VK_ERROR_FORMAT_NOT_SUPPORTED: return "format not supported";
38 case VK_ERROR_FRAGMENTED_POOL: return "fragmented pool";
39 case VK_ERROR_UNKNOWN: return "unknown";
40 case VK_ERROR_OUT_OF_POOL_MEMORY: return "out of pool memory";
41 case VK_ERROR_INVALID_EXTERNAL_HANDLE: return "invalidernal handle";
42 case VK_ERROR_FRAGMENTATION: return "fragmentation";
43 case VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS: return "invalid opaque capture address";
44 case VK_ERROR_SURFACE_LOST_KHR: return "surface lost";
45 case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "native window in use";
46 case VK_SUBOPTIMAL_KHR: return "suboptimal";
47 case VK_ERROR_OUT_OF_DATE_KHR: return "out of date";
48 case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "incompatible display";
49 case VK_ERROR_VALIDATION_FAILED_EXT: return "validation failed";
50 case VK_ERROR_INVALID_SHADER_NV: return "invalid shader";
51 case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: return "invalid drm format modifier plane layout";
52 case VK_ERROR_NOT_PERMITTED_EXT: return "not permitted";
53 case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT: return "full screen exclusive mode lost";
54 case VK_THREAD_IDLE_KHR: return "thread idle";
55 case VK_THREAD_DONE_KHR: return "thread done";
56 case VK_OPERATION_DEFERRED_KHR: return "operation deferred";
57 case VK_OPERATION_NOT_DEFERRED_KHR: return "operation not deferred";
58 case VK_PIPELINE_COMPILE_REQUIRED_EXT: return "pipeline compile required";
59 default: return format("VkResult(%d)", code);
63 VulkanOptions::VulkanOptions():
64 enable_validation(false),
65 enable_debug_report(false),
66 enable_geometry_shader(false)
70 void VulkanContext::platform_init(const VulkanOptions &opts)
73 VulkanFunctions &f = priv->functions;
77 f.vkCreateInstance = get_function<PFN_vkCreateInstance>("vkCreateInstance");
79 vector<const char *> layers;
80 if(opts.enable_validation)
81 layers.push_back("VK_LAYER_KHRONOS_validation");
83 vector<const char *> extensions;
84 extensions.push_back("VK_KHR_surface");
85 extensions.push_back("VK_KHR_xlib_surface");
86 extensions.push_back("VK_EXT_debug_utils");
87 if(opts.enable_debug_report)
88 extensions.push_back("VK_EXT_debug_report");
90 VkApplicationInfo app_info = { };
91 app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
92 app_info.pApplicationName = Application::get_name().c_str();
93 app_info.pEngineName = "MSP";
94 app_info.apiVersion = (1<<22)|(2<<12);
96 VkInstanceCreateInfo instance_create_info = { };
97 instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
98 instance_create_info.pApplicationInfo = &app_info;
99 instance_create_info.enabledLayerCount = layers.size();
100 instance_create_info.ppEnabledLayerNames = layers.data();
101 instance_create_info.enabledExtensionCount = extensions.size();
102 instance_create_info.ppEnabledExtensionNames = extensions.data();
104 VkResult result = f.vkCreateInstance(&instance_create_info, 0, &priv->instance);
105 if(result!=VK_SUCCESS)
106 throw vulkan_error(result, "vkCreateInstance");
108 f.vkDestroyInstance = get_function<PFN_vkDestroyInstance>("vkDestroyInstance");
109 f.vkEnumeratePhysicalDevices = get_function<PFN_vkEnumeratePhysicalDevices>("vkEnumeratePhysicalDevices");
110 f.vkGetPhysicalDeviceQueueFamilyProperties = get_function<PFN_vkGetPhysicalDeviceQueueFamilyProperties>("vkGetPhysicalDeviceQueueFamilyProperties");
111 f.vkGetPhysicalDeviceSurfaceSupport = get_function<PFN_vkGetPhysicalDeviceSurfaceSupportKHR>("vkGetPhysicalDeviceSurfaceSupportKHR");
112 f.vkCreateDevice = get_function<PFN_vkCreateDevice>("vkCreateDevice");
113 f.vkDestroyDevice = get_function<PFN_vkDestroyDevice>("vkDestroyDevice");
114 f.vkGetDeviceQueue = get_function<PFN_vkGetDeviceQueue>("vkGetDeviceQueue");
115 f.vkCreateXlibSurface = get_function<PFN_vkCreateXlibSurfaceKHR>("vkCreateXlibSurfaceKHR");
116 f.vkDestroySurface = get_function<PFN_vkDestroySurfaceKHR>("vkDestroySurfaceKHR");
117 f.vkCreateDebugReportCallback = get_function<PFN_vkCreateDebugReportCallbackEXT>("vkCreateDebugReportCallbackEXT");
118 f.vkDestroyDebugReportCallback = get_function<PFN_vkDestroyDebugReportCallbackEXT>("vkDestroyDebugReportCallbackEXT");
120 if(opts.enable_debug_report)
122 VkDebugReportCallbackCreateInfoEXT debug_report_create_info = { };
123 debug_report_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
124 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;
125 debug_report_create_info.pfnCallback = &Private::debug_report_func;
126 debug_report_create_info.pUserData = this;
128 result = f.vkCreateDebugReportCallback(priv->instance, &debug_report_create_info, 0, &priv->debug_report_callback);
129 if(result!=VK_SUCCESS)
130 throw vulkan_error(result, "vkCreateDebugReportCallback");
133 priv->debug_report_callback = 0;
135 VkXlibSurfaceCreateInfoKHR surface_create_info = { };
136 surface_create_info.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
137 surface_create_info.dpy = display.get_private().display;
138 surface_create_info.window = window.get_private().window;
140 result = f.vkCreateXlibSurface(priv->instance, &surface_create_info, 0, &priv->surface);
141 if(result!=VK_SUCCESS)
142 throw vulkan_error(result, "vkCreateXlibSurface");
144 unsigned n_phys_devices = 0;
145 result = f.vkEnumeratePhysicalDevices(priv->instance, &n_phys_devices, 0);
146 if(result!=VK_SUCCESS)
147 throw vulkan_error(result, "vkEnumeratePhysicalDevices");
148 else if(!n_phys_devices)
149 throw runtime_error("no physical device found");
150 vector<VkPhysicalDevice> phys_devices(n_phys_devices);
151 result = f.vkEnumeratePhysicalDevices(priv->instance, &n_phys_devices, &phys_devices[0]);
152 if(result!=VK_SUCCESS)
153 throw vulkan_error(result, "vkEnumeratePhysicalDevices");
155 priv->physical_device = 0;
156 unsigned gfx_queue_index = 0;
157 for(unsigned i=0; i<n_phys_devices; ++i)
159 VkPhysicalDevice phys_device = phys_devices[i];
161 unsigned n_queue_families = 0;
162 f.vkGetPhysicalDeviceQueueFamilyProperties(phys_device, &n_queue_families, 0);
163 vector<VkQueueFamilyProperties> queue_family_props(n_queue_families);
164 f.vkGetPhysicalDeviceQueueFamilyProperties(phys_device, &n_queue_families, queue_family_props.data());
166 for(; gfx_queue_index<n_queue_families; ++gfx_queue_index)
167 if((queue_family_props[gfx_queue_index].queueFlags&VK_QUEUE_GRAPHICS_BIT))
170 if(gfx_queue_index>=n_queue_families)
173 VkBool32 supported = VK_FALSE;
174 result = f.vkGetPhysicalDeviceSurfaceSupport(phys_device, gfx_queue_index, priv->surface, &supported);
175 if(result!=VK_SUCCESS)
180 priv->physical_device = phys_device;
185 if(!priv->physical_device)
186 throw runtime_error("no usable physical devices found");
188 priv->graphics_queue_family = gfx_queue_index;
190 float queue_priority = 1.0f;
191 VkDeviceQueueCreateInfo queue_create_info = { };
192 queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
193 queue_create_info.queueFamilyIndex = gfx_queue_index;
194 queue_create_info.queueCount = 1;
195 queue_create_info.pQueuePriorities = &queue_priority;
198 extensions.push_back("VK_KHR_swapchain");
200 VkPhysicalDeviceFeatures features = { };
201 features.geometryShader = (opts.enable_geometry_shader ? VK_TRUE : VK_FALSE);
203 VkDeviceCreateInfo device_create_info = { };
204 device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
205 device_create_info.queueCreateInfoCount = 1;
206 device_create_info.pQueueCreateInfos = &queue_create_info;
207 device_create_info.enabledExtensionCount = extensions.size();
208 device_create_info.ppEnabledExtensionNames = extensions.data();
209 device_create_info.pEnabledFeatures = &features;
211 result = f.vkCreateDevice(priv->physical_device, &device_create_info, 0, &priv->device);
212 if(result!=VK_SUCCESS)
213 throw vulkan_error(result, "vkCreateDevice");
215 f.vkGetDeviceQueue(priv->device, gfx_queue_index, 0, &priv->graphics_queue);
220 f.vkDestroyDevice(priv->device, 0);
222 f.vkDestroySurface(priv->instance, priv->surface, 0);
223 if(priv->debug_report_callback)
224 f.vkDestroyDebugReportCallback(priv->instance, priv->debug_report_callback, 0);
226 f.vkDestroyInstance(priv->instance, 0);
232 VulkanContext::~VulkanContext()
234 const VulkanFunctions &f = priv->functions;
235 f.vkDestroyDevice(priv->device, 0);
236 f.vkDestroySurface(priv->instance, priv->surface, 0);
237 if(priv->debug_report_callback)
238 f.vkDestroyDebugReportCallback(priv->instance, priv->debug_report_callback, 0);
239 f.vkDestroyInstance(priv->instance, 0);
243 void (*VulkanContext::_get_function(const std::string &name) const)()
245 return vkGetInstanceProcAddr(priv->instance, name.c_str());
249 VulkanContext::Private::Private():
254 debug_report_callback(0)
257 VkBool32 VulkanContext::Private::debug_report_func(VkDebugReportFlagsEXT, VkDebugReportObjectTypeEXT, uint64_t, size_t, int32_t, const char *, const char *message, void *)
259 IO::print(IO::cerr, "%s\n", message);
263 } // namespace Graphics