DSP/LLE: add multithread mode
This commit is contained in:
parent
fbad420240
commit
443f4b964d
10 changed files with 92 additions and 12 deletions
2
externals/teakra
vendored
2
externals/teakra
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 343bad999d53279b5ed966db3f36e2d1c6f5d85b
|
||||
Subproject commit fd97ef90bff46bd5c3163edfd32b4cb38964eebe
|
|
@ -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 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<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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue