renderer_vulkan: Add single-thread record ability to the scheduler

* Async is pretty nice but games that do a lot of flushes might have worse performance due to thread synchronization overhead

* I haven't noticed any cases of this yet but it doesn't hurt making this a UI option
This commit is contained in:
GPUCode
2022-10-27 14:22:03 +03:00
parent 3c09c03180
commit f9274f8b9a
8 changed files with 43 additions and 9 deletions

View File

@ -604,6 +604,7 @@ void Config::ReadRendererValues() {
qt_config->beginGroup(QStringLiteral("Renderer")); qt_config->beginGroup(QStringLiteral("Renderer"));
ReadGlobalSetting(Settings::values.physical_device); ReadGlobalSetting(Settings::values.physical_device);
ReadGlobalSetting(Settings::values.async_command_recording);
ReadGlobalSetting(Settings::values.graphics_api); ReadGlobalSetting(Settings::values.graphics_api);
ReadGlobalSetting(Settings::values.use_hw_renderer); ReadGlobalSetting(Settings::values.use_hw_renderer);
ReadGlobalSetting(Settings::values.use_hw_shader); ReadGlobalSetting(Settings::values.use_hw_shader);
@ -1085,6 +1086,7 @@ void Config::SaveRendererValues() {
WriteGlobalSetting(Settings::values.graphics_api); WriteGlobalSetting(Settings::values.graphics_api);
WriteGlobalSetting(Settings::values.physical_device); WriteGlobalSetting(Settings::values.physical_device);
WriteGlobalSetting(Settings::values.async_command_recording);
WriteGlobalSetting(Settings::values.use_hw_renderer); WriteGlobalSetting(Settings::values.use_hw_renderer);
WriteGlobalSetting(Settings::values.use_hw_shader); WriteGlobalSetting(Settings::values.use_hw_shader);
#ifdef __APPLE__ #ifdef __APPLE__

View File

@ -85,6 +85,7 @@ void ConfigureGraphics::SetConfiguration() {
ui->toggle_vsync_new->setChecked(Settings::values.use_vsync_new.GetValue()); ui->toggle_vsync_new->setChecked(Settings::values.use_vsync_new.GetValue());
ui->graphics_api_combo->setCurrentIndex(static_cast<int>(Settings::values.graphics_api.GetValue())); ui->graphics_api_combo->setCurrentIndex(static_cast<int>(Settings::values.graphics_api.GetValue()));
ui->physical_device_combo->setCurrentIndex(static_cast<int>(Settings::values.physical_device.GetValue())); ui->physical_device_combo->setCurrentIndex(static_cast<int>(Settings::values.physical_device.GetValue()));
ui->toggle_async_recording->setChecked(Settings::values.async_command_recording.GetValue());
if (Settings::IsConfiguringGlobal()) { if (Settings::IsConfiguringGlobal()) {
ui->toggle_shader_jit->setChecked(Settings::values.use_shader_jit.GetValue()); ui->toggle_shader_jit->setChecked(Settings::values.use_shader_jit.GetValue());
@ -106,6 +107,8 @@ void ConfigureGraphics::ApplyConfiguration() {
use_vsync_new); use_vsync_new);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.graphics_api, ui->graphics_api_combo); ConfigurationShared::ApplyPerGameSetting(&Settings::values.graphics_api, ui->graphics_api_combo);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.physical_device, ui->physical_device_combo); ConfigurationShared::ApplyPerGameSetting(&Settings::values.physical_device, ui->physical_device_combo);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.async_command_recording, ui->toggle_async_recording,
async_command_recording);
if (Settings::IsConfiguringGlobal()) { if (Settings::IsConfiguringGlobal()) {
Settings::values.use_shader_jit = ui->toggle_shader_jit->isChecked(); Settings::values.use_shader_jit = ui->toggle_shader_jit->isChecked();

View File

@ -40,6 +40,7 @@ private:
ConfigurationShared::CheckState shaders_accurate_mul; ConfigurationShared::CheckState shaders_accurate_mul;
ConfigurationShared::CheckState use_disk_shader_cache; ConfigurationShared::CheckState use_disk_shader_cache;
ConfigurationShared::CheckState use_vsync_new; ConfigurationShared::CheckState use_vsync_new;
ConfigurationShared::CheckState async_command_recording;
std::unique_ptr<Ui::ConfigureGraphics> ui; std::unique_ptr<Ui::ConfigureGraphics> ui;
QColor bg_color; QColor bg_color;
}; };

View File

@ -171,6 +171,16 @@
<string>Advanced</string> <string>Advanced</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QCheckBox" name="toggle_async_recording">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Offloads command buffer recording and fragment shader generation to a worker thread. Can improve performance especially on weaker systems. Disable if you notice better performance. If unsure leave it enabled,&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Async Command Recording</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QCheckBox" name="toggle_disk_shader_cache"> <widget class="QCheckBox" name="toggle_disk_shader_cache">
<property name="toolTip"> <property name="toolTip">

View File

@ -106,6 +106,7 @@ void LogSettings() {
log_setting("Core_UseCpuJit", values.use_cpu_jit.GetValue()); log_setting("Core_UseCpuJit", values.use_cpu_jit.GetValue());
log_setting("Core_CPUClockPercentage", values.cpu_clock_percentage.GetValue()); log_setting("Core_CPUClockPercentage", values.cpu_clock_percentage.GetValue());
log_setting("Renderer_GraphicsAPI", GetAPIName(values.graphics_api.GetValue())); log_setting("Renderer_GraphicsAPI", GetAPIName(values.graphics_api.GetValue()));
log_setting("Renderer_AsyncRecording", values.async_command_recording.GetValue());
log_setting("Renderer_UseHwRenderer", values.use_hw_renderer.GetValue()); log_setting("Renderer_UseHwRenderer", values.use_hw_renderer.GetValue());
log_setting("Renderer_UseHwShader", values.use_hw_shader.GetValue()); log_setting("Renderer_UseHwShader", values.use_hw_shader.GetValue());
log_setting("Renderer_SeparableShader", values.separable_shader.GetValue()); log_setting("Renderer_SeparableShader", values.separable_shader.GetValue());

View File

@ -450,6 +450,7 @@ struct Values {
SwitchableSetting<u16> physical_device{0, "physical_device"}; SwitchableSetting<u16> physical_device{0, "physical_device"};
Setting<bool> renderer_debug{false, "renderer_debug"}; Setting<bool> renderer_debug{false, "renderer_debug"};
Setting<bool> dump_command_buffers{false, "dump_command_buffers"}; Setting<bool> dump_command_buffers{false, "dump_command_buffers"};
SwitchableSetting<bool> async_command_recording{true, "async_command_recording"};
SwitchableSetting<bool> use_hw_renderer{true, "use_hw_renderer"}; SwitchableSetting<bool> use_hw_renderer{true, "use_hw_renderer"};
SwitchableSetting<bool> use_hw_shader{true, "use_hw_shader"}; SwitchableSetting<bool> use_hw_shader{true, "use_hw_shader"};
SwitchableSetting<bool> separable_shader{false, "use_separable_shader"}; SwitchableSetting<bool> separable_shader{false, "use_separable_shader"};

View File

@ -4,7 +4,7 @@
#include <mutex> #include <mutex>
#include <utility> #include <utility>
#include "common/microprofile.h" #include "common/microprofile.h"
#include "common/thread.h" #include "core/settings.h"
#include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/renderer_vulkan.h" #include "video_core/renderer_vulkan/renderer_vulkan.h"
@ -16,7 +16,7 @@ void Scheduler::CommandChunk::ExecuteAll(vk::CommandBuffer render_cmdbuf, vk::Co
while (command != nullptr) { while (command != nullptr) {
auto next = command->GetNext(); auto next = command->GetNext();
command->Execute(render_cmdbuf, upload_cmdbuf); command->Execute(render_cmdbuf, upload_cmdbuf);
command->~Command(); std::destroy_at(command);
command = next; command = next;
} }
submit = false; submit = false;
@ -26,10 +26,13 @@ void Scheduler::CommandChunk::ExecuteAll(vk::CommandBuffer render_cmdbuf, vk::Co
} }
Scheduler::Scheduler(const Instance& instance, RendererVulkan& renderer) Scheduler::Scheduler(const Instance& instance, RendererVulkan& renderer)
: instance{instance}, renderer{renderer}, master_semaphore{instance}, command_pool{instance, master_semaphore} { : instance{instance}, renderer{renderer}, master_semaphore{instance}, command_pool{instance, master_semaphore},
AcquireNewChunk(); use_worker_thread{Settings::values.async_command_recording} {
AllocateWorkerCommandBuffers(); AllocateWorkerCommandBuffers();
if (use_worker_thread) {
AcquireNewChunk();
worker_thread = std::jthread([this](std::stop_token token) { WorkerThread(token); }); worker_thread = std::jthread([this](std::stop_token token) { WorkerThread(token); });
}
} }
Scheduler::~Scheduler() = default; Scheduler::~Scheduler() = default;
@ -47,6 +50,10 @@ void Scheduler::Finish(vk::Semaphore signal, vk::Semaphore wait) {
MICROPROFILE_DEFINE(Vulkan_WaitForWorker, "Vulkan", "Wait for worker", MP_RGB(255, 192, 192)); MICROPROFILE_DEFINE(Vulkan_WaitForWorker, "Vulkan", "Wait for worker", MP_RGB(255, 192, 192));
void Scheduler::WaitWorker() { void Scheduler::WaitWorker() {
if (!use_worker_thread) {
return;
}
MICROPROFILE_SCOPE(Vulkan_WaitForWorker); MICROPROFILE_SCOPE(Vulkan_WaitForWorker);
DispatchWork(); DispatchWork();
@ -162,8 +169,12 @@ void Scheduler::SubmitExecution(vk::Semaphore signal_semaphore, vk::Semaphore wa
} }
}); });
if (!use_worker_thread) {
AllocateWorkerCommandBuffers();
} else {
chunk->MarkSubmit(); chunk->MarkSubmit();
DispatchWork(); DispatchWork();
}
} }
void Scheduler::AcquireNewChunk() { void Scheduler::AcquireNewChunk() {

View File

@ -52,6 +52,11 @@ public:
/// Records the command to the current chunk. /// Records the command to the current chunk.
template <typename T> template <typename T>
void Record(T&& command) { void Record(T&& command) {
if (!use_worker_thread) {
command(render_cmdbuf, upload_cmdbuf);
return;
}
if (chunk->Record(command)) { if (chunk->Record(command)) {
return; return;
} }
@ -144,7 +149,7 @@ private:
return false; return false;
} }
Command* const current_last = last; Command* const current_last = last;
last = new (data.data() + command_offset) FuncType(std::move(command)); last = std::construct_at(reinterpret_cast<FuncType*>(data.data() + command_offset), std::move(command));
if (current_last) { if (current_last) {
current_last->SetNext(last); current_last->SetNext(last);
@ -202,7 +207,7 @@ private:
std::condition_variable_any work_cv; std::condition_variable_any work_cv;
std::condition_variable wait_cv; std::condition_variable wait_cv;
std::jthread worker_thread; std::jthread worker_thread;
std::jthread prsent_thread; bool use_worker_thread;
}; };
} // namespace Vulkan } // namespace Vulkan