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;