12# include <vulkan/vulkan_win32.h>
15# include <vulkan/vulkan_xlib.h>
17# ifdef WITH_GHOST_WAYLAND
18# include <vulkan/vulkan_wayland.h>
24#if !defined(_WIN32) or defined(_M_ARM64)
26# define VMA_EXTERNAL_MEMORY_WIN32 0
28#include "vk_mem_alloc.h"
51#define FORMAT_ERROR(X) \
86 FORMAT_ERROR(VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT);
88 FORMAT_ERROR(VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT);
95 return "Unknown Error";
100#define VK_CHECK(__expression, fail_value) \
102 VkResult r = (__expression); \
103 if (r != VK_SUCCESS) { \
105 "Vulkan: %s resulted in code %s.", \
106 __STR(__expression), \
107 vulkan_error_as_string(r)); \
126 VkSwapchainKHR vk_swapchain =
swapchains.back();
128 vkDestroySwapchainKHR(vk_device, vk_swapchain,
nullptr);
133 vkDestroySemaphore(vk_device, vk_semaphore,
nullptr);
158 for (
const VkExtensionProperties &extension :
extensions) {
159 if (strcmp(extension.extensionName, extension_name) == 0) {
168 for (
const char *extension_name : extension_names) {
176 bool enable(
const char *extension_name,
bool optional =
false)
181 "Vulkan: %s extension enabled: name=%s",
182 optional ?
"optional" :
"required",
184 enabled.push_back(extension_name);
190 "Vulkan: %s extension not available: name=%s",
191 optional ?
"optional" :
"required",
197 bool enable(
const vector<const char *> &extension_names,
bool optional =
false)
199 bool failure =
false;
200 for (
const char *extension_name : extension_names) {
201 failure |= !
enable(extension_name, optional);
208 for (
const char *enabled_extension_name :
enabled) {
209 if (strcmp(enabled_extension_name, extension_name) == 0) {
235 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
238 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES,
244 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT};
262 features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
263 features_11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
264 features_12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
287 uint32_t extensions_count;
288 VK_CHECK(vkEnumerateDeviceExtensionProperties(
291 extensions.extensions.resize(extensions_count);
292 VK_CHECK(vkEnumerateDeviceExtensionProperties(
308 uint32_t queue_family_count = 0;
309 vkGetPhysicalDeviceQueueFamilyProperties(
vk_physical_device, &queue_family_count,
nullptr);
311 vector<VkQueueFamilyProperties> queue_families(queue_family_count);
312 vkGetPhysicalDeviceQueueFamilyProperties(
316 for (
const auto &queue_family : queue_families) {
320 if ((queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) &&
321 (queue_family.queueFlags & VK_QUEUE_COMPUTE_BIT))
336 VmaAllocatorCreateInfo vma_allocator_create_info = {};
337 vma_allocator_create_info.vulkanApiVersion = VK_API_VERSION_1_2;
339 vma_allocator_create_info.device =
vk_device;
340 vma_allocator_create_info.instance = vk_instance;
341 vma_allocator_create_info.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT;
342 if (
extensions.is_enabled(VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME)) {
343 vma_allocator_create_info.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT;
345 if (
extensions.is_enabled(VK_KHR_MAINTENANCE_4_EXTENSION_NAME)) {
346 vma_allocator_create_info.flags |= VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE4_BIT;
348 vmaCreateAllocator(&vma_allocator_create_info, &
vma_allocator);
381 uint32_t extension_count = 0;
382 VK_CHECK(vkEnumerateInstanceExtensionProperties(
nullptr, &extension_count,
nullptr),
false);
383 extensions.extensions.resize(extension_count);
384 VK_CHECK(vkEnumerateInstanceExtensionProperties(
385 nullptr, &extension_count,
extensions.extensions.data()),
392 VkApplicationInfo vk_application_info = {VK_STRUCTURE_TYPE_APPLICATION_INFO,
395 VK_MAKE_VERSION(1, 0, 0),
397 VK_MAKE_VERSION(1, 0, 0),
399 VkInstanceCreateInfo vk_instance_create_info = {VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
402 &vk_application_info,
415 const vector<const char *> &required_extensions)
417 VkPhysicalDevice best_physical_device = VK_NULL_HANDLE;
419 uint32_t device_count = 0;
420 vkEnumeratePhysicalDevices(
vk_instance, &device_count,
nullptr);
422 vector<VkPhysicalDevice> physical_devices(device_count);
423 vkEnumeratePhysicalDevices(
vk_instance, &device_count, physical_devices.data());
425 int best_device_score = -1;
426 int device_index = -1;
427 for (
const auto &physical_device : physical_devices) {
438 if (!device_vk.
features.features.geometryShader ||
439 !device_vk.
features.features.dualSrcBlend || !device_vk.
features.features.logicOp ||
440 !device_vk.
features.features.imageCubeArray)
445 int device_score = 0;
446 switch (device_vk.
properties.properties.deviceType) {
447 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
450 case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
453 case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
456 case VK_PHYSICAL_DEVICE_TYPE_CPU:
470 if (preferred_device.
index == device_index) {
474 if (device_score > best_device_score) {
475 best_physical_device = physical_device;
476 best_device_score = device_score;
480 if (best_physical_device == VK_NULL_HANDLE) {
491 vector<const char *> &required_device_extensions,
492 vector<const char *> &optional_device_extensions)
497 device.extensions.enable(required_device_extensions);
498 device.extensions.enable(optional_device_extensions,
true);
499 device.init_generic_queue_family();
501 float queue_priorities[] = {1.0f};
502 vector<VkDeviceQueueCreateInfo> queue_create_infos;
503 VkDeviceQueueCreateInfo graphic_queue_create_info = {};
504 graphic_queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
505 graphic_queue_create_info.queueFamilyIndex =
device.generic_queue_family;
506 graphic_queue_create_info.queueCount = 1;
507 graphic_queue_create_info.pQueuePriorities = queue_priorities;
508 queue_create_infos.push_back(graphic_queue_create_info);
510 VkPhysicalDeviceFeatures device_features = {};
511 device_features.geometryShader = VK_TRUE;
512 device_features.logicOp = VK_TRUE;
513 device_features.dualSrcBlend = VK_TRUE;
514 device_features.imageCubeArray = VK_TRUE;
515 device_features.multiDrawIndirect = VK_TRUE;
516 device_features.multiViewport = VK_TRUE;
517 device_features.shaderClipDistance = VK_TRUE;
518 device_features.drawIndirectFirstInstance = VK_TRUE;
519 device_features.fragmentStoresAndAtomics = VK_TRUE;
520 device_features.samplerAnisotropy =
device.features.features.samplerAnisotropy;
521 device_features.wideLines =
device.features.features.wideLines;
523 VkDeviceCreateInfo device_create_info = {};
524 device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
525 device_create_info.queueCreateInfoCount = uint32_t(queue_create_infos.size());
526 device_create_info.pQueueCreateInfos = queue_create_infos.data();
527 device_create_info.enabledExtensionCount = uint32_t(
device.extensions.enabled.size());
528 device_create_info.ppEnabledExtensionNames =
device.extensions.enabled.data();
529 device_create_info.pEnabledFeatures = &device_features;
531 std::vector<void *> feature_struct_ptr;
534 VkPhysicalDeviceVulkan11Features vulkan_11_features = {};
535 vulkan_11_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
536 vulkan_11_features.shaderDrawParameters = VK_TRUE;
537 feature_struct_ptr.push_back(&vulkan_11_features);
540 VkPhysicalDeviceVulkan12Features vulkan_12_features = {};
541 vulkan_12_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
542 vulkan_12_features.shaderOutputLayer =
device.features_12.shaderOutputLayer;
543 vulkan_12_features.shaderOutputViewportIndex =
device.features_12.shaderOutputViewportIndex;
544 vulkan_12_features.bufferDeviceAddress =
device.features_12.bufferDeviceAddress;
545 vulkan_12_features.timelineSemaphore = VK_TRUE;
546 feature_struct_ptr.push_back(&vulkan_12_features);
549 VkPhysicalDeviceProvokingVertexFeaturesEXT provoking_vertex_features = {};
550 provoking_vertex_features.sType =
551 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT;
552 provoking_vertex_features.provokingVertexLast = VK_TRUE;
553 feature_struct_ptr.push_back(&provoking_vertex_features);
556 VkPhysicalDeviceDynamicRenderingFeatures dynamic_rendering = {};
557 dynamic_rendering.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES;
558 dynamic_rendering.dynamicRendering = VK_TRUE;
559 feature_struct_ptr.push_back(&dynamic_rendering);
561 VkPhysicalDeviceDynamicRenderingUnusedAttachmentsFeaturesEXT
562 dynamic_rendering_unused_attachments = {};
563 dynamic_rendering_unused_attachments.sType =
564 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_FEATURES_EXT;
565 dynamic_rendering_unused_attachments.dynamicRenderingUnusedAttachments = VK_TRUE;
566 if (
device.extensions.is_enabled(VK_EXT_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_EXTENSION_NAME)) {
567 feature_struct_ptr.push_back(&dynamic_rendering_unused_attachments);
570 VkPhysicalDeviceDynamicRenderingLocalReadFeaturesKHR dynamic_rendering_local_read = {};
571 dynamic_rendering_local_read.sType =
572 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES_KHR;
573 dynamic_rendering_local_read.dynamicRenderingLocalRead = VK_TRUE;
574 if (
device.extensions.is_enabled(VK_KHR_DYNAMIC_RENDERING_LOCAL_READ_EXTENSION_NAME)) {
575 feature_struct_ptr.push_back(&dynamic_rendering_local_read);
579 VkPhysicalDeviceRobustness2FeaturesEXT robustness_2_features = {
580 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT};
581 if (
device.extensions.is_enabled(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME)) {
582 robustness_2_features.nullDescriptor =
device.features_robustness2.nullDescriptor;
583 feature_struct_ptr.push_back(&robustness_2_features);
587 VkPhysicalDeviceMaintenance4FeaturesKHR maintenance_4 = {};
588 maintenance_4.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES_KHR;
589 maintenance_4.maintenance4 = VK_TRUE;
590 if (
device.extensions.is_enabled(VK_KHR_MAINTENANCE_4_EXTENSION_NAME)) {
591 feature_struct_ptr.push_back(&maintenance_4);
595 VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT swapchain_maintenance_1 = {
596 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT,
nullptr, VK_TRUE};
597 if (
device.extensions.is_enabled(VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME)) {
598 feature_struct_ptr.push_back(&swapchain_maintenance_1);
599 device.use_vk_ext_swapchain_maintenance_1 =
true;
603 VkPhysicalDeviceDescriptorBufferFeaturesEXT descriptor_buffer = {
604 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT,
610 if (
device.extensions.is_enabled(VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME)) {
611 feature_struct_ptr.push_back(&descriptor_buffer);
615 VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR fragment_shader_barycentric = {};
616 fragment_shader_barycentric.sType =
617 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR;
618 fragment_shader_barycentric.fragmentShaderBarycentric = VK_TRUE;
619 if (
device.extensions.is_enabled(VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME)) {
620 feature_struct_ptr.push_back(&fragment_shader_barycentric);
624 VkPhysicalDeviceMemoryPriorityFeaturesEXT memory_priority = {
625 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT,
nullptr, VK_TRUE};
626 if (
device.extensions.is_enabled(VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME)) {
627 feature_struct_ptr.push_back(&memory_priority);
631 VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT pageable_device_local_memory = {
632 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PAGEABLE_DEVICE_LOCAL_MEMORY_FEATURES_EXT,
635 if (
device.extensions.is_enabled(VK_EXT_PAGEABLE_DEVICE_LOCAL_MEMORY_EXTENSION_NAME)) {
636 feature_struct_ptr.push_back(&pageable_device_local_memory);
640 for (
int i = 1;
i < feature_struct_ptr.size();
i++) {
641 ((VkBaseInStructure *)(feature_struct_ptr[
i - 1]))->pNext =
642 (VkBaseInStructure *)(feature_struct_ptr[
i]);
645 device_create_info.pNext = feature_struct_ptr[0];
648 device.init_generic_queue();
670#elif defined(__APPLE__)
671 CAMetalLayer *metal_layer,
682 int contextMajorVersion,
683 int contextMinorVersion,
689#elif defined(__APPLE__)
690 metal_layer_(metal_layer),
697 wayland_surface_(wayland_surface),
698 wayland_display_(wayland_display),
699 wayland_window_info_(wayland_window_info),
701 context_major_version_(contextMajorVersion),
702 context_minor_version_(contextMinorVersion),
703 preferred_device_(preferred_device),
705 surface_(VK_NULL_HANDLE),
706 swapchain_(VK_NULL_HANDLE),
709 use_hdr_swapchain_(
false)
711 frame_data_.reserve(5);
720 for (VkFence fence : fence_pile_) {
721 vkDestroyFence(device_vk.
vk_device, fence,
nullptr);
726 if (surface_ != VK_NULL_HANDLE) {
727 vkDestroySurfaceKHR(instance_vk.
vk_instance, surface_,
nullptr);
731 if (device_vk.
users == 0) {
739 if (acquired_swapchain_image_index_.has_value()) {
745 VkDevice vk_device = device_vk.
vk_device;
760 render_frame_ = (render_frame_ + 1) % frame_data_.size();
761 GHOST_Frame &submission_frame_data = frame_data_[render_frame_];
769 this->destroySwapchainPresentFences(swapchain);
773 const bool use_hdr_swapchain = hdr_info_ &&
774 (hdr_info_->wide_gamut_enabled || hdr_info_->hdr_enabled) &&
776 if (use_hdr_swapchain != use_hdr_swapchain_) {
778 recreateSwapchain(use_hdr_swapchain);
781#ifdef WITH_GHOST_WAYLAND
785 if (wayland_window_info_) {
786 const bool recreate_swapchain =
787 ((wayland_window_info_->size[0] !=
788 std::max(render_extent_.width, render_extent_min_.width)) ||
789 (wayland_window_info_->size[1] !=
790 std::max(render_extent_.height, render_extent_min_.height)));
792 if (recreate_swapchain) {
794 recreateSwapchain(use_hdr_swapchain);
801 if (swapchain_ == VK_NULL_HANDLE) {
802 recreateSwapchain(use_hdr_swapchain);
806 uint32_t image_index = 0;
807 if (swapchain_ != VK_NULL_HANDLE) {
810 VkResult acquire_result = VK_ERROR_OUT_OF_DATE_KHR;
811 while (swapchain_ != VK_NULL_HANDLE &&
812 (acquire_result == VK_ERROR_OUT_OF_DATE_KHR || acquire_result == VK_SUBOPTIMAL_KHR))
814 acquire_result = vkAcquireNextImageKHR(vk_device,
820 if (acquire_result == VK_ERROR_OUT_OF_DATE_KHR || acquire_result == VK_SUBOPTIMAL_KHR) {
821 recreateSwapchain(use_hdr_swapchain);
836 if (swap_buffer_acquired_callback_) {
837 swap_buffer_acquired_callback_();
840 if (swapchain_ == VK_NULL_HANDLE) {
841 CLOG_TRACE(&
LOG,
"Swap-chain unavailable (minimized window).");
846 "Acquired swap-chain image (render_frame=%lu, image_index=%u)",
849 acquired_swapchain_image_index_ = image_index;
853VkFence GHOST_ContextVK::getFence()
855 if (!fence_pile_.empty()) {
856 VkFence fence = fence_pile_.back();
857 fence_pile_.pop_back();
861 VkFence fence = VK_NULL_HANDLE;
862 const VkFenceCreateInfo fence_create_info = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO};
863 vkCreateFence(device_vk.
vk_device, &fence_create_info,
nullptr, &fence);
867void GHOST_ContextVK::setPresentFence(VkSwapchainKHR swapchain, VkFence present_fence)
869 if (present_fence == VK_NULL_HANDLE) {
872 present_fences_[swapchain].push_back(present_fence);
875 for (std::pair<
const VkSwapchainKHR, std::vector<VkFence>> &item : present_fences_) {
876 std::vector<VkFence>::iterator end = item.second.end();
877 std::vector<VkFence>::iterator it = std::remove_if(
878 item.second.begin(), item.second.end(), [&](
const VkFence fence) {
879 if (vkGetFenceStatus(device_vk.vk_device, fence) == VK_NOT_READY) {
882 vkResetFences(device_vk.
vk_device, 1, &fence);
883 fence_pile_.push_back(fence);
886 item.second.erase(it, end);
894 if (swapchain_ == VK_NULL_HANDLE) {
895 GHOST_VulkanSwapChainData swap_chain_data = {};
896 if (swap_buffer_draw_callback_) {
897 swap_buffer_draw_callback_(&swap_chain_data);
902 if (!acquired_swapchain_image_index_.has_value()) {
907 VkDevice vk_device = device_vk.
vk_device;
909 uint32_t image_index = acquired_swapchain_image_index_.value();
911 GHOST_Frame &submission_frame_data = frame_data_[render_frame_];
912 const bool use_hdr_swapchain = hdr_info_ && hdr_info_->hdr_enabled &&
915 GHOST_VulkanSwapChainData swap_chain_data;
916 swap_chain_data.image = swapchain_image.
vk_image;
917 swap_chain_data.surface_format = surface_format_;
918 swap_chain_data.extent = render_extent_;
922 swap_chain_data.sdr_scale = (hdr_info_) ? hdr_info_->sdr_white_level : 1.0f;
925 if (swap_buffer_draw_callback_) {
926 swap_buffer_draw_callback_(&swap_chain_data);
929 VkPresentInfoKHR present_info = {};
930 present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
931 present_info.waitSemaphoreCount = 1;
933 present_info.swapchainCount = 1;
934 present_info.pSwapchains = &swapchain_;
935 present_info.pImageIndices = &image_index;
936 present_info.pResults =
nullptr;
938 VkResult present_result = VK_SUCCESS;
941 VkSwapchainPresentFenceInfoEXT fence_info{VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT};
942 VkFence present_fence = VK_NULL_HANDLE;
944 present_fence = this->getFence();
946 fence_info.swapchainCount = 1;
947 fence_info.pFences = &present_fence;
949 present_info.pNext = &fence_info;
951 present_result = vkQueuePresentKHR(device_vk.
generic_queue, &present_info);
952 this->setPresentFence(swapchain_, present_fence);
954 acquired_swapchain_image_index_.reset();
956 if (present_result == VK_ERROR_OUT_OF_DATE_KHR || present_result == VK_SUBOPTIMAL_KHR) {
957 recreateSwapchain(use_hdr_swapchain);
960 if (present_result != VK_SUCCESS) {
962 "Vulkan: failed to present swap-chain image : %s",
971 GHOST_VulkanSwapChainData *r_swap_chain_data)
973 r_swap_chain_data->image = VK_NULL_HANDLE;
974 r_swap_chain_data->surface_format = surface_format_;
975 r_swap_chain_data->extent = render_extent_;
976 r_swap_chain_data->sdr_scale = (hdr_info_) ? hdr_info_->sdr_white_level : 1.0f;
1011 std::function<
void(
const GHOST_VulkanSwapChainData *)> swap_buffer_draw_callback,
1012 std::function<
void(
void)> swap_buffer_acquired_callback,
1013 std::function<
void(GHOST_VulkanOpenXRData *)> openxr_acquire_framebuffer_image_callback,
1014 std::function<
void(GHOST_VulkanOpenXRData *)> openxr_release_framebuffer_image_callback)
1016 swap_buffer_draw_callback_ = swap_buffer_draw_callback;
1017 swap_buffer_acquired_callback_ = swap_buffer_acquired_callback;
1018 openxr_acquire_framebuffer_image_callback_ = openxr_acquire_framebuffer_image_callback;
1019 openxr_release_framebuffer_image_callback_ = openxr_release_framebuffer_image_callback;
1036 VkPhysicalDevice device,
1037 VkSurfaceKHR surface,
1038 VkPresentModeKHR *r_presentMode)
1040 uint32_t present_count;
1041 vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &present_count,
nullptr);
1043 vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &present_count, presents.data());
1048 for (
auto present_mode : presents) {
1049 if (present_mode == VK_PRESENT_MODE_IMMEDIATE_KHR) {
1050 *r_presentMode = present_mode;
1055 "Vulkan: VSync off was requested via --gpu-vsync, "
1056 "but VK_PRESENT_MODE_IMMEDIATE_KHR is not supported.");
1065 for (
auto present_mode : presents) {
1066 if (present_mode == VK_PRESENT_MODE_MAILBOX_KHR) {
1067 *r_presentMode = present_mode;
1075 *r_presentMode = VK_PRESENT_MODE_FIFO_KHR;
1085 const VkSurfaceKHR surface,
1086 bool use_hdr_swapchain,
1087 VkSurfaceFormatKHR &r_surfaceFormat)
1089 uint32_t format_count;
1090 vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &format_count,
nullptr);
1092 vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &format_count, formats.data());
1095 make_pair(VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT, VK_FORMAT_R16G16B16A16_SFLOAT),
1096 make_pair(VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, VK_FORMAT_R16G16B16A16_SFLOAT),
1097 make_pair(VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, VK_FORMAT_R8G8B8A8_UNORM),
1098 make_pair(VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, VK_FORMAT_B8G8R8A8_UNORM),
1101 for (pair<VkColorSpaceKHR, VkFormat> &pair : selection_order) {
1102 if (pair.second == VK_FORMAT_R16G16B16A16_SFLOAT && !use_hdr_swapchain) {
1105 for (
const VkSurfaceFormatKHR &
format : formats) {
1106 if (
format.colorSpace == pair.first &&
format.format == pair.second) {
1107 r_surfaceFormat =
format;
1120 const VkSemaphoreCreateInfo vk_semaphore_create_info = {
1121 VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
nullptr, 0};
1122 const VkFenceCreateInfo vk_fence_create_info = {
1123 VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
nullptr, VK_FENCE_CREATE_SIGNALED_BIT};
1124 for (GHOST_SwapchainImage &swapchain_image : swapchain_images_) {
1126 if (swapchain_image.present_semaphore == VK_NULL_HANDLE) {
1128 device, &vk_semaphore_create_info,
nullptr, &swapchain_image.present_semaphore),
1133 for (
int index = 0; index < frame_data_.size(); index++) {
1134 GHOST_Frame &frame_data = frame_data_[index];
1150GHOST_TSuccess GHOST_ContextVK::recreateSwapchain(
bool use_hdr_swapchain)
1153 GHOST_DeviceVK &device_vk = instance_vk.
device.value();
1155 surface_format_ = {};
1162 VkPresentModeKHR present_mode;
1168 VkSurfacePresentScalingCapabilitiesEXT vk_surface_present_scaling_capabilities = {
1169 VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT,
1171 VkSurfaceCapabilities2KHR vk_surface_capabilities = {
1172 VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR,
1173 &vk_surface_present_scaling_capabilities,
1175 VkSurfacePresentModeEXT vk_surface_present_mode = {
1176 VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT,
nullptr, present_mode};
1177 VkPhysicalDeviceSurfaceInfo2KHR vk_physical_device_surface_info = {
1178 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR, &vk_surface_present_mode, surface_};
1179 VkSurfaceCapabilitiesKHR capabilities = {};
1183 &vk_physical_device_surface_info,
1184 &vk_surface_capabilities),
1186 capabilities = vk_surface_capabilities.surfaceCapabilities;
1189 VK_CHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
1194 use_hdr_swapchain_ = use_hdr_swapchain;
1195 render_extent_ = capabilities.currentExtent;
1196 render_extent_min_ = capabilities.minImageExtent;
1203#ifdef WITH_GHOST_WAYLAND
1205 if (wayland_window_info_) {
1206 width = wayland_window_info_->size[0];
1207 height = wayland_window_info_->size[1];
1211 if (width == 0 || height == 0) {
1216 render_extent_.width = width;
1217 render_extent_.height = height;
1219 if (capabilities.minImageExtent.width > render_extent_.width) {
1220 render_extent_.width = capabilities.minImageExtent.width;
1222 if (capabilities.minImageExtent.height > render_extent_.height) {
1223 render_extent_.height = capabilities.minImageExtent.height;
1228 if (vk_surface_present_scaling_capabilities.minScaledImageExtent.width > render_extent_.width)
1230 render_extent_.width = vk_surface_present_scaling_capabilities.minScaledImageExtent.width;
1232 if (vk_surface_present_scaling_capabilities.minScaledImageExtent.height >
1233 render_extent_.height)
1235 render_extent_.height = vk_surface_present_scaling_capabilities.minScaledImageExtent.height;
1240 GHOST_FrameDiscard &discard_pile = frame_data_[render_frame_].discard_pile;
1241 for (GHOST_SwapchainImage &swapchain_image : swapchain_images_) {
1242 swapchain_image.vk_image = VK_NULL_HANDLE;
1243 if (swapchain_image.present_semaphore != VK_NULL_HANDLE) {
1244 discard_pile.
semaphores.push_back(swapchain_image.present_semaphore);
1245 swapchain_image.present_semaphore = VK_NULL_HANDLE;
1254 if (render_extent_.width == 0 || render_extent_.height == 0) {
1256 discard_pile.
swapchains.push_back(swapchain_);
1257 swapchain_ = VK_NULL_HANDLE;
1265 uint32_t image_count_requested = present_mode == VK_PRESENT_MODE_MAILBOX_KHR ? 3 : 2;
1267 if (capabilities.minImageCount != 0 && image_count_requested < capabilities.minImageCount) {
1268 image_count_requested = capabilities.minImageCount;
1270 if (capabilities.maxImageCount != 0 && image_count_requested > capabilities.maxImageCount) {
1271 image_count_requested = capabilities.maxImageCount;
1274 VkSwapchainKHR old_swapchain = swapchain_;
1279 VkPresentScalingFlagBitsEXT vk_present_scaling = old_swapchain == VK_NULL_HANDLE ?
1280 VK_PRESENT_SCALING_STRETCH_BIT_EXT :
1281 VK_PRESENT_SCALING_ONE_TO_ONE_BIT_EXT;
1283 VkSwapchainPresentModesCreateInfoEXT vk_swapchain_present_modes = {
1284 VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODES_CREATE_INFO_EXT,
nullptr, 1, &present_mode};
1285 VkSwapchainPresentScalingCreateInfoEXT vk_swapchain_present_scaling = {
1286 VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_SCALING_CREATE_INFO_EXT,
1287 &vk_swapchain_present_modes,
1288 vk_surface_present_scaling_capabilities.supportedPresentScaling & vk_present_scaling,
1289 vk_surface_present_scaling_capabilities.supportedPresentGravityX &
1290 VK_PRESENT_GRAVITY_MIN_BIT_EXT,
1291 vk_surface_present_scaling_capabilities.supportedPresentGravityY &
1292 VK_PRESENT_GRAVITY_MAX_BIT_EXT,
1295 VkSwapchainCreateInfoKHR create_info = {};
1296 create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
1298 create_info.pNext = &vk_swapchain_present_scaling;
1300 create_info.surface = surface_;
1301 create_info.minImageCount = image_count_requested;
1302 create_info.imageFormat = surface_format_.format;
1303 create_info.imageColorSpace = surface_format_.colorSpace;
1304 create_info.imageExtent = render_extent_;
1305 create_info.imageArrayLayers = 1;
1306 create_info.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT |
1307 (use_hdr_swapchain ? VK_IMAGE_USAGE_STORAGE_BIT : 0);
1308 create_info.preTransform = capabilities.currentTransform;
1309 create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
1310 create_info.presentMode = present_mode;
1311 create_info.clipped = VK_TRUE;
1312 create_info.oldSwapchain = old_swapchain;
1313 create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
1314 create_info.queueFamilyIndexCount = 0;
1315 create_info.pQueueFamilyIndices =
nullptr;
1317 VK_CHECK(vkCreateSwapchainKHR(device_vk.
vk_device, &create_info,
nullptr, &swapchain_),
1322 vkGetSwapchainImagesKHR(device_vk.
vk_device, swapchain_, &actual_image_count,
nullptr);
1326 if (actual_image_count > frame_data_.size()) {
1327 CLOG_TRACE(&
LOG,
"Vulkan: Increasing frame data to %u frames", actual_image_count);
1328 assert(actual_image_count <= frame_data_.capacity());
1329 frame_data_.resize(actual_image_count);
1331 swapchain_images_.resize(actual_image_count);
1332 std::vector<VkImage> swapchain_images(actual_image_count);
1333 vkGetSwapchainImagesKHR(
1334 device_vk.
vk_device, swapchain_, &actual_image_count, swapchain_images.data());
1335 for (
int index = 0; index < actual_image_count; index++) {
1336 swapchain_images_[index].vk_image = swapchain_images[index];
1339 "Vulkan: recreating swapchain: width=%u, height=%u, format=%d, colorSpace=%d, "
1340 "present_mode=%d, image_count_requested=%u, image_count_acquired=%u, swapchain=%lx, "
1341 "old_swapchain=%lx",
1342 render_extent_.width,
1343 render_extent_.height,
1344 surface_format_.format,
1345 surface_format_.colorSpace,
1347 image_count_requested,
1354 for (GHOST_Frame &frame : frame_data_) {
1355 if (frame.acquire_semaphore != VK_NULL_HANDLE) {
1356 discard_pile.
semaphores.push_back(frame.acquire_semaphore);
1358 frame.acquire_semaphore = VK_NULL_HANDLE;
1360 if (old_swapchain) {
1361 discard_pile.
swapchains.push_back(old_swapchain);
1363 initializeFrameData();
1365 image_count_ = actual_image_count;
1370void GHOST_ContextVK::destroySwapchainPresentFences(VkSwapchainKHR swapchain)
1373 const std::vector<VkFence> &fences = present_fences_[swapchain];
1374 if (!fences.empty()) {
1376 for (VkFence fence : fences) {
1377 vkDestroyFence(device_vk.
vk_device, fence,
nullptr);
1380 present_fences_.erase(swapchain);
1387 if (swapchain_ != VK_NULL_HANDLE) {
1388 this->destroySwapchainPresentFences(swapchain_);
1389 vkDestroySwapchainKHR(device_vk.
vk_device, swapchain_,
nullptr);
1392 for (GHOST_SwapchainImage &swapchain_image : swapchain_images_) {
1393 swapchain_image.destroy(device_vk.
vk_device);
1395 swapchain_images_.clear();
1396 for (GHOST_Frame &frame_data : frame_data_) {
1398 this->destroySwapchainPresentFences(swapchain);
1402 frame_data_.clear();
1407const char *GHOST_ContextVK::getPlatformSpecificSurfaceExtension()
const
1410 return VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
1411#elif defined(__APPLE__)
1412 return VK_EXT_METAL_SURFACE_EXTENSION_NAME;
1414 switch (platform_) {
1415# ifdef WITH_GHOST_X11
1416 case GHOST_kVulkanPlatformX11:
1417 return VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
1420# ifdef WITH_GHOST_WAYLAND
1421 case GHOST_kVulkanPlatformWayland:
1422 return VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
1434 bool use_vk_ext_swapchain_colorspace =
false;
1436 const bool use_window_surface = (hwnd_ !=
nullptr);
1437#elif defined(__APPLE__)
1438 const bool use_window_surface = (metal_layer_ !=
nullptr);
1440 bool use_window_surface =
false;
1441 switch (platform_) {
1442# ifdef WITH_GHOST_X11
1443 case GHOST_kVulkanPlatformX11:
1444 use_window_surface = (display_ !=
nullptr) && (window_ != (
Window)
nullptr);
1447# ifdef WITH_GHOST_WAYLAND
1448 case GHOST_kVulkanPlatformWayland:
1449 use_window_surface = (wayland_display_ !=
nullptr) && (wayland_surface_ !=
nullptr);
1453 use_window_surface =
false;
1458 vector<const char *> required_device_extensions;
1459 vector<const char *> optional_device_extensions;
1469 if (use_window_surface) {
1470 const char *native_surface_extension_name = getPlatformSpecificSurfaceExtension();
1474 const bool use_vk_ext_swapchain_maintenance1 =
1475#ifdef WITH_GHOST_X11
1476 platform_ != GHOST_kVulkanPlatformX11 &&
1480 if (use_vk_ext_swapchain_maintenance1) {
1481 instance_vk.
extensions.
enable(VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME);
1482 instance_vk.
extensions.
enable(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME);
1483 optional_device_extensions.push_back(VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME);
1487 VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME,
true);
1489 required_device_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
1493 VK_MAKE_VERSION(context_major_version_, context_minor_version_, 0)))
1502 if (use_window_surface) {
1504 VkWin32SurfaceCreateInfoKHR surface_create_info = {};
1505 surface_create_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
1506 surface_create_info.hinstance = GetModuleHandle(
nullptr);
1507 surface_create_info.hwnd = hwnd_;
1509 vkCreateWin32SurfaceKHR(instance_vk.
vk_instance, &surface_create_info,
nullptr, &surface_),
1511#elif defined(__APPLE__)
1512 VkMetalSurfaceCreateInfoEXT info = {};
1513 info.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT;
1514 info.pNext =
nullptr;
1516 info.pLayer = metal_layer_;
1520 switch (platform_) {
1521# ifdef WITH_GHOST_X11
1522 case GHOST_kVulkanPlatformX11: {
1523 VkXlibSurfaceCreateInfoKHR surface_create_info = {};
1524 surface_create_info.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
1525 surface_create_info.dpy = display_;
1526 surface_create_info.window = window_;
1528 instance_vk.
vk_instance, &surface_create_info,
nullptr, &surface_),
1533# ifdef WITH_GHOST_WAYLAND
1534 case GHOST_kVulkanPlatformWayland: {
1535 VkWaylandSurfaceCreateInfoKHR surface_create_info = {};
1536 surface_create_info.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
1537 surface_create_info.display = wayland_display_;
1538 surface_create_info.surface = wayland_surface_;
1539 VK_CHECK(vkCreateWaylandSurfaceKHR(
1540 instance_vk.
vk_instance, &surface_create_info,
nullptr, &surface_),
1546 surface_ = VK_NULL_HANDLE;
1558 optional_device_extensions.push_back(VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME);
1560 optional_device_extensions.push_back(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME);
1563 required_device_extensions.push_back(VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME);
1564 required_device_extensions.push_back(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
1565 optional_device_extensions.push_back(VK_KHR_DYNAMIC_RENDERING_LOCAL_READ_EXTENSION_NAME);
1566 optional_device_extensions.push_back(
1567 VK_EXT_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_EXTENSION_NAME);
1568 optional_device_extensions.push_back(VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME);
1569 optional_device_extensions.push_back(VK_KHR_MAINTENANCE_4_EXTENSION_NAME);
1570 optional_device_extensions.push_back(VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME);
1571 optional_device_extensions.push_back(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME);
1572 optional_device_extensions.push_back(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME);
1573 optional_device_extensions.push_back(VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME);
1574 optional_device_extensions.push_back(VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME);
1575 optional_device_extensions.push_back(VK_EXT_PAGEABLE_DEVICE_LOCAL_MEMORY_EXTENSION_NAME);
1581 if (!instance_vk.
create_device(use_vk_ext_swapchain_colorspace,
1582 required_device_extensions,
1583 optional_device_extensions))
1592 render_extent_ = {0, 0};
1593 render_extent_min_ = {0, 0};
1594 surface_format_ = {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR};
#define CLOG_ERROR(clg_ref,...)
#define CLOG_DEBUG(clg_ref,...)
#define CLOG_WARN(clg_ref,...)
#define CLOG_AT_LEVEL(clg_ref, verbose_level,...)
#define CLOG_TRACE(clg_ref,...)
static bool selectSurfaceFormat(const VkPhysicalDevice physical_device, const VkSurfaceKHR surface, bool use_hdr_swapchain, VkSurfaceFormatKHR &r_surfaceFormat)
static std::optional< GHOST_InstanceVK > vulkan_instance
#define VK_CHECK(__expression, fail_value)
static const char * vulkan_error_as_string(VkResult result)
static GHOST_TSuccess selectPresentMode(const GHOST_TVSyncModes vsync, VkPhysicalDevice device, VkSurfaceKHR surface, VkPresentModeKHR *r_presentMode)
GHOST_TVulkanPlatformType
@ GHOST_kVulkanPlatformHeadless
unsigned long long int uint64_t
GHOST_TSuccess swapBufferRelease() override
GHOST_TSuccess activateDrawingContext() override
GHOST_TSuccess getVulkanSwapChainFormat(GHOST_VulkanSwapChainData *r_swap_chain_data) override
GHOST_ContextVK(const GHOST_ContextParams &context_params, 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, const GHOST_GPUDevice &preferred_device, const GHOST_WindowHDRInfo *hdr_info_=nullptr)
GHOST_TSuccess initializeDrawingContext() override
GHOST_TSuccess setVulkanSwapBuffersCallbacks(std::function< void(const GHOST_VulkanSwapChainData *)> swap_buffer_draw_callback, std::function< void(void)> swap_buffer_acquired_callback, std::function< void(GHOST_VulkanOpenXRData *)> openxr_acquire_framebuffer_image_callback, std::function< void(GHOST_VulkanOpenXRData *)> openxr_release_framebuffer_image_callback) override
GHOST_TSuccess getVulkanHandles(GHOST_VulkanHandles &r_handles) override
GHOST_TSuccess releaseDrawingContext() override
GHOST_TSuccess swapBufferAcquire() override
GHOST_TSuccess releaseNativeHandles() override
~GHOST_ContextVK() override
GHOST_Context(const GHOST_ContextParams &context_params)
static GHOST_Context * active_context_
virtual GHOST_TVSyncModes getVSync()
GHOST_ContextParams context_params_
VkPhysicalDevice vk_physical_device
VmaAllocator vma_allocator
void init_generic_queue_family()
VkPhysicalDeviceRobustness2FeaturesEXT features_robustness2
bool use_vk_ext_swapchain_maintenance_1
void init_memory_allocator(VkInstance vk_instance)
VkPhysicalDeviceFeatures2 features
uint32_t generic_queue_family
VkPhysicalDeviceVulkan12Properties properties_12
VkPhysicalDeviceVulkan12Features features_12
VkPhysicalDeviceProperties2 properties
GHOST_ExtensionsVK extensions
void init_generic_queue()
bool use_vk_ext_swapchain_colorspace
VkPhysicalDeviceVulkan11Features features_11
GHOST_DeviceVK(VkPhysicalDevice vk_physical_device, const bool use_vk_ext_swapchain_colorspace)
#define assert(assertion)
bool GPU_vulkan_is_supported_driver(VkPhysicalDevice vk_physical_device)
bool is_supported(const char *extension_name) const
bool is_enabled(const char *extension_name) const
vector< const char * > enabled
bool enable(const char *extension_name, bool optional=false)
vector< VkExtensionProperties > extensions
bool enable(const vector< const char * > &extension_names, bool optional=false)
bool is_supported(const vector< const char * > &extension_names)
std::vector< VkSwapchainKHR > swapchains
void destroy(VkDevice vk_device)
std::vector< VkSemaphore > semaphores
VkSemaphore acquire_semaphore
GHOST_FrameDiscard discard_pile
void destroy(VkDevice vk_device)
VkPhysicalDevice vk_physical_device
bool select_physical_device(const GHOST_GPUDevice &preferred_device, const vector< const char * > &required_extensions)
std::optional< GHOST_DeviceVK > device
GHOST_ExtensionsVK extensions
bool create_instance(uint32_t vulkan_api_version)
bool create_device(const bool use_vk_ext_swapchain_maintenance1, vector< const char * > &required_device_extensions, vector< const char * > &optional_device_extensions)
void destroy(VkDevice vk_device)
VkSemaphore present_semaphore