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_shader_chain.hpp
|
||||||
../vulkan/vulkan_simple_output.hpp
|
../vulkan/vulkan_simple_output.hpp
|
||||||
../vulkan/vulkan_simple_output.cpp
|
../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.cpp
|
||||||
src/gtk_display_driver_vulkan.h)
|
src/gtk_display_driver_vulkan.h)
|
||||||
|
|
||||||
|
|
|
@ -92,6 +92,7 @@ int S9xVulkanDisplayDriver::init()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
window->enable_widget("shader_parameters_item", true);
|
window->enable_widget("shader_parameters_item", true);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,21 +118,21 @@ void S9xVulkanDisplayDriver::update(uint16_t *buffer, int width, int height, int
|
||||||
if (!context)
|
if (!context)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (gui_config->reduce_input_lag)
|
|
||||||
context->wait_idle();
|
|
||||||
|
|
||||||
auto viewport = S9xApplyAspect(width, height, current_width, current_height);
|
auto viewport = S9xApplyAspect(width, height, current_width, current_height);
|
||||||
|
context->swapchain->set_max_frame_rate(60.09881389744051);
|
||||||
|
|
||||||
if (shaderchain)
|
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);
|
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)
|
else if (simple_output)
|
||||||
{
|
{
|
||||||
simple_output->set_filter(Settings.BilinearFilter);
|
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);
|
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()
|
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_swapchain.hpp"
|
||||||
#include "vulkan/vulkan_structs.hpp"
|
#include "vulkan/vulkan_structs.hpp"
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
namespace Vulkan
|
namespace Vulkan
|
||||||
{
|
{
|
||||||
|
@ -230,6 +231,11 @@ bool Swapchain::begin_frame()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Swapchain::set_max_frame_rate(double frame_rate)
|
||||||
|
{
|
||||||
|
throttle.set_frame_rate(frame_rate);
|
||||||
|
}
|
||||||
|
|
||||||
bool Swapchain::end_frame()
|
bool Swapchain::end_frame()
|
||||||
{
|
{
|
||||||
auto &frame = frames[current_frame];
|
auto &frame = frames[current_frame];
|
||||||
|
@ -249,6 +255,19 @@ bool Swapchain::end_frame()
|
||||||
.setSwapchains(swapchain_object.get())
|
.setSwapchains(swapchain_object.get())
|
||||||
.setImageIndices(current_swapchain_image);
|
.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);
|
auto result = queue.presentKHR(present_info);
|
||||||
|
|
||||||
current_frame = (current_frame + 1) % max_latency;
|
current_frame = (current_frame + 1) % max_latency;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include "vulkan/vulkan.hpp"
|
#include "vulkan/vulkan.hpp"
|
||||||
#include "vulkan/vulkan_handles.hpp"
|
#include "vulkan/vulkan_handles.hpp"
|
||||||
#include "vulkan/vulkan_structs.hpp"
|
#include "vulkan/vulkan_structs.hpp"
|
||||||
#include <deque>
|
#include "std_chrono_throttle.hpp"
|
||||||
|
|
||||||
namespace Vulkan
|
namespace Vulkan
|
||||||
{
|
{
|
||||||
|
@ -28,6 +28,7 @@ class Swapchain
|
||||||
bool end_frame();
|
bool end_frame();
|
||||||
// Returns true if vsync setting was changed, false if it was the same
|
// Returns true if vsync setting was changed, false if it was the same
|
||||||
bool set_vsync(bool on);
|
bool set_vsync(bool on);
|
||||||
|
void set_max_frame_rate(double frame_rate);
|
||||||
|
|
||||||
vk::Image get_image();
|
vk::Image get_image();
|
||||||
vk::Framebuffer get_framebuffer();
|
vk::Framebuffer get_framebuffer();
|
||||||
|
@ -61,6 +62,7 @@ class Swapchain
|
||||||
|
|
||||||
vk::UniqueRenderPass render_pass;
|
vk::UniqueRenderPass render_pass;
|
||||||
|
|
||||||
|
Throttle throttle;
|
||||||
unsigned int current_frame = 0;
|
unsigned int current_frame = 0;
|
||||||
unsigned int current_swapchain_image = 0;
|
unsigned int current_swapchain_image = 0;
|
||||||
unsigned int num_swapchain_images = 0;
|
unsigned int num_swapchain_images = 0;
|
||||||
|
|
|
@ -449,6 +449,7 @@
|
||||||
<ClInclude Include="..\vulkan\vulkan_slang_pipeline.hpp" />
|
<ClInclude Include="..\vulkan\vulkan_slang_pipeline.hpp" />
|
||||||
<ClInclude Include="..\vulkan\vulkan_swapchain.hpp" />
|
<ClInclude Include="..\vulkan\vulkan_swapchain.hpp" />
|
||||||
<ClInclude Include="..\vulkan\vulkan_texture.hpp" />
|
<ClInclude Include="..\vulkan\vulkan_texture.hpp" />
|
||||||
|
<ClInclude Include="..\vulkan\std_chrono_throttle.hpp" />
|
||||||
<ClInclude Include="AVIOutput.h" />
|
<ClInclude Include="AVIOutput.h" />
|
||||||
<ClInclude Include="CCGShader.h" />
|
<ClInclude Include="CCGShader.h" />
|
||||||
<ClInclude Include="CD3DCG.h" />
|
<ClInclude Include="CD3DCG.h" />
|
||||||
|
@ -612,6 +613,7 @@
|
||||||
<ClCompile Include="..\vulkan\vulkan_slang_pipeline.cpp" />
|
<ClCompile Include="..\vulkan\vulkan_slang_pipeline.cpp" />
|
||||||
<ClCompile Include="..\vulkan\vulkan_swapchain.cpp" />
|
<ClCompile Include="..\vulkan\vulkan_swapchain.cpp" />
|
||||||
<ClCompile Include="..\vulkan\vulkan_texture.cpp" />
|
<ClCompile Include="..\vulkan\vulkan_texture.cpp" />
|
||||||
|
<ClCompile Include="..\vulkan\std_chrono_throttle.cpp" />
|
||||||
<ClCompile Include="AVIOutput.cpp" />
|
<ClCompile Include="AVIOutput.cpp" />
|
||||||
<ClCompile Include="CCGShader.cpp" />
|
<ClCompile Include="CCGShader.cpp" />
|
||||||
<ClCompile Include="CD3DCG.cpp" />
|
<ClCompile Include="CD3DCG.cpp" />
|
||||||
|
@ -688,4 +690,4 @@
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
Loading…
Reference in New Issue