diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt index df8e4ab5ca..3323b3cf9a 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt @@ -1189,9 +1189,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { quickSettings.addDivider(container) - if (::emulationState.isInitialized && emulationState.frameGenAtLaunch && - LosslessScalingHelper.isInstalled() && LosslessScalingHelper.isSupportedByGpu() - ) { + if (LosslessScalingHelper.isInstalled() && LosslessScalingHelper.isSupportedByGpu()) { quickSettings.addFrameGen(container) quickSettings.addDivider(container) } @@ -2281,10 +2279,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { private var surface: Surface? = null lateinit var emulationThread: Thread - @get:Synchronized - var frameGenAtLaunch = false - private set - init { state = State.STOPPED } @@ -2369,7 +2363,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { @Synchronized fun changeProgram(programIndex: Int) { emulationThread.join() - frameGenAtLaunch = BooleanSetting.RENDERER_FRAME_GEN.getBoolean(false) emulationThread = Thread({ Log.debug("[EmulationFragment] Starting emulation thread.") NativeLibrary.run(gamePath, programIndex, false) @@ -2437,7 +2430,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { when (state) { State.STOPPED -> { NativeLibrary.surfaceChanged(currentSurface) - frameGenAtLaunch = BooleanSetting.RENDERER_FRAME_GEN.getBoolean(false) emulationThread = Thread({ Log.debug("[EmulationFragment] Starting emulation thread.") NativeLibrary.run(gamePath, programIndex, true) diff --git a/src/video_core/renderer_vulkan/present/frame_gen.cpp b/src/video_core/renderer_vulkan/present/frame_gen.cpp index b0d16819e5..e6d857323b 100644 --- a/src/video_core/renderer_vulkan/present/frame_gen.cpp +++ b/src/video_core/renderer_vulkan/present/frame_gen.cpp @@ -198,6 +198,10 @@ void FrameGen::Process(const Device& device, Frame* frame, VkFormat format, VkExtent2D guest_extent) { generated = false; + if (!shaders) { + shaders.emplace(device); + } + if (unavailable || !Settings::values.frame_gen.GetValue()) { if (chain) { scheduler.Finish(); @@ -207,17 +211,14 @@ void FrameGen::Process(const Device& device, Frame* frame, VkFormat format, return; } - if (!frame->storage_view) { + if (!shaders->IsValid()) { unavailable = true; return; } - if (!shaders) { - shaders.emplace(device); - if (!shaders->IsValid()) { - unavailable = true; - return; - } + if (!frame->storage_view) { + warm_streak = 0; + return; } peak_guest_extent.width = std::max(peak_guest_extent.width, guest_extent.width); diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 96eeeb8045..205382f81a 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp @@ -8,6 +8,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include "common/settings.h" #include "video_core/framebuffer_config.h" #include "video_core/present.h" #include "video_core/renderer_vulkan/present/filters.h" @@ -87,13 +88,18 @@ void BlitScreen::SetWindowAdaptPass(const Device& device) { void BlitScreen::PrepareFrame(const Device& device, Frame* frame, const Layout::FramebufferLayout& layout) { - if (!window_adapt || (frame->width == layout.width && frame->height == layout.height)) { + if (!window_adapt) { + return; + } + + if (frame->width != layout.width || frame->height != layout.height) { + WaitIdle(device); + } else if (!present_manager.NeedsStorage(frame, true)) { return; } - WaitIdle(device); present_manager.RecreateFrame(frame, layout.width, layout.height, swapchain_view_format, - window_adapt->GetRenderPass()); + window_adapt->GetRenderPass(), true); } void BlitScreen::DrawToFrame(const Device& device, RasterizerVulkan& rasterizer, Frame* frame, @@ -120,16 +126,20 @@ void BlitScreen::DrawToFrame(const Device& device, RasterizerVulkan& rasterizer, swapchain_view_format = current_swapchain_view_format; } + const bool storage_required = Settings::values.frame_gen.GetValue(); if (resource_update_required) { WaitIdle(device); SetWindowAdaptPass(device); if (presentation_recreate_required) { present_manager.RecreateFrame(frame, layout.width, layout.height, swapchain_view_format, - window_adapt->GetRenderPass()); + window_adapt->GetRenderPass(), storage_required); } image_index = 0; + } else if (present_manager.NeedsStorage(frame, storage_required)) { + present_manager.RecreateFrame(frame, layout.width, layout.height, swapchain_view_format, + window_adapt->GetRenderPass(), true); } const VkExtent2D window_size{ diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp index 3491f8fb75..d173a3ba5f 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp @@ -29,9 +29,6 @@ static_assert(MAX_FRAMES_IN_FLIGHT <= LSFG_MAX_TARGETS); bool CanStoreToFrame(const vk::PhysicalDevice& physical_device, VkFormat format) { #ifdef HAS_LSFG - if (!Settings::values.frame_gen.GetValue()) { - return false; - } const VkFormatProperties props{physical_device.GetFormatProperties(format)}; return (props.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) != 0; #else @@ -160,6 +157,7 @@ PresentManager::PresentManager(const vk::Instance& instance_, .pNext = nullptr, .flags = VK_FENCE_CREATE_SIGNALED_BIT, }); + frame.storage_capable = storage_supported; free_queue.push_back(&frame); } @@ -205,15 +203,22 @@ size_t PresentManager::MaxExtraFrames() const { return image_count - 1; } +bool PresentManager::NeedsStorage(const Frame* frame, bool required) const { + return required && frame->storage_capable && !frame->storage_view; +} + void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, VkFormat image_view_format, - VkRenderPass rd) { + VkRenderPass rd, bool storage) { auto& dld = device.GetLogical(); frame->width = width; frame->height = height; - const VkImageUsageFlags storage_usage = - storage_supported ? static_cast(VK_IMAGE_USAGE_STORAGE_BIT) : 0; + const bool with_storage = storage && frame->storage_capable; + VkImageUsageFlags storage_usage = 0; + if (with_storage) { + storage_usage = VK_IMAGE_USAGE_STORAGE_BIT; + } frame->image = memory_allocator.CreateImage({ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, @@ -264,7 +269,7 @@ void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, VkFormat }); frame->storage_view = vk::ImageView{}; - if (storage_supported) { + if (with_storage) { frame->storage_view = dld.CreateImageView({ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .pNext = nullptr, diff --git a/src/video_core/renderer_vulkan/vk_present_manager.h b/src/video_core/renderer_vulkan/vk_present_manager.h index 577a82098a..4741c55e61 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.h +++ b/src/video_core/renderer_vulkan/vk_present_manager.h @@ -36,6 +36,7 @@ struct Frame { vk::CommandBuffer cmdbuf; vk::Semaphore render_ready; vk::Fence present_done; + bool storage_capable{}; }; class PresentManager { @@ -57,7 +58,9 @@ public: /// Recreates the present frame to match the provided parameters void RecreateFrame(Frame* frame, u32 width, u32 height, VkFormat image_view_format, - VkRenderPass rd); + VkRenderPass rd, bool storage); + + [[nodiscard]] bool NeedsStorage(const Frame* frame, bool required) const; /// Waits for the present thread to finish presenting all queued frames. void WaitPresent();