diff --git a/UnleashedRecomp/CMakeLists.txt b/UnleashedRecomp/CMakeLists.txt index e45beef9..239c85c4 100644 --- a/UnleashedRecomp/CMakeLists.txt +++ b/UnleashedRecomp/CMakeLists.txt @@ -212,7 +212,6 @@ set(SWA_THIRDPARTY_INCLUDES "${SWA_THIRDPARTY_ROOT}/imgui" "${SWA_THIRDPARTY_ROOT}/libmspack/libmspack/mspack" "${SWA_THIRDPARTY_ROOT}/magic_enum/include" - "${SWA_THIRDPARTY_ROOT}/miniaudio" "${SWA_THIRDPARTY_ROOT}/stb" "${SWA_THIRDPARTY_ROOT}/tiny-AES-c" "${SWA_THIRDPARTY_ROOT}/TinySHA1" diff --git a/UnleashedRecomp/apu/driver/sdl2_driver.cpp b/UnleashedRecomp/apu/driver/sdl2_driver.cpp index 12bca12f..7c8777e7 100644 --- a/UnleashedRecomp/apu/driver/sdl2_driver.cpp +++ b/UnleashedRecomp/apu/driver/sdl2_driver.cpp @@ -7,20 +7,8 @@ static PPCFunc* g_clientCallback{}; static uint32_t g_clientCallbackParam{}; // pointer in guest memory static SDL_AudioDeviceID g_audioDevice{}; -static std::unique_ptr g_audioCtx; -static uint32_t* g_audioOutput; static bool g_downMixToStereo; -static void AudioCallback(void*, uint8_t* frames, int len) -{ - if (g_audioCtx == nullptr) - g_audioCtx = std::make_unique(0); - - g_audioCtx->ppcContext.r3.u64 = g_clientCallbackParam; - g_audioOutput = reinterpret_cast(frames); - (*g_clientCallback)(g_audioCtx->ppcContext, reinterpret_cast(g_memory.base)); -} - void XAudioInitializeSystem() { SDL_SetHint(SDL_HINT_AUDIO_CATEGORY, "playback"); @@ -32,7 +20,6 @@ void XAudioInitializeSystem() desired.format = AUDIO_F32SYS; desired.channels = XAUDIO_NUM_CHANNELS; desired.samples = XAUDIO_NUM_SAMPLES; - desired.callback = AudioCallback; g_audioDevice = SDL_OpenAudioDevice(nullptr, 0, &desired, &obtained, SDL_AUDIO_ALLOW_CHANNELS_CHANGE); if (obtained.channels != 2 && obtained.channels != XAUDIO_NUM_CHANNELS) @@ -44,6 +31,44 @@ void XAudioInitializeSystem() g_downMixToStereo = (obtained.channels == 2); } +static std::unique_ptr g_audioThread; + +static void AudioThread() +{ + using namespace std::chrono_literals; + + GuestThreadContext ctx(0); + + size_t channels = g_downMixToStereo ? 2 : XAUDIO_NUM_CHANNELS; + + constexpr double INTERVAL = double(XAUDIO_NUM_SAMPLES) / double(XAUDIO_SAMPLES_HZ); + auto start = std::chrono::steady_clock::now(); + size_t iteration = 1; + + while (true) + { + uint32_t queuedAudioSize = SDL_GetQueuedAudioSize(g_audioDevice); + constexpr size_t MAX_LATENCY = 10; + const size_t callbackAudioSize = channels * XAUDIO_NUM_SAMPLES * sizeof(float); + + if ((queuedAudioSize / callbackAudioSize) <= MAX_LATENCY) + { + ctx.ppcContext.r3.u32 = g_clientCallbackParam; + g_clientCallback(ctx.ppcContext, reinterpret_cast(g_memory.base)); + } + + auto next = start + std::chrono::duration(iteration * INTERVAL); + auto now = std::chrono::steady_clock::now(); + + if ((next - now) > 1s) + next = now; + + std::this_thread::sleep_until(next); + + iteration = std::chrono::duration(std::chrono::steady_clock::now() - start).count() / INTERVAL + 1; + } +} + void XAudioRegisterClient(PPCFunc* callback, uint32_t param) { auto* pClientParam = static_cast(g_userHeap.Alloc(sizeof(param))); @@ -53,6 +78,7 @@ void XAudioRegisterClient(PPCFunc* callback, uint32_t param) g_clientCallback = callback; SDL_PauseAudioDevice(g_audioDevice, 0); + g_audioThread = std::make_unique(AudioThread); } void XAudioSubmitFrame(void* samples) @@ -68,6 +94,8 @@ void XAudioSubmitFrame(void* samples) auto floatSamples = reinterpret_cast*>(samples); + std::array audioFrames; + for (size_t i = 0; i < XAUDIO_NUM_SAMPLES; i++) { float ch0 = floatSamples[0 * XAUDIO_NUM_SAMPLES + i]; @@ -77,21 +105,24 @@ void XAudioSubmitFrame(void* samples) float ch4 = floatSamples[4 * XAUDIO_NUM_SAMPLES + i]; float ch5 = floatSamples[5 * XAUDIO_NUM_SAMPLES + i]; - float left = ch0 + ch2 * 0.75f + ch4; - float right = ch1 + ch2 * 0.75f + ch5; - - g_audioOutput[i * 2 + 0] = *reinterpret_cast(&left); - g_audioOutput[i * 2 + 1] = *reinterpret_cast(&right); + audioFrames[i * 2 + 0] = ch0 + ch2 * 0.75f + ch4; + audioFrames[i * 2 + 1] = ch1 + ch2 * 0.75f + ch5; } + + SDL_QueueAudio(g_audioDevice, &audioFrames, sizeof(audioFrames)); } else { auto rawSamples = reinterpret_cast*>(samples); + std::array audioFrames; + for (size_t i = 0; i < XAUDIO_NUM_SAMPLES; i++) { for (size_t j = 0; j < XAUDIO_NUM_CHANNELS; j++) - g_audioOutput[i * XAUDIO_NUM_CHANNELS + j] = rawSamples[j * XAUDIO_NUM_SAMPLES + i]; + audioFrames[i * XAUDIO_NUM_CHANNELS + j] = rawSamples[j * XAUDIO_NUM_SAMPLES + i]; } + + SDL_QueueAudio(g_audioDevice, &audioFrames, sizeof(audioFrames)); } } diff --git a/UnleashedRecomp/cpu/guest_thread.cpp b/UnleashedRecomp/cpu/guest_thread.cpp index 32412b40..290fc51c 100644 --- a/UnleashedRecomp/cpu/guest_thread.cpp +++ b/UnleashedRecomp/cpu/guest_thread.cpp @@ -32,6 +32,7 @@ GuestThreadContext::GuestThreadContext(uint32_t cpuNumber) ppcContext.fn = (uint8_t*)g_codeCache.bucket; ppcContext.r1.u64 = g_memory.MapVirtual(thread + PCR_SIZE + TLS_SIZE + TEB_SIZE + STACK_SIZE); // stack pointer ppcContext.r13.u64 = g_memory.MapVirtual(thread); + ppcContext.fpscr.loadFromHost(); assert(GetPPCContext() == nullptr); SetPPCContext(ppcContext); @@ -77,7 +78,7 @@ uint32_t GuestThread::Start(const GuestThreadParams& params) GuestThreadContext ctx(cpuNumber); ctx.ppcContext.r3.u64 = params.value; - GuestCode::Run(g_codeCache.Find(params.function), &ctx.ppcContext, g_memory.Translate(0)); + reinterpret_cast(g_codeCache.Find(params.function))(ctx.ppcContext, reinterpret_cast(g_memory.base)); return ctx.ppcContext.r3.u32; } diff --git a/UnleashedRecomp/kernel/imports.cpp b/UnleashedRecomp/kernel/imports.cpp index d570d16a..e206b47b 100644 --- a/UnleashedRecomp/kernel/imports.cpp +++ b/UnleashedRecomp/kernel/imports.cpp @@ -76,16 +76,16 @@ static std::atomic g_keSetEventGeneration; struct Semaphore final : KernelObject, HostObject { - std::atomic count; + std::counting_semaphore<> semaphore; uint32_t maximumCount; Semaphore(XKSEMAPHORE* semaphore) - : count(semaphore->Header.SignalState), maximumCount(semaphore->Limit) + : semaphore(semaphore->Header.SignalState), maximumCount(semaphore->Limit) { } Semaphore(uint32_t count, uint32_t maximumCount) - : count(count), maximumCount(maximumCount) + : semaphore(count), maximumCount(maximumCount) { } @@ -93,32 +93,11 @@ struct Semaphore final : KernelObject, HostObject { if (timeout == 0) { - uint32_t currentCount = count.load(); - if (currentCount != 0) - { - if (count.compare_exchange_weak(currentCount, currentCount - 1)) - return STATUS_SUCCESS; - } - - return STATUS_TIMEOUT; + return semaphore.try_acquire() ? STATUS_SUCCESS : STATUS_TIMEOUT; } else if (timeout == INFINITE) { - uint32_t currentCount; - while (true) - { - currentCount = count.load(); - if (currentCount != 0) - { - if (count.compare_exchange_weak(currentCount, currentCount - 1)) - return STATUS_SUCCESS; - } - else - { - count.wait(0); - } - } - + semaphore.acquire(); return STATUS_SUCCESS; } else @@ -130,13 +109,7 @@ struct Semaphore final : KernelObject, HostObject void Release(uint32_t releaseCount, uint32_t* previousCount) { - if (previousCount != nullptr) - *previousCount = count; - - assert(count + releaseCount <= maximumCount); - - count += releaseCount; - count.notify_all(); + semaphore.release(releaseCount); } };