From 6d51d95d447625b9e473db5f6c959c1a809ae446 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 6 Dec 2018 07:14:54 -0500 Subject: [PATCH 01/24] audio_core: add teakra and lle interface --- .gitmodules | 15 +++++++++------ externals/CMakeLists.txt | 3 +++ externals/teakra | 1 + src/audio_core/CMakeLists.txt | 5 +++-- src/audio_core/lle/lle.cpp | 17 +++++++++++++++++ src/audio_core/lle/lle.h | 22 ++++++++++++++++++++++ 6 files changed, 55 insertions(+), 8 deletions(-) create mode 160000 externals/teakra create mode 100644 src/audio_core/lle/lle.cpp create mode 100644 src/audio_core/lle/lle.h diff --git a/.gitmodules b/.gitmodules index b7f41e5f6..b0e5a858c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -38,11 +38,14 @@ path = externals/discord-rpc url = https://github.com/discordapp/discord-rpc.git [submodule "externals/libzmq"] - path = externals/libzmq - url = https://github.com/zeromq/libzmq + path = externals/libzmq + url = https://github.com/zeromq/libzmq [submodule "externals/cppzmq"] - path = externals/cppzmq - url = https://github.com/zeromq/cppzmq + path = externals/cppzmq + url = https://github.com/zeromq/cppzmq [submodule "cpp-jwt"] - path = externals/cpp-jwt - url = https://github.com/arun11299/cpp-jwt.git + path = externals/cpp-jwt + url = https://github.com/arun11299/cpp-jwt.git +[submodule "teakra"] + path = externals/teakra + url = https://github.com/wwylele/teakra.git diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index b96bebb7f..55bf4f8c4 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -51,6 +51,9 @@ add_subdirectory(soundtouch) # The SoundTouch target doesn't export the necessary include paths as properties by default target_include_directories(SoundTouch INTERFACE ./soundtouch/include) +# Teakra +add_subdirectory(teakra) + # Xbyak if (ARCHITECTURE_x86_64) # Defined before "dynarmic" above diff --git a/externals/teakra b/externals/teakra new file mode 160000 index 000000000..6dc129754 --- /dev/null +++ b/externals/teakra @@ -0,0 +1 @@ +Subproject commit 6dc1297548a116e6ef78ddd1a52ab3b3f9af0b17 diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt index de6079edc..538cfd894 100644 --- a/src/audio_core/CMakeLists.txt +++ b/src/audio_core/CMakeLists.txt @@ -14,6 +14,8 @@ add_library(audio_core STATIC hle/shared_memory.h hle/source.cpp hle/source.h + lle/lle.cpp + lle/lle.h interpolate.cpp interpolate.h null_sink.h @@ -30,7 +32,7 @@ add_library(audio_core STATIC create_target_directory_groups(audio_core) target_link_libraries(audio_core PUBLIC common core) -target_link_libraries(audio_core PRIVATE SoundTouch) +target_link_libraries(audio_core PRIVATE SoundTouch teakra) if(SDL2_FOUND) target_link_libraries(audio_core PRIVATE SDL2) @@ -41,4 +43,3 @@ if(ENABLE_CUBEB) target_link_libraries(audio_core PRIVATE cubeb) add_definitions(-DHAVE_CUBEB=1) endif() - diff --git a/src/audio_core/lle/lle.cpp b/src/audio_core/lle/lle.cpp new file mode 100644 index 000000000..7ac26e921 --- /dev/null +++ b/src/audio_core/lle/lle.cpp @@ -0,0 +1,17 @@ +// Copyright 2018 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "audio_core/lle/lle.h" +#include "teakra/teakra.h" + +namespace AudioCore { + +struct DspLle::Impl final { + Teakra::Teakra teakra; +}; + +DspLle::DspLle() : impl(std::make_unique()) {} +DspLle::~DspLle() = default; + +} // namespace AudioCore diff --git a/src/audio_core/lle/lle.h b/src/audio_core/lle/lle.h new file mode 100644 index 000000000..d92ff88f6 --- /dev/null +++ b/src/audio_core/lle/lle.h @@ -0,0 +1,22 @@ +// Copyright 2018 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "audio_core/dsp_interface.h" + +namespace AudioCore { + +class DspLle final : public DspInterface { +public: + DspLle(); + ~DspLle(); + +private: + struct Impl; + friend struct Impl; + std::unique_ptr impl; +}; + +} // namespace AudioCore From 7f568a3c195d150e15241d1e92516616de00212b Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 6 Dec 2018 07:18:26 -0500 Subject: [PATCH 02/24] DSP/HLE: move implementation of RecvData to audio_core, behind common interface --- src/audio_core/dsp_interface.h | 9 +++++++-- src/audio_core/hle/hle.cpp | 23 +++++++++++++++++++++-- src/audio_core/hle/hle.h | 3 +-- src/core/hle/service/dsp/dsp_dsp.cpp | 22 +++------------------- src/core/hle/service/dsp/dsp_dsp.h | 2 ++ 5 files changed, 34 insertions(+), 25 deletions(-) diff --git a/src/audio_core/dsp_interface.h b/src/audio_core/dsp_interface.h index aef57db87..b1188ab11 100644 --- a/src/audio_core/dsp_interface.h +++ b/src/audio_core/dsp_interface.h @@ -32,8 +32,13 @@ public: DspInterface& operator=(const DspInterface&) = delete; DspInterface& operator=(DspInterface&&) = delete; - /// Get the state of the DSP - virtual DspState GetDspState() const = 0; + /** + * Reads data from one of three DSP registers + * @note this function blocks until the data is available + * @param register_number the index of the register to read + * @returns the value of the register + */ + virtual u16 RecvData(u32 register_number) = 0; /** * Reads `length` bytes from the DSP pipe identified with `pipe_number`. diff --git a/src/audio_core/hle/hle.cpp b/src/audio_core/hle/hle.cpp index 4fa4145e2..eaf5c8c27 100644 --- a/src/audio_core/hle/hle.cpp +++ b/src/audio_core/hle/hle.cpp @@ -29,6 +29,7 @@ public: DspState GetDspState() const; + u16 RecvData(u32 register_number); std::vector PipeRead(DspPipe pipe_number, u32 length); std::size_t GetPipeReadableSize(DspPipe pipe_number) const; void PipeWrite(DspPipe pipe_number, const std::vector& buffer); @@ -93,6 +94,24 @@ DspState DspHle::Impl::GetDspState() const { return dsp_state; } +u16 DspHle::Impl::RecvData(u32 register_number) { + ASSERT_MSG(register_number == 0, "Unknown register_number {}", register_number); + + // Application reads this after requesting DSP shutdown, to verify the DSP has indeed shutdown + // or slept. + + switch (GetDspState()) { + case AudioCore::DspState::On: + return 0; + case AudioCore::DspState::Off: + case AudioCore::DspState::Sleeping: + return 1; + default: + UNREACHABLE(); + break; + } +} + std::vector DspHle::Impl::PipeRead(DspPipe pipe_number, u32 length) { const std::size_t pipe_index = static_cast(pipe_number); @@ -342,8 +361,8 @@ void DspHle::Impl::AudioTickCallback(s64 cycles_late) { DspHle::DspHle(Memory::MemorySystem& memory) : impl(std::make_unique(*this, memory)) {} DspHle::~DspHle() = default; -DspState DspHle::GetDspState() const { - return impl->GetDspState(); +u16 DspHle::RecvData(u32 register_number) { + return impl->RecvData(register_number); } std::vector DspHle::PipeRead(DspPipe pipe_number, u32 length) { diff --git a/src/audio_core/hle/hle.h b/src/audio_core/hle/hle.h index 70abddbd5..cc225b3d5 100644 --- a/src/audio_core/hle/hle.h +++ b/src/audio_core/hle/hle.h @@ -24,8 +24,7 @@ public: explicit DspHle(Memory::MemorySystem& memory); ~DspHle(); - DspState GetDspState() const override; - + u16 RecvData(u32 register_number) override; std::vector PipeRead(DspPipe pipe_number, u32 length) override; std::size_t GetPipeReadableSize(DspPipe pipe_number) const override; void PipeWrite(DspPipe pipe_number, const std::vector& buffer) override; diff --git a/src/core/hle/service/dsp/dsp_dsp.cpp b/src/core/hle/service/dsp/dsp_dsp.cpp index b15e670d3..8dc31d08d 100644 --- a/src/core/hle/service/dsp/dsp_dsp.cpp +++ b/src/core/hle/service/dsp/dsp_dsp.cpp @@ -24,26 +24,9 @@ void DSP_DSP::RecvData(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x01, 1, 0); const u32 register_number = rp.Pop(); - ASSERT_MSG(register_number == 0, "Unknown register_number {}", register_number); - - // Application reads this after requesting DSP shutdown, to verify the DSP has indeed shutdown - // or slept. - IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); - - switch (Core::DSP().GetDspState()) { - case AudioCore::DspState::On: - rb.Push(0); - break; - case AudioCore::DspState::Off: - case AudioCore::DspState::Sleeping: - rb.Push(1); - break; - default: - UNREACHABLE(); - break; - } + rb.Push(system.DSP().RecvData(register_number)); LOG_DEBUG(Service_DSP, "register_number={}", register_number); } @@ -350,7 +333,8 @@ bool DSP_DSP::HasTooManyEventsRegistered() const { return number >= max_number_of_interrupt_events; } -DSP_DSP::DSP_DSP(Core::System& system) : ServiceFramework("dsp::DSP", DefaultMaxSessions) { +DSP_DSP::DSP_DSP(Core::System& system) + : ServiceFramework("dsp::DSP", DefaultMaxSessions), system(system) { static const FunctionInfo functions[] = { // clang-format off {0x00010040, &DSP_DSP::RecvData, "RecvData"}, diff --git a/src/core/hle/service/dsp/dsp_dsp.h b/src/core/hle/service/dsp/dsp_dsp.h index 7226aeeac..78651bad8 100644 --- a/src/core/hle/service/dsp/dsp_dsp.h +++ b/src/core/hle/service/dsp/dsp_dsp.h @@ -245,6 +245,8 @@ private: /// Checks if we are trying to register more than 6 events bool HasTooManyEventsRegistered() const; + Core::System& system; + Kernel::SharedPtr semaphore_event; Kernel::SharedPtr interrupt_zero = nullptr; /// Currently unknown purpose From b609753fb6fbb73a19f21ca22466555f00a37920 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 6 Dec 2018 07:22:31 -0500 Subject: [PATCH 03/24] audio_core/lle: implement RecvData --- src/audio_core/lle/lle.cpp | 12 ++++++++++++ src/audio_core/lle/lle.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/src/audio_core/lle/lle.cpp b/src/audio_core/lle/lle.cpp index 7ac26e921..4201e592d 100644 --- a/src/audio_core/lle/lle.cpp +++ b/src/audio_core/lle/lle.cpp @@ -9,8 +9,20 @@ namespace AudioCore { struct DspLle::Impl final { Teakra::Teakra teakra; + + static constexpr unsigned TeakraSlice = 20000; + void RunTeakraSlice() { + teakra.Run(TeakraSlice); + } }; +u16 DspLle::RecvData(u32 register_number) { + while (!impl->teakra.RecvDataIsReady(register_number)) { + impl->RunTeakraSlice(); + } + return impl->teakra.RecvData(static_cast(register_number)); +} + DspLle::DspLle() : impl(std::make_unique()) {} DspLle::~DspLle() = default; diff --git a/src/audio_core/lle/lle.h b/src/audio_core/lle/lle.h index d92ff88f6..8e049e9da 100644 --- a/src/audio_core/lle/lle.h +++ b/src/audio_core/lle/lle.h @@ -13,6 +13,8 @@ public: DspLle(); ~DspLle(); + u16 RecvData(u32 register_number) override; + private: struct Impl; friend struct Impl; From 14eb3561decb9ebbf2304637834939471468eb6e Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 6 Dec 2018 07:28:47 -0500 Subject: [PATCH 04/24] audio_core/hle: move implementation of RecvDataIsReady --- src/audio_core/dsp_interface.h | 7 +++++++ src/audio_core/hle/hle.cpp | 10 ++++++++++ src/audio_core/hle/hle.h | 1 + src/core/hle/service/dsp/dsp_dsp.cpp | 4 +--- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/audio_core/dsp_interface.h b/src/audio_core/dsp_interface.h index b1188ab11..f44c77534 100644 --- a/src/audio_core/dsp_interface.h +++ b/src/audio_core/dsp_interface.h @@ -40,6 +40,13 @@ public: */ virtual u16 RecvData(u32 register_number) = 0; + /** + * Checks whether data is ready in one of three DSP registers + * @param register_number the index of the register to check + * @returns true if data is ready + */ + virtual bool RecvDataIsReady(u32 register_number) const = 0; + /** * Reads `length` bytes from the DSP pipe identified with `pipe_number`. * @note Can read up to the maximum value of a u16 in bytes (65,535). diff --git a/src/audio_core/hle/hle.cpp b/src/audio_core/hle/hle.cpp index eaf5c8c27..3b3d03d55 100644 --- a/src/audio_core/hle/hle.cpp +++ b/src/audio_core/hle/hle.cpp @@ -30,6 +30,7 @@ public: DspState GetDspState() const; u16 RecvData(u32 register_number); + bool RecvDataIsReady(u32 register_number) const; std::vector PipeRead(DspPipe pipe_number, u32 length); std::size_t GetPipeReadableSize(DspPipe pipe_number) const; void PipeWrite(DspPipe pipe_number, const std::vector& buffer); @@ -112,6 +113,11 @@ u16 DspHle::Impl::RecvData(u32 register_number) { } } +bool DspHle::Impl::RecvDataIsReady(u32 register_number) const { + ASSERT_MSG(register_number == 0, "Unknown register_number {}", register_number); + return true; +} + std::vector DspHle::Impl::PipeRead(DspPipe pipe_number, u32 length) { const std::size_t pipe_index = static_cast(pipe_number); @@ -365,6 +371,10 @@ u16 DspHle::RecvData(u32 register_number) { return impl->RecvData(register_number); } +bool DspHle::RecvDataIsReady(u32 register_number) const { + return impl->RecvDataIsReady(register_number); +} + std::vector DspHle::PipeRead(DspPipe pipe_number, u32 length) { return impl->PipeRead(pipe_number, length); } diff --git a/src/audio_core/hle/hle.h b/src/audio_core/hle/hle.h index cc225b3d5..8db78cf53 100644 --- a/src/audio_core/hle/hle.h +++ b/src/audio_core/hle/hle.h @@ -25,6 +25,7 @@ public: ~DspHle(); u16 RecvData(u32 register_number) override; + bool RecvDataIsReady(u32 register_number) const override; std::vector PipeRead(DspPipe pipe_number, u32 length) override; std::size_t GetPipeReadableSize(DspPipe pipe_number) const override; void PipeWrite(DspPipe pipe_number, const std::vector& buffer) override; diff --git a/src/core/hle/service/dsp/dsp_dsp.cpp b/src/core/hle/service/dsp/dsp_dsp.cpp index 8dc31d08d..6acfad566 100644 --- a/src/core/hle/service/dsp/dsp_dsp.cpp +++ b/src/core/hle/service/dsp/dsp_dsp.cpp @@ -35,11 +35,9 @@ void DSP_DSP::RecvDataIsReady(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x02, 1, 0); const u32 register_number = rp.Pop(); - ASSERT_MSG(register_number == 0, "Unknown register_number {}", register_number); - IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); - rb.Push(true); /// 0 = not ready, 1 = ready to read + rb.Push(system.DSP().RecvDataIsReady(register_number)); LOG_DEBUG(Service_DSP, "register_number={}", register_number); } From 4671ccf416b02bea8b7d17a278ca0522157e9a91 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 6 Dec 2018 07:30:10 -0500 Subject: [PATCH 05/24] audio_core/lle: implement RecvDataIsReady --- src/audio_core/lle/lle.cpp | 4 ++++ src/audio_core/lle/lle.h | 1 + 2 files changed, 5 insertions(+) diff --git a/src/audio_core/lle/lle.cpp b/src/audio_core/lle/lle.cpp index 4201e592d..7c9da30e2 100644 --- a/src/audio_core/lle/lle.cpp +++ b/src/audio_core/lle/lle.cpp @@ -23,6 +23,10 @@ u16 DspLle::RecvData(u32 register_number) { return impl->teakra.RecvData(static_cast(register_number)); } +bool DspLle::RecvDataIsReady(u32 register_number) const { + return impl->teakra.RecvDataIsReady(register_number); +} + DspLle::DspLle() : impl(std::make_unique()) {} DspLle::~DspLle() = default; diff --git a/src/audio_core/lle/lle.h b/src/audio_core/lle/lle.h index 8e049e9da..dc5def3dd 100644 --- a/src/audio_core/lle/lle.h +++ b/src/audio_core/lle/lle.h @@ -14,6 +14,7 @@ public: ~DspLle(); u16 RecvData(u32 register_number) override; + bool RecvDataIsReady(u32 register_number) const override; private: struct Impl; From c9736b330019ff2cd0cdb465ecfd49895e92d63a Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 6 Dec 2018 07:35:07 -0500 Subject: [PATCH 06/24] audio_core/hle,lle: implement SetSemaphore --- src/audio_core/dsp_interface.h | 6 ++++++ src/audio_core/hle/hle.cpp | 4 ++++ src/audio_core/hle/hle.h | 1 + src/audio_core/lle/lle.cpp | 4 ++++ src/audio_core/lle/lle.h | 1 + src/core/hle/service/dsp/dsp_dsp.cpp | 2 ++ 6 files changed, 18 insertions(+) diff --git a/src/audio_core/dsp_interface.h b/src/audio_core/dsp_interface.h index f44c77534..5d7119cb6 100644 --- a/src/audio_core/dsp_interface.h +++ b/src/audio_core/dsp_interface.h @@ -47,6 +47,12 @@ public: */ virtual bool RecvDataIsReady(u32 register_number) const = 0; + /** + * Sets the DSP semaphore register + * @param semaphore_value the value set to the semaphore register + */ + virtual void SetSemaphore(u16 semaphore_value) = 0; + /** * Reads `length` bytes from the DSP pipe identified with `pipe_number`. * @note Can read up to the maximum value of a u16 in bytes (65,535). diff --git a/src/audio_core/hle/hle.cpp b/src/audio_core/hle/hle.cpp index 3b3d03d55..c5f3d0f44 100644 --- a/src/audio_core/hle/hle.cpp +++ b/src/audio_core/hle/hle.cpp @@ -375,6 +375,10 @@ bool DspHle::RecvDataIsReady(u32 register_number) const { return impl->RecvDataIsReady(register_number); } +void DspHle::SetSemaphore(u16 semaphore_value) { + // Do nothing in HLE +} + std::vector DspHle::PipeRead(DspPipe pipe_number, u32 length) { return impl->PipeRead(pipe_number, length); } diff --git a/src/audio_core/hle/hle.h b/src/audio_core/hle/hle.h index 8db78cf53..1c756b60f 100644 --- a/src/audio_core/hle/hle.h +++ b/src/audio_core/hle/hle.h @@ -26,6 +26,7 @@ public: u16 RecvData(u32 register_number) override; bool RecvDataIsReady(u32 register_number) const override; + void SetSemaphore(u16 semaphore_value) override; std::vector PipeRead(DspPipe pipe_number, u32 length) override; std::size_t GetPipeReadableSize(DspPipe pipe_number) const override; void PipeWrite(DspPipe pipe_number, const std::vector& buffer) override; diff --git a/src/audio_core/lle/lle.cpp b/src/audio_core/lle/lle.cpp index 7c9da30e2..bc030b77c 100644 --- a/src/audio_core/lle/lle.cpp +++ b/src/audio_core/lle/lle.cpp @@ -27,6 +27,10 @@ bool DspLle::RecvDataIsReady(u32 register_number) const { return impl->teakra.RecvDataIsReady(register_number); } +void DspLle::SetSemaphore(u16 semaphore_value) { + impl->teakra.SetSemaphore(semaphore_value); +} + DspLle::DspLle() : impl(std::make_unique()) {} DspLle::~DspLle() = default; diff --git a/src/audio_core/lle/lle.h b/src/audio_core/lle/lle.h index dc5def3dd..d6f7160d6 100644 --- a/src/audio_core/lle/lle.h +++ b/src/audio_core/lle/lle.h @@ -15,6 +15,7 @@ public: u16 RecvData(u32 register_number) override; bool RecvDataIsReady(u32 register_number) const override; + void SetSemaphore(u16 semaphore_value) override; private: struct Impl; diff --git a/src/core/hle/service/dsp/dsp_dsp.cpp b/src/core/hle/service/dsp/dsp_dsp.cpp index 6acfad566..97993a30e 100644 --- a/src/core/hle/service/dsp/dsp_dsp.cpp +++ b/src/core/hle/service/dsp/dsp_dsp.cpp @@ -46,6 +46,8 @@ void DSP_DSP::SetSemaphore(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x07, 1, 0); const u16 semaphore_value = rp.Pop(); + system.DSP().SetSemaphore(semaphore_value); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(RESULT_SUCCESS); From e40efbf37baed5ea5c19897acc06e1cf4dbe2b77 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 6 Dec 2018 07:42:07 -0500 Subject: [PATCH 07/24] audio_core/lle: implement PipeWrite --- src/audio_core/lle/lle.cpp | 92 ++++++++++++++++++++++++++++++++++++++ src/audio_core/lle/lle.h | 1 + 2 files changed, 93 insertions(+) diff --git a/src/audio_core/lle/lle.cpp b/src/audio_core/lle/lle.cpp index bc030b77c..0f6c7a8bb 100644 --- a/src/audio_core/lle/lle.cpp +++ b/src/audio_core/lle/lle.cpp @@ -3,17 +3,105 @@ // Refer to the license.txt file included. #include "audio_core/lle/lle.h" +#include "common/assert.h" +#include "common/swap.h" #include "teakra/teakra.h" namespace AudioCore { +struct PipeStatus { + u16_le waddress; + u16_le bsize; + u16_le read_bptr; + u16_le write_bptr; + u8 slot_index; + u8 flags; +}; + +static_assert(sizeof(PipeStatus) == 10); + +enum class PipeDirection : u8 { + DSPtoCPU = 0, + CPUtoDSP = 1, +}; + +static u8 PipeIndexToSlotIndex(u8 pipe_index, PipeDirection direction) { + return (pipe_index << 1) + (u8)direction; +} + struct DspLle::Impl final { Teakra::Teakra teakra; + u16 pipe_base_waddr = 0; static constexpr unsigned TeakraSlice = 20000; void RunTeakraSlice() { teakra.Run(TeakraSlice); } + + u8* GetDspDataPointer(u32 baddr) { + auto& memory = teakra.GetDspMemory(); + return &memory[0x40000 + baddr]; + } + + PipeStatus GetPipeStatus(u8 pipe_index, PipeDirection direction) { + u8 slot_index = PipeIndexToSlotIndex(pipe_index, direction); + PipeStatus pipe_status; + std::memcpy(&pipe_status, + GetDspDataPointer(pipe_base_waddr * 2 + slot_index * sizeof(PipeStatus)), + sizeof(PipeStatus)); + ASSERT(pipe_status.slot_index == slot_index); + return pipe_status; + } + + void UpdatePipeStatus(const PipeStatus& pipe_status) { + u8 slot_index = pipe_status.slot_index; + u8* status_address = + GetDspDataPointer(pipe_base_waddr * 2 + slot_index * sizeof(PipeStatus)); + if (slot_index % 2 == 0) { + std::memcpy(status_address + 4, &pipe_status.read_bptr, sizeof(u16)); + } else { + std::memcpy(status_address + 6, &pipe_status.write_bptr, sizeof(u16)); + } + } + + void WritePipe(u8 pipe_index, const std::vector& data) { + PipeStatus pipe_status = GetPipeStatus(pipe_index, PipeDirection::CPUtoDSP); + bool need_update = false; + const u8* buffer_ptr = data.data(); + u16 bsize = (u16)data.size(); + while (bsize != 0) { + u16 x = pipe_status.read_bptr ^ pipe_status.write_bptr; + ASSERT_MSG(x != 0x8000, "Pipe is Full"); + u16 write_bend; + if (x > 0x8000) + write_bend = pipe_status.read_bptr & 0x7FFF; + else + write_bend = pipe_status.bsize; + u16 write_bbegin = pipe_status.write_bptr & 0x7FFF; + ASSERT_MSG(write_bend > write_bbegin, + "Pipe is in inconsistent state: end {:04X} <= begin {:04X}, size {:04X}", + write_bend, write_bbegin, pipe_status.bsize); + u16 write_bsize = std::min(bsize, write_bend - write_bbegin); + std::memcpy(GetDspDataPointer(pipe_status.waddress * 2 + write_bbegin), buffer_ptr, + write_bsize); + buffer_ptr += write_bsize; + pipe_status.write_bptr += write_bsize; + bsize -= write_bsize; + ASSERT_MSG((pipe_status.write_bptr & 0x7FFF) <= pipe_status.bsize, + "Pipe is in inconsistent state: write > size"); + if ((pipe_status.write_bptr & 0x7FFF) == pipe_status.bsize) { + pipe_status.write_bptr &= 0x8000; + pipe_status.write_bptr ^= 0x8000; + } + need_update = true; + } + if (need_update) { + UpdatePipeStatus(pipe_status); + while (!teakra.SendDataIsEmpty(2)) + RunTeakraSlice(); + teakra.SendData(2, pipe_status.slot_index); + } + } }; u16 DspLle::RecvData(u32 register_number) { @@ -31,6 +119,10 @@ void DspLle::SetSemaphore(u16 semaphore_value) { impl->teakra.SetSemaphore(semaphore_value); } +void DspLle::PipeWrite(DspPipe pipe_number, const std::vector& buffer) { + impl->WritePipe(static_cast(pipe_number), buffer); +} + DspLle::DspLle() : impl(std::make_unique()) {} DspLle::~DspLle() = default; diff --git a/src/audio_core/lle/lle.h b/src/audio_core/lle/lle.h index d6f7160d6..9b282dcb6 100644 --- a/src/audio_core/lle/lle.h +++ b/src/audio_core/lle/lle.h @@ -16,6 +16,7 @@ public: u16 RecvData(u32 register_number) override; bool RecvDataIsReady(u32 register_number) const override; void SetSemaphore(u16 semaphore_value) override; + void PipeWrite(DspPipe pipe_number, const std::vector& buffer) override; private: struct Impl; From daf23eca2edea76ef15ff377d691da3e59c75fa7 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 6 Dec 2018 07:43:09 -0500 Subject: [PATCH 08/24] DSP_DSP: avoid global in WriteProcessPipe --- src/core/hle/service/dsp/dsp_dsp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/hle/service/dsp/dsp_dsp.cpp b/src/core/hle/service/dsp/dsp_dsp.cpp index 97993a30e..10f63b62c 100644 --- a/src/core/hle/service/dsp/dsp_dsp.cpp +++ b/src/core/hle/service/dsp/dsp_dsp.cpp @@ -94,7 +94,7 @@ void DSP_DSP::WriteProcessPipe(Kernel::HLERequestContext& ctx) { break; } - Core::DSP().PipeWrite(pipe, buffer); + system.DSP().PipeWrite(pipe, buffer); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(RESULT_SUCCESS); From 5c13eca700df1c0ecb2c666ed0f5e7ce9526671b Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 6 Dec 2018 07:49:07 -0500 Subject: [PATCH 09/24] audio_core/lle: implement PipeRead/GetPipeReadableSize --- src/audio_core/lle/lle.cpp | 55 ++++++++++++++++++++++++++++++++++++++ src/audio_core/lle/lle.h | 2 ++ 2 files changed, 57 insertions(+) diff --git a/src/audio_core/lle/lle.cpp b/src/audio_core/lle/lle.cpp index 0f6c7a8bb..7ead44e82 100644 --- a/src/audio_core/lle/lle.cpp +++ b/src/audio_core/lle/lle.cpp @@ -102,6 +102,53 @@ struct DspLle::Impl final { teakra.SendData(2, pipe_status.slot_index); } } + + std::vector ReadPipe(u8 pipe_index, u16 bsize) { + PipeStatus pipe_status = GetPipeStatus(pipe_index, PipeDirection::DSPtoCPU); + bool need_update = false; + std::vector data(bsize); + u8* buffer_ptr = data.data(); + while (bsize != 0) { + u16 x = pipe_status.read_bptr ^ pipe_status.write_bptr; + ASSERT_MSG(x != 0, "Pipe is empty"); + u16 read_bend; + if (x >= 0x8000) { + read_bend = pipe_status.bsize; + } else { + read_bend = pipe_status.write_bptr & 0x7FFF; + } + u16 read_bbegin = pipe_status.read_bptr & 0x7FFF; + ASSERT(read_bend > read_bbegin); + u16 read_bsize = std::min(bsize, read_bend - read_bbegin); + std::memcpy(buffer_ptr, GetDspDataPointer(pipe_status.waddress * 2 + read_bbegin), + read_bsize); + buffer_ptr += read_bsize; + pipe_status.read_bptr += read_bsize; + bsize -= read_bsize; + ASSERT_MSG((pipe_status.read_bptr & 0x7FFF) <= pipe_status.bsize, + "Pipe is in inconsistent state: read > size"); + if ((pipe_status.read_bptr & 0x7FFF) == pipe_status.bsize) { + pipe_status.read_bptr &= 0x8000; + pipe_status.read_bptr ^= 0x8000; + } + need_update = true; + } + if (need_update) { + UpdatePipeStatus(pipe_status); + while (!teakra.SendDataIsEmpty(2)) + RunTeakraSlice(); + teakra.SendData(2, pipe_status.slot_index); + } + return data; + } + u16 GetPipeReadableSize(u8 pipe_index) { + PipeStatus pipe_status = GetPipeStatus(pipe_index, PipeDirection::DSPtoCPU); + u16 size = pipe_status.write_bptr - pipe_status.read_bptr; + if ((pipe_status.read_bptr ^ pipe_status.write_bptr) >= 0x8000) { + size += pipe_status.bsize; + } + return size & 0x7FFF; + } }; u16 DspLle::RecvData(u32 register_number) { @@ -119,6 +166,14 @@ void DspLle::SetSemaphore(u16 semaphore_value) { impl->teakra.SetSemaphore(semaphore_value); } +std::vector DspLle::PipeRead(DspPipe pipe_number, u32 length) { + return impl->ReadPipe(static_cast(pipe_number), static_cast(length)); +} + +std::size_t DspLle::GetPipeReadableSize(DspPipe pipe_number) const { + return impl->GetPipeReadableSize(static_cast(pipe_number)); +} + void DspLle::PipeWrite(DspPipe pipe_number, const std::vector& buffer) { impl->WritePipe(static_cast(pipe_number), buffer); } diff --git a/src/audio_core/lle/lle.h b/src/audio_core/lle/lle.h index 9b282dcb6..5a343d496 100644 --- a/src/audio_core/lle/lle.h +++ b/src/audio_core/lle/lle.h @@ -16,6 +16,8 @@ public: u16 RecvData(u32 register_number) override; bool RecvDataIsReady(u32 register_number) const override; void SetSemaphore(u16 semaphore_value) override; + std::vector PipeRead(DspPipe pipe_number, u32 length) override; + std::size_t GetPipeReadableSize(DspPipe pipe_number) const override; void PipeWrite(DspPipe pipe_number, const std::vector& buffer) override; private: From df8aaee9659d62a5d522c8530d9ecf738a6e02cd Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 6 Dec 2018 07:51:51 -0500 Subject: [PATCH 10/24] DSP_DSP: avoid global in ReadPipe --- src/core/hle/service/dsp/dsp_dsp.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/hle/service/dsp/dsp_dsp.cpp b/src/core/hle/service/dsp/dsp_dsp.cpp index 10f63b62c..30cab2f63 100644 --- a/src/core/hle/service/dsp/dsp_dsp.cpp +++ b/src/core/hle/service/dsp/dsp_dsp.cpp @@ -110,11 +110,11 @@ void DSP_DSP::ReadPipe(Kernel::HLERequestContext& ctx) { const u16 size = rp.Pop(); const DspPipe pipe = static_cast(channel); - const u16 pipe_readable_size = static_cast(Core::DSP().GetPipeReadableSize(pipe)); + const u16 pipe_readable_size = static_cast(system.DSP().GetPipeReadableSize(pipe)); std::vector pipe_buffer; if (pipe_readable_size >= size) - pipe_buffer = Core::DSP().PipeRead(pipe, size); + pipe_buffer = system.DSP().PipeRead(pipe, size); else UNREACHABLE(); // No more data is in pipe. Hardware hangs in this case; Should never happen. @@ -132,7 +132,7 @@ void DSP_DSP::GetPipeReadableSize(Kernel::HLERequestContext& ctx) { const u32 peer = rp.Pop(); const DspPipe pipe = static_cast(channel); - const u16 pipe_readable_size = static_cast(Core::DSP().GetPipeReadableSize(pipe)); + const u16 pipe_readable_size = static_cast(system.DSP().GetPipeReadableSize(pipe)); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); @@ -149,11 +149,11 @@ void DSP_DSP::ReadPipeIfPossible(Kernel::HLERequestContext& ctx) { const u16 size = rp.Pop(); const DspPipe pipe = static_cast(channel); - const u16 pipe_readable_size = static_cast(Core::DSP().GetPipeReadableSize(pipe)); + const u16 pipe_readable_size = static_cast(system.DSP().GetPipeReadableSize(pipe)); std::vector pipe_buffer; if (pipe_readable_size >= size) - pipe_buffer = Core::DSP().PipeRead(pipe, size); + pipe_buffer = system.DSP().PipeRead(pipe, size); IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); rb.Push(RESULT_SUCCESS); From 9ab4e3c686f343acd7680cf60165aee5f8b14cd2 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 6 Dec 2018 08:10:00 -0500 Subject: [PATCH 11/24] audio_core/lle: implement GetDspMemory and SetServiceToInterrupt --- src/audio_core/lle/lle.cpp | 55 ++++++++++++++++++++++++++++++++++++++ src/audio_core/lle/lle.h | 4 +++ 2 files changed, 59 insertions(+) diff --git a/src/audio_core/lle/lle.cpp b/src/audio_core/lle/lle.cpp index 7ead44e82..4dbcf2f29 100644 --- a/src/audio_core/lle/lle.cpp +++ b/src/audio_core/lle/lle.cpp @@ -5,6 +5,7 @@ #include "audio_core/lle/lle.h" #include "common/assert.h" #include "common/swap.h" +#include "core/hle/service/dsp/dsp_dsp.h" #include "teakra/teakra.h" namespace AudioCore { @@ -33,6 +34,9 @@ struct DspLle::Impl final { Teakra::Teakra teakra; u16 pipe_base_waddr = 0; + bool semaphore_signaled = false; + bool data_signaled = false; + static constexpr unsigned TeakraSlice = 20000; void RunTeakraSlice() { teakra.Run(TeakraSlice); @@ -178,6 +182,57 @@ void DspLle::PipeWrite(DspPipe pipe_number, const std::vector& buffer) { impl->WritePipe(static_cast(pipe_number), buffer); } +std::array& DspLle::GetDspMemory() { + return impl->teakra.GetDspMemory(); +} + +void DspLle::SetServiceToInterrupt(std::weak_ptr dsp) { + impl->teakra.SetRecvDataHandler(0, [dsp]() { + if (auto locked = dsp.lock()) { + locked->SignalInterrupt(Service::DSP::DSP_DSP::InterruptType::Zero, + static_cast(0)); + } + }); + impl->teakra.SetRecvDataHandler(1, [dsp]() { + if (auto locked = dsp.lock()) { + locked->SignalInterrupt(Service::DSP::DSP_DSP::InterruptType::One, + static_cast(0)); + } + }); + + auto ProcessPipeEvent = [this, dsp](bool event_from_data) { + auto& teakra = impl->teakra; + if (event_from_data) { + impl->data_signaled = true; + } else { + if ((teakra.GetSemaphore() & 0x8000) == 0) + return; + impl->semaphore_signaled = true; + } + if (impl->semaphore_signaled && impl->data_signaled) { + impl->semaphore_signaled = impl->data_signaled = false; + u16 slot = teakra.RecvData(2); + u16 side = slot % 2; + u16 pipe = slot / 2; + ASSERT(pipe < 16); + if (side != static_cast(PipeDirection::DSPtoCPU)) + return; + if (pipe == 0) { + // pipe 0 is for debug. 3DS automatically drains this pipe and discards the data + impl->ReadPipe(pipe, impl->GetPipeReadableSize(pipe)); + } else { + if (auto locked = dsp.lock()) { + locked->SignalInterrupt(Service::DSP::DSP_DSP::InterruptType::Pipe, + static_cast(pipe)); + } + } + } + }; + + impl->teakra.SetRecvDataHandler(2, [ProcessPipeEvent]() { ProcessPipeEvent(true); }); + impl->teakra.SetSemaphoreHandler([ProcessPipeEvent]() { ProcessPipeEvent(false); }); +} + DspLle::DspLle() : impl(std::make_unique()) {} DspLle::~DspLle() = default; diff --git a/src/audio_core/lle/lle.h b/src/audio_core/lle/lle.h index 5a343d496..7e418f4f2 100644 --- a/src/audio_core/lle/lle.h +++ b/src/audio_core/lle/lle.h @@ -20,6 +20,10 @@ public: std::size_t GetPipeReadableSize(DspPipe pipe_number) const override; void PipeWrite(DspPipe pipe_number, const std::vector& buffer) override; + std::array& GetDspMemory() override; + + void SetServiceToInterrupt(std::weak_ptr dsp) override; + private: struct Impl; friend struct Impl; From 4add509b2062d745ec5cf1feb136785bd9dae7c6 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 6 Dec 2018 08:35:21 -0500 Subject: [PATCH 12/24] audio_core/hle: move implementation of LoadComponent --- src/audio_core/dsp_interface.h | 3 +++ src/audio_core/hle/hle.cpp | 12 ++++++++++++ src/audio_core/hle/hle.h | 2 ++ src/core/hle/service/dsp/dsp_dsp.cpp | 18 +++++------------- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/audio_core/dsp_interface.h b/src/audio_core/dsp_interface.h index 5d7119cb6..eab08d5f8 100644 --- a/src/audio_core/dsp_interface.h +++ b/src/audio_core/dsp_interface.h @@ -88,6 +88,9 @@ public: /// Sets the dsp class that we trigger interrupts for virtual void SetServiceToInterrupt(std::weak_ptr dsp) = 0; + /// Loads the DSP program + virtual void LoadComponent(const std::vector& buffer) = 0; + /// Select the sink to use based on sink id. void SetSink(const std::string& sink_id, const std::string& audio_device); /// Get the current sink diff --git a/src/audio_core/hle/hle.cpp b/src/audio_core/hle/hle.cpp index c5f3d0f44..4b490d9bb 100644 --- a/src/audio_core/hle/hle.cpp +++ b/src/audio_core/hle/hle.cpp @@ -11,6 +11,7 @@ #include "audio_core/sink.h" #include "common/assert.h" #include "common/common_types.h" +#include "common/hash.h" #include "common/logging/log.h" #include "core/core.h" #include "core/core_timing.h" @@ -399,4 +400,15 @@ void DspHle::SetServiceToInterrupt(std::weak_ptr dsp) { impl->SetServiceToInterrupt(std::move(dsp)); } +void DspHle::LoadComponent(const std::vector& component_data) { + // HLE doesn't need DSP program. Only log some info here + LOG_INFO(Service_DSP, "Firmware hash: {:#018x}", + Common::ComputeHash64(component_data.data(), component_data.size())); + // Some versions of the firmware have the location of DSP structures listed here. + if (component_data.size() > 0x37C) { + LOG_INFO(Service_DSP, "Structures hash: {:#018x}", + Common::ComputeHash64(component_data.data() + 0x340, 60)); + } +} + } // namespace AudioCore diff --git a/src/audio_core/hle/hle.h b/src/audio_core/hle/hle.h index 1c756b60f..a472ca3c2 100644 --- a/src/audio_core/hle/hle.h +++ b/src/audio_core/hle/hle.h @@ -35,6 +35,8 @@ public: void SetServiceToInterrupt(std::weak_ptr dsp) override; + void LoadComponent(const std::vector& buffer) override; + private: struct Impl; friend struct Impl; diff --git a/src/core/hle/service/dsp/dsp_dsp.cpp b/src/core/hle/service/dsp/dsp_dsp.cpp index 30cab2f63..fec7ad7bf 100644 --- a/src/core/hle/service/dsp/dsp_dsp.cpp +++ b/src/core/hle/service/dsp/dsp_dsp.cpp @@ -4,7 +4,6 @@ #include "audio_core/audio_types.h" #include "common/assert.h" -#include "common/hash.h" #include "common/logging/log.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" @@ -173,23 +172,16 @@ void DSP_DSP::LoadComponent(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); rb.Push(RESULT_SUCCESS); - rb.Push(true); /// Pretend that we actually loaded the DSP firmware + rb.Push(true); rb.PushMappedBuffer(buffer); - // TODO(bunnei): Implement real DSP firmware loading - std::vector component_data(size); buffer.Read(component_data.data(), 0, size); - LOG_INFO(Service_DSP, "Firmware hash: {:#018x}", - Common::ComputeHash64(component_data.data(), component_data.size())); - // Some versions of the firmware have the location of DSP structures listed here. - if (size > 0x37C) { - LOG_INFO(Service_DSP, "Structures hash: {:#018x}", - Common::ComputeHash64(component_data.data() + 0x340, 60)); - } - LOG_WARNING(Service_DSP, "(STUBBED) called size=0x{:X}, prog_mask=0x{:08X}, data_mask=0x{:08X}", - size, prog_mask, data_mask); + system.DSP().LoadComponent(component_data); + + LOG_INFO(Service_DSP, "(STUBBED) called size=0x{:X}, prog_mask=0x{:08X}, data_mask=0x{:08X}", + size, prog_mask, data_mask); } void DSP_DSP::FlushDataCache(Kernel::HLERequestContext& ctx) { From 9b41e6f85fa20034eb7297462bafb9fb48b5b5a0 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 6 Dec 2018 09:09:14 -0500 Subject: [PATCH 13/24] audio_core/lle: implement LoadComponent --- src/audio_core/lle/lle.cpp | 121 +++++++++++++++++++++++++++++++++++++ src/audio_core/lle/lle.h | 2 + 2 files changed, 123 insertions(+) diff --git a/src/audio_core/lle/lle.cpp b/src/audio_core/lle/lle.cpp index 4dbcf2f29..feb4b1e86 100644 --- a/src/audio_core/lle/lle.cpp +++ b/src/audio_core/lle/lle.cpp @@ -2,14 +2,80 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include "audio_core/lle/lle.h" #include "common/assert.h" +#include "common/bit_field.h" #include "common/swap.h" +#include "core/core.h" +#include "core/core_timing.h" #include "core/hle/service/dsp/dsp_dsp.h" #include "teakra/teakra.h" namespace AudioCore { +enum class SegmentType : u8 { + ProgramA = 0, + ProgramB = 1, + Data = 2, +}; + +class Dsp1 { +public: + Dsp1(const std::vector& raw); + + struct Header { + std::array signature; + std::array magic; + u32_le binary_size; + u16_le memory_layout; + INSERT_PADDING_BYTES(3); + SegmentType special_segment_type; + u8 num_segments; + union { + BitField<0, 1, u8> recv_data_on_start; + BitField<1, 1, u8> load_special_segment; + }; + u32_le special_segment_address; + u32_le special_segment_size; + u64_le zero; + struct Segment { + u32_le offset; + u32_le address; + u32_le size; + INSERT_PADDING_BYTES(3); + SegmentType memory_type; + std::array sha256; + }; + std::array segments; + }; + static_assert(sizeof(Header) == 0x300); + + struct Segment { + std::vector data; + SegmentType memory_type; + u32 target; + }; + + std::vector segments; + bool recv_data_on_start; +}; + +Dsp1::Dsp1(const std::vector& raw) { + Header header; + std::memcpy(&header, raw.data(), sizeof(header)); + recv_data_on_start = header.recv_data_on_start != 0; + for (u32 i = 0; i < header.num_segments; ++i) { + Segment segment; + segment.data = + std::vector(raw.begin() + header.segments[i].offset, + raw.begin() + header.segments[i].offset + header.segments[i].size); + segment.memory_type = header.segments[i].memory_type; + segment.target = header.segments[i].address; + segments.push_back(segment); + } +} + struct PipeStatus { u16_le waddress; u16_le bsize; @@ -31,17 +97,34 @@ static u8 PipeIndexToSlotIndex(u8 pipe_index, PipeDirection direction) { } struct DspLle::Impl final { + Impl() { + teakra_slice_event = Core::System::GetInstance().CoreTiming().RegisterEvent( + "DSP slice", [this](u64, int late) { TeakraSliceEvent(static_cast(late)); }); + } + Teakra::Teakra teakra; u16 pipe_base_waddr = 0; bool semaphore_signaled = false; bool data_signaled = false; + Core::TimingEventType* teakra_slice_event; + static constexpr unsigned TeakraSlice = 20000; void RunTeakraSlice() { teakra.Run(TeakraSlice); } + void TeakraSliceEvent(u64 late) { + RunTeakraSlice(); + u64 next = TeakraSlice * 2; // DSP runs at clock rate half of the CPU rate + if (next < late) + next = 0; + else + next -= late; + Core::System::GetInstance().CoreTiming().ScheduleEvent(next, teakra_slice_event, 0); + } + u8* GetDspDataPointer(u32 baddr) { auto& memory = teakra.GetDspMemory(); return &memory[0x40000 + baddr]; @@ -153,6 +236,40 @@ struct DspLle::Impl final { } return size & 0x7FFF; } + + void LoadComponent(const std::vector& buffer) { + Dsp1 dsp(buffer); + auto& dsp_memory = teakra.GetDspMemory(); + u8* program = dsp_memory.data(); + u8* data = dsp_memory.data() + 0x40000; + dsp_memory.fill(0); + for (const auto& segment : dsp.segments) { + if (segment.memory_type == SegmentType::ProgramA || + segment.memory_type == SegmentType::ProgramB) { + std::memcpy(program + segment.target * 2, segment.data.data(), segment.data.size()); + } else if (segment.memory_type == SegmentType::Data) { + std::memcpy(data + segment.target * 2, segment.data.data(), segment.data.size()); + } + } + + // TODO: load special segment + + Core::System::GetInstance().CoreTiming().ScheduleEvent(TeakraSlice, teakra_slice_event, 0); + + // Wait for initialization + if (dsp.recv_data_on_start) { + for (unsigned i = 0; i < 3; ++i) { + while (!teakra.RecvDataIsReady(i)) + RunTeakraSlice(); + ASSERT(teakra.RecvData(i) == 1); + } + } + + // Get pipe base address + while (!teakra.RecvDataIsReady(2)) + RunTeakraSlice(); + pipe_base_waddr = teakra.RecvData(2); + } }; u16 DspLle::RecvData(u32 register_number) { @@ -233,6 +350,10 @@ void DspLle::SetServiceToInterrupt(std::weak_ptr dsp) { impl->teakra.SetSemaphoreHandler([ProcessPipeEvent]() { ProcessPipeEvent(false); }); } +void DspLle::LoadComponent(const std::vector& buffer) { + impl->LoadComponent(buffer); +} + DspLle::DspLle() : impl(std::make_unique()) {} DspLle::~DspLle() = default; diff --git a/src/audio_core/lle/lle.h b/src/audio_core/lle/lle.h index 7e418f4f2..1e9302ed0 100644 --- a/src/audio_core/lle/lle.h +++ b/src/audio_core/lle/lle.h @@ -24,6 +24,8 @@ public: void SetServiceToInterrupt(std::weak_ptr dsp) override; + void LoadComponent(const std::vector& buffer) override; + private: struct Impl; friend struct Impl; From 6f6ffceec4cc9e1652af8eca4a3cf908570d33d3 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 6 Dec 2018 09:50:55 -0500 Subject: [PATCH 14/24] audio_core/hle,lle: implement UnloadComponent --- src/audio_core/dsp_interface.h | 3 +++ src/audio_core/hle/hle.cpp | 4 +++ src/audio_core/hle/hle.h | 1 + src/audio_core/lle/lle.cpp | 37 +++++++++++++++++++++++++++- src/audio_core/lle/lle.h | 1 + src/core/hle/service/dsp/dsp_dsp.cpp | 11 +++++++++ src/core/hle/service/dsp/dsp_dsp.h | 9 +++++++ 7 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/audio_core/dsp_interface.h b/src/audio_core/dsp_interface.h index eab08d5f8..7a16dea0f 100644 --- a/src/audio_core/dsp_interface.h +++ b/src/audio_core/dsp_interface.h @@ -91,6 +91,9 @@ public: /// Loads the DSP program virtual void LoadComponent(const std::vector& buffer) = 0; + /// Unloads the DSP program + virtual void UnloadComponent() = 0; + /// Select the sink to use based on sink id. void SetSink(const std::string& sink_id, const std::string& audio_device); /// Get the current sink diff --git a/src/audio_core/hle/hle.cpp b/src/audio_core/hle/hle.cpp index 4b490d9bb..6e7b45278 100644 --- a/src/audio_core/hle/hle.cpp +++ b/src/audio_core/hle/hle.cpp @@ -411,4 +411,8 @@ void DspHle::LoadComponent(const std::vector& component_data) { } } +void DspHle::UnloadComponent() { + // Do nothing +} + } // namespace AudioCore diff --git a/src/audio_core/hle/hle.h b/src/audio_core/hle/hle.h index a472ca3c2..4ab468331 100644 --- a/src/audio_core/hle/hle.h +++ b/src/audio_core/hle/hle.h @@ -36,6 +36,7 @@ public: void SetServiceToInterrupt(std::weak_ptr dsp) override; void LoadComponent(const std::vector& buffer) override; + void UnloadComponent() override; private: struct Impl; diff --git a/src/audio_core/lle/lle.cpp b/src/audio_core/lle/lle.cpp index feb4b1e86..a7f46a913 100644 --- a/src/audio_core/lle/lle.cpp +++ b/src/audio_core/lle/lle.cpp @@ -109,6 +109,7 @@ struct DspLle::Impl final { bool data_signaled = false; Core::TimingEventType* teakra_slice_event; + bool loaded = false; static constexpr unsigned TeakraSlice = 20000; void RunTeakraSlice() { @@ -238,11 +239,17 @@ struct DspLle::Impl final { } void LoadComponent(const std::vector& buffer) { + if (loaded) { + LOG_ERROR(Audio_DSP, "Component already loaded!"); + return; + } + + teakra.Reset(); + Dsp1 dsp(buffer); auto& dsp_memory = teakra.GetDspMemory(); u8* program = dsp_memory.data(); u8* data = dsp_memory.data() + 0x40000; - dsp_memory.fill(0); for (const auto& segment : dsp.segments) { if (segment.memory_type == SegmentType::ProgramA || segment.memory_type == SegmentType::ProgramB) { @@ -269,6 +276,30 @@ struct DspLle::Impl final { while (!teakra.RecvDataIsReady(2)) RunTeakraSlice(); pipe_base_waddr = teakra.RecvData(2); + + loaded = true; + } + + void UnloadComponent() { + if (!loaded) { + LOG_ERROR(Audio_DSP, "Component not loaded!"); + return; + } + + // Send finalization signal + while (!teakra.SendDataIsEmpty(2)) + RunTeakraSlice(); + + teakra.SendData(2, 0x8000); + + // Wait for completion + while (!teakra.RecvDataIsReady(2)) + RunTeakraSlice(); + + teakra.RecvData(2); // discard the value + + Core::System::GetInstance().CoreTiming().UnscheduleEvent(teakra_slice_event, 0); + loaded = false; } }; @@ -354,6 +385,10 @@ void DspLle::LoadComponent(const std::vector& buffer) { impl->LoadComponent(buffer); } +void DspLle::UnloadComponent() { + impl->UnloadComponent(); +} + DspLle::DspLle() : impl(std::make_unique()) {} DspLle::~DspLle() = default; diff --git a/src/audio_core/lle/lle.h b/src/audio_core/lle/lle.h index 1e9302ed0..002de8aa7 100644 --- a/src/audio_core/lle/lle.h +++ b/src/audio_core/lle/lle.h @@ -25,6 +25,7 @@ public: void SetServiceToInterrupt(std::weak_ptr dsp) override; void LoadComponent(const std::vector& buffer) override; + void UnloadComponent() override; private: struct Impl; diff --git a/src/core/hle/service/dsp/dsp_dsp.cpp b/src/core/hle/service/dsp/dsp_dsp.cpp index fec7ad7bf..c885b73fa 100644 --- a/src/core/hle/service/dsp/dsp_dsp.cpp +++ b/src/core/hle/service/dsp/dsp_dsp.cpp @@ -184,6 +184,17 @@ void DSP_DSP::LoadComponent(Kernel::HLERequestContext& ctx) { size, prog_mask, data_mask); } +void DSP_DSP::UnloadComponent(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x12, 0, 0); + + system.DSP().UnloadComponent(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); + + LOG_INFO(Service_DSP, "(STUBBED)"); +} + void DSP_DSP::FlushDataCache(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x13, 2, 2); const VAddr address = rp.Pop(); diff --git a/src/core/hle/service/dsp/dsp_dsp.h b/src/core/hle/service/dsp/dsp_dsp.h index 78651bad8..2bc601511 100644 --- a/src/core/hle/service/dsp/dsp_dsp.h +++ b/src/core/hle/service/dsp/dsp_dsp.h @@ -153,6 +153,15 @@ private: */ void LoadComponent(Kernel::HLERequestContext& ctx); + /** + * DSP_DSP::UnloadComponent service function + * Inputs: + * 0 : Header Code[0x00120000] + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void UnloadComponent(Kernel::HLERequestContext& ctx); + /** * DSP_DSP::FlushDataCache service function * From 92e5c51adb2d973441ab303d9726f8474746a717 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 6 Dec 2018 10:18:39 -0500 Subject: [PATCH 15/24] Service/DSP: implement semaphore event --- src/core/hle/kernel/wait_object.cpp | 7 +++++++ src/core/hle/kernel/wait_object.h | 7 +++++++ src/core/hle/service/dsp/dsp_dsp.cpp | 7 +++++-- src/core/hle/service/dsp/dsp_dsp.h | 1 + 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp index d64b7def7..51d929d12 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/wait_object.cpp @@ -86,10 +86,17 @@ void WaitObject::WakeupAllWaitingThreads() { thread->ResumeFromWait(); } + + if (hle_notifier) + hle_notifier(); } const std::vector>& WaitObject::GetWaitingThreads() const { return waiting_threads; } +void WaitObject::SetHLENotifier(std::function callback) { + hle_notifier = callback; +} + } // namespace Kernel diff --git a/src/core/hle/kernel/wait_object.h b/src/core/hle/kernel/wait_object.h index 01fc40a0d..693ae2186 100644 --- a/src/core/hle/kernel/wait_object.h +++ b/src/core/hle/kernel/wait_object.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include #include "common/common_types.h" @@ -52,9 +53,15 @@ public: /// Get a const reference to the waiting threads list for debug use const std::vector>& GetWaitingThreads() const; + /// Sets a callback which is called when the object becomes available + void SetHLENotifier(std::function callback); + private: /// Threads waiting for this object to become available std::vector> waiting_threads; + + /// Function to call when this object becomes available + std::function hle_notifier; }; // Specialization of DynamicObjectCast for WaitObjects diff --git a/src/core/hle/service/dsp/dsp_dsp.cpp b/src/core/hle/service/dsp/dsp_dsp.cpp index c885b73fa..062ce8565 100644 --- a/src/core/hle/service/dsp/dsp_dsp.cpp +++ b/src/core/hle/service/dsp/dsp_dsp.cpp @@ -268,12 +268,12 @@ void DSP_DSP::GetSemaphoreEventHandle(Kernel::HLERequestContext& ctx) { void DSP_DSP::SetSemaphoreMask(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x17, 1, 0); - const u32 mask = rp.Pop(); + preset_semaphore = rp.Pop(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_DSP, "(STUBBED) called mask=0x{:08X}", mask); + LOG_WARNING(Service_DSP, "(STUBBED) called mask=0x{:04X}", preset_semaphore); } void DSP_DSP::GetHeadphoneStatus(Kernel::HLERequestContext& ctx) { @@ -380,6 +380,9 @@ DSP_DSP::DSP_DSP(Core::System& system) semaphore_event = system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "DSP_DSP::semaphore_event"); + + semaphore_event->SetHLENotifier( + [this]() { this->system.DSP().SetSemaphore(preset_semaphore); }); } DSP_DSP::~DSP_DSP() { diff --git a/src/core/hle/service/dsp/dsp_dsp.h b/src/core/hle/service/dsp/dsp_dsp.h index 2bc601511..5bf00334b 100644 --- a/src/core/hle/service/dsp/dsp_dsp.h +++ b/src/core/hle/service/dsp/dsp_dsp.h @@ -257,6 +257,7 @@ private: Core::System& system; Kernel::SharedPtr semaphore_event; + u16 preset_semaphore = 0; Kernel::SharedPtr interrupt_zero = nullptr; /// Currently unknown purpose Kernel::SharedPtr interrupt_one = nullptr; /// Currently unknown purpose From 483680a1246de2b82f926dccd47be1e72e062c7e Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 6 Dec 2018 11:12:47 -0500 Subject: [PATCH 16/24] audio_core/lle: only process pipe signal after loading --- src/audio_core/lle/lle.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/audio_core/lle/lle.cpp b/src/audio_core/lle/lle.cpp index a7f46a913..36ad0c20e 100644 --- a/src/audio_core/lle/lle.cpp +++ b/src/audio_core/lle/lle.cpp @@ -349,6 +349,9 @@ void DspLle::SetServiceToInterrupt(std::weak_ptr dsp) { }); auto ProcessPipeEvent = [this, dsp](bool event_from_data) { + if (!impl->loaded) + return; + auto& teakra = impl->teakra; if (event_from_data) { impl->data_signaled = true; From 21da135cc67356e1a76bcfd286cb1e802e6c738f Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 6 Dec 2018 11:13:13 -0500 Subject: [PATCH 17/24] Configuration: add option to use DSP LLE --- src/citra/config.cpp | 1 + src/citra/default_ini.h | 5 +++++ src/citra_qt/configuration/config.cpp | 2 ++ .../configuration/configure_audio.cpp | 8 ++++++++ src/citra_qt/configuration/configure_audio.ui | 19 ++++++++++++++++++- src/core/core.cpp | 8 +++++++- src/core/settings.cpp | 1 + src/core/settings.h | 1 + 8 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/citra/config.cpp b/src/citra/config.cpp index 3cd7bec88..7e83e4160 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp @@ -155,6 +155,7 @@ void Config::ReadValues() { static_cast(sdl2_config->GetInteger("Layout", "custom_bottom_bottom", 480)); // Audio + Settings::values.enable_dsp_lle = sdl2_config->GetBoolean("Audio", "enable_dsp_lle", 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 730809413..5015a1885 100644 --- a/src/citra/default_ini.h +++ b/src/citra/default_ini.h @@ -167,6 +167,11 @@ custom_bottom_bottom = swap_screen = [Audio] + +# Whether or not to enable DSP LLE +# 0 (default): No, 1: Yes +enable_dsp_lle = + # 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 dcbe18122..3dc2de659 100644 --- a/src/citra_qt/configuration/config.cpp +++ b/src/citra_qt/configuration/config.cpp @@ -136,6 +136,7 @@ void Config::ReadValues() { qt_config->endGroup(); qt_config->beginGroup("Audio"); + Settings::values.enable_dsp_lle = ReadSetting("enable_dsp_lle", false).toBool(); Settings::values.sink_id = ReadSetting("output_engine", "auto").toString().toStdString(); Settings::values.enable_audio_stretching = ReadSetting("enable_audio_stretching", true).toBool(); @@ -415,6 +416,7 @@ void Config::SaveValues() { qt_config->endGroup(); qt_config->beginGroup("Audio"); + WriteSetting("enable_dsp_lle", Settings::values.enable_dsp_lle, 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 0ab5a3ae4..84bece2b3 100644 --- a/src/citra_qt/configuration/configure_audio.cpp +++ b/src/citra_qt/configuration/configure_audio.cpp @@ -6,6 +6,7 @@ #include "audio_core/sink.h" #include "audio_core/sink_details.h" #include "citra_qt/configuration/configure_audio.h" +#include "core/core.h" #include "core/settings.h" #include "ui_configure_audio.h" @@ -19,6 +20,10 @@ ConfigureAudio::ConfigureAudio(QWidget* parent) ui->output_sink_combo_box->addItem(sink_detail.id); } + ui->emulation_combo_box->addItem(tr("HLE (fast)")); + ui->emulation_combo_box->addItem(tr("LLE (accurate)")); + ui->emulation_combo_box->setEnabled(!Core::System::GetInstance().IsPoweredOn()); + connect(ui->volume_slider, &QSlider::valueChanged, this, &ConfigureAudio::setVolumeIndicatorText); @@ -41,6 +46,8 @@ void ConfigureAudio::setConfiguration() { ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching); 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); } void ConfigureAudio::setOutputSinkFromSinkID() { @@ -85,6 +92,7 @@ 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; } void ConfigureAudio::updateAudioDevices(int sink_index) { diff --git a/src/citra_qt/configuration/configure_audio.ui b/src/citra_qt/configuration/configure_audio.ui index b80b10d37..1cfbeef37 100644 --- a/src/citra_qt/configuration/configure_audio.ui +++ b/src/citra_qt/configuration/configure_audio.ui @@ -6,7 +6,7 @@ 0 0 - 188 + 240 246 @@ -17,6 +17,23 @@ Audio + + + + 0 + + + + + Emulation: + + + + + + + + diff --git a/src/core/core.cpp b/src/core/core.cpp index 95fa69f43..f2da40704 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -6,6 +6,7 @@ #include #include "audio_core/dsp_interface.h" #include "audio_core/hle/hle.h" +#include "audio_core/lle/lle.h" #include "common/logging/log.h" #include "core/arm/arm_interface.h" #ifdef ARCHITECTURE_x86_64 @@ -188,7 +189,12 @@ System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) { cpu_core = std::make_unique(*this, USER32MODE); } - dsp_core = std::make_unique(*memory); + if (Settings::values.enable_dsp_lle) { + dsp_core = std::make_unique(); + } else { + dsp_core = std::make_unique(*memory); + } + dsp_core->SetSink(Settings::values.sink_id, Settings::values.audio_device_id); dsp_core->EnableStretching(Settings::values.enable_audio_stretching); diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 8bdf5689b..a03115e5b 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -79,6 +79,7 @@ void LogSettings() { LogSetting("Layout_Factor3d", Settings::values.factor_3d); 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_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 929db156c..614323514 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -147,6 +147,7 @@ struct Values { u8 factor_3d; // Audio + bool enable_dsp_lle; std::string sink_id; bool enable_audio_stretching; std::string audio_device_id; From 67213ca855198290b689545039a7ba561ec2c3ab Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Thu, 6 Dec 2018 12:19:58 -0500 Subject: [PATCH 18/24] audio_core/lle: link ahbm and audio callback --- src/audio_core/dsp_interface.cpp | 7 +++++++ src/audio_core/dsp_interface.h | 1 + src/audio_core/lle/lle.cpp | 12 +++++++++++- src/audio_core/lle/lle.h | 2 +- src/core/core.cpp | 2 +- 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/audio_core/dsp_interface.cpp b/src/audio_core/dsp_interface.cpp index d6343d332..f99b3538a 100644 --- a/src/audio_core/dsp_interface.cpp +++ b/src/audio_core/dsp_interface.cpp @@ -44,6 +44,13 @@ void DspInterface::OutputFrame(StereoFrame16& frame) { fifo.Push(frame.data(), frame.size()); } +void DspInterface::OutputSample(std::array sample) { + if (!sink) + return; + + fifo.Push(&sample, 1); +} + void DspInterface::OutputCallback(s16* buffer, std::size_t num_frames) { std::size_t frames_written; if (perform_time_stretching) { diff --git a/src/audio_core/dsp_interface.h b/src/audio_core/dsp_interface.h index 7a16dea0f..e7f996bb6 100644 --- a/src/audio_core/dsp_interface.h +++ b/src/audio_core/dsp_interface.h @@ -103,6 +103,7 @@ public: protected: void OutputFrame(StereoFrame16& frame); + void OutputSample(std::array sample); private: void FlushResidualStretcherAudio(); diff --git a/src/audio_core/lle/lle.cpp b/src/audio_core/lle/lle.cpp index 36ad0c20e..91c68546a 100644 --- a/src/audio_core/lle/lle.cpp +++ b/src/audio_core/lle/lle.cpp @@ -392,7 +392,17 @@ void DspLle::UnloadComponent() { impl->UnloadComponent(); } -DspLle::DspLle() : impl(std::make_unique()) {} +DspLle::DspLle(Memory::MemorySystem& memory) : impl(std::make_unique()) { + Teakra::AHBMCallback ahbm; + ahbm.read8 = [&memory](u32 address) -> u8 { + return *memory.GetFCRAMPointer(address - Memory::FCRAM_PADDR); + }; + ahbm.write8 = [&memory](u32 address, u8 value) { + *memory.GetFCRAMPointer(address - Memory::FCRAM_PADDR) = value; + }; + impl->teakra.SetAHBMCallback(ahbm); + impl->teakra.SetAudioCallback([this](std::array sample) { OutputSample(sample); }); +} DspLle::~DspLle() = default; } // namespace AudioCore diff --git a/src/audio_core/lle/lle.h b/src/audio_core/lle/lle.h index 002de8aa7..c8a6d007b 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: - DspLle(); + explicit DspLle(Memory::MemorySystem& memory); ~DspLle(); u16 RecvData(u32 register_number) override; diff --git a/src/core/core.cpp b/src/core/core.cpp index f2da40704..b1b2ec138 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -190,7 +190,7 @@ System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) { } if (Settings::values.enable_dsp_lle) { - dsp_core = std::make_unique(); + dsp_core = std::make_unique(*memory); } else { dsp_core = std::make_unique(*memory); } From e3ac24848750ac8593ba91295cb71205b0a9ec2a Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Sat, 8 Dec 2018 00:14:51 -0500 Subject: [PATCH 19/24] update teakra: implement idle skipping --- externals/teakra | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/externals/teakra b/externals/teakra index 6dc129754..ad151388c 160000 --- a/externals/teakra +++ b/externals/teakra @@ -1 +1 @@ -Subproject commit 6dc1297548a116e6ef78ddd1a52ab3b3f9af0b17 +Subproject commit ad151388cd24e0b85b3992dfa92d66808f7ae925 From 05c372bf6c0abe2a547b34eb9bc6a4a22664d149 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Sat, 8 Dec 2018 20:36:04 -0500 Subject: [PATCH 20/24] Update teakra to fix macos issue; address comment feedbacks --- externals/teakra | 2 +- src/audio_core/lle/lle.cpp | 90 ++++++++++++------- src/audio_core/lle/lle.h | 3 +- src/citra/default_ini.h | 1 - src/citra_qt/configuration/configure_audio.ui | 2 +- src/core/hle/kernel/wait_object.cpp | 3 +- src/core/hle/service/dsp/dsp_dsp.cpp | 8 +- 7 files changed, 65 insertions(+), 44 deletions(-) diff --git a/externals/teakra b/externals/teakra index ad151388c..97f9ec617 160000 --- a/externals/teakra +++ b/externals/teakra @@ -1 +1 @@ -Subproject commit ad151388cd24e0b85b3992dfa92d66808f7ae925 +Subproject commit 97f9ec6171882ee65fe6a011af82b96cfb98cff0 diff --git a/src/audio_core/lle/lle.cpp b/src/audio_core/lle/lle.cpp index 91c68546a..2defd14ed 100644 --- a/src/audio_core/lle/lle.cpp +++ b/src/audio_core/lle/lle.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include "audio_core/lle/lle.h" #include "common/assert.h" #include "common/bit_field.h" @@ -10,7 +11,6 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/hle/service/dsp/dsp_dsp.h" -#include "teakra/teakra.h" namespace AudioCore { @@ -22,11 +22,11 @@ enum class SegmentType : u8 { class Dsp1 { public: - Dsp1(const std::vector& raw); + explicit Dsp1(const std::vector& raw); struct Header { std::array signature; - std::array magic; + std::array magic; u32_le binary_size; u16_le memory_layout; INSERT_PADDING_BYTES(3); @@ -72,7 +72,7 @@ Dsp1::Dsp1(const std::vector& raw) { raw.begin() + header.segments[i].offset + header.segments[i].size); segment.memory_type = header.segments[i].memory_type; segment.target = header.segments[i].address; - segments.push_back(segment); + segments.push_back(std::move(segment)); } } @@ -83,6 +83,26 @@ struct PipeStatus { u16_le write_bptr; u8 slot_index; u8 flags; + + static constexpr u16 WrapBit = 0x8000; + static constexpr u16 PtrMask = 0x7FFF; + + bool IsFull() const { + return (read_bptr ^ write_bptr) == WrapBit; + } + + bool IsEmpty() const { + return (read_bptr ^ write_bptr) == 0; + } + + /* + * IsWrapped: Are read and write pointers not in the same pass. + * false: ----[xxxx]---- + * true: xxxx]----[xxxx (data is wrapping around the end) + */ + bool IsWrapped() const { + return (read_bptr ^ write_bptr) >= WrapBit; + } }; static_assert(sizeof(PipeStatus) == 10); @@ -93,7 +113,7 @@ enum class PipeDirection : u8 { }; static u8 PipeIndexToSlotIndex(u8 pipe_index, PipeDirection direction) { - return (pipe_index << 1) + (u8)direction; + return (pipe_index << 1) + static_cast(direction); } struct DspLle::Impl final { @@ -111,7 +131,9 @@ struct DspLle::Impl final { Core::TimingEventType* teakra_slice_event; bool loaded = false; - static constexpr unsigned TeakraSlice = 20000; + static constexpr u32 DspDataOffset = 0x40000; + static constexpr u32 TeakraSlice = 20000; + void RunTeakraSlice() { teakra.Run(TeakraSlice); } @@ -128,7 +150,7 @@ struct DspLle::Impl final { u8* GetDspDataPointer(u32 baddr) { auto& memory = teakra.GetDspMemory(); - return &memory[0x40000 + baddr]; + return &memory[DspDataOffset + baddr]; } PipeStatus GetPipeStatus(u8 pipe_index, PipeDirection direction) { @@ -156,16 +178,15 @@ struct DspLle::Impl final { PipeStatus pipe_status = GetPipeStatus(pipe_index, PipeDirection::CPUtoDSP); bool need_update = false; const u8* buffer_ptr = data.data(); - u16 bsize = (u16)data.size(); + u16 bsize = static_cast(data.size()); while (bsize != 0) { - u16 x = pipe_status.read_bptr ^ pipe_status.write_bptr; - ASSERT_MSG(x != 0x8000, "Pipe is Full"); + ASSERT_MSG(!pipe_status.IsFull(), "Pipe is Full"); u16 write_bend; - if (x > 0x8000) - write_bend = pipe_status.read_bptr & 0x7FFF; + if (pipe_status.IsWrapped()) + write_bend = pipe_status.read_bptr & PipeStatus::PtrMask; else write_bend = pipe_status.bsize; - u16 write_bbegin = pipe_status.write_bptr & 0x7FFF; + u16 write_bbegin = pipe_status.write_bptr & PipeStatus::PtrMask; ASSERT_MSG(write_bend > write_bbegin, "Pipe is in inconsistent state: end {:04X} <= begin {:04X}, size {:04X}", write_bend, write_bbegin, pipe_status.bsize); @@ -175,11 +196,11 @@ struct DspLle::Impl final { buffer_ptr += write_bsize; pipe_status.write_bptr += write_bsize; bsize -= write_bsize; - ASSERT_MSG((pipe_status.write_bptr & 0x7FFF) <= pipe_status.bsize, + ASSERT_MSG((pipe_status.write_bptr & PipeStatus::PtrMask) <= pipe_status.bsize, "Pipe is in inconsistent state: write > size"); - if ((pipe_status.write_bptr & 0x7FFF) == pipe_status.bsize) { - pipe_status.write_bptr &= 0x8000; - pipe_status.write_bptr ^= 0x8000; + if ((pipe_status.write_bptr & PipeStatus::PtrMask) == pipe_status.bsize) { + pipe_status.write_bptr &= PipeStatus::WrapBit; + pipe_status.write_bptr ^= PipeStatus::WrapBit; } need_update = true; } @@ -197,15 +218,14 @@ struct DspLle::Impl final { std::vector data(bsize); u8* buffer_ptr = data.data(); while (bsize != 0) { - u16 x = pipe_status.read_bptr ^ pipe_status.write_bptr; - ASSERT_MSG(x != 0, "Pipe is empty"); + ASSERT_MSG(!pipe_status.IsEmpty(), "Pipe is empty"); u16 read_bend; - if (x >= 0x8000) { + if (pipe_status.IsWrapped()) { read_bend = pipe_status.bsize; } else { - read_bend = pipe_status.write_bptr & 0x7FFF; + read_bend = pipe_status.write_bptr & PipeStatus::PtrMask; } - u16 read_bbegin = pipe_status.read_bptr & 0x7FFF; + u16 read_bbegin = pipe_status.read_bptr & PipeStatus::PtrMask; ASSERT(read_bend > read_bbegin); u16 read_bsize = std::min(bsize, read_bend - read_bbegin); std::memcpy(buffer_ptr, GetDspDataPointer(pipe_status.waddress * 2 + read_bbegin), @@ -213,11 +233,11 @@ struct DspLle::Impl final { buffer_ptr += read_bsize; pipe_status.read_bptr += read_bsize; bsize -= read_bsize; - ASSERT_MSG((pipe_status.read_bptr & 0x7FFF) <= pipe_status.bsize, + ASSERT_MSG((pipe_status.read_bptr & PipeStatus::PtrMask) <= pipe_status.bsize, "Pipe is in inconsistent state: read > size"); - if ((pipe_status.read_bptr & 0x7FFF) == pipe_status.bsize) { - pipe_status.read_bptr &= 0x8000; - pipe_status.read_bptr ^= 0x8000; + if ((pipe_status.read_bptr & PipeStatus::PtrMask) == pipe_status.bsize) { + pipe_status.read_bptr &= PipeStatus::WrapBit; + pipe_status.read_bptr ^= PipeStatus::WrapBit; } need_update = true; } @@ -232,10 +252,10 @@ struct DspLle::Impl final { u16 GetPipeReadableSize(u8 pipe_index) { PipeStatus pipe_status = GetPipeStatus(pipe_index, PipeDirection::DSPtoCPU); u16 size = pipe_status.write_bptr - pipe_status.read_bptr; - if ((pipe_status.read_bptr ^ pipe_status.write_bptr) >= 0x8000) { + if (pipe_status.IsWrapped()) { size += pipe_status.bsize; } - return size & 0x7FFF; + return size & PipeStatus::PtrMask; } void LoadComponent(const std::vector& buffer) { @@ -249,7 +269,7 @@ struct DspLle::Impl final { Dsp1 dsp(buffer); auto& dsp_memory = teakra.GetDspMemory(); u8* program = dsp_memory.data(); - u8* data = dsp_memory.data() + 0x40000; + u8* data = dsp_memory.data() + DspDataOffset; for (const auto& segment : dsp.segments) { if (segment.memory_type == SegmentType::ProgramA || segment.memory_type == SegmentType::ProgramB) { @@ -265,10 +285,11 @@ struct DspLle::Impl final { // Wait for initialization if (dsp.recv_data_on_start) { - for (unsigned i = 0; i < 3; ++i) { - while (!teakra.RecvDataIsReady(i)) - RunTeakraSlice(); - ASSERT(teakra.RecvData(i) == 1); + for (u8 i = 0; i < 3; ++i) { + do { + while (!teakra.RecvDataIsReady(i)) + RunTeakraSlice(); + } while (teakra.RecvData(i) != 1); } } @@ -287,10 +308,11 @@ struct DspLle::Impl final { } // Send finalization signal + constexpr u16 FinalizeSignal = 0x8000; while (!teakra.SendDataIsEmpty(2)) RunTeakraSlice(); - teakra.SendData(2, 0x8000); + teakra.SendData(2, FinalizeSignal); // Wait for completion while (!teakra.RecvDataIsReady(2)) diff --git a/src/audio_core/lle/lle.h b/src/audio_core/lle/lle.h index c8a6d007b..5c89e0656 100644 --- a/src/audio_core/lle/lle.h +++ b/src/audio_core/lle/lle.h @@ -11,7 +11,7 @@ namespace AudioCore { class DspLle final : public DspInterface { public: explicit DspLle(Memory::MemorySystem& memory); - ~DspLle(); + ~DspLle() override; u16 RecvData(u32 register_number) override; bool RecvDataIsReady(u32 register_number) const override; @@ -29,7 +29,6 @@ public: private: struct Impl; - friend struct Impl; std::unique_ptr impl; }; diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h index 5015a1885..dfef2b227 100644 --- a/src/citra/default_ini.h +++ b/src/citra/default_ini.h @@ -167,7 +167,6 @@ custom_bottom_bottom = swap_screen = [Audio] - # Whether or not to enable DSP LLE # 0 (default): No, 1: Yes enable_dsp_lle = diff --git a/src/citra_qt/configuration/configure_audio.ui b/src/citra_qt/configuration/configure_audio.ui index 1cfbeef37..9a3768b2a 100644 --- a/src/citra_qt/configuration/configure_audio.ui +++ b/src/citra_qt/configuration/configure_audio.ui @@ -6,7 +6,7 @@ 0 0 - 240 + 188 246 diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp index 51d929d12..a63cf4c33 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/wait_object.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include "common/assert.h" #include "common/logging/log.h" #include "core/hle/kernel/errors.h" @@ -96,7 +97,7 @@ const std::vector>& WaitObject::GetWaitingThreads() const { } void WaitObject::SetHLENotifier(std::function callback) { - hle_notifier = callback; + hle_notifier = std::move(callback); } } // namespace Kernel diff --git a/src/core/hle/service/dsp/dsp_dsp.cpp b/src/core/hle/service/dsp/dsp_dsp.cpp index 062ce8565..22eba5ea4 100644 --- a/src/core/hle/service/dsp/dsp_dsp.cpp +++ b/src/core/hle/service/dsp/dsp_dsp.cpp @@ -50,7 +50,7 @@ void DSP_DSP::SetSemaphore(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_DSP, "(STUBBED) called, semaphore_value={:04X}", semaphore_value); + LOG_INFO(Service_DSP, "called, semaphore_value={:04X}", semaphore_value); } void DSP_DSP::ConvertProcessAddressFromDspDram(Kernel::HLERequestContext& ctx) { @@ -180,8 +180,8 @@ void DSP_DSP::LoadComponent(Kernel::HLERequestContext& ctx) { system.DSP().LoadComponent(component_data); - LOG_INFO(Service_DSP, "(STUBBED) called size=0x{:X}, prog_mask=0x{:08X}, data_mask=0x{:08X}", - size, prog_mask, data_mask); + LOG_INFO(Service_DSP, "called size=0x{:X}, prog_mask=0x{:08X}, data_mask=0x{:08X}", size, + prog_mask, data_mask); } void DSP_DSP::UnloadComponent(Kernel::HLERequestContext& ctx) { @@ -357,7 +357,7 @@ DSP_DSP::DSP_DSP(Core::System& system) {0x000F0080, &DSP_DSP::GetPipeReadableSize, "GetPipeReadableSize"}, {0x001000C0, &DSP_DSP::ReadPipeIfPossible, "ReadPipeIfPossible"}, {0x001100C2, &DSP_DSP::LoadComponent, "LoadComponent"}, - {0x00120000, nullptr, "UnloadComponent"}, + {0x00120000, &DSP_DSP::UnloadComponent, "UnloadComponent"}, {0x00130082, &DSP_DSP::FlushDataCache, "FlushDataCache"}, {0x00140082, &DSP_DSP::InvalidateDataCache, "InvalidateDCache"}, {0x00150082, &DSP_DSP::RegisterInterruptEvents, "RegisterInterruptEvents"}, From 969dc3b46f257ffdad6520531af333eaa300315a Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Sat, 15 Dec 2018 13:36:33 -0500 Subject: [PATCH 21/24] Update teakra and address more comments --- externals/teakra | 2 +- src/audio_core/lle/lle.cpp | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/externals/teakra b/externals/teakra index 97f9ec617..343bad999 160000 --- a/externals/teakra +++ b/externals/teakra @@ -1 +1 @@ -Subproject commit 97f9ec6171882ee65fe6a011af82b96cfb98cff0 +Subproject commit 343bad999d53279b5ed966db3f36e2d1c6f5d85b diff --git a/src/audio_core/lle/lle.cpp b/src/audio_core/lle/lle.cpp index 2defd14ed..603e9fa80 100644 --- a/src/audio_core/lle/lle.cpp +++ b/src/audio_core/lle/lle.cpp @@ -153,7 +153,12 @@ struct DspLle::Impl final { return &memory[DspDataOffset + baddr]; } - PipeStatus GetPipeStatus(u8 pipe_index, PipeDirection direction) { + const u8* GetDspDataPointer(u32 baddr) const { + auto& memory = teakra.GetDspMemory(); + return &memory[DspDataOffset + baddr]; + } + + PipeStatus GetPipeStatus(u8 pipe_index, PipeDirection direction) const { u8 slot_index = PipeIndexToSlotIndex(pipe_index, direction); PipeStatus pipe_status; std::memcpy(&pipe_status, @@ -249,7 +254,7 @@ struct DspLle::Impl final { } return data; } - u16 GetPipeReadableSize(u8 pipe_index) { + u16 GetPipeReadableSize(u8 pipe_index) const { PipeStatus pipe_status = GetPipeStatus(pipe_index, PipeDirection::DSPtoCPU); u16 size = pipe_status.write_bptr - pipe_status.read_bptr; if (pipe_status.IsWrapped()) { @@ -307,7 +312,7 @@ struct DspLle::Impl final { return; } - // Send finalization signal + // Send finalization signal via command/reply register 2 constexpr u16 FinalizeSignal = 0x8000; while (!teakra.SendDataIsEmpty(2)) RunTeakraSlice(); From fbad420240c2247e0ebf792404876c17a7b88c2b Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Wed, 19 Dec 2018 19:44:11 -0500 Subject: [PATCH 22/24] Common/Barrier: add method to get current generation --- src/common/thread.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/common/thread.h b/src/common/thread.h index e84db99a0..38532a190 100644 --- a/src/common/thread.h +++ b/src/common/thread.h @@ -79,9 +79,14 @@ public: } } + std::size_t Generation() const { + std::unique_lock lk(mutex); + return generation; + } + private: std::condition_variable condvar; - std::mutex mutex; + mutable std::mutex mutex; std::size_t count; std::size_t waiting = 0; std::size_t generation = 0; // Incremented once each time the barrier is used From 443f4b964d17dad0a8e8b043bd866e99a65f0696 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Wed, 19 Dec 2018 19:45:22 -0500 Subject: [PATCH 23/24] 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; From a7a24367d49514d54d45959d5edeae824b837959 Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Fri, 21 Dec 2018 21:34:36 -0500 Subject: [PATCH 24/24] update teakra --- externals/teakra | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/externals/teakra b/externals/teakra index fd97ef90b..e6ea0eae6 160000 --- a/externals/teakra +++ b/externals/teakra @@ -1 +1 @@ -Subproject commit fd97ef90bff46bd5c3163edfd32b4cb38964eebe +Subproject commit e6ea0eae656c022d7878ffabc4e016b3e6f0c536