From d25bea576212d70fb89e3d4476379a433f818ee1 Mon Sep 17 00:00:00 2001 From: Pavel Barabanov Date: Thu, 10 Apr 2025 22:24:15 +0300 Subject: Android: add FRAME_SKIPPING and FRAME_INTERPOLATION --- src/video_core/renderer_vulkan/renderer_vulkan.cpp | 75 +++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) (limited to 'src/video_core/renderer_vulkan/renderer_vulkan.cpp') diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 4a2d4b23ef..3ca69de530 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -35,7 +35,9 @@ #include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_surface.h" #include "video_core/vulkan_common/vulkan_wrapper.h" - +#ifdef __ANDROID__ +#include +#endif namespace Vulkan { namespace { @@ -136,11 +138,82 @@ RendererVulkan::~RendererVulkan() { void(device.GetLogical().WaitIdle()); } +#ifdef __ANDROID__ +class BooleanSetting { + public: + static BooleanSetting ENABLE_FRAME_SKIPPING; + static BooleanSetting ENABLE_FRAME_INTERPOLATION; + explicit BooleanSetting(bool initial_value = false) : value(initial_value) {} + + [[nodiscard]] bool getBoolean() const { + return value; + } + + void setBoolean(bool new_value) { + value = new_value; + } + + private: + bool value; + }; + + // Initialize static members + BooleanSetting BooleanSetting::ENABLE_FRAME_SKIPPING(false); + BooleanSetting BooleanSetting::ENABLE_FRAME_INTERPOLATION(false); + + extern "C" JNIEXPORT jboolean JNICALL + Java_org_uzuy_uzuy_1emu_features_settings_model_BooleanSetting_isFrameSkippingEnabled(JNIEnv* env, jobject /* this */) { + return static_cast(BooleanSetting::ENABLE_FRAME_SKIPPING.getBoolean()); + } + + extern "C" JNIEXPORT jboolean JNICALL + Java_org_uzuy_uzuy_1emu_features_settings_model_BooleanSetting_isFrameInterpolationEnabled(JNIEnv* env, jobject /* this */) { + return static_cast(BooleanSetting::ENABLE_FRAME_INTERPOLATION.getBoolean()); + } + + void RendererVulkan::InterpolateFrames(Frame* prev_frame, Frame* interpolated_frame) { + if (prev_frame && interpolated_frame) { + *interpolated_frame = std::move(*prev_frame); // Use move assignment to avoid copy issues + + // TODO: Implement actual interpolation logic here + } + } + #endif + void RendererVulkan::Composite(std::span framebuffers) { + #ifdef __ANDROID__ + static int frame_counter = 0; + static int target_fps = 60; // Target FPS (30 or 60) + int frame_skip_threshold = 1; + + bool enable_frame_skipping = BooleanSetting::ENABLE_FRAME_SKIPPING.getBoolean(); + bool enable_frame_interpolation = BooleanSetting::ENABLE_FRAME_INTERPOLATION.getBoolean(); + #endif + if (framebuffers.empty()) { return; } + #ifdef __ANDROID__ + if (enable_frame_skipping) { + frame_skip_threshold = (target_fps == 30) ? 2 : 2; + } + + frame_counter++; + if (frame_counter % frame_skip_threshold != 0) { + if (enable_frame_interpolation && previous_frame) { + Frame* interpolated_frame = present_manager.GetRenderFrame(); + InterpolateFrames(previous_frame, interpolated_frame); + blit_swapchain.DrawToFrame(rasterizer, interpolated_frame, framebuffers, + render_window.GetFramebufferLayout(), swapchain.GetImageCount(), + swapchain.GetImageViewFormat()); + scheduler.Flush(*interpolated_frame->render_ready); + present_manager.Present(interpolated_frame); + } + return; + } + #endif + SCOPE_EXIT { render_window.OnFrameDisplayed(); }; -- cgit v1.2.3