diff --git a/src/app/app_core.c b/src/app/app_core.c index 98892718..a8f78b5c 100644 --- a/src/app/app_core.c +++ b/src/app/app_core.c @@ -248,7 +248,7 @@ void P_AppStartup(String args_str) SimStartupReceipt sim_sr = sim_startup(); /* Interface systems */ - PB_StartupReceipt playback_sr = playback_startup(&mixer_sr); + PB_StartupReceipt playback_sr = PB_Startup(&mixer_sr); struct user_startup_receipt user_sr = user_startup(&font_sr, &sprite_sr, &draw_sr, &asset_cache_sr, &sound_sr, &mixer_sr, &sim_sr, connect_address); (UNUSED)user_sr; diff --git a/src/base/base_core.h b/src/base/base_core.h index b0dea057..51a3211c 100644 --- a/src/base/base_core.h +++ b/src/base/base_core.h @@ -83,6 +83,15 @@ extern "C" { # define LanguageIsC 1 #endif +//- Windows NTDDI version +/* FIXME: Remove this */ +#if 0 +#if PlatformIsWindows +# define NTDDI_WIN11_DT 0x0C0A0000 +# define NTDDI_VERSION 0x0A000000 +#endif +#endif + //////////////////////////////// //~ Debug diff --git a/src/base/base_fiber.c b/src/base/base_fiber.c index 37299c06..bab456ff 100644 --- a/src/base/base_fiber.c +++ b/src/base/base_fiber.c @@ -1,9 +1,14 @@ #if PlatformIsWindows +//////////////////////////////// +//~ Windows headers #define WIN32_LEAN_AND_MEAN #define UNICODE #include +//////////////////////////////// +//~ FiberId + i16 FiberId(void) { return (i16)(i64)GetFiberData(); diff --git a/src/base/base_incbin.c b/src/base/base_incbin.c index 20212cc5..7ce9795a 100644 --- a/src/base/base_incbin.c +++ b/src/base/base_incbin.c @@ -1,9 +1,15 @@ #if CompilerIsMsvc +//////////////////////////////// +//~ Windows headers + #define WIN32_LEAN_AND_MEAN #define UNICODE #include +//////////////////////////////// +//~ Incbin + /* Find first resource with `type` and return the data in `udata`. */ BOOL CALLBACK IncbinEnumerateResourceNamesFunc(HMODULE module, LPCWSTR type, LPCWSTR wstr_entry_name, LONG_PTR udata) { diff --git a/src/base/base_memory.c b/src/base/base_memory.c index 21fadb11..5f709fa9 100644 --- a/src/base/base_memory.c +++ b/src/base/base_memory.c @@ -1,13 +1,15 @@ +#if PlatformIsWindows //////////////////////////////// -//~ Memory allocation - -#if PlatformIsWindows +//~ Windows headers #define WIN32_LEAN_AND_MEAN #define UNICODE #include +//////////////////////////////// +//~ Memory allocation + //- Reserve void *ReserveMemory(u64 size) { diff --git a/src/dxc/dxc_core_win32.cpp b/src/dxc/dxc_core_win32.cpp index 2dedccb5..a7336146 100644 --- a/src/dxc/dxc_core_win32.cpp +++ b/src/dxc/dxc_core_win32.cpp @@ -16,6 +16,9 @@ DXC_Result DXC_Compile(Arena *arena, String shader_source, i32 num_args, String # pragma clang diagnostic ignored "-Wlanguage-extension-token" #endif +//////////////////////////////// +//~ Windows headers + #pragma warning(push, 0) # define WIN32_LEAN_AND_MEAN # define UNICODE @@ -28,6 +31,9 @@ DXC_Result DXC_Compile(Arena *arena, String shader_source, i32 num_args, String #pragma comment(lib, "d3dcompiler") #pragma comment(lib, "dxcompiler") +//////////////////////////////// +//~ Compile + /* https://github.com/microsoft/DirectXShaderCompiler/wiki/Using-dxc.exe-and-dxcompiler.dll */ DXC_Result DXC_Compile(Arena *arena, String shader_source, i32 num_args, String *args) { diff --git a/src/gp/gp_core_dx12.c b/src/gp/gp_core_dx12.c index f379918a..922da0bd 100644 --- a/src/gp/gp_core_dx12.c +++ b/src/gp/gp_core_dx12.c @@ -1,3 +1,6 @@ +//////////////////////////////// +//~ Windows headers + #pragma warning(push, 0) # define UNICODE # define COBJMACROS @@ -20,6 +23,9 @@ # pragma comment(lib, "advapi32") #endif +//////////////////////////////// +//~ Dx12 + #define DX12_ALLOW_TEARING 1 #define DX12_WAIT_FRAME_LATENCY 1 #define DX12_SWAPCHAIN_FLAGS (((DX12_ALLOW_TEARING != 0) * DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) | ((DX12_WAIT_FRAME_LATENCY != 0) * DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT)) diff --git a/src/mp3/mp3.h b/src/mp3/mp3.h index b24ced56..6ae91e50 100644 --- a/src/mp3/mp3.h +++ b/src/mp3/mp3.h @@ -5,19 +5,4 @@ #include "mp3_core.h" -#if PlatformIsWindows - #pragma warning(push, 0) -# define COBJMACROS -# define WIN32_LEAN_AND_MEAN -# define UNICODE -# include -# include -# include -# include -# include -# include -# pragma warning(pop) -# include "mp3_mmf.h" -#endif - #endif diff --git a/src/mp3/mp3_mmf.c b/src/mp3/mp3_mmf.c index 438503bc..f35dfc91 100644 --- a/src/mp3/mp3_mmf.c +++ b/src/mp3/mp3_mmf.c @@ -1,7 +1,25 @@ +//////////////////////////////// +//~ Windows headers + +#pragma warning(push, 0) +# define COBJMACROS +# define WIN32_LEAN_AND_MEAN +# define UNICODE +# include +# include +# include +# include +# include +# include +#pragma warning(pop) + #pragma comment(lib, "mfplat") #pragma comment(lib, "mfreadwrite") #pragma comment(lib, "shlwapi") +//////////////////////////////// +//~ Decode + MP3_Result MP3_Decode(Arena *arena, String encoded, u32 sample_rate, MP3_DecodeFlag flags) { MP3_Result result = ZI; diff --git a/src/mp3/mp3_mmf.h b/src/mp3/mp3_mmf.h deleted file mode 100644 index e69de29b..00000000 diff --git a/src/platform/platform.h b/src/platform/platform.h index fa98c422..053f2d51 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -8,24 +8,6 @@ #include "platform_log.h" #if PlatformIsWindows -# pragma warning(push, 0) -# define UNICODE -# define WIN32_LEAN_AND_MEAN -/* FIXME: Remove this */ -# define NTDDI_WIN11_DT 0x0C0A0000 -# define NTDDI_VERSION 0x0A000000 -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# pragma warning(pop) # include "platform_win32.h" #endif diff --git a/src/platform/platform_win32.h b/src/platform/platform_win32.h index 7bda8516..a1755548 100644 --- a/src/platform/platform_win32.h +++ b/src/platform/platform_win32.h @@ -1,3 +1,22 @@ +//////////////////////////////// +//~ Win32 headers + +#pragma warning(push, 0) +# define UNICODE +# define WIN32_LEAN_AND_MEAN +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#pragma warning(pop) + //////////////////////////////// //~ Ticket mutex types diff --git a/src/playback/playback.c b/src/playback/playback.c index e254378f..4a7f6ea2 100644 --- a/src/playback/playback.c +++ b/src/playback/playback.c @@ -1,7 +1,7 @@ #include "playback.h" #if PlatformIsWindows -# include "playback_core_win32.c" +# include "playback_win32.c" #else # error Playback core not implemented for this platform #endif diff --git a/src/playback/playback.h b/src/playback/playback.h index 9ed64c6f..92189091 100644 --- a/src/playback/playback.h +++ b/src/playback/playback.h @@ -7,4 +7,8 @@ #include "playback_core.h" +#if PlatformIsWindows +# include "playback_win32.h" +#endif + #endif diff --git a/src/playback/playback_core.h b/src/playback/playback_core.h index 78e31f28..06a409d3 100644 --- a/src/playback/playback_core.h +++ b/src/playback/playback_core.h @@ -1,2 +1,4 @@ +#define PB_SampleRate 48000 + Struct(PB_StartupReceipt) { i32 _; }; -PB_StartupReceipt playback_startup(M_StartupReceipt *mixer_sr); +PB_StartupReceipt PB_Startup(M_StartupReceipt *mixer_sr); diff --git a/src/playback/playback_core_win32.c b/src/playback/playback_win32.c similarity index 54% rename from src/playback/playback_core_win32.c rename to src/playback/playback_win32.c index 8622fe66..65a523a0 100644 --- a/src/playback/playback_core_win32.c +++ b/src/playback/playback_win32.c @@ -1,77 +1,39 @@ -/* ========================== * - * WASAPI backend for audio playback +/* WASAPI backend for audio playback * - * Based on mmozeiko's WASAPI example + * Based on mmozeiko's WASAPI examples * https://gist.github.com/mmozeiko/5a5b168e61aff4c1eaec0381da62808f#file-win32_wasapi-h - * ========================== */ + */ -#define COBJMACROS -#define WIN32_LEAN_AND_MEAN -#define UNICODE -#include -#include -#include -#include -#include -#include +PB_WSP_SharedState PB_WSP_shared_state = ZI; -DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xbcde0395, 0xe52f, 0x467c, 0x8e, 0x3d, 0xc4, 0x57, 0x92, 0x91, 0x69, 0x2e); -DEFINE_GUID(IID_IMMDeviceEnumerator, 0xa95664d2, 0x9614, 0x4f35, 0xa7, 0x46, 0xde, 0x8d, 0xb6, 0x36, 0x17, 0xe6); -DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1, 0x78, 0xc2, 0xf5, 0x68, 0xa7, 0x03, 0xb2); -DEFINE_GUID(IID_IAudioClient3, 0x7ed4ee07, 0x8e67, 0x4cd4, 0x8c, 0x1a, 0x2b, 0x7a, 0x59, 0x87, 0xad, 0x42); -DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7, 0xbf, 0xad, 0xdc, 0xa7, 0xc2, 0x60, 0xe2); +//////////////////////////////// +//~ Startup -#define PLAYBACK_SAMPLE_RATE 48000 - -struct wasapi_buffer { - u32 frames_count; - u8 *frames; -}; - -Global struct { - Atomic32 shutdown; - IAudioClient *client; - HANDLE event; - IAudioRenderClient *playback; - WAVEFORMATEX *buffer_format; - u32 buffer_frames; - P_Counter playback_job_counter; -} G = ZI, DebugAlias(G, G_playback_wasapi); - -/* ========================== * - * Startup - * ========================== */ - -internal void wasapi_initialize(void); -internal P_ExitFuncDef(playback_shutdown); -internal P_JobDef(playback_job, _); - -PB_StartupReceipt playback_startup(M_StartupReceipt *mixer_sr) +PB_StartupReceipt PB_Startup(M_StartupReceipt *mixer_sr) { __prof; + PB_WSP_SharedState *g = &PB_WSP_shared_state; (UNUSED)mixer_sr; - wasapi_initialize(); + PB_WSP_InitializeWasapi(); /* Start playback job */ - P_Run(1, playback_job, 0, P_Pool_Audio, P_Priority_High, &G.playback_job_counter); - P_OnExit(&playback_shutdown); + P_Run(1, PB_WSP_PlaybackJob, 0, P_Pool_Audio, P_Priority_High, &g->PB_WSP_PlaybackJob_counter); + P_OnExit(&PB_WSP_Shutdown); return (PB_StartupReceipt) { 0 }; } -internal P_ExitFuncDef(playback_shutdown) +P_ExitFuncDef(PB_WSP_Shutdown) { __prof; - Atomic32FetchSet(&G.shutdown, 1); - P_WaitOnCounter(&G.playback_job_counter); + PB_WSP_SharedState *g = &PB_WSP_shared_state; + Atomic32FetchSet(&g->shutdown, 1); + P_WaitOnCounter(&g->PB_WSP_PlaybackJob_counter); } -/* ========================== * - * Wasapi initialization - * ========================== */ - -internal void wasapi_initialize(void) +void PB_WSP_InitializeWasapi(void) { - u64 sample_rate = PLAYBACK_SAMPLE_RATE; + PB_WSP_SharedState *g = &PB_WSP_shared_state; + u64 sample_rate = PB_SampleRate; u64 channel_count = 2; u32 channel_mask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; @@ -85,7 +47,7 @@ internal void wasapi_initialize(void) IMMDeviceEnumerator_Release(enumerator); /* Create audio client for device */ - IMMDevice_Activate(device, &IID_IAudioClient, CLSCTX_ALL, 0, (LPVOID *)&G.client); + IMMDevice_Activate(device, &IID_IAudioClient, CLSCTX_ALL, 0, (LPVOID *)&g->client); IMMDevice_Release(device); WAVEFORMATEXTENSIBLE format_ex = { @@ -107,7 +69,8 @@ internal void wasapi_initialize(void) #if 0 b32 client_initialized = 0; IAudioClient3 *client3; - if (SUCCEEDED(IAudioClient_QueryInterface(G.client, &IID_IAudioClient3, (LPVOID *)&client3))) { + if (SUCCEEDED(IAudioClient_QueryInterface(g->client, &IID_IAudioClient3, (LPVOID *)&client3))) + { /* From Martins: Minimum buffer size will typically be 480 samples (10msec @ 48khz) * but it can be 128 samples (2.66 msec @ 48khz) if driver is properly installed * see bullet-point instructions here: https://learn.microsoft.com/en-us/windows-hardware/drivers/audio/low-latency-audio#measurement-tools @@ -116,7 +79,8 @@ internal void wasapi_initialize(void) IAudioClient3_GetSharedModeEnginePeriod(client3, wfx, &default_period_samples, &fundamental_period_samples, &min_period_samples, &max_period_samples); const DWORD flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK; - if (SUCCEEDED(IAudioClient3_InitializeSharedAudioStream(client3, flags, min_period_samples, wfx, 0))) { + if (SUCCEEDED(IAudioClient3_InitializeSharedAudioStream(client3, flags, min_period_samples, wfx, 0))) + { client_initialized = 1; } @@ -126,10 +90,11 @@ internal void wasapi_initialize(void) b32 client_initialized = 0; #endif - if (!client_initialized) { + if (!client_initialized) + { /* Get duration for shared-mode streams, this will typically be 480 samples (10msec @ 48khz) */ REFERENCE_TIME duration; - IAudioClient_GetDevicePeriod(G.client, &duration, 0); + IAudioClient_GetDevicePeriod(g->client, &duration, 0); /* Initialize audio playback * @@ -139,66 +104,71 @@ internal void wasapi_initialize(void) * but allows for any input format. */ const DWORD flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY; - IAudioClient_Initialize(G.client, AUDCLNT_SHAREMODE_SHARED, flags, duration, 0, wfx, 0); + IAudioClient_Initialize(g->client, AUDCLNT_SHAREMODE_SHARED, flags, duration, 0, wfx, 0); } - IAudioClient_GetMixFormat(G.client, &G.buffer_format); + IAudioClient_GetMixFormat(g->client, &g->buffer_format); /* Set up event handler to wait on */ - G.event = CreateEventW(0, 0, 0, 0); - IAudioClient_SetEventHandle(G.client, G.event); + g->event = CreateEventW(0, 0, 0, 0); + IAudioClient_SetEventHandle(g->client, g->event); /* Get playback client */ - IAudioClient_GetService(G.client, &IID_IAudioRenderClient, (LPVOID *)&G.playback); + IAudioClient_GetService(g->client, &IID_IAudioRenderClient, (LPVOID *)&g->playback); /* Start the playback */ - IAudioClient_Start(G.client); + IAudioClient_Start(g->client); /* Get audio buffer size in samples */ - IAudioClient_GetBufferSize(G.client, &G.buffer_frames); + IAudioClient_GetBufferSize(g->client, &g->buffer_frames); } -/* ========================== * - * Playback thread update - * ========================== */ +//////////////////////////////// +//~ Wasapi update -internal struct wasapi_buffer wasapi_update_begin(void) +PB_WSP_Buff PB_WSP_BeginUpdate(void) { __prof; - struct wasapi_buffer wspbuf = ZI; + PB_WSP_SharedState *g = &PB_WSP_shared_state; + PB_WSP_Buff wspbuf = ZI; /* Get padding frames */ u32 padding_frames; - IAudioClient_GetCurrentPadding(G.client, &padding_frames); + IAudioClient_GetCurrentPadding(g->client, &padding_frames); /* Get output buffer from WASAPI */ wspbuf.frames_count = 0; - if (padding_frames <= G.buffer_frames) { - wspbuf.frames_count = G.buffer_frames - padding_frames; + if (padding_frames <= g->buffer_frames) + { + wspbuf.frames_count = g->buffer_frames - padding_frames; } - IAudioRenderClient_GetBuffer(G.playback, wspbuf.frames_count, &wspbuf.frames); + IAudioRenderClient_GetBuffer(g->playback, wspbuf.frames_count, &wspbuf.frames); return wspbuf; } -internal void wasapi_update_end(struct wasapi_buffer *wspbuf, M_PcmF32 src) +void PB_WSP_EndUpdate(PB_WSP_Buff *wspbuf, M_PcmF32 src) { __prof; + PB_WSP_SharedState *g = &PB_WSP_shared_state; u32 frames_in_source = src.count / 2; u32 frames_in_output = wspbuf->frames_count; u32 flags = 0; - if (frames_in_source == frames_in_output) { + if (frames_in_source == frames_in_output) + { /* Copy bytes to output */ - u32 bytes_per_sample = G.buffer_format->nBlockAlign / G.buffer_format->nChannels; + u32 bytes_per_sample = g->buffer_format->nBlockAlign / g->buffer_format->nChannels; u32 write_size = frames_in_source * 2 * bytes_per_sample; CopyBytes(wspbuf->frames, src.samples, write_size); - } else { + } + else + { /* Submit silence if not enough samples */ flags = AUDCLNT_BUFFERFLAGS_SILENT; /* This shouldn't occur, mixer should be generating samples equivilent - * to value returned from `wasapi_update_begin`. */ + * to value returned from `PB_WSP_BeginUpdate`. */ Assert(0); } @@ -207,33 +177,34 @@ internal void wasapi_update_end(struct wasapi_buffer *wspbuf, M_PcmF32 src) #endif /* Submit output buffer to WASAPI */ - IAudioRenderClient_ReleaseBuffer(G.playback, frames_in_source, flags); + IAudioRenderClient_ReleaseBuffer(g->playback, frames_in_source, flags); __profframe("Audio"); } -/* ========================== * - * Playback thread entry - * ========================== */ +//////////////////////////////// +//~ Playback job -internal P_JobDef(playback_job, _) +P_JobDef(PB_WSP_PlaybackJob, _) { __prof; + PB_WSP_SharedState *g = &PB_WSP_shared_state; (UNUSED)_; /* FIXME: If playback fails at any point and mixer stops advancing, we * need to halt mixer to prevent memory leak when sounds are played. */ /* TODO: Signal counter that running job wiats on, rather than scheduling job manually */ - while (!Atomic32Fetch(&G.shutdown)) { + while (!Atomic32Fetch(&g->shutdown)) + { TempArena scratch = BeginScratchNoConflict(); { __profn("Wasapi wait"); - WaitForSingleObject(G.event, INFINITE); + WaitForSingleObject(g->event, INFINITE); } { __profn("Fill sample buffer"); - struct wasapi_buffer wspbuf = wasapi_update_begin(); + PB_WSP_Buff wspbuf = PB_WSP_BeginUpdate(); M_PcmF32 pcm = M_MixAllTracks(scratch.arena, wspbuf.frames_count); - wasapi_update_end(&wspbuf, pcm); + PB_WSP_EndUpdate(&wspbuf, pcm); } EndScratch(scratch); } diff --git a/src/playback/playback_win32.h b/src/playback/playback_win32.h new file mode 100644 index 00000000..e8a64476 --- /dev/null +++ b/src/playback/playback_win32.h @@ -0,0 +1,64 @@ +//////////////////////////////// +//~ Win32 headers + +#pragma warning(push, 0) +# define COBJMACROS +# define WIN32_LEAN_AND_MEAN +# define UNICODE +# include +# include +# include +# include +# include +# include +#pragma warning(pop) + +DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xbcde0395, 0xe52f, 0x467c, 0x8e, 0x3d, 0xc4, 0x57, 0x92, 0x91, 0x69, 0x2e); +DEFINE_GUID(IID_IMMDeviceEnumerator, 0xa95664d2, 0x9614, 0x4f35, 0xa7, 0x46, 0xde, 0x8d, 0xb6, 0x36, 0x17, 0xe6); +DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1, 0x78, 0xc2, 0xf5, 0x68, 0xa7, 0x03, 0xb2); +DEFINE_GUID(IID_IAudioClient3, 0x7ed4ee07, 0x8e67, 0x4cd4, 0x8c, 0x1a, 0x2b, 0x7a, 0x59, 0x87, 0xad, 0x42); +DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7, 0xbf, 0xad, 0xdc, 0xa7, 0xc2, 0x60, 0xe2); + +//////////////////////////////// +//~ Wasapi buffer types + +Struct(PB_WSP_Buff) +{ + u32 frames_count; + u8 *frames; +}; + +//////////////////////////////// +//~ Shared state + +Struct(PB_WSP_SharedState) +{ + Atomic32 shutdown; + IAudioClient *client; + HANDLE event; + IAudioRenderClient *playback; + WAVEFORMATEX *buffer_format; + u32 buffer_frames; + P_Counter PB_WSP_PlaybackJob_counter; +}; + +extern PB_WSP_SharedState PB_WSP_shared_state; + +//////////////////////////////// +//~ Wasapi startup + +void PB_WSP_InitializeWasapi(void); +P_ExitFuncDef(PB_WSP_Shutdown); +P_JobDef(PB_WSP_PlaybackJob, _); +P_ExitFuncDef(PB_WSP_Shutdown); + +//////////////////////////////// +//~ Playback update + +PB_WSP_Buff PB_WSP_BeginUpdate(void); +void PB_WSP_EndUpdate(PB_WSP_Buff *wspbuf, M_PcmF32 src); + +//////////////////////////////// +//~ Playback job + +P_JobDef(PB_WSP_PlaybackJob, _); diff --git a/src/ttf/ttf_core_dwrite.cpp b/src/ttf/ttf_core_dwrite.cpp index 64f51391..a2836f83 100644 --- a/src/ttf/ttf_core_dwrite.cpp +++ b/src/ttf/ttf_core_dwrite.cpp @@ -1,7 +1,10 @@ /* Based on Allen Webster's dwrite rasterizer example - * https://github.com/4th-dimention/examps */ +#define WIN32_LEAN_AND_MEAN +#define UNICODE #pragma warning(push, 0) +# include # include # include #pragma warning(pop)