vulkan: Add a throttler before present for precise frame rates.

This commit is contained in:
BearOso 2023-02-23 11:00:06 -06:00
parent 1d0dab45da
commit b82edaac96
7 changed files with 85 additions and 6 deletions

View File

@ -126,6 +126,8 @@ if(USE_SLANG)
../vulkan/vulkan_shader_chain.hpp
../vulkan/vulkan_simple_output.hpp
../vulkan/vulkan_simple_output.cpp
../vulkan/std_chrono_throttle.cpp
../vulkan/std_chrono_throttle.hpp
src/gtk_display_driver_vulkan.cpp
src/gtk_display_driver_vulkan.h)

View File

@ -92,6 +92,7 @@ int S9xVulkanDisplayDriver::init()
else
{
window->enable_widget("shader_parameters_item", true);
return 0;
}
}
@ -117,21 +118,21 @@ void S9xVulkanDisplayDriver::update(uint16_t *buffer, int width, int height, int
if (!context)
return;
if (gui_config->reduce_input_lag)
context->wait_idle();
auto viewport = S9xApplyAspect(width, height, current_width, current_height);
context->swapchain->set_max_frame_rate(60.09881389744051);
if (shaderchain)
{
shaderchain->do_frame((uint8_t *)buffer, width, height, stride_in_pixels << 1, vk::Format::eR5G6B5UnormPack16, viewport.x, viewport.y, viewport.w, viewport.h);
return;
}
else if (simple_output)
{
simple_output->set_filter(Settings.BilinearFilter);
simple_output->do_frame((uint8_t *)buffer, width, height, stride_in_pixels << 1, viewport.x, viewport.y, viewport.w, viewport.h);
}
if (gui_config->reduce_input_lag)
context->wait_idle();
}
int S9xVulkanDisplayDriver::query_availability()

View File

@ -0,0 +1,37 @@
#include "std_chrono_throttle.hpp"
#include <thread>
using namespace std::chrono;
void Throttle::set_frame_rate(double frame_rate)
{
max_frame_rate = frame_rate;
frame_duration = 1.0 / max_frame_rate;
frame_duration_us = microseconds(int64_t(frame_duration * 1000000.0));
}
microseconds Throttle::remaining()
{
auto now = time_point_cast<microseconds>(steady_clock::now());
auto diff = (now - then);
return frame_duration_us - diff;
}
void Throttle::wait_for_frame()
{
auto time_to_wait = remaining();
if (time_to_wait.count() > 0)
std::this_thread::sleep_for(time_to_wait);
}
void Throttle::advance()
{
then += frame_duration_us;
}
void Throttle::reset()
{
auto now = time_point_cast<microseconds>(steady_clock::now());
then = now;
}

View File

@ -0,0 +1,16 @@
#pragma once
#include <chrono>
struct Throttle
{
void set_frame_rate(double frame_rate);
void advance();
void reset();
void wait_for_frame();
std::chrono::microseconds remaining();
double max_frame_rate = 0.0;
double frame_duration = 0.0;
std::chrono::microseconds frame_duration_us;
std::chrono::time_point<std::chrono::steady_clock, std::chrono::microseconds> then;
};

View File

@ -1,5 +1,6 @@
#include "vulkan_swapchain.hpp"
#include "vulkan/vulkan_structs.hpp"
#include <thread>
namespace Vulkan
{
@ -230,6 +231,11 @@ bool Swapchain::begin_frame()
return true;
}
void Swapchain::set_max_frame_rate(double frame_rate)
{
throttle.set_frame_rate(frame_rate);
}
bool Swapchain::end_frame()
{
auto &frame = frames[current_frame];
@ -249,6 +255,19 @@ bool Swapchain::end_frame()
.setSwapchains(swapchain_object.get())
.setImageIndices(current_swapchain_image);
if (throttle.max_frame_rate != 0.0)
{
auto remaining = throttle.remaining();
if (remaining < -throttle.frame_duration_us / 10)
throttle.reset();
else if (remaining.count() > 0)
{
queue.waitIdle();
throttle.wait_for_frame();
throttle.advance();
}
}
auto result = queue.presentKHR(present_info);
current_frame = (current_frame + 1) % max_latency;

View File

@ -3,7 +3,7 @@
#include "vulkan/vulkan.hpp"
#include "vulkan/vulkan_handles.hpp"
#include "vulkan/vulkan_structs.hpp"
#include <deque>
#include "std_chrono_throttle.hpp"
namespace Vulkan
{
@ -28,6 +28,7 @@ class Swapchain
bool end_frame();
// Returns true if vsync setting was changed, false if it was the same
bool set_vsync(bool on);
void set_max_frame_rate(double frame_rate);
vk::Image get_image();
vk::Framebuffer get_framebuffer();
@ -61,6 +62,7 @@ class Swapchain
vk::UniqueRenderPass render_pass;
Throttle throttle;
unsigned int current_frame = 0;
unsigned int current_swapchain_image = 0;
unsigned int num_swapchain_images = 0;

View File

@ -449,6 +449,7 @@
<ClInclude Include="..\vulkan\vulkan_slang_pipeline.hpp" />
<ClInclude Include="..\vulkan\vulkan_swapchain.hpp" />
<ClInclude Include="..\vulkan\vulkan_texture.hpp" />
<ClInclude Include="..\vulkan\std_chrono_throttle.hpp" />
<ClInclude Include="AVIOutput.h" />
<ClInclude Include="CCGShader.h" />
<ClInclude Include="CD3DCG.h" />
@ -612,6 +613,7 @@
<ClCompile Include="..\vulkan\vulkan_slang_pipeline.cpp" />
<ClCompile Include="..\vulkan\vulkan_swapchain.cpp" />
<ClCompile Include="..\vulkan\vulkan_texture.cpp" />
<ClCompile Include="..\vulkan\std_chrono_throttle.cpp" />
<ClCompile Include="AVIOutput.cpp" />
<ClCompile Include="CCGShader.cpp" />
<ClCompile Include="CD3DCG.cpp" />
@ -688,4 +690,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>