Browse Source

Better frame pacing

pull/3535/head
MaranBr 3 weeks ago
committed by crueter
parent
commit
b69285d510
  1. 5
      src/common/settings.h
  2. 2
      src/video_core/renderer_vulkan/vk_scheduler.cpp
  3. 31
      src/video_core/renderer_vulkan/vk_scheduler.h
  4. 21
      src/video_core/renderer_vulkan/vk_swapchain.cpp

5
src/common/settings.h

@ -464,7 +464,10 @@ struct Values {
FramePacingMode::Target_Auto, FramePacingMode::Target_Auto,
FramePacingMode::Target_240, FramePacingMode::Target_240,
"frame_pacing_mode", "frame_pacing_mode",
Category::RendererAdvanced};
Category::RendererAdvanced,
Specialization::Default,
true,
true};
SwitchableSetting<AstcRecompression, true> astc_recompression{linkage, SwitchableSetting<AstcRecompression, true> astc_recompression{linkage,
AstcRecompression::Uncompressed, AstcRecompression::Uncompressed,

2
src/video_core/renderer_vulkan/vk_scheduler.cpp

@ -347,7 +347,7 @@ void Scheduler::EndRenderPass()
Record([num_images = num_renderpass_images, Record([num_images = num_renderpass_images,
images = renderpass_images, images = renderpass_images,
ranges = renderpass_image_ranges](vk::CommandBuffer cmdbuf) { ranges = renderpass_image_ranges](vk::CommandBuffer cmdbuf) {
std::vector<VkImageMemoryBarrier> barriers(num_images);
std::array<VkImageMemoryBarrier, 9> barriers;
VkPipelineStageFlags src_stages = 0; VkPipelineStageFlags src_stages = 0;
for (size_t i = 0; i < num_images; ++i) { for (size_t i = 0; i < num_images; ++i) {
const VkImageSubresourceRange& range = ranges[i]; const VkImageSubresourceRange& range = ranges[i];

31
src/video_core/renderer_vulkan/vk_scheduler.h

@ -115,29 +115,24 @@ public:
/// Waits for the given GPU tick, optionally pacing frames. /// Waits for the given GPU tick, optionally pacing frames.
void Wait(u64 tick, double target_fps = 0.0) { void Wait(u64 tick, double target_fps = 0.0) {
if (Settings::values.use_speed_limit.GetValue() && target_fps > 0.0) { if (Settings::values.use_speed_limit.GetValue() && target_fps > 0.0) {
auto frame_duration = std::chrono::duration_cast<std::chrono::steady_clock::duration>(std::chrono::duration<double>(1.0 / target_fps));
auto now = std::chrono::steady_clock::now();
if (now < next_frame_time) {
std::this_thread::sleep_until(next_frame_time);
next_frame_time += frame_duration;
} else {
next_frame_time = now + frame_duration;
if (last_frame_time == std::chrono::steady_clock::time_point{}) {
last_frame_time = std::chrono::steady_clock::now();
}
auto frame_duration = std::chrono::duration<double>(1.0 / target_fps);
auto elapsed = std::chrono::steady_clock::now() - last_frame_time;
auto sleep_time = frame_duration - elapsed;
auto sleep_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(sleep_time).count();
if (sleep_time_ms > 0) {
std::this_thread::sleep_for(std::chrono::milliseconds(sleep_time_ms));
} }
last_frame_time = std::chrono::steady_clock::now();
} }
if (tick > master_semaphore->CurrentTick() && !chunk->Empty()) {
if (tick > 0) {
if (tick >= master_semaphore->CurrentTick()) {
Flush(); Flush();
} }
master_semaphore->Wait(tick); master_semaphore->Wait(tick);
} }
/// Resets the frame pacing state by setting the next frame time.
void ResetFramePacing(double target_fps = 0.0) {
if (target_fps > 0.0) {
auto frame_duration = std::chrono::duration_cast<std::chrono::steady_clock::duration>(std::chrono::duration<double>(1.0 / target_fps));
next_frame_time = std::chrono::steady_clock::now() + frame_duration;
} else {
next_frame_time = std::chrono::steady_clock::time_point{};
}
} }
/// Returns the master timeline semaphore. /// Returns the master timeline semaphore.
@ -282,7 +277,7 @@ private:
std::condition_variable_any event_cv; std::condition_variable_any event_cv;
std::jthread worker_thread; std::jthread worker_thread;
std::chrono::steady_clock::time_point next_frame_time{};
std::chrono::steady_clock::time_point last_frame_time{};
}; };
} // namespace Vulkan } // namespace Vulkan

21
src/video_core/renderer_vulkan/vk_swapchain.cpp

@ -146,25 +146,6 @@ void Swapchain::Create(
{ {
is_outdated = false; is_outdated = false;
is_suboptimal = false; is_suboptimal = false;
switch (Settings::values.frame_pacing_mode.GetValue()) {
case Settings::FramePacingMode::Target_Auto:
scheduler.ResetFramePacing();
break;
case Settings::FramePacingMode::Target_30:
scheduler.ResetFramePacing(30.0);
break;
case Settings::FramePacingMode::Target_60:
scheduler.ResetFramePacing(60.0);
break;
case Settings::FramePacingMode::Target_120:
scheduler.ResetFramePacing(120.0);
break;
case Settings::FramePacingMode::Target_240:
scheduler.ResetFramePacing(240.0);
break;
}
width = width_; width = width_;
height = height_; height = height_;
#ifdef ANDROID #ifdef ANDROID
@ -213,7 +194,6 @@ bool Swapchain::AcquireNextImage() {
break; break;
} }
if (resource_ticks[image_index] != 0 && !scheduler.IsFree(resource_ticks[image_index])) {
switch (Settings::values.frame_pacing_mode.GetValue()) { switch (Settings::values.frame_pacing_mode.GetValue()) {
case Settings::FramePacingMode::Target_Auto: case Settings::FramePacingMode::Target_Auto:
scheduler.Wait(resource_ticks[image_index]); scheduler.Wait(resource_ticks[image_index]);
@ -231,7 +211,6 @@ bool Swapchain::AcquireNextImage() {
scheduler.Wait(resource_ticks[image_index], 240.0); scheduler.Wait(resource_ticks[image_index], 240.0);
break; break;
} }
}
resource_ticks[image_index] = scheduler.CurrentTick(); resource_ticks[image_index] = scheduler.CurrentTick();

Loading…
Cancel
Save