From d89ef01fa666b020e182557f4cd7de9722b0a015 Mon Sep 17 00:00:00 2001 From: Charlie Malmqvist Date: Sat, 3 Aug 2024 16:40:41 +0200 Subject: [PATCH] v0.01.003 - Mouse pointers, Audio improvement & features, bug fixes --- TODO | 23 +++-- changelog.txt | 41 ++++++-- oogabooga/cpu.c | 2 +- oogabooga/examples/audio_test.c | 2 +- oogabooga/examples/renderer_stress_test.c | 4 +- oogabooga/growing_array.c | 111 ++++++++++++++++------ oogabooga/os_impl_windows.c | 28 +++--- 7 files changed, 150 insertions(+), 61 deletions(-) diff --git a/TODO b/TODO index 4c6624f..b9a5e1a 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,6 @@ +- Gamepad - Audio - - Avoid playing identical audio at the same time - Allow audio programming - Inject mixer proc per player - Inject a mixer proc before and after filling output buffer @@ -9,14 +9,13 @@ - Handle audio sources which had their format defaulted to update when default device changes For streamed audio sources this should be easy enough, because the conversion happens from raw format to source format as we stream it. For loaded sources though, we would need to convert the source->pcm_frames. + Probably just dirty flag - Optimize - Spam simd - - Concurrent jobs for players? - Pool of intermediate buffers (2^) - - Bugs: - - Small fadeout on pause is slightly noisy - - Setting time stamp/progression causes noise (need fade transition like on pause/play) - - End of clip also causes noise if audio clip does not end smoothly + - Bugs / Issues: + - Small fadeout on start/pause is sometimes noisy + - If audio starts/end abrubtly we will get noise. Maybe detect that on load and apply small fade in/out? - Setting audio source to a format which differs from audio output format in both channels and bit_width at the same time will produce pure loud noise. - 24-Bit audio conversion doesn't really work @@ -38,12 +37,14 @@ - OS - Window::bool is_minimized - don't set window.width & window.height to 0 + - Handle monitor change - Sockets recv, send - Mouse pointer - Hide mouse pointer + +- Better hash table - Memory - - In heap allocator, mark pages that fit entirely into free nodes as NOACCESS - Arenas - Examples/Guides: @@ -51,13 +52,19 @@ - Z sorting - Scissor boxing - Concurrency + - strings - Rework profiler - Store records and convert to google trace format on exit - Measure both time and cycles, output a google_trace_cycles.json & google_trace_time.json +- Concurrency + - Event objects for binary semaphore + - Needs testing: - Audio format channel conversions - sample rate downsampling - non stereo or mono audio - - Audio spacialization on anything that's not stereo \ No newline at end of file + - Audio spacialization on anything that's not stereo + - Compiling with msvc + - Compiling with gcc \ No newline at end of file diff --git a/changelog.txt b/changelog.txt index ddff4da..2e5c059 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,8 +1,12 @@ -## v0.01.003 - Stuff +## v0.01.003 - Mouse pointers, Audio improvement & features, bug fixes - Os layer - Implemented setting of mouse pointers, either to system standard pointers or a custom image - - Ignore SETCURSOR events unless window resize + os_set_mouse_pointer_standard(kind) + os_set_mouse_pointer_custom(pointer) + os_make_custom_mouse_pointer(image, width, height, hotspot_x, hotspot_y) + os_make_custom_mouse_pointer_from_file(path, hotspot_x, hotspot_y, allocator) + - Ignore SETCURSOR events unless for window resize pointer - Store SYSTEM_INFO in init - os_get_number_of_logical_processors() @@ -15,14 +19,35 @@ - os_lock_program_memory_pages - Heap locks pages when completely free + - Audio + - Implemented playback speed configuration + - Implemented a way to recognize audio sources which start playing at the exact same time so we can avoid phase cancellation + - Refactor playback configuration members in Audio_Player to be in a struct Audio_Playback_Configuration + Example: player.volume -> player.config.volume + - bool disable_spacialization -> bool enable_spacialization (inverted) + - Deprecated: + play_one_audio_clip_source_at_position() + play_one_audio_clip_at_position() + - Added: + play_one_audio_clip_source_with_config() + play_one_audio_clip_with_config() + - Removed 'bool retain_progression_factor' parameter in audio_player_set_source() + - Fixed a bug where players didn't loop when set to do so + - Fixed a bug where wav sources would return 4 garbage samples at the start of playback, causing a glitch in the sound + - Fixed a crash when default audio device could not be initialized + - Fixed a bunch of bugs & woopsies + - Updated audio_test.c + - Misc - - Deprecate Rangef stuff - - peek_random() - - Update #Contributions - - Clean up memory barriers in concurrency.c and use volatile instead - - Output d3d11 debug messages before crash on hr fail - - Configurable temporary storage size for new threads + - Deprecated Rangef stuff + - added peek_random() + - Updated #Contributions + - Cleaned up memory barriers in concurrency.c and use volatile instead + - Made hr fails output d3d11 debug messages before crash + - Made temporary storage size runtime-configurable for new threads - Cleanup temporary storage after thread destroy + - Added Header checking in growing array + - Unfucked linmath alignment ## v0.01.002 - Flexible build options, Hotloading, growing array diff --git a/oogabooga/cpu.c b/oogabooga/cpu.c index d901910..bebe8b3 100644 --- a/oogabooga/cpu.c +++ b/oogabooga/cpu.c @@ -249,7 +249,7 @@ typedef struct Cpu_Capabilities { #define COMPILER_CAN_DO_AVX2 0 #define COMPILER_CAN_DO_AVX512 0 - #define deprecated(msg) + #define DEPRECATED(proc, msg) #define MEMORY_BARRIER diff --git a/oogabooga/examples/audio_test.c b/oogabooga/examples/audio_test.c index 1eed554..0733635 100644 --- a/oogabooga/examples/audio_test.c +++ b/oogabooga/examples/audio_test.c @@ -31,7 +31,7 @@ int entry(int argc, char **argv) { bool bruh_ok = audio_open_source_load(&bruh, STR("oogabooga/examples/bruh.wav"), heap); assert(bruh_ok, "Could not load bruh.wav"); - bool song_ok = audio_open_source_stream_format(&song, STR("oogabooga/examples/song.ogg"), heap); + bool song_ok = audio_open_source_stream(&song, STR("oogabooga/examples/song.ogg"), heap); assert(song_ok, "Could not load song.ogg"); // By default, audio sources will be converted to the same format as the output buffer. diff --git a/oogabooga/examples/renderer_stress_test.c b/oogabooga/examples/renderer_stress_test.c index 4fbc465..1e773dc 100644 --- a/oogabooga/examples/renderer_stress_test.c +++ b/oogabooga/examples/renderer_stress_test.c @@ -102,7 +102,7 @@ int entry(int argc, char **argv) { v2(input_frame.mouse_x+256, input_frame.mouse_y+256) ); } - + seed_for_random = 69; for (u64 i = 0; i < 30000; i++) { float32 aspect = (float32)window.width/(float32)window.height; @@ -113,7 +113,7 @@ int entry(int argc, char **argv) { float x = get_random_float32() * (max_x-min_x) + min_x; float y = get_random_float32() * (max_y-min_y) + min_y; - + push_z_layer((s32)(y*100)); draw_image(bush_image, v2(x, y), v2(0.1, 0.1), COLOR_WHITE); pop_z_layer(); diff --git a/oogabooga/growing_array.c b/oogabooga/growing_array.c index 128a94e..7253f07 100644 --- a/oogabooga/growing_array.c +++ b/oogabooga/growing_array.c @@ -1,46 +1,85 @@ /* - Thing *things; - growing_array_init(&things, sizeof(Thing)); - - growing_array_deinit(&things); - - Thing new_thing; - growing_array_add(&things, &new_thing); // 'thing' is copied - - Thing *nth_thing = &things[n]; - - growing_array_reserve_count(&things, 690); - growing_array_resize_count(&things, 69); - - // "Slow", but stuff in the array keeps the same order - growing_array_ordered_remove_by_index(&things, i); - - // Fast, but will not keep stuff ordered - growing_array_unordered_remove_by_index(&things, i); - - growing_array_ordered_remove_by_pointer(&things, nth_thing); - growing_array_unordered_remove_by_pointer(&things, nth_thing); - - Thing thing_prototype; - growing_array_ordered_remove_one_by_value(&things, thing_prototype); - growing_array_unordered_remove_one_by_value(&things, thing_prototype); - growing_array_ordered_remove_all_by_value(&things, thing_prototype); - growing_array_unordered_remove_all_by_value(&things, thing_prototype); - - growing_array_get_valid_count(&things); - growing_array_get_allocated_count(&things); + Full API: + + void growing_array_init_reserve(void **array, u64 block_size_in_bytes, u64 count_to_reserve, Allocator allocator); + void growing_array_init(void **array, u64 block_size_in_bytes, Allocator allocator); + void growing_array_deinit(void **array); + + void *growing_array_add_empty(void **array); + void growing_array_add(void **array, void *item); + + void growing_array_reserve(void **array, u64 count_to_reserve); + void growing_array_resize(void **array, u64 new_count); + void growing_array_pop(void **array); + void growing_array_clear(void **array); + + // Returns -1 if not found + s32 growing_array_find_index_from_left_by_pointer(void **array, void *p); + s32 growing_array_find_index_from_left_by_value(void **array, void *p); + + void growing_array_ordered_remove_by_index(void **array, u32 index); + void growing_array_unordered_remove_by_index(void **array, u32 index); + bool growing_array_ordered_remove_by_pointer(void **array, void *p); + bool growing_array_unordered_remove_by_pointer(void **array, void *p); + bool growing_array_ordered_remove_one_by_value(void **array, void *p); + bool growing_array_unordered_remove_one_by_value(void **array, void *p); + + u32 growing_array_get_valid_count(void *array); + u32 growing_array_get_allocated_count(void *array); + + Usage: + + Thing *things; + growing_array_init(&things, sizeof(Thing)); + + growing_array_deinit(&things); + + Thing new_thing; + growing_array_add(&things, &new_thing); // 'thing' is copied + + Thing *nth_thing = &things[n]; + + growing_array_reserve_count(&things, 690); + growing_array_resize_count(&things, 69); + + // "Slow", but stuff in the array keeps the same order + growing_array_ordered_remove_by_index(&things, i); + + // Fast, but will not keep stuff ordered + growing_array_unordered_remove_by_index(&things, i); + + growing_array_ordered_remove_by_pointer(&things, nth_thing); + growing_array_unordered_remove_by_pointer(&things, nth_thing); + + Thing thing_prototype; + growing_array_ordered_remove_one_by_value(&things, thing_prototype); + growing_array_unordered_remove_one_by_value(&things, thing_prototype); + growing_array_ordered_remove_all_by_value(&things, thing_prototype); + growing_array_unordered_remove_all_by_value(&things, thing_prototype); + + growing_array_get_valid_count(&things); + growing_array_get_allocated_count(&things); */ +#define GROWING_ARRAY_SIGNATURE 2224364215 + typedef struct Growing_Array_Header { + u32 signature; u32 valid_count; u32 allocated_count; u32 block_size_in_bytes; Allocator allocator; } Growing_Array_Header; +bool +check_growing_array_signature(void **array) { + Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; + if (header->signature != GROWING_ARRAY_SIGNATURE) return false; + return true; +} void growing_array_init_reserve(void **array, u64 block_size_in_bytes, u64 count_to_reserve, Allocator allocator) { @@ -54,6 +93,7 @@ growing_array_init_reserve(void **array, u64 block_size_in_bytes, u64 count_to_r header->block_size_in_bytes = block_size_in_bytes; header->valid_count = 0; header->allocated_count = count_to_reserve; + header->signature = GROWING_ARRAY_SIGNATURE; *array = header+1; } @@ -63,12 +103,14 @@ growing_array_init(void **array, u64 block_size_in_bytes, Allocator allocator) { } void growing_array_deinit(void **array) { + assert(check_growing_array_signature(array), "Not a valid growing array"); Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; dealloc(header->allocator, header); } void growing_array_reserve(void **array, u64 count_to_reserve) { + assert(check_growing_array_signature(array), "Not a valid growing array"); Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; if (header->allocated_count >= count_to_reserve) return; @@ -90,6 +132,7 @@ growing_array_reserve(void **array, u64 count_to_reserve) { void* growing_array_add_empty(void **array) { + assert(check_growing_array_signature(array), "Not a valid growing array"); Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; growing_array_reserve(array, header->valid_count+1); @@ -119,18 +162,21 @@ void growing_array_resize(void **array, u64 new_count) { } void growing_array_pop(void **array) { + assert(check_growing_array_signature(array), "Not a valid growing array"); Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; assert(header->valid_count > 0, "No items to pop in growing array"); header->valid_count -= 1; } void growing_array_clear(void **array) { + assert(check_growing_array_signature(array), "Not a valid growing array"); Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; header->valid_count = 0; } void growing_array_ordered_remove_by_index(void **array, u32 index) { + assert(check_growing_array_signature(array), "Not a valid growing array"); Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; assert(index < header->valid_count, "Growing array index out of range"); @@ -150,6 +196,7 @@ growing_array_ordered_remove_by_index(void **array, u32 index) { } void growing_array_unordered_remove_by_index(void **array, u32 index) { + assert(check_growing_array_signature(array), "Not a valid growing array"); Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; assert(index < header->valid_count, "Growing array index out of range"); @@ -171,6 +218,7 @@ growing_array_unordered_remove_by_index(void **array, u32 index) { s32 growing_array_find_index_from_left_by_pointer(void **array, void *p) { + assert(check_growing_array_signature(array), "Not a valid growing array"); Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; for (u32 i = 0; i < header->valid_count; i++) { @@ -184,6 +232,7 @@ growing_array_find_index_from_left_by_pointer(void **array, void *p) { } s32 growing_array_find_index_from_left_by_value(void **array, void *p) { + assert(check_growing_array_signature(array), "Not a valid growing array"); Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; for (u32 i = 0; i < header->valid_count; i++) { @@ -251,11 +300,13 @@ growing_array_unordered_remove_one_by_value(void **array, void *p) { u32 growing_array_get_valid_count(void *array) { + assert(check_growing_array_signature(&array), "Not a valid growing array"); Growing_Array_Header *header = ((Growing_Array_Header*)array) - 1; return header->valid_count; } u32 growing_array_get_allocated_count(void *array) { + assert(check_growing_array_signature(&array), "Not a valid growing array"); Growing_Array_Header *header = ((Growing_Array_Header*)array) - 1; return header->allocated_count; } \ No newline at end of file diff --git a/oogabooga/os_impl_windows.c b/oogabooga/os_impl_windows.c index cce8b78..afaeb52 100644 --- a/oogabooga/os_impl_windows.c +++ b/oogabooga/os_impl_windows.c @@ -396,6 +396,11 @@ void os_init(u64 program_memory_capacity) { #ifndef OOGABOOGA_HEADLESS win32_init_window(); + // Set a dummy output format before audio init in case it fails. + audio_output_format.sample_rate = 48000; + audio_output_format.channels = 2; + audio_output_format.bit_width = AUDIO_BITS_32; + local_persist Thread audio_thread, audio_poll_default_device_thread; os_thread_init(&audio_thread, win32_audio_thread); @@ -1416,8 +1421,6 @@ const GUID CLSID_MMDeviceEnumerator = {0xbcde0395, 0xe52f, 0x467c, {0x8e,0x3d, 0 const GUID IID_IMMDeviceEnumerator = {0xa95664d2, 0x9614, 0x4f35, {0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6}}; const GUID IID_IAudioClient = {0x1cb9ad4c, 0xdbfa, 0x4c32, {0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2}}; const GUID IID_IAudioRenderClient = {0xf294acfc, 0x3146, 0x4483, {0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2}}; -DEFINE_GUID(IID_ISimpleAudioVolume, -0x87CE5498, 0x68D6, 0x44E5, 0x92, 0x15, 0x6D, 0xA4, 0x7E, 0xF8, 0x83, 0xD8); IAudioClient* win32_audio_client; IAudioRenderClient* win32_render_client; @@ -1425,12 +1428,13 @@ bool win32_audio_deactivated = false; Audio_Format audio_output_format; // For use when loading audio sources IMMDevice* win32_audio_device = 0; IMMDeviceEnumerator* win32_device_enumerator = 0; -ISimpleAudioVolume* win32_audio_volume = 0; Mutex audio_init_mutex; void win32_audio_init() { + local_persist bool did_report_error_last_call = false; + win32_audio_client = 0; win32_render_client = 0; win32_audio_deactivated = 0; @@ -1502,7 +1506,8 @@ win32_audio_init() { ); if (hr != S_OK) { win32_audio_deactivated = true; - log_error("Default audio output device is not supported."); + if (!did_report_error_last_call) log_error("Default audio output device is not supported."); + did_report_error_last_call = true; return; } output_format = (WAVEFORMATEX*)format_s16; @@ -1518,6 +1523,12 @@ win32_audio_init() { BUFFER_DURATION_MS*10000ll, 0, output_format, 0 ); + if (hr == 0x8889000A) { + if (!did_report_error_last_call) log_error("IAudioClient_Initialize failed for default device\nSample rate: %d\nBit-width: %d\n Channels: %d", device_base_format->nSamplesPerSec, device_base_format->wBitsPerSample, device_base_format->nChannels); + win32_audio_deactivated = true; + did_report_error_last_call = true; + return; + } win32_check_hr(hr); hr = IAudioClient_GetService(win32_audio_client, &IID_IAudioRenderClient, (void**)&win32_render_client); @@ -1536,14 +1547,8 @@ win32_audio_init() { DWORD task_index; AvSetMmThreadCharacteristics(TEXT("Pro Audio"), &task_index); - hr = IAudioClient_GetService(win32_audio_client, &IID_ISimpleAudioVolume, (void**)&win32_audio_volume); - if (SUCCEEDED(hr)) { - hr = ISimpleAudioVolume_SetMasterVolume(win32_audio_volume, 1.0f, 0); - win32_check_hr(hr); - ISimpleAudioVolume_Release(win32_audio_volume); - } - log_info("Successfully initialized default audio device. Channels: %d, sample_rate: %d, bits: %d", audio_output_format.channels, audio_output_format.sample_rate, get_audio_bit_width_byte_size(audio_output_format.bit_width)*8); + did_report_error_last_call = false; } @@ -1574,6 +1579,7 @@ win32_audio_poll_default_device_thread(Thread *t) { win32_check_hr(hr); if (wcscmp(now_default_id, previous_id) != 0) { + log("Hi"); win32_audio_deactivated = true; }