diff --git a/Aerofoil/GpMain_Win32.cpp b/Aerofoil/GpMain_Win32.cpp index 3ae45b3..041dba4 100644 --- a/Aerofoil/GpMain_Win32.cpp +++ b/Aerofoil/GpMain_Win32.cpp @@ -448,6 +448,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine g_gpGlobalConfig.m_osGlobals = &g_gpWindowsGlobals; g_gpGlobalConfig.m_logger = logger; + g_gpGlobalConfig.m_systemServices = GpSystemServices_Win32::GetInstance(); GpDisplayDriverFactory::RegisterDisplayDriverFactory(EGpDisplayDriverType_D3D11, GpDriver_CreateDisplayDriver_D3D11); GpAudioDriverFactory::RegisterAudioDriverFactory(EGpAudioDriverType_XAudio2, GpDriver_CreateAudioDriver_XAudio2); diff --git a/Aerofoil/GpSystemServices_Win32.cpp b/Aerofoil/GpSystemServices_Win32.cpp index 0a2229d..2824dc0 100644 --- a/Aerofoil/GpSystemServices_Win32.cpp +++ b/Aerofoil/GpSystemServices_Win32.cpp @@ -56,6 +56,11 @@ PortabilityLayer::HostMutex *GpSystemServices_Win32::CreateMutex() return GpMutex_Win32::Create(); } +PortabilityLayer::HostMutex *GpSystemServices_Win32::CreateRecursiveMutex() +{ + return GpMutex_Win32::Create(); +} + PortabilityLayer::HostThreadEvent *GpSystemServices_Win32::CreateThreadEvent(bool autoReset, bool startSignaled) { return GpThreadEvent_Win32::Create(autoReset, startSignaled); diff --git a/Aerofoil/GpSystemServices_Win32.h b/Aerofoil/GpSystemServices_Win32.h index 28e5e5f..934783e 100644 --- a/Aerofoil/GpSystemServices_Win32.h +++ b/Aerofoil/GpSystemServices_Win32.h @@ -18,6 +18,7 @@ public: int64_t GetTime() const override; void GetLocalDateTime(unsigned int &year, unsigned int &month, unsigned int &day, unsigned int &hour, unsigned int &minute, unsigned int &second) const override; PortabilityLayer::HostMutex *CreateMutex() override; + PortabilityLayer::HostMutex *CreateRecursiveMutex() override; PortabilityLayer::HostThreadEvent *CreateThreadEvent(bool autoReset, bool startSignaled) override; uint64_t GetFreeMemoryCosmetic() const override; void Beep() const override; diff --git a/AerofoilSDL/AerofoilSDL.vcxproj b/AerofoilSDL/AerofoilSDL.vcxproj index 23ce25a..afee054 100644 --- a/AerofoilSDL/AerofoilSDL.vcxproj +++ b/AerofoilSDL/AerofoilSDL.vcxproj @@ -91,6 +91,7 @@ + diff --git a/AerofoilSDL/AerofoilSDL.vcxproj.filters b/AerofoilSDL/AerofoilSDL.vcxproj.filters index ebadabc..26bb538 100644 --- a/AerofoilSDL/AerofoilSDL.vcxproj.filters +++ b/AerofoilSDL/AerofoilSDL.vcxproj.filters @@ -60,6 +60,9 @@ Source Files + + Source Files + diff --git a/AerofoilSDL/GpAudioDriver_SDL2.cpp b/AerofoilSDL/GpAudioDriver_SDL2.cpp new file mode 100644 index 0000000..b0aca13 --- /dev/null +++ b/AerofoilSDL/GpAudioDriver_SDL2.cpp @@ -0,0 +1,560 @@ +#include "IGpAudioDriver.h" +#include "IGpAudioChannel.h" +#include "IGpAudioChannelCallbacks.h" +#include "IGpPrefsHandler.h" +#include "GpAudioDriverProperties.h" +#include "CoreDefs.h" + +#include "HostMutex.h" +#include "HostSystemServices.h" + +#include "SDL_audio.h" +#include "GpRingBuffer.h" + +#include "SDL_atomic.h" + +#include +#include +#include +#include + +class GpAudioDriver_SDL2; + +static void *AlignedAlloc(size_t size, size_t alignment) +{ + void *storage = malloc(size + alignment); + if (!storage) + return nullptr; + + uintptr_t alignedPtr = reinterpret_cast(storage); + size_t padding = alignment - static_cast(alignedPtr % alignment); + + uint8_t *storageLoc = static_cast(storage); + uint8_t *objectLoc = storageLoc + padding; + uint8_t *paddingSizeLoc = storageLoc + padding - 1; + + *reinterpret_cast(paddingSizeLoc) = static_cast(padding); + + return objectLoc; +} + +static void AlignedFree(void *ptr) +{ + size_t padding = static_cast(ptr)[-1]; + void *storageLoc = static_cast(ptr) - padding; + + free(storageLoc); +} + +struct GpAudioChannelBufferChain_SDL2 final +{ + GpAudioChannelBufferChain_SDL2(); + + static GpAudioChannelBufferChain_SDL2 *Alloc(); + void Release(); + + static const size_t kMaxCapacity = 65536; + + size_t m_consumed; + size_t m_used; + uint8_t m_data[kMaxCapacity]; + GpAudioChannelBufferChain_SDL2 *m_next; + bool m_hasTrigger; +}; + +GP_ALIGNED(GP_SYSTEM_MEMORY_ALIGNMENT) class GpAudioChannel_SDL2 final : public IGpAudioChannel +{ +public: + enum ChannelState + { + ChannelState_Idle, + ChannelState_Playing, + ChannelState_Stopped, + }; + + friend class GpAudioDriver_SDL2; + + GpAudioChannel_SDL2(); + ~GpAudioChannel_SDL2(); + + void AddRef(); + void Release(); + + void SetAudioChannelContext(IGpAudioChannelCallbacks *callbacks) override; + void PostBuffer(const void *buffer, size_t bufferSize) override; + void Stop() override; + void Destroy() override; + + void Consume(uint8_t *output, size_t sz); + + static GpAudioChannel_SDL2 *Alloc(GpAudioDriver_SDL2 *driver); + +private: + bool Init(GpAudioDriver_SDL2 *driver); + + IGpAudioChannelCallbacks *m_callbacks; + PortabilityLayer::HostMutex *m_mutex; + GpAudioDriver_SDL2 *m_owner; + + SDL_atomic_t m_refCount; + + GpAudioChannelBufferChain_SDL2 *m_firstPendingBuffer; + GpAudioChannelBufferChain_SDL2 *m_lastPendingBuffer; + + ChannelState m_channelState; +}; + +GP_ALIGNED(GP_SYSTEM_MEMORY_ALIGNMENT) class GpAudioDriver_SDL2 final : public IGpAudioDriver, public IGpPrefsHandler +{ +public: + friend class GpAudioChannel_SDL2; + + explicit GpAudioDriver_SDL2(const GpAudioDriverProperties &properties); + ~GpAudioDriver_SDL2(); + + IGpAudioChannel *CreateChannel() override; + void SetMasterVolume(uint32_t vol, uint32_t maxVolume) override; + void Shutdown() override; + IGpPrefsHandler *GetPrefsHandler() const override; + + void ApplyPrefs(const void *identifier, size_t identifierSize, const void *contents, size_t contentsSize, uint32_t version) override; + bool SavePrefs(void *context, WritePrefsFunc_t writeFunc) override; + + bool Init(); + +private: + void DetachAudioChannel(GpAudioChannel_SDL2 *channel); + + static void SDLCALL StaticMixAudio(void *userdata, Uint8 *stream, int len); + + void MixAudio(void *stream, size_t len); + void RefillMixChunk(GpAudioChannel_SDL2 *const*channels, size_t numChannels); + + GpAudioDriverProperties m_properties; + PortabilityLayer::HostMutex *m_mutex; + PortabilityLayer::HostMutex *m_mixState; + + static const size_t kMaxChannels = 16; + static const size_t kMixChunkSize = 256; + + GpAudioChannel_SDL2 *m_channels[kMaxChannels]; + size_t m_numChannels; + + bool m_sdlAudioRunning; + + GP_ALIGNED(GP_SYSTEM_MEMORY_ALIGNMENT) int16_t m_mixChunk[kMixChunkSize]; + size_t m_mixChunkReadOffset; +}; + +GpAudioChannelBufferChain_SDL2::GpAudioChannelBufferChain_SDL2() + : m_used(0) + , m_consumed(0) + , m_next(nullptr) + , m_hasTrigger(false) +{ +} + + +GpAudioChannelBufferChain_SDL2 *GpAudioChannelBufferChain_SDL2::Alloc() +{ + void *storage = AlignedAlloc(sizeof(GpAudioChannelBufferChain_SDL2), GP_SYSTEM_MEMORY_ALIGNMENT); + return new (storage) GpAudioChannelBufferChain_SDL2(); +} + +void GpAudioChannelBufferChain_SDL2::Release() +{ + this->~GpAudioChannelBufferChain_SDL2(); + AlignedFree(this); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// GpAudioChannel + +GpAudioChannel_SDL2::GpAudioChannel_SDL2() + : m_callbacks(nullptr) + , m_mutex(nullptr) + , m_owner(nullptr) + , m_firstPendingBuffer(nullptr) + , m_lastPendingBuffer(nullptr) +{ + SDL_AtomicSet(&m_refCount, 1); +} + +GpAudioChannel_SDL2::~GpAudioChannel_SDL2() +{ + Stop(); + + if (m_mutex) + m_mutex->Destroy(); + + while (m_firstPendingBuffer) + { + GpAudioChannelBufferChain_SDL2 *buffer = m_firstPendingBuffer; + m_firstPendingBuffer = buffer->m_next; + buffer->Release(); + } +} + +void GpAudioChannel_SDL2::AddRef() +{ + SDL_AtomicIncRef(&m_refCount); +} + +void GpAudioChannel_SDL2::Release() +{ + if (SDL_AtomicDecRef(&m_refCount)) + { + this->~GpAudioChannel_SDL2(); + AlignedFree(this); + } +} + + +void GpAudioChannel_SDL2::SetAudioChannelContext(IGpAudioChannelCallbacks *callbacks) +{ + m_callbacks = callbacks; +} + +void GpAudioChannel_SDL2::PostBuffer(const void *buffer, size_t bufferSize) +{ + m_mutex->Lock(); + + while (bufferSize > 0) + { + GpAudioChannelBufferChain_SDL2 *newBuffer = GpAudioChannelBufferChain_SDL2::Alloc(); + if (newBuffer == nullptr) + break; + + if (m_lastPendingBuffer == nullptr) + m_firstPendingBuffer = newBuffer; + else + m_lastPendingBuffer->m_next = newBuffer; + m_lastPendingBuffer = newBuffer; + + size_t bufferable = newBuffer->kMaxCapacity; + if (bufferSize < bufferable) + bufferable = bufferSize; + + memcpy(newBuffer->m_data, buffer, bufferable); + + buffer = static_cast(buffer) + bufferable; + bufferSize -= bufferable; + m_lastPendingBuffer->m_used = bufferable; + m_lastPendingBuffer->m_hasTrigger = (bufferSize == 0); + } + + m_mutex->Unlock(); +} + +void GpAudioChannel_SDL2::Stop() +{ + m_mutex->Lock(); + + GpAudioChannelBufferChain_SDL2 *buffer = m_firstPendingBuffer; + m_firstPendingBuffer = nullptr; + m_lastPendingBuffer = nullptr; + + while (buffer) + { + if (buffer->m_hasTrigger && m_callbacks) + m_callbacks->NotifyBufferFinished(); + + GpAudioChannelBufferChain_SDL2 *nextBuffer = buffer->m_next; + buffer->Release(); + + buffer = nextBuffer; + } + + m_mutex->Unlock(); +} + +void GpAudioChannel_SDL2::Destroy() +{ + if (m_owner) + m_owner->DetachAudioChannel(this); + + this->Release(); +} + +bool GpAudioChannel_SDL2::Init(GpAudioDriver_SDL2 *driver) +{ + m_owner = driver; + m_mutex = driver->m_properties.m_systemServices->CreateRecursiveMutex(); + if (!m_mutex) + return false; + + return true; +} + +void GpAudioChannel_SDL2::Consume(uint8_t *output, size_t sz) +{ + m_mutex->Lock(); + + while (m_firstPendingBuffer != nullptr) + { + GpAudioChannelBufferChain_SDL2 *buffer = m_firstPendingBuffer; + const size_t available = (buffer->m_used - buffer->m_consumed); + if (available <= sz) + { + memcpy(output, buffer->m_data + buffer->m_consumed, available); + sz -= available; + output += available; + + m_firstPendingBuffer = buffer->m_next; + if (m_firstPendingBuffer == nullptr) + m_lastPendingBuffer = nullptr; + + if (buffer->m_hasTrigger && m_callbacks) + m_callbacks->NotifyBufferFinished(); + + buffer->Release(); + + if (sz == 0) + break; + } + else + { + memcpy(output, buffer->m_data + buffer->m_consumed, sz); + buffer->m_consumed += sz; + buffer += sz; + sz = 0; + break; + } + } + + m_mutex->Unlock(); + + memset(output, 0x80, sz); +} + +GpAudioChannel_SDL2 *GpAudioChannel_SDL2::Alloc(GpAudioDriver_SDL2 *driver) +{ + void *storage = AlignedAlloc(sizeof(GpAudioChannel_SDL2), GP_SYSTEM_MEMORY_ALIGNMENT); + if (!storage) + return nullptr; + + GpAudioChannel_SDL2 *channel = new (storage) GpAudioChannel_SDL2(); + if (!channel->Init(driver)) + { + channel->Destroy(); + return nullptr; + } + + return channel; +} + + +///////////////////////////////////////////////////////////////////////////////////////// +// GpAudioDriver_SDL2 + +GpAudioDriver_SDL2::GpAudioDriver_SDL2(const GpAudioDriverProperties &properties) + : m_properties(properties) + , m_mutex(nullptr) + , m_numChannels(0) + , m_sdlAudioRunning(false) + , m_mixChunkReadOffset(kMixChunkSize) + +{ + for (size_t i = 0; i < kMaxChannels; i++) + m_channels[i] = nullptr; + + for (size_t i = 0; i < kMixChunkSize; i++) + m_mixChunk[i] = 0; +} + +GpAudioDriver_SDL2::~GpAudioDriver_SDL2() +{ + if (m_sdlAudioRunning) + SDL_CloseAudio(); + + if (m_mutex) + m_mutex->Destroy(); +} + +IGpAudioChannel *GpAudioDriver_SDL2::CreateChannel() +{ + GpAudioChannel_SDL2 *newChannel = GpAudioChannel_SDL2::Alloc(this); + if (!newChannel) + return nullptr; + + m_mutex->Lock(); + if (m_numChannels == kMaxChannels) + { + newChannel->Destroy(); + m_mutex->Unlock(); + return nullptr; + } + + m_channels[m_numChannels] = newChannel; + m_numChannels++; + + m_mutex->Unlock(); + + return newChannel; +} + +void GpAudioDriver_SDL2::SetMasterVolume(uint32_t vol, uint32_t maxVolume) +{ +} + +void GpAudioDriver_SDL2::Shutdown() +{ + this->~GpAudioDriver_SDL2(); + AlignedFree(this); +} + +IGpPrefsHandler *GpAudioDriver_SDL2::GetPrefsHandler() const +{ + return const_cast(this); +} + +void GpAudioDriver_SDL2::ApplyPrefs(const void *identifier, size_t identifierSize, const void *contents, size_t contentsSize, uint32_t version) +{ +} + +bool GpAudioDriver_SDL2::SavePrefs(void *context, WritePrefsFunc_t writeFunc) +{ + return true; +} + +bool GpAudioDriver_SDL2::Init() +{ + m_mutex = m_properties.m_systemServices->CreateMutex(); + if (!m_mutex) + return false; + + SDL_AudioSpec requestedSpec; + memset(&requestedSpec, 0, sizeof(requestedSpec)); + + requestedSpec.callback = GpAudioDriver_SDL2::StaticMixAudio; + requestedSpec.channels = 1; + requestedSpec.format = AUDIO_S16; + requestedSpec.freq = m_properties.m_sampleRate; + requestedSpec.samples = 512; + requestedSpec.userdata = this; + + if (SDL_OpenAudio(&requestedSpec, nullptr)) + { + requestedSpec.freq = 22050; + if (SDL_OpenAudio(&requestedSpec, nullptr)) + return false; + } + + SDL_PauseAudio(0); + + m_sdlAudioRunning = true; + + return true; +} + +void GpAudioDriver_SDL2::DetachAudioChannel(GpAudioChannel_SDL2 *channel) +{ + m_mutex->Lock(); + const size_t numChannels = m_numChannels; + for (size_t i = 0; i < numChannels; i++) + { + if (m_channels[i] == channel) + { + m_numChannels = numChannels - 1; + m_channels[i] = m_channels[numChannels - 1]; + m_channels[numChannels - 1] = nullptr; + break; + } + } + m_mutex->Unlock(); +} + +void GpAudioDriver_SDL2::StaticMixAudio(void *userdata, Uint8 *stream, int len) +{ + static_cast(userdata)->MixAudio(stream, static_cast(len)); +} + +void GpAudioDriver_SDL2::MixAudio(void *stream, size_t len) +{ + GpAudioChannel_SDL2 *mixingChannels[kMaxChannels]; + size_t numChannels = 0; + + m_mutex->Lock(); + numChannels = m_numChannels; + for (size_t i = 0; i < numChannels; i++) + { + GpAudioChannel_SDL2 *channel = m_channels[i]; + channel->AddRef(); + + mixingChannels[i] = channel; + } + m_mutex->Unlock(); + + size_t samplesRemaining = len / sizeof(int16_t); + + for (;;) + { + size_t availableInMixChunk = kMixChunkSize - m_mixChunkReadOffset; + + if (availableInMixChunk > samplesRemaining) + { + m_mixChunkReadOffset += samplesRemaining; + memcpy(stream, m_mixChunk + m_mixChunkReadOffset, samplesRemaining * sizeof(int16_t)); + + break; + } + else + { + memcpy(stream, m_mixChunk + m_mixChunkReadOffset, availableInMixChunk * sizeof(int16_t)); + + stream = static_cast(stream) + availableInMixChunk; + samplesRemaining -= availableInMixChunk; + + m_mixChunkReadOffset = 0; + RefillMixChunk(mixingChannels, numChannels); + } + } + + for (size_t i = 0; i < numChannels; i++) + mixingChannels[i]->Release(); +} + +void GpAudioDriver_SDL2::RefillMixChunk(GpAudioChannel_SDL2 *const*channels, size_t numChannels) +{ + uint8_t audioMixBufferUnaligned[kMixChunkSize + GP_SYSTEM_MEMORY_ALIGNMENT]; + uint8_t *audioMixBuffer = audioMixBufferUnaligned; + + { + uintptr_t bufferPtr = reinterpret_cast(audioMixBuffer); + size_t alignPadding = GP_SYSTEM_MEMORY_ALIGNMENT - (bufferPtr % GP_SYSTEM_MEMORY_ALIGNMENT); + audioMixBuffer += alignPadding; + } + + for (size_t i = 0; i < numChannels; i++) + { + channels[i]->Consume(audioMixBuffer, kMixChunkSize); + + if (i == 0) + { + for (size_t j = 0; j < kMixChunkSize; j++) + m_mixChunk[j] = audioMixBuffer[j] - 0x80; + } + else + { + for (size_t j = 0; j < kMixChunkSize; j++) + m_mixChunk[j] += audioMixBuffer[j] - 0x80; + } + } +} + + +IGpAudioDriver *GpDriver_CreateAudioDriver_SDL(const GpAudioDriverProperties &properties) +{ + void *storage = AlignedAlloc(sizeof(GpAudioDriver_SDL2), GP_SYSTEM_MEMORY_ALIGNMENT); + if (!storage) + return nullptr; + + GpAudioDriver_SDL2 *driver = new (storage) GpAudioDriver_SDL2(properties); + if (!driver->Init()) + { + driver->Shutdown(); + return nullptr; + } + + return driver; +} diff --git a/AerofoilSDL/GpMain_SDL_Win32.cpp b/AerofoilSDL/GpMain_SDL_Win32.cpp index 1491b2e..5800385 100644 --- a/AerofoilSDL/GpMain_SDL_Win32.cpp +++ b/AerofoilSDL/GpMain_SDL_Win32.cpp @@ -29,11 +29,11 @@ GpWindowsGlobals g_gpWindowsGlobals; -extern "C" __declspec(dllimport) IGpAudioDriver *GpDriver_CreateAudioDriver_XAudio2(const GpAudioDriverProperties &properties); extern "C" __declspec(dllimport) IGpInputDriver *GpDriver_CreateInputDriver_XInput(const GpInputDriverProperties &properties); extern "C" __declspec(dllimport) IGpFontHandler *GpDriver_CreateFontHandler_FreeType2(const GpFontHandlerProperties &properties); IGpDisplayDriver *GpDriver_CreateDisplayDriver_SDL_GL2(const GpDisplayDriverProperties &properties); +IGpAudioDriver *GpDriver_CreateAudioDriver_SDL(const GpAudioDriverProperties &properties); static void PostMouseEvent(IGpVOSEventQueue *eventQueue, GpMouseEventType_t eventType, GpMouseButton_t button, int32_t x, int32_t y, float pixelScaleX, float pixelScaleY) { @@ -438,7 +438,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine g_gpGlobalConfig.m_displayDriverType = EGpDisplayDriverType_SDL_GL2; - g_gpGlobalConfig.m_audioDriverType = EGpAudioDriverType_XAudio2; + g_gpGlobalConfig.m_audioDriverType = EGpAudioDriverType_SDL2; g_gpGlobalConfig.m_fontHandlerType = EGpFontHandlerType_FreeType2; @@ -452,9 +452,10 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine g_gpGlobalConfig.m_osGlobals = &g_gpWindowsGlobals; g_gpGlobalConfig.m_logger = logger; + g_gpGlobalConfig.m_systemServices = GpSystemServices_Win32::GetInstance(); GpDisplayDriverFactory::RegisterDisplayDriverFactory(EGpDisplayDriverType_SDL_GL2, GpDriver_CreateDisplayDriver_SDL_GL2); - GpAudioDriverFactory::RegisterAudioDriverFactory(EGpAudioDriverType_XAudio2, GpDriver_CreateAudioDriver_XAudio2); + GpAudioDriverFactory::RegisterAudioDriverFactory(EGpAudioDriverType_SDL2, GpDriver_CreateAudioDriver_SDL); GpInputDriverFactory::RegisterInputDriverFactory(EGpInputDriverType_XInput, GpDriver_CreateInputDriver_XInput); GpFontHandlerFactory::RegisterFontHandlerFactory(EGpFontHandlerType_FreeType2, GpDriver_CreateFontHandler_FreeType2); diff --git a/Common/CoreDefs.h b/Common/CoreDefs.h index 06c56ac..48031a6 100644 --- a/Common/CoreDefs.h +++ b/Common/CoreDefs.h @@ -6,6 +6,12 @@ #define GP_IS_CPP11 0 #endif +#ifdef _MSC_VER +#define GP_ALIGNED(n) __declspec(align(n)) +#else +#define GP_ALIGNED(n) __attribute__((aligned(n))) +#endif + #if GP_IS_CPP11 #define GP_DELETED = delete #define GP_STATIC_ASSERT(n) static_assert((n), "Static assert failed: " #n) diff --git a/GpCommon/EGpAudioDriverType.h b/GpCommon/EGpAudioDriverType.h index 5351735..7f589e3 100644 --- a/GpCommon/EGpAudioDriverType.h +++ b/GpCommon/EGpAudioDriverType.h @@ -3,6 +3,7 @@ enum EGpAudioDriverType { EGpAudioDriverType_XAudio2, + EGpAudioDriverType_SDL2, EGpAudioDriverType_Count, }; diff --git a/GpCommon/GpAudioDriverProperties.h b/GpCommon/GpAudioDriverProperties.h index 9f802cd..f2ff2c2 100644 --- a/GpCommon/GpAudioDriverProperties.h +++ b/GpCommon/GpAudioDriverProperties.h @@ -2,6 +2,11 @@ #include "EGpAudioDriverType.h" +namespace PortabilityLayer +{ + class HostSystemServices; +} + struct IGpAudioDriver; struct IGpLogDriver; @@ -13,4 +18,5 @@ struct GpAudioDriverProperties bool m_debug; IGpLogDriver *m_logger; + PortabilityLayer::HostSystemServices *m_systemServices; }; diff --git a/GpCommon/GpRingBuffer.h b/GpCommon/GpRingBuffer.h index 2e8eb4b..96585f3 100644 --- a/GpCommon/GpRingBuffer.h +++ b/GpCommon/GpRingBuffer.h @@ -19,19 +19,43 @@ public: { assert(index < m_Size); return m_Items[(m_Start + index) % TCapacity]; - } + } void RemoveFromStart() { assert(m_Size >= 1); m_Start = (m_Start + 1) % TCapacity; m_Size--; + } + + const uint8_t *GetContiguousAtStart(size_t count) + { + assert(m_Size >= count); + assert(m_Start + count <= TCapacity); + const uint8_t *ptr = m_Items + m_Start; + m_Start = (m_Start + count) % TCapacity; + m_Size -= count; + + return ptr; + } + + void RemoveCountFromStart(size_t count) + { + assert(m_Size >= count); + m_Start = (m_Start + count) % TCapacity; + m_Size -= count; } void RemoveFromEnd() { assert(m_Size >= 1); m_Size--; + } + + void RemoveCountFromEnd(size_t count) + { + assert(m_Size >= count); + m_Size -= count; } void Clear() @@ -52,12 +76,54 @@ public: m_Size++; return &m_Items[(m_Start + (m_Size - 1)) % TCapacity]; + } + + size_t SizeContiguous() const + { + if (m_Size >= TCapacity - m_Start) + return TCapacity - m_Start; + else + return m_Size; } + size_t AppendMultiple(size_t quantity, TItem *& outPtr) + { + if (TCapacity - m_Start > m_Size) + { + const size_t available = TCapacity - (m_Start + m_Size); + outPtr = m_Items + m_Start + m_Size; + if (available < quantity) + { + m_Size += available; + return available; + } + else + { + m_Size += quantity; + return quantity; + } + } + else + { + const size_t available = TCapacity - m_Size; + outPtr = m_Items + ((m_Start + m_Size) % TCapacity); + if (available < quantity) + { + m_Size += available; + return available; + } + else + { + m_Size += quantity; + return quantity; + } + } + } + static const size_t CAPACITY = TCapacity; private: TItem m_Items[TCapacity]; size_t m_Size; size_t m_Start; -}; \ No newline at end of file +}; diff --git a/GpCommon/IGpAudioChannel.h b/GpCommon/IGpAudioChannel.h index 3d34a26..cbbb080 100644 --- a/GpCommon/IGpAudioChannel.h +++ b/GpCommon/IGpAudioChannel.h @@ -1,11 +1,11 @@ #pragma once -struct IGpAudioChannelCallbacks; +struct IGpAudioChannelCallbacks; struct IGpAudioChannel { virtual void SetAudioChannelContext(IGpAudioChannelCallbacks *callbacks) = 0; virtual void PostBuffer(const void *buffer, size_t bufferSize) = 0; virtual void Stop() = 0; - virtual void Destroy() = 0; + virtual void Destroy() = 0; }; diff --git a/GpShell/GpGlobalConfig.h b/GpShell/GpGlobalConfig.h index b3bb9f0..d1cf59e 100644 --- a/GpShell/GpGlobalConfig.h +++ b/GpShell/GpGlobalConfig.h @@ -5,7 +5,12 @@ #include "EGpFontHandlerType.h" #include "EGpInputDriverType.h" -struct IGpLogDriver; +struct IGpLogDriver; + +namespace PortabilityLayer +{ + class HostSystemServices; +} struct GpGlobalConfig { @@ -17,6 +22,7 @@ struct GpGlobalConfig size_t m_numInputDrivers; IGpLogDriver *m_logger; + PortabilityLayer::HostSystemServices *m_systemServices; void *m_osGlobals; }; diff --git a/GpShell/GpMain.cpp b/GpShell/GpMain.cpp index 350e982..0a35c6e 100644 --- a/GpShell/GpMain.cpp +++ b/GpShell/GpMain.cpp @@ -85,6 +85,7 @@ int GpMain::Run() adProps.m_debug = true; #endif adProps.m_logger = g_gpGlobalConfig.m_logger; + adProps.m_systemServices = g_gpGlobalConfig.m_systemServices; IGpInputDriver **inputDrivers = static_cast(malloc(sizeof(IGpInputDriver*) * g_gpGlobalConfig.m_numInputDrivers)); diff --git a/PortabilityLayer/HostSystemServices.h b/PortabilityLayer/HostSystemServices.h index 9af144a..a9b0503 100644 --- a/PortabilityLayer/HostSystemServices.h +++ b/PortabilityLayer/HostSystemServices.h @@ -19,6 +19,7 @@ namespace PortabilityLayer virtual int64_t GetTime() const = 0; virtual void GetLocalDateTime(unsigned int &year, unsigned int &month, unsigned int &day, unsigned int &hour, unsigned int &minute, unsigned int &second) const = 0; virtual HostMutex *CreateMutex() = 0; + virtual HostMutex *CreateRecursiveMutex() = 0; virtual HostThreadEvent *CreateThreadEvent(bool autoReset, bool startSignaled) = 0; virtual size_t GetFreeMemoryCosmetic() const = 0; // Returns free memory in bytes, does not have to be accurate virtual void Beep() const = 0;