mirror of https://github.com/snes9xgit/snes9x.git
vulkan: Move throttle out of swapchain.
Make the swapchain wrapper more flexible, allowing deferring the swap from the end_frame function.
This commit is contained in:
parent
b82edaac96
commit
309f9e650d
|
@ -22,6 +22,7 @@ class S9xDisplayDriver
|
||||||
virtual void *get_parameters() = 0;
|
virtual void *get_parameters() = 0;
|
||||||
virtual void save(const char *filename) = 0;
|
virtual void save(const char *filename) = 0;
|
||||||
virtual bool is_ready() = 0;
|
virtual bool is_ready() = 0;
|
||||||
|
virtual bool can_throttle() { return false; };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Snes9xWindow *window;
|
Snes9xWindow *window;
|
||||||
|
|
|
@ -125,11 +125,11 @@ void S9xOpenGLDisplayDriver::update(uint16_t *buffer, int width, int height, int
|
||||||
if (using_glsl_shaders)
|
if (using_glsl_shaders)
|
||||||
{
|
{
|
||||||
glsl_shader->render(texmap, width, height, content.x, allocation.get_height() - content.y - content.h, content.w, content.h, S9xViewportCallback);
|
glsl_shader->render(texmap, width, height, content.x, allocation.get_height() - content.y - content.h, content.w, content.h, S9xViewportCallback);
|
||||||
swap_buffers();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
{
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
}
|
||||||
|
|
||||||
swap_buffers();
|
swap_buffers();
|
||||||
}
|
}
|
||||||
|
@ -426,6 +426,12 @@ int S9xOpenGLDisplayDriver::init()
|
||||||
|
|
||||||
void S9xOpenGLDisplayDriver::swap_buffers()
|
void S9xOpenGLDisplayDriver::swap_buffers()
|
||||||
{
|
{
|
||||||
|
if (Settings.SkipFrames == THROTTLE_TIMER_FRAMESKIP || Settings.SkipFrames == THROTTLE_TIMER)
|
||||||
|
{
|
||||||
|
throttle.set_frame_rate(Settings.PAL ? PAL_PROGRESSIVE_FRAME_RATE : NTSC_PROGRESSIVE_FRAME_RATE);
|
||||||
|
throttle.wait_for_frame_and_rebase_time();
|
||||||
|
}
|
||||||
|
|
||||||
context->swap_buffers();
|
context->swap_buffers();
|
||||||
|
|
||||||
if (config->reduce_input_lag)
|
if (config->reduce_input_lag)
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "shaders/glsl.h"
|
#include "shaders/glsl.h"
|
||||||
|
#include "vulkan/std_chrono_throttle.hpp"
|
||||||
|
|
||||||
#define BUFFER_OFFSET(i) ((char *)(i))
|
#define BUFFER_OFFSET(i) ((char *)(i))
|
||||||
|
|
||||||
|
@ -30,14 +31,15 @@ class S9xOpenGLDisplayDriver : public S9xDisplayDriver
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
S9xOpenGLDisplayDriver(Snes9xWindow *window, Snes9xConfig *config);
|
S9xOpenGLDisplayDriver(Snes9xWindow *window, Snes9xConfig *config);
|
||||||
void refresh(int width, int height);
|
void refresh(int width, int height) override;
|
||||||
int init();
|
int init() override;
|
||||||
void deinit();
|
void deinit() override;
|
||||||
void update(uint16_t *buffer, int width, int height, int stride_in_pixels);
|
void update(uint16_t *buffer, int width, int height, int stride_in_pixels) override;
|
||||||
void *get_parameters();
|
void *get_parameters() override;
|
||||||
void save(const char *filename);
|
void save(const char *filename) override;
|
||||||
static int query_availability();
|
static int query_availability();
|
||||||
bool is_ready();
|
bool is_ready() override;
|
||||||
|
bool can_throttle() override { return true; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool opengl_defaults();
|
bool opengl_defaults();
|
||||||
|
@ -68,6 +70,8 @@ class S9xOpenGLDisplayDriver : public S9xDisplayDriver
|
||||||
|
|
||||||
OpenGLContext *context;
|
OpenGLContext *context;
|
||||||
|
|
||||||
|
Throttle throttle;
|
||||||
|
|
||||||
#ifdef GDK_WINDOWING_X11
|
#ifdef GDK_WINDOWING_X11
|
||||||
GTKGLXContext glx;
|
GTKGLXContext glx;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -119,20 +119,27 @@ void S9xVulkanDisplayDriver::update(uint16_t *buffer, int width, int height, int
|
||||||
return;
|
return;
|
||||||
|
|
||||||
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_without_swap((uint8_t *)buffer, width, height, stride_in_pixels << 1, vk::Format::eR5G6B5UnormPack16, viewport.x, viewport.y, viewport.w, viewport.h);
|
||||||
}
|
}
|
||||||
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_without_swap((uint8_t *)buffer, width, height, stride_in_pixels << 1, viewport.x, viewport.y, viewport.w, viewport.h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Settings.SkipFrames == THROTTLE_TIMER || Settings.SkipFrames == THROTTLE_TIMER_FRAMESKIP)
|
||||||
|
{
|
||||||
|
throttle.set_frame_rate(Settings.PAL ? PAL_PROGRESSIVE_FRAME_RATE : NTSC_PROGRESSIVE_FRAME_RATE);
|
||||||
|
throttle.wait_for_frame_and_rebase_time();
|
||||||
|
}
|
||||||
|
|
||||||
|
context->swapchain->swap();
|
||||||
|
|
||||||
if (gui_config->reduce_input_lag)
|
if (gui_config->reduce_input_lag)
|
||||||
context->wait_idle();
|
context->wait_idle();
|
||||||
}
|
}
|
||||||
|
|
||||||
int S9xVulkanDisplayDriver::query_availability()
|
int S9xVulkanDisplayDriver::query_availability()
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "../../vulkan/vulkan_context.hpp"
|
#include "../../vulkan/vulkan_context.hpp"
|
||||||
#include "../../vulkan/vulkan_shader_chain.hpp"
|
#include "../../vulkan/vulkan_shader_chain.hpp"
|
||||||
#include "../../vulkan/vulkan_simple_output.hpp"
|
#include "../../vulkan/vulkan_simple_output.hpp"
|
||||||
|
#include "../../vulkan/std_chrono_throttle.hpp"
|
||||||
|
|
||||||
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
||||||
#include "gtk_wayland_surface.h"
|
#include "gtk_wayland_surface.h"
|
||||||
|
@ -27,6 +28,7 @@ class S9xVulkanDisplayDriver : public S9xDisplayDriver
|
||||||
void *get_parameters() override;
|
void *get_parameters() override;
|
||||||
void save(const char *filename) override;
|
void save(const char *filename) override;
|
||||||
bool is_ready() override;
|
bool is_ready() override;
|
||||||
|
bool can_throttle() override { return true; }
|
||||||
|
|
||||||
static int query_availability();
|
static int query_availability();
|
||||||
|
|
||||||
|
@ -40,6 +42,7 @@ class S9xVulkanDisplayDriver : public S9xDisplayDriver
|
||||||
Window xid;
|
Window xid;
|
||||||
int current_width;
|
int current_width;
|
||||||
int current_height;
|
int current_height;
|
||||||
|
Throttle throttle;
|
||||||
|
|
||||||
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
||||||
std::unique_ptr<WaylandSurface> wayland_surface;
|
std::unique_ptr<WaylandSurface> wayland_surface;
|
||||||
|
|
|
@ -450,6 +450,9 @@ static void S9xThrottle(int method)
|
||||||
}
|
}
|
||||||
else // THROTTLE_TIMER or THROTTLE_TIMER_FRAMESKIP
|
else // THROTTLE_TIMER or THROTTLE_TIMER_FRAMESKIP
|
||||||
{
|
{
|
||||||
|
if (S9xDisplayGetDriver()->can_throttle())
|
||||||
|
return;
|
||||||
|
|
||||||
if (method == THROTTLE_TIMER_FRAMESKIP)
|
if (method == THROTTLE_TIMER_FRAMESKIP)
|
||||||
{
|
{
|
||||||
if (now - frame_clock > Settings.FrameTime)
|
if (now - frame_clock > Settings.FrameTime)
|
||||||
|
|
4
snes9x.h
4
snes9x.h
|
@ -61,6 +61,10 @@
|
||||||
|
|
||||||
#define NTSC_MASTER_CLOCK 21477272.727272 // 21477272 + 8/11 exact
|
#define NTSC_MASTER_CLOCK 21477272.727272 // 21477272 + 8/11 exact
|
||||||
#define PAL_MASTER_CLOCK 21281370.0
|
#define PAL_MASTER_CLOCK 21281370.0
|
||||||
|
#define NTSC_PROGRESSIVE_FRAME_RATE 60.09881389744051
|
||||||
|
#define NTSC_INTERLACED_FRAME_RATE 59.94005994
|
||||||
|
#define PAL_PROGRESSIVE_FRAME_RATE 50.006977968
|
||||||
|
|
||||||
|
|
||||||
#define SNES_MAX_NTSC_VCOUNTER 262
|
#define SNES_MAX_NTSC_VCOUNTER 262
|
||||||
#define SNES_MAX_PAL_VCOUNTER 312
|
#define SNES_MAX_PAL_VCOUNTER 312
|
||||||
|
|
|
@ -25,6 +25,20 @@ void Throttle::wait_for_frame()
|
||||||
std::this_thread::sleep_for(time_to_wait);
|
std::this_thread::sleep_for(time_to_wait);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Throttle::wait_for_frame_and_rebase_time()
|
||||||
|
{
|
||||||
|
auto time_to_wait = remaining();
|
||||||
|
|
||||||
|
if (time_to_wait < -frame_duration_us / 10)
|
||||||
|
reset();
|
||||||
|
|
||||||
|
if (time_to_wait.count() > 0)
|
||||||
|
{
|
||||||
|
std::this_thread::sleep_for(time_to_wait);
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Throttle::advance()
|
void Throttle::advance()
|
||||||
{
|
{
|
||||||
then += frame_duration_us;
|
then += frame_duration_us;
|
||||||
|
|
|
@ -8,6 +8,7 @@ struct Throttle
|
||||||
void advance();
|
void advance();
|
||||||
void reset();
|
void reset();
|
||||||
void wait_for_frame();
|
void wait_for_frame();
|
||||||
|
void wait_for_frame_and_rebase_time();
|
||||||
std::chrono::microseconds remaining();
|
std::chrono::microseconds remaining();
|
||||||
double max_frame_rate = 0.0;
|
double max_frame_rate = 0.0;
|
||||||
double frame_duration = 0.0;
|
double frame_duration = 0.0;
|
||||||
|
|
|
@ -390,6 +390,12 @@ void ShaderChain::update_descriptor_set(vk::CommandBuffer cmd, int pipe_num, int
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderChain::do_frame(uint8_t *data, int width, int height, int stride, vk::Format format, int viewport_x, int viewport_y, int viewport_width, int viewport_height)
|
void ShaderChain::do_frame(uint8_t *data, int width, int height, int stride, vk::Format format, int viewport_x, int viewport_y, int viewport_width, int viewport_height)
|
||||||
|
{
|
||||||
|
do_frame_without_swap(data, width, height, stride, format, viewport_x, viewport_y, viewport_width, viewport_height);
|
||||||
|
context->swapchain->swap();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderChain::do_frame_without_swap(uint8_t *data, int width, int height, int stride, vk::Format format, int viewport_x, int viewport_y, int viewport_width, int viewport_height)
|
||||||
{
|
{
|
||||||
if (!context->swapchain->begin_frame())
|
if (!context->swapchain->begin_frame())
|
||||||
return;
|
return;
|
||||||
|
@ -508,8 +514,7 @@ void ShaderChain::do_frame(uint8_t *data, int width, int height, int stride, vk:
|
||||||
frame.image.current_layout = vk::ImageLayout::eTransferDstOptimal;
|
frame.image.current_layout = vk::ImageLayout::eTransferDstOptimal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
context->swapchain->end_frame_without_swap();
|
||||||
context->swapchain->end_frame();
|
|
||||||
|
|
||||||
last_frame_index = current_frame_index;
|
last_frame_index = current_frame_index;
|
||||||
frame_count++;
|
frame_count++;
|
||||||
|
|
|
@ -20,6 +20,7 @@ class ShaderChain
|
||||||
void update_and_propagate_sizes(int original_width_, int original_height_, int viewport_width_, int viewport_height_);
|
void update_and_propagate_sizes(int original_width_, int original_height_, int viewport_width_, int viewport_height_);
|
||||||
bool load_lookup_textures();
|
bool load_lookup_textures();
|
||||||
void do_frame(uint8_t *data, int width, int height, int stride, vk::Format format, int viewport_x, int viewport_y, int viewport_width, int viewport_height);
|
void do_frame(uint8_t *data, int width, int height, int stride, vk::Format format, int viewport_x, int viewport_y, int viewport_width, int viewport_height);
|
||||||
|
void do_frame_without_swap(uint8_t *data, int width, int height, int stride, vk::Format format, int viewport_x, int viewport_y, int viewport_width, int viewport_height);
|
||||||
void upload_original(uint8_t *data, int width, int height, int stride, vk::Format format);
|
void upload_original(uint8_t *data, int width, int height, int stride, vk::Format format);
|
||||||
void upload_original(vk::CommandBuffer cmd, uint8_t *data, int width, int height, int stride, vk::Format format);
|
void upload_original(vk::CommandBuffer cmd, uint8_t *data, int width, int height, int stride, vk::Format format);
|
||||||
void construct_buffer_objects();
|
void construct_buffer_objects();
|
||||||
|
|
|
@ -215,7 +215,7 @@ void SimpleOutput::set_filter(bool on)
|
||||||
filter = on;
|
filter = on;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimpleOutput::do_frame(uint8_t *buffer, int width, int height, int byte_stride, int viewport_x, int viewport_y, int viewport_width, int viewport_height)
|
void SimpleOutput::do_frame_without_swap(uint8_t *buffer, int width, int height, int byte_stride, int viewport_x, int viewport_y, int viewport_width, int viewport_height)
|
||||||
{
|
{
|
||||||
if (!context)
|
if (!context)
|
||||||
return;
|
return;
|
||||||
|
@ -252,7 +252,13 @@ void SimpleOutput::do_frame(uint8_t *buffer, int width, int height, int byte_str
|
||||||
cmd.draw(3, 1, 0, 0);
|
cmd.draw(3, 1, 0, 0);
|
||||||
|
|
||||||
swapchain->end_render_pass();
|
swapchain->end_render_pass();
|
||||||
swapchain->end_frame();
|
swapchain->end_frame_without_swap();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleOutput::do_frame(uint8_t *buffer, int width, int height, int byte_stride, int viewport_x, int viewport_y, int viewport_width, int viewport_height)
|
||||||
|
{
|
||||||
|
do_frame_without_swap(buffer, width, height, byte_stride, viewport_x, viewport_y, viewport_width, viewport_height);
|
||||||
|
swapchain->swap();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
|
@ -11,6 +11,7 @@ class SimpleOutput
|
||||||
SimpleOutput(Vulkan::Context *context, vk::Format format);
|
SimpleOutput(Vulkan::Context *context, vk::Format format);
|
||||||
~SimpleOutput();
|
~SimpleOutput();
|
||||||
void do_frame(uint8_t *buffer, int width, int height, int byte_stride, int viewport_x, int viewport_y, int viewport_width, int viewport_height);
|
void do_frame(uint8_t *buffer, int width, int height, int byte_stride, int viewport_x, int viewport_y, int viewport_width, int viewport_height);
|
||||||
|
void do_frame_without_swap(uint8_t *buffer, int width, int height, int byte_stride, int viewport_x, int viewport_y, int viewport_width, int viewport_height);
|
||||||
void set_filter(bool on);
|
void set_filter(bool on);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -231,12 +231,7 @@ bool Swapchain::begin_frame()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Swapchain::set_max_frame_rate(double frame_rate)
|
void Swapchain::end_frame_without_swap()
|
||||||
{
|
|
||||||
throttle.set_frame_rate(frame_rate);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Swapchain::end_frame()
|
|
||||||
{
|
{
|
||||||
auto &frame = frames[current_frame];
|
auto &frame = frames[current_frame];
|
||||||
frame.command_buffer->end();
|
frame.command_buffer->end();
|
||||||
|
@ -249,25 +244,15 @@ bool Swapchain::end_frame()
|
||||||
frame.complete.get());
|
frame.complete.get());
|
||||||
|
|
||||||
queue.submit(submit_info, frame.fence.get());
|
queue.submit(submit_info, frame.fence.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Swapchain::swap()
|
||||||
|
{
|
||||||
auto present_info = vk::PresentInfoKHR{}
|
auto present_info = vk::PresentInfoKHR{}
|
||||||
.setWaitSemaphores(frames[current_frame].complete.get())
|
.setWaitSemaphores(frames[current_frame].complete.get())
|
||||||
.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;
|
||||||
|
@ -277,6 +262,12 @@ bool Swapchain::end_frame()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Swapchain::end_frame()
|
||||||
|
{
|
||||||
|
end_frame_without_swap();
|
||||||
|
return swap();
|
||||||
|
}
|
||||||
|
|
||||||
vk::Framebuffer Swapchain::get_framebuffer()
|
vk::Framebuffer Swapchain::get_framebuffer()
|
||||||
{
|
{
|
||||||
return imageviewfbs[current_swapchain_image].framebuffer.get();
|
return imageviewfbs[current_swapchain_image].framebuffer.get();
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
#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 "std_chrono_throttle.hpp"
|
|
||||||
|
|
||||||
namespace Vulkan
|
namespace Vulkan
|
||||||
{
|
{
|
||||||
|
@ -26,9 +25,10 @@ class Swapchain
|
||||||
void end_render_pass();
|
void end_render_pass();
|
||||||
bool wait_on_frame(int frame_num);
|
bool wait_on_frame(int frame_num);
|
||||||
bool end_frame();
|
bool end_frame();
|
||||||
|
void end_frame_without_swap();
|
||||||
|
bool swap();
|
||||||
// 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();
|
||||||
|
@ -62,7 +62,6 @@ 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;
|
||||||
|
|
Loading…
Reference in New Issue