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>
46#define FORMAT_ERROR(X) \
81 FORMAT_ERROR(VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT);
83 FORMAT_ERROR(VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT);
90 return "Unknown Error";
95#define VK_CHECK(__expression) \
97 VkResult r = (__expression); \
98 if (r != VK_SUCCESS) { \
100 &LOG, "%s resulted in code %s.", __STR(__expression), vulkan_error_as_string(r)); \
101 return GHOST_kFailure; \
108 const char *extension_name)
110 for (
const VkExtensionProperties &extension_properties : extension_list) {
111 if (strcmp(extension_properties.extensionName, extension_name) == 0) {
132 VkSwapchainKHR vk_swapchain =
swapchains.back();
134 vkDestroySwapchainKHR(vk_device, vk_swapchain,
nullptr);
139 vkDestroySemaphore(vk_device, vk_semaphore,
nullptr);
168 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
171 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES,
177 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT};
193 features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
194 features_11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
195 features_12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
204 if (
device != VK_NULL_HANDLE) {
205 vkDestroyDevice(
device,
nullptr);
219 vkEnumerateDeviceExtensionProperties(
physical_device,
nullptr, &ext_count,
nullptr);
221 vector<VkExtensionProperties> available_exts(ext_count);
222 vkEnumerateDeviceExtensionProperties(
225 for (
const auto &extension_needed : required_extensions) {
227 for (
const auto &extension : available_exts) {
228 if (strcmp(extension_needed, extension.extensionName) == 0) {
241 vector<const char *> &optional_extensions)
243 if (
device != VK_NULL_HANDLE) {
248 vector<VkDeviceQueueCreateInfo> queue_create_infos;
249 vector<const char *> device_extensions(required_extensions);
250 for (
const char *optional_extension : optional_extensions) {
251 const bool extension_found =
has_extensions({optional_extension});
252 if (extension_found) {
253 CLOG_INFO(&
LOG, 2,
"enable optional extension: `%s`", optional_extension);
254 device_extensions.push_back(optional_extension);
257 CLOG_INFO(&
LOG, 2,
"optional extension not found: `%s`", optional_extension);
262 auto extension_enabled = [=](
const char *extension_name) {
263 for (
const char *device_extension_name : device_extensions) {
264 if (strcmp(device_extension_name, extension_name) == 0) {
271 float queue_priorities[] = {1.0f};
272 VkDeviceQueueCreateInfo graphic_queue_create_info = {};
273 graphic_queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
275 graphic_queue_create_info.queueCount = 1;
276 graphic_queue_create_info.pQueuePriorities = queue_priorities;
277 queue_create_infos.push_back(graphic_queue_create_info);
279 VkPhysicalDeviceFeatures device_features = {};
281 device_features.geometryShader = VK_TRUE;
283 device_features.logicOp = VK_TRUE;
285 device_features.dualSrcBlend = VK_TRUE;
286 device_features.imageCubeArray = VK_TRUE;
287 device_features.multiDrawIndirect = VK_TRUE;
288 device_features.multiViewport = VK_TRUE;
289 device_features.shaderClipDistance = VK_TRUE;
290 device_features.drawIndirectFirstInstance = VK_TRUE;
291 device_features.fragmentStoresAndAtomics = VK_TRUE;
292 device_features.samplerAnisotropy =
features.features.samplerAnisotropy;
294 VkDeviceCreateInfo device_create_info = {};
295 device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
296 device_create_info.queueCreateInfoCount = uint32_t(queue_create_infos.size());
297 device_create_info.pQueueCreateInfos = queue_create_infos.data();
298 device_create_info.enabledExtensionCount = uint32_t(device_extensions.size());
299 device_create_info.ppEnabledExtensionNames = device_extensions.data();
300 device_create_info.pEnabledFeatures = &device_features;
302 std::vector<void *> feature_struct_ptr;
305 VkPhysicalDeviceVulkan11Features vulkan_11_features = {};
306 vulkan_11_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
307 vulkan_11_features.shaderDrawParameters =
features_11.shaderDrawParameters;
308 feature_struct_ptr.push_back(&vulkan_11_features);
311 VkPhysicalDeviceVulkan12Features vulkan_12_features = {};
312 vulkan_12_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
313 vulkan_12_features.shaderOutputLayer =
features_12.shaderOutputLayer;
314 vulkan_12_features.shaderOutputViewportIndex =
features_12.shaderOutputViewportIndex;
315 vulkan_12_features.bufferDeviceAddress =
features_12.bufferDeviceAddress;
316 vulkan_12_features.timelineSemaphore = VK_TRUE;
317 feature_struct_ptr.push_back(&vulkan_12_features);
320 VkPhysicalDeviceProvokingVertexFeaturesEXT provoking_vertex_features = {};
321 provoking_vertex_features.sType =
322 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT;
323 provoking_vertex_features.provokingVertexLast = VK_TRUE;
324 feature_struct_ptr.push_back(&provoking_vertex_features);
327 VkPhysicalDeviceDynamicRenderingFeatures dynamic_rendering = {};
328 dynamic_rendering.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES;
329 dynamic_rendering.dynamicRendering = VK_TRUE;
330 if (extension_enabled(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME)) {
331 feature_struct_ptr.push_back(&dynamic_rendering);
334 VkPhysicalDeviceDynamicRenderingUnusedAttachmentsFeaturesEXT
335 dynamic_rendering_unused_attachments = {};
336 dynamic_rendering_unused_attachments.sType =
337 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_FEATURES_EXT;
338 dynamic_rendering_unused_attachments.dynamicRenderingUnusedAttachments = VK_TRUE;
339 if (extension_enabled(VK_EXT_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_EXTENSION_NAME)) {
340 feature_struct_ptr.push_back(&dynamic_rendering_unused_attachments);
343 VkPhysicalDeviceDynamicRenderingLocalReadFeaturesKHR dynamic_rendering_local_read = {};
344 dynamic_rendering_local_read.sType =
345 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES_KHR;
346 dynamic_rendering_local_read.dynamicRenderingLocalRead = VK_TRUE;
347 if (extension_enabled(VK_KHR_DYNAMIC_RENDERING_LOCAL_READ_EXTENSION_NAME)) {
348 feature_struct_ptr.push_back(&dynamic_rendering_local_read);
352 VkPhysicalDeviceRobustness2FeaturesEXT robustness_2_features = {
353 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT};
354 if (extension_enabled(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME)) {
356 feature_struct_ptr.push_back(&robustness_2_features);
360 VkPhysicalDeviceMaintenance4FeaturesKHR maintenance_4 = {};
361 maintenance_4.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES_KHR;
362 maintenance_4.maintenance4 = VK_TRUE;
363 if (extension_enabled(VK_KHR_MAINTENANCE_4_EXTENSION_NAME)) {
364 feature_struct_ptr.push_back(&maintenance_4);
368 VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT swapchain_maintenance_1 = {
369 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT,
nullptr, VK_TRUE};
370 if (extension_enabled(VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME)) {
371 feature_struct_ptr.push_back(&swapchain_maintenance_1);
376 VkPhysicalDeviceDescriptorBufferFeaturesEXT descriptor_buffer = {
377 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT,
383 if (extension_enabled(VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME)) {
384 feature_struct_ptr.push_back(&descriptor_buffer);
388 VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR fragment_shader_barycentric = {};
389 fragment_shader_barycentric.sType =
390 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR;
391 fragment_shader_barycentric.fragmentShaderBarycentric = VK_TRUE;
392 if (extension_enabled(VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME)) {
393 feature_struct_ptr.push_back(&fragment_shader_barycentric);
397 VkPhysicalDeviceMemoryPriorityFeaturesEXT memory_priority = {
398 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT,
nullptr, VK_TRUE};
399 if (extension_enabled(VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME)) {
400 feature_struct_ptr.push_back(&memory_priority);
404 VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT pageable_device_local_memory = {
405 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PAGEABLE_DEVICE_LOCAL_MEMORY_FEATURES_EXT,
408 if (extension_enabled(VK_EXT_PAGEABLE_DEVICE_LOCAL_MEMORY_EXTENSION_NAME)) {
409 feature_struct_ptr.push_back(&pageable_device_local_memory);
413 for (
int i = 1;
i < feature_struct_ptr.size();
i++) {
414 ((VkBaseInStructure *)(feature_struct_ptr[
i - 1]))->pNext =
415 (VkBaseInStructure *)(feature_struct_ptr[
i]);
418 device_create_info.pNext = feature_struct_ptr[0];
424 uint32_t queue_family_count = 0;
425 vkGetPhysicalDeviceQueueFamilyProperties(
physical_device, &queue_family_count,
nullptr);
427 vector<VkQueueFamilyProperties> queue_families(queue_family_count);
428 vkGetPhysicalDeviceQueueFamilyProperties(
432 for (
const auto &queue_family : queue_families) {
436 if ((queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) &&
437 (queue_family.queueFlags & VK_QUEUE_COMPUTE_BIT))
456 VkSurfaceKHR vk_surface,
464 VkPhysicalDevice best_physical_device = VK_NULL_HANDLE;
466 uint32_t device_count = 0;
467 vkEnumeratePhysicalDevices(vk_instance, &device_count,
nullptr);
470 vkEnumeratePhysicalDevices(vk_instance, &device_count, physical_devices.data());
472 int best_device_score = -1;
473 int device_index = -1;
474 for (
const auto &physical_device : physical_devices) {
485 if (vk_surface != VK_NULL_HANDLE) {
486 uint32_t format_count;
487 vkGetPhysicalDeviceSurfaceFormatsKHR(
490 uint32_t present_count;
491 vkGetPhysicalDeviceSurfacePresentModesKHR(
495 if (format_count == 0 || present_count == 0) {
501 if (!device_vk.
features.features.dualSrcBlend || !device_vk.
features.features.imageCubeArray) {
505 if (!device_vk.
features.features.geometryShader || !device_vk.
features.features.dualSrcBlend ||
506 !device_vk.
features.features.logicOp || !device_vk.
features.features.imageCubeArray)
512 int device_score = 0;
513 switch (device_vk.
properties.properties.deviceType) {
514 case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
517 case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
520 case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
523 case VK_PHYSICAL_DEVICE_TYPE_CPU:
535 if (preferred_device.
index == device_index) {
539 if (device_score > best_device_score) {
540 best_physical_device = physical_device;
541 best_device_score = device_score;
545 if (best_physical_device == VK_NULL_HANDLE) {
560#elif defined(__APPLE__)
561 CAMetalLayer *metal_layer,
572 int contextMajorVersion,
573 int contextMinorVersion,
579#elif defined(__APPLE__)
580 m_metal_layer(metal_layer),
582 m_platform(platform),
587 m_wayland_surface(wayland_surface),
588 m_wayland_display(wayland_display),
589 m_wayland_window_info(wayland_window_info),
591 m_context_major_version(contextMajorVersion),
592 m_context_minor_version(contextMinorVersion),
594 m_preferred_device(preferred_device),
595 m_surface(VK_NULL_HANDLE),
596 m_swapchain(VK_NULL_HANDLE),
610 if (m_surface != VK_NULL_HANDLE) {
611 vkDestroySurfaceKHR(device_vk.
instance, m_surface,
nullptr);
615 if (device_vk.
users == 0) {
623 if (m_swapchain == VK_NULL_HANDLE) {
643 GHOST_Frame &submission_frame_data = m_frame_data[m_render_frame];
644 uint64_t next_render_frame = (m_render_frame + 1) % m_frame_data.size();
649 VkFence *next_frame_fence = &m_frame_data[next_render_frame].submission_fence;
650 vkWaitForFences(device, 1, next_frame_fence,
true,
UINT64_MAX);
653#ifdef WITH_GHOST_WAYLAND
657 if (m_wayland_window_info) {
658 const bool recreate_swapchain =
659 ((m_wayland_window_info->size[0] !=
660 std::max(m_render_extent.width, m_render_extent_min.width)) ||
661 (m_wayland_window_info->size[1] !=
662 std::max(m_render_extent.height, m_render_extent_min.height)));
664 if (recreate_swapchain) {
673 VkResult acquire_result = VK_ERROR_OUT_OF_DATE_KHR;
674 uint32_t image_index = 0;
675 while (acquire_result == VK_ERROR_OUT_OF_DATE_KHR || acquire_result == VK_SUBOPTIMAL_KHR) {
676 acquire_result = vkAcquireNextImageKHR(device,
682 if (acquire_result == VK_ERROR_OUT_OF_DATE_KHR || acquire_result == VK_SUBOPTIMAL_KHR) {
686 CLOG_INFO(&
LOG, 3,
"render_frame=%lu, image_index=%u", m_render_frame, image_index);
689 GHOST_VulkanSwapChainData swap_chain_data;
690 swap_chain_data.image = swapchain_image.
vk_image;
691 swap_chain_data.surface_format = m_surface_format;
692 swap_chain_data.extent = m_render_extent;
698 if (swap_buffers_pre_callback_) {
699 swap_buffers_pre_callback_(&swap_chain_data);
702 VkPresentInfoKHR present_info = {};
703 present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
704 present_info.waitSemaphoreCount = 1;
706 present_info.swapchainCount = 1;
707 present_info.pSwapchains = &m_swapchain;
708 present_info.pImageIndices = &image_index;
709 present_info.pResults =
nullptr;
711 VkResult present_result = VK_SUCCESS;
714 present_result = vkQueuePresentKHR(m_present_queue, &present_info);
716 m_render_frame = next_render_frame;
717 if (present_result == VK_ERROR_OUT_OF_DATE_KHR || present_result == VK_SUBOPTIMAL_KHR) {
719 if (swap_buffers_post_callback_) {
720 swap_buffers_post_callback_();
724 if (present_result != VK_SUCCESS) {
729 if (swap_buffers_post_callback_) {
730 swap_buffers_post_callback_();
737 GHOST_VulkanSwapChainData *r_swap_chain_data)
739 r_swap_chain_data->image = VK_NULL_HANDLE;
740 r_swap_chain_data->surface_format = m_surface_format;
741 r_swap_chain_data->extent = m_render_extent;
772 std::function<
void(
const GHOST_VulkanSwapChainData *)> swap_buffers_pre_callback,
773 std::function<
void(
void)> swap_buffers_post_callback,
774 std::function<
void(GHOST_VulkanOpenXRData *)> openxr_acquire_framebuffer_image_callback,
775 std::function<
void(GHOST_VulkanOpenXRData *)> openxr_release_framebuffer_image_callback)
777 swap_buffers_pre_callback_ = swap_buffers_pre_callback;
778 swap_buffers_post_callback_ = swap_buffers_post_callback;
779 openxr_acquire_framebuffer_image_callback_ = openxr_acquire_framebuffer_image_callback;
780 openxr_release_framebuffer_image_callback_ = openxr_release_framebuffer_image_callback;
798 uint32_t extension_count = 0;
799 vkEnumerateInstanceExtensionProperties(
nullptr, &extension_count,
nullptr);
802 vkEnumerateInstanceExtensionProperties(
nullptr, &extension_count, extensions.data());
808 const char *extension_name)
810 for (
const auto &extension : extensions_available) {
811 if (strcmp(extension_name, extension.extensionName) == 0) {
820 const char *extension_name)
823 extensions_enabled.push_back(extension_name);
826 CLOG_ERROR(&
LOG,
"required extension not found: %s", extension_name);
831 VkSurfaceKHR surface,
832 VkPresentModeKHR *r_presentMode)
834 uint32_t present_count;
835 vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &present_count,
nullptr);
837 vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &present_count, presents.data());
843 for (
auto present_mode : presents) {
844 if (present_mode == VK_PRESENT_MODE_MAILBOX_KHR) {
845 *r_presentMode = present_mode;
853 *r_presentMode = VK_PRESENT_MODE_FIFO_KHR;
863 const VkSurfaceKHR surface,
864 VkSurfaceFormatKHR &r_surfaceFormat)
866 uint32_t format_count;
867 vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &format_count,
nullptr);
869 vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &format_count, formats.data());
871 for (
const VkSurfaceFormatKHR &
format : formats) {
872 if (
format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR &&
873 format.format == VK_FORMAT_R8G8B8A8_UNORM)
880 for (
const VkSurfaceFormatKHR &
format : formats) {
881 if (
format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR &&
882 format.format == VK_FORMAT_B8G8R8A8_UNORM)
897 const VkSemaphoreCreateInfo vk_semaphore_create_info = {
898 VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
nullptr, 0};
899 const VkFenceCreateInfo vk_fence_create_info = {
900 VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
nullptr, VK_FENCE_CREATE_SIGNALED_BIT};
901 for (GHOST_SwapchainImage &swapchain_image : m_swapchain_images) {
903 if (swapchain_image.present_semaphore == VK_NULL_HANDLE) {
905 device, &vk_semaphore_create_info,
nullptr, &swapchain_image.present_semaphore));
909 for (
int index = 0; index < m_frame_data.size(); index++) {
910 GHOST_Frame &frame_data = m_frame_data[index];
918 vkCreateFence(device, &vk_fence_create_info,
nullptr, &frame_data.
submission_fence));
929 VkPhysicalDevice physical_device =
vulkan_device->physical_device;
931 m_surface_format = {};
936 VkPresentModeKHR present_mode;
942 VkSurfacePresentScalingCapabilitiesEXT vk_surface_present_scaling_capabilities = {
943 VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT,
945 VkSurfaceCapabilities2KHR vk_surface_capabilities = {
946 VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR,
947 &vk_surface_present_scaling_capabilities,
949 VkSurfacePresentModeEXT vk_surface_present_mode = {
950 VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT,
nullptr, present_mode};
951 VkPhysicalDeviceSurfaceInfo2KHR vk_physical_device_surface_info = {
952 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR, &vk_surface_present_mode, m_surface};
953 VkSurfaceCapabilitiesKHR capabilities = {};
956 VK_CHECK(vkGetPhysicalDeviceSurfaceCapabilities2KHR(
957 physical_device, &vk_physical_device_surface_info, &vk_surface_capabilities));
958 capabilities = vk_surface_capabilities.surfaceCapabilities;
961 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, m_surface, &capabilities);
964 m_render_extent = capabilities.currentExtent;
965 m_render_extent_min = capabilities.minImageExtent;
972#ifdef WITH_GHOST_WAYLAND
974 if (m_wayland_window_info) {
975 width = m_wayland_window_info->size[0];
976 height = m_wayland_window_info->size[1];
980 if (width == 0 || height == 0) {
985 m_render_extent.width = width;
986 m_render_extent.height = height;
988 if (capabilities.minImageExtent.width > m_render_extent.width) {
989 m_render_extent.width = capabilities.minImageExtent.width;
991 if (capabilities.minImageExtent.height > m_render_extent.height) {
992 m_render_extent.height = capabilities.minImageExtent.height;
997 if (vk_surface_present_scaling_capabilities.minScaledImageExtent.width > m_render_extent.width)
999 m_render_extent.width = vk_surface_present_scaling_capabilities.minScaledImageExtent.width;
1001 if (vk_surface_present_scaling_capabilities.minScaledImageExtent.height >
1002 m_render_extent.height)
1004 m_render_extent.height = vk_surface_present_scaling_capabilities.minScaledImageExtent.height;
1017 if (
vulkan_device->properties_12.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY) {
1018 if (m_render_extent.width == 0) {
1019 m_render_extent.width = 1;
1021 if (m_render_extent.height == 0) {
1022 m_render_extent.height = 1;
1029 uint32_t image_count_requested = present_mode == VK_PRESENT_MODE_MAILBOX_KHR ? 3 : 2;
1031 if (capabilities.minImageCount != 0 && image_count_requested < capabilities.minImageCount) {
1032 image_count_requested = capabilities.minImageCount;
1034 if (capabilities.maxImageCount != 0 && image_count_requested > capabilities.maxImageCount) {
1035 image_count_requested = capabilities.maxImageCount;
1038 VkSwapchainKHR old_swapchain = m_swapchain;
1043 VkPresentScalingFlagBitsEXT vk_present_scaling = old_swapchain == VK_NULL_HANDLE ?
1044 VK_PRESENT_SCALING_STRETCH_BIT_EXT :
1045 VK_PRESENT_SCALING_ONE_TO_ONE_BIT_EXT;
1047 VkSwapchainPresentModesCreateInfoEXT vk_swapchain_present_modes = {
1048 VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODES_CREATE_INFO_EXT,
nullptr, 1, &present_mode};
1049 VkSwapchainPresentScalingCreateInfoEXT vk_swapchain_present_scaling = {
1050 VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_SCALING_CREATE_INFO_EXT,
1051 &vk_swapchain_present_modes,
1052 vk_surface_present_scaling_capabilities.supportedPresentScaling & vk_present_scaling,
1053 vk_surface_present_scaling_capabilities.supportedPresentGravityX &
1054 VK_PRESENT_GRAVITY_MIN_BIT_EXT,
1055 vk_surface_present_scaling_capabilities.supportedPresentGravityY &
1056 VK_PRESENT_GRAVITY_MAX_BIT_EXT,
1059 VkSwapchainCreateInfoKHR create_info = {};
1060 create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
1062 create_info.pNext = &vk_swapchain_present_scaling;
1064 create_info.surface = m_surface;
1065 create_info.minImageCount = image_count_requested;
1066 create_info.imageFormat = m_surface_format.format;
1067 create_info.imageColorSpace = m_surface_format.colorSpace;
1068 create_info.imageExtent = m_render_extent;
1069 create_info.imageArrayLayers = 1;
1070 create_info.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;
1071 create_info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
1072 create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
1073 create_info.presentMode = present_mode;
1074 create_info.clipped = VK_TRUE;
1075 create_info.oldSwapchain = old_swapchain;
1076 create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
1077 create_info.queueFamilyIndexCount = 0;
1078 create_info.pQueueFamilyIndices =
nullptr;
1081 VK_CHECK(vkCreateSwapchainKHR(device, &create_info,
nullptr, &m_swapchain));
1085 vkGetSwapchainImagesKHR(device, m_swapchain, &actual_image_count,
nullptr);
1090 GHOST_FrameDiscard &discard_pile = m_frame_data[m_render_frame].discard_pile;
1091 for (GHOST_SwapchainImage &swapchain_image : m_swapchain_images) {
1092 swapchain_image.vk_image = VK_NULL_HANDLE;
1093 if (swapchain_image.present_semaphore != VK_NULL_HANDLE) {
1094 discard_pile.
semaphores.push_back(swapchain_image.present_semaphore);
1095 swapchain_image.present_semaphore = VK_NULL_HANDLE;
1098 m_swapchain_images.resize(actual_image_count);
1099 std::vector<VkImage> swapchain_images(actual_image_count);
1100 vkGetSwapchainImagesKHR(device, m_swapchain, &actual_image_count, swapchain_images.data());
1101 for (
int index = 0; index < actual_image_count; index++) {
1102 m_swapchain_images[index].vk_image = swapchain_images[index];
1106 "recreating swapchain: width=%u, height=%u, format=%d, colorSpace=%d, "
1107 "present_mode=%d, image_count_requested=%u, image_count_acquired=%u, swapchain=%lx, "
1108 "old_swapchain=%lx",
1109 m_render_extent.width,
1110 m_render_extent.height,
1111 m_surface_format.format,
1112 m_surface_format.colorSpace,
1114 image_count_requested,
1121 for (GHOST_Frame &frame : m_frame_data) {
1122 discard_pile.
semaphores.push_back(frame.acquire_semaphore);
1123 frame.acquire_semaphore = VK_NULL_HANDLE;
1125 if (old_swapchain) {
1126 discard_pile.
swapchains.push_back(old_swapchain);
1128 initializeFrameData();
1130 m_image_count = actual_image_count;
1140 if (m_swapchain != VK_NULL_HANDLE) {
1141 vkDestroySwapchainKHR(device, m_swapchain,
nullptr);
1143 VK_CHECK(vkDeviceWaitIdle(device));
1144 for (GHOST_SwapchainImage &swapchain_image : m_swapchain_images) {
1145 swapchain_image.destroy(device);
1147 m_swapchain_images.clear();
1148 for (GHOST_Frame &frame_data : m_frame_data) {
1151 m_frame_data.clear();
1156const char *GHOST_ContextVK::getPlatformSpecificSurfaceExtension()
const
1159 return VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
1160#elif defined(__APPLE__)
1161 return VK_EXT_METAL_SURFACE_EXTENSION_NAME;
1163 switch (m_platform) {
1164# ifdef WITH_GHOST_X11
1165 case GHOST_kVulkanPlatformX11:
1166 return VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
1169# ifdef WITH_GHOST_WAYLAND
1170 case GHOST_kVulkanPlatformWayland:
1171 return VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
1184 const bool use_window_surface = (m_hwnd !=
nullptr);
1185#elif defined(__APPLE__)
1186 const bool use_window_surface = (m_metal_layer !=
nullptr);
1188 bool use_window_surface =
false;
1189 switch (m_platform) {
1190# ifdef WITH_GHOST_X11
1191 case GHOST_kVulkanPlatformX11:
1192 use_window_surface = (m_display !=
nullptr) && (m_window != (
Window)
nullptr);
1195# ifdef WITH_GHOST_WAYLAND
1196 case GHOST_kVulkanPlatformWayland:
1197 use_window_surface = (m_wayland_display !=
nullptr) && (m_wayland_surface !=
nullptr);
1201 use_window_surface =
false;
1207 vector<const char *> required_device_extensions;
1208 vector<const char *> optional_device_extensions;
1209 vector<const char *> extensions_enabled;
1212 requireExtension(extensions_available, extensions_enabled, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
1215 if (use_window_surface) {
1216 const char *native_surface_extension_name = getPlatformSpecificSurfaceExtension();
1217 requireExtension(extensions_available, extensions_enabled, VK_KHR_SURFACE_EXTENSION_NAME);
1218 requireExtension(extensions_available, extensions_enabled, native_surface_extension_name);
1219 required_device_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
1222 const bool use_swapchain_maintenance1 =
1223#ifdef WITH_GHOST_X11
1224 m_platform != GHOST_kVulkanPlatformX11 &&
1226 contains_extension(extensions_available, VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME) &&
1227 contains_extension(extensions_available, VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME);
1228 if (use_swapchain_maintenance1) {
1230 extensions_available, extensions_enabled, VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME);
1233 VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME);
1234 optional_device_extensions.push_back(VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME);
1240 optional_device_extensions.push_back(VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME);
1241#elif not defined(__APPLE__)
1242 optional_device_extensions.push_back(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME);
1246 optional_device_extensions.push_back(VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME);
1248 required_device_extensions.push_back(VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME);
1250 optional_device_extensions.push_back(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME);
1251 optional_device_extensions.push_back(VK_KHR_DYNAMIC_RENDERING_LOCAL_READ_EXTENSION_NAME);
1252 optional_device_extensions.push_back(VK_EXT_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_EXTENSION_NAME);
1253 optional_device_extensions.push_back(VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME);
1254 optional_device_extensions.push_back(VK_KHR_MAINTENANCE_4_EXTENSION_NAME);
1255 optional_device_extensions.push_back(VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME);
1256 optional_device_extensions.push_back(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME);
1257 optional_device_extensions.push_back(VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME);
1258 optional_device_extensions.push_back(VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME);
1259 optional_device_extensions.push_back(VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME);
1260 optional_device_extensions.push_back(VK_EXT_PAGEABLE_DEVICE_LOCAL_MEMORY_EXTENSION_NAME);
1262 VkInstance instance = VK_NULL_HANDLE;
1265 VkApplicationInfo app_info = {};
1266 app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
1267 app_info.pApplicationName =
"Blender";
1268 app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
1269 app_info.pEngineName =
"Blender";
1270 app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0);
1271 app_info.apiVersion = VK_MAKE_VERSION(m_context_major_version, m_context_minor_version, 0);
1274 VkInstanceCreateInfo create_info = {};
1275 create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
1276 create_info.pApplicationInfo = &app_info;
1277 create_info.enabledExtensionCount = uint32_t(extensions_enabled.size());
1278 create_info.ppEnabledExtensionNames = extensions_enabled.data();
1281 create_info.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
1284 VK_CHECK(vkCreateInstance(&create_info,
nullptr, &instance));
1290 if (use_window_surface) {
1292 VkWin32SurfaceCreateInfoKHR surface_create_info = {};
1293 surface_create_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
1294 surface_create_info.hinstance = GetModuleHandle(
nullptr);
1295 surface_create_info.hwnd = m_hwnd;
1296 VK_CHECK(vkCreateWin32SurfaceKHR(instance, &surface_create_info,
nullptr, &m_surface));
1297#elif defined(__APPLE__)
1298 VkMetalSurfaceCreateInfoEXT info = {};
1299 info.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT;
1300 info.pNext =
nullptr;
1302 info.pLayer = m_metal_layer;
1303 VK_CHECK(vkCreateMetalSurfaceEXT(instance, &info,
nullptr, &m_surface));
1305 switch (m_platform) {
1306# ifdef WITH_GHOST_X11
1307 case GHOST_kVulkanPlatformX11: {
1308 VkXlibSurfaceCreateInfoKHR surface_create_info = {};
1309 surface_create_info.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
1310 surface_create_info.dpy = m_display;
1311 surface_create_info.window = m_window;
1312 VK_CHECK(vkCreateXlibSurfaceKHR(instance, &surface_create_info,
nullptr, &m_surface));
1316# ifdef WITH_GHOST_WAYLAND
1317 case GHOST_kVulkanPlatformWayland: {
1318 VkWaylandSurfaceCreateInfoKHR surface_create_info = {};
1319 surface_create_info.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
1320 surface_create_info.display = m_wayland_display;
1321 surface_create_info.surface = m_wayland_surface;
1322 VK_CHECK(vkCreateWaylandSurfaceKHR(instance, &surface_create_info,
nullptr, &m_surface));
1327 m_surface = VK_NULL_HANDLE;
1335 if (!
ensure_vulkan_device(instance, m_surface, m_preferred_device, required_device_extensions)) {
1340 vulkan_device->ensure_device(required_device_extensions, optional_device_extensions);
1345 if (use_window_surface) {
1348 recreateSwapchain();
#define CLOG_ERROR(clg_ref,...)
#define CLOG_INFO(clg_ref, level,...)
static bool contains_extension(const vector< VkExtensionProperties > &extension_list, const char *extension_name)
#define VK_CHECK(__expression)
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)
static constexpr uint32_t GHOST_FRAMES_IN_FLIGHT
GHOST_TVulkanPlatformType
@ GHOST_kVulkanPlatformHeadless
unsigned long long int uint64_t
GHOST_TSuccess activateDrawingContext() override
GHOST_TSuccess swapBuffers() override
GHOST_TSuccess setVulkanSwapBuffersCallbacks(std::function< void(const GHOST_VulkanSwapChainData *)> swap_buffers_pre_callback, std::function< void(void)> swap_buffers_post_callback, std::function< void(GHOST_VulkanOpenXRData *)> openxr_acquire_framebuffer_image_callback, std::function< void(GHOST_VulkanOpenXRData *)> openxr_release_framebuffer_image_callback) override
GHOST_TSuccess getVulkanSwapChainFormat(GHOST_VulkanSwapChainData *r_swap_chain_data) override
GHOST_TSuccess initializeDrawingContext() override
GHOST_TSuccess getVulkanHandles(GHOST_VulkanHandles &r_handles) override
GHOST_TSuccess releaseDrawingContext() override
GHOST_TSuccess releaseNativeHandles() override
~GHOST_ContextVK() 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)
static GHOST_Context * active_context_
GHOST_Context(bool stereoVisual)
bool has_extensions(const vector< const char * > &required_extensions)
GHOST_DeviceVK(VkInstance vk_instance, VkPhysicalDevice vk_physical_device)
void init_generic_queue_family()
VkPhysicalDeviceRobustness2FeaturesEXT features_robustness2
bool use_vk_ext_swapchain_maintenance_1
VkPhysicalDeviceFeatures2 features
VkPhysicalDevice physical_device
uint32_t generic_queue_family
VkPhysicalDeviceVulkan12Properties properties_12
VkPhysicalDeviceVulkan12Features features_12
VkPhysicalDeviceProperties2 properties
void ensure_device(vector< const char * > &required_extensions, vector< const char * > &optional_extensions)
VkPhysicalDeviceVulkan11Features features_11
#define assert(assertion)
bool GPU_vulkan_is_supported_driver(VkPhysicalDevice vk_physical_device)
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)
void destroy(VkDevice vk_device)
VkSemaphore present_semaphore