From 42b748a881630f2405570f56c9a6448ebadff0a1 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 14 Jan 2015 22:45:36 +0300 Subject: [PATCH 1/7] Syscall name resolving improved --- rpcs3/Emu/ARMv7/Modules/sceLibc.cpp | 2 +- rpcs3/Emu/ARMv7/PSVFuncList.cpp | 32 +++++++-------- rpcs3/Emu/CPU/CPUThread.cpp | 63 +++++++++++++++++++++++++++-- rpcs3/Emu/Cell/PPUThread.h | 26 +++++++----- rpcs3/Emu/SysCalls/CB_FUNC.h | 4 +- rpcs3/Emu/SysCalls/SC_FUNC.h | 4 +- rpcs3/Loader/ELF32.cpp | 5 +-- 7 files changed, 97 insertions(+), 39 deletions(-) diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp index 95a1339e2d..9abcf593e4 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp @@ -26,7 +26,7 @@ namespace sce_libc_func }); } - void printf(vm::psv::ptr fmt) + void printf(vm::psv::ptr fmt) // va_args... { sceLibc.Error("printf(fmt=0x%x)", fmt); diff --git a/rpcs3/Emu/ARMv7/PSVFuncList.cpp b/rpcs3/Emu/ARMv7/PSVFuncList.cpp index d1d3d2b1a6..84262b3b0f 100644 --- a/rpcs3/Emu/ARMv7/PSVFuncList.cpp +++ b/rpcs3/Emu/ARMv7/PSVFuncList.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" +#include #include "Utilities/Log.h" #include "Emu/System.h" #include "PSVFuncList.h" @@ -7,29 +8,19 @@ std::vector g_psv_func_list; void add_psv_func(psv_func& data) { + // setup special functions (without NIDs) if (!g_psv_func_list.size()) { psv_func unimplemented; - unimplemented.nid = 0x00000000; // must not be a valid id - unimplemented.name = "INVALID FUNCTION (0x0)"; - unimplemented.func.reset(new psv_func_detail::func_binder([]() -> u32 - { - LOG_ERROR(HLE, "Unimplemented function executed"); - Emu.Pause(); - - return 0xffffffffu; - })); + unimplemented.nid = 0; + unimplemented.name = "Special function (unimplemented stub)"; + unimplemented.func.reset(new psv_func_detail::func_binder([](ARMv7Thread& CPU){ CPU.m_last_syscall = vm::psv::read32(CPU.PC + 4); throw "Unimplemented function executed"; })); g_psv_func_list.push_back(unimplemented); psv_func hle_return; - hle_return.nid = 0x00000001; // must not be a valid id - hle_return.name = "INVALID FUNCTION (0x1)"; - hle_return.func.reset(new psv_func_detail::func_binder([](ARMv7Thread& CPU) - { - CPU.FastStop(); - - return; - })); + hle_return.nid = 1; + hle_return.name = "Special function (return from HLE)"; + hle_return.func.reset(new psv_func_detail::func_binder([](ARMv7Thread& CPU){ CPU.FastStop(); })); g_psv_func_list.push_back(hle_return); } @@ -40,7 +31,7 @@ psv_func* get_psv_func_by_nid(u32 nid) { for (auto& f : g_psv_func_list) { - if (f.nid == nid) + if (f.nid == nid && &f - g_psv_func_list.data() >= 2 /* special functions count */) { return &f; } @@ -61,8 +52,13 @@ u32 get_psv_func_index(psv_func* func) void execute_psv_func_by_index(ARMv7Thread& CPU, u32 index) { assert(index < g_psv_func_list.size()); + + auto old_last_syscall = CPU.m_last_syscall; + CPU.m_last_syscall = g_psv_func_list[index].nid; (*g_psv_func_list[index].func)(CPU); + + CPU.m_last_syscall = old_last_syscall; } extern psv_log_base sceLibc; diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 826a593806..b990e0097b 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -1,10 +1,11 @@ #include "stdafx.h" #include "rpcs3/Ini.h" -#include "Emu/SysCalls/SysCalls.h" #include "Utilities/Log.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/DbgCommand.h" +#include "Emu/SysCalls/SysCalls.h" +#include "Emu/ARMv7/PSVFuncList.h" #include "CPUDecoder.h" #include "CPUThread.h" @@ -256,6 +257,62 @@ void CPUThread::ExecOnce() void CPUThread::Task() { + auto get_syscall_name = [this](u64 syscall) -> std::string + { + switch (GetType()) + { + case CPU_THREAD_ARMv7: + { + if ((u32)syscall == syscall) + { + if (syscall) + { + if (auto func = get_psv_func_by_nid((u32)syscall)) + { + return func->name; + } + } + else + { + return{}; + } + } + + return "unknown function"; + } + case CPU_THREAD_PPU: + { + if ((u32)syscall == syscall) + { + if (syscall) + { + if (syscall < 1024) + { + // TODO: + //return SysCalls::GetSyscallName((u32)syscall); + } + else + { + return SysCalls::GetHLEFuncName((u32)syscall); + } + } + else + { + return{}; + } + } + + // fallthrough + } + case CPU_THREAD_SPU: + case CPU_THREAD_RAW_SPU: + default: + { + return "unknown syscall"; + } + } + }; + if (Ini.HLELogging.GetValue()) LOG_NOTICE(GENERAL, "%s enter", CPUThread::GetFName().c_str()); const std::vector& bp = Emu.GetBreakPoints(); @@ -310,13 +367,13 @@ void CPUThread::Task() } catch (const std::string& e) { - LOG_ERROR(GENERAL, "Exception: %s (is_alive=%d, m_last_syscall=0x%llx (%s))", e, IsAlive(), m_last_syscall, SysCalls::GetHLEFuncName((u32)m_last_syscall)); + LOG_ERROR(GENERAL, "Exception: %s (is_alive=%d, m_last_syscall=0x%llx (%s))", e, IsAlive(), m_last_syscall, get_syscall_name(m_last_syscall)); LOG_NOTICE(GENERAL, RegsToString()); Emu.Pause(); } catch (const char* e) { - LOG_ERROR(GENERAL, "Exception: %s (is_alive=%d, m_last_syscall=0x%llx (%s))", e, IsAlive(), m_last_syscall, SysCalls::GetHLEFuncName((u32)m_last_syscall)); + LOG_ERROR(GENERAL, "Exception: %s (is_alive=%d, m_last_syscall=0x%llx (%s))", e, IsAlive(), m_last_syscall, get_syscall_name(m_last_syscall)); LOG_NOTICE(GENERAL, RegsToString()); Emu.Pause(); } diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index c0d5eda43c..4f023597ba 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -816,9 +816,9 @@ public: template struct cast_ppu_gpr { - static_assert(sizeof(T) <= 8, "Type for cast_ppu_gpr is invalid (too big)"); + static_assert(sizeof(T) <= 8, "Invalid type for cast_ppu_gpr"); - static u64 func(const T& value) + __forceinline static u64 to_gpr(const T& value) { u64 result = 0; (T&)result = value; @@ -829,7 +829,7 @@ struct cast_ppu_gpr template struct cast_ppu_gpr { - static u64 func(const T& value) + __forceinline static u64 to_gpr(const T& value) { return (u8&)value; } @@ -838,7 +838,7 @@ struct cast_ppu_gpr template struct cast_ppu_gpr { - static u64 func(const T& value) + __forceinline static u64 to_gpr(const T& value) { return (u16&)value; } @@ -847,7 +847,7 @@ struct cast_ppu_gpr template struct cast_ppu_gpr { - static u64 func(const T& value) + __forceinline static u64 to_gpr(const T& value) { return (u32&)value; } @@ -856,7 +856,7 @@ struct cast_ppu_gpr template struct cast_ppu_gpr { - static u64 func(const T& value) + __forceinline static u64 to_gpr(const T& value) { return (u64&)value; } @@ -865,7 +865,7 @@ struct cast_ppu_gpr template<> struct cast_ppu_gpr { - static u64 func(const s8& value) + __forceinline static u64 to_gpr(const s8& value) { return value; } @@ -874,7 +874,7 @@ struct cast_ppu_gpr template<> struct cast_ppu_gpr { - static u64 func(const s16& value) + __forceinline static u64 to_gpr(const s16& value) { return value; } @@ -883,7 +883,7 @@ struct cast_ppu_gpr template<> struct cast_ppu_gpr { - static u64 func(const s32& value) + __forceinline static u64 to_gpr(const s32& value) { return value; } @@ -892,8 +892,14 @@ struct cast_ppu_gpr template<> struct cast_ppu_gpr { - static u64 func(const s64& value) + __forceinline static u64 to_gpr(const s64& value) { return value; } }; + +template +__forceinline static u64 cast_to_ppu_gpr(const T& value) +{ + return cast_ppu_gpr::to_gpr(value); +} diff --git a/rpcs3/Emu/SysCalls/CB_FUNC.h b/rpcs3/Emu/SysCalls/CB_FUNC.h index 129fd5c109..ac49cb90b5 100644 --- a/rpcs3/Emu/SysCalls/CB_FUNC.h +++ b/rpcs3/Emu/SysCalls/CB_FUNC.h @@ -26,7 +26,7 @@ namespace cb_detail __forceinline static void set_value(PPUThread& CPU, const T& arg) { - CPU.GPR[g_count + 2] = cast_ppu_gpr::func(arg); + CPU.GPR[g_count + 2] = cast_to_ppu_gpr(arg); } }; @@ -63,7 +63,7 @@ namespace cb_detail { const int stack_pos = 0x70 + (g_count - 9) * 8 - FIXED_STACK_FRAME_SIZE; static_assert(stack_pos < 0, "TODO: Increase fixed stack frame size (arg count limit broken)"); - vm::write64(CPU.GPR[1] + stack_pos, cast_ppu_gpr::func(arg)); + vm::write64(CPU.GPR[1] + stack_pos, cast_to_ppu_gpr(arg)); } }; diff --git a/rpcs3/Emu/SysCalls/SC_FUNC.h b/rpcs3/Emu/SysCalls/SC_FUNC.h index d1d5f38dd1..d3ad6739b5 100644 --- a/rpcs3/Emu/SysCalls/SC_FUNC.h +++ b/rpcs3/Emu/SysCalls/SC_FUNC.h @@ -77,7 +77,7 @@ namespace detail static __forceinline void func(PPUThread& CPU, const T& result) { - CPU.GPR[3] = cast_ppu_gpr::func(result); + CPU.GPR[3] = cast_to_ppu_gpr(result); } }; @@ -88,7 +88,7 @@ namespace detail static __forceinline void func(PPUThread& CPU, const T& result) { - CPU.FPR[1] = (double)result; + CPU.FPR[1] = result; } }; diff --git a/rpcs3/Loader/ELF32.cpp b/rpcs3/Loader/ELF32.cpp index 31925d4b57..cb9be62759 100644 --- a/rpcs3/Loader/ELF32.cpp +++ b/rpcs3/Loader/ELF32.cpp @@ -187,9 +187,8 @@ namespace loader LOG_ERROR(LOADER, "Unimplemented function 0x%08x (addr=0x%x)", nid, addr); vm::psv::write16(addr + 0, 0xf870); // HACK instruction (Thumb) - vm::psv::write16(addr + 2, 0x0000); // index 0 - vm::psv::write16(addr + 4, 0x4770); // BX LR - vm::psv::write16(addr + 6, 0); // null + vm::psv::write16(addr + 2, 0); // index 0 (unimplemented stub) + vm::psv::write32(addr + 4, nid); // nid } } } From fd06f7038713434b472de6848ec8ff1de05a884f Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Fri, 16 Jan 2015 17:36:53 +0300 Subject: [PATCH 2/7] cellAudio updated, thread_t updated --- Utilities/Thread.cpp | 78 +- Utilities/Thread.h | 22 +- rpcs3/Emu/Audio/AL/OpenALThread.cpp | 6 +- rpcs3/Emu/Audio/AudioDumper.cpp | 44 +- rpcs3/Emu/Audio/AudioDumper.h | 7 +- rpcs3/Emu/Audio/XAudio2/XAudio2Thread.cpp | 12 +- rpcs3/Emu/CPU/CPUThread.cpp | 12 +- rpcs3/Emu/RSX/RSXThread.cpp | 2 +- rpcs3/Emu/SysCalls/Callback.cpp | 4 +- rpcs3/Emu/SysCalls/Modules/cellAdec.cpp | 13 +- rpcs3/Emu/SysCalls/Modules/cellAudio.cpp | 1009 ++++++++--------- .../{Audio => SysCalls/Modules}/cellAudio.h | 60 +- rpcs3/Emu/SysCalls/Modules/cellDmux.cpp | 8 +- rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp | 3 +- rpcs3/Emu/SysCalls/Modules/cellVdec.cpp | 23 +- rpcs3/Emu/SysCalls/Modules/libmixer.cpp | 53 +- rpcs3/Emu/SysCalls/lv2/cellFs.cpp | 6 +- rpcs3/emucore.vcxproj | 1 + rpcs3/emucore.vcxproj.filters | 3 + 19 files changed, 669 insertions(+), 697 deletions(-) rename rpcs3/Emu/{Audio => SysCalls/Modules}/cellAudio.h (81%) diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 1af3f5da95..2da136ede4 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "Log.h" +#include "rpcs3/Ini.h" #include "Emu/System.h" #include "Emu/CPU/CPUThread.h" #include "Emu/SysCalls/SysCalls.h" @@ -285,7 +286,7 @@ void signal_handler(int sig, siginfo_t* info, void* uct) ucontext_t* const ctx = (ucontext_t*)uct; const u64 addr64 = (u64)info->si_addr - (u64)Memory.GetBaseAddr(); //const bool is_writing = false; // TODO: get it correctly - if (addr64 < 0x100000000ull) + if (addr64 < 0x100000000ull && GetCurrentNamedThread()) { const u32 addr = (u32)addr64; if (addr - RAW_SPU_BASE_ADDR < (6 * RAW_SPU_OFFSET) && (addr % RAW_SPU_OFFSET) >= RAW_SPU_PROB_OFFSET) // RawSPU MMIO registers @@ -384,7 +385,7 @@ NamedThreadBase* GetCurrentNamedThread() void SetCurrentNamedThread(NamedThreadBase* value) { - auto old_value = g_tls_this_thread; + const auto old_value = g_tls_this_thread; if (old_value == value) { @@ -536,23 +537,40 @@ bool ThreadBase::TestDestroy() const return m_destroy; } -thread::thread(const std::string& name, std::function func) : m_name(name) +thread_t::thread_t(const std::string& name, std::function func) : m_name(name), m_state(TS_NON_EXISTENT) { start(func); } -thread::thread(const std::string& name) : m_name(name) +thread_t::thread_t(const std::string& name) : m_name(name), m_state(TS_NON_EXISTENT) { } -thread::thread() +thread_t::thread_t() : m_state(TS_NON_EXISTENT) { } -void thread::start(std::function func) +void thread_t::set_name(const std::string& name) { + m_name = name; +} + +thread_t::~thread_t() +{ + if (m_state == TS_JOINABLE) + { + m_thr.detach(); + } +} + +void thread_t::start(std::function func) +{ + if (m_state.exchange(TS_NON_EXISTENT) == TS_JOINABLE) + { + m_thr.join(); // forcefully join previously created thread + } + std::string name = m_name; - m_thr = std::thread([func, name]() { SetCurrentThreadDebugName(name.c_str()); @@ -567,6 +585,11 @@ void thread::start(std::function func) SetCurrentNamedThread(&info); g_thread_count++; + if (Ini.HLELogging.GetValue()) + { + LOG_NOTICE(HLE, name + " started"); + } + try { func(); @@ -580,6 +603,15 @@ void thread::start(std::function func) LOG_ERROR(GENERAL, "%s: %s", name.c_str(), e.c_str()); } + if (Emu.IsStopped()) + { + LOG_NOTICE(HLE, name + " aborted"); + } + else if (Ini.HLELogging.GetValue()) + { + LOG_NOTICE(HLE, name + " ended"); + } + SetCurrentNamedThread(nullptr); g_thread_count--; @@ -587,21 +619,41 @@ void thread::start(std::function func) _set_se_translator(old_se_translator); #endif }); + + if (m_state.exchange(TS_JOINABLE) == TS_JOINABLE) + { + assert(!"thread_t::start() failed"); // probably started from another thread + } } -void thread::detach() +void thread_t::detach() { - m_thr.detach(); + if (m_state.exchange(TS_NON_EXISTENT) == TS_JOINABLE) + { + m_thr.detach(); + } + else + { + assert(!"thread_t::detach() failed"); // probably joined or detached + } } -void thread::join() +void thread_t::join() { - m_thr.join(); + if (m_state.exchange(TS_NON_EXISTENT) == TS_JOINABLE) + { + m_thr.join(); + } + else + { + assert(!"thread_t::join() failed"); // probably joined or detached + } } -bool thread::joinable() const +bool thread_t::joinable() const { - return m_thr.joinable(); + //return m_thr.joinable(); + return m_state == TS_JOINABLE; } bool waiter_map_t::is_stopped(u64 signal_id) diff --git a/Utilities/Thread.h b/Utilities/Thread.h index 4b54317bec..200b54b02d 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -54,18 +54,32 @@ public: virtual void Task() = 0; }; -class thread +class thread_t { + enum thread_state_t + { + TS_NON_EXISTENT, + TS_JOINABLE, + }; + + std::atomic m_state; std::string m_name; std::thread m_thr; public: - thread(const std::string& name, std::function func); - thread(const std::string& name); - thread(); + thread_t(const std::string& name, std::function func); + thread_t(const std::string& name); + thread_t(); + ~thread_t(); + thread_t(const thread_t& right) = delete; + thread_t(thread_t&& right) = delete; + + thread_t& operator =(const thread_t& right) = delete; + thread_t& operator =(thread_t&& right) = delete; public: + void set_name(const std::string& name); void start(std::function func); void detach(); void join(); diff --git a/rpcs3/Emu/Audio/AL/OpenALThread.cpp b/rpcs3/Emu/Audio/AL/OpenALThread.cpp index f63fda6dc6..38e1be699e 100644 --- a/rpcs3/Emu/Audio/AL/OpenALThread.cpp +++ b/rpcs3/Emu/Audio/AL/OpenALThread.cpp @@ -11,8 +11,6 @@ ALCenum g_last_alc_error = ALC_NO_ERROR; #define checkForAlError(sit) if((g_last_al_error = alGetError()) != AL_NO_ERROR) printAlError(g_last_al_error, sit) #define checkForAlcError(sit) if((g_last_alc_error = alcGetError(m_device)) != ALC_NO_ERROR) printAlcError(g_last_alc_error, sit) -static const ALenum g_audio_format = Ini.AudioConvertToU16.GetValue() ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO_FLOAT32; - void printAlError(ALenum err, const char* situation) { if (err != AL_NO_ERROR) @@ -102,7 +100,7 @@ void OpenALThread::Open(const void* src, int size) for (uint i = 0; iCreateSourceVoice(&m_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO); diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index b990e0097b..df64539f20 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -280,6 +280,7 @@ void CPUThread::Task() return "unknown function"; } + case CPU_THREAD_PPU: { if ((u32)syscall == syscall) @@ -290,6 +291,7 @@ void CPUThread::Task() { // TODO: //return SysCalls::GetSyscallName((u32)syscall); + return "unknown syscall"; } else { @@ -302,13 +304,19 @@ void CPUThread::Task() } } - // fallthrough + return "unknown function"; } + case CPU_THREAD_SPU: case CPU_THREAD_RAW_SPU: default: { - return "unknown syscall"; + if (!syscall) + { + return{}; + } + + return "unknown function"; } } }; diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 28333b1e59..f3bd2be3a6 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -2350,7 +2350,7 @@ void RSXThread::Task() m_last_flip_time = get_system_time() - 1000000; volatile bool is_vblank_stopped = false; - thread vblank("VBlank thread", [&]() + thread_t vblank("VBlank thread", [&]() { const u64 start_time = get_system_time(); diff --git a/rpcs3/Emu/SysCalls/Callback.cpp b/rpcs3/Emu/SysCalls/Callback.cpp index e01b341fbe..c74fc84871 100644 --- a/rpcs3/Emu/SysCalls/Callback.cpp +++ b/rpcs3/Emu/SysCalls/Callback.cpp @@ -82,7 +82,7 @@ void CallbackManager::Init() static_cast(m_cb_thread)->DoRun(); } - thread cb_async_thread("CallbackManager::Async() thread", [this]() + thread_t cb_async_thread("CallbackManager thread", [this]() { SetCurrentNamedThread(m_cb_thread); @@ -108,8 +108,6 @@ void CallbackManager::Init() m_cb_thread->WaitForAnySignal(); } }); - - cb_async_thread.detach(); } void CallbackManager::Clear() diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp index fe7c74d1a7..f1b9ef1f5e 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp @@ -224,7 +224,7 @@ u32 adecOpen(AudioDecoder* adec_ptr) adec.id = adec_id; adec.adecCb = (PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU); - adec.adecCb->SetName("Audio Decoder[" + std::to_string(adec_id) + "] Callback"); + adec.adecCb->SetName(fmt::format("AudioDecoder[%d] Callback", adec_id)); adec.adecCb->SetEntry(0); adec.adecCb->SetPrio(1001); adec.adecCb->SetStackSize(0x10000); @@ -232,11 +232,9 @@ u32 adecOpen(AudioDecoder* adec_ptr) adec.adecCb->InitRegs(); adec.adecCb->DoRun(); - thread t("Audio Decoder[" + std::to_string(adec_id) + "] Thread", [adec_ptr, sptr]() + thread_t t(fmt::format("AudioDecoder[%d] Thread", adec_id), [adec_ptr, sptr]() { AudioDecoder& adec = *adec_ptr; - cellAdec->Notice("Audio Decoder thread started"); - AdecTask& task = adec.task; while (true) @@ -471,18 +469,15 @@ u32 adecOpen(AudioDecoder* adec_ptr) default: { - ADEC_ERROR("Audio Decoder thread error: unknown task(%d)", task.type); + ADEC_ERROR("AudioDecoder thread error: unknown task(%d)", task.type); } } } adec.is_finished = true; - if (adec.is_closed) cellAdec->Notice("Audio Decoder thread ended"); - if (Emu.IsStopped()) cellAdec->Warning("Audio Decoder thread aborted"); + if (Emu.IsStopped()) cellAdec->Warning("AudioDecoder thread aborted"); }); - t.detach(); - return adec_id; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp index 6ebbce0d14..db77b18b28 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp @@ -11,461 +11,401 @@ #include "Emu/Event.h" #include "Emu/Audio/AudioManager.h" #include "Emu/Audio/AudioDumper.h" -#include "Emu/Audio/cellAudio.h" + +#include "cellAudio.h" Module *cellAudio = nullptr; -static std::mutex audioMutex; +AudioConfig g_audio; -AudioConfig m_config; - -static const bool g_is_u16 = Ini.AudioConvertToU16.GetValue(); - -// libaudio Functions - -#define BUFFER_NUM 32 -#define BUFFER_SIZE 256 int cellAudioInit() { cellAudio->Warning("cellAudioInit()"); - if (m_config.m_is_audio_initialized) + if (!g_audio.state.compare_and_swap_test(AUDIO_STATE_NOT_INITIALIZED, AUDIO_STATE_INITIALIZED)) { return CELL_AUDIO_ERROR_ALREADY_INIT; } - m_config.m_is_audio_initialized = true; - m_config.start_time = 0; - m_config.counter = 0; + for (auto& port : g_audio.ports) + { + port.state.write_relaxed(AUDIO_PORT_STATE_NOT_OPENED); + } - // alloc memory - m_config.m_buffer = (u32)Memory.Alloc(128 * 1024 * m_config.AUDIO_PORT_COUNT, 1024); - memset(vm::get_ptr(m_config.m_buffer), 0, 128 * 1024 * m_config.AUDIO_PORT_COUNT); - m_config.m_indexes = (u32)Memory.Alloc(sizeof(u64) * m_config.AUDIO_PORT_COUNT, 16); - memset(vm::get_ptr(m_config.m_indexes), 0, sizeof(u64) * m_config.AUDIO_PORT_COUNT); + g_audio.start_time = 0; + g_audio.counter = 0; + g_audio.keys.clear(); - thread t("Audio Thread", []() + // alloc memory (only once until the emulator is stopped) + g_audio.buffer = g_audio.buffer ? g_audio.buffer : vm::cast(Memory.MainMem.AllocAlign(128 * 1024 * AUDIO_PORT_COUNT, 4096)); + g_audio.indexes = g_audio.indexes ? g_audio.indexes : vm::cast(Memory.MainMem.AllocAlign(sizeof(u64) * AUDIO_PORT_COUNT, __alignof(u64))); + + // clear memory + memset(vm::get_ptr(g_audio.buffer), 0, 128 * 1024 * AUDIO_PORT_COUNT); + memset(vm::get_ptr(g_audio.indexes), 0, sizeof(u64) * AUDIO_PORT_COUNT); + + g_audio.audio_thread.start([]() + { + const bool do_dump = Ini.AudioDumpToFile.GetValue(); + + AudioDumper m_dump; + if (do_dump && !m_dump.Init(8)) // Init AudioDumper for 8 channels { - AudioDumper m_dump(8); // WAV file header (8 ch) + cellAudio->Error("AudioDumper::Init() failed"); + return; + } - bool do_dump = Ini.AudioDumpToFile.GetValue(); - - if (do_dump && !m_dump.Init()) - { - cellAudio->Error("cellAudioInit(): AudioDumper::Init() failed"); - return; - } + float buf2ch[2 * BUFFER_SIZE]; // intermediate buffer for 2 channels + float buf8ch[8 * BUFFER_SIZE]; // intermediate buffer for 8 channels - cellAudio->Notice("Audio thread started"); + static const size_t out_buffer_size = 2 * BUFFER_SIZE; - if (Ini.AudioDumpToFile.GetValue()) - m_dump.WriteHeader(); + std::unique_ptr out_buffer[BUFFER_NUM]; - float buf2ch[2 * BUFFER_SIZE]; // intermediate buffer for 2 channels - float buf8ch[8 * BUFFER_SIZE]; // intermediate buffer for 8 channels + for (u32 i = 0; i < BUFFER_NUM; i++) + { + out_buffer[i].reset(new float[2 * BUFFER_SIZE] {}); + } - uint oal_buffer_offset = 0; - const uint oal_buffer_size = 2 * BUFFER_SIZE; + squeue_t out_queue; - std::unique_ptr oal_buffer[BUFFER_NUM]; - std::unique_ptr oal_buffer_float[BUFFER_NUM]; + std::vector keys; - for (u32 i = 0; i < BUFFER_NUM; i++) - { - oal_buffer[i] = std::unique_ptr(new s16[oal_buffer_size] {} ); - oal_buffer_float[i] = std::unique_ptr(new float[oal_buffer_size] {} ); - } + g_audio.start_time = get_system_time(); - squeue_t queue; - squeue_t queue_float; - - std::vector keys; + thread_t iat("Internal Audio Thread", [&out_queue]() + { + const bool use_u16 = Ini.AudioConvertToU16.GetValue(); Emu.GetAudioManager().GetAudioOut().Init(); - // Note: What if the ini value changes? - if (g_is_u16) - Emu.GetAudioManager().GetAudioOut().Open(oal_buffer[0].get(), oal_buffer_size * sizeof(s16)); - else - Emu.GetAudioManager().GetAudioOut().Open(oal_buffer_float[0].get(), oal_buffer_size * sizeof(float)); - + bool opened = false; - m_config.start_time = get_system_time(); - - volatile bool internal_finished = false; - - thread iat("Internal Audio Thread", [oal_buffer_size, &queue, &queue_float, &internal_finished]() + while (g_audio.state.read_relaxed() == AUDIO_STATE_INITIALIZED && !Emu.IsStopped()) { - while (true) + float* buffer; + if (out_queue.pop(buffer)) { - s16* oal_buffer = nullptr; - float* oal_buffer_float = nullptr; - - if (g_is_u16) - queue.pop(oal_buffer); - else - queue_float.pop(oal_buffer_float); - - if (g_is_u16) + if (use_u16) { - if (oal_buffer) - { - Emu.GetAudioManager().GetAudioOut().AddData(oal_buffer, oal_buffer_size * sizeof(s16)); - continue; - } - } - else - { - if (oal_buffer_float) - { - Emu.GetAudioManager().GetAudioOut().AddData(oal_buffer_float, oal_buffer_size * sizeof(float)); - continue; - } - } - internal_finished = true; - return; - } - }); - iat.detach(); + // convert the data from float to u16 with clipping: + // 2x MULPS + // 2x MAXPS (optional) + // 2x MINPS (optional) + // 2x CVTPS2DQ (converts float to s32) + // PACKSSDW (converts s32 to s16 with signed saturation) - while (m_config.m_is_audio_initialized) - { - if (Emu.IsStopped()) - { - cellAudio->Warning("Audio thread aborted"); - goto abort; - } - - const u64 stamp0 = get_system_time(); - - // TODO: send beforemix event (in ~2,6 ms before mixing) - - // precise time of sleeping: 5,(3) ms (or 256/48000 sec) - if (m_config.counter * 256000000 / 48000 >= stamp0 - m_config.start_time) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - continue; - } - - m_config.counter++; - - const u32 oal_pos = m_config.counter % BUFFER_NUM; - - if (Emu.IsPaused()) - { - continue; - } - - bool first_mix = true; - - // mixing: - for (u32 i = 0; i < m_config.AUDIO_PORT_COUNT; i++) - { - if (!m_config.m_ports[i].m_is_audio_port_started) continue; - - AudioPortConfig& port = m_config.m_ports[i]; - - const u32 block_size = port.channel * 256; - const u32 position = port.tag % port.block; // old value - const u32 buf_addr = m_config.m_buffer + (i * 128 * 1024) + (position * block_size * sizeof(float)); - - auto buf = vm::get_ptr>(buf_addr); - - static const float k = 1.0f; // may be 1.0f - const float m = port.level; - - if (port.channel == 2) - { - if (first_mix) - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) - { - // reverse byte order - const float left = buf[i + 0] * m; - const float right = buf[i + 1] * m; - - buf2ch[i + 0] = left; - buf2ch[i + 1] = right; - - buf8ch[i * 4 + 0] = left; - buf8ch[i * 4 + 1] = right; - buf8ch[i * 4 + 2] = 0.0f; - buf8ch[i * 4 + 3] = 0.0f; - buf8ch[i * 4 + 4] = 0.0f; - buf8ch[i * 4 + 5] = 0.0f; - buf8ch[i * 4 + 6] = 0.0f; - buf8ch[i * 4 + 7] = 0.0f; - } - first_mix = false; - } - else - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) - { - const float left = buf[i + 0] * m; - const float right = buf[i + 1] * m; - - buf2ch[i + 0] += left; - buf2ch[i + 1] += right; - - buf8ch[i * 4 + 0] += left; - buf8ch[i * 4 + 1] += right; - } - } - } - else if (port.channel == 6) - { - if (first_mix) - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) - { - const float left = buf[i * 3 + 0] * m; - const float right = buf[i * 3 + 1] * m; - const float center = buf[i * 3 + 2] * m; - const float low_freq = buf[i * 3 + 3] * m; - const float rear_left = buf[i * 3 + 4] * m; - const float rear_right = buf[i * 3 + 5] * m; - - const float mid = (center + low_freq) * 0.708f; - buf2ch[i + 0] = (left + rear_left + mid) * k; - buf2ch[i + 1] = (right + rear_right + mid) * k; - - buf8ch[i * 4 + 0] = left; - buf8ch[i * 4 + 1] = right; - buf8ch[i * 4 + 2] = center; - buf8ch[i * 4 + 3] = low_freq; - buf8ch[i * 4 + 4] = rear_left; - buf8ch[i * 4 + 5] = rear_right; - buf8ch[i * 4 + 6] = 0.0f; - buf8ch[i * 4 + 7] = 0.0f; - } - first_mix = false; - } - else - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) - { - const float left = buf[i * 3 + 0] * m; - const float right = buf[i * 3 + 1] * m; - const float center = buf[i * 3 + 2] * m; - const float low_freq = buf[i * 3 + 3] * m; - const float rear_left = buf[i * 3 + 4] * m; - const float rear_right = buf[i * 3 + 5] * m; - - const float mid = (center + low_freq) * 0.708f; - buf2ch[i + 0] += (left + rear_left + mid) * k; - buf2ch[i + 1] += (right + rear_right + mid) * k; - - buf8ch[i * 4 + 0] += left; - buf8ch[i * 4 + 1] += right; - buf8ch[i * 4 + 2] += center; - buf8ch[i * 4 + 3] += low_freq; - buf8ch[i * 4 + 4] += rear_left; - buf8ch[i * 4 + 5] += rear_right; - } - } - } - else if (port.channel == 8) - { - if (first_mix) - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) - { - const float left = buf[i * 4 + 0] * m; - const float right = buf[i * 4 + 1] * m; - const float center = buf[i * 4 + 2] * m; - const float low_freq = buf[i * 4 + 3] * m; - const float rear_left = buf[i * 4 + 4] * m; - const float rear_right = buf[i * 4 + 5] * m; - const float side_left = buf[i * 4 + 6] * m; - const float side_right = buf[i * 4 + 7] * m; - - const float mid = (center + low_freq) * 0.708f; - buf2ch[i + 0] = (left + rear_left + side_left + mid) * k; - buf2ch[i + 1] = (right + rear_right + side_right + mid) * k; - - buf8ch[i * 4 + 0] = left; - buf8ch[i * 4 + 1] = right; - buf8ch[i * 4 + 2] = center; - buf8ch[i * 4 + 3] = low_freq; - buf8ch[i * 4 + 4] = rear_left; - buf8ch[i * 4 + 5] = rear_right; - buf8ch[i * 4 + 6] = side_left; - buf8ch[i * 4 + 7] = side_right; - } - first_mix = false; - } - else - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) - { - const float left = buf[i * 4 + 0] * m; - const float right = buf[i * 4 + 1] * m; - const float center = buf[i * 4 + 2] * m; - const float low_freq = buf[i * 4 + 3] * m; - const float rear_left = buf[i * 4 + 4] * m; - const float rear_right = buf[i * 4 + 5] * m; - const float side_left = buf[i * 4 + 6] * m; - const float side_right = buf[i * 4 + 7] * m; - - const float mid = (center + low_freq) * 0.708f; - buf2ch[i + 0] += (left + rear_left + side_left + mid) * k; - buf2ch[i + 1] += (right + rear_right + side_right + mid) * k; - - buf8ch[i * 4 + 0] += left; - buf8ch[i * 4 + 1] += right; - buf8ch[i * 4 + 2] += center; - buf8ch[i * 4 + 3] += low_freq; - buf8ch[i * 4 + 4] += rear_left; - buf8ch[i * 4 + 5] += rear_right; - buf8ch[i * 4 + 6] += side_left; - buf8ch[i * 4 + 7] += side_right; - } - } - } - - memset(buf, 0, block_size * sizeof(float)); - } - - // convert the data from float to u16 with clipping: - if (!first_mix) - { - // 2x MULPS - // 2x MAXPS (optional) - // 2x MINPS (optional) - // 2x CVTPS2DQ (converts float to s32) - // PACKSSDW (converts s32 to s16 with signed saturation) - - if (g_is_u16) - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 8) + u16 buf_u16[out_buffer_size]; + for (size_t i = 0; i < out_buffer_size; i += 8) { static const __m128 float2u16 = { 0x8000, 0x8000, 0x8000, 0x8000 }; - (__m128i&)(oal_buffer[oal_pos][oal_buffer_offset + i]) = _mm_packs_epi32( - _mm_cvtps_epi32(_mm_mul_ps((__m128&)(buf2ch[i]), float2u16)), - _mm_cvtps_epi32(_mm_mul_ps((__m128&)(buf2ch[i + 4]), float2u16))); + (__m128i&)(buf_u16[i]) = _mm_packs_epi32( + _mm_cvtps_epi32(_mm_mul_ps((__m128&)(buffer[i]), float2u16)), + _mm_cvtps_epi32(_mm_mul_ps((__m128&)(buffer[i + 4]), float2u16))); } - } - else - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i++) - { - oal_buffer_float[oal_pos][oal_buffer_offset + i] = buf2ch[i]; - } - } - //const u64 stamp1 = get_system_time(); - - if (first_mix) - { - if (g_is_u16) memset(&oal_buffer[oal_pos][0], 0, oal_buffer_size * sizeof(s16)); - else memset(&oal_buffer_float[oal_pos][0], 0, oal_buffer_size * sizeof(float)); - } - oal_buffer_offset += sizeof(buf2ch) / sizeof(float); - - if(oal_buffer_offset >= oal_buffer_size) - { - if (g_is_u16) - queue.push(&oal_buffer[oal_pos][0]); - - queue_float.push(&oal_buffer_float[oal_pos][0]); - oal_buffer_offset = 0; - } - - //const u64 stamp2 = get_system_time(); - - // send aftermix event (normal audio event) - { - std::lock_guard lock(audioMutex); - // update indexes: - auto indexes = vm::ptr::make(m_config.m_indexes); - for (u32 i = 0; i < m_config.AUDIO_PORT_COUNT; i++) - { - if (!m_config.m_ports[i].m_is_audio_port_started) continue; - - AudioPortConfig& port = m_config.m_ports[i]; - - u32 position = port.tag % port.block; // old value - port.counter = m_config.counter; - port.tag++; // absolute index of block that will be read - indexes[i] = (position + 1) % port.block; // write new value - } - // load keys: - keys.resize(m_config.m_keys.size()); - memcpy(keys.data(), m_config.m_keys.data(), sizeof(u64) * keys.size()); - } - for (u32 i = 0; i < keys.size(); i++) - { - // TODO: check event source - Emu.GetEventManager().SendEvent(keys[i], 0x10103000e010e07, 0, 0, 0); - } - - //const u64 stamp3 = get_system_time(); - - if (do_dump && !first_mix) - { - if (m_dump.GetCh() == 8) - { - if (m_dump.WriteData(&buf8ch, sizeof(buf8ch)) != sizeof(buf8ch)) // write file data + if (!opened) { - cellAudio->Error("cellAudioInit(): AudioDumper::WriteData() failed"); - goto abort; + Emu.GetAudioManager().GetAudioOut().Open(buf_u16, out_buffer_size * sizeof(u16)); + opened = true; } - } - else if (m_dump.GetCh() == 2) - { - if (m_dump.WriteData(&buf2ch, sizeof(buf2ch)) != sizeof(buf2ch)) // write file data + else { - cellAudio->Error("cellAudioInit(): AudioDumper::WriteData() failed"); - goto abort; + Emu.GetAudioManager().GetAudioOut().AddData(buf_u16, out_buffer_size * sizeof(u16)); } } else { - cellAudio->Error("cellAudioInit(): unknown AudioDumper::GetCh() value (%d)", m_dump.GetCh()); - goto abort; + if (!opened) + { + Emu.GetAudioManager().GetAudioOut().Open(buffer, out_buffer_size * sizeof(float)); + opened = true; + } + else + { + Emu.GetAudioManager().GetAudioOut().AddData(buffer, out_buffer_size * sizeof(float)); + } } } - - //LOG_NOTICE(HLE, "Audio perf: start=%d (access=%d, AddData=%d, events=%d, dump=%d)", - //stamp0 - m_config.start_time, stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3); - } - cellAudio->Notice("Audio thread ended"); -abort: - queue.push(nullptr); - queue_float.push(nullptr); - - if(do_dump) - m_dump.Finalize(); - - m_config.m_is_audio_initialized = false; - - m_config.m_keys.clear(); - for (u32 i = 0; i < m_config.AUDIO_PORT_COUNT; i++) - { - AudioPortConfig& port = m_config.m_ports[i]; - port.m_is_audio_port_opened = false; - port.m_is_audio_port_started = false; - } - m_config.m_port_in_use = 0; - - while (!internal_finished) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + else + { + break; + } } - m_config.m_is_audio_finalized = true; + Emu.GetAudioManager().GetAudioOut().Quit(); }); - t.detach(); - while (!m_config.start_time) // waiting for initialization - { - if (Emu.IsStopped()) + while (g_audio.state.read_relaxed() == AUDIO_STATE_INITIALIZED && !Emu.IsStopped()) { - cellAudio->Warning("cellAudioInit() aborted"); - return CELL_OK; + const u64 stamp0 = get_system_time(); + + // TODO: send beforemix event (in ~2,6 ms before mixing) + + // precise time of sleeping: 5,(3) ms (or 256/48000 sec) + if (g_audio.counter * 256000000 / 48000 >= stamp0 - g_audio.start_time) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + continue; + } + + g_audio.counter++; + + const u32 out_pos = g_audio.counter % BUFFER_NUM; + + if (Emu.IsPaused()) + { + continue; + } + + bool first_mix = true; + + // mixing: + for (auto& port : g_audio.ports) + { + if (port.state.read_relaxed() != AUDIO_PORT_STATE_STARTED) continue; + + const u32 block_size = port.channel * 256; + const u32 position = port.tag % port.block; // old value + const u32 buf_addr = port.addr + position * block_size * sizeof(float); + + auto buf = vm::get_ptr>(buf_addr); + + static const float k = 1.0f; // may be 1.0f + const float m = port.level; + + if (port.channel == 2) + { + if (first_mix) + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) + { + // reverse byte order + const float left = buf[i + 0] * m; + const float right = buf[i + 1] * m; + + buf2ch[i + 0] = left; + buf2ch[i + 1] = right; + + buf8ch[i * 4 + 0] = left; + buf8ch[i * 4 + 1] = right; + buf8ch[i * 4 + 2] = 0.0f; + buf8ch[i * 4 + 3] = 0.0f; + buf8ch[i * 4 + 4] = 0.0f; + buf8ch[i * 4 + 5] = 0.0f; + buf8ch[i * 4 + 6] = 0.0f; + buf8ch[i * 4 + 7] = 0.0f; + } + first_mix = false; + } + else + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) + { + const float left = buf[i + 0] * m; + const float right = buf[i + 1] * m; + + buf2ch[i + 0] += left; + buf2ch[i + 1] += right; + + buf8ch[i * 4 + 0] += left; + buf8ch[i * 4 + 1] += right; + } + } + } + else if (port.channel == 6) + { + if (first_mix) + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) + { + const float left = buf[i * 3 + 0] * m; + const float right = buf[i * 3 + 1] * m; + const float center = buf[i * 3 + 2] * m; + const float low_freq = buf[i * 3 + 3] * m; + const float rear_left = buf[i * 3 + 4] * m; + const float rear_right = buf[i * 3 + 5] * m; + + const float mid = (center + low_freq) * 0.708f; + buf2ch[i + 0] = (left + rear_left + mid) * k; + buf2ch[i + 1] = (right + rear_right + mid) * k; + + buf8ch[i * 4 + 0] = left; + buf8ch[i * 4 + 1] = right; + buf8ch[i * 4 + 2] = center; + buf8ch[i * 4 + 3] = low_freq; + buf8ch[i * 4 + 4] = rear_left; + buf8ch[i * 4 + 5] = rear_right; + buf8ch[i * 4 + 6] = 0.0f; + buf8ch[i * 4 + 7] = 0.0f; + } + first_mix = false; + } + else + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) + { + const float left = buf[i * 3 + 0] * m; + const float right = buf[i * 3 + 1] * m; + const float center = buf[i * 3 + 2] * m; + const float low_freq = buf[i * 3 + 3] * m; + const float rear_left = buf[i * 3 + 4] * m; + const float rear_right = buf[i * 3 + 5] * m; + + const float mid = (center + low_freq) * 0.708f; + buf2ch[i + 0] += (left + rear_left + mid) * k; + buf2ch[i + 1] += (right + rear_right + mid) * k; + + buf8ch[i * 4 + 0] += left; + buf8ch[i * 4 + 1] += right; + buf8ch[i * 4 + 2] += center; + buf8ch[i * 4 + 3] += low_freq; + buf8ch[i * 4 + 4] += rear_left; + buf8ch[i * 4 + 5] += rear_right; + } + } + } + else if (port.channel == 8) + { + if (first_mix) + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) + { + const float left = buf[i * 4 + 0] * m; + const float right = buf[i * 4 + 1] * m; + const float center = buf[i * 4 + 2] * m; + const float low_freq = buf[i * 4 + 3] * m; + const float rear_left = buf[i * 4 + 4] * m; + const float rear_right = buf[i * 4 + 5] * m; + const float side_left = buf[i * 4 + 6] * m; + const float side_right = buf[i * 4 + 7] * m; + + const float mid = (center + low_freq) * 0.708f; + buf2ch[i + 0] = (left + rear_left + side_left + mid) * k; + buf2ch[i + 1] = (right + rear_right + side_right + mid) * k; + + buf8ch[i * 4 + 0] = left; + buf8ch[i * 4 + 1] = right; + buf8ch[i * 4 + 2] = center; + buf8ch[i * 4 + 3] = low_freq; + buf8ch[i * 4 + 4] = rear_left; + buf8ch[i * 4 + 5] = rear_right; + buf8ch[i * 4 + 6] = side_left; + buf8ch[i * 4 + 7] = side_right; + } + first_mix = false; + } + else + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) + { + const float left = buf[i * 4 + 0] * m; + const float right = buf[i * 4 + 1] * m; + const float center = buf[i * 4 + 2] * m; + const float low_freq = buf[i * 4 + 3] * m; + const float rear_left = buf[i * 4 + 4] * m; + const float rear_right = buf[i * 4 + 5] * m; + const float side_left = buf[i * 4 + 6] * m; + const float side_right = buf[i * 4 + 7] * m; + + const float mid = (center + low_freq) * 0.708f; + buf2ch[i + 0] += (left + rear_left + side_left + mid) * k; + buf2ch[i + 1] += (right + rear_right + side_right + mid) * k; + + buf8ch[i * 4 + 0] += left; + buf8ch[i * 4 + 1] += right; + buf8ch[i * 4 + 2] += center; + buf8ch[i * 4 + 3] += low_freq; + buf8ch[i * 4 + 4] += rear_left; + buf8ch[i * 4 + 5] += rear_right; + buf8ch[i * 4 + 6] += side_left; + buf8ch[i * 4 + 7] += side_right; + } + } + } + + memset(buf, 0, block_size * sizeof(float)); + } + + + if (!first_mix) + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i++) + { + out_buffer[out_pos][i] = buf2ch[i]; + } + } + + //const u64 stamp1 = get_system_time(); + + if (first_mix) + { + memset(out_buffer[out_pos].get(), 0, out_buffer_size * sizeof(float)); + } + + out_queue.push(out_buffer[out_pos].get()); + + //const u64 stamp2 = get_system_time(); + + // send aftermix event (normal audio event) + { + std::lock_guard lock(g_audio.mutex); + // update indexes: + auto indexes = vm::ptr::make(g_audio.indexes); + for (u32 i = 0; i < AUDIO_PORT_COUNT; i++) + { + AudioPortConfig& port = g_audio.ports[i]; + + if (port.state.read_relaxed() != AUDIO_PORT_STATE_STARTED) continue; + + u32 position = port.tag % port.block; // old value + port.counter = g_audio.counter; + port.tag++; // absolute index of block that will be read + indexes[i] = (position + 1) % port.block; // write new value + } + // load keys: + keys.resize(g_audio.keys.size()); + memcpy(keys.data(), g_audio.keys.data(), sizeof(u64) * keys.size()); + } + for (u32 i = 0; i < keys.size(); i++) + { + // TODO: check event source + Emu.GetEventManager().SendEvent(keys[i], 0x10103000e010e07, 0, 0, 0); + } + + //const u64 stamp3 = get_system_time(); + + if (do_dump && !first_mix) + { + if (m_dump.GetCh() == 8) + { + if (m_dump.WriteData(&buf8ch, sizeof(buf8ch)) != sizeof(buf8ch)) // write file data + { + cellAudio->Error("AudioDumper::WriteData() failed"); + break; + } + } + else if (m_dump.GetCh() == 2) + { + if (m_dump.WriteData(&buf2ch, sizeof(buf2ch)) != sizeof(buf2ch)) // write file data + { + cellAudio->Error("AudioDumper::WriteData() failed"); + break; + } + } + else + { + cellAudio->Error("AudioDumper::GetCh() returned unknown value (%d)", m_dump.GetCh()); + break; + } + } + + //LOG_NOTICE(HLE, "Audio perf: start=%d (access=%d, AddData=%d, events=%d, dump=%d)", + //stamp0 - m_config.start_time, stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3); } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - } + + iat.join(); + }); return CELL_OK; } @@ -474,26 +414,13 @@ int cellAudioQuit() { cellAudio->Warning("cellAudioQuit()"); - if (!m_config.m_is_audio_initialized) + if (!g_audio.state.compare_and_swap_test(AUDIO_STATE_INITIALIZED, AUDIO_STATE_FINALIZED)) { return CELL_AUDIO_ERROR_NOT_INIT; } - m_config.m_is_audio_initialized = false; - - while (!m_config.m_is_audio_finalized) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - if (Emu.IsStopped()) - { - cellAudio->Warning("cellAudioQuit(): aborted"); - return CELL_OK; - } - } - - Memory.Free(m_config.m_buffer); - Memory.Free(m_config.m_indexes); - + g_audio.audio_thread.join(); + g_audio.state.exchange(AUDIO_STATE_NOT_INITIALIZED); return CELL_OK; } @@ -506,22 +433,17 @@ int cellAudioPortOpen(vm::ptr audioParam, vm::ptr portN return CELL_AUDIO_ERROR_PARAM; } - if (m_config.m_port_in_use >= m_config.AUDIO_PORT_COUNT) + for (u32 i = 0; i < AUDIO_PORT_COUNT; i++) { - return CELL_AUDIO_ERROR_PORT_FULL; - } - - for (u32 i = 0; i < m_config.AUDIO_PORT_COUNT; i++) - { - if (!m_config.m_ports[i].m_is_audio_port_opened) + if (g_audio.ports[i].state.compare_and_swap_test(AUDIO_PORT_STATE_NOT_OPENED, AUDIO_PORT_STATE_OPENED)) { - AudioPortConfig& port = m_config.m_ports[i]; - + AudioPortConfig& port = g_audio.ports[i]; + port.channel = (u8)audioParam->nChannel; port.block = (u8)audioParam->nBlock; port.attr = audioParam->attr; - port.addr = m_config.m_buffer + (128 * 1024 * i); - port.read_index_addr = m_config.m_indexes + (sizeof(u64) * i); + port.addr = g_audio.buffer + (128 * 1024 * i); + port.read_index_addr = g_audio.indexes + (sizeof(u64) * i); port.size = port.channel * port.block * 256 * sizeof(float); if (port.attr & CELL_AUDIO_PORTATTR_INITLEVEL) { @@ -535,12 +457,8 @@ int cellAudioPortOpen(vm::ptr audioParam, vm::ptr portN *portNum = i; cellAudio->Warning("*** audio port opened(nChannel=%d, nBlock=%d, attr=0x%llx, level=%f): port = %d", port.channel, port.block, port.attr, port.level, i); - - port.m_is_audio_port_opened = true; - port.m_is_audio_port_started = false; - port.tag = 0; - m_config.m_port_in_use++; + port.tag = 0; return CELL_OK; } } @@ -552,25 +470,20 @@ int cellAudioGetPortConfig(u32 portNum, vm::ptr portConfig) { cellAudio->Warning("cellAudioGetPortConfig(portNum=0x%x, portConfig_addr=0x%x)", portNum, portConfig.addr()); - if (portNum >= m_config.AUDIO_PORT_COUNT) + if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - if (!m_config.m_ports[portNum].m_is_audio_port_opened) + switch (auto state = g_audio.ports[portNum].state.read_sync()) { - portConfig->status = CELL_AUDIO_STATUS_CLOSE; - } - else if (m_config.m_ports[portNum].m_is_audio_port_started) - { - portConfig->status = CELL_AUDIO_STATUS_RUN; - } - else - { - portConfig->status = CELL_AUDIO_STATUS_READY; + case AUDIO_PORT_STATE_NOT_OPENED: portConfig->status = CELL_AUDIO_STATUS_CLOSE; break; + case AUDIO_PORT_STATE_OPENED: portConfig->status = CELL_AUDIO_STATUS_READY; break; + case AUDIO_PORT_STATE_STARTED: portConfig->status = CELL_AUDIO_STATUS_RUN; break; + default: throw fmt::format("cellAudioGetPortConfig(%d): invalid port state (0x%x)", portNum, state); } - AudioPortConfig& port = m_config.m_ports[portNum]; + AudioPortConfig& port = g_audio.ports[portNum]; portConfig->nChannel = port.channel; portConfig->nBlock = port.block; @@ -589,93 +502,80 @@ int cellAudioPortStart(u32 portNum) { cellAudio->Warning("cellAudioPortStart(portNum=0x%x)", portNum); - if (portNum >= m_config.AUDIO_PORT_COUNT) + if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - if (!m_config.m_ports[portNum].m_is_audio_port_opened) + switch (auto state = g_audio.ports[portNum].state.compare_and_swap(AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_STARTED)) { - return CELL_AUDIO_ERROR_PORT_OPEN; + case AUDIO_PORT_STATE_NOT_OPENED: return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + case AUDIO_PORT_STATE_STARTED: return CELL_AUDIO_ERROR_PORT_ALREADY_RUN; + case AUDIO_PORT_STATE_OPENED: return CELL_OK; + default: throw fmt::format("cellAudioPortStart(%d): invalid port state (0x%x)", portNum, state); } - - if (m_config.m_ports[portNum].m_is_audio_port_started) - { - return CELL_AUDIO_ERROR_PORT_ALREADY_RUN; - } - - m_config.m_ports[portNum].m_is_audio_port_started = true; - - return CELL_OK; } int cellAudioPortClose(u32 portNum) { cellAudio->Warning("cellAudioPortClose(portNum=0x%x)", portNum); - if (portNum >= m_config.AUDIO_PORT_COUNT) + if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - if (!m_config.m_ports[portNum].m_is_audio_port_opened) + switch (auto state = g_audio.ports[portNum].state.exchange(AUDIO_PORT_STATE_NOT_OPENED)) { - return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + case AUDIO_PORT_STATE_NOT_OPENED: return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + case AUDIO_PORT_STATE_STARTED: return CELL_OK; + case AUDIO_PORT_STATE_OPENED: return CELL_OK; + default: throw fmt::format("cellAudioPortClose(%d): invalid port state (0x%x)", portNum, state); } - - m_config.m_ports[portNum].m_is_audio_port_started = false; - m_config.m_ports[portNum].m_is_audio_port_opened = false; - m_config.m_port_in_use--; - return CELL_OK; } int cellAudioPortStop(u32 portNum) { - cellAudio->Warning("cellAudioPortStop(portNum=0x%x)",portNum); - - if (portNum >= m_config.AUDIO_PORT_COUNT) + cellAudio->Warning("cellAudioPortStop(portNum=0x%x)", portNum); + + if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - if (!m_config.m_ports[portNum].m_is_audio_port_opened) + switch (auto state = g_audio.ports[portNum].state.compare_and_swap(AUDIO_PORT_STATE_STARTED, AUDIO_PORT_STATE_OPENED)) { - return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + case AUDIO_PORT_STATE_NOT_OPENED: return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + case AUDIO_PORT_STATE_STARTED: return CELL_OK; + case AUDIO_PORT_STATE_OPENED: return CELL_AUDIO_ERROR_PORT_OPEN; + default: throw fmt::format("cellAudioPortStop(%d): invalid port state (0x%x)", portNum, state); } - - if (!m_config.m_ports[portNum].m_is_audio_port_started) - { - return CELL_AUDIO_ERROR_PORT_NOT_RUN; - } - - m_config.m_ports[portNum].m_is_audio_port_started = false; - return CELL_OK; } int cellAudioGetPortTimestamp(u32 portNum, u64 tag, vm::ptr stamp) { cellAudio->Log("cellAudioGetPortTimestamp(portNum=0x%x, tag=0x%llx, stamp_addr=0x%x)", portNum, tag, stamp.addr()); - if (portNum >= m_config.AUDIO_PORT_COUNT) + if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - if (!m_config.m_ports[portNum].m_is_audio_port_opened) - { - return CELL_AUDIO_ERROR_PORT_NOT_OPEN; - } + //if (!g_audio.ports[portNum].is_audio_port_opened) + //{ + // return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + //} - if (!m_config.m_ports[portNum].m_is_audio_port_started) - { - return CELL_AUDIO_ERROR_PORT_NOT_RUN; - } + //if (!g_audio.ports[portNum].is_audio_port_started) + //{ + // return CELL_AUDIO_ERROR_PORT_NOT_RUN; + //} - AudioPortConfig& port = m_config.m_ports[portNum]; + AudioPortConfig& port = g_audio.ports[portNum]; - std::lock_guard lock(audioMutex); + std::lock_guard lock(g_audio.mutex); - *stamp = m_config.start_time + (port.counter + (tag - port.tag)) * 256000000 / 48000; + *stamp = g_audio.start_time + (port.counter + (tag - port.tag)) * 256000000 / 48000; return CELL_OK; } @@ -684,22 +584,22 @@ int cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, vm::ptr tag) { cellAudio->Log("cellAudioGetPortBlockTag(portNum=0x%x, blockNo=0x%llx, tag_addr=0x%x)", portNum, blockNo, tag.addr()); - if (portNum >= m_config.AUDIO_PORT_COUNT) + if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - if (!m_config.m_ports[portNum].m_is_audio_port_opened) - { - return CELL_AUDIO_ERROR_PORT_NOT_OPEN; - } + //if (!g_audio.ports[portNum].is_audio_port_opened) + //{ + // return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + //} - if (!m_config.m_ports[portNum].m_is_audio_port_started) - { - return CELL_AUDIO_ERROR_PORT_NOT_RUN; - } + //if (!g_audio.ports[portNum].is_audio_port_started) + //{ + // return CELL_AUDIO_ERROR_PORT_NOT_RUN; + //} - AudioPortConfig& port = m_config.m_ports[portNum]; + AudioPortConfig& port = g_audio.ports[portNum]; if (blockNo >= port.block) { @@ -707,17 +607,17 @@ int cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, vm::ptr tag) return CELL_AUDIO_ERROR_PARAM; } - std::lock_guard lock(audioMutex); + std::lock_guard lock(g_audio.mutex); u64 tag_base = port.tag; if (tag_base % port.block > blockNo) { - tag_base &= ~(port.block-1); + tag_base &= ~(port.block - 1); tag_base += port.block; } else { - tag_base &= ~(port.block-1); + tag_base &= ~(port.block - 1); } *tag = tag_base + blockNo; @@ -728,24 +628,24 @@ int cellAudioSetPortLevel(u32 portNum, float level) { cellAudio->Todo("cellAudioSetPortLevel(portNum=0x%x, level=%f)", portNum, level); - AudioPortConfig& port = m_config.m_ports[portNum]; - - if (portNum >= m_config.AUDIO_PORT_COUNT) + if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - if (!port.m_is_audio_port_opened) - { - return CELL_AUDIO_ERROR_PORT_NOT_OPEN; - } + AudioPortConfig& port = g_audio.ports[portNum]; - if (!port.m_is_audio_port_started) - { - return CELL_AUDIO_ERROR_PORT_NOT_RUN; - } + //if (!port.is_audio_port_opened) + //{ + // return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + //} - std::lock_guard lock(audioMutex); + //if (!port.is_audio_port_started) + //{ + // return CELL_AUDIO_ERROR_PORT_NOT_RUN; + //} + + std::lock_guard lock(g_audio.mutex); port.level = level; // TODO @@ -757,7 +657,7 @@ int cellAudioCreateNotifyEventQueue(vm::ptr id, vm::ptr key) { cellAudio->Warning("cellAudioCreateNotifyEventQueue(id_addr=0x%x, key_addr=0x%x)", id.addr(), key.addr()); - std::lock_guard lock(audioMutex); + std::lock_guard lock(g_audio.mutex); u64 event_key = 0; while (Emu.GetEventManager().CheckKey((event_key << 48) | 0x80004d494f323221)) @@ -790,21 +690,21 @@ int cellAudioSetNotifyEventQueue(u64 key) { cellAudio->Warning("cellAudioSetNotifyEventQueue(key=0x%llx)", key); - std::lock_guard lock(audioMutex); + std::lock_guard lock(g_audio.mutex); - for (u32 i = 0; i < m_config.m_keys.size(); i++) // check for duplicates + for (u32 i = 0; i < g_audio.keys.size(); i++) // check for duplicates { - if (m_config.m_keys[i] == key) + if (g_audio.keys[i] == key) { return CELL_AUDIO_ERROR_PARAM; } } - m_config.m_keys.push_back(key); + g_audio.keys.push_back(key); /*EventQueue* eq; if (!Emu.GetEventManager().GetEventQueue(key, eq)) { - return CELL_AUDIO_ERROR_PARAM; + return CELL_AUDIO_ERROR_PARAM; }*/ // TODO: connect port (?????) @@ -822,14 +722,14 @@ int cellAudioRemoveNotifyEventQueue(u64 key) { cellAudio->Warning("cellAudioRemoveNotifyEventQueue(key=0x%llx)", key); - std::lock_guard lock(audioMutex); + std::lock_guard lock(g_audio.mutex); bool found = false; - for (u32 i = 0; i < m_config.m_keys.size(); i++) + for (u32 i = 0; i < g_audio.keys.size(); i++) { - if (m_config.m_keys[i] == key) + if (g_audio.keys[i] == key) { - m_config.m_keys.erase(m_config.m_keys.begin() + i); + g_audio.keys.erase(g_audio.keys.begin() + i); found = true; break; } @@ -844,7 +744,7 @@ int cellAudioRemoveNotifyEventQueue(u64 key) /*EventQueue* eq; if (!Emu.GetEventManager().GetEventQueue(key, eq)) { - return CELL_AUDIO_ERROR_PARAM; + return CELL_AUDIO_ERROR_PARAM; }*/ // TODO: disconnect port @@ -860,14 +760,14 @@ int cellAudioRemoveNotifyEventQueueEx(u64 key, u32 iFlags) s32 cellAudioAddData(u32 portNum, vm::ptr src, u32 samples, float volume) { - cellAudio->Log("cellAudioAddData(portNum=%d, src_addr=0x%x, samples=%d, volume=%f)", portNum, src.addr(), samples, volume); - - if (!m_config.m_is_audio_initialized) + cellAudio->Log("cellAudioAddData(portNum=%d, src=0x%x, samples=%d, volume=%f)", portNum, src, samples, volume); + + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) { return CELL_AUDIO_ERROR_NOT_INIT; } - if (portNum >= m_config.AUDIO_PORT_COUNT || !src || src.addr() % 4) + if (portNum >= AUDIO_PORT_COUNT || !src || src.addr() % 4) { return CELL_AUDIO_ERROR_PARAM; } @@ -879,8 +779,8 @@ s32 cellAudioAddData(u32 portNum, vm::ptr src, u32 samples, float volume) return CELL_AUDIO_ERROR_PARAM; } - const AudioPortConfig& port = m_config.m_ports[portNum]; - + const AudioPortConfig& port = g_audio.ports[portNum]; + const auto dst = vm::ptr::make(port.addr + (port.tag % port.block) * port.channel * 256 * sizeof(float)); for (u32 i = 0; i < samples * port.channel; i++) @@ -893,19 +793,14 @@ s32 cellAudioAddData(u32 portNum, vm::ptr src, u32 samples, float volume) s32 cellAudioAdd2chData(u32 portNum, vm::ptr src, u32 samples, float volume) { - cellAudio->Log("cellAudioAdd2chData(portNum=%d, src_addr=0x%x, samples=%d, volume=%f)", portNum, src.addr(), samples, volume); + cellAudio->Log("cellAudioAdd2chData(portNum=%d, src=0x%x, samples=%d, volume=%f)", portNum, src, samples, volume); - if (!m_config.m_is_audio_initialized) + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) { return CELL_AUDIO_ERROR_NOT_INIT; } - if (portNum >= m_config.AUDIO_PORT_COUNT) - { - return CELL_AUDIO_ERROR_PARAM; - } - - if (portNum >= m_config.AUDIO_PORT_COUNT || !src || src.addr() % 4) + if (portNum >= AUDIO_PORT_COUNT || !src || src.addr() % 4) { return CELL_AUDIO_ERROR_PARAM; } @@ -917,7 +812,7 @@ s32 cellAudioAdd2chData(u32 portNum, vm::ptr src, u32 samples, float volu return CELL_AUDIO_ERROR_PARAM; } - const AudioPortConfig& port = m_config.m_ports[portNum]; + const AudioPortConfig& port = g_audio.ports[portNum]; const auto dst = vm::ptr::make(port.addr + (port.tag % port.block) * port.channel * 256 * sizeof(float)); @@ -961,24 +856,19 @@ s32 cellAudioAdd2chData(u32 portNum, vm::ptr src, u32 samples, float volu s32 cellAudioAdd6chData(u32 portNum, vm::ptr src, float volume) { - cellAudio->Log("cellAudioAdd6chData(portNum=%d, src_addr=0x%x, volume=%f)", portNum, src.addr(), volume); + cellAudio->Log("cellAudioAdd6chData(portNum=%d, src=0x%x, volume=%f)", portNum, src, volume); - if (!m_config.m_is_audio_initialized) + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) { return CELL_AUDIO_ERROR_NOT_INIT; } - if (portNum >= m_config.AUDIO_PORT_COUNT) + if (portNum >= AUDIO_PORT_COUNT || !src || src.addr() % 4) { return CELL_AUDIO_ERROR_PARAM; } - if (portNum >= m_config.AUDIO_PORT_COUNT || !src || src.addr() % 4) - { - return CELL_AUDIO_ERROR_PARAM; - } - - const AudioPortConfig& port = m_config.m_ports[portNum]; + const AudioPortConfig& port = g_audio.ports[portNum]; const auto dst = vm::ptr::make(port.addr + (port.tag % port.block) * port.channel * 256 * sizeof(float)); @@ -1004,7 +894,7 @@ s32 cellAudioAdd6chData(u32 portNum, vm::ptr src, float volume) { cellAudio->Error("cellAudioAdd6chData(portNum=%d): invalid port.channel value (%d)", portNum, port.channel); } - + return CELL_OK; } @@ -1036,6 +926,10 @@ void cellAudio_init(Module *pxThis) { cellAudio = pxThis; + g_audio.state.write_relaxed(AUDIO_STATE_NOT_INITIALIZED); + g_audio.buffer = 0; + g_audio.indexes = 0; + REG_FUNC(cellAudio, cellAudioInit); REG_FUNC(cellAudio, cellAudioPortClose); REG_FUNC(cellAudio, cellAudioPortStop); @@ -1060,3 +954,8 @@ void cellAudio_init(Module *pxThis) REG_FUNC(cellAudio, cellAudioSetPersonalDevice); REG_FUNC(cellAudio, cellAudioUnsetPersonalDevice); } + +void cellAudio_load() +{ + // never called :( +} diff --git a/rpcs3/Emu/Audio/cellAudio.h b/rpcs3/Emu/SysCalls/Modules/cellAudio.h similarity index 81% rename from rpcs3/Emu/Audio/cellAudio.h rename to rpcs3/Emu/SysCalls/Modules/cellAudio.h index b6cabcea59..83fd4fc097 100644 --- a/rpcs3/Emu/Audio/cellAudio.h +++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.h @@ -72,10 +72,32 @@ struct CellAudioPortConfig be_t portAddr; }; +enum : u32 +{ + BUFFER_NUM = 32, + BUFFER_SIZE = 256, + AUDIO_PORT_COUNT = 8, +}; + +enum AudioState : u32 +{ + AUDIO_STATE_NOT_INITIALIZED, + AUDIO_STATE_INITIALIZED, + AUDIO_STATE_FINALIZED, +}; + +enum AudioPortState : u32 +{ + AUDIO_PORT_STATE_NOT_OPENED, + AUDIO_PORT_STATE_OPENED, + AUDIO_PORT_STATE_STARTED, +}; + struct AudioPortConfig { - bool m_is_audio_port_opened; - bool m_is_audio_port_started; + std::mutex mutex; + atomic_le_t state; + u8 channel; u8 block; float level; @@ -89,34 +111,20 @@ struct AudioPortConfig struct AudioConfig //custom structure { - enum - { - AUDIO_PORT_COUNT = 8, - }; - AudioPortConfig m_ports[AUDIO_PORT_COUNT]; - u32 m_buffer; // 1 MB memory for audio ports - u32 m_indexes; // current block indexes and other info - bool m_is_audio_initialized; - bool m_is_audio_finalized; - u32 m_port_in_use; + std::mutex mutex; + atomic_le_t state; + thread_t audio_thread; + + AudioPortConfig ports[AUDIO_PORT_COUNT]; + u32 buffer; // 1 MB memory for audio ports + u32 indexes; // current block indexes and other info u64 counter; u64 start_time; - std::vector m_keys; + std::vector keys; - AudioConfig() - : m_is_audio_initialized(false) - , m_is_audio_finalized(false) - , m_port_in_use(0) - , counter(0) + AudioConfig() : audio_thread("Audio Thread") { - memset(&m_ports, 0, sizeof(AudioPortConfig) * AUDIO_PORT_COUNT); - } - - void Clear() - { - memset(&m_ports, 0, sizeof(AudioPortConfig) * AUDIO_PORT_COUNT); - m_port_in_use = 0; } }; -extern AudioConfig m_config; +extern AudioConfig g_audio; diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp index ff4cc079df..7670b22b4a 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp @@ -306,7 +306,7 @@ u32 dmuxOpen(Demuxer* dmux_ptr) dmux.id = dmux_id; dmux.dmuxCb = (PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU); - dmux.dmuxCb->SetName("Demuxer[" + std::to_string(dmux_id) + "] Callback"); + dmux.dmuxCb->SetName(fmt::format("Demuxer[%d] Callback", dmux_id)); dmux.dmuxCb->SetEntry(0); dmux.dmuxCb->SetPrio(1001); dmux.dmuxCb->SetStackSize(0x10000); @@ -314,10 +314,9 @@ u32 dmuxOpen(Demuxer* dmux_ptr) dmux.dmuxCb->InitRegs(); dmux.dmuxCb->DoRun(); - thread t("Demuxer[" + std::to_string(dmux_id) + "] Thread", [dmux_ptr, sptr]() + thread_t t(fmt::format("Demuxer[%d] Thread", dmux_id), [dmux_ptr, sptr]() { Demuxer& dmux = *dmux_ptr; - cellDmux->Notice("Demuxer thread started (mem=0x%x, size=0x%x, cb_addr=0x%x, arg=0x%x)", dmux.memAddr, dmux.memSize, dmux.cbFunc.addr(), dmux.cbArg); DemuxerTask task; DemuxerStream stream = {}; @@ -761,11 +760,8 @@ u32 dmuxOpen(Demuxer* dmux_ptr) dmux.is_finished = true; if (Emu.IsStopped()) cellDmux->Warning("Demuxer thread aborted"); - if (dmux.is_closed) cellDmux->Notice("Demuxer thread ended"); }); - t.detach(); - return dmux_id; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp b/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp index a652d134f9..64107c9461 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp @@ -123,7 +123,7 @@ s32 cellMsgDialogOpen2(u32 type, vm::ptr msgString, vm::ptr msgString, vm::ptrSetName("Video Decoder[" + std::to_string(vdec_id) + "] Callback"); + vdec.vdecCb->SetName(fmt::format("VideoDecoder[%d] Callback", vdec_id)); vdec.vdecCb->SetEntry(0); vdec.vdecCb->SetPrio(1001); vdec.vdecCb->SetStackSize(0x10000); @@ -222,11 +222,9 @@ u32 vdecOpen(VideoDecoder* vdec_ptr) vdec.vdecCb->InitRegs(); vdec.vdecCb->DoRun(); - thread t("Video Decoder[" + std::to_string(vdec_id) + "] Thread", [vdec_ptr, sptr]() + thread_t t(fmt::format("VideoDecoder[%d] Thread", vdec_id), [vdec_ptr, sptr]() { VideoDecoder& vdec = *vdec_ptr; - cellVdec->Notice("Video Decoder thread started"); - VdecTask& task = vdec.task; while (true) @@ -431,7 +429,15 @@ u32 vdecOpen(VideoDecoder* vdec_ptr) { if (vdec.last_pts == -1) { - vdec.last_pts = 0x8000; //av_frame_get_best_effort_timestamp(frame.data); + u64 ts = av_frame_get_best_effort_timestamp(frame.data); + if (ts != AV_NOPTS_VALUE) + { + vdec.last_pts = ts; + } + else + { + vdec.last_pts = 0; + } } else switch (vdec.frc_set) { @@ -539,18 +545,15 @@ u32 vdecOpen(VideoDecoder* vdec_ptr) default: { - VDEC_ERROR("Video Decoder thread error: unknown task(%d)", task.type); + VDEC_ERROR("VideoDecoder thread error: unknown task(%d)", task.type); } } } vdec.is_finished = true; - if (Emu.IsStopped()) cellVdec->Warning("Video Decoder thread aborted"); - if (vdec.is_closed) cellVdec->Notice("Video Decoder thread ended"); + if (Emu.IsStopped()) cellVdec->Warning("VideoDecoder thread aborted"); }); - t.detach(); - return vdec_id; } diff --git a/rpcs3/Emu/SysCalls/Modules/libmixer.cpp b/rpcs3/Emu/SysCalls/Modules/libmixer.cpp index a6859cf19b..9591474ec7 100644 --- a/rpcs3/Emu/SysCalls/Modules/libmixer.cpp +++ b/rpcs3/Emu/SysCalls/Modules/libmixer.cpp @@ -5,7 +5,7 @@ #include "Emu/SysCalls/CB_FUNC.h" #include "Emu/CPU/CPUThreadManager.h" -#include "Emu/Audio/cellAudio.h" +#include "cellAudio.h" #include "libmixer.h" Module *libmixer = nullptr; @@ -298,9 +298,9 @@ int cellSurMixerCreate(vm::ptr config) surMixer = *config; - AudioPortConfig& port = m_config.m_ports[SUR_PORT]; + AudioPortConfig& port = g_audio.ports[SUR_PORT]; - if (port.m_is_audio_port_opened) + if (!port.state.compare_and_swap_test(AUDIO_PORT_STATE_NOT_OPENED, AUDIO_PORT_STATE_OPENED)) { return CELL_LIBMIXER_ERROR_FULL; } @@ -309,22 +309,19 @@ int cellSurMixerCreate(vm::ptr config) port.block = 16; port.attr = 0; port.level = 1.0f; + port.tag = 0; libmixer->Warning("*** audio port opened(default)"); - port.m_is_audio_port_opened = true; - port.tag = 0; - m_config.m_port_in_use++; - - libmixer->Warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)", - (u32)surMixer.chStrips1, (u32)surMixer.chStrips2, (u32)surMixer.chStrips6, (u32)surMixer.chStrips8); - mixcount = 0; surMixerCb.set(0); - thread t("Surmixer Thread", []() + libmixer->Warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)", + (u32)surMixer.chStrips1, (u32)surMixer.chStrips2, (u32)surMixer.chStrips6, (u32)surMixer.chStrips8); + + thread_t t("Surmixer Thread", []() { - AudioPortConfig& port = m_config.m_ports[SUR_PORT]; + AudioPortConfig& port = g_audio.ports[SUR_PORT]; PPUThread& cb_thread = *(PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU); cb_thread.SetName("Surmixer Callback Thread"); @@ -335,7 +332,7 @@ int cellSurMixerCreate(vm::ptr config) cb_thread.InitRegs(); cb_thread.DoRun(); - while (port.m_is_audio_port_opened) + while (port.state.read_relaxed() != AUDIO_PORT_STATE_NOT_OPENED) { if (Emu.IsStopped()) { @@ -349,7 +346,7 @@ int cellSurMixerCreate(vm::ptr config) continue; } - if (port.m_is_audio_port_started) + if (port.state.read_relaxed() == AUDIO_PORT_STATE_STARTED) { //u64 stamp0 = get_system_time(); @@ -440,7 +437,7 @@ int cellSurMixerCreate(vm::ptr config) //u64 stamp2 = get_system_time(); - auto buf = vm::get_ptr>(m_config.m_buffer + (128 * 1024 * SUR_PORT) + (mixcount % port.block) * port.channel * 256 * sizeof(float)); + auto buf = vm::get_ptr>(g_audio.buffer + (128 * 1024 * SUR_PORT) + (mixcount % port.block) * port.channel * 256 * sizeof(float)); for (u32 i = 0; i < (sizeof(mixdata) / sizeof(float)); i++) { @@ -464,7 +461,6 @@ int cellSurMixerCreate(vm::ptr config) Emu.GetCPU().RemoveThread(cb_thread.GetId()); surMixerCb.set(0); }); - t.detach(); return CELL_OK; } @@ -515,13 +511,8 @@ int cellSurMixerStart() { libmixer->Warning("cellSurMixerStart()"); - AudioPortConfig& port = m_config.m_ports[SUR_PORT]; + g_audio.ports[SUR_PORT].state.compare_and_swap(AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_STARTED); - if (port.m_is_audio_port_opened) - { - port.m_is_audio_port_started = true; - } - return CELL_OK; } @@ -535,14 +526,7 @@ int cellSurMixerFinalize() { libmixer->Warning("cellSurMixerFinalize()"); - AudioPortConfig& port = m_config.m_ports[SUR_PORT]; - - if (port.m_is_audio_port_opened) - { - port.m_is_audio_port_started = false; - port.m_is_audio_port_opened = false; - m_config.m_port_in_use--; - } + g_audio.ports[SUR_PORT].state.compare_and_swap(AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_NOT_OPENED); return CELL_OK; } @@ -581,12 +565,7 @@ int cellSurMixerPause(u32 type) { libmixer->Warning("cellSurMixerPause(type=%d)", type); - AudioPortConfig& port = m_config.m_ports[SUR_PORT]; - - if (port.m_is_audio_port_opened) - { - port.m_is_audio_port_started = false; - } + g_audio.ports[SUR_PORT].state.compare_and_swap(AUDIO_PORT_STATE_STARTED, AUDIO_PORT_STATE_OPENED); return CELL_OK; } @@ -603,7 +582,7 @@ int cellSurMixerGetTimestamp(u64 tag, vm::ptr stamp) { libmixer->Log("cellSurMixerGetTimestamp(tag=0x%llx, stamp_addr=0x%x)", tag, stamp.addr()); - *stamp = m_config.start_time + (tag) * 256000000 / 48000; // ??? + *stamp = g_audio.start_time + (tag) * 256000000 / 48000; // ??? return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/cellFs.cpp b/rpcs3/Emu/SysCalls/lv2/cellFs.cpp index 3fb8bf1db7..4f83878a83 100644 --- a/rpcs3/Emu/SysCalls/lv2/cellFs.cpp +++ b/rpcs3/Emu/SysCalls/lv2/cellFs.cpp @@ -966,11 +966,7 @@ int cellFsAioRead(vm::ptr aio, vm::ptr id, vm::ptr + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 2f0baf5d6f..1ef837c8fd 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -1279,5 +1279,8 @@ Emu\Audio\XAudio2 + + Emu\SysCalls\Modules + \ No newline at end of file From 4dae27c1d41d91d655d4c1de69ae87ad1fc2711d Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Fri, 16 Jan 2015 20:09:53 +0300 Subject: [PATCH 3/7] squeue_t updated --- Utilities/Thread.cpp | 4 +- Utilities/Thread.h | 60 ++++++++++++++++------- rpcs3/Emu/Audio/AL/OpenALThread.h | 2 +- rpcs3/Emu/Audio/Null/NullAudioThread.h | 2 +- rpcs3/Emu/Audio/XAudio2/XAudio2Thread.cpp | 8 ++- rpcs3/Emu/SysCalls/Modules/cellAudio.cpp | 7 ++- 6 files changed, 58 insertions(+), 25 deletions(-) diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 2da136ede4..d7e30f9214 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -717,7 +717,7 @@ void waiter_map_t::notify(u64 signal_id) } } -bool squeue_test_exit(const volatile bool* do_exit) +bool squeue_test_exit() { - return Emu.IsStopped() || (do_exit && *do_exit); + return Emu.IsStopped(); } diff --git a/Utilities/Thread.h b/Utilities/Thread.h index 200b54b02d..a80097932b 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -162,7 +162,7 @@ public: void notify(u64 signal_id); }; -bool squeue_test_exit(const volatile bool* do_exit); +bool squeue_test_exit(); template class squeue_t @@ -213,7 +213,7 @@ public: return m_sync.read_relaxed().count == sq_size; } - bool push(const T& data, const volatile bool* do_exit = nullptr) + bool push(const T& data, const std::function& test_exit) { u32 pos = 0; @@ -236,7 +236,7 @@ public: return SQSVR_OK; })) { - if (res == SQSVR_FAILED && squeue_test_exit(do_exit)) + if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit())) { return false; } @@ -261,14 +261,22 @@ public: return true; } - bool try_push(const T& data) + bool push(const T& data, const volatile bool* do_exit) { - static const volatile bool no_wait = true; - - return push(data, &no_wait); + return push(data, [do_exit](){ return do_exit && *do_exit; }); } - bool pop(T& data, const volatile bool* do_exit = nullptr) + bool push(const T& data) + { + return push(data, [](){ return false; }); + } + + bool try_push(const T& data) + { + return push(data, [](){ return true; }); + } + + bool pop(T& data, const std::function& test_exit) { u32 pos = 0; @@ -291,7 +299,7 @@ public: return SQSVR_OK; })) { - if (res == SQSVR_FAILED && squeue_test_exit(do_exit)) + if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit())) { return false; } @@ -321,14 +329,22 @@ public: return true; } - bool try_pop(T& data) + bool pop(T& data, const volatile bool* do_exit) { - static const volatile bool no_wait = true; - - return pop(data, &no_wait); + return pop(data, [do_exit](){ return do_exit && *do_exit; }); } - bool peek(T& data, u32 start_pos = 0, const volatile bool* do_exit = nullptr) + bool pop(T& data) + { + return pop(data, [](){ return false; }); + } + + bool try_pop(T& data) + { + return pop(data, [](){ return true; }); + } + + bool peek(T& data, u32 start_pos, const std::function& test_exit) { assert(start_pos < sq_size); u32 pos = 0; @@ -352,7 +368,7 @@ public: return SQSVR_OK; })) { - if (res == SQSVR_FAILED && squeue_test_exit(do_exit)) + if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit())) { return false; } @@ -375,11 +391,19 @@ public: return true; } + bool peek(T& data, u32 start_pos, const volatile bool* do_exit) + { + return peek(data, start_pos, [do_exit](){ return do_exit && *do_exit; }); + } + + bool peek(T& data, u32 start_pos = 0) + { + return peek(data, start_pos, [](){ return false; }); + } + bool try_peek(T& data, u32 start_pos = 0) { - static const volatile bool no_wait = true; - - return peek(data, start_pos, &no_wait); + return peek(data, start_pos, [](){ return true; }); } class squeue_data_t diff --git a/rpcs3/Emu/Audio/AL/OpenALThread.h b/rpcs3/Emu/Audio/AL/OpenALThread.h index 4d8f72a821..a02a100435 100644 --- a/rpcs3/Emu/Audio/AL/OpenALThread.h +++ b/rpcs3/Emu/Audio/AL/OpenALThread.h @@ -24,4 +24,4 @@ public: virtual void Close(); virtual void Stop(); virtual void AddData(const void* src, int size); -}; \ No newline at end of file +}; diff --git a/rpcs3/Emu/Audio/Null/NullAudioThread.h b/rpcs3/Emu/Audio/Null/NullAudioThread.h index 15dd40e12c..46de961af2 100644 --- a/rpcs3/Emu/Audio/Null/NullAudioThread.h +++ b/rpcs3/Emu/Audio/Null/NullAudioThread.h @@ -15,4 +15,4 @@ public: virtual void Close() {} virtual void Stop() {} virtual void AddData(const void* src, int size) {} -}; \ No newline at end of file +}; diff --git a/rpcs3/Emu/Audio/XAudio2/XAudio2Thread.cpp b/rpcs3/Emu/Audio/XAudio2/XAudio2Thread.cpp index ba414bcddd..d5b5e2b5e9 100644 --- a/rpcs3/Emu/Audio/XAudio2/XAudio2Thread.cpp +++ b/rpcs3/Emu/Audio/XAudio2/XAudio2Thread.cpp @@ -15,6 +15,7 @@ void XAudio2Thread::Init() { HRESULT hr = S_OK; +#if (_WIN32_WINNT < 0x0602) hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); if (FAILED(hr)) { @@ -22,6 +23,7 @@ void XAudio2Thread::Init() Emu.Pause(); return; } +#endif hr = XAudio2Create(&m_xaudio2_instance, 0, XAUDIO2_DEFAULT_PROCESSOR); if (FAILED(hr)) @@ -50,6 +52,10 @@ void XAudio2Thread::Quit() m_xaudio2_instance->StopEngine(); m_xaudio2_instance->Release(); m_xaudio2_instance = nullptr; + +#if (_WIN32_WINNT < 0x0602) + CoUninitialize(); +#endif } void XAudio2Thread::Play() @@ -131,4 +137,4 @@ void XAudio2Thread::AddData(const void* src, int size) Emu.Pause(); } } -#endif \ No newline at end of file +#endif diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp index db77b18b28..815668386d 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp @@ -84,7 +84,7 @@ int cellAudioInit() while (g_audio.state.read_relaxed() == AUDIO_STATE_INITIALIZED && !Emu.IsStopped()) { float* buffer; - if (out_queue.pop(buffer)) + if (out_queue.pop(buffer, [](){ return g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED; })) { if (use_u16) { @@ -343,7 +343,10 @@ int cellAudioInit() memset(out_buffer[out_pos].get(), 0, out_buffer_size * sizeof(float)); } - out_queue.push(out_buffer[out_pos].get()); + if (!out_queue.push(out_buffer[out_pos].get(), [](){ return g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED; })) + { + break; + } //const u64 stamp2 = get_system_time(); From b897a5d20a1f4f924feb728cd951f02c94a726c2 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Sat, 17 Jan 2015 19:14:58 +0300 Subject: [PATCH 4/7] cellAudio, thread_t improvements, pause/resume callback --- Utilities/Thread.cpp | 34 +- Utilities/Thread.h | 31 +- rpcs3/Emu/SysCalls/Callback.cpp | 37 ++ rpcs3/Emu/SysCalls/Callback.h | 51 ++- rpcs3/Emu/SysCalls/Modules/cellAudio.cpp | 468 +++++++++++++---------- rpcs3/Emu/SysCalls/Modules/cellAudio.h | 25 +- rpcs3/Emu/SysCalls/Modules/libmixer.cpp | 69 ++-- rpcs3/Emu/SysCalls/Modules/libmixer.h | 13 +- rpcs3/Emu/SysCalls/lv2/sys_time.h | 5 +- rpcs3/Emu/System.cpp | 4 + 10 files changed, 478 insertions(+), 259 deletions(-) diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index d7e30f9214..01ff0787be 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -537,16 +537,32 @@ bool ThreadBase::TestDestroy() const return m_destroy; } -thread_t::thread_t(const std::string& name, std::function func) : m_name(name), m_state(TS_NON_EXISTENT) +thread_t::thread_t(const std::string& name, bool autojoin, std::function func) + : m_name(name) + , m_state(TS_NON_EXISTENT) + , m_autojoin(autojoin) { start(func); } -thread_t::thread_t(const std::string& name) : m_name(name), m_state(TS_NON_EXISTENT) +thread_t::thread_t(const std::string& name, std::function func) + : m_name(name) + , m_state(TS_NON_EXISTENT) + , m_autojoin(false) +{ + start(func); +} + +thread_t::thread_t(const std::string& name) + : m_name(name) + , m_state(TS_NON_EXISTENT) + , m_autojoin(false) { } -thread_t::thread_t() : m_state(TS_NON_EXISTENT) +thread_t::thread_t() + : m_state(TS_NON_EXISTENT) + , m_autojoin(false) { } @@ -559,7 +575,14 @@ thread_t::~thread_t() { if (m_state == TS_JOINABLE) { - m_thr.detach(); + if (m_autojoin) + { + m_thr.join(); + } + else + { + m_thr.detach(); + } } } @@ -717,6 +740,9 @@ void waiter_map_t::notify(u64 signal_id) } } +static const std::function SQUEUE_ALWAYS_EXIT = [](){ return true; }; +static const std::function SQUEUE_NEVER_EXIT = [](){ return false; }; + bool squeue_test_exit() { return Emu.IsStopped(); diff --git a/Utilities/Thread.h b/Utilities/Thread.h index a80097932b..4e51438636 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -65,8 +65,10 @@ class thread_t std::atomic m_state; std::string m_name; std::thread m_thr; + bool m_autojoin; public: + thread_t(const std::string& name, bool autojoin, std::function func); thread_t(const std::string& name, std::function func); thread_t(const std::string& name); thread_t(); @@ -162,6 +164,9 @@ public: void notify(u64 signal_id); }; +extern const std::function SQUEUE_ALWAYS_EXIT; +extern const std::function SQUEUE_NEVER_EXIT; + bool squeue_test_exit(); template @@ -266,14 +271,14 @@ public: return push(data, [do_exit](){ return do_exit && *do_exit; }); } - bool push(const T& data) + __forceinline bool push(const T& data) { - return push(data, [](){ return false; }); + return push(data, SQUEUE_NEVER_EXIT); } - bool try_push(const T& data) + __forceinline bool try_push(const T& data) { - return push(data, [](){ return true; }); + return push(data, SQUEUE_ALWAYS_EXIT); } bool pop(T& data, const std::function& test_exit) @@ -334,14 +339,14 @@ public: return pop(data, [do_exit](){ return do_exit && *do_exit; }); } - bool pop(T& data) + __forceinline bool pop(T& data) { - return pop(data, [](){ return false; }); + return pop(data, SQUEUE_NEVER_EXIT); } - bool try_pop(T& data) + __forceinline bool try_pop(T& data) { - return pop(data, [](){ return true; }); + return pop(data, SQUEUE_ALWAYS_EXIT); } bool peek(T& data, u32 start_pos, const std::function& test_exit) @@ -362,7 +367,7 @@ public: { return SQSVR_LOCKED; } - + sync.pop_lock = 1; pos = sync.position + start_pos; return SQSVR_OK; @@ -396,14 +401,14 @@ public: return peek(data, start_pos, [do_exit](){ return do_exit && *do_exit; }); } - bool peek(T& data, u32 start_pos = 0) + __forceinline bool peek(T& data, u32 start_pos = 0) { - return peek(data, start_pos, [](){ return false; }); + return peek(data, start_pos, SQUEUE_NEVER_EXIT); } - bool try_peek(T& data, u32 start_pos = 0) + __forceinline bool try_peek(T& data, u32 start_pos = 0) { - return peek(data, start_pos, [](){ return true; }); + return peek(data, start_pos, SQUEUE_ALWAYS_EXIT); } class squeue_data_t diff --git a/rpcs3/Emu/SysCalls/Callback.cpp b/rpcs3/Emu/SysCalls/Callback.cpp index c74fc84871..b0d10c5316 100644 --- a/rpcs3/Emu/SysCalls/Callback.cpp +++ b/rpcs3/Emu/SysCalls/Callback.cpp @@ -117,3 +117,40 @@ void CallbackManager::Clear() m_cb_list.clear(); m_async_list.clear(); } + +u64 CallbackManager::AddPauseCallback(const std::function& func) +{ + std::lock_guard lock(m_mutex); + + m_pause_cb_list.push_back({ func, next_tag }); + return next_tag++; +} + +void CallbackManager::RemovePauseCallback(const u64 tag) +{ + std::lock_guard lock(m_mutex); + + for (auto& data : m_pause_cb_list) + { + if (data.tag == tag) + { + m_pause_cb_list.erase(m_pause_cb_list.begin() + (&data - m_pause_cb_list.data())); + return; + } + } + + assert(!"CallbackManager()::RemovePauseCallback(): tag not found"); +} + +void CallbackManager::RunPauseCallbacks(const bool is_paused) +{ + std::lock_guard lock(m_mutex); + + for (auto& data : m_pause_cb_list) + { + if (data.cb) + { + data.cb(is_paused); + } + } +} diff --git a/rpcs3/Emu/SysCalls/Callback.h b/rpcs3/Emu/SysCalls/Callback.h index 7cb6b8699b..2e8c64cf92 100644 --- a/rpcs3/Emu/SysCalls/Callback.h +++ b/rpcs3/Emu/SysCalls/Callback.h @@ -3,21 +3,62 @@ class CPUThread; class PPUThread; +typedef void(PauseResumeCB)(bool is_paused); + class CallbackManager { - std::vector> m_cb_list; - std::vector> m_async_list; - CPUThread* m_cb_thread; std::mutex m_mutex; + std::vector> m_cb_list; + std::vector> m_async_list; + CPUThread* m_cb_thread; + + struct PauseResumeCBS + { + std::function cb; + u64 tag; + }; + + u64 next_tag; // not initialized, only increased + std::vector m_pause_cb_list; public: - void Register(const std::function& func); // register callback (called in Check() method) + void Register(const std::function& func); // register callback (called in Check() method) - void Async(const std::function& func); // register callback for callback thread (called immediately) + void Async(const std::function& func); // register callback for callback thread (called immediately) bool Check(CPUThread& CPU, s32& result); // call one callback registered by Register() method void Init(); void Clear(); + + u64 AddPauseCallback(const std::function& func); // register callback for pausing/resuming emulation events + void RemovePauseCallback(const u64 tag); // unregister callback (uses the result of AddPauseCallback() function) + void RunPauseCallbacks(const bool is_paused); +}; + +class PauseCallbackRegisterer +{ + CallbackManager& cb_manager; + u64 cb_tag; + +public: + PauseCallbackRegisterer(CallbackManager& cb_manager, const std::function& func) + : cb_manager(cb_manager) + , cb_tag(cb_manager.AddPauseCallback(func)) + { + } + + PauseCallbackRegisterer() = delete; + PauseCallbackRegisterer(const PauseCallbackRegisterer& right) = delete; + PauseCallbackRegisterer(PauseCallbackRegisterer&& right) = delete; + + ~PauseCallbackRegisterer() + { + cb_manager.RemovePauseCallback(cb_tag); + } + + PauseCallbackRegisterer& operator =(const PauseCallbackRegisterer& right) = delete; + PauseCallbackRegisterer& operator =(PauseCallbackRegisterer&& right) = delete; + }; diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp index 815668386d..4d65c06c51 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp @@ -18,7 +18,7 @@ Module *cellAudio = nullptr; AudioConfig g_audio; -int cellAudioInit() +s32 cellAudioInit() { cellAudio->Warning("cellAudioInit()"); @@ -27,23 +27,27 @@ int cellAudioInit() return CELL_AUDIO_ERROR_ALREADY_INIT; } + // clear ports for (auto& port : g_audio.ports) { - port.state.write_relaxed(AUDIO_PORT_STATE_NOT_OPENED); + port.state.write_relaxed(AUDIO_PORT_STATE_CLOSED); } + // reset variables g_audio.start_time = 0; g_audio.counter = 0; g_audio.keys.clear(); + g_audio.start_time = get_system_time(); // alloc memory (only once until the emulator is stopped) - g_audio.buffer = g_audio.buffer ? g_audio.buffer : vm::cast(Memory.MainMem.AllocAlign(128 * 1024 * AUDIO_PORT_COUNT, 4096)); + g_audio.buffer = g_audio.buffer ? g_audio.buffer : vm::cast(Memory.MainMem.AllocAlign(AUDIO_PORT_OFFSET * AUDIO_PORT_COUNT, 4096)); g_audio.indexes = g_audio.indexes ? g_audio.indexes : vm::cast(Memory.MainMem.AllocAlign(sizeof(u64) * AUDIO_PORT_COUNT, __alignof(u64))); // clear memory - memset(vm::get_ptr(g_audio.buffer), 0, 128 * 1024 * AUDIO_PORT_COUNT); + memset(vm::get_ptr(g_audio.buffer), 0, AUDIO_PORT_OFFSET * AUDIO_PORT_COUNT); memset(vm::get_ptr(g_audio.indexes), 0, sizeof(u64) * AUDIO_PORT_COUNT); + // start audio thread g_audio.audio_thread.start([]() { const bool do_dump = Ini.AudioDumpToFile.GetValue(); @@ -51,8 +55,7 @@ int cellAudioInit() AudioDumper m_dump; if (do_dump && !m_dump.Init(8)) // Init AudioDumper for 8 channels { - cellAudio->Error("AudioDumper::Init() failed"); - return; + throw "AudioDumper::Init() failed"; } float buf2ch[2 * BUFFER_SIZE]; // intermediate buffer for 2 channels @@ -67,69 +70,60 @@ int cellAudioInit() out_buffer[i].reset(new float[2 * BUFFER_SIZE] {}); } - squeue_t out_queue; + squeue_t out_queue; std::vector keys; - g_audio.start_time = get_system_time(); - - thread_t iat("Internal Audio Thread", [&out_queue]() + thread_t iat("Internal Audio Thread", true /* autojoin */, [&out_queue]() { const bool use_u16 = Ini.AudioConvertToU16.GetValue(); Emu.GetAudioManager().GetAudioOut().Init(); bool opened = false; + float* buffer; - while (g_audio.state.read_relaxed() == AUDIO_STATE_INITIALIZED && !Emu.IsStopped()) + while (out_queue.pop(buffer, [](){ return g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED; })) { - float* buffer; - if (out_queue.pop(buffer, [](){ return g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED; })) + if (use_u16) { - if (use_u16) + // convert the data from float to u16 with clipping: + // 2x MULPS + // 2x MAXPS (optional) + // 2x MINPS (optional) + // 2x CVTPS2DQ (converts float to s32) + // PACKSSDW (converts s32 to s16 with signed saturation) + + u16 buf_u16[out_buffer_size]; + for (size_t i = 0; i < out_buffer_size; i += 8) { - // convert the data from float to u16 with clipping: - // 2x MULPS - // 2x MAXPS (optional) - // 2x MINPS (optional) - // 2x CVTPS2DQ (converts float to s32) - // PACKSSDW (converts s32 to s16 with signed saturation) + static const __m128 float2u16 = { 0x8000, 0x8000, 0x8000, 0x8000 }; + (__m128i&)(buf_u16[i]) = _mm_packs_epi32( + _mm_cvtps_epi32(_mm_mul_ps((__m128&)(buffer[i]), float2u16)), + _mm_cvtps_epi32(_mm_mul_ps((__m128&)(buffer[i + 4]), float2u16))); + } - u16 buf_u16[out_buffer_size]; - for (size_t i = 0; i < out_buffer_size; i += 8) - { - static const __m128 float2u16 = { 0x8000, 0x8000, 0x8000, 0x8000 }; - (__m128i&)(buf_u16[i]) = _mm_packs_epi32( - _mm_cvtps_epi32(_mm_mul_ps((__m128&)(buffer[i]), float2u16)), - _mm_cvtps_epi32(_mm_mul_ps((__m128&)(buffer[i + 4]), float2u16))); - } - - if (!opened) - { - Emu.GetAudioManager().GetAudioOut().Open(buf_u16, out_buffer_size * sizeof(u16)); - opened = true; - } - else - { - Emu.GetAudioManager().GetAudioOut().AddData(buf_u16, out_buffer_size * sizeof(u16)); - } + if (!opened) + { + Emu.GetAudioManager().GetAudioOut().Open(buf_u16, out_buffer_size * sizeof(u16)); + opened = true; } else { - if (!opened) - { - Emu.GetAudioManager().GetAudioOut().Open(buffer, out_buffer_size * sizeof(float)); - opened = true; - } - else - { - Emu.GetAudioManager().GetAudioOut().AddData(buffer, out_buffer_size * sizeof(float)); - } + Emu.GetAudioManager().GetAudioOut().AddData(buf_u16, out_buffer_size * sizeof(u16)); } } else { - break; + if (!opened) + { + Emu.GetAudioManager().GetAudioOut().Open(buffer, out_buffer_size * sizeof(float)); + opened = true; + } + else + { + Emu.GetAudioManager().GetAudioOut().AddData(buffer, out_buffer_size * sizeof(float)); + } } } @@ -143,7 +137,7 @@ int cellAudioInit() // TODO: send beforemix event (in ~2,6 ms before mixing) // precise time of sleeping: 5,(3) ms (or 256/48000 sec) - if (g_audio.counter * 256000000 / 48000 >= stamp0 - g_audio.start_time) + if (g_audio.counter * AUDIO_SAMPLES * MHZ / 48000 >= stamp0 - g_audio.start_time) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); continue; @@ -165,14 +159,39 @@ int cellAudioInit() { if (port.state.read_relaxed() != AUDIO_PORT_STATE_STARTED) continue; - const u32 block_size = port.channel * 256; + const u32 block_size = port.channel * AUDIO_SAMPLES; const u32 position = port.tag % port.block; // old value const u32 buf_addr = port.addr + position * block_size * sizeof(float); auto buf = vm::get_ptr>(buf_addr); static const float k = 1.0f; // may be 1.0f - const float m = port.level; + const float& m = port.level; + + auto step_volume = [](AudioPortConfig& port) // part of cellAudioSetPortLevel functionality + { + if (port.level_inc) + { + port.level += port.level_inc; + + if (port.level_inc > 0.0f) + { + if (port.level_set - port.level <= 0.0f) + { + port.level = port.level_set; + port.level_inc = 0.0f; + } + } + else + { + if (port.level_set - port.level >= 0.0f) + { + port.level = port.level_set; + port.level_inc = 0.0f; + } + } + } + }; if (port.channel == 2) { @@ -180,6 +199,8 @@ int cellAudioInit() { for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) { + step_volume(port); + // reverse byte order const float left = buf[i + 0] * m; const float right = buf[i + 1] * m; @@ -202,6 +223,8 @@ int cellAudioInit() { for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) { + step_volume(port); + const float left = buf[i + 0] * m; const float right = buf[i + 1] * m; @@ -213,64 +236,14 @@ int cellAudioInit() } } } - else if (port.channel == 6) - { - if (first_mix) - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) - { - const float left = buf[i * 3 + 0] * m; - const float right = buf[i * 3 + 1] * m; - const float center = buf[i * 3 + 2] * m; - const float low_freq = buf[i * 3 + 3] * m; - const float rear_left = buf[i * 3 + 4] * m; - const float rear_right = buf[i * 3 + 5] * m; - - const float mid = (center + low_freq) * 0.708f; - buf2ch[i + 0] = (left + rear_left + mid) * k; - buf2ch[i + 1] = (right + rear_right + mid) * k; - - buf8ch[i * 4 + 0] = left; - buf8ch[i * 4 + 1] = right; - buf8ch[i * 4 + 2] = center; - buf8ch[i * 4 + 3] = low_freq; - buf8ch[i * 4 + 4] = rear_left; - buf8ch[i * 4 + 5] = rear_right; - buf8ch[i * 4 + 6] = 0.0f; - buf8ch[i * 4 + 7] = 0.0f; - } - first_mix = false; - } - else - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) - { - const float left = buf[i * 3 + 0] * m; - const float right = buf[i * 3 + 1] * m; - const float center = buf[i * 3 + 2] * m; - const float low_freq = buf[i * 3 + 3] * m; - const float rear_left = buf[i * 3 + 4] * m; - const float rear_right = buf[i * 3 + 5] * m; - - const float mid = (center + low_freq) * 0.708f; - buf2ch[i + 0] += (left + rear_left + mid) * k; - buf2ch[i + 1] += (right + rear_right + mid) * k; - - buf8ch[i * 4 + 0] += left; - buf8ch[i * 4 + 1] += right; - buf8ch[i * 4 + 2] += center; - buf8ch[i * 4 + 3] += low_freq; - buf8ch[i * 4 + 4] += rear_left; - buf8ch[i * 4 + 5] += rear_right; - } - } - } else if (port.channel == 8) { if (first_mix) { for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) { + step_volume(port); + const float left = buf[i * 4 + 0] * m; const float right = buf[i * 4 + 1] * m; const float center = buf[i * 4 + 2] * m; @@ -299,6 +272,8 @@ int cellAudioInit() { for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) { + step_volume(port); + const float left = buf[i * 4 + 0] * m; const float right = buf[i * 4 + 1] * m; const float center = buf[i * 4 + 2] * m; @@ -323,6 +298,10 @@ int cellAudioInit() } } } + else + { + throw fmt::format("Unknown channel count (port=%d, channel=%d)", &port - g_audio.ports, port.channel); + } memset(buf, 0, block_size * sizeof(float)); } @@ -384,36 +363,31 @@ int cellAudioInit() { if (m_dump.WriteData(&buf8ch, sizeof(buf8ch)) != sizeof(buf8ch)) // write file data { - cellAudio->Error("AudioDumper::WriteData() failed"); - break; + throw "AudioDumper::WriteData() failed (2 ch)"; } } else if (m_dump.GetCh() == 2) { if (m_dump.WriteData(&buf2ch, sizeof(buf2ch)) != sizeof(buf2ch)) // write file data { - cellAudio->Error("AudioDumper::WriteData() failed"); - break; + throw "AudioDumper::WriteData() failed (8 ch)"; } } else { - cellAudio->Error("AudioDumper::GetCh() returned unknown value (%d)", m_dump.GetCh()); - break; + throw fmt::format("AudioDumper::GetCh() returned unknown value (%d)", m_dump.GetCh()); } } //LOG_NOTICE(HLE, "Audio perf: start=%d (access=%d, AddData=%d, events=%d, dump=%d)", //stamp0 - m_config.start_time, stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3); } - - iat.join(); }); return CELL_OK; } -int cellAudioQuit() +s32 cellAudioQuit() { cellAudio->Warning("cellAudioQuit()"); @@ -427,84 +401,153 @@ int cellAudioQuit() return CELL_OK; } -int cellAudioPortOpen(vm::ptr audioParam, vm::ptr portNum) +s32 cellAudioPortOpen(vm::ptr audioParam, vm::ptr portNum) { - cellAudio->Warning("cellAudioPortOpen(audioParam_addr=0x%x, portNum_addr=0x%x)", audioParam.addr(), portNum.addr()); + cellAudio->Warning("cellAudioPortOpen(audioParam=0x%x, portNum=0x%x)", audioParam, portNum); - if (audioParam->nChannel > 8 || audioParam->nBlock > 16) + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (!audioParam || !portNum) { return CELL_AUDIO_ERROR_PARAM; } - for (u32 i = 0; i < AUDIO_PORT_COUNT; i++) + const u64 channel = audioParam->nChannel; + const u64 block = audioParam->nBlock; + const u64 attr = audioParam->attr; + + // check attributes + if (channel != CELL_AUDIO_PORT_2CH && + channel != CELL_AUDIO_PORT_8CH && + channel) { - if (g_audio.ports[i].state.compare_and_swap_test(AUDIO_PORT_STATE_NOT_OPENED, AUDIO_PORT_STATE_OPENED)) - { - AudioPortConfig& port = g_audio.ports[i]; - - port.channel = (u8)audioParam->nChannel; - port.block = (u8)audioParam->nBlock; - port.attr = audioParam->attr; - port.addr = g_audio.buffer + (128 * 1024 * i); - port.read_index_addr = g_audio.indexes + (sizeof(u64) * i); - port.size = port.channel * port.block * 256 * sizeof(float); - if (port.attr & CELL_AUDIO_PORTATTR_INITLEVEL) - { - port.level = audioParam->level; - } - else - { - port.level = 1.0f; - } - - *portNum = i; - cellAudio->Warning("*** audio port opened(nChannel=%d, nBlock=%d, attr=0x%llx, level=%f): port = %d", - port.channel, port.block, port.attr, port.level, i); - - port.tag = 0; - return CELL_OK; - } + return CELL_AUDIO_ERROR_PARAM; } - return CELL_AUDIO_ERROR_PORT_FULL; + if (block != CELL_AUDIO_BLOCK_8 && + block != CELL_AUDIO_BLOCK_16 && + block != 2 && + block != 4 && + block != 32) + { + return CELL_AUDIO_ERROR_PARAM; + } + + // list unsupported flags + if (attr & CELL_AUDIO_PORTATTR_BGM) + { + cellAudio->Todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_BGM"); + } + if (attr & CELL_AUDIO_PORTATTR_OUT_SECONDARY) + { + cellAudio->Todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_SECONDARY"); + } + if (attr & CELL_AUDIO_PORTATTR_OUT_PERSONAL_0) + { + cellAudio->Todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_PERSONAL_0"); + } + if (attr & CELL_AUDIO_PORTATTR_OUT_PERSONAL_1) + { + cellAudio->Todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_PERSONAL_1"); + } + if (attr & CELL_AUDIO_PORTATTR_OUT_PERSONAL_2) + { + cellAudio->Todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_PERSONAL_2"); + } + if (attr & CELL_AUDIO_PORTATTR_OUT_PERSONAL_3) + { + cellAudio->Todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_PERSONAL_3"); + } + if (attr & CELL_AUDIO_PORTATTR_OUT_NO_ROUTE) + { + cellAudio->Todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_NO_ROUTE"); + } + if (attr & 0xFFFFFFFFF0EFEFEEULL) + { + cellAudio->Todo("cellAudioPortOpen(): unknown attributes set (0x%llx)", attr); + } + + // open audio port + const u32 port_index = g_audio.open_port(); + + if (!~port_index) + { + return CELL_AUDIO_ERROR_PORT_FULL; + } + + AudioPortConfig& port = g_audio.ports[port_index]; + + port.channel = (u32)channel; + port.block = (u32)block; + port.attr = attr; + port.addr = g_audio.buffer + AUDIO_PORT_OFFSET * port_index; + port.read_index_addr = g_audio.indexes + sizeof(u64) * port_index; + port.size = port.channel * port.block * AUDIO_SAMPLES * sizeof(float); + port.tag = 0; + + if (port.attr & CELL_AUDIO_PORTATTR_INITLEVEL) + { + port.level = audioParam->level; + } + else + { + port.level = 1.0f; + } + + port.level_set = port.level; + port.level_inc = 0.0f; + + *portNum = port_index; + cellAudio->Warning("*** audio port opened(nChannel=%d, nBlock=%d, attr=0x%llx, level=%f): port = %d", channel, block, attr, port.level, port_index); + + return CELL_OK; } -int cellAudioGetPortConfig(u32 portNum, vm::ptr portConfig) +s32 cellAudioGetPortConfig(u32 portNum, vm::ptr portConfig) { - cellAudio->Warning("cellAudioGetPortConfig(portNum=0x%x, portConfig_addr=0x%x)", portNum, portConfig.addr()); + cellAudio->Warning("cellAudioGetPortConfig(portNum=0x%x, portConfig=0x%x)", portNum, portConfig); - if (portNum >= AUDIO_PORT_COUNT) + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (!portConfig || portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - switch (auto state = g_audio.ports[portNum].state.read_sync()) + AudioPortConfig& port = g_audio.ports[portNum]; + + portConfig->readIndexAddr = port.read_index_addr; + + switch (auto state = port.state.read_sync()) { - case AUDIO_PORT_STATE_NOT_OPENED: portConfig->status = CELL_AUDIO_STATUS_CLOSE; break; + case AUDIO_PORT_STATE_CLOSED: portConfig->status = CELL_AUDIO_STATUS_CLOSE; break; case AUDIO_PORT_STATE_OPENED: portConfig->status = CELL_AUDIO_STATUS_READY; break; case AUDIO_PORT_STATE_STARTED: portConfig->status = CELL_AUDIO_STATUS_RUN; break; default: throw fmt::format("cellAudioGetPortConfig(%d): invalid port state (0x%x)", portNum, state); } - AudioPortConfig& port = g_audio.ports[portNum]; - portConfig->nChannel = port.channel; portConfig->nBlock = port.block; portConfig->portSize = port.size; - portConfig->portAddr = port.addr; // 0x20020000 - portConfig->readIndexAddr = port.read_index_addr; // 0x20010010 on ps3 - - cellAudio->Log("*** port config: nChannel=%d, nBlock=%d, portSize=0x%x, portAddr=0x%x, readIndexAddr=0x%x", - (u32)portConfig->nChannel, (u32)portConfig->nBlock, (u32)portConfig->portSize, (u32)portConfig->portAddr, (u32)portConfig->readIndexAddr); - // portAddr - readIndexAddr == 0xFFF0 on ps3 - + portConfig->portAddr = port.addr; return CELL_OK; } -int cellAudioPortStart(u32 portNum) +s32 cellAudioPortStart(u32 portNum) { cellAudio->Warning("cellAudioPortStart(portNum=0x%x)", portNum); + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; @@ -512,35 +555,45 @@ int cellAudioPortStart(u32 portNum) switch (auto state = g_audio.ports[portNum].state.compare_and_swap(AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_STARTED)) { - case AUDIO_PORT_STATE_NOT_OPENED: return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + case AUDIO_PORT_STATE_CLOSED: return CELL_AUDIO_ERROR_PORT_NOT_OPEN; case AUDIO_PORT_STATE_STARTED: return CELL_AUDIO_ERROR_PORT_ALREADY_RUN; case AUDIO_PORT_STATE_OPENED: return CELL_OK; default: throw fmt::format("cellAudioPortStart(%d): invalid port state (0x%x)", portNum, state); } } -int cellAudioPortClose(u32 portNum) +s32 cellAudioPortClose(u32 portNum) { cellAudio->Warning("cellAudioPortClose(portNum=0x%x)", portNum); + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - switch (auto state = g_audio.ports[portNum].state.exchange(AUDIO_PORT_STATE_NOT_OPENED)) + switch (auto state = g_audio.ports[portNum].state.exchange(AUDIO_PORT_STATE_CLOSED)) { - case AUDIO_PORT_STATE_NOT_OPENED: return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + case AUDIO_PORT_STATE_CLOSED: return CELL_AUDIO_ERROR_PORT_NOT_OPEN; case AUDIO_PORT_STATE_STARTED: return CELL_OK; case AUDIO_PORT_STATE_OPENED: return CELL_OK; default: throw fmt::format("cellAudioPortClose(%d): invalid port state (0x%x)", portNum, state); } } -int cellAudioPortStop(u32 portNum) +s32 cellAudioPortStop(u32 portNum) { cellAudio->Warning("cellAudioPortStop(portNum=0x%x)", portNum); + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; @@ -548,34 +601,36 @@ int cellAudioPortStop(u32 portNum) switch (auto state = g_audio.ports[portNum].state.compare_and_swap(AUDIO_PORT_STATE_STARTED, AUDIO_PORT_STATE_OPENED)) { - case AUDIO_PORT_STATE_NOT_OPENED: return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + case AUDIO_PORT_STATE_CLOSED: return CELL_AUDIO_ERROR_PORT_NOT_RUN; case AUDIO_PORT_STATE_STARTED: return CELL_OK; - case AUDIO_PORT_STATE_OPENED: return CELL_AUDIO_ERROR_PORT_OPEN; + case AUDIO_PORT_STATE_OPENED: return CELL_AUDIO_ERROR_PORT_NOT_RUN; default: throw fmt::format("cellAudioPortStop(%d): invalid port state (0x%x)", portNum, state); } } -int cellAudioGetPortTimestamp(u32 portNum, u64 tag, vm::ptr stamp) +s32 cellAudioGetPortTimestamp(u32 portNum, u64 tag, vm::ptr stamp) { - cellAudio->Log("cellAudioGetPortTimestamp(portNum=0x%x, tag=0x%llx, stamp_addr=0x%x)", portNum, tag, stamp.addr()); + cellAudio->Log("cellAudioGetPortTimestamp(portNum=0x%x, tag=0x%llx, stamp=0x%x)", portNum, tag, stamp); + + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - //if (!g_audio.ports[portNum].is_audio_port_opened) - //{ - // return CELL_AUDIO_ERROR_PORT_NOT_OPEN; - //} - - //if (!g_audio.ports[portNum].is_audio_port_started) - //{ - // return CELL_AUDIO_ERROR_PORT_NOT_RUN; - //} - AudioPortConfig& port = g_audio.ports[portNum]; + if (port.state.read_relaxed() == AUDIO_PORT_STATE_CLOSED) + { + return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + } + + // TODO: check tag (CELL_AUDIO_ERROR_TAG_NOT_FOUND error) + std::lock_guard lock(g_audio.mutex); *stamp = g_audio.start_time + (port.counter + (tag - port.tag)) * 256000000 / 48000; @@ -583,30 +638,29 @@ int cellAudioGetPortTimestamp(u32 portNum, u64 tag, vm::ptr stamp) return CELL_OK; } -int cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, vm::ptr tag) +s32 cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, vm::ptr tag) { - cellAudio->Log("cellAudioGetPortBlockTag(portNum=0x%x, blockNo=0x%llx, tag_addr=0x%x)", portNum, blockNo, tag.addr()); + cellAudio->Log("cellAudioGetPortBlockTag(portNum=0x%x, blockNo=0x%llx, tag=0x%x)", portNum, blockNo, tag); + + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - //if (!g_audio.ports[portNum].is_audio_port_opened) - //{ - // return CELL_AUDIO_ERROR_PORT_NOT_OPEN; - //} - - //if (!g_audio.ports[portNum].is_audio_port_started) - //{ - // return CELL_AUDIO_ERROR_PORT_NOT_RUN; - //} - AudioPortConfig& port = g_audio.ports[portNum]; + if (port.state.read_relaxed() == AUDIO_PORT_STATE_CLOSED) + { + return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + } + if (blockNo >= port.block) { - cellAudio->Error("cellAudioGetPortBlockTag: wrong blockNo(%lld)", blockNo); return CELL_AUDIO_ERROR_PARAM; } @@ -627,9 +681,14 @@ int cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, vm::ptr tag) return CELL_OK; } -int cellAudioSetPortLevel(u32 portNum, float level) +s32 cellAudioSetPortLevel(u32 portNum, float level) { - cellAudio->Todo("cellAudioSetPortLevel(portNum=0x%x, level=%f)", portNum, level); + cellAudio->Log("cellAudioSetPortLevel(portNum=0x%x, level=%f)", portNum, level); + + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } if (portNum >= AUDIO_PORT_COUNT) { @@ -638,19 +697,22 @@ int cellAudioSetPortLevel(u32 portNum, float level) AudioPortConfig& port = g_audio.ports[portNum]; - //if (!port.is_audio_port_opened) - //{ - // return CELL_AUDIO_ERROR_PORT_NOT_OPEN; - //} + if (port.state.read_relaxed() == AUDIO_PORT_STATE_CLOSED) + { + return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + } - //if (!port.is_audio_port_started) - //{ - // return CELL_AUDIO_ERROR_PORT_NOT_RUN; - //} + if (level >= 0.0f) + { + std::lock_guard lock(g_audio.mutex); - std::lock_guard lock(g_audio.mutex); - - port.level = level; // TODO + port.level_set = level; + port.level_inc = (port.level - level) / 624.0f; + } + else + { + cellAudio->Todo("cellAudioSetPortLevel(portNum=0x%x): negative level value (%f)", portNum, level); + } return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.h b/rpcs3/Emu/SysCalls/Modules/cellAudio.h index 83fd4fc097..ca165476c1 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudio.h +++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.h @@ -77,6 +77,8 @@ enum : u32 BUFFER_NUM = 32, BUFFER_SIZE = 256, AUDIO_PORT_COUNT = 8, + AUDIO_PORT_OFFSET = 256 * 1024, + AUDIO_SAMPLES = CELL_AUDIO_BLOCK_SAMPLES, }; enum AudioState : u32 @@ -88,7 +90,7 @@ enum AudioState : u32 enum AudioPortState : u32 { - AUDIO_PORT_STATE_NOT_OPENED, + AUDIO_PORT_STATE_CLOSED, AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_STARTED, }; @@ -98,15 +100,17 @@ struct AudioPortConfig std::mutex mutex; atomic_le_t state; - u8 channel; - u8 block; - float level; + u32 channel; + u32 block; u64 attr; u64 tag; u64 counter; // copy of global counter u32 addr; u32 read_index_addr; u32 size; + float level; + float level_set; + float level_inc; }; struct AudioConfig //custom structure @@ -125,6 +129,19 @@ struct AudioConfig //custom structure AudioConfig() : audio_thread("Audio Thread") { } + + u32 open_port() + { + for (u32 i = 0; i < AUDIO_PORT_COUNT; i++) + { + if (ports[i].state.compare_and_swap_test(AUDIO_PORT_STATE_CLOSED, AUDIO_PORT_STATE_OPENED)) + { + return i; + } + } + + return ~0; + } }; extern AudioConfig g_audio; diff --git a/rpcs3/Emu/SysCalls/Modules/libmixer.cpp b/rpcs3/Emu/SysCalls/Modules/libmixer.cpp index 9591474ec7..0030923d06 100644 --- a/rpcs3/Emu/SysCalls/Modules/libmixer.cpp +++ b/rpcs3/Emu/SysCalls/Modules/libmixer.cpp @@ -10,9 +10,7 @@ Module *libmixer = nullptr; -CellSurMixerConfig surMixer; - -#define SUR_PORT (7) +SurMixerConfig g_surmx; vm::ptr surMixerCb; vm::ptr surMixerCbArg; std::mutex mixer_mutex; @@ -31,13 +29,13 @@ int cellAANAddData(u32 aan_handle, u32 aan_port, u32 offset, vm::ptr addr switch (type) { case CELL_SURMIXER_CHSTRIP_TYPE1A: - if (port >= surMixer.chStrips1) type = 0; break; + if (port >= g_surmx.ch_strips_1) type = 0; break; case CELL_SURMIXER_CHSTRIP_TYPE2A: - if (port >= surMixer.chStrips2) type = 0; break; + if (port >= g_surmx.ch_strips_2) type = 0; break; case CELL_SURMIXER_CHSTRIP_TYPE6A: - if (port >= surMixer.chStrips6) type = 0; break; + if (port >= g_surmx.ch_strips_6) type = 0; break; case CELL_SURMIXER_CHSTRIP_TYPE8A: - if (port >= surMixer.chStrips8) type = 0; break; + if (port >= g_surmx.ch_strips_8) type = 0; break; default: type = 0; break; } @@ -296,15 +294,21 @@ int cellSurMixerCreate(vm::ptr config) { libmixer->Warning("cellSurMixerCreate(config_addr=0x%x)", config.addr()); - surMixer = *config; + g_surmx.audio_port = g_audio.open_port(); - AudioPortConfig& port = g_audio.ports[SUR_PORT]; - - if (!port.state.compare_and_swap_test(AUDIO_PORT_STATE_NOT_OPENED, AUDIO_PORT_STATE_OPENED)) + if (!~g_surmx.audio_port) { return CELL_LIBMIXER_ERROR_FULL; } + g_surmx.priority = config->priority; + g_surmx.ch_strips_1 = config->chStrips1; + g_surmx.ch_strips_2 = config->chStrips2; + g_surmx.ch_strips_6 = config->chStrips6; + g_surmx.ch_strips_8 = config->chStrips8; + + AudioPortConfig& port = g_audio.ports[g_surmx.audio_port]; + port.channel = 8; port.block = 16; port.attr = 0; @@ -316,12 +320,11 @@ int cellSurMixerCreate(vm::ptr config) mixcount = 0; surMixerCb.set(0); - libmixer->Warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)", - (u32)surMixer.chStrips1, (u32)surMixer.chStrips2, (u32)surMixer.chStrips6, (u32)surMixer.chStrips8); + libmixer->Warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)", config->chStrips1, config->chStrips2, config->chStrips6, config->chStrips8); thread_t t("Surmixer Thread", []() { - AudioPortConfig& port = g_audio.ports[SUR_PORT]; + AudioPortConfig& port = g_audio.ports[g_surmx.audio_port]; PPUThread& cb_thread = *(PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU); cb_thread.SetName("Surmixer Callback Thread"); @@ -332,14 +335,8 @@ int cellSurMixerCreate(vm::ptr config) cb_thread.InitRegs(); cb_thread.DoRun(); - while (port.state.read_relaxed() != AUDIO_PORT_STATE_NOT_OPENED) + while (port.state.read_relaxed() != AUDIO_PORT_STATE_CLOSED && !Emu.IsStopped()) { - if (Emu.IsStopped()) - { - libmixer->Warning("Surmixer aborted"); - break; - } - if (mixcount > (port.tag + 0)) // adding positive value (1-15): preemptive buffer filling (hack) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack @@ -437,7 +434,7 @@ int cellSurMixerCreate(vm::ptr config) //u64 stamp2 = get_system_time(); - auto buf = vm::get_ptr>(g_audio.buffer + (128 * 1024 * SUR_PORT) + (mixcount % port.block) * port.channel * 256 * sizeof(float)); + auto buf = vm::get_ptr>(port.addr + (mixcount % port.block) * port.channel * AUDIO_SAMPLES * sizeof(float)); for (u32 i = 0; i < (sizeof(mixdata) / sizeof(float)); i++) { @@ -511,7 +508,12 @@ int cellSurMixerStart() { libmixer->Warning("cellSurMixerStart()"); - g_audio.ports[SUR_PORT].state.compare_and_swap(AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_STARTED); + if (g_surmx.audio_port >= AUDIO_PORT_COUNT) + { + return CELL_LIBMIXER_ERROR_NOT_INITIALIZED; + } + + g_audio.ports[g_surmx.audio_port].state.compare_and_swap(AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_STARTED); return CELL_OK; } @@ -526,12 +528,17 @@ int cellSurMixerFinalize() { libmixer->Warning("cellSurMixerFinalize()"); - g_audio.ports[SUR_PORT].state.compare_and_swap(AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_NOT_OPENED); + if (g_surmx.audio_port >= AUDIO_PORT_COUNT) + { + return CELL_LIBMIXER_ERROR_NOT_INITIALIZED; + } + + g_audio.ports[g_surmx.audio_port].state.compare_and_swap(AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_CLOSED); return CELL_OK; } -int cellSurMixerSurBusAddData(u32 busNo, u32 offset, u32 addr, u32 samples) +int cellSurMixerSurBusAddData(u32 busNo, u32 offset, vm::ptr addr, u32 samples) { if (busNo < 8 && samples == 256 && offset == 0) { @@ -548,8 +555,7 @@ int cellSurMixerSurBusAddData(u32 busNo, u32 offset, u32 addr, u32 samples) for (u32 i = 0; i < samples; i++) { // reverse byte order and mix - u32 v = vm::read32(addr + i * sizeof(float)); - mixdata[i*8+busNo] += (float&)v; + mixdata[i * 8 + busNo] += addr[i]; } return CELL_OK; @@ -565,7 +571,12 @@ int cellSurMixerPause(u32 type) { libmixer->Warning("cellSurMixerPause(type=%d)", type); - g_audio.ports[SUR_PORT].state.compare_and_swap(AUDIO_PORT_STATE_STARTED, AUDIO_PORT_STATE_OPENED); + if (g_surmx.audio_port >= AUDIO_PORT_COUNT) + { + return CELL_LIBMIXER_ERROR_NOT_INITIALIZED; + } + + g_audio.ports[g_surmx.audio_port].state.compare_and_swap(AUDIO_PORT_STATE_STARTED, AUDIO_PORT_STATE_OPENED); return CELL_OK; } @@ -617,6 +628,8 @@ void libmixer_init(Module *pxThis) { libmixer = pxThis; + g_surmx.audio_port = ~0; + REG_SUB(libmixer, "surmxAAN", cellAANAddData, 0xffffffff7c691b78, 0xffffffff7c0802a6, diff --git a/rpcs3/Emu/SysCalls/Modules/libmixer.h b/rpcs3/Emu/SysCalls/Modules/libmixer.h index 45f8a26af9..9a7978f9a5 100644 --- a/rpcs3/Emu/SysCalls/Modules/libmixer.h +++ b/rpcs3/Emu/SysCalls/Modules/libmixer.h @@ -1,6 +1,7 @@ #pragma once -enum //libmixer Error Codes +// Error Codes +enum { CELL_LIBMIXER_ERROR_NOT_INITIALIZED = 0x80310002, CELL_LIBMIXER_ERROR_INVALID_PARAMATER = 0x80310003, @@ -164,6 +165,16 @@ struct CellSurMixerChStripParam be_t intVal; }; +struct SurMixerConfig +{ + u32 audio_port; + s32 priority; + u32 ch_strips_1; + u32 ch_strips_2; + u32 ch_strips_6; + u32 ch_strips_8; +}; + struct SSPlayer { bool m_created; // SSPlayerCreate/Remove diff --git a/rpcs3/Emu/SysCalls/lv2/sys_time.h b/rpcs3/Emu/SysCalls/lv2/sys_time.h index 34d755db8a..dacff931e0 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_time.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_time.h @@ -1,6 +1,9 @@ #pragma once -#define MHZ (1000000) +enum : u32 +{ + MHZ = 1000000, +}; // Auxiliary functions u64 get_time(); diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index ee84464bd8..8696a631d0 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -328,6 +328,8 @@ void Emulator::Pause() if (InterlockedCompareExchange((volatile u32*)&m_status, Paused, Running) == Running) { SendDbgCommand(DID_PAUSED_EMU); + + GetCallbackManager().RunPauseCallbacks(true); } } @@ -341,6 +343,8 @@ void Emulator::Resume() CheckStatus(); SendDbgCommand(DID_RESUMED_EMU); + + GetCallbackManager().RunPauseCallbacks(false); } void Emulator::Stop() From a6754e29a69e25a76e99e0c7dafca0431da9d273 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Sat, 17 Jan 2015 19:36:23 +0300 Subject: [PATCH 5/7] Compilation fix --- Utilities/Thread.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 01ff0787be..a3831a3f98 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -740,8 +740,8 @@ void waiter_map_t::notify(u64 signal_id) } } -static const std::function SQUEUE_ALWAYS_EXIT = [](){ return true; }; -static const std::function SQUEUE_NEVER_EXIT = [](){ return false; }; +const std::function SQUEUE_ALWAYS_EXIT = [](){ return true; }; +const std::function SQUEUE_NEVER_EXIT = [](){ return false; }; bool squeue_test_exit() { From 011362bf1ce75a2998a92450c02f14ba1defae19 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Sat, 17 Jan 2015 21:33:39 +0300 Subject: [PATCH 6/7] Things updated --- rpcs3/Emu/RSX/RSXThread.cpp | 9 +---- rpcs3/Emu/SysCalls/Modules/cellAdec.cpp | 1 - rpcs3/Emu/SysCalls/Modules/cellAudio.cpp | 48 +++++++++++++++++++++--- rpcs3/Emu/SysCalls/Modules/cellDmux.cpp | 1 - rpcs3/Emu/SysCalls/Modules/cellVdec.cpp | 1 - 5 files changed, 44 insertions(+), 16 deletions(-) diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index f3bd2be3a6..b8a32f93ef 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -2356,14 +2356,8 @@ void RSXThread::Task() m_vblank_count = 0; - while (!TestDestroy()) + while (!TestDestroy() && !Emu.IsStopped()) { - if (Emu.IsStopped()) - { - LOG_WARNING(RSX, "VBlank thread aborted"); - return; - } - if (get_system_time() - start_time > m_vblank_count * 1000000 / 60) { m_vblank_count++; @@ -2383,7 +2377,6 @@ void RSXThread::Task() is_vblank_stopped = true; }); - vblank.detach(); while (!TestDestroy()) try { diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp index f1b9ef1f5e..52f8e06a64 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp @@ -475,7 +475,6 @@ u32 adecOpen(AudioDecoder* adec_ptr) } adec.is_finished = true; - if (Emu.IsStopped()) cellAdec->Warning("AudioDecoder thread aborted"); }); return adec_id; diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp index 4d65c06c51..d7e24e4bae 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp @@ -2,6 +2,7 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/Modules.h" +#include "Emu/SysCalls/Callback.h" #include "Emu/Memory/atomic_type.h" #include "rpcs3/Ini.h" @@ -130,27 +131,64 @@ s32 cellAudioInit() Emu.GetAudioManager().GetAudioOut().Quit(); }); + u64 last_pause_time; + std::atomic added_time(0); + NamedThreadBase* audio_thread = GetCurrentNamedThread(); + + PauseCallbackRegisterer pcb(Emu.GetCallbackManager(), [&last_pause_time, &added_time, audio_thread](bool is_paused) + { + if (is_paused) + { + last_pause_time = get_system_time(); + } + else + { + added_time += get_system_time() - last_pause_time; + audio_thread->Notify(); + } + }); + while (g_audio.state.read_relaxed() == AUDIO_STATE_INITIALIZED && !Emu.IsStopped()) { + if (Emu.IsPaused()) + { + GetCurrentNamedThread()->WaitForAnySignal(); + continue; + } + + if (added_time) + { + g_audio.start_time += added_time.exchange(0); + } + const u64 stamp0 = get_system_time(); // TODO: send beforemix event (in ~2,6 ms before mixing) // precise time of sleeping: 5,(3) ms (or 256/48000 sec) - if (g_audio.counter * AUDIO_SAMPLES * MHZ / 48000 >= stamp0 - g_audio.start_time) + const u64 expected_time = g_audio.counter * AUDIO_SAMPLES * MHZ / 48000; + if (expected_time >= stamp0 - g_audio.start_time) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); continue; } + + // crutch to hide giant lags caused by debugger + const u64 missed_time = stamp0 - g_audio.start_time - expected_time; + if (missed_time > AUDIO_SAMPLES * MHZ / 48000) + { + cellAudio->Notice("%f ms adjusted", (float)missed_time / 1000); + g_audio.start_time += missed_time; + } g_audio.counter++; const u32 out_pos = g_audio.counter % BUFFER_NUM; - if (Emu.IsPaused()) - { - continue; - } + //if (Emu.IsPaused()) + //{ + // continue; + //} bool first_mix = true; diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp index 7670b22b4a..a2a80f1719 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp @@ -759,7 +759,6 @@ u32 dmuxOpen(Demuxer* dmux_ptr) } dmux.is_finished = true; - if (Emu.IsStopped()) cellDmux->Warning("Demuxer thread aborted"); }); return dmux_id; diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp index b1d2cacf1c..e44573d2c7 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp @@ -551,7 +551,6 @@ u32 vdecOpen(VideoDecoder* vdec_ptr) } vdec.is_finished = true; - if (Emu.IsStopped()) cellVdec->Warning("VideoDecoder thread aborted"); }); return vdec_id; From d557ba2d970a830254eb2497a7353d37f0a71f66 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Sun, 18 Jan 2015 02:01:08 +0300 Subject: [PATCH 7/7] Audio format changed to 8ch --- rpcs3/Emu/Audio/AL/OpenALThread.cpp | 4 ++-- rpcs3/Emu/Audio/AudioManager.h | 4 ++-- rpcs3/Emu/Audio/XAudio2/XAudio2Thread.cpp | 7 +++--- rpcs3/Emu/RSX/RSXThread.cpp | 16 +++----------- rpcs3/Emu/SysCalls/Modules/cellAudio.cpp | 25 ++++++++++++++-------- rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp | 8 +++---- rpcs3/Emu/System.cpp | 10 +++------ 7 files changed, 34 insertions(+), 40 deletions(-) diff --git a/rpcs3/Emu/Audio/AL/OpenALThread.cpp b/rpcs3/Emu/Audio/AL/OpenALThread.cpp index 38e1be699e..14fcd2dc5e 100644 --- a/rpcs3/Emu/Audio/AL/OpenALThread.cpp +++ b/rpcs3/Emu/Audio/AL/OpenALThread.cpp @@ -100,7 +100,7 @@ void OpenALThread::Open(const void* src, int size) for (uint i = 0; i lock(m_cs_main); @@ -2402,7 +2399,7 @@ void RSXThread::Task() m_sem_flush.post_and_wait(); } - std::this_thread::sleep_for (std::chrono::milliseconds(1)); // hack + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack continue; } @@ -2469,24 +2466,17 @@ void RSXThread::Task() value += (count + 1) * 4; }); } - catch (const std::string& e) { LOG_ERROR(RSX, "Exception: %s", e.c_str()); Emu.Pause(); } - catch (const char* e) { LOG_ERROR(RSX, "Exception: %s", e); Emu.Pause(); } - while (!is_vblank_stopped) - { - std::this_thread::sleep_for (std::chrono::milliseconds(1)); // hack - } - LOG_NOTICE(RSX, "RSX thread ended"); OnExitThread(); diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp index d7e24e4bae..7f84d1ec2f 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp @@ -54,7 +54,7 @@ s32 cellAudioInit() const bool do_dump = Ini.AudioDumpToFile.GetValue(); AudioDumper m_dump; - if (do_dump && !m_dump.Init(8)) // Init AudioDumper for 8 channels + if (do_dump && !m_dump.Init(2)) // Init AudioDumper for 2 channels { throw "AudioDumper::Init() failed"; } @@ -62,13 +62,13 @@ s32 cellAudioInit() float buf2ch[2 * BUFFER_SIZE]; // intermediate buffer for 2 channels float buf8ch[8 * BUFFER_SIZE]; // intermediate buffer for 8 channels - static const size_t out_buffer_size = 2 * BUFFER_SIZE; + static const size_t out_buffer_size = 8 * BUFFER_SIZE; // output buffer for 8 channels std::unique_ptr out_buffer[BUFFER_NUM]; for (u32 i = 0; i < BUFFER_NUM; i++) { - out_buffer[i].reset(new float[2 * BUFFER_SIZE] {}); + out_buffer[i].reset(new float[out_buffer_size] {}); } squeue_t out_queue; @@ -347,9 +347,16 @@ s32 cellAudioInit() if (!first_mix) { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i++) + // copy output data (2 ch) + //for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i++) + //{ + // out_buffer[out_pos][i] = buf2ch[i]; + //} + + // copy output data (8 ch) + for (u32 i = 0; i < (sizeof(buf8ch) / sizeof(float)); i++) { - out_buffer[out_pos][i] = buf2ch[i]; + out_buffer[out_pos][i] = buf8ch[i]; } } @@ -399,16 +406,16 @@ s32 cellAudioInit() { if (m_dump.GetCh() == 8) { - if (m_dump.WriteData(&buf8ch, sizeof(buf8ch)) != sizeof(buf8ch)) // write file data + if (m_dump.WriteData(&buf8ch, sizeof(buf8ch)) != sizeof(buf8ch)) // write file data (8 ch) { - throw "AudioDumper::WriteData() failed (2 ch)"; + throw "AudioDumper::WriteData() failed (8 ch)"; } } else if (m_dump.GetCh() == 2) { - if (m_dump.WriteData(&buf2ch, sizeof(buf2ch)) != sizeof(buf2ch)) // write file data + if (m_dump.WriteData(&buf2ch, sizeof(buf2ch)) != sizeof(buf2ch)) // write file data (2 ch) { - throw "AudioDumper::WriteData() failed (8 ch)"; + throw "AudioDumper::WriteData() failed (2 ch)"; } } else diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp b/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp index 8ad6d0c650..33059ed1aa 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp @@ -390,7 +390,7 @@ int cellAudioOutGetSoundAvailability(u32 audioOut, u32 type, u32 fs, u32 option) option = 0; - int available = 2; // should be at least 2 + int available = 8; // should be at least 2 switch(fs) { @@ -431,7 +431,7 @@ int cellAudioOutGetSoundAvailability2(u32 audioOut, u32 type, u32 fs, u32 ch, u3 option = 0; - int available = 2; // should be at least 2 + int available = 8; // should be at least 2 switch(fs) { @@ -578,9 +578,9 @@ int cellAudioOutGetDeviceInfo(u32 audioOut, u32 deviceIndex, vm::ptrstate = CELL_AUDIO_OUT_DEVICE_STATE_AVAILABLE; info->latency = 1000; info->availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM; - info->availableModes[0].channel = CELL_AUDIO_OUT_CHNUM_2; + info->availableModes[0].channel = CELL_AUDIO_OUT_CHNUM_8; info->availableModes[0].fs = CELL_AUDIO_OUT_FS_48KHZ; - info->availableModes[0].layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_2CH; + info->availableModes[0].layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_8CH_LREClrxy; return CELL_AUDIO_OUT_SUCCEEDED; } diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 8696a631d0..9944a5860f 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -354,17 +354,13 @@ void Emulator::Stop() SendDbgCommand(DID_STOP_EMU); m_status = Stopped; - u32 uncounted = 0; - while (true) + while (g_thread_count) { - if (g_thread_count <= uncounted) - { - LOG_NOTICE(HLE, "All threads stopped..."); - break; - } std::this_thread::sleep_for(std::chrono::milliseconds(1)); } + LOG_NOTICE(HLE, "All threads stopped..."); + m_rsx_callback = 0; // TODO: check finalization order