mirror of https://github.com/snes9xgit/snes9x.git
vulkan: Add a throttler before present for precise frame rates.
This commit is contained in:
parent
1d0dab45da
commit
b82edaac96
|
@ -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)
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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" />
|
||||
|
|
Loading…
Reference in New Issue