Browse Source

[VK]: Support for frame interpolation on PC and improve it's logic

I also suspect that frame interpolation hasn't been ever working, as it needs frame_skip_threshold and it was only being initialized if frame_skipping was on (actually a disabled and useless option, thats why i also nuked it), and the toggle was very messy with jni.
pull/217/head
Gamer64 7 months ago
committed by crueter
parent
commit
9786b1aa41
  1. 3
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt
  2. 9
      src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt
  3. 2
      src/android/app/src/main/res/values/strings.xml
  4. 4
      src/common/settings.h
  5. 66
      src/video_core/renderer_vulkan/renderer_vulkan.cpp
  6. 9
      src/yuzu/configuration/shared_translation.cpp

3
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt

@ -51,7 +51,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
ENABLE_RAII("enable_raii"),
FRAME_INTERPOLATION("frame_interpolation"),
// FRAME_SKIPPING("frame_skipping"),
PERF_OVERLAY_BACKGROUND("perf_overlay_background"),
SHOW_PERFORMANCE_OVERLAY("show_performance_overlay"),
@ -68,8 +67,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
USE_LRU_CACHE("use_lru_cache");
external fun isRaiiEnabled(): Boolean
// external fun isFrameSkippingEnabled(): Boolean
external fun isFrameInterpolationEnabled(): Boolean
override fun getBoolean(needsGlobal: Boolean): Boolean =
NativeConfig.getBoolean(key, needsGlobal)

9
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt

@ -234,15 +234,6 @@ abstract class SettingsItem(
descriptionId = R.string.frame_interpolation_description
)
)
// put(
// SwitchSetting(
// BooleanSetting.FRAME_SKIPPING,
// titleId = R.string.frame_skipping,
// descriptionId = R.string.frame_skipping_description
// )
// )
put(
SwitchSetting(
dockedModeSetting,

2
src/android/app/src/main/res/values/strings.xml

@ -479,8 +479,6 @@
<string name="display">Display</string>
<string name="processing">Post-Processing</string>
<string name="frame_skipping">WIP: Frameskip</string>
<string name="frame_skipping_description">Toggle frame skipping to improve performance by reducing the number of rendered frames. This feature is still being worked on and will be enabled in future releases.</string>
<string name="renderer_accuracy">Accuracy level</string>
<string name="renderer_resolution">Resolution (Handheld/Docked)</string>
<string name="renderer_vsync">VSync mode</string>

4
src/common/settings.h

@ -322,12 +322,8 @@ struct Values {
SwitchableSetting<int> vulkan_device{linkage, 0, "vulkan_device", Category::Renderer,
Specialization::RuntimeList};
SwitchableSetting<bool> enable_raii{linkage, false, "enable_raii", Category::Renderer};
#ifdef __ANDROID__
SwitchableSetting<bool> frame_interpolation{linkage, true, "frame_interpolation", Category::Renderer,
Specialization::RuntimeList};
SwitchableSetting<bool> frame_skipping{linkage, false, "frame_skipping", Category::Renderer,
Specialization::RuntimeList};
#endif
SwitchableSetting<bool> use_disk_shader_cache{linkage, true, "use_disk_shader_cache",
Category::Renderer};
SwitchableSetting<SpirvOptimizeMode, true> optimize_spirv_output{linkage,

66
src/video_core/renderer_vulkan/renderer_vulkan.cpp

@ -38,9 +38,7 @@
#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 <jni.h>
#endif
namespace Vulkan {
namespace {
@ -189,39 +187,6 @@ RendererVulkan::~RendererVulkan() {
void(device.GetLogical().WaitIdle());
}
#ifdef __ANDROID__
class BooleanSetting {
public:
// static BooleanSetting FRAME_SKIPPING;
static BooleanSetting 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::FRAME_SKIPPING(false);
BooleanSetting BooleanSetting::FRAME_INTERPOLATION(false);
// extern "C" JNIEXPORT jboolean JNICALL
// Java_org_yuzu_yuzu_1emu_features_settings_model_BooleanSetting_isFrameSkippingEnabled(JNIEnv* env, jobject /* this */) {
// return static_cast<jboolean>(BooleanSetting::FRAME_SKIPPING.getBoolean());
// }
extern "C" JNIEXPORT jboolean JNICALL
Java_org_yuzu_yuzu_1emu_features_settings_model_BooleanSetting_isFrameInterpolationEnabled(JNIEnv* env, jobject /* this */) {
return static_cast<jboolean>(BooleanSetting::FRAME_INTERPOLATION.getBoolean());
}
void RendererVulkan::InterpolateFrames(Frame* prev_frame, Frame* interpolated_frame) {
if (!prev_frame || !interpolated_frame || !prev_frame->image || !interpolated_frame->image) {
return;
@ -292,30 +257,15 @@ class BooleanSetting {
TransitionImageLayout(cmdbuf, *interpolated_frame->image, VK_IMAGE_LAYOUT_GENERAL);
});
}
#endif
void RendererVulkan::Composite(std::span<const Tegra::FramebufferConfig> framebuffers) {
#ifdef __ANDROID__
static int frame_counter = 0;
static int target_fps = 60; // Target FPS (30 or 60)
int frame_skip_threshold = 1;
bool frame_skipping = false; //BooleanSetting::FRAME_SKIPPING.getBoolean();
bool frame_interpolation = BooleanSetting::FRAME_INTERPOLATION.getBoolean();
#endif
if (framebuffers.empty()) {
return;
}
#ifdef __ANDROID__
if (frame_skipping) {
frame_skip_threshold = (target_fps == 30) ? 2 : 2;
}
bool frame_interpolation_enabled = Settings::values.frame_interpolation.GetValue();
frame_counter++;
if (frame_counter % frame_skip_threshold != 0) {
if (frame_interpolation && previous_frame) {
if (frame_interpolation_enabled && previous_frame) {
Frame* interpolated_frame = present_manager.GetRenderFrame();
InterpolateFrames(previous_frame, interpolated_frame);
blit_swapchain.DrawToFrame(rasterizer, interpolated_frame, framebuffers,
@ -323,10 +273,11 @@ void RendererVulkan::Composite(std::span<const Tegra::FramebufferConfig> framebu
swapchain.GetImageViewFormat());
scheduler.Flush(*interpolated_frame->render_ready);
present_manager.Present(interpolated_frame);
}
// Optionally, update previous_frame here if you want to chain interpolations
previous_frame = interpolated_frame;
return;
}
#endif
SCOPE_EXIT {
render_window.OnFrameDisplayed();
@ -346,6 +297,11 @@ void RendererVulkan::Composite(std::span<const Tegra::FramebufferConfig> framebu
scheduler.Flush(*frame->render_ready);
present_manager.Present(frame);
// Store the current frame for interpolation on the next call
if (frame_interpolation_enabled) {
previous_frame = frame;
}
gpu.RendererFrameEndNotify();
rasterizer.TickFrame();
}

9
src/yuzu/configuration/shared_translation.cpp

@ -250,6 +250,12 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent)
"of available video memory for performance. Has no effect on integrated graphics. "
"Aggressive mode may severely impact the performance of other applications such as "
"recording software."));
INSERT(Settings,
frame_interpolation,
tr("Enhanced Frame Pacing"),
tr("Ensures smooth and consistent frame delivery by synchronizing the timing between frames, "
"reducing stuttering and uneven animation. Ideal for games that experience frame timing "
"instability or micro-stutters during gameplay."));
INSERT(Settings,
skip_cpu_inner_invalidation,
tr("Skip CPU Inner Invalidation"),
@ -333,14 +339,13 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent)
barrier_feedback_loops,
tr("Barrier feedback loops"),
tr("Improves rendering of transparency effects in specific games."));
// Renderer (Extensions)
INSERT(Settings,
enable_raii,
tr("RAII"),
tr("A method of automatic resource management in Vulkan "
"that ensures proper release of resources "
"when they are no longer needed, but may cause crashes in bundled games."));
// Renderer (Extensions)
INSERT(Settings,
dyna_state,
tr("Extended Dynamic State"),

Loading…
Cancel
Save