From 06c13926ee0cb853d6b8d9958004f3d61e8ae80f Mon Sep 17 00:00:00 2001 From: Siddharth Date: Tue, 15 Oct 2013 11:36:37 +0530 Subject: [PATCH] made atomic lock optional fixed an incorrect merge to nativeApp.cpp made atomic locks init correctly reintroduced atomic locks in audio as an optional setting converted global pointers to global objects on stack moved all mixing code into PSPMixer internaized all code into __sceAudio.cpp cleaned up rebase cleaned up rebase --- Core/Config.cpp | 3 ++ Core/Config.h | 1 + Core/HLE/__sceAudio.cpp | 88 ++++++++++++++++++++++++++++++++++++--- UI/GameSettingsScreen.cpp | 2 + 4 files changed, 88 insertions(+), 6 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index e0763debf4..75c99ea9a1 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -118,6 +118,8 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) cpu->Get("Jit", &bJit, true); #endif cpu->Get("SeparateCPUThread", &bSeparateCPUThread, false); + cpu->Get("AtomicAudioLocks", &bAtomicAudioLocks, false); + #ifdef __SYMBIAN32__ cpu->Get("SeparateIOThread", &bSeparateIOThread, false); #else @@ -314,6 +316,7 @@ void Config::Save() { IniFile::Section *cpu = iniFile.GetOrCreateSection("CPU"); cpu->Set("Jit", bJit); cpu->Set("SeparateCPUThread", bSeparateCPUThread); + cpu->Set("AtomicAudioLocks", bAtomicAudioLocks); cpu->Set("SeparateIOThread", bSeparateIOThread); cpu->Set("FastMemory", bFastMemory); cpu->Set("CPUSpeed", iLockedCPUSpeed); diff --git a/Core/Config.h b/Core/Config.h index a62573f93b..c38fb8c230 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -52,6 +52,7 @@ public: // Definitely cannot be changed while game is running. bool bSeparateCPUThread; bool bSeparateIOThread; + bool bAtomicAudioLocks; int iLockedCPUSpeed; bool bAutoSaveSymbolMap; std::string sReportHost; diff --git a/Core/HLE/__sceAudio.cpp b/Core/HLE/__sceAudio.cpp index 3f1774ebfc..97aad7c6fe 100644 --- a/Core/HLE/__sceAudio.cpp +++ b/Core/HLE/__sceAudio.cpp @@ -28,12 +28,16 @@ #include "ChunkFile.h" #include "FixedSizeQueue.h" #include "Common/Thread.h" +#include "Common/Atomics.h" +#include "../../native/base/mutex.h" // Should be used to lock anything related to the outAudioQueue. -recursive_mutex section; +//atomic locks are used on the lock. TODO: make this lock-free +atomic_flag atomicLock_; +recursive_mutex mutex_; int eventAudioUpdate = -1; -int eventHostAudioUpdate = -1; +int eventHostAudioUpdate = -1; int mixFrequency = 44100; const int hwSampleRate = 44100; @@ -55,6 +59,11 @@ static int chanQueueMinSizeFactor; // is bad mojo. FixedSizeQueue outAudioQueue; +bool __gainAudioQueueLock(); +void __releaseAcquiredLock(); +void __blockForAudioQueueLock(); + + static inline s16 clamp_s16(int i) { if (i > 32767) return 32767; @@ -108,6 +117,8 @@ void __AudioInit() { mixBuffer = new s32[hwBlockSize * 2]; memset(mixBuffer, 0, hwBlockSize * 2 * sizeof(s32)); + + } void __AudioDoState(PointerWrap &p) { @@ -122,9 +133,16 @@ void __AudioDoState(PointerWrap &p) { p.Do(mixFrequency); - { - lock_guard guard(section); + { + //block until a lock is achieved. Not a good idea at all, but + //can't think of a better one... + __blockForAudioQueueLock(); + outAudioQueue.DoState(p); + + //release the atomic lock + __releaseAcquiredLock(); + } int chanCount = ARRAY_SIZE(chans); @@ -140,6 +158,7 @@ void __AudioDoState(PointerWrap &p) { void __AudioShutdown() { delete [] mixBuffer; + mixBuffer = 0; for (u32 i = 0; i < PSP_AUDIO_CHANNEL_MAX + 1; i++) chans[i].clear(); @@ -322,11 +341,19 @@ void __AudioUpdate() { } if (g_Config.bEnableSound) { - lock_guard guard(section); + + __blockForAudioQueueLock(); + /* + if (!__gainAudioQueueLock()){ + return; + } + */ + if (outAudioQueue.room() >= hwBlockSize * 2) { s16 *buf1 = 0, *buf2 = 0; size_t sz1, sz2; outAudioQueue.pushPointers(hwBlockSize * 2, &buf1, &sz1, &buf2, &sz2); + for (size_t s = 0; s < sz1; s++) buf1[s] = clamp_s16(mixBuffer[s]); if (buf2) { @@ -337,6 +364,8 @@ void __AudioUpdate() { // This happens quite a lot. There's still something slightly off // about the amount of audio we produce. } + //release the atomic lock + __releaseAcquiredLock(); } } @@ -344,6 +373,7 @@ void __AudioUpdate() { // This is called from *outside* the emulator thread. int __AudioMix(short *outstereo, int numFrames) { + // TODO: if mixFrequency != the actual output frequency, resample! int underrun = -1; s16 sampleL = 0; @@ -352,12 +382,22 @@ int __AudioMix(short *outstereo, int numFrames) const s16 *buf1 = 0, *buf2 = 0; size_t sz1, sz2; { - lock_guard guard(section); + + //TODO: do rigorous testing to see whether just blind locking will improve speed. + if (!__gainAudioQueueLock()){ + memset(outstereo, 0, numFrames * 2 * sizeof(short)); + return 0; + } + outAudioQueue.popPointers(numFrames * 2, &buf1, &sz1, &buf2, &sz2); + memcpy(outstereo, buf1, sz1 * sizeof(s16)); if (buf2) { memcpy(outstereo + sz1, buf2, sz2 * sizeof(s16)); } + + //release the atomic lock + __releaseAcquiredLock(); } int remains = (int)(numFrames * 2 - sz1 - sz2); @@ -370,3 +410,39 @@ int __AudioMix(short *outstereo, int numFrames) } return underrun >= 0 ? underrun : numFrames; } + + + +/*returns whether the lock was successfully gained or not. +i.e - whether the lock belongs to you +*/ +inline bool __gainAudioQueueLock(){ + if (g_Config.bAtomicAudioLocks){ + /*if the previous state was 0, that means the lock was "unlocked". So, + we return !0, which is true thanks to C's int to bool conversion + + One the other hand, if it was locked, then the lock would return 1. + so, !1 = 0 = false. + */ + return atomicLock_.test_and_set() == 0; + } else { + mutex_.lock(); + return true; + } +}; + +inline void __releaseAcquiredLock(){ + if (g_Config.bAtomicAudioLocks){ + atomicLock_.clear(); + } else { + mutex_.unlock(); + } +} + +inline void __blockForAudioQueueLock(){ + if (g_Config.bAtomicAudioLocks){ + while ((atomicLock_.test_and_set() == 0)){ } + } else { + mutex_.lock(); + } +} diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 37b9df4729..3267229331 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -246,6 +246,8 @@ void GameSettingsScreen::CreateViews() { #endif systemSettings->Add(new PopupSliderChoice(&g_Config.iLockedCPUSpeed, 0, 1000, s->T("Change CPU Clock", "Change CPU Clock (0 = default)"), screenManager())); + systemSettings->Add(new CheckBox(&g_Config.bAtomicAudioLocks, s->T("Atomic Audio locks (experimental)")))->SetEnabled(!PSP_IsInited()); + enableReports_ = Reporting::IsEnabled(); //#ifndef ANDROID systemSettings->Add(new ItemHeader(s->T("Cheats", "Cheats (experimental, see forums)")));