mirror of https://github.com/snes9xgit/snes9x.git
170 lines
4.9 KiB
C++
170 lines
4.9 KiB
C++
/*****************************************************************************\
|
|
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
|
|
This file is licensed under the Snes9x License.
|
|
For further information, consult the LICENSE file in the root directory.
|
|
\*****************************************************************************/
|
|
|
|
#include "gtk_compat.h"
|
|
#include "gtk_display.h"
|
|
#include "gtk_display_driver_vulkan.h"
|
|
#include "gtk_shader_parameters.h"
|
|
#include "snes9x.h"
|
|
#include "gfx.h"
|
|
#include "fmt/format.h"
|
|
|
|
S9xVulkanDisplayDriver::S9xVulkanDisplayDriver(Snes9xWindow *_window, Snes9xConfig *_config)
|
|
{
|
|
window = _window;
|
|
config = _config;
|
|
drawing_area = window->drawing_area;
|
|
gdk_window = nullptr;
|
|
gdk_display = nullptr;
|
|
context.reset();
|
|
}
|
|
|
|
S9xVulkanDisplayDriver::~S9xVulkanDisplayDriver()
|
|
{
|
|
}
|
|
|
|
void S9xVulkanDisplayDriver::refresh(int width, int height)
|
|
{
|
|
if (!context)
|
|
return;
|
|
|
|
bool vsync_changed = context->swapchain->set_vsync(gui_config->sync_to_vblank);
|
|
|
|
auto new_width = drawing_area->get_width() * drawing_area->get_scale_factor();
|
|
auto new_height = drawing_area->get_height() * drawing_area->get_scale_factor();
|
|
|
|
if (new_width != current_width || new_height != current_height || vsync_changed)
|
|
{
|
|
#ifdef GDK_WINDOWING_WAYLAND
|
|
if (GDK_IS_WAYLAND_WINDOW(drawing_area->get_window()->gobj()))
|
|
{
|
|
wayland_surface->resize();
|
|
}
|
|
#endif
|
|
context->recreate_swapchain(new_width, new_height);
|
|
context->wait_idle();
|
|
current_width = new_width;
|
|
current_height = new_height;
|
|
}
|
|
|
|
context->swapchain->set_vsync(gui_config->sync_to_vblank);
|
|
}
|
|
|
|
int S9xVulkanDisplayDriver::init()
|
|
{
|
|
current_width = drawing_area->get_width() * drawing_area->get_scale_factor();
|
|
current_height = drawing_area->get_height() * drawing_area->get_scale_factor();
|
|
|
|
context = std::make_unique<Vulkan::Context>();
|
|
|
|
#ifdef GDK_WINDOWING_WAYLAND
|
|
if (GDK_IS_WAYLAND_WINDOW(drawing_area->get_window()->gobj()))
|
|
{
|
|
wayland_surface = std::make_unique<WaylandSurface>();
|
|
if (!wayland_surface->attach(GTK_WIDGET(drawing_area->gobj())))
|
|
{
|
|
return -1;
|
|
}
|
|
context->init_wayland(wayland_surface->display, wayland_surface->child, current_width, current_height);
|
|
}
|
|
#endif
|
|
if (GDK_IS_X11_WINDOW(drawing_area->get_window()->gobj()))
|
|
{
|
|
display = gdk_x11_display_get_xdisplay(drawing_area->get_display()->gobj());
|
|
xid = gdk_x11_window_get_xid(drawing_area->get_window()->gobj());
|
|
|
|
context->init_Xlib(display, xid);
|
|
}
|
|
|
|
device = context->device;
|
|
|
|
if (!gui_config->shader_filename.empty() && gui_config->use_shaders)
|
|
{
|
|
shaderchain = std::make_unique<Vulkan::ShaderChain>(context.get());
|
|
if (!shaderchain->load_shader_preset(gui_config->shader_filename))
|
|
{
|
|
fmt::print("Couldn't load shader preset file\n");
|
|
shaderchain = nullptr;
|
|
}
|
|
else
|
|
{
|
|
window->enable_widget("shader_parameters_item", true);
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
simple_output = std::make_unique<Vulkan::SimpleOutput>(context.get(), vk::Format::eR5G6B5UnormPack16);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void S9xVulkanDisplayDriver::deinit()
|
|
{
|
|
if (!context)
|
|
return;
|
|
|
|
if (shaderchain)
|
|
gtk_shader_parameters_dialog_close();
|
|
|
|
context->wait_idle();
|
|
}
|
|
|
|
void S9xVulkanDisplayDriver::update(uint16_t *buffer, int width, int height, int stride_in_pixels)
|
|
{
|
|
if (!context)
|
|
return;
|
|
|
|
auto viewport = S9xApplyAspect(width, height, current_width, current_height);
|
|
bool retval = false;
|
|
|
|
if (shaderchain)
|
|
{
|
|
retval = 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);
|
|
retval = simple_output->do_frame_without_swap((uint8_t *)buffer, width, height, stride_in_pixels << 1, viewport.x, viewport.y, viewport.w, viewport.h);
|
|
}
|
|
|
|
if (retval)
|
|
{
|
|
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();
|
|
}
|
|
}
|
|
|
|
int S9xVulkanDisplayDriver::query_availability()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void *S9xVulkanDisplayDriver::get_parameters()
|
|
{
|
|
if (shaderchain)
|
|
return &shaderchain->preset->parameters;
|
|
return nullptr;
|
|
}
|
|
|
|
void S9xVulkanDisplayDriver::save(const char *filename)
|
|
{
|
|
if (shaderchain)
|
|
shaderchain->preset->save_to_file(filename);
|
|
}
|
|
|
|
bool S9xVulkanDisplayDriver::is_ready()
|
|
{
|
|
return true;
|
|
} |