12# include <vulkan/vulkan_win32.h>
13#elif defined(__APPLE__)
14# include <MoltenVK/vk_mvk_moltenvk.h>
17# include <vulkan/vulkan_xlib.h>
19# ifdef WITH_GHOST_WAYLAND
20# include <vulkan/vulkan_wayland.h>
44#define SELECT_COMPATIBLE_SURFACES_ONLY false
48uint32_t GHOST_ContextVK::s_currentImage = 0;
52#define FORMAT_ERROR(X) \
87 FORMAT_ERROR(VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT);
89 FORMAT_ERROR(VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT);
96 return "Unknown Error";
100#define __STR(A) "" #A
101#define VK_CHECK(__expression) \
103 VkResult r = (__expression); \
104 if (r != VK_SUCCESS) { \
106 "Vulkan Error : %s:%d : %s failled with %s\n", \
109 __STR(__expression), \
110 vulkan_error_as_string(r)); \
111 return GHOST_kFailure; \
115#define DEBUG_PRINTF(...) \
117 printf(__VA_ARGS__); \
126 VkInstance instance = VK_NULL_HANDLE;
149 features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
150 features_11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
151 features_12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
159 if (
device != VK_NULL_HANDLE) {
160 vkDestroyDevice(
device,
nullptr);
174 vkEnumerateDeviceExtensionProperties(
physical_device,
nullptr, &ext_count,
nullptr);
176 vector<VkExtensionProperties> available_exts(ext_count);
177 vkEnumerateDeviceExtensionProperties(
180 for (
const auto &extension_needed : required_extensions) {
182 for (
const auto &extension : available_exts) {
183 if (strcmp(extension_needed, extension.extensionName) == 0) {
196 vector<const char *> &optional_extensions)
198 if (
device != VK_NULL_HANDLE) {
203 vector<VkDeviceQueueCreateInfo> queue_create_infos;
204 vector<const char *> device_extensions(required_extensions);
205 for (
const char *optional_extension : optional_extensions) {
207 device_extensions.push_back(optional_extension);
211 float queue_priorities[] = {1.0f};
212 VkDeviceQueueCreateInfo graphic_queue_create_info = {};
213 graphic_queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
215 graphic_queue_create_info.queueCount = 1;
216 graphic_queue_create_info.pQueuePriorities = queue_priorities;
217 queue_create_infos.push_back(graphic_queue_create_info);
219 VkPhysicalDeviceFeatures device_features = {};
221 device_features.geometryShader = VK_TRUE;
223 device_features.logicOp = VK_TRUE;
225 device_features.dualSrcBlend = VK_TRUE;
226 device_features.imageCubeArray = VK_TRUE;
227 device_features.multiDrawIndirect = VK_TRUE;
228 device_features.multiViewport = VK_TRUE;
229 device_features.shaderClipDistance = VK_TRUE;
230 device_features.drawIndirectFirstInstance = VK_TRUE;
231 device_features.fragmentStoresAndAtomics = VK_TRUE;
232 device_features.samplerAnisotropy =
features.features.samplerAnisotropy;
234 VkDeviceCreateInfo device_create_info = {};
235 device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
236 device_create_info.queueCreateInfoCount =
uint32_t(queue_create_infos.size());
237 device_create_info.pQueueCreateInfos = queue_create_infos.data();
238 device_create_info.enabledExtensionCount =
uint32_t(device_extensions.size());
239 device_create_info.ppEnabledExtensionNames = device_extensions.data();
240 device_create_info.pEnabledFeatures = &device_features;
242 void *device_create_info_p_next =
nullptr;
245 VkPhysicalDeviceVulkan12Features vulkan_12_features = {};
246 vulkan_12_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
247 vulkan_12_features.shaderOutputLayer =
features_12.shaderOutputLayer;
248 vulkan_12_features.shaderOutputViewportIndex =
features_12.shaderOutputViewportIndex;
249 vulkan_12_features.pNext = device_create_info_p_next;
250 device_create_info_p_next = &vulkan_12_features;
253 VkPhysicalDeviceShaderDrawParametersFeatures shader_draw_parameters = {};
254 shader_draw_parameters.sType =
255 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES;
256 shader_draw_parameters.shaderDrawParameters =
features_11.shaderDrawParameters;
257 shader_draw_parameters.pNext = device_create_info_p_next;
258 device_create_info_p_next = &shader_draw_parameters;
261 VkPhysicalDeviceDynamicRenderingFeatures dynamic_rendering = {};
262 dynamic_rendering.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES;
263 dynamic_rendering.dynamicRendering =
true;
264 dynamic_rendering.pNext = device_create_info_p_next;
265 device_create_info_p_next = &dynamic_rendering;
267 VkPhysicalDeviceDynamicRenderingUnusedAttachmentsFeaturesEXT
268 dynamic_rendering_unused_attachments = {};
269 dynamic_rendering_unused_attachments.sType =
270 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_FEATURES_EXT;
271 dynamic_rendering_unused_attachments.dynamicRenderingUnusedAttachments = VK_TRUE;
272 if (
has_extensions({VK_EXT_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_EXTENSION_NAME})) {
273 dynamic_rendering_unused_attachments.pNext = device_create_info_p_next;
274 device_create_info_p_next = &dynamic_rendering_unused_attachments;
278 VkPhysicalDeviceMaintenance4FeaturesKHR maintenance_4 = {};
279 maintenance_4.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES_KHR;
280 maintenance_4.maintenance4 = VK_TRUE;
282 maintenance_4.pNext = device_create_info_p_next;
283 device_create_info_p_next = &maintenance_4;
287 VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR fragment_shader_barycentric = {};
288 fragment_shader_barycentric.sType =
289 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR;
290 fragment_shader_barycentric.fragmentShaderBarycentric = VK_TRUE;
291 if (
has_extensions({VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME})) {
292 fragment_shader_barycentric.pNext = device_create_info_p_next;
293 device_create_info_p_next = &fragment_shader_barycentric;
296 device_create_info.pNext = device_create_info_p_next;
303 vkGetPhysicalDeviceQueueFamilyProperties(
physical_device, &queue_family_count,
nullptr);
305 vector<VkQueueFamilyProperties> queue_families(queue_family_count);
306 vkGetPhysicalDeviceQueueFamilyProperties(
310 for (
const auto &queue_family : queue_families) {
314 if ((queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) &&
315 (queue_family.queueFlags & VK_QUEUE_COMPUTE_BIT))
322 fprintf(stderr,
"Couldn't find any Graphic queue family on selected device\n");
336 VkSurfaceKHR vk_surface,
344 VkPhysicalDevice best_physical_device = VK_NULL_HANDLE;
347 vkEnumeratePhysicalDevices(vk_instance, &device_count,
nullptr);
350 vkEnumeratePhysicalDevices(vk_instance, &device_count, physical_devices.data());
352 int best_device_score = -1;
353 int device_index = -1;
354 for (
const auto &physical_device : physical_devices) {
362 if (vk_surface != VK_NULL_HANDLE) {
364 vkGetPhysicalDeviceSurfaceFormatsKHR(
368 vkGetPhysicalDeviceSurfacePresentModesKHR(
372 if (format_count == 0 || present_count == 0) {
378 if (!device_vk.
features.features.dualSrcBlend || !device_vk.
features.features.imageCubeArray) {
382 if (!device_vk.
features.features.geometryShader || !device_vk.
features.features.dualSrcBlend ||
383 !device_vk.
features.features.logicOp || !device_vk.
features.features.imageCubeArray)
389 int device_score = 0;
391 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
394 case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
397 case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
400 case VK_PHYSICAL_DEVICE_TYPE_CPU:
412 if (preferred_device.
index == device_index) {
416 if (device_score > best_device_score) {
417 best_physical_device = physical_device;
418 best_device_score = device_score;
422 if (best_physical_device == VK_NULL_HANDLE) {
423 fprintf(stderr,
"Error: No suitable Vulkan Device found!\n");
437#elif defined(__APPLE__)
438 CAMetalLayer *metal_layer,
449 int contextMajorVersion,
450 int contextMinorVersion,
456#elif defined(__APPLE__)
457 m_metal_layer(metal_layer),
459 m_platform(platform),
464 m_wayland_surface(wayland_surface),
465 m_wayland_display(wayland_display),
466 m_wayland_window_info(wayland_window_info),
468 m_context_major_version(contextMajorVersion),
469 m_context_minor_version(contextMinorVersion),
471 m_preferred_device(preferred_device),
472 m_command_pool(VK_NULL_HANDLE),
473 m_command_buffer(VK_NULL_HANDLE),
474 m_surface(VK_NULL_HANDLE),
475 m_swapchain(VK_NULL_HANDLE),
476 m_fence(VK_NULL_HANDLE)
488 if (m_command_buffer != VK_NULL_HANDLE) {
489 vkFreeCommandBuffers(device_vk.
device, m_command_pool, 1, &m_command_buffer);
490 m_command_buffer = VK_NULL_HANDLE;
492 if (m_command_pool != VK_NULL_HANDLE) {
493 vkDestroyCommandPool(device_vk.
device, m_command_pool,
nullptr);
495 if (m_surface != VK_NULL_HANDLE) {
496 vkDestroySurfaceKHR(device_vk.
instance, m_surface,
nullptr);
500 if (device_vk.
users == 0) {
511 if (m_swapchain != VK_NULL_HANDLE) {
512 vkDestroySwapchainKHR(device, m_swapchain,
nullptr);
514 if (m_fence != VK_NULL_HANDLE) {
515 vkDestroyFence(device, m_fence,
nullptr);
516 m_fence = VK_NULL_HANDLE;
523 if (m_swapchain == VK_NULL_HANDLE) {
527#ifdef WITH_GHOST_WAYLAND
531 if (m_wayland_window_info) {
532 const bool recreate_swapchain =
533 ((m_wayland_window_info->
size[0] !=
534 std::max(m_render_extent.width, m_render_extent_min.width)) ||
535 (m_wayland_window_info->
size[1] !=
536 std::max(m_render_extent.height, m_render_extent_min.height)));
538 if (recreate_swapchain) {
548 vkAcquireNextImageKHR(device, m_swapchain,
UINT64_MAX, VK_NULL_HANDLE, m_fence, &s_currentImage);
550 VK_CHECK(vkResetFences(device, 1, &m_fence));
552 GHOST_VulkanSwapChainData swap_chain_data;
553 swap_chain_data.swap_chain_index = s_currentImage;
554 swap_chain_data.image = m_swapchain_images[s_currentImage];
555 swap_chain_data.format = m_surface_format.format;
556 swap_chain_data.extent = m_render_extent;
558 if (swap_buffers_pre_callback_) {
559 swap_buffers_pre_callback_(&swap_chain_data);
562 VkPresentInfoKHR present_info = {};
563 present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
564 present_info.waitSemaphoreCount = 0;
565 present_info.pWaitSemaphores =
nullptr;
566 present_info.swapchainCount = 1;
567 present_info.pSwapchains = &m_swapchain;
568 present_info.pImageIndices = &s_currentImage;
569 present_info.pResults =
nullptr;
571 VkResult result = VK_SUCCESS;
574 result = vkQueuePresentKHR(m_present_queue, &present_info);
576 if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
580 if (swap_buffers_post_callback_) {
581 swap_buffers_post_callback_();
585 else if (result != VK_SUCCESS) {
587 "Error: Failed to present swap chain image : %s\n",
589 if (swap_buffers_post_callback_) {
590 swap_buffers_post_callback_();
595 s_currentImage = (s_currentImage + 1) % m_swapchain_images.size();
597 if (swap_buffers_post_callback_) {
598 swap_buffers_post_callback_();
605 GHOST_VulkanSwapChainData *r_swap_chain_data)
607 r_swap_chain_data->swap_chain_index = s_currentImage;
608 r_swap_chain_data->image = VK_NULL_HANDLE;
609 r_swap_chain_data->format = m_surface_format.format;
610 r_swap_chain_data->extent = m_render_extent;
616 void *r_physical_device,
620 void **r_queue_mutex)
622 *((VkInstance *)r_instance) = VK_NULL_HANDLE;
623 *((VkPhysicalDevice *)r_physical_device) = VK_NULL_HANDLE;
624 *((VkDevice *)r_device) = VK_NULL_HANDLE;
628 *((VkPhysicalDevice *)r_physical_device) =
vulkan_device->physical_device;
630 *r_graphic_queue_family =
vulkan_device->generic_queue_family;
631 std::mutex **queue_mutex = (std::mutex **)r_queue_mutex;
635 *((VkQueue *)r_queue) = m_graphic_queue;
641 std::function<
void(
const GHOST_VulkanSwapChainData *)> swap_buffers_pre_callback,
642 std::function<
void(
void)> swap_buffers_post_callback)
644 swap_buffers_pre_callback_ = swap_buffers_pre_callback;
645 swap_buffers_post_callback_ = swap_buffers_post_callback;
662 vkEnumerateInstanceExtensionProperties(
nullptr, &extension_count,
nullptr);
665 vkEnumerateInstanceExtensionProperties(
nullptr, &extension_count, extensions.data());
671 const char *extension_name)
673 for (
const auto &extension : extensions_available) {
674 if (strcmp(extension_name, extension.extensionName) == 0) {
683 const char *extension_name)
686 extensions_enabled.push_back(extension_name);
689 fprintf(stderr,
"Error: %s not found.\n", extension_name);
694 VkSurfaceKHR surface,
695 VkPresentModeKHR *r_presentMode)
699 vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &present_count,
nullptr);
701 vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &present_count, presents.data());
703 for (
auto present_mode : presents) {
704 if (present_mode == VK_PRESENT_MODE_FIFO_KHR) {
705 *r_presentMode = present_mode;
710 for (
auto present_mode : presents) {
711 if (present_mode == VK_PRESENT_MODE_MAILBOX_KHR) {
712 *r_presentMode = present_mode;
717 fprintf(stderr,
"Error: FIFO present mode is not supported by the swap chain!\n");
725 VkCommandPoolCreateInfo poolInfo = {};
726 poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
727 poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
728 poolInfo.queueFamilyIndex =
vulkan_device->generic_queue_family;
737 assert(m_command_pool != VK_NULL_HANDLE);
738 assert(m_command_buffer == VK_NULL_HANDLE);
739 VkCommandBufferAllocateInfo alloc_info = {};
740 alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
741 alloc_info.commandPool = m_command_pool;
742 alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
743 alloc_info.commandBufferCount = 1;
751 if (surface_format.colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
755 if (surface_format.format == VK_FORMAT_R8G8B8A8_UNORM ||
756 surface_format.format == VK_FORMAT_B8G8R8A8_UNORM)
770 const VkSurfaceKHR surface,
771 VkSurfaceFormatKHR &r_surfaceFormat)
774 vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &format_count,
nullptr);
776 vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &format_count, formats.data());
778 for (
const VkSurfaceFormatKHR &
format : formats) {
785#if !SELECT_COMPATIBLE_SURFACES_ONLY
786 r_surfaceFormat = formats[0];
796 VkPhysicalDevice physical_device =
vulkan_device->physical_device;
798 m_surface_format = {};
799#if SELECT_COMPATIBLE_SURFACES_ONLY
807 VkPresentModeKHR present_mode;
812 VkSurfaceCapabilitiesKHR capabilities;
813 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, m_surface, &capabilities);
815 m_render_extent = capabilities.currentExtent;
816 m_render_extent_min = capabilities.minImageExtent;
823#ifdef WITH_GHOST_WAYLAND
825 if (m_wayland_window_info) {
826 width = m_wayland_window_info->
size[0];
827 height = m_wayland_window_info->
size[1];
831 if (width == 0 || height == 0) {
836 m_render_extent.width = width;
837 m_render_extent.height = height;
839 if (capabilities.minImageExtent.width > m_render_extent.width) {
840 m_render_extent.width = capabilities.minImageExtent.width;
842 if (capabilities.minImageExtent.height > m_render_extent.height) {
843 m_render_extent.height = capabilities.minImageExtent.height;
848 uint32_t image_count = capabilities.minImageCount + 1;
850 if (image_count > capabilities.maxImageCount && capabilities.maxImageCount > 0) {
851 image_count = capabilities.maxImageCount;
853 if (capabilities.minImageCount <= 3 && image_count > 3) {
857 VkSwapchainCreateInfoKHR create_info = {};
858 create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
859 create_info.surface = m_surface;
860 create_info.minImageCount = image_count;
861 create_info.imageFormat = m_surface_format.format;
862 create_info.imageColorSpace = m_surface_format.colorSpace;
863 create_info.imageExtent = m_render_extent;
864 create_info.imageArrayLayers = 1;
865 create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
866 create_info.preTransform = capabilities.currentTransform;
867 create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
868 create_info.presentMode = present_mode;
869 create_info.clipped = VK_TRUE;
870 create_info.oldSwapchain = VK_NULL_HANDLE;
871 create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
872 create_info.queueFamilyIndexCount = 0;
873 create_info.pQueueFamilyIndices =
nullptr;
876 VK_CHECK(vkCreateSwapchainKHR(device, &create_info,
nullptr, &m_swapchain));
879 vkGetSwapchainImagesKHR(device, m_swapchain, &image_count,
nullptr);
880 m_swapchain_images.resize(image_count);
881 vkGetSwapchainImagesKHR(device, m_swapchain, &image_count, m_swapchain_images.data());
883 VkFenceCreateInfo fence_info = {};
884 fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
885 VK_CHECK(vkCreateFence(device, &fence_info,
nullptr, &m_fence));
888 VkCommandBufferBeginInfo begin_info = {};
889 begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
890 VK_CHECK(vkBeginCommandBuffer(m_command_buffer, &begin_info));
891 VkImageMemoryBarrier *barriers =
new VkImageMemoryBarrier[image_count];
892 for (
int i = 0; i < image_count; i++) {
893 VkImageMemoryBarrier &barrier = barriers[i];
896 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
897 barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
898 barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
899 barrier.image = m_swapchain_images[i];
900 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
901 barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
902 barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
904 vkCmdPipelineBarrier(m_command_buffer,
905 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
906 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
907 VK_DEPENDENCY_BY_REGION_BIT,
914 VK_CHECK(vkEndCommandBuffer(m_command_buffer));
916 VkPipelineStageFlags wait_stages[] = {VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT};
917 VkSubmitInfo submit_info = {};
918 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
919 submit_info.pWaitDstStageMask = wait_stages;
920 submit_info.commandBufferCount = 1;
921 submit_info.pCommandBuffers = &m_command_buffer;
922 submit_info.signalSemaphoreCount = 0;
923 submit_info.pSignalSemaphores =
nullptr;
924 VK_CHECK(vkQueueSubmit(m_graphic_queue, 1, &submit_info,
nullptr));
925 VK_CHECK(vkQueueWaitIdle(m_graphic_queue));
932const char *GHOST_ContextVK::getPlatformSpecificSurfaceExtension()
const
935 return VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
936#elif defined(__APPLE__)
937 return VK_EXT_METAL_SURFACE_EXTENSION_NAME;
939 switch (m_platform) {
940# ifdef WITH_GHOST_X11
941 case GHOST_kVulkanPlatformX11:
942 return VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
945# ifdef WITH_GHOST_WAYLAND
946 case GHOST_kVulkanPlatformWayland:
947 return VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
958 const bool use_window_surface = (m_hwnd !=
nullptr);
959#elif defined(__APPLE__)
960 const bool use_window_surface = (m_metal_layer !=
nullptr);
962 bool use_window_surface =
false;
963 switch (m_platform) {
964# ifdef WITH_GHOST_X11
965 case GHOST_kVulkanPlatformX11:
966 use_window_surface = (m_display !=
nullptr) && (m_window != (
Window)
nullptr);
969# ifdef WITH_GHOST_WAYLAND
970 case GHOST_kVulkanPlatformWayland:
971 use_window_surface = (m_wayland_display !=
nullptr) && (m_wayland_surface !=
nullptr);
978 vector<const char *> required_device_extensions;
979 vector<const char *> optional_device_extensions;
980 vector<const char *> extensions_enabled;
983 requireExtension(extensions_available, extensions_enabled, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
986 if (use_window_surface) {
987 const char *native_surface_extension_name = getPlatformSpecificSurfaceExtension();
988 requireExtension(extensions_available, extensions_enabled, VK_KHR_SURFACE_EXTENSION_NAME);
989 requireExtension(extensions_available, extensions_enabled, native_surface_extension_name);
991 required_device_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
993 required_device_extensions.push_back(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
997 optional_device_extensions.push_back(VK_EXT_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_EXTENSION_NAME);
998 optional_device_extensions.push_back(VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME);
999 optional_device_extensions.push_back(VK_KHR_MAINTENANCE_4_EXTENSION_NAME);
1000 optional_device_extensions.push_back(VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME);
1005 extensions_available, extensions_enabled, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
1008 VkInstance instance = VK_NULL_HANDLE;
1010 VkApplicationInfo app_info = {};
1011 app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
1012 app_info.pApplicationName =
"Blender";
1013 app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
1014 app_info.pEngineName =
"Blender";
1015 app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0);
1016 app_info.apiVersion = VK_MAKE_VERSION(m_context_major_version, m_context_minor_version, 0);
1019 VkInstanceCreateInfo create_info = {};
1020 create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
1021 create_info.pApplicationInfo = &app_info;
1022 create_info.enabledExtensionCount =
uint32_t(extensions_enabled.size());
1023 create_info.ppEnabledExtensionNames = extensions_enabled.data();
1026 VkValidationFeaturesEXT validationFeatures = {};
1027 validationFeatures.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
1028 validationFeatures.enabledValidationFeatureCount = 1;
1030 VkValidationFeatureEnableEXT enabledValidationFeatures[1] = {
1031 VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT};
1032 validationFeatures.pEnabledValidationFeatures = enabledValidationFeatures;
1034 create_info.pNext = &validationFeatures;
1038 create_info.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
1041 VK_CHECK(vkCreateInstance(&create_info,
nullptr, &instance));
1047 if (use_window_surface) {
1049 VkWin32SurfaceCreateInfoKHR surface_create_info = {};
1050 surface_create_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
1051 surface_create_info.hinstance = GetModuleHandle(
nullptr);
1052 surface_create_info.hwnd = m_hwnd;
1053 VK_CHECK(vkCreateWin32SurfaceKHR(instance, &surface_create_info,
nullptr, &m_surface));
1054#elif defined(__APPLE__)
1055 VkMetalSurfaceCreateInfoEXT info = {};
1056 info.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT;
1057 info.pNext =
nullptr;
1059 info.pLayer = m_metal_layer;
1060 VK_CHECK(vkCreateMetalSurfaceEXT(instance, &info,
nullptr, &m_surface));
1062 switch (m_platform) {
1063# ifdef WITH_GHOST_X11
1064 case GHOST_kVulkanPlatformX11: {
1065 VkXlibSurfaceCreateInfoKHR surface_create_info = {};
1066 surface_create_info.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
1067 surface_create_info.dpy = m_display;
1068 surface_create_info.window = m_window;
1069 VK_CHECK(vkCreateXlibSurfaceKHR(instance, &surface_create_info,
nullptr, &m_surface));
1073# ifdef WITH_GHOST_WAYLAND
1074 case GHOST_kVulkanPlatformWayland: {
1075 VkWaylandSurfaceCreateInfoKHR surface_create_info = {};
1076 surface_create_info.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
1077 surface_create_info.display = m_wayland_display;
1078 surface_create_info.surface = m_wayland_surface;
1079 VK_CHECK(vkCreateWaylandSurfaceKHR(instance, &surface_create_info,
nullptr, &m_surface));
1088 if (!
ensure_vulkan_device(instance, m_surface, m_preferred_device, required_device_extensions)) {
1093 vulkan_device->ensure_device(required_device_extensions, optional_device_extensions);
1098 createCommandPools();
1099 createGraphicsCommandBuffer();
1100 if (use_window_surface) {
#define VK_CHECK(__expression)
static bool surfaceFormatSupported(const VkSurfaceFormatKHR &surface_format)
static bool checkExtensionSupport(const vector< VkExtensionProperties > &extensions_available, const char *extension_name)
static const char * vulkan_error_as_string(VkResult result)
static void requireExtension(const vector< VkExtensionProperties > &extensions_available, vector< const char * > &extensions_enabled, const char *extension_name)
static GHOST_TSuccess ensure_vulkan_device(VkInstance vk_instance, VkSurfaceKHR vk_surface, const GHOST_GPUDevice &preferred_device, const vector< const char * > &required_extensions)
static bool selectSurfaceFormat(const VkPhysicalDevice physical_device, const VkSurfaceKHR surface, VkSurfaceFormatKHR &r_surfaceFormat)
static vector< VkExtensionProperties > getExtensionsAvailable()
static std::optional< GHOST_DeviceVK > vulkan_device
static GHOST_TSuccess selectPresentMode(VkPhysicalDevice device, VkSurfaceKHR surface, VkPresentModeKHR *r_presentMode)
GHOST_TVulkanPlatformType
GHOST_TSuccess activateDrawingContext() override
GHOST_TSuccess swapBuffers() override
GHOST_TSuccess getVulkanSwapChainFormat(GHOST_VulkanSwapChainData *r_swap_chain_data) override
GHOST_TSuccess getVulkanHandles(void *r_instance, void *r_physical_device, void *r_device, uint32_t *r_graphic_queue_family, void *r_queue, void **r_queue_mutex) override
GHOST_TSuccess initializeDrawingContext() override
GHOST_TSuccess releaseDrawingContext() override
GHOST_TSuccess releaseNativeHandles() override
GHOST_TSuccess setVulkanSwapBuffersCallbacks(std::function< void(const GHOST_VulkanSwapChainData *)> swap_buffers_pre_callback, std::function< void(void)> swap_buffers_post_callback) override
GHOST_ContextVK(bool stereoVisual, GHOST_TVulkanPlatformType platform, Window window, Display *display, wl_surface *wayland_surface, wl_display *wayland_display, const GHOST_ContextVK_WindowInfo *wayland_window_info, int contextMajorVersion, int contextMinorVersion, int debug, const GHOST_GPUDevice &preferred_device)
bool has_extensions(const vector< const char * > &required_extensions)
GHOST_DeviceVK(VkInstance vk_instance, VkPhysicalDevice vk_physical_device)
void init_generic_queue_family()
VkPhysicalDeviceFeatures2 features
VkPhysicalDevice physical_device
uint32_t generic_queue_family
VkPhysicalDeviceVulkan12Features features_12
VkPhysicalDeviceProperties properties
void ensure_device(vector< const char * > &required_extensions, vector< const char * > &optional_extensions)
VkPhysicalDeviceVulkan11Features features_11