diff --git a/Source/Core/Core/HW/GBACore.cpp b/Source/Core/Core/HW/GBACore.cpp index 55a268c28a..0e42a3ec66 100644 --- a/Source/Core/Core/HW/GBACore.cpp +++ b/Source/Core/Core/HW/GBACore.cpp @@ -5,9 +5,6 @@ #include "Core/HW/GBACore.h" -#define PYCPARSE // Remove static functions from the header -#include -#undef PYCPARSE #include #include #include @@ -163,11 +160,23 @@ Core::Core(::Core::System& system, int device_number) : m_device_number(device_number), m_system(system) { mLogSetDefaultLogger(&s_stub_logger); + + MutexInit(&m_core_sync.videoFrameMutex); + ConditionInit(&m_core_sync.videoFrameAvailableCond); + ConditionInit(&m_core_sync.videoFrameRequiredCond); + ConditionInit(&m_core_sync.audioRequiredCond); + MutexInit(&m_core_sync.audioBufferMutex); } Core::~Core() { Stop(); + + MutexDeinit(&m_core_sync.videoFrameMutex); + ConditionDeinit(&m_core_sync.videoFrameAvailableCond); + ConditionDeinit(&m_core_sync.videoFrameRequiredCond); + ConditionDeinit(&m_core_sync.audioRequiredCond); + MutexDeinit(&m_core_sync.audioBufferMutex); } bool Core::Start(u64 gc_ticks) @@ -258,6 +267,8 @@ bool Core::Start(u64 gc_ticks) AddCallbacks(); SetupEvent(); + m_core->setSync(m_core, &m_core_sync); + m_core->reset(m_core); m_started = true; start_guard.Dismiss(); @@ -450,34 +461,43 @@ void Core::AddCallbacks() m_core->addCoreCallbacks(m_core, &callbacks); } +static void ReadAudioBufferIntoMixer(mAudioBuffer* audio_buffer, Mixer* mixer, + std::size_t device_number) +{ + std::array sample_buffer; + const auto read_size = sample_buffer.size() / audio_buffer->channels; + while (true) + { + const auto sample_count = mAudioBufferRead(audio_buffer, sample_buffer.data(), read_size); + if (sample_count == 0) + break; + mixer->PushGBASamples(device_number, sample_buffer.data(), sample_count); + } +} + void Core::SetAVStream() { - m_stream = {}; - m_stream.core = this; - m_stream.videoDimensionsChanged = [](mAVStream* stream, unsigned width, unsigned height) { - auto core = static_cast(stream)->core; + m_stream = { + .core = this, + .mixer = m_system.GetSoundStream()->GetMixer(), + }; + + m_stream.videoDimensionsChanged = [](mAVStream* stream, unsigned /*width*/, unsigned /*height*/) { + auto* core = static_cast(stream)->core; core->SetVideoBuffer(); }; m_stream.audioRateChanged = [](mAVStream* stream, unsigned rate) { - auto* core = static_cast(stream)->core; - auto* const sound_stream = core->m_system.GetSoundStream(); - sound_stream->GetMixer()->SetGBAInputSampleRate(core->m_device_number, rate); + auto* const av_stream = static_cast(stream); + auto* const core = av_stream->core; + auto* const audio_buffer = core->GetAudioBuffer(); + ReadAudioBufferIntoMixer(audio_buffer, av_stream->mixer, av_stream->core->m_device_number); + av_stream->mixer->SetGBAInputSampleRate(core->m_device_number, rate); }; m_stream.postAudioBuffer = [](mAVStream* stream, mAudioBuffer* audio_buffer) { - size_t sample_count = mAudioBufferAvailable(audio_buffer); - const size_t required_buffer_size = sample_count * audio_buffer->channels; - auto* const av_stream = static_cast(stream); - if (required_buffer_size > av_stream->sample_buffer.size()) - av_stream->sample_buffer.reset(required_buffer_size); - - sample_count = mAudioBufferRead(audio_buffer, av_stream->sample_buffer.data(), sample_count); - - auto* const core = av_stream->core; - auto* const sound_stream = core->m_system.GetSoundStream(); - sound_stream->GetMixer()->PushGBASamples(core->m_device_number, av_stream->sample_buffer.data(), - sample_count); + ReadAudioBufferIntoMixer(audio_buffer, av_stream->mixer, av_stream->core->m_device_number); }; + m_core->setAVStream(m_core, &m_stream); } @@ -485,12 +505,8 @@ void Core::SetupEvent() { m_event.context = this; m_event.name = "Dolphin Sync"; - m_event.callback = [](mTiming* timing, void* context, u32 cycles_late) { - Core* core = static_cast(context); - if (core->m_core->platform(core->m_core) == mPLATFORM_GBA) - static_cast<::GBA*>(core->m_core->board)->earlyExit = true; - else if (core->m_core->platform(core->m_core) == mPLATFORM_GB) - static_cast<::GB*>(core->m_core->board)->earlyExit = true; + m_event.callback = [](mTiming* /*timing*/, void* context, u32 /*cycles_late*/) { + auto* const core = static_cast(context); core->m_waiting_for_event = false; }; m_event.priority = 0x80; diff --git a/Source/Core/Core/HW/GBACore.h b/Source/Core/Core/HW/GBACore.h index 47f5a3102e..3427f8eb0f 100644 --- a/Source/Core/Core/HW/GBACore.h +++ b/Source/Core/Core/HW/GBACore.h @@ -12,18 +12,22 @@ #include #include -#define PYCPARSE // Remove static functions from the header -#include -#undef PYCPARSE #include +#include +#if !defined(_WIN32) +#define USE_PTHREADS // Required for Mutex/Condition in mCoreSync. +#endif +#include +#undef USE_PTHREADS #include -#include "Common/Buffer.h" #include "Common/CommonTypes.h" #include "Common/WorkQueueThread.h" class GBAHostInterface; +class Mixer; class PointerWrap; + namespace Core { class System; @@ -31,15 +35,18 @@ class System; namespace HW::GBA { + class Core; + struct SIODriver : GBASIODriver { Core* core; }; + struct AVStream : mAVStream { Core* core; - Common::UniqueBuffer sample_buffer; + Mixer* mixer; }; struct CoreInfo @@ -134,6 +141,7 @@ private: std::string m_game_title; mCore* m_core{}; + mCoreSync m_core_sync{}; mTimingEvent m_event{}; bool m_waiting_for_event = false; SIODriver m_sio_driver{}; @@ -164,5 +172,7 @@ private: ::Core::System& m_system; }; + } // namespace HW::GBA + #endif // HAS_LIBMGBA