diff options
Diffstat (limited to 'drivers/vulkan/rendering_device_driver_vulkan.cpp')
-rw-r--r-- | drivers/vulkan/rendering_device_driver_vulkan.cpp | 152 |
1 files changed, 143 insertions, 9 deletions
diff --git a/drivers/vulkan/rendering_device_driver_vulkan.cpp b/drivers/vulkan/rendering_device_driver_vulkan.cpp index d20f396281..a43c55a17b 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.cpp +++ b/drivers/vulkan/rendering_device_driver_vulkan.cpp @@ -35,6 +35,16 @@ #include "thirdparty/misc/smolv.h" #include "vulkan_hooks.h" +#if defined(ANDROID_ENABLED) +#include "platform/android/java_godot_wrapper.h" +#include "platform/android/os_android.h" +#include "platform/android/thread_jandroid.h" +#endif + +#if defined(SWAPPY_FRAME_PACING_ENABLED) +#include "thirdparty/swappy-frame-pacing/swappyVk.h" +#endif + #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) #define PRINT_NATIVE_COMMANDS 0 @@ -533,6 +543,37 @@ Error RenderingDeviceDriverVulkan::_initialize_device_extensions() { err = vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &device_extension_count, device_extensions.ptr()); ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); +#if defined(SWAPPY_FRAME_PACING_ENABLED) + if (swappy_frame_pacer_enable) { + char **swappy_required_extensions; + uint32_t swappy_required_extensions_count = 0; + // Determine number of extensions required by Swappy frame pacer. + SwappyVk_determineDeviceExtensions(physical_device, device_extension_count, device_extensions.ptr(), &swappy_required_extensions_count, nullptr); + + if (swappy_required_extensions_count < device_extension_count) { + // Determine the actual extensions. + swappy_required_extensions = (char **)malloc(swappy_required_extensions_count * sizeof(char *)); + char *pRequiredExtensionsData = (char *)malloc(swappy_required_extensions_count * (VK_MAX_EXTENSION_NAME_SIZE + 1)); + for (uint32_t i = 0; i < swappy_required_extensions_count; i++) { + swappy_required_extensions[i] = &pRequiredExtensionsData[i * (VK_MAX_EXTENSION_NAME_SIZE + 1)]; + } + SwappyVk_determineDeviceExtensions(physical_device, device_extension_count, + device_extensions.ptr(), &swappy_required_extensions_count, swappy_required_extensions); + + // Enable extensions requested by Swappy. + for (uint32_t i = 0; i < swappy_required_extensions_count; i++) { + CharString extension_name(swappy_required_extensions[i]); + if (requested_device_extensions.has(extension_name)) { + enabled_device_extension_names.insert(extension_name); + } + } + + free(pRequiredExtensionsData); + free(swappy_required_extensions); + } + } +#endif + #ifdef DEV_ENABLED for (uint32_t i = 0; i < device_extension_count; i++) { print_verbose(String("VULKAN: Found device extension ") + String::utf8(device_extensions[i].extensionName)); @@ -1371,6 +1412,18 @@ Error RenderingDeviceDriverVulkan::initialize(uint32_t p_device_index, uint32_t max_descriptor_sets_per_pool = GLOBAL_GET("rendering/rendering_device/vulkan/max_descriptors_per_pool"); breadcrumb_buffer = buffer_create(sizeof(uint32_t), BufferUsageBits::BUFFER_USAGE_TRANSFER_TO_BIT, MemoryAllocationType::MEMORY_ALLOCATION_TYPE_CPU); +#if defined(SWAPPY_FRAME_PACING_ENABLED) + swappy_frame_pacer_enable = GLOBAL_GET("display/window/frame_pacing/android/enable_frame_pacing"); + swappy_mode = GLOBAL_GET("display/window/frame_pacing/android/swappy_mode"); + + if (VulkanHooks::get_singleton() != nullptr) { + // Hooks control device creation & possibly presentation + // (e.g. OpenXR) thus it's too risky to use Swappy. + swappy_frame_pacer_enable = false; + OS::get_singleton()->print("VulkanHooks detected (e.g. OpenXR): Force-disabling Swappy Frame Pacing.\n"); + } +#endif + return OK; } @@ -2356,6 +2409,14 @@ RDD::CommandQueueID RenderingDeviceDriverVulkan::command_queue_create(CommandQue ERR_FAIL_COND_V_MSG(picked_queue_index >= queue_family.size(), CommandQueueID(), "A queue in the picked family could not be found."); +#if defined(SWAPPY_FRAME_PACING_ENABLED) + if (swappy_frame_pacer_enable) { + VkQueue selected_queue; + vkGetDeviceQueue(vk_device, family_index, picked_queue_index, &selected_queue); + SwappyVk_setQueueFamilyIndex(vk_device, selected_queue, family_index); + } +#endif + // Create the virtual queue. CommandQueue *command_queue = memnew(CommandQueue); command_queue->queue_family = family_index; @@ -2501,7 +2562,16 @@ Error RenderingDeviceDriverVulkan::command_queue_execute_and_present(CommandQueu present_info.pResults = results.ptr(); device_queue.submit_mutex.lock(); +#if defined(SWAPPY_FRAME_PACING_ENABLED) + if (swappy_frame_pacer_enable) { + err = SwappyVk_queuePresent(device_queue.queue, &present_info); + } else { + err = device_functions.QueuePresentKHR(device_queue.queue, &present_info); + } +#else err = device_functions.QueuePresentKHR(device_queue.queue, &present_info); +#endif + device_queue.submit_mutex.unlock(); // Set the index to an invalid value. If any of the swap chains returned out of date, indicate it should be resized the next time it's acquired. @@ -2681,6 +2751,14 @@ void RenderingDeviceDriverVulkan::_swap_chain_release(SwapChain *swap_chain) { swap_chain->framebuffers.clear(); if (swap_chain->vk_swapchain != VK_NULL_HANDLE) { +#if defined(SWAPPY_FRAME_PACING_ENABLED) + if (swappy_frame_pacer_enable) { + // Swappy has a bug where the ANativeWindow will be leaked if we call + // SwappyVk_destroySwapchain, so we must release it by hand. + SwappyVk_setWindow(vk_device, swap_chain->vk_swapchain, nullptr); + SwappyVk_destroySwapchain(vk_device, swap_chain->vk_swapchain); + } +#endif device_functions.DestroySwapchainKHR(vk_device, swap_chain->vk_swapchain, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SWAPCHAIN_KHR)); swap_chain->vk_swapchain = VK_NULL_HANDLE; } @@ -2797,6 +2875,20 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue, VkResult err = functions.GetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface->vk_surface, &surface_capabilities); ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); + // No swapchain yet, this is the first time we're creating it. + if (!swap_chain->vk_swapchain) { + uint32_t width = surface_capabilities.currentExtent.width; + uint32_t height = surface_capabilities.currentExtent.height; + if (surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR || + surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) { + // Swap to get identity width and height. + surface_capabilities.currentExtent.height = width; + surface_capabilities.currentExtent.width = height; + } + + native_display_size = surface_capabilities.currentExtent; + } + VkExtent2D extent; if (surface_capabilities.currentExtent.width == 0xFFFFFFFF) { // The current extent is currently undefined, so the current surface width and height will be clamped to the surface's capabilities. @@ -2863,15 +2955,8 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue, desired_swapchain_images = MIN(desired_swapchain_images, surface_capabilities.maxImageCount); } - // Prefer identity transform if it's supported, use the current transform otherwise. - // This behavior is intended as Godot does not supported native rotation in platforms that use these bits. // Refer to the comment in command_queue_present() for more details. - VkSurfaceTransformFlagBitsKHR surface_transform_bits; - if (surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { - surface_transform_bits = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - } else { - surface_transform_bits = surface_capabilities.currentTransform; - } + VkSurfaceTransformFlagBitsKHR surface_transform_bits = surface_capabilities.currentTransform; VkCompositeAlphaFlagBitsKHR composite_alpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; if (OS::get_singleton()->is_layered_allowed() || !(surface_capabilities.supportedCompositeAlpha & composite_alpha)) { @@ -2898,7 +2983,7 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue, swap_create_info.minImageCount = desired_swapchain_images; swap_create_info.imageFormat = swap_chain->format; swap_create_info.imageColorSpace = swap_chain->color_space; - swap_create_info.imageExtent = extent; + swap_create_info.imageExtent = native_display_size; swap_create_info.imageArrayLayers = 1; swap_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; swap_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; @@ -2909,6 +2994,39 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue, err = device_functions.CreateSwapchainKHR(vk_device, &swap_create_info, VKC::get_allocation_callbacks(VK_OBJECT_TYPE_SWAPCHAIN_KHR), &swap_chain->vk_swapchain); ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); +#if defined(SWAPPY_FRAME_PACING_ENABLED) + if (swappy_frame_pacer_enable) { + const double max_fps = Engine::get_singleton()->get_max_fps(); + const uint64_t max_time = max_fps > 0 ? uint64_t((1000.0 * 1000.0 * 1000.0) / max_fps) : 0; + + SwappyVk_initAndGetRefreshCycleDuration(get_jni_env(), static_cast<OS_Android *>(OS::get_singleton())->get_godot_java()->get_activity(), physical_device, + vk_device, swap_chain->vk_swapchain, &swap_chain->refresh_duration); + SwappyVk_setWindow(vk_device, swap_chain->vk_swapchain, static_cast<OS_Android *>(OS::get_singleton())->get_native_window()); + SwappyVk_setSwapIntervalNS(vk_device, swap_chain->vk_swapchain, MAX(swap_chain->refresh_duration, max_time)); + + enum SwappyModes { + PIPELINE_FORCED_ON, + AUTO_FPS_PIPELINE_FORCED_ON, + AUTO_FPS_AUTO_PIPELINE, + }; + + switch (swappy_mode) { + case PIPELINE_FORCED_ON: + SwappyVk_setAutoSwapInterval(true); + SwappyVk_setAutoPipelineMode(true); + break; + case AUTO_FPS_PIPELINE_FORCED_ON: + SwappyVk_setAutoSwapInterval(true); + SwappyVk_setAutoPipelineMode(false); + break; + case AUTO_FPS_AUTO_PIPELINE: + SwappyVk_setAutoSwapInterval(false); + SwappyVk_setAutoPipelineMode(false); + break; + } + } +#endif + uint32_t image_count = 0; err = device_functions.GetSwapchainImagesKHR(vk_device, swap_chain->vk_swapchain, &image_count, nullptr); ERR_FAIL_COND_V(err != VK_SUCCESS, ERR_CANT_CREATE); @@ -3049,6 +3167,22 @@ RDD::DataFormat RenderingDeviceDriverVulkan::swap_chain_get_format(SwapChainID p } } +void RenderingDeviceDriverVulkan::swap_chain_set_max_fps(SwapChainID p_swap_chain, int p_max_fps) { + DEV_ASSERT(p_swap_chain.id != 0); + +#ifdef SWAPPY_FRAME_PACING_ENABLED + if (!swappy_frame_pacer_enable) { + return; + } + + SwapChain *swap_chain = (SwapChain *)(p_swap_chain.id); + if (swap_chain->vk_swapchain != VK_NULL_HANDLE) { + const uint64_t max_time = p_max_fps > 0 ? uint64_t((1000.0 * 1000.0 * 1000.0) / p_max_fps) : 0; + SwappyVk_setSwapIntervalNS(vk_device, swap_chain->vk_swapchain, MAX(swap_chain->refresh_duration, max_time)); + } +#endif +} + void RenderingDeviceDriverVulkan::swap_chain_free(SwapChainID p_swap_chain) { DEV_ASSERT(p_swap_chain.id != 0); |