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.
#include <array>
#include <atomic>
#include <thread>
#include <teakra/teakra.h>
#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<u64>(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<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 TeakraSlice = 20000;
void RunTeakraSlice() {
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() {
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<u8, Memory::DSP_RAM_SIZE>& DspLle::GetDspMemory() {
}
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()) {
locked->SignalInterrupt(Service::DSP::DSP_DSP::InterruptType::Zero,
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()) {
locked->SignalInterrupt(Service::DSP::DSP_DSP::InterruptType::One,
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
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<DspPipe>(pipe));
@ -419,7 +473,8 @@ void DspLle::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;
ahbm.read8 = [&memory](u32 address) -> u8 {
return *memory.GetFCRAMPointer(address - Memory::FCRAM_PADDR);

View file

@ -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;

View file

@ -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);

View file

@ -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 =

View file

@ -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");

View file

@ -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<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) {

View file

@ -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<AudioCore::DspLle>(*memory);
dsp_core = std::make_unique<AudioCore::DspLle>(*memory,
Settings::values.enable_dsp_lle_multithread);
} else {
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_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);

View file

@ -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;