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 save(const char *filename) = 0;
|
||||
virtual bool is_ready() = 0;
|
||||
virtual bool can_throttle() { return false; };
|
||||
|
||||
protected:
|
||||
Snes9xWindow *window;
|
||||
|
|
|
@ -125,11 +125,11 @@ void S9xOpenGLDisplayDriver::update(uint16_t *buffer, int width, int height, int
|
|||
if (using_glsl_shaders)
|
||||
{
|
||||
glsl_shader->render(texmap, width, height, content.x, allocation.get_height() - content.y - content.h, content.w, content.h, S9xViewportCallback);
|
||||
swap_buffers();
|
||||
return;
|
||||
}
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
else
|
||||
{
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
||||
swap_buffers();
|
||||
}
|
||||
|
@ -426,6 +426,12 @@ int S9xOpenGLDisplayDriver::init()
|
|||
|
||||
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();
|
||||
|
||||
if (config->reduce_input_lag)
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#endif
|
||||
|
||||
#include "shaders/glsl.h"
|
||||
#include "vulkan/std_chrono_throttle.hpp"
|
||||
|
||||
#define BUFFER_OFFSET(i) ((char *)(i))
|
||||
|
||||
|
@ -30,14 +31,15 @@ class S9xOpenGLDisplayDriver : public S9xDisplayDriver
|
|||
{
|
||||
public:
|
||||
S9xOpenGLDisplayDriver(Snes9xWindow *window, Snes9xConfig *config);
|
||||
void refresh(int width, int height);
|
||||
int init();
|
||||
void deinit();
|
||||
void update(uint16_t *buffer, int width, int height, int stride_in_pixels);
|
||||
void *get_parameters();
|
||||
void save(const char *filename);
|
||||
void refresh(int width, int height) override;
|
||||
int init() override;
|
||||
void deinit() override;
|
||||
void update(uint16_t *buffer, int width, int height, int stride_in_pixels) override;
|
||||
void *get_parameters() override;
|
||||
void save(const char *filename) override;
|
||||
static int query_availability();
|
||||
bool is_ready();
|
||||
bool is_ready() override;
|
||||
bool can_throttle() override { return true; };
|
||||
|
||||
private:
|
||||
bool opengl_defaults();
|
||||
|
@ -68,6 +70,8 @@ class S9xOpenGLDisplayDriver : public S9xDisplayDriver
|
|||
|
||||
OpenGLContext *context;
|
||||
|
||||
Throttle throttle;
|
||||
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
GTKGLXContext glx;
|
||||
#endif
|
||||
|
|
|
@ -119,20 +119,27 @@ void S9xVulkanDisplayDriver::update(uint16_t *buffer, int width, int height, int
|
|||
return;
|
||||
|
||||
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);
|
||||
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)
|
||||
{
|
||||
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)
|
||||
context->wait_idle();
|
||||
context->wait_idle();
|
||||
}
|
||||
|
||||
int S9xVulkanDisplayDriver::query_availability()
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "../../vulkan/vulkan_context.hpp"
|
||||
#include "../../vulkan/vulkan_shader_chain.hpp"
|
||||
#include "../../vulkan/vulkan_simple_output.hpp"
|
||||
#include "../../vulkan/std_chrono_throttle.hpp"
|
||||
|
||||
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
||||
#include "gtk_wayland_surface.h"
|
||||
|
@ -27,6 +28,7 @@ class S9xVulkanDisplayDriver : public S9xDisplayDriver
|
|||
void *get_parameters() override;
|
||||
void save(const char *filename) override;
|
||||
bool is_ready() override;
|
||||
bool can_throttle() override { return true; }
|
||||
|
||||
static int query_availability();
|
||||
|
||||
|
@ -40,6 +42,7 @@ class S9xVulkanDisplayDriver : public S9xDisplayDriver
|
|||
Window xid;
|
||||
int current_width;
|
||||
int current_height;
|
||||
Throttle throttle;
|
||||
|
||||
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
||||
std::unique_ptr<WaylandSurface> wayland_surface;
|
||||
|
|
|
@ -450,6 +450,9 @@ static void S9xThrottle(int method)
|
|||
}
|
||||
else // THROTTLE_TIMER or THROTTLE_TIMER_FRAMESKIP
|
||||
{
|
||||
if (S9xDisplayGetDriver()->can_throttle())
|
||||
return;
|
||||
|
||||
if (method == THROTTLE_TIMER_FRAMESKIP)
|
||||
{
|
||||
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 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_PAL_VCOUNTER 312
|
||||
|
|
|
@ -25,6 +25,20 @@ void Throttle::wait_for_frame()
|
|||
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()
|
||||
{
|
||||
then += frame_duration_us;
|
||||
|
|
|
@ -8,6 +8,7 @@ struct Throttle
|
|||
void advance();
|
||||
void reset();
|
||||
void wait_for_frame();
|
||||
void wait_for_frame_and_rebase_time();
|
||||
std::chrono::microseconds remaining();
|
||||
double max_frame_rate = 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)
|
||||
{
|
||||
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())
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
context->swapchain->end_frame();
|
||||
context->swapchain->end_frame_without_swap();
|
||||
|
||||
last_frame_index = current_frame_index;
|
||||
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_);
|
||||
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_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(vk::CommandBuffer cmd, uint8_t *data, int width, int height, int stride, vk::Format format);
|
||||
void construct_buffer_objects();
|
||||
|
|
|
@ -215,7 +215,7 @@ void SimpleOutput::set_filter(bool 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)
|
||||
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);
|
||||
|
||||
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
|
|
@ -11,6 +11,7 @@ class SimpleOutput
|
|||
SimpleOutput(Vulkan::Context *context, vk::Format format);
|
||||
~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_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);
|
||||
|
||||
private:
|
||||
|
|
|
@ -231,12 +231,7 @@ 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()
|
||||
void Swapchain::end_frame_without_swap()
|
||||
{
|
||||
auto &frame = frames[current_frame];
|
||||
frame.command_buffer->end();
|
||||
|
@ -249,25 +244,15 @@ bool Swapchain::end_frame()
|
|||
frame.complete.get());
|
||||
|
||||
queue.submit(submit_info, frame.fence.get());
|
||||
}
|
||||
|
||||
bool Swapchain::swap()
|
||||
{
|
||||
auto present_info = vk::PresentInfoKHR{}
|
||||
.setWaitSemaphores(frames[current_frame].complete.get())
|
||||
.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;
|
||||
|
@ -277,6 +262,12 @@ bool Swapchain::end_frame()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Swapchain::end_frame()
|
||||
{
|
||||
end_frame_without_swap();
|
||||
return swap();
|
||||
}
|
||||
|
||||
vk::Framebuffer Swapchain::get_framebuffer()
|
||||
{
|
||||
return imageviewfbs[current_swapchain_image].framebuffer.get();
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include "vulkan/vulkan.hpp"
|
||||
#include "vulkan/vulkan_handles.hpp"
|
||||
#include "vulkan/vulkan_structs.hpp"
|
||||
#include "std_chrono_throttle.hpp"
|
||||
|
||||
namespace Vulkan
|
||||
{
|
||||
|
@ -26,9 +25,10 @@ class Swapchain
|
|||
void end_render_pass();
|
||||
bool wait_on_frame(int frame_num);
|
||||
bool end_frame();
|
||||
void end_frame_without_swap();
|
||||
bool swap();
|
||||
// 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();
|
||||
|
@ -62,7 +62,6 @@ 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;
|
||||
|
|
Loading…
Reference in New Issue