From 443f4b964d17dad0a8e8b043bd866e99a65f0696 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Wed, 19 Dec 2018 19:45:22 -0500 Subject: [PATCH] DSP/LLE: add multithread mode --- externals/teakra | 2 +- src/audio_core/lle/lle.cpp | 69 +++++++++++++++++-- src/audio_core/lle/lle.h | 2 +- src/citra/config.cpp | 2 + src/citra/default_ini.h | 5 ++ src/citra_qt/configuration/config.cpp | 3 + .../configuration/configure_audio.cpp | 16 ++++- src/core/core.cpp | 3 +- src/core/settings.cpp | 1 + src/core/settings.h | 1 + 10 files changed, 92 insertions(+), 12 deletions(-) diff --git a/externals/teakra b/externals/teakra index 343bad999..fd97ef90b 160000 --- a/externals/teakra +++ b/externals/teakra @@ -1 +1 @@ -Subproject commit 343bad999d53279b5ed966db3f36e2d1c6f5d85b +Subproject commit fd97ef90bff46bd5c3163edfd32b4cb38964eebe diff --git a/src/audio_core/lle/lle.cpp b/src/audio_core/lle/lle.cpp index 603e9fa80..e9948d1c2 100644 --- a/src/audio_core/lle/lle.cpp +++ b/src/audio_core/lle/lle.cpp @@ -3,13 +3,17 @@ // Refer to the license.txt file included. #include +#include +#include #include #include "audio_core/lle/lle.h" #include "common/assert.h" #include "common/bit_field.h" #include "common/swap.h" +#include "common/thread.h" #include "core/core.h" #include "core/core_timing.h" +#include "core/hle/lock.h" #include "core/hle/service/dsp/dsp_dsp.h" namespace AudioCore { @@ -117,11 +121,15 @@ static u8 PipeIndexToSlotIndex(u8 pipe_index, PipeDirection direction) { } struct DspLle::Impl final { - Impl() { + Impl(bool multithread) : multithread(multithread) { teakra_slice_event = Core::System::GetInstance().CoreTiming().RegisterEvent( "DSP slice", [this](u64, int late) { TeakraSliceEvent(static_cast(late)); }); } + ~Impl() { + StopTeakraThread(); + } + Teakra::Teakra teakra; u16 pipe_base_waddr = 0; @@ -129,13 +137,44 @@ struct DspLle::Impl final { bool data_signaled = false; Core::TimingEventType* teakra_slice_event; - bool loaded = false; + std::atomic loaded = false; + + const bool multithread; + std::thread teakra_thread; + Common::Barrier teakra_slice_barrier{2}; + std::atomic stop_signal = false; + std::size_t stop_generation; static constexpr u32 DspDataOffset = 0x40000; static constexpr u32 TeakraSlice = 20000; + void TeakraThread() { + while (true) { + teakra.Run(TeakraSlice); + teakra_slice_barrier.Sync(); + if (stop_signal) { + if (stop_generation == teakra_slice_barrier.Generation()) + break; + } + } + stop_signal = false; + } + + void StopTeakraThread() { + if (teakra_thread.joinable()) { + stop_generation = teakra_slice_barrier.Generation() + 1; + stop_signal = true; + teakra_slice_barrier.Sync(); + teakra_thread.join(); + } + } + void RunTeakraSlice() { - teakra.Run(TeakraSlice); + if (multithread) { + teakra_slice_barrier.Sync(); + } else { + teakra.Run(TeakraSlice); + } } void TeakraSliceEvent(u64 late) { @@ -288,6 +327,10 @@ struct DspLle::Impl final { Core::System::GetInstance().CoreTiming().ScheduleEvent(TeakraSlice, teakra_slice_event, 0); + if (multithread) { + teakra_thread = std::thread(&Impl::TeakraThread, this); + } + // Wait for initialization if (dsp.recv_data_on_start) { for (u8 i = 0; i < 3; ++i) { @@ -312,6 +355,8 @@ struct DspLle::Impl final { return; } + loaded = false; + // Send finalization signal via command/reply register 2 constexpr u16 FinalizeSignal = 0x8000; while (!teakra.SendDataIsEmpty(2)) @@ -326,7 +371,7 @@ struct DspLle::Impl final { teakra.RecvData(2); // discard the value Core::System::GetInstance().CoreTiming().UnscheduleEvent(teakra_slice_event, 0); - loaded = false; + StopTeakraThread(); } }; @@ -362,13 +407,21 @@ std::array& DspLle::GetDspMemory() { } void DspLle::SetServiceToInterrupt(std::weak_ptr dsp) { - impl->teakra.SetRecvDataHandler(0, [dsp]() { + impl->teakra.SetRecvDataHandler(0, [this, dsp]() { + if (!impl->loaded) + return; + + std::lock_guard lock(HLE::g_hle_lock); if (auto locked = dsp.lock()) { locked->SignalInterrupt(Service::DSP::DSP_DSP::InterruptType::Zero, static_cast(0)); } }); - impl->teakra.SetRecvDataHandler(1, [dsp]() { + impl->teakra.SetRecvDataHandler(1, [this, dsp]() { + if (!impl->loaded) + return; + + std::lock_guard lock(HLE::g_hle_lock); if (auto locked = dsp.lock()) { locked->SignalInterrupt(Service::DSP::DSP_DSP::InterruptType::One, static_cast(0)); @@ -399,6 +452,7 @@ void DspLle::SetServiceToInterrupt(std::weak_ptr dsp) { // pipe 0 is for debug. 3DS automatically drains this pipe and discards the data impl->ReadPipe(pipe, impl->GetPipeReadableSize(pipe)); } else { + std::lock_guard lock(HLE::g_hle_lock); if (auto locked = dsp.lock()) { locked->SignalInterrupt(Service::DSP::DSP_DSP::InterruptType::Pipe, static_cast(pipe)); @@ -419,7 +473,8 @@ void DspLle::UnloadComponent() { impl->UnloadComponent(); } -DspLle::DspLle(Memory::MemorySystem& memory) : impl(std::make_unique()) { +DspLle::DspLle(Memory::MemorySystem& memory, bool multithread) + : impl(std::make_unique(multithread)) { Teakra::AHBMCallback ahbm; ahbm.read8 = [&memory](u32 address) -> u8 { return *memory.GetFCRAMPointer(address - Memory::FCRAM_PADDR); diff --git a/src/audio_core/lle/lle.h b/src/audio_core/lle/lle.h index 5c89e0656..dc3647aa0 100644 --- a/src/audio_core/lle/lle.h +++ b/src/audio_core/lle/lle.h @@ -10,7 +10,7 @@ namespace AudioCore { class DspLle final : public DspInterface { public: - explicit DspLle(Memory::MemorySystem& memory); + explicit DspLle(Memory::MemorySystem& memory, bool multithread); ~DspLle() override; u16 RecvData(u32 register_number) override; diff --git a/src/citra/config.cpp b/src/citra/config.cpp index 7e83e4160..8ef4fa510 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp @@ -156,6 +156,8 @@ void Config::ReadValues() { // Audio Settings::values.enable_dsp_lle = sdl2_config->GetBoolean("Audio", "enable_dsp_lle", false); + Settings::values.enable_dsp_lle_multithread = + sdl2_config->GetBoolean("Audio", "enable_dsp_lle_multithread", false); Settings::values.sink_id = sdl2_config->GetString("Audio", "output_engine", "auto"); Settings::values.enable_audio_stretching = sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true); diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h index dfef2b227..a1d4bda0c 100644 --- a/src/citra/default_ini.h +++ b/src/citra/default_ini.h @@ -171,6 +171,11 @@ swap_screen = # 0 (default): No, 1: Yes enable_dsp_lle = +# Whether or not to run DSP LLE on a different thread +# 0 (default): No, 1: Yes +enable_dsp_lle_thread = + + # Which audio output engine to use. # auto (default): Auto-select, null: No audio output, sdl2: SDL2 (if available) output_engine = diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp index 3dc2de659..e4c76a4c5 100644 --- a/src/citra_qt/configuration/config.cpp +++ b/src/citra_qt/configuration/config.cpp @@ -137,6 +137,8 @@ void Config::ReadValues() { qt_config->beginGroup("Audio"); Settings::values.enable_dsp_lle = ReadSetting("enable_dsp_lle", false).toBool(); + Settings::values.enable_dsp_lle_multithread = + ReadSetting("enable_dsp_lle_multithread", false).toBool(); Settings::values.sink_id = ReadSetting("output_engine", "auto").toString().toStdString(); Settings::values.enable_audio_stretching = ReadSetting("enable_audio_stretching", true).toBool(); @@ -417,6 +419,7 @@ void Config::SaveValues() { qt_config->beginGroup("Audio"); WriteSetting("enable_dsp_lle", Settings::values.enable_dsp_lle, false); + WriteSetting("enable_dsp_lle_multithread", Settings::values.enable_dsp_lle_multithread, false); WriteSetting("output_engine", QString::fromStdString(Settings::values.sink_id), "auto"); WriteSetting("enable_audio_stretching", Settings::values.enable_audio_stretching, true); WriteSetting("output_device", QString::fromStdString(Settings::values.audio_device_id), "auto"); diff --git a/src/citra_qt/configuration/configure_audio.cpp b/src/citra_qt/configuration/configure_audio.cpp index 84bece2b3..4a3a94a55 100644 --- a/src/citra_qt/configuration/configure_audio.cpp +++ b/src/citra_qt/configuration/configure_audio.cpp @@ -22,6 +22,7 @@ ConfigureAudio::ConfigureAudio(QWidget* parent) ui->emulation_combo_box->addItem(tr("HLE (fast)")); ui->emulation_combo_box->addItem(tr("LLE (accurate)")); + ui->emulation_combo_box->addItem(tr("LLE multi-core")); ui->emulation_combo_box->setEnabled(!Core::System::GetInstance().IsPoweredOn()); connect(ui->volume_slider, &QSlider::valueChanged, this, @@ -47,7 +48,17 @@ void ConfigureAudio::setConfiguration() { ui->volume_slider->setValue(Settings::values.volume * ui->volume_slider->maximum()); setVolumeIndicatorText(ui->volume_slider->sliderPosition()); - ui->emulation_combo_box->setCurrentIndex(Settings::values.enable_dsp_lle ? 1 : 0); + int selection; + if (Settings::values.enable_dsp_lle) { + if (Settings::values.enable_dsp_lle_multithread) { + selection = 2; + } else { + selection = 1; + } + } else { + selection = 0; + } + ui->emulation_combo_box->setCurrentIndex(selection); } void ConfigureAudio::setOutputSinkFromSinkID() { @@ -92,7 +103,8 @@ void ConfigureAudio::applyConfiguration() { .toStdString(); Settings::values.volume = static_cast(ui->volume_slider->sliderPosition()) / ui->volume_slider->maximum(); - Settings::values.enable_dsp_lle = ui->emulation_combo_box->currentIndex() == 1; + Settings::values.enable_dsp_lle = ui->emulation_combo_box->currentIndex() != 0; + Settings::values.enable_dsp_lle_multithread = ui->emulation_combo_box->currentIndex() == 2; } void ConfigureAudio::updateAudioDevices(int sink_index) { diff --git a/src/core/core.cpp b/src/core/core.cpp index b1b2ec138..a6af49b41 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -190,7 +190,8 @@ System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) { } if (Settings::values.enable_dsp_lle) { - dsp_core = std::make_unique(*memory); + dsp_core = std::make_unique(*memory, + Settings::values.enable_dsp_lle_multithread); } else { dsp_core = std::make_unique(*memory); } diff --git a/src/core/settings.cpp b/src/core/settings.cpp index a03115e5b..2141d57bd 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -80,6 +80,7 @@ void LogSettings() { LogSetting("Layout_LayoutOption", static_cast(Settings::values.layout_option)); LogSetting("Layout_SwapScreen", Settings::values.swap_screen); LogSetting("Audio_EnableDspLle", Settings::values.enable_dsp_lle); + LogSetting("Audio_EnableDspLleMultithread", Settings::values.enable_dsp_lle_multithread); LogSetting("Audio_OutputEngine", Settings::values.sink_id); LogSetting("Audio_EnableAudioStretching", Settings::values.enable_audio_stretching); LogSetting("Audio_OutputDevice", Settings::values.audio_device_id); diff --git a/src/core/settings.h b/src/core/settings.h index 614323514..7d49c7c39 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -148,6 +148,7 @@ struct Values { // Audio bool enable_dsp_lle; + bool enable_dsp_lle_multithread; std::string sink_id; bool enable_audio_stretching; std::string audio_device_id;