HostDisplay: Add threaded presentation for Vulkan renderer

Can add a significant speedup for fast forward. Automatically disabled
when vsync is enabled.
This commit is contained in:
Connor McLaughlin
2020-12-26 23:22:24 +10:00
parent 1a6a14fcd4
commit 702ed21207
29 changed files with 241 additions and 76 deletions

View File

@ -34,6 +34,8 @@ DisplaySettingsWidget::DisplaySettingsWidget(QtHostInterface* host_interface, QW
"IntegerScaling");
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.vsync, "Display", "VSync");
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.gpuThread, "GPU", "UseThread", true);
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.threadedPresentation, "GPU",
"ThreadedPresentation", true);
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.showOSDMessages, "Display", "ShowOSDMessages",
true);
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.showFPS, "Display", "ShowFPS", false);
@ -85,6 +87,9 @@ DisplaySettingsWidget::DisplaySettingsWidget(QtHostInterface* host_interface, QW
m_ui.vsync, tr("VSync"), tr("Checked"),
tr("Enable this option to match DuckStation's refresh rate with your current monitor or screen. "
"VSync is automatically disabled when it is not possible (e.g. running at non-100% speed)."));
dialog->registerWidgetHelp(m_ui.threadedPresentation, tr("Threaded Presentation"), tr("Checked"),
tr("Presents frames on a background thread when fast forwarding or vsync is disabled. "
"This can measurably improve performance in the Vulkan renderer."));
dialog->registerWidgetHelp(m_ui.gpuThread, tr("Threaded Rendering"), tr("Checked"),
tr("Uses a second thread for drawing graphics. Currently only available for the software "
"renderer, but can provide a significant speed improvement, and is safe to use."));
@ -104,7 +109,7 @@ DisplaySettingsWidget::DisplaySettingsWidget(QtHostInterface* host_interface, QW
{
QCheckBox* cb = new QCheckBox(tr("Use Blit Swap Chain"), m_ui.basicGroupBox);
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, cb, "Display", "UseBlitSwapChain", false);
m_ui.basicCheckboxGridLayout->addWidget(cb, 1, 0, 1, 1);
m_ui.basicCheckboxGridLayout->addWidget(cb, 1, 1, 1, 1);
dialog->registerWidgetHelp(cb, tr("Use Blit Swap Chain"), tr("Unchecked"),
tr("Uses a blit presentation model instead of flipping when using the Direct3D 11 "
"renderer. This usually results in slower performance, but may be required for some "
@ -141,6 +146,7 @@ void DisplaySettingsWidget::populateGPUAdaptersAndResolutions()
std::vector<std::string> adapter_names;
std::vector<std::string> fullscreen_modes;
bool thread_supported = false;
bool threaded_presentation_supported = false;
switch (static_cast<GPURenderer>(m_ui.renderer->currentIndex()))
{
#ifdef WIN32
@ -155,6 +161,7 @@ void DisplaySettingsWidget::populateGPUAdaptersAndResolutions()
case GPURenderer::HardwareVulkan:
adapter_names = FrontendCommon::VulkanHostDisplay::EnumerateAdapterNames();
threaded_presentation_supported = true;
break;
case GPURenderer::Software:
@ -207,6 +214,7 @@ void DisplaySettingsWidget::populateGPUAdaptersAndResolutions()
}
m_ui.gpuThread->setEnabled(thread_supported);
m_ui.threadedPresentation->setEnabled(threaded_presentation_supported);
}
void DisplaySettingsWidget::onGPUAdapterIndexChanged()

View File

@ -78,6 +78,13 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="threadedPresentation">
<property name="text">
<string>Threaded Presentation</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>

View File

@ -90,8 +90,7 @@ bool MainWindow::shouldHideCursorInFullscreen() const
return g_host_interface->GetBoolSettingValue("Main", "HideCursorInFullscreen", true);
}
QtDisplayWidget* MainWindow::createDisplay(QThread* worker_thread, const QString& adapter_name, bool use_debug_device,
bool fullscreen, bool render_to_main)
QtDisplayWidget* MainWindow::createDisplay(QThread* worker_thread, bool fullscreen, bool render_to_main)
{
Assert(!m_host_display && !m_display_widget);
Assert(!fullscreen || !render_to_main);
@ -143,7 +142,8 @@ QtDisplayWidget* MainWindow::createDisplay(QThread* worker_thread, const QString
return nullptr;
}
if (!m_host_display->CreateRenderDevice(wi.value(), adapter_name.toStdString(), use_debug_device))
if (!m_host_display->CreateRenderDevice(wi.value(), g_settings.gpu_adapter, g_settings.gpu_use_debug_device,
g_settings.gpu_threaded_presentation))
{
reportError(tr("Failed to create host display device context."));
destroyDisplayWidget();
@ -815,11 +815,14 @@ void MainWindow::updateEmulationActions(bool starting, bool running)
}
}
if (g_settings.debugging.enable_gdb_server) {
if (starting && !m_gdb_server) {
if (g_settings.debugging.enable_gdb_server)
{
if (starting && !m_gdb_server)
{
m_gdb_server = new GDBServer(this, g_settings.debugging.gdb_server_port);
}
else if (!running && m_gdb_server) {
else if (!running && m_gdb_server)
{
delete m_gdb_server;
m_gdb_server = nullptr;
}

View File

@ -47,8 +47,7 @@ private Q_SLOTS:
void reportError(const QString& message);
void reportMessage(const QString& message);
bool confirmMessage(const QString& message);
QtDisplayWidget* createDisplay(QThread* worker_thread, const QString& adapter_name, bool use_debug_device,
bool fullscreen, bool render_to_main);
QtDisplayWidget* createDisplay(QThread* worker_thread, bool fullscreen, bool render_to_main);
QtDisplayWidget* updateDisplay(QThread* worker_thread, bool fullscreen, bool render_to_main);
void displaySizeRequested(qint32 width, qint32 height);
void destroyDisplay();

View File

@ -488,9 +488,7 @@ bool QtHostInterface::AcquireHostDisplay()
m_is_rendering_to_main = m_settings_interface->GetBoolValue("Main", "RenderToMainWindow", true);
QtDisplayWidget* display_widget =
createDisplayRequested(m_worker_thread, QString::fromStdString(g_settings.gpu_adapter),
g_settings.gpu_use_debug_device, m_is_fullscreen, m_is_rendering_to_main);
QtDisplayWidget* display_widget = createDisplayRequested(m_worker_thread, m_is_fullscreen, m_is_rendering_to_main);
if (!display_widget || !m_display->HasRenderDevice())
{
emit destroyDisplayRequested();
@ -501,7 +499,8 @@ bool QtHostInterface::AcquireHostDisplay()
createImGuiContext(display_widget->devicePixelRatioFromScreen());
if (!m_display->MakeRenderContextCurrent() ||
!m_display->InitializeRenderDevice(GetShaderCacheBasePath(), g_settings.gpu_use_debug_device) ||
!m_display->InitializeRenderDevice(GetShaderCacheBasePath(), g_settings.gpu_use_debug_device,
g_settings.gpu_threaded_presentation) ||
!CreateHostDisplayResources())
{
destroyImGuiContext();

View File

@ -129,8 +129,7 @@ Q_SIGNALS:
void emulationPaused(bool paused);
void stateSaved(const QString& game_code, bool global, qint32 slot);
void gameListRefreshed();
QtDisplayWidget* createDisplayRequested(QThread* worker_thread, const QString& adapter_name, bool use_debug_device,
bool fullscreen, bool render_to_main);
QtDisplayWidget* createDisplayRequested(QThread* worker_thread, bool fullscreen, bool render_to_main);
QtDisplayWidget* updateDisplayRequested(QThread* worker_thread, bool fullscreen, bool render_to_main);
void displaySizeRequested(qint32 width, qint32 height);
void focusDisplayWidgetRequested();