citra-emu
/
citra-canary
Archived
1
0
Fork 0

DSP/LLE: add multithread mode

This commit is contained in:
Weiyi Wang 2018-12-19 19:45:22 -05:00
parent fbad420240
commit 443f4b964d
10 changed files with 92 additions and 12 deletions

2
externals/teakra vendored

@ -1 +1 @@
Subproject commit 343bad999d53279b5ed966db3f36e2d1c6f5d85b Subproject commit fd97ef90bff46bd5c3163edfd32b4cb38964eebe

View File

@ -3,13 +3,17 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <array> #include <array>
#include <atomic>
#include <thread>
#include <teakra/teakra.h> #include <teakra/teakra.h>
#include "audio_core/lle/lle.h" #include "audio_core/lle/lle.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/swap.h" #include "common/swap.h"
#include "common/thread.h"
#include "core/core.h" #include "core/core.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/hle/lock.h"
#include "core/hle/service/dsp/dsp_dsp.h" #include "core/hle/service/dsp/dsp_dsp.h"
namespace AudioCore { namespace AudioCore {
@ -117,11 +121,15 @@ static u8 PipeIndexToSlotIndex(u8 pipe_index, PipeDirection direction) {
} }
struct DspLle::Impl final { struct DspLle::Impl final {
Impl() { Impl(bool multithread) : multithread(multithread) {
teakra_slice_event = Core::System::GetInstance().CoreTiming().RegisterEvent( teakra_slice_event = Core::System::GetInstance().CoreTiming().RegisterEvent(
"DSP slice", [this](u64, int late) { TeakraSliceEvent(static_cast<u64>(late)); }); "DSP slice", [this](u64, int late) { TeakraSliceEvent(static_cast<u64>(late)); });
} }
~Impl() {
StopTeakraThread();
}
Teakra::Teakra teakra; Teakra::Teakra teakra;
u16 pipe_base_waddr = 0; u16 pipe_base_waddr = 0;
@ -129,13 +137,44 @@ struct DspLle::Impl final {
bool data_signaled = false; bool data_signaled = false;
Core::TimingEventType* teakra_slice_event; Core::TimingEventType* teakra_slice_event;
bool loaded = false; std::atomic<bool> loaded = false;
const bool multithread;
std::thread teakra_thread;
Common::Barrier teakra_slice_barrier{2};
std::atomic<bool> stop_signal = false;
std::size_t stop_generation;
static constexpr u32 DspDataOffset = 0x40000; static constexpr u32 DspDataOffset = 0x40000;
static constexpr u32 TeakraSlice = 20000; 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() { void RunTeakraSlice() {
teakra.Run(TeakraSlice); if (multithread) {
teakra_slice_barrier.Sync();
} else {
teakra.Run(TeakraSlice);
}
} }
void TeakraSliceEvent(u64 late) { void TeakraSliceEvent(u64 late) {
@ -288,6 +327,10 @@ struct DspLle::Impl final {
Core::System::GetInstance().CoreTiming().ScheduleEvent(TeakraSlice, teakra_slice_event, 0); Core::System::GetInstance().CoreTiming().ScheduleEvent(TeakraSlice, teakra_slice_event, 0);
if (multithread) {
teakra_thread = std::thread(&Impl::TeakraThread, this);
}
// Wait for initialization // Wait for initialization
if (dsp.recv_data_on_start) { if (dsp.recv_data_on_start) {
for (u8 i = 0; i < 3; ++i) { for (u8 i = 0; i < 3; ++i) {
@ -312,6 +355,8 @@ struct DspLle::Impl final {
return; return;
} }
loaded = false;
// Send finalization signal via command/reply register 2 // Send finalization signal via command/reply register 2
constexpr u16 FinalizeSignal = 0x8000; constexpr u16 FinalizeSignal = 0x8000;
while (!teakra.SendDataIsEmpty(2)) while (!teakra.SendDataIsEmpty(2))
@ -326,7 +371,7 @@ struct DspLle::Impl final {
teakra.RecvData(2); // discard the value teakra.RecvData(2); // discard the value
Core::System::GetInstance().CoreTiming().UnscheduleEvent(teakra_slice_event, 0); Core::System::GetInstance().CoreTiming().UnscheduleEvent(teakra_slice_event, 0);
loaded = false; StopTeakraThread();
} }
}; };
@ -362,13 +407,21 @@ std::array<u8, Memory::DSP_RAM_SIZE>& DspLle::GetDspMemory() {
} }
void DspLle::SetServiceToInterrupt(std::weak_ptr<Service::DSP::DSP_DSP> dsp) { void DspLle::SetServiceToInterrupt(std::weak_ptr<Service::DSP::DSP_DSP> 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()) { if (auto locked = dsp.lock()) {
locked->SignalInterrupt(Service::DSP::DSP_DSP::InterruptType::Zero, locked->SignalInterrupt(Service::DSP::DSP_DSP::InterruptType::Zero,
static_cast<DspPipe>(0)); static_cast<DspPipe>(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()) { if (auto locked = dsp.lock()) {
locked->SignalInterrupt(Service::DSP::DSP_DSP::InterruptType::One, locked->SignalInterrupt(Service::DSP::DSP_DSP::InterruptType::One,
static_cast<DspPipe>(0)); static_cast<DspPipe>(0));
@ -399,6 +452,7 @@ void DspLle::SetServiceToInterrupt(std::weak_ptr<Service::DSP::DSP_DSP> dsp) {
// pipe 0 is for debug. 3DS automatically drains this pipe and discards the data // pipe 0 is for debug. 3DS automatically drains this pipe and discards the data
impl->ReadPipe(pipe, impl->GetPipeReadableSize(pipe)); impl->ReadPipe(pipe, impl->GetPipeReadableSize(pipe));
} else { } else {
std::lock_guard lock(HLE::g_hle_lock);
if (auto locked = dsp.lock()) { if (auto locked = dsp.lock()) {
locked->SignalInterrupt(Service::DSP::DSP_DSP::InterruptType::Pipe, locked->SignalInterrupt(Service::DSP::DSP_DSP::InterruptType::Pipe,
static_cast<DspPipe>(pipe)); static_cast<DspPipe>(pipe));
@ -419,7 +473,8 @@ void DspLle::UnloadComponent() {
impl->UnloadComponent(); impl->UnloadComponent();
} }
DspLle::DspLle(Memory::MemorySystem& memory) : impl(std::make_unique<Impl>()) { DspLle::DspLle(Memory::MemorySystem& memory, bool multithread)
: impl(std::make_unique<Impl>(multithread)) {
Teakra::AHBMCallback ahbm; Teakra::AHBMCallback ahbm;
ahbm.read8 = [&memory](u32 address) -> u8 { ahbm.read8 = [&memory](u32 address) -> u8 {
return *memory.GetFCRAMPointer(address - Memory::FCRAM_PADDR); return *memory.GetFCRAMPointer(address - Memory::FCRAM_PADDR);

View File

@ -10,7 +10,7 @@ namespace AudioCore {
class DspLle final : public DspInterface { class DspLle final : public DspInterface {
public: public:
explicit DspLle(Memory::MemorySystem& memory); explicit DspLle(Memory::MemorySystem& memory, bool multithread);
~DspLle() override; ~DspLle() override;
u16 RecvData(u32 register_number) override; u16 RecvData(u32 register_number) override;

View File

@ -156,6 +156,8 @@ void Config::ReadValues() {
// Audio // Audio
Settings::values.enable_dsp_lle = sdl2_config->GetBoolean("Audio", "enable_dsp_lle", false); 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.sink_id = sdl2_config->GetString("Audio", "output_engine", "auto");
Settings::values.enable_audio_stretching = Settings::values.enable_audio_stretching =
sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true); sdl2_config->GetBoolean("Audio", "enable_audio_stretching", true);

View File

@ -171,6 +171,11 @@ swap_screen =
# 0 (default): No, 1: Yes # 0 (default): No, 1: Yes
enable_dsp_lle = 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. # Which audio output engine to use.
# auto (default): Auto-select, null: No audio output, sdl2: SDL2 (if available) # auto (default): Auto-select, null: No audio output, sdl2: SDL2 (if available)
output_engine = output_engine =

View File

@ -137,6 +137,8 @@ void Config::ReadValues() {
qt_config->beginGroup("Audio"); qt_config->beginGroup("Audio");
Settings::values.enable_dsp_lle = ReadSetting("enable_dsp_lle", false).toBool(); 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.sink_id = ReadSetting("output_engine", "auto").toString().toStdString();
Settings::values.enable_audio_stretching = Settings::values.enable_audio_stretching =
ReadSetting("enable_audio_stretching", true).toBool(); ReadSetting("enable_audio_stretching", true).toBool();
@ -417,6 +419,7 @@ void Config::SaveValues() {
qt_config->beginGroup("Audio"); qt_config->beginGroup("Audio");
WriteSetting("enable_dsp_lle", Settings::values.enable_dsp_lle, false); 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("output_engine", QString::fromStdString(Settings::values.sink_id), "auto");
WriteSetting("enable_audio_stretching", Settings::values.enable_audio_stretching, true); WriteSetting("enable_audio_stretching", Settings::values.enable_audio_stretching, true);
WriteSetting("output_device", QString::fromStdString(Settings::values.audio_device_id), "auto"); WriteSetting("output_device", QString::fromStdString(Settings::values.audio_device_id), "auto");

View File

@ -22,6 +22,7 @@ ConfigureAudio::ConfigureAudio(QWidget* parent)
ui->emulation_combo_box->addItem(tr("HLE (fast)")); ui->emulation_combo_box->addItem(tr("HLE (fast)"));
ui->emulation_combo_box->addItem(tr("LLE (accurate)")); 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()); ui->emulation_combo_box->setEnabled(!Core::System::GetInstance().IsPoweredOn());
connect(ui->volume_slider, &QSlider::valueChanged, this, 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()); ui->volume_slider->setValue(Settings::values.volume * ui->volume_slider->maximum());
setVolumeIndicatorText(ui->volume_slider->sliderPosition()); 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() { void ConfigureAudio::setOutputSinkFromSinkID() {
@ -92,7 +103,8 @@ void ConfigureAudio::applyConfiguration() {
.toStdString(); .toStdString();
Settings::values.volume = Settings::values.volume =
static_cast<float>(ui->volume_slider->sliderPosition()) / ui->volume_slider->maximum(); static_cast<float>(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) { void ConfigureAudio::updateAudioDevices(int sink_index) {

View File

@ -190,7 +190,8 @@ System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) {
} }
if (Settings::values.enable_dsp_lle) { if (Settings::values.enable_dsp_lle) {
dsp_core = std::make_unique<AudioCore::DspLle>(*memory); dsp_core = std::make_unique<AudioCore::DspLle>(*memory,
Settings::values.enable_dsp_lle_multithread);
} else { } else {
dsp_core = std::make_unique<AudioCore::DspHle>(*memory); dsp_core = std::make_unique<AudioCore::DspHle>(*memory);
} }

View File

@ -80,6 +80,7 @@ void LogSettings() {
LogSetting("Layout_LayoutOption", static_cast<int>(Settings::values.layout_option)); LogSetting("Layout_LayoutOption", static_cast<int>(Settings::values.layout_option));
LogSetting("Layout_SwapScreen", Settings::values.swap_screen); LogSetting("Layout_SwapScreen", Settings::values.swap_screen);
LogSetting("Audio_EnableDspLle", Settings::values.enable_dsp_lle); 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_OutputEngine", Settings::values.sink_id);
LogSetting("Audio_EnableAudioStretching", Settings::values.enable_audio_stretching); LogSetting("Audio_EnableAudioStretching", Settings::values.enable_audio_stretching);
LogSetting("Audio_OutputDevice", Settings::values.audio_device_id); LogSetting("Audio_OutputDevice", Settings::values.audio_device_id);

View File

@ -148,6 +148,7 @@ struct Values {
// Audio // Audio
bool enable_dsp_lle; bool enable_dsp_lle;
bool enable_dsp_lle_multithread;
std::string sink_id; std::string sink_id;
bool enable_audio_stretching; bool enable_audio_stretching;
std::string audio_device_id; std::string audio_device_id;