From a8191a239a703d313c1c5710bd138d3ac9d5f829 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Sun, 9 Feb 2025 19:01:41 +0100 Subject: [PATCH] working again, ui layout not yet fully implemented. test framework functional. --- .gitignore | 5 +- architecture/arm/Intrinsics.h | 12 +- architecture/arm/neon/utils/Utils.h | 109 ++++ architecture/arm/sve/utils/Utils.h | 110 ++++ architecture/x86/Intrinsics.h | 14 +- {stdlib => architecture/x86}/simd/SIMD_F32.h | 2 +- {stdlib => architecture/x86}/simd/SIMD_F64.h | 2 +- {stdlib => architecture/x86}/simd/SIMD_I16.h | 2 +- {stdlib => architecture/x86}/simd/SIMD_I32.h | 6 +- {stdlib => architecture/x86}/simd/SIMD_I64.h | 2 +- {stdlib => architecture/x86}/simd/SIMD_I8.h | 4 +- {stdlib => architecture/x86}/simd/SIMD_SVML.h | 2 + architecture/x86/simd/utils/Utils.h | 84 +++ asset/Asset.h | 2 +- asset/AssetArchive.h | 6 +- asset/AssetManagementSystem.h | 16 +- audio/Audio.cpp | 2 +- audio/AudioMixer.h | 22 +- audio/Qoa.h | 21 +- audio/Wav.h | 2 +- auth/Auth.h | 6 +- camera/Camera.h | 3 +- command/AppCmdBuffer.cpp | 114 ++-- command/AppCmdBuffer.h | 12 +- compiler/gcc/CompilerUtils.h | 56 ++ compiler/msvc/CompilerUtils.h | 57 +- entity/AnimationEntityComponent.h | 2 +- entity/EntityComponentSystem.h | 2 +- environment/Globe.h | 7 +- font/Font.h | 28 +- gpuapi/RenderUtils.h | 79 ++- gpuapi/opengl/AppCmdBuffer.h | 2 +- gpuapi/opengl/OpenglUtils.h | 61 +- gpuapi/vulkan/ShaderUtils.h | 21 +- gpuapi/vulkan/VulkanUtils.h | 31 +- image/Bitmap.h | 16 +- image/Image.cpp | 2 +- image/Png.h | 4 +- image/Qoi.h | 4 +- localization/Language.h | 2 +- log/Debug.cpp | 22 +- log/Debug.h | 11 +- log/DebugMemory.h | 24 +- log/Log.h | 1 - log/TimingStat.h | 1 - math/Evaluator.h | 169 +++-- math/matrix/MatrixFloat32.h | 25 +- memory/BufferMemory.h | 2 +- memory/ChunkMemory.h | 81 ++- memory/Queue.h | 2 +- memory/RingMemory.h | 38 +- memory/ThreadedQueue.h | 4 +- memory/ThreadedRingMemory.h | 4 +- module/ModuleManager.h | 4 +- object/Mesh.h | 80 +-- object/Vertex.h | 8 - platform/linux/ExceptionHandler.h | 22 +- platform/linux/Library.cpp | 2 +- platform/linux/SystemInfo.cpp | 8 +- platform/linux/UtilsLinux.h | 26 +- platform/linux/threading/Thread.h | 15 + platform/linux/threading/ThreadDefines.h | 4 +- platform/win32/Allocator.h | 1 - platform/win32/Clipboard.h | 1 - platform/win32/ExceptionHandler.h | 150 +++-- platform/win32/FileUtils.cpp | 6 +- platform/win32/Library.cpp | 2 +- platform/win32/SystemInfo.cpp | 2 +- platform/win32/TimeUtils.h | 25 +- platform/win32/UtilsWin32.h | 7 +- platform/win32/UtilsWindows.h | 1 + platform/win32/audio/DirectSound.h | 4 +- platform/win32/input/HidInput.h | 4 +- platform/win32/input/RawInput.h | 8 +- platform/win32/threading/Thread.h | 25 +- platform/win32/threading/ThreadDefines.h | 2 +- scene/SceneInfo.h | 20 + sort/BinarySearch.h | 23 + sort/EytzingerSearch.h | 74 +++ sort/HeapSort.h | 50 ++ sort/InsertionSort.h | 16 + sort/IntroSort.h | 37 ++ sort/QuickSort.h | 37 ++ sort/Sort.h | 34 + stdlib/HashMap.h | 41 +- stdlib/Simd.h | 32 +- stdlib/Types.h | 32 +- tests.bat | 82 +++ tests/.vscode/c_cpp_properties.json | 23 + tests/.vscode/launch.json | 16 + tests/.vscode/settings.json | 322 +++++++++ tests/.vscode/tasks.json | 80 +++ tests/MainTest.cpp | 44 ++ tests/TestFramework.h | 354 ++++++++++ tests/math/EvaluatorTest.cpp | 57 ++ tests/memory/ChunkMemoryTest.cpp | 148 +++++ tests/memory/RingMemoryTest.cpp | 108 +++ tests/stdlib/HashMapTest.cpp | 59 ++ tests/ui/UILayoutTest.cpp | 80 +++ tests/ui/UIThemeTest.cpp | 49 ++ tests/utils/BitUtilsTest.cpp | 198 ++++++ tests/utils/EndianUtilsTest.cpp | 138 ++++ tests/utils/StringUtilsTest.cpp | 196 ++++++ tests/utils/UtilsTest.cpp | 147 +++++ tests_iter.bat | 68 ++ thread/Thread.h | 3 +- thread/ThreadJob.h | 6 +- thread/ThreadPool.h | 11 +- ui/UIButton.h | 21 +- ui/UICursor.h | 7 +- ui/UICustom.h | 68 ++ ui/UIElement.h | 3 +- ui/UIElementType.h | 24 +- ui/UIInput.h | 11 +- ui/UILabel.h | 23 +- ui/UILayout.cpp | 188 +++--- ui/UILayout.h | 3 +- ui/UITheme.h | 110 ++-- ui/attribute/UIAttribute.h | 61 +- ui/attribute/UIAttributeType.h | 19 +- utils/BitUtils.h | 46 +- utils/EndianUtils.h | 2 +- utils/PerformanceProfiler.h | 88 +-- utils/StringUtils.h | 617 +++++++++++++----- utils/TestUtils.h | 131 +--- utils/Utils.h | 96 +-- 126 files changed, 4670 insertions(+), 1158 deletions(-) create mode 100644 architecture/arm/neon/utils/Utils.h create mode 100644 architecture/arm/sve/utils/Utils.h rename {stdlib => architecture/x86}/simd/SIMD_F32.h (99%) rename {stdlib => architecture/x86}/simd/SIMD_F64.h (94%) rename {stdlib => architecture/x86}/simd/SIMD_I16.h (99%) rename {stdlib => architecture/x86}/simd/SIMD_I32.h (99%) rename {stdlib => architecture/x86}/simd/SIMD_I64.h (94%) rename {stdlib => architecture/x86}/simd/SIMD_I8.h (99%) rename {stdlib => architecture/x86}/simd/SIMD_SVML.h (99%) create mode 100644 architecture/x86/simd/utils/Utils.h create mode 100644 scene/SceneInfo.h create mode 100644 sort/BinarySearch.h create mode 100644 sort/EytzingerSearch.h create mode 100644 sort/HeapSort.h create mode 100644 sort/InsertionSort.h create mode 100644 sort/IntroSort.h create mode 100644 sort/QuickSort.h create mode 100644 sort/Sort.h create mode 100644 tests.bat create mode 100644 tests/.vscode/c_cpp_properties.json create mode 100644 tests/.vscode/launch.json create mode 100644 tests/.vscode/settings.json create mode 100644 tests/.vscode/tasks.json create mode 100644 tests/MainTest.cpp create mode 100644 tests/TestFramework.h create mode 100644 tests/math/EvaluatorTest.cpp create mode 100644 tests/memory/ChunkMemoryTest.cpp create mode 100644 tests/memory/RingMemoryTest.cpp create mode 100644 tests/stdlib/HashMapTest.cpp create mode 100644 tests/ui/UILayoutTest.cpp create mode 100644 tests/ui/UIThemeTest.cpp create mode 100644 tests/utils/BitUtilsTest.cpp create mode 100644 tests/utils/EndianUtilsTest.cpp create mode 100644 tests/utils/StringUtilsTest.cpp create mode 100644 tests/utils/UtilsTest.cpp create mode 100644 tests_iter.bat create mode 100644 ui/UICustom.h diff --git a/.gitignore b/.gitignore index 2584896..ef5bbb3 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,7 @@ bin/* *.obj *.log *.spv -*.res \ No newline at end of file +*.res +*.exe +*.map +*.pdb \ No newline at end of file diff --git a/architecture/arm/Intrinsics.h b/architecture/arm/Intrinsics.h index 3af425f..18cfbde 100644 --- a/architecture/arm/Intrinsics.h +++ b/architecture/arm/Intrinsics.h @@ -13,6 +13,7 @@ #include #include "../../stdlib/Types.h" +#include "../../compiler/CompilerUtils.h" #define intrin_sqrt_f32(a) svget1_f32(svsqrt_f32(svdup_f32((a)))) #define intrin_sqrt_f64(a) svget1_f64(svsqrt_f64(svdup_f64((a)))) @@ -35,6 +36,15 @@ #define intrin_crc32_u32(crc, data) __crc32w((crc), (data)) #define intrin_crc32_u64(crc, data) __crc32d((crc), (data)) -#define intrin_timestamp_counter() ({ uint64_t cntvct; asm volatile("mrs %0, cntvct_el0" : "=r"(cntvct)); cntvct; }) +#define intrin_bits_count_32(data) compiler_popcount_32((data)) +#define intrin_bits_count_64(data) compiler_popcount_64((data)) + +#define intrin_prefetch(mem) compiler_prefetch((mem)) + +#if _WIN32 + #define intrin_timestamp_counter() ({ uint64_t cntvct; asm volatile("mrs %0, cntvct_el0" : "=r"(cntvct)); cntvct; }) +#else + #define intrin_timestamp_counter() __builtin_readcyclecounter() +#endif #endif \ No newline at end of file diff --git a/architecture/arm/neon/utils/Utils.h b/architecture/arm/neon/utils/Utils.h new file mode 100644 index 0000000..5b9fefc --- /dev/null +++ b/architecture/arm/neon/utils/Utils.h @@ -0,0 +1,109 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_ARCHITECTURE_ARM_NEON_UTILS_H +#define TOS_ARCHITECTURE_ARM_NEON_UTILS_H + +#include +#include "../../../../stdlib/Types.h" +#include "../../../../compiler/CompilerUtils.h" +#include "../../../../stdlib/Simd.h" +#include + +// @question When do we want to use neon and when do we want to use sve? +// Only allowed for data >= 64 bits +bool is_empty(const uint8_t* region, uint64_t size, int32_t steps = 8) { + if (*((uint64_t *) region) != 0) { + return false; + } + + const uint8_t* end = region + size; + steps = intrin_validate_steps(region, steps); + + switch (steps) { + case 16: { + while (region + 64 <= end) { + uint8x16_t chunk1 = vld1q_u8(region); + uint8x16_t chunk2 = vld1q_u8(region + 16); + uint8x16_t chunk3 = vld1q_u8(region + 32); + uint8x16_t chunk4 = vld1q_u8(region + 48); + + uint8x16_t zero = vdupq_n_u8(0); + uint8x16_t result1 = vceqq_u8(chunk1, zero); + uint8x16_t result2 = vceqq_u8(chunk2, zero); + uint8x16_t result3 = vceqq_u8(chunk3, zero); + uint8x16_t result4 = vceqq_u8(chunk4, zero); + + uint8x16_t combined = vandq_u8(vandq_u8(result1, result2), vandq_u8(result3, result4)); + + if (vminvq_u8(combined) != 0xFF) { + return false; + } + + region += 64; + } + break; + } + case 8: { + while (region + 32 <= end) { + uint8x16_t chunk1 = vld1q_u8(region); + uint8x16_t chunk2 = vld1q_u8(region + 16); + + uint8x16_t zero = vdupq_n_u8(0); + uint8x16_t result1 = vceqq_u8(chunk1, zero); + uint8x16_t result2 = vceqq_u8(chunk2, zero); + + uint8x16_t combined = vandq_u8(result1, result2); + + if (vminvq_u8(combined) != 0xFF) { + return false; + } + + region += 32; + } + break; + } + case 4: { + while (region + 16 <= end) { + uint8x16_t chunk = vld1q_u8(region); + + uint8x16_t zero = vdupq_n_u8(0); + uint8x16_t result = vceqq_u8(chunk, zero); + + if (vminvq_u8(result) != 0xFF) { + return false; + } + + region += 16; + } + break; + } + case 1: { + while (region + 4 <= end) { + if (*((const uint32_t *) region) != 0) { + return false; + } + + region += 4; + } + + while (region < end) { + if (*region++ != 0) { + return false; + } + } + break; + } + default: + UNREACHABLE(); + } + + return true; +} + +#endif \ No newline at end of file diff --git a/architecture/arm/sve/utils/Utils.h b/architecture/arm/sve/utils/Utils.h new file mode 100644 index 0000000..e633638 --- /dev/null +++ b/architecture/arm/sve/utils/Utils.h @@ -0,0 +1,110 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_ARCHITECTURE_ARM_SVE_UTILS_H +#define TOS_ARCHITECTURE_ARM_SVE_UTILS_H + +#include +#include "../../../../stdlib/Types.h" +#include "../../../../compiler/CompilerUtils.h" +#include "../../../../stdlib/Simd.h" +#include + +// Only allowed for data >= 64 bits +bool is_empty(const uint8_t* region, uint64_t size, int32_t steps = 8) { + if (*((uint64_t *) region) != 0) { + return false; + } + + const uint8_t* end = region + size; + steps = intrin_validate_steps(region, steps); + + uint64_t sve_vector_bytes = svcntb(); + + switch (steps) { + case 16: { + while (region + sve_vector_bytes * 4 <= end) { + svuint8_t chunk1 = svld1_u8(svptrue_b8(), region); + svuint8_t chunk2 = svld1_u8(svptrue_b8(), region + sve_vector_bytes); + svuint8_t chunk3 = svld1_u8(svptrue_b8(), region + sve_vector_bytes * 2); + svuint8_t chunk4 = svld1_u8(svptrue_b8(), region + sve_vector_bytes * 3); + + svuint8_t zero = svdup_n_u8(0); + svbool_t cmp1 = svcmpeq_u8(svptrue_b8(), chunk1, zero); + svbool_t cmp2 = svcmpeq_u8(svptrue_b8(), chunk2, zero); + svbool_t cmp3 = svcmpeq_u8(svptrue_b8(), chunk3, zero); + svbool_t cmp4 = svcmpeq_u8(svptrue_b8(), chunk4, zero); + + svbool_t combined = svand_b_z(svptrue_b8(), svand_b_z(svptrue_b8(), cmp1, cmp2), svand_b_z(svptrue_b8(), cmp3, cmp4)); + + if (!svptest_any(svptrue_b8(), combined)) { + return false; + } + + region += sve_vector_bytes * 4; + } + break; + } + case 8: { + while (region + sve_vector_bytes * 2 <= end) { + svuint8_t chunk1 = svld1_u8(svptrue_b8(), region); + svuint8_t chunk2 = svld1_u8(svptrue_b8(), region + sve_vector_bytes); + + svuint8_t zero = svdup_n_u8(0); + svbool_t cmp1 = svcmpeq_u8(svptrue_b8(), chunk1, zero); + svbool_t cmp2 = svcmpeq_u8(svptrue_b8(), chunk2, zero); + + svbool_t combined = svand_b_z(svptrue_b8(), cmp1, cmp2); + + if (!svptest_any(svptrue_b8(), combined)) { + return false; + } + + region += sve_vector_bytes * 2; + } + break; + } + case 4: { + while (region + sve_vector_bytes <= end) { + svuint8_t chunk = svld1_u8(svptrue_b8(), region); + + svuint8_t zero = svdup_n_u8(0); + svbool_t cmp = svcmpeq_u8(svptrue_b8(), chunk, zero); + + if (!svptest_any(svptrue_b8(), cmp)) { + return false; + } + + region += sve_vector_bytes; + } + break; + } + case 1: { + while (region + 4 <= end) { + if (*((const uint32_t *) region) != 0) { + return false; + } + + region += 4; + } + + while (region < end) { + if (*region++ != 0) { + return false; + } + } + break; + } + default: + UNREACHABLE(); + } + + return true; +} + +#endif \ No newline at end of file diff --git a/architecture/x86/Intrinsics.h b/architecture/x86/Intrinsics.h index 1c8fd89..6a8172a 100644 --- a/architecture/x86/Intrinsics.h +++ b/architecture/x86/Intrinsics.h @@ -51,6 +51,18 @@ #define intrin_crc32_u32(crc, data) _mm_crc32_u32((crc), (data)) #define intrin_crc32_u64(crc, data) _mm_crc32_u64((crc), (data)) -#define intrin_timestamp_counter() __rdtsc() +#define intrin_bits_count_32(data) _mm_popcnt_u32((data)) +#define intrin_bits_count_64(data) _mm_popcnt_u64((data)) + +#define intrin_prefetch(mem) _mm_prefetch((mem)) + +inline +uint64 intrin_timestamp_counter() { + _mm_mfence(); + uint64 res = __rdtsc(); + _mm_mfence(); + + return res; +} #endif \ No newline at end of file diff --git a/stdlib/simd/SIMD_F32.h b/architecture/x86/simd/SIMD_F32.h similarity index 99% rename from stdlib/simd/SIMD_F32.h rename to architecture/x86/simd/SIMD_F32.h index 5ad0563..7925f3b 100644 --- a/stdlib/simd/SIMD_F32.h +++ b/architecture/x86/simd/SIMD_F32.h @@ -12,7 +12,7 @@ #include #include -#include "../Types.h" +#include "../../../stdlib/Types.h" #include "SIMD_SVML.h" struct f32_4 { diff --git a/stdlib/simd/SIMD_F64.h b/architecture/x86/simd/SIMD_F64.h similarity index 94% rename from stdlib/simd/SIMD_F64.h rename to architecture/x86/simd/SIMD_F64.h index 145e53c..9a19795 100644 --- a/stdlib/simd/SIMD_F64.h +++ b/architecture/x86/simd/SIMD_F64.h @@ -12,7 +12,7 @@ #include #include -#include "../Types.h" +#include "../../../stdlib/Types.h" struct f64_2 { union { diff --git a/stdlib/simd/SIMD_I16.h b/architecture/x86/simd/SIMD_I16.h similarity index 99% rename from stdlib/simd/SIMD_I16.h rename to architecture/x86/simd/SIMD_I16.h index 3c3c73e..938d0c9 100644 --- a/stdlib/simd/SIMD_I16.h +++ b/architecture/x86/simd/SIMD_I16.h @@ -12,7 +12,7 @@ #include #include -#include "../Types.h" +#include "../../../stdlib/Types.h" struct int16_8 { union { diff --git a/stdlib/simd/SIMD_I32.h b/architecture/x86/simd/SIMD_I32.h similarity index 99% rename from stdlib/simd/SIMD_I32.h rename to architecture/x86/simd/SIMD_I32.h index b43ce9c..5781a63 100644 --- a/stdlib/simd/SIMD_I32.h +++ b/architecture/x86/simd/SIMD_I32.h @@ -13,8 +13,8 @@ #include #include -#include "../Types.h" -#include "../../utils/BitUtils.h" +#include "../../../stdlib/Types.h" +#include "../../../utils/BitUtils.h" #include "SIMD_F32.h" // @todo a lot of sse functions require high level (e.g. sse4.1) this needs to be changed to be more general @@ -1639,7 +1639,7 @@ endian_swap(const int* val, int* result, int32 size, int32 steps) } } -#if _WIN32 || __LITTLE_ENDIAN +#if _WIN32 || __LITTLE_ENDIAN__ #define SWAP_ENDIAN_LITTLE_SIMD(val, result, size, steps) ((void)0) #define SWAP_ENDIAN_BIG_SIMD(val, result, size, steps) endian_swap((val), (result), (size), (steps)) #else diff --git a/stdlib/simd/SIMD_I64.h b/architecture/x86/simd/SIMD_I64.h similarity index 94% rename from stdlib/simd/SIMD_I64.h rename to architecture/x86/simd/SIMD_I64.h index 370398e..407b446 100644 --- a/stdlib/simd/SIMD_I64.h +++ b/architecture/x86/simd/SIMD_I64.h @@ -12,7 +12,7 @@ #include #include -#include "../Types.h" +#include "../../../stdlib/Types.h" #include "SIMD_F64.h" struct int64_2 { diff --git a/stdlib/simd/SIMD_I8.h b/architecture/x86/simd/SIMD_I8.h similarity index 99% rename from stdlib/simd/SIMD_I8.h rename to architecture/x86/simd/SIMD_I8.h index a3ad406..31b1821 100644 --- a/stdlib/simd/SIMD_I8.h +++ b/architecture/x86/simd/SIMD_I8.h @@ -12,7 +12,7 @@ #include #include -#include "../Types.h" +#include "../../../stdlib/Types.h" #include "SIMD_F32.h" #include "SIMD_I32.h" @@ -885,7 +885,7 @@ bool simd_compare_64(const byte* a, const byte* b) } int simd_compare(const byte* a, const byte* b, uint32 size, uint32 steps = 8) { - int32 i = 0; + uint32 i = 0; if (steps == 16) { if (size >= 128) { diff --git a/stdlib/simd/SIMD_SVML.h b/architecture/x86/simd/SIMD_SVML.h similarity index 99% rename from stdlib/simd/SIMD_SVML.h rename to architecture/x86/simd/SIMD_SVML.h index 0308ada..d76f262 100644 --- a/stdlib/simd/SIMD_SVML.h +++ b/architecture/x86/simd/SIMD_SVML.h @@ -12,6 +12,8 @@ #include #include +#include "../../../stdlib/Types.h" + #if __linux__ #include "math.h" diff --git a/architecture/x86/simd/utils/Utils.h b/architecture/x86/simd/utils/Utils.h new file mode 100644 index 0000000..5f6afa9 --- /dev/null +++ b/architecture/x86/simd/utils/Utils.h @@ -0,0 +1,84 @@ +/** + * Jingga + * + * @copyright Jingga + * @license OMS License 2.0 + * @version 1.0.0 + * @link https://jingga.app + */ +#ifndef TOS_ARCHITECTURE_X86_UTILS_H +#define TOS_ARCHITECTURE_X86_UTILS_H + +#include +#include "../../../../stdlib/Types.h" +#include "../../../../compiler/CompilerUtils.h" +#include "../../../../stdlib/Simd.h" + +// Only allowed for data >= 64 bits +bool is_empty(const byte* region, uint64 size, int32 steps = 8) +{ + if (*((uint64 *) region) != 0) { + return false; + } + + const byte* end = region + size; + steps = intrin_validate_steps(region, steps); + + switch (steps) { + case 16: { + while (region + 64 <= end) { + __m512i chunk = _mm512_loadu_si512((const __m512i *) region); + __mmask64 mask = _mm512_cmpeq_epi8_mask(chunk, _mm512_setzero_si512()); + if (mask != 0xFFFFFFFFFFFFFFFF) { + return false; + } + + region += 64; + } + }; + [[fallthrough]]; + case 8: { + while (region + 32 <= end) { + __m256i chunk = _mm256_loadu_si256((const __m256i *) region); + if (!_mm256_testz_si256(chunk, chunk)) { + return false; + } + + region += 32; + } + }; + [[fallthrough]]; + case 4: { + while (region + 16 <= end) { + __m128i chunk = _mm_loadu_si128((const __m128i *) region); + if (!_mm_testz_si128(chunk, chunk)) { + return false; + } + + region += 16; + } + } + [[fallthrough]]; + case 1: { + while (region + 4 <= end) { + if (*((const uint32_t *) region) != 0) { + return false; + } + + region += 4; + } + + while (region < end) { + if (*region++ != 0) { + return false; + } + } + } break; + default: + UNREACHABLE(); + } + + return true; +} + +#endif \ No newline at end of file diff --git a/asset/Asset.h b/asset/Asset.h index 792b066..9d8fc3b 100644 --- a/asset/Asset.h +++ b/asset/Asset.h @@ -24,7 +24,7 @@ struct Asset { uint32 official_id; // @performance Maybe if we would set the IS_LOADED_STATE in the enum as the highest bit we could use the state variable and check it with >= - int32 is_loaded; + atomic_32 int32 is_loaded; // Describes how much ram/vram the asset uses // E.g. vram_size = 0 but ram_size > 0 means that it never uses any gpu memory diff --git a/asset/AssetArchive.h b/asset/AssetArchive.h index 42bafdc..13832ed 100644 --- a/asset/AssetArchive.h +++ b/asset/AssetArchive.h @@ -89,7 +89,7 @@ int32 asset_archive_header_size(AssetArchive* __restrict archive, const byte* __ + asset_dependency_count * sizeof(int32); } -void asset_archive_header_load(AssetArchiveHeader* __restrict header, const byte* __restrict data, int32 steps = 8) +void asset_archive_header_load(AssetArchiveHeader* __restrict header, const byte* __restrict data, [[maybe_unused]] int32 steps = 8) { header->version = SWAP_ENDIAN_LITTLE(*((int32 *) data)); data += sizeof(header->version); @@ -142,7 +142,7 @@ void asset_archive_load(AssetArchive* archive, const char* path, BufferMemory* b } archive->mmf = file_mmf_handle(archive->fd_async); - FileBody file; + FileBody file = {}; file.size = 64; // Find header size @@ -186,7 +186,7 @@ Asset* asset_archive_asset_load(const AssetArchive* archive, int32 id, AssetMana AssetArchiveElement* element = &archive->header.asset_element[id & 0x00FFFFFF]; byte component_id = archive->asset_type_map[element->type]; - AssetComponent* ac = &ams->asset_components[component_id]; + //AssetComponent* ac = &ams->asset_components[component_id]; // Create a string representation from the asset id // We can't just use the asset id, since an int can have a \0 between high byte and low byte diff --git a/asset/AssetManagementSystem.h b/asset/AssetManagementSystem.h index 2cc257c..3fbb8ba 100644 --- a/asset/AssetManagementSystem.h +++ b/asset/AssetManagementSystem.h @@ -222,7 +222,7 @@ Asset* thrd_ams_get_reserve_asset_wait(AssetManagementSystem* ams, byte type, co ac->ram_size += asset->ram_size; ++ac->asset_count; - DEBUG_MEMORY_RESERVE((uintptr_t) asset, asset->ram_size, 180); + DEBUG_MEMORY_RESERVE((uintptr_t) asset, asset->ram_size); return asset; } @@ -246,7 +246,7 @@ void ams_remove_asset(AssetManagementSystem* ams, AssetComponent* ac, Asset* ass } inline -void ams_remove_asset_ram(AssetManagementSystem* ams, AssetComponent* ac, Asset* asset) +void ams_remove_asset_ram(AssetComponent* ac, Asset* asset) { ac->ram_size -= asset->ram_size; chunk_free_elements( @@ -393,7 +393,7 @@ Asset* ams_reserve_asset(AssetManagementSystem* ams, byte type, const char* name ac->ram_size += asset->ram_size; ++ac->asset_count; - DEBUG_MEMORY_RESERVE((uintptr_t) asset, asset->ram_size, 180); + DEBUG_MEMORY_RESERVE((uintptr_t) asset, asset->ram_size); return asset; } @@ -426,7 +426,7 @@ Asset* thrd_ams_reserve_asset(AssetManagementSystem* ams, byte type, const char* ac->ram_size += asset.ram_size; ++ac->asset_count; - DEBUG_MEMORY_RESERVE((uintptr_t) asset_data, asset.ram_size, 180); + DEBUG_MEMORY_RESERVE((uintptr_t) asset_data, asset.ram_size); return (Asset *) hashmap_insert(&ams->hash_map, name, (byte *) &asset)->value; } @@ -446,7 +446,7 @@ void thrd_ams_update(AssetManagementSystem* ams, uint64 time, uint64 dt) } // Iterate the hash map to find all assets - int32 chunk_id = 0; + uint32 chunk_id = 0; chunk_iterate_start(&ams->hash_map.buf, chunk_id) HashEntry* entry = (HashEntry *) chunk_get_element(&ams->hash_map.buf, chunk_id); Asset* asset = (Asset *) entry->value; @@ -475,7 +475,7 @@ void thrd_ams_update(AssetManagementSystem* ams, uint64 time, uint64 dt) } else if ((asset->state & ASSET_STATE_RAM_GC) && time - asset->last_access <= dt ) { - ams_remove_asset_ram(ams, &ams->asset_components[asset->component_id], asset); + ams_remove_asset_ram(&ams->asset_components[asset->component_id], asset); } else if ((asset->state & ASSET_STATE_VRAM_GC) && time - asset->last_access <= dt ) { @@ -506,7 +506,7 @@ Asset* ams_insert_asset(AssetManagementSystem* ams, Asset* asset_temp, const cha ++ac->asset_count; Asset* asset = (Asset *) hashmap_insert(&ams->hash_map, name, (byte *) asset_temp)->value; - DEBUG_MEMORY_RESERVE((uintptr_t) asset->self, asset->ram_size, 180); + DEBUG_MEMORY_RESERVE((uintptr_t) asset->self, asset->ram_size); return asset; } @@ -537,7 +537,7 @@ Asset* thrd_ams_insert_asset(AssetManagementSystem* ams, Asset* asset_temp, cons ++ac->asset_count; Asset* asset = (Asset *) hashmap_insert(&ams->hash_map, name, (byte *) asset_temp)->value; - DEBUG_MEMORY_RESERVE((uintptr_t) asset->self, asset->ram_size, 180); + DEBUG_MEMORY_RESERVE((uintptr_t) asset->self, asset->ram_size); atomic_set_release(&asset->is_loaded, 1); diff --git a/audio/Audio.cpp b/audio/Audio.cpp index 879b380..9e5e249 100644 --- a/audio/Audio.cpp +++ b/audio/Audio.cpp @@ -19,7 +19,7 @@ void audio_from_file(Audio* __restrict audio, const char* __restrict path, RingMemory* __restrict ring) { - FileBody file; + FileBody file = {}; file_read(path, &file, ring); ASSERT_SIMPLE(file.size); diff --git a/audio/AudioMixer.h b/audio/AudioMixer.h index 8798495..549d3d3 100644 --- a/audio/AudioMixer.h +++ b/audio/AudioMixer.h @@ -71,7 +71,7 @@ enum AudioMixerState { struct AudioMixer { ChunkMemory audio_instances; AudioMixerState state_old; - int32 state_new; + atomic_64 int32 state_new; uint64 effect; @@ -207,7 +207,7 @@ int32 apply_speed(int16* buffer, uint32 buffer_size, f32 speed) { // Speed up if (speed > 1.0f) { - for (int32 i = 0; i < new_size; ++i) { + for (uint32 i = 0; i < new_size; ++i) { // @bug What if 2 consecutive values fall onto the same int index for stereo. This would break it. // The problem is, even by doing this as stereo calculation we would still have the same issue just not on the current value but the next loop uint32 src_index = (uint32) (i * speed); @@ -265,7 +265,7 @@ void apply_flanger(int16* buffer, uint32 buffer_size, f32 rate, f32 depth, int32 f32 temp = OMS_TWO_PI * rate / sample_rate; for (uint32 i = 0; i < buffer_size; ++i) { - int32 delay = (int32) (delay_samples * (0.5f + 0.5f * sinf(i * temp))); + uint32 delay = (uint32) (delay_samples * (0.5f + 0.5f * sinf(i * temp))); if (i >= delay) { buffer[i] += (int16) (buffer[i - delay] * 0.5f); } @@ -291,9 +291,9 @@ void apply_distortion(int16* buffer, uint32 buffer_size, f32 gain) { void apply_chorus(int16* buffer, uint32 buffer_size, f32 rate, f32 depth, int32 sample_rate) { f32 temp = OMS_TWO_PI * rate / sample_rate; - int32 max_delay = (int32) (depth * sample_rate); + uint32 max_delay = (uint32) (depth * sample_rate); for (uint32 i = 0; i < buffer_size; ++i) { - int32 delay = (int32) (max_delay * (0.5f + 0.5f * sinf(i * temp))); + uint32 delay = (uint32) (max_delay * (0.5f + 0.5f * sinf(i * temp))); if (i >= delay) { buffer[i] += (int16) (buffer[i - delay] * 0.5f); } @@ -307,8 +307,8 @@ void apply_pitch_shift(int16* buffer, uint32 buffer_size, f32 pitch_factor) { } void apply_granular_delay(int16* buffer, uint32 buffer_size, f32 delay, f32 granularity, int32 sample_rate) { - int32 delay_samples = (int32) (delay * sample_rate); - int32 limit = (int32) (granularity * sample_rate); + uint32 delay_samples = (uint32) (delay * sample_rate); + uint32 limit = (uint32) (granularity * sample_rate); for (uint32 i = 0; i < buffer_size; ++i) { if (i % limit == 0 && i >= delay_samples) { @@ -324,7 +324,7 @@ void apply_frequency_modulation(int16* buffer, uint32 buffer_size, f32 mod_freq, } } -void apply_stereo_panning(int16* buffer, int32 buffer_size, f32 pan) { +void apply_stereo_panning(int16* buffer, uint32 buffer_size, f32 pan) { f32 left_gain = 1.0f - pan; f32 right_gain = pan; @@ -482,7 +482,7 @@ void audio_mixer_mix(AudioMixer* mixer, uint32 size) { } uint32 sound_sample_count = sound->audio_size / mixer->settings.sample_size; - int32 sound_sample_index = sound->sample_index; + uint32 sound_sample_index = sound->sample_index; int16* audio_data = (int16 *) sound->audio_data; // Temporary buffer for effects processing @@ -491,7 +491,7 @@ void audio_mixer_mix(AudioMixer* mixer, uint32 size) { // Careful, NOT voice since we will probably manually layer them according to their position? if (sound->channels == 1) { // We make it stereo - for (int32 j = 0; j < limit; ++j) { + for (uint32 j = 0; j < limit; ++j) { if (sound_sample_index >= sound_sample_count) { if (!(sound->effect & AUDIO_EFFECT_REPEAT)) { limit = j; @@ -518,7 +518,7 @@ void audio_mixer_mix(AudioMixer* mixer, uint32 size) { limit += sample_adjustment; } } else { - for (int32 j = 0; j < limit; ++j) { + for (uint32 j = 0; j < limit; ++j) { if (sound_sample_index >= sound_sample_count) { if (!(sound->effect & AUDIO_EFFECT_REPEAT)) { limit = j; diff --git a/audio/Qoa.h b/audio/Qoa.h index 5afe316..9c95679 100644 --- a/audio/Qoa.h +++ b/audio/Qoa.h @@ -182,7 +182,7 @@ int32 qoa_clamp_s16(int32 v) { return v; } -uint32 qoa_encode_frame(const int16* sample_data, int32 channels, uint32 frame_samples, QoaLms* lms, byte* bytes) +uint32 qoa_encode_frame(const int16* sample_data, uint32 channels, uint32 frame_samples, QoaLms* lms, byte* bytes) { byte* start = bytes; @@ -319,11 +319,11 @@ uint32 qoa_encode(const Audio* audio, byte* data) { /* Calculate the encoded size and allocate */ uint32 sample_count = audio->size / (audio->channels * audio->bloc_size); - uint32 num_frames = (sample_count + QOA_FRAME_LEN - 1) / QOA_FRAME_LEN; - uint32 num_slices = (sample_count + QOA_SLICE_LEN - 1) / QOA_SLICE_LEN; + // uint32 num_frames = (sample_count + QOA_FRAME_LEN - 1) / QOA_FRAME_LEN; + //uint32 num_slices = (sample_count + QOA_SLICE_LEN - 1) / QOA_SLICE_LEN; QoaLms lms[QOA_MAX_CHANNELS]; - for (int32 i = 0; i < audio->channels; ++i) { + for (uint32 i = 0; i < audio->channels; ++i) { /* Set the initial LMS weights to {0, 0, -1, 2}. This helps with the prediction of the first few ms of a file. @@ -339,7 +339,6 @@ uint32 qoa_encode(const Audio* audio, byte* data) { // Go through all frames int32 frame_samples = QOA_FRAME_LEN; - int32 p = 0; for (uint32 sample_index = 0; sample_index < sample_count; sample_index += frame_samples) { frame_samples = qoa_clamp(QOA_FRAME_LEN, 0, sample_count - sample_index); @@ -352,7 +351,7 @@ uint32 qoa_encode(const Audio* audio, byte* data) { return (uint32) (data - start); } -uint32 qoa_decode_frame(const byte* bytes, int32 channels, QoaLms* lms, int16* sample_data) +uint32 qoa_decode_frame(const byte* bytes, uint32 channels, QoaLms* lms, int16* sample_data) { const byte* start = bytes; @@ -360,11 +359,11 @@ uint32 qoa_decode_frame(const byte* bytes, int32 channels, QoaLms* lms, int16* s uint32 frame_samples = SWAP_ENDIAN_LITTLE(*((uint32 *) bytes)); bytes += sizeof(frame_samples); - uint32 slices = (frame_samples + QOA_SLICE_LEN - 1) / QOA_SLICE_LEN; - uint32 frame_size = QOA_FRAME_SIZE(channels, slices); - uint32 data_size = frame_size - 4 - QOA_LMS_LEN * 4 * channels; - uint32 num_slices = data_size / 8; - uint32 max_total_samples = num_slices * QOA_SLICE_LEN; + //uint32 slices = (frame_samples + QOA_SLICE_LEN - 1) / QOA_SLICE_LEN; + //uint32 frame_size = QOA_FRAME_SIZE(channels, slices); + //uint32 data_size = frame_size - 4 - QOA_LMS_LEN * 4 * channels; + //uint32 num_slices = data_size / 8; + // uint32 max_total_samples = num_slices * QOA_SLICE_LEN; // Read the LMS state: 4 x 2 bytes history, 4 x 2 bytes weights per channel for (uint32 c = 0; c < channels; ++c) { diff --git a/audio/Wav.h b/audio/Wav.h index fd67c62..b5661ac 100644 --- a/audio/Wav.h +++ b/audio/Wav.h @@ -63,7 +63,7 @@ void generate_default_wav_references(const byte* data, uint32 size, Wav* wav) memcpy(&wav->header, data, WAV_HEADER_SIZE); // swap endian if we are on big endian system - #if !_WIN32 && !__LITTLE_ENDIAN + #if !_WIN32 && !__LITTLE_ENDIAN__ wav->header.size = SWAP_ENDIAN_LITTLE(wav->header.size); wav->header.bloc_size = SWAP_ENDIAN_LITTLE(wav->header.bloc_size); wav->header.audio_format = SWAP_ENDIAN_LITTLE(wav->header.audio_format); diff --git a/auth/Auth.h b/auth/Auth.h index 4084b95..54913ba 100644 --- a/auth/Auth.h +++ b/auth/Auth.h @@ -31,10 +31,10 @@ size_t write_function(char* data, size_t size, size_t count, void* arg) { char* dst = (char *)arg; - size_t length = strlen(dst); + size_t length = str_length(dst); // Ensure we do not exceed the buffer length - size_t available_space = OMS_MIN(MAX_AUTH_RESPONSE_LENGTH, strlen(dst)); + size_t available_space = OMS_MIN(MAX_AUTH_RESPONSE_LENGTH, str_length(dst)); if (available_space > 0) { strncat(dst, data, available_space - 1); } @@ -92,7 +92,7 @@ int get_access_token( curl_easy_cleanup(curl); if (code == CURLE_OK && http_code == 200) { - strncpy(access_token, response, strlen(response)); + strncpy(access_token, response, str_length(response)); return 1; } diff --git a/camera/Camera.h b/camera/Camera.h index f2e52d3..d80b694 100644 --- a/camera/Camera.h +++ b/camera/Camera.h @@ -71,7 +71,7 @@ camera_update_vectors(Camera* camera) vec3_normalize(&camera->up); } -void camera_rotate(Camera* camera, int32 dx, int32 dy, f32 dt) +void camera_rotate(Camera* camera, int32 dx, int32 dy) { camera->state_changes |= CAMERA_STATE_CHANGE_NORMAL; camera->orientation.x += dy * camera->sensitivity; @@ -219,7 +219,6 @@ void camera_movement(Camera* camera, CameraMovement* movement, f32 dt, bool rela camera->zoom -= velocity; } break; default: { - UNREACHABLE(); } } } diff --git a/command/AppCmdBuffer.cpp b/command/AppCmdBuffer.cpp index 7551044..793a95e 100644 --- a/command/AppCmdBuffer.cpp +++ b/command/AppCmdBuffer.cpp @@ -27,6 +27,7 @@ #include "../ui/UILayout.h" #include "../ui/UILayout.cpp" #include "../ui/UITheme.h" +#include "../scene/SceneInfo.h" #include "../system/FileUtils.cpp" #include "../compiler/CompilerUtils.h" @@ -43,14 +44,14 @@ void cmd_buffer_create(AppCmdBuffer* cb, BufferMemory* buf, int32 commands_count // This doesn't load the asset directly but tells (most likely) a worker thread to load an asset static inline -void cmd_asset_load_enqueue(AppCmdBuffer* cb, Command* cmd) +void cmd_asset_load_enqueue(AppCmdBuffer* __restrict cb, Command* __restrict cmd) { queue_enqueue_wait_atomic(cb->assets_to_load, (byte *) cmd->data); } // This doesn't load the file directly but tells (most likely) a worker thread to load a file static inline -void cmd_file_load_enqueue(AppCmdBuffer* cb, Command* cmd) +void cmd_file_load_enqueue(AppCmdBuffer* __restrict cb, Command* __restrict cmd) { // cmd->data structure: // start with a pointer to a callback function @@ -59,9 +60,9 @@ void cmd_file_load_enqueue(AppCmdBuffer* cb, Command* cmd) } static inline -void cmd_file_load(AppCmdBuffer* cb, Command* cmd) +void cmd_file_load(AppCmdBuffer* __restrict cb, Command* __restrict cmd) { - FileBody file; + FileBody file = {}; file_read((const char *) cmd->data + sizeof(CommandFunction), &file, cb->thrd_mem_vol); // WARNING: This is not the normal cmd.callback @@ -71,14 +72,14 @@ void cmd_file_load(AppCmdBuffer* cb, Command* cmd) } static inline -void* cmd_func_run(AppCmdBuffer* cb, Command* cmd) +void* cmd_func_run(AppCmdBuffer*, Command* cmd) { CommandFunction func = *((CommandFunction *) cmd->data); return func(cmd); } static inline -Asset* cmd_asset_load(AppCmdBuffer* cb, Command* cmd) +Asset* cmd_asset_load(AppCmdBuffer* __restrict cb, Command* __restrict cmd) { int32 asset_id = (int32) str_to_int((char *) cmd->data); int32 archive_id = (asset_id >> 24) & 0xFF; @@ -86,7 +87,7 @@ Asset* cmd_asset_load(AppCmdBuffer* cb, Command* cmd) } static inline -Asset* cmd_audio_play_enqueue(AppCmdBuffer* cb, Command* cmd) +Asset* cmd_audio_play_enqueue(AppCmdBuffer* __restrict cb, Command* __restrict cmd) { Asset* asset = thrd_ams_get_asset_wait(cb->ams, (char *) cmd->data); if (!asset) { @@ -104,7 +105,7 @@ Asset* cmd_audio_play_enqueue(AppCmdBuffer* cb, Command* cmd) } static inline -Asset* cmd_audio_play_async(AppCmdBuffer* cb, Command* cmd) +Asset* cmd_audio_play_async(AppCmdBuffer* __restrict cb, Command* __restrict cmd) { Asset* asset = thrd_ams_get_asset_wait(cb->ams, (char *) cmd->data); if (!asset) { @@ -117,7 +118,7 @@ Asset* cmd_audio_play_async(AppCmdBuffer* cb, Command* cmd) } static inline -Asset* cmd_texture_create(AppCmdBuffer* cb, Command* cmd) +Asset* cmd_texture_create(AppCmdBuffer* __restrict cb, Command* __restrict cmd) { Asset* asset = thrd_ams_get_asset_wait(cb->ams, (char *) cmd->data); if (!asset) { @@ -135,7 +136,7 @@ Asset* cmd_texture_create(AppCmdBuffer* cb, Command* cmd) } static inline -Asset* cmd_texture_load_async(AppCmdBuffer* cb, Command* cmd) +Asset* cmd_texture_load_async(AppCmdBuffer* __restrict cb, Command* __restrict cmd) { Asset* asset = thrd_ams_get_asset_wait(cb->ams, (char *) cmd->data); if (!asset) { @@ -148,7 +149,7 @@ Asset* cmd_texture_load_async(AppCmdBuffer* cb, Command* cmd) } static inline -Asset* cmd_font_create(AppCmdBuffer* cb, Command* cmd) +Asset* cmd_font_create(AppCmdBuffer* __restrict cb, Command* __restrict cmd) { Asset* asset = thrd_ams_get_asset_wait(cb->ams, (char *) cmd->data); if (!asset) { @@ -164,7 +165,7 @@ Asset* cmd_font_create(AppCmdBuffer* cb, Command* cmd) } static inline -Asset* cmd_font_load_async(AppCmdBuffer* cb, Command* cmd) +Asset* cmd_font_load_async(AppCmdBuffer* __restrict cb, Command* __restrict cmd) { Asset* asset = thrd_ams_get_asset_wait(cb->ams, (char *) cmd->data); if (!asset) { @@ -177,7 +178,7 @@ Asset* cmd_font_load_async(AppCmdBuffer* cb, Command* cmd) } inline -void thrd_cmd_insert(AppCmdBuffer* cb, Command* cmd_temp) +void thrd_cmd_insert(AppCmdBuffer* __restrict cb, Command* __restrict cmd_temp) { pthread_mutex_lock(&cb->mutex); int32 index = chunk_reserve(&cb->commands, 1); @@ -201,6 +202,7 @@ inline void thrd_cmd_insert(AppCmdBuffer* cb, CommandType type, int32 data) { Command cmd; + cmd.callback = NULL; cmd.type = type; *((int32 *) cmd.data) = data; @@ -211,14 +213,16 @@ inline void thrd_cmd_insert(AppCmdBuffer* cb, CommandType type, const char* data) { Command cmd; + cmd.callback = NULL; cmd.type = type; str_copy_short((char *) cmd.data, data); thrd_cmd_insert(cb, &cmd); } -inline void thrd_cmd_func_insert(AppCmdBuffer* cb, CommandType type, CommandFunction* func) { +inline void thrd_cmd_func_insert(AppCmdBuffer* cb, CommandFunction* func) { Command cmd; + cmd.callback = NULL; cmd.type = CMD_FUNC_RUN; *((CommandFunction *) cmd.data) = *func; @@ -227,6 +231,7 @@ inline void thrd_cmd_func_insert(AppCmdBuffer* cb, CommandType type, CommandFunc inline void thrd_cmd_audio_play(AppCmdBuffer* cb, int32 data) { Command cmd; + cmd.callback = NULL; cmd.type = CMD_AUDIO_PLAY; *((int32 *) cmd.data) = data; @@ -235,6 +240,7 @@ inline void thrd_cmd_audio_play(AppCmdBuffer* cb, int32 data) { inline void thrd_cmd_audio_play(AppCmdBuffer* cb, const char* data) { Command cmd; + cmd.callback = NULL; cmd.type = CMD_AUDIO_PLAY; str_copy_short((char *) cmd.data, data); @@ -243,6 +249,7 @@ inline void thrd_cmd_audio_play(AppCmdBuffer* cb, const char* data) { inline void thrd_cmd_func_run(AppCmdBuffer* cb, CommandFunction* func) { Command cmd; + cmd.callback = NULL; cmd.type = CMD_FUNC_RUN; *((CommandFunction *) cmd.data) = *func; @@ -251,6 +258,7 @@ inline void thrd_cmd_func_run(AppCmdBuffer* cb, CommandFunction* func) { inline void thrd_cmd_texture_load(AppCmdBuffer* cb, int32 data) { Command cmd; + cmd.callback = NULL; cmd.type = CMD_TEXTURE_LOAD; *((int32 *) cmd.data) = data; @@ -259,6 +267,7 @@ inline void thrd_cmd_texture_load(AppCmdBuffer* cb, int32 data) { inline void thrd_cmd_texture_load(AppCmdBuffer* cb, const char* data) { Command cmd; + cmd.callback = NULL; cmd.type = CMD_TEXTURE_LOAD; str_copy_short((char *) cmd.data, data); @@ -267,6 +276,7 @@ inline void thrd_cmd_texture_load(AppCmdBuffer* cb, const char* data) { inline void thrd_cmd_font_load(AppCmdBuffer* cb, int32 data) { Command cmd; + cmd.callback = NULL; cmd.type = CMD_FONT_LOAD; *((int32 *) cmd.data) = data; @@ -275,6 +285,7 @@ inline void thrd_cmd_font_load(AppCmdBuffer* cb, int32 data) { inline void thrd_cmd_font_load(AppCmdBuffer* cb, const char* data) { Command cmd; + cmd.callback = NULL; cmd.type = CMD_FONT_LOAD; str_copy_short((char *) cmd.data, data); @@ -339,7 +350,7 @@ inline Asset* cmd_audio_play(AppCmdBuffer* cb, const char* name) { return asset; } -inline void* cmd_func_run(AppCmdBuffer* cb, CommandFunction func) { +inline void* cmd_func_run(AppCmdBuffer*, CommandFunction func) { return func(NULL); } @@ -444,8 +455,14 @@ UILayout* cmd_layout_load_sync( AppCmdBuffer* cb, UILayout* layout, const char* layout_path ) { - FileBody layout_file; + FileBody layout_file = {}; file_read(layout_path, &layout_file, cb->mem_vol); + + if (!layout_file.content) { + LOG_FORMAT(layout_file.content == NULL, "Failed loading layout \"%s\"\n", {{LOG_DATA_CHAR_STR, &layout_path}}); + return NULL; + } + layout_from_data(layout_file.content, layout); return layout; @@ -456,7 +473,7 @@ UIThemeStyle* cmd_theme_load_sync( AppCmdBuffer* cb, UIThemeStyle* theme, const char* theme_path ) { - FileBody theme_file; + FileBody theme_file = {}; file_read(theme_path, &theme_file, cb->mem_vol); theme_from_data(theme_file.content, theme); @@ -465,7 +482,7 @@ UIThemeStyle* cmd_theme_load_sync( inline void cmd_layout_populate_sync( - AppCmdBuffer* cb, + AppCmdBuffer*, UILayout* layout, const UIThemeStyle* theme, const Camera* camera ) { @@ -474,15 +491,20 @@ void cmd_layout_populate_sync( inline UILayout* cmd_ui_load_sync( - AppCmdBuffer* cb, - UILayout* layout, const char* layout_path, - UIThemeStyle* general_theme, - UIThemeStyle* theme, const char* theme_path, - const Camera* camera + AppCmdBuffer* __restrict cb, + UILayout* __restrict layout, const char* __restrict layout_path, + UIThemeStyle* __restrict general_theme, + UIThemeStyle* __restrict theme, const char* __restrict theme_path, + const Camera* __restrict camera ) { - cmd_layout_load_sync(cb, layout, layout_path); - cmd_layout_populate_sync(cb, layout, general_theme, camera); + if (!cmd_layout_load_sync(cb, layout, layout_path)) { + // We have to make sure that at least the font is set + layout->font = general_theme->font; + return NULL; + } + + cmd_layout_populate_sync(cb, layout, general_theme, camera); cmd_theme_load_sync(cb, theme, theme_path); cmd_layout_populate_sync(cb, layout, theme, camera); @@ -490,43 +512,41 @@ UILayout* cmd_ui_load_sync( } static inline -UILayout* cmd_ui_load(AppCmdBuffer* cb, Command* cmd) +UILayout* cmd_ui_load(AppCmdBuffer* __restrict cb, const Command* __restrict cmd) { - byte* pos = cmd->data; + const byte* pos = cmd->data; - UILayout* layout = (UILayout *) pos; + SceneInfo* scene = (SceneInfo *) *((uintptr_t *) pos); pos += sizeof(uintptr_t); char* layout_path = (char *) pos; str_move_to((const char **) &pos, '\0'); ++pos; - UIThemeStyle* general_theme = (UIThemeStyle *) pos; - pos += sizeof(uintptr_t); - - UIThemeStyle* theme = (UIThemeStyle *) pos; + UIThemeStyle* general_theme = (UIThemeStyle *) *((uintptr_t *) pos); pos += sizeof(uintptr_t); char* theme_path = (char *) pos; str_move_to((const char **) &pos, '\0'); ++pos; - Camera* camera = (Camera *) pos; + Camera* camera = (Camera *) *((uintptr_t *) pos); return cmd_ui_load_sync( cb, - layout, layout_path, + &scene->ui_layout, layout_path, general_theme, - theme, theme_path, + &scene->ui_theme, theme_path, camera ); } inline void thrd_cmd_ui_load( - AppCmdBuffer* cb, - UILayout* layout, const char* layout_path, - UIThemeStyle* general_theme, - UIThemeStyle* theme, const char* theme_path, - const Camera* camera, + AppCmdBuffer* __restrict cb, + SceneInfo* __restrict scene_info, + const char* __restrict layout_path, + UIThemeStyle* __restrict general_theme, + const char* __restrict theme_path, + const Camera* __restrict camera, CommandFunction callback ) { Command cmd; @@ -534,8 +554,8 @@ void thrd_cmd_ui_load( cmd.callback = callback; byte* pos = cmd.data; - // Layout pointer - *((uintptr_t *) pos) = (uintptr_t) layout; + // Scene info pointer + *((uintptr_t *) pos) = (uintptr_t) scene_info; pos += sizeof(uintptr_t); // Layout path @@ -546,10 +566,6 @@ void thrd_cmd_ui_load( *((uintptr_t *) pos) = (uintptr_t) general_theme; pos += sizeof(uintptr_t); - // Theme pointer - *((uintptr_t *) pos) = (uintptr_t) theme; - pos += sizeof(uintptr_t); - // Theme path pos += str_copy_until((char *) pos, theme_path, '\0'); *pos = '\0'; ++pos; @@ -571,7 +587,7 @@ void thrd_cmd_ui_load( void cmd_iterate(AppCmdBuffer* cb) { int32 last_element = 0; - int32 chunk_id = 0; + uint32 chunk_id = 0; chunk_iterate_start(&cb->commands, chunk_id) Command* cmd = (Command *) chunk_get_element(&cb->commands, chunk_id); bool remove = true; @@ -614,7 +630,7 @@ void cmd_iterate(AppCmdBuffer* cb) remove = cmd_shader_load(cb, cmd) != NULL; } break; case CMD_UI_LOAD: { - remove = cmd_ui_load(cb, cmd) != NULL; + cmd_ui_load(cb, cmd); } break; default: { UNREACHABLE(); @@ -634,7 +650,7 @@ void cmd_iterate(AppCmdBuffer* cb) // @performance This adds some unnecessary overhead. // It would be better, if we could define cb->last_element as the limit in the for loop - if (chunk_id == cb->last_element) { + if (chunk_id == (uint32) cb->last_element) { break; } chunk_iterate_end; diff --git a/command/AppCmdBuffer.h b/command/AppCmdBuffer.h index 1b6f1cc..733a98c 100644 --- a/command/AppCmdBuffer.h +++ b/command/AppCmdBuffer.h @@ -49,14 +49,14 @@ struct AppCmdBuffer { #if OPENGL #include "../gpuapi/opengl/AppCmdBuffer.h" #elif VULKAN - inline void* cmd_shader_load(AppCmdBuffer* cb, Command* cmd) { return NULL; } - inline void* cmd_shader_load_sync(AppCmdBuffer* cb, void* shader, int32* shader_ids) { return NULL; } + inline void* cmd_shader_load(AppCmdBuffer*, Command*) { return NULL; } + inline void* cmd_shader_load_sync(AppCmdBuffer*, void*, int32*) { return NULL; } #elif DIRECTX - inline void* cmd_shader_load(AppCmdBuffer* cb, Command* cmd) { return NULL; } - inline void* cmd_shader_load_sync(AppCmdBuffer* cb, void* shader, int32* shader_ids) { return NULL; } + inline void* cmd_shader_load(AppCmdBuffer*, Command*) { return NULL; } + inline void* cmd_shader_load_sync(AppCmdBuffer*, void*, int32*) { return NULL; } #else - inline void* cmd_shader_load(AppCmdBuffer* cb, Command* cmd) { return NULL; } - inline void* cmd_shader_load_sync(AppCmdBuffer* cb, void* shader, int32* shader_ids) { return NULL; } + inline void* cmd_shader_load(AppCmdBuffer*, Command*) { return NULL; } + inline void* cmd_shader_load_sync(AppCmdBuffer*, void*, int32*) { return NULL; } #endif #endif \ No newline at end of file diff --git a/compiler/gcc/CompilerUtils.h b/compiler/gcc/CompilerUtils.h index 42773de..69766d5 100644 --- a/compiler/gcc/CompilerUtils.h +++ b/compiler/gcc/CompilerUtils.h @@ -22,4 +22,60 @@ #define UNREACHABLE() __builtin_unreachable() #endif +#define FORCE_INLINE __attribute__((always_inline)) + +#define compiler_popcount_32(data) __builtin_popcount((data)) +#define compiler_popcount_64(data) __builtin_popcountl((data)) +#define __restrict __restrict__ + +#define compiler_prefetch(mem) __builtin_prefetch((mem), 0, 3) + +int32 compiler_find_first_bit_r2l(uint64 mask) { + if (!mask) { + return -1; + } + + #if __LITTLE_ENDIAN__ + return return 63 - __builtin_clzll(mask); + #else + return __builtin_ctzll(mask); + #endif +} + +int32 compiler_find_first_bit_r2l(uint32 mask) { + if (!mask) { + return -1; + } + + #if __LITTLE_ENDIAN__ + return __builtin_ctz(mask); + #else + return 31 - __builtin_clz(mask); + #endif +} + +int32 compiler_find_first_bit_l2r(uint64 mask) { + if (!mask) { + return -1; + } + + #if __LITTLE_ENDIAN__ + return return 63 - __builtin_clzll(mask); + #else + return __builtin_ctzll(mask); + #endif +} + +int32 compiler_find_first_bit_l2r(uint32 mask) { + if (!mask) { + return -1; + } + + #if __LITTLE_ENDIAN__ + return __builtin_ctz(mask); + #else + return 31 - __builtin_clz(mask); + #endif +} + #endif \ No newline at end of file diff --git a/compiler/msvc/CompilerUtils.h b/compiler/msvc/CompilerUtils.h index 6461532..d697833 100644 --- a/compiler/msvc/CompilerUtils.h +++ b/compiler/msvc/CompilerUtils.h @@ -20,9 +20,64 @@ typedef SSIZE_T ssize_t; #if DEBUG - #define UNREACHABLE() ASSERT_SIMPLE(false) + #define UNREACHABLE() ASSERT_SIMPLE(false) __assume(0) #else #define UNREACHABLE() __assume(0) #endif +#define FORCE_INLINE __forceinline + +#define compiler_popcount_32(data) __popcnt((data)) +#define compiler_popcount_64(data) __popcnt64((data)) + +#define compiler_prefetch(mem) __prefetch((mem)) + +inline +int32 compiler_find_first_bit_r2l(uint64 mask) { + if (!mask) { + return -1; + } + + unsigned long index; + _BitScanForward64(&index, mask); + + return index; +} + +inline +int32 compiler_find_first_bit_r2l(uint32 mask) { + if (!mask) { + return -1; + } + + unsigned long index; + _BitScanForward(&index, mask); + + return index; +} + +inline +int32 compiler_find_first_bit_l2r(uint64 mask) { + if (!mask) { + return -1; + } + + unsigned long index; + _BitScanReverse64(&index, mask); + + return index; +} + +inline +int32 compiler_find_first_bit_l2r(uint32 mask) { + if (!mask) { + return -1; + } + + unsigned long index; + _BitScanReverse(&index, mask); + + return index; +} + #endif \ No newline at end of file diff --git a/entity/AnimationEntityComponent.h b/entity/AnimationEntityComponent.h index 8286aac..974fab8 100644 --- a/entity/AnimationEntityComponent.h +++ b/entity/AnimationEntityComponent.h @@ -55,7 +55,7 @@ void update_animation_entity(AnimationEntityComponent* anim, uint32 time, uint32 void update_animation_entities(ChunkMemory* anim_ec, uint32 time, uint32 delay) { - int32 chunk_id = 0; + uint32 chunk_id = 0; chunk_iterate_start(anim_ec, chunk_id) AnimationEntityComponent* anim = (AnimationEntityComponent *) chunk_get_element(anim_ec, chunk_id); if (anim->setting & ANIMATION_SETTING_PAUSE) { diff --git a/entity/EntityComponentSystem.h b/entity/EntityComponentSystem.h index 67224f4..720edfa 100644 --- a/entity/EntityComponentSystem.h +++ b/entity/EntityComponentSystem.h @@ -108,7 +108,7 @@ Entity* ecs_insert_entity(EntityComponentSystem* ecs, Entity* entity_temp, int32 memcpy(entity, entity_temp, mem->chunk_size); // @todo log entity stats (count, ram, vram) - //DEBUG_MEMORY_RESERVE((uintptr_t) entity, entity->ram_size, 180); + //DEBUG_MEMORY_RESERVE((uintptr_t) entity, entity->ram_size); return entity; } diff --git a/environment/Globe.h b/environment/Globe.h index c46de5b..885f055 100644 --- a/environment/Globe.h +++ b/environment/Globe.h @@ -13,11 +13,10 @@ * @return f32 A day time ranging from 0.0 to 1.0 */ f32 time_of_day(f64 time, f32 day_length) { - f64 t = time; - t /= day_length; - t -= (int32) t; + time /= day_length; + time -= (int64) time; - return (f32) t; + return (f32) time; } /** diff --git a/font/Font.h b/font/Font.h index 5fda67d..d1326e5 100644 --- a/font/Font.h +++ b/font/Font.h @@ -49,8 +49,8 @@ void font_init(Font* font, byte* data, int count) inline Glyph* font_glyph_find(const Font* font, uint32 codepoint) { - int32 perfect_glyph_pos = codepoint - font->glyphs[0].codepoint; - int32 limit = OMS_MIN(perfect_glyph_pos, font->glyph_count - 1); + uint32 perfect_glyph_pos = codepoint - font->glyphs[0].codepoint; + uint32 limit = OMS_MIN(perfect_glyph_pos, font->glyph_count - 1); // We try to jump to the correct glyph based on the glyph codepoint if (font->glyphs[limit].codepoint == codepoint) { @@ -81,11 +81,11 @@ void font_from_file_txt( RingMemory* ring ) { - FileBody file; + FileBody file = {}; file_read(path, &file, ring); ASSERT_SIMPLE(file.size); - char* pos = (char *) file.content; + const char* pos = (char *) file.content; bool start = true; char block_name[32]; @@ -121,16 +121,16 @@ void font_from_file_txt( *texture_pos++ = '\0'; } else if (str_compare(block_name, "font_size") == 0) { - font->size = strtof(pos, &pos); + font->size = str_to_float(pos, &pos); } else if (str_compare(block_name, "line_height") == 0) { - font->line_height = strtof(pos, &pos); + font->line_height = str_to_float(pos, &pos); } else if (str_compare(block_name, "image_width") == 0) { - image_width = strtoul(pos, &pos, 10); + image_width = (int32) str_to_int(pos, &pos); } else if (str_compare(block_name, "image_height") == 0) { - image_height = strtoul(pos, &pos, 10); + image_height = (int32) str_to_int(pos, &pos); } else if (str_compare(block_name, "glyph_count") == 0) { // glyph_count has to be the last general element - font->glyph_count = strtoul(pos, &pos, 10); + font->glyph_count = (uint32) str_to_int(pos, &pos); start = false; } @@ -140,9 +140,9 @@ void font_from_file_txt( // Parsing glyphs // In the text file we don't have to define width and height of the character, we calculate that here font->glyphs[glyph_index] = { - strtoul(pos, &pos, 10), - {0.0f, 0.0f, strtof(++pos, &pos), strtof(++pos, &pos), strtof(++pos, &pos)}, - {strtof(++pos, &pos), strtof(++pos, &pos), strtof(++pos, &pos), strtof(++pos, &pos)} + (uint32) str_to_int(pos, &pos), + {0.0f, 0.0f, str_to_float(++pos, &pos), str_to_float(++pos, &pos), str_to_float(++pos, &pos)}, + {str_to_float(++pos, &pos), str_to_float(++pos, &pos), str_to_float(++pos, &pos), str_to_float(++pos, &pos)} }; font->glyphs[glyph_index].metrics.width = font->glyphs[glyph_index].coords.end.x - font->glyphs[glyph_index].coords.start.x; @@ -177,7 +177,7 @@ int32 font_data_size(const Font* font) int32 font_from_data( const byte* data, Font* font, - int32 steps = 8 + [[maybe_unused]] int32 steps = 8 ) { const byte* pos = data; @@ -213,7 +213,7 @@ int32 font_from_data( int32 font_to_data( const Font* font, byte* data, - int32 steps = 8 + [[maybe_unused]] int32 steps = 8 ) { byte* pos = data; diff --git a/gpuapi/RenderUtils.h b/gpuapi/RenderUtils.h index 961f2c5..69b803b 100644 --- a/gpuapi/RenderUtils.h +++ b/gpuapi/RenderUtils.h @@ -27,13 +27,13 @@ int32 vertex_degenerate_create( // They are alternating every loop BUT since we use references they look the same in code // WARNING: Before using we must make sure that the 0 index is defined // The easiest way is to just define a "degenerate" starting point - vertices[0] = {{vertices[0 - 1].position.x, vertices[0 - 1].position.y, zindex}, {0, 0}}; - vertices[1] = {{x, y, zindex}, {0, 0}}; + vertices[0] = {{vertices[-1].position.x, vertices[-1].position.y, zindex}, {}}; + vertices[1] = {{x, y, zindex}, {}}; return 2; } -inline +static inline void adjust_aligned_position( f32* __restrict x, f32* __restrict y, f32 width, f32 height, @@ -53,6 +53,25 @@ void adjust_aligned_position( } } +static inline +void adjust_aligned_position( + v4_f32* vec, + byte alignment +) +{ + if (alignment & UI_ALIGN_H_RIGHT) { + vec->x -= vec->width; + } else if (alignment & UI_ALIGN_H_CENTER) { + vec->x -= vec->width / 2; + } + + if (alignment & UI_ALIGN_V_TOP) { + vec->y -= vec->height; + } else if (alignment & UI_ALIGN_V_CENTER) { + vec->y -= vec->height / 2; + } +} + inline int32 vertex_line_create( Vertex3DTextureColor* __restrict vertices, f32 zindex, @@ -81,12 +100,15 @@ int32 vertex_line_create( f32 norm1 = n1 * n_; f32 norm2 = n2 * n_; - int32 idx = vertex_degenerate_create(vertices, zindex, start.x, start.y); + int32 idx = 0; - vertices[idx++] = {{start.x, start.y, zindex}, {-((f32) rgba), 0.0f}}; - vertices[idx++] = {{start.x + thickness * norm1, start.y + thickness * norm2, zindex}, {-((f32) rgba), 0.0f}}; - vertices[idx++] = {{end.x, end.y, zindex}, {-((f32) rgba), 0.0f}}; - vertices[idx++] = {{end.x + thickness * norm1, end.y + thickness * norm2, zindex}, {-((f32) rgba), 0.0f}}; + vertices[idx++] = {{start.x, start.y, zindex}, {-1.0f, BITCAST(rgba, f32)}}; + vertices[idx++] = {{start.x + thickness * norm1, start.y + thickness * norm2, zindex}, {-1.0f, BITCAST(rgba, f32)}}; + vertices[idx++] = {{end.x, end.y, zindex}, {-1.0f, BITCAST(rgba, f32)}}; + + vertices[idx++] = {{end.x, end.y, zindex}, {-1.0f, BITCAST(rgba, f32)}}; + vertices[idx++] = {{end.x + thickness * norm1, end.y + thickness * norm2, zindex}, {-1.0f, BITCAST(rgba, f32)}}; + vertices[idx++] = {{start.x + thickness * norm1, start.y + thickness * norm2, zindex}, {-1.0f, BITCAST(rgba, f32)}}; return idx; } @@ -97,26 +119,31 @@ inline int32 vertex_rect_create( Vertex3DTextureColor* __restrict vertices, f32 zindex, v4_f32 dimension, byte alignment, - uint32 rgba = 0, v2_f32 tex1 = {0}, v2_f32 tex2 = {0} + uint32 rgba = 0, v2_f32 tex1 = {}, v2_f32 tex2 = {} ) { if (alignment) { - adjust_aligned_position(&dimension.x, &dimension.y, dimension.width, dimension.height, alignment); + adjust_aligned_position(&dimension, alignment); } if (rgba) { - tex1.x = -((f32) rgba); - tex2.x = -((f32) rgba); - } + tex1.x = -1.0f; + tex1.y = BITCAST(rgba, f32); - int32 idx = vertex_degenerate_create(vertices, zindex, dimension.x, dimension.y); + tex2.x = -1.0f; + tex2.y = BITCAST(rgba, f32); + } f32 y_height = dimension.y + dimension.height; f32 x_width = dimension.x + dimension.width; + int32 idx = 0; - vertices[idx++] = {{dimension.x, dimension.y, zindex}, {tex1.x, tex1.y}}; + vertices[idx++] = {{dimension.x, dimension.y, zindex}, tex1}; vertices[idx++] = {{dimension.x, y_height, zindex}, {tex1.x, tex2.y}}; vertices[idx++] = {{x_width, dimension.y, zindex}, {tex2.x, tex1.y}}; - vertices[idx++] = {{x_width, y_height, zindex}, {tex2.x, tex2.y}}; + + vertices[idx++] = {{x_width, dimension.y, zindex}, {tex2.x, tex1.y}}; + vertices[idx++] = {{dimension.x, y_height, zindex}, {tex1.x, tex2.y}}; + vertices[idx++] = {{x_width, y_height, zindex}, tex2}; return idx; } @@ -214,13 +241,19 @@ v3_int32 vertex_text_create( Vertex3DTextureColor* __restrict vertices, f32 zindex, v4_f32 dimension, byte alignment, const Font* __restrict font, const char* __restrict text, - f32 size, uint32 rgba = 0, - f32 font_weight = 1.0f + f32 size, uint32 rgba = 0 ) { - int32 length = utf8_strlen(text); - bool is_ascii = (int32) strlen(text) == length; + int32 length = utf8_str_length(text); + if (length < 1) { + return {}; + } + + bool is_ascii = (int32) str_length(text) == length; f32 scale = size / font->size; + (void) rgba; // @todo we don't have a way to change colors of text for now due to our reduce Vertex size + // To fix this we would have to add an additional 4 bytes for every vertex which we maybe don't want to + // If we do a different alignment we need to pre-calculate the width and height if (alignment & (UI_ALIGN_H_RIGHT | UI_ALIGN_H_CENTER | UI_ALIGN_V_TOP | UI_ALIGN_V_CENTER)) { if ((alignment & (UI_ALIGN_H_RIGHT | UI_ALIGN_H_CENTER)) @@ -233,7 +266,7 @@ v3_int32 vertex_text_create( dimension.height = text_calculate_dimensions_height(font, text, scale, length); } - adjust_aligned_position(&dimension.x, &dimension.y, dimension.width, dimension.height, alignment); + adjust_aligned_position(&dimension, alignment); } f32 line_height_scaled = font->line_height * scale; @@ -267,9 +300,9 @@ v3_int32 vertex_text_create( if (character != ' ' && character != '\t') { // @todo We should probably inline the code here, we might be able to even optimize it then idx += vertex_rect_create( - vertices, zindex, + vertices + idx, zindex, {offset_x, offset_y, glyph->metrics.width * scale, glyph->metrics.height * scale}, 0, - rgba, glyph->coords.start, glyph->coords.end + 0, glyph->coords.start, glyph->coords.end ); } diff --git a/gpuapi/opengl/AppCmdBuffer.h b/gpuapi/opengl/AppCmdBuffer.h index 4bfe048..463e7f2 100644 --- a/gpuapi/opengl/AppCmdBuffer.h +++ b/gpuapi/opengl/AppCmdBuffer.h @@ -16,7 +16,7 @@ #include "../ShaderType.h" #include "../../asset/Asset.h" -void* cmd_shader_load(AppCmdBuffer* cb, Command* cmd) { +void* cmd_shader_load(AppCmdBuffer*, Command*) { return NULL; } diff --git a/gpuapi/opengl/OpenglUtils.h b/gpuapi/opengl/OpenglUtils.h index 20eb4ff..41f8696 100644 --- a/gpuapi/opengl/OpenglUtils.h +++ b/gpuapi/opengl/OpenglUtils.h @@ -26,6 +26,21 @@ #include "../../platform/linux/Window.h" #endif +#if DEBUG + void gpuapi_error() + { + GLenum err; + while ((err = glGetError()) != GL_NO_ERROR) { + LOG_FORMAT(true, "Opengl error: %d", {{LOG_DATA_INT32, (int32 *) &err}}); + ASSERT_SIMPLE(err == GL_NO_ERROR); + } + } + + #define ASSERT_GPU_API() gpuapi_error() +#else + #define ASSERT_GPU_API() ((void) 0) +#endif + struct OpenglFrameData { uint32 framebuffer; uint32 renderbuffer; @@ -38,7 +53,7 @@ struct OpenglFrameData { Texture* texture_msaa; }; -void opengl_debug_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) +void opengl_debug_callback(GLenum, GLenum, GLuint, GLenum severity, GLsizei, const GLchar* message, const void*) { if (severity < GL_DEBUG_SEVERITY_LOW) { return; @@ -213,15 +228,10 @@ void draw_triangles_3d_textureless(VertexRef* vertices, GLuint buffer, int32 cou glVertexAttribPointer(vertices->normal_id, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex3D), (void *) (sizeof(f32) * 3)); glEnableVertexAttribArray(vertices->normal_id); - // color attribute - glVertexAttribPointer(vertices->color_id, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex3D), (void *) (sizeof(f32) * 8)); - glEnableVertexAttribArray(vertices->color_id); - glDrawArrays(GL_TRIANGLES, 0, count); glDisableVertexAttribArray(vertices->data_id); glDisableVertexAttribArray(vertices->normal_id); - glDisableVertexAttribArray(vertices->color_id); glBindBuffer(GL_ARRAY_BUFFER, 0); } @@ -264,10 +274,6 @@ void draw_triangles_2d(VertexRef* vertices, GLuint buffer, int32 count) { glVertexAttribIPointer(vertices->tex_coord_id, 2, GL_UNSIGNED_INT, sizeof(Vertex2D), (void *) (sizeof(f32) * 2)); glEnableVertexAttribArray(vertices->tex_coord_id); - // color attribute - glVertexAttribPointer(vertices->color_id, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), (void *) (sizeof(f32) * 4)); - glEnableVertexAttribArray(vertices->color_id); - glDrawArrays(GL_TRIANGLES, 0, count); glDisableVertexAttribArray(vertices->position_id); @@ -389,6 +395,7 @@ void gpuapi_buffer_update_sub(uint32 vbo, int32 offset, int32 size, const void* { glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferSubData(GL_ARRAY_BUFFER, offset, size, data); + ASSERT_GPU_API(); LOG_INCREMENT_BY(DEBUG_COUNTER_GPU_UPLOAD, size); } @@ -405,25 +412,6 @@ uint32 gpuapi_shaderbuffer_generate(int32 size, const void* data) return sbo; } -// @todo this is not necessary?! We have a flag to determine the BindTexture Type -// Only problem are the parameters -uint32 gpuapi_upload_color_palette(const byte* palette, int32 count, int32 sampler_id) -{ - uint32 texture_id; - - glGenTextures(1, &texture_id); - glActiveTexture(GL_TEXTURE0 + sampler_id); - glBindTexture(GL_TEXTURE_1D, texture_id); - - glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, count, 0, GL_RGBA, GL_UNSIGNED_BYTE, palette); - - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - return texture_id; -} - inline uint32 gpuapi_uniformbuffer_generate(int32 size, const void* data) { @@ -491,21 +479,6 @@ int get_gpu_free_memory() return available; } -void gpuapi_error() -{ - GLenum err; - while ((err = glGetError()) != GL_NO_ERROR) { - LOG_FORMAT(true, "Opengl error: %d", {{LOG_DATA_INT32, (int32 *) &err}}); - ASSERT_SIMPLE(err == GL_NO_ERROR); - } -} - -#if DEBUG - #define ASSERT_GPU_API() gpuapi_error() -#else - #define ASSERT_GPU_API() ((void) 0) -#endif - /* void render_9_patch(GLuint texture, int32 imgWidth, int32 imgHeight, diff --git a/gpuapi/vulkan/ShaderUtils.h b/gpuapi/vulkan/ShaderUtils.h index 599af61..42c53a1 100644 --- a/gpuapi/vulkan/ShaderUtils.h +++ b/gpuapi/vulkan/ShaderUtils.h @@ -15,18 +15,19 @@ #include "../../memory/RingMemory.h" #include "../../log/Log.h" -inline uint32_t shader_get_uniform_location(VkWriteDescriptorSet* descriptor, VkDevice device, VkCommandBuffer commandBuffer, VkDescriptorSet descriptorSet, uint32_t binding, VkDescriptorType descriptorType) -{ - VkWriteDescriptorSet descriptorWrite = {}; - descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptorWrite.dstSet = descriptorSet; - descriptorWrite.dstBinding = binding; - descriptorWrite.dstArrayElement = 0; - descriptorWrite.descriptorType = descriptorType; - descriptorWrite.descriptorCount = 1; +inline uint32_t shader_get_uniform_location( + VkWriteDescriptorSet* descriptor, + VkDescriptorSet descriptorSet, uint32_t binding, VkDescriptorType descriptorType +) { + descriptor->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptor->dstSet = descriptorSet; + descriptor->dstBinding = binding; + descriptor->dstArrayElement = 0; + descriptor->descriptorType = descriptorType; + descriptor->descriptorCount = 1; } -inline void shader_set_value(VkDevice device, VkCommandBuffer commandBuffer, VkDescriptorSet descriptorSet, uint32_t binding, VkDescriptorType descriptorType, int32_t value) +inline void shader_set_value(VkDevice device, VkDescriptorSet descriptorSet, uint32_t binding, VkDescriptorType descriptorType, int32_t value) { VkDescriptorBufferInfo bufferInfo = {}; bufferInfo.buffer = {}; // You should have a buffer holding the value diff --git a/gpuapi/vulkan/VulkanUtils.h b/gpuapi/vulkan/VulkanUtils.h index ad97688..f473c47 100644 --- a/gpuapi/vulkan/VulkanUtils.h +++ b/gpuapi/vulkan/VulkanUtils.h @@ -52,6 +52,9 @@ struct VulkanSwapChainSupportDetails { inline void change_viewport(Window* w, int32 offset_x = 0, int32 offset_y = 0) { + (void *) w; + (void) offset_x; + (void) offset_y; // @todo implement } @@ -62,7 +65,7 @@ int32 vulkan_check_validation_layer_support(const char** validation_layers, uint VkLayerProperties* available_layers = (VkLayerProperties *) ring_get_memory(ring, layer_count * sizeof(VkLayerProperties)); vkEnumerateInstanceLayerProperties(&layer_count, available_layers); - for (int32 i = 0; i < validation_layer_count; ++i) { + for (uint32 i = 0; i < validation_layer_count; ++i) { bool layerFound = false; for (uint32 j = 0; j < layer_count; ++j) { @@ -73,7 +76,7 @@ int32 vulkan_check_validation_layer_support(const char** validation_layers, uint } if (!layerFound) { - return -(i + 1); + return -((int32) (i + 1)); } } @@ -87,7 +90,7 @@ int32 vulkan_check_extension_support(const char** extensions, uint32 extension_c VkExtensionProperties* available_extensions = (VkExtensionProperties *) ring_get_memory(ring, ext_count * sizeof(VkExtensionProperties)); vkEnumerateInstanceExtensionProperties(NULL, &ext_count, available_extensions); - for (int32 i = 0; i < extension_count; ++i) { + for (uint32 i = 0; i < extension_count; ++i) { bool layerFound = false; for (uint32 j = 0; j < ext_count; ++j) { @@ -98,7 +101,7 @@ int32 vulkan_check_extension_support(const char** extensions, uint32 extension_c } if (!layerFound) { - return -(i + 1); + return -((int32) (i + 1)); } } @@ -225,9 +228,9 @@ bool vulkan_device_supports_extensions(VkPhysicalDevice device, const char** dev VkExtensionProperties* available_extensions = (VkExtensionProperties *) ring_get_memory(ring, extension_count * sizeof(VkExtensionProperties)); vkEnumerateDeviceExtensionProperties(device, NULL, &extension_count, available_extensions); - for (int32 i = 0; i < device_extension_count; ++i) { + for (uint32 i = 0; i < device_extension_count; ++i) { bool found = false; - for (int32 j = 0; j < extension_count; ++j) { + for (uint32 j = 0; j < extension_count; ++j) { if (str_compare(device_extensions[i], available_extensions[j].extensionName) == 0) { found = true; break; @@ -269,7 +272,7 @@ VulkanQueueFamilyIndices vulkan_find_queue_families(VkPhysicalDevice physical_de VkQueueFamilyProperties* queue_families = (VkQueueFamilyProperties *) ring_get_memory(ring, (queue_family_count + 1) * sizeof(VkQueueFamilyProperties)); vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, queue_families); - for (int32 i = 0; i < queue_family_count; ++i) { + for (uint32 i = 0; i < queue_family_count; ++i) { if (queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { indices.graphics_family = i + 1; } @@ -338,7 +341,7 @@ void gpuapi_pick_physical_device( VkPhysicalDevice* devices = (VkPhysicalDevice *) ring_get_memory(ring, device_count * sizeof(VkPhysicalDevice)); vkEnumeratePhysicalDevices(instance, &device_count, devices); - for (int32 i = 0; i < device_count; ++i) { + for (uint32 i = 0; i < device_count; ++i) { if (vulkan_is_device_suitable(devices[i], surface, device_extensions, device_extension_count, ring)) { // @question Do we really have to do a memcpy or could we just assign? Isn't VkPhysicalDevice just a pointer internally? memcpy(physical_device, &devices[i], sizeof(VkPhysicalDevice)); @@ -351,7 +354,7 @@ void gpuapi_pick_physical_device( } void gpuapi_create_logical_device( - VkInstance instance, VkSurfaceKHR surface, VkDevice* device, VkPhysicalDevice physical_device, + VkSurfaceKHR surface, VkDevice* device, VkPhysicalDevice physical_device, VkQueue* graphics_queue, VkQueue* present_queue, const char** device_extensions, uint32 device_extension_count, const char** validation_layers, uint32 validation_layer_count, RingMemory* ring @@ -412,7 +415,7 @@ void vulkan_swap_chain_create( VulkanSwapChainSupportDetails swap_chain_support = vulkan_query_swap_chain_support(physical_device, surface, ring); VkSurfaceFormatKHR* surface_format = &swap_chain_support.formats[0]; - for (int32 i = 0; i < swap_chain_support.format_size; ++i) { + for (uint32 i = 0; i < swap_chain_support.format_size; ++i) { if (swap_chain_support.formats[i].format == VK_FORMAT_B8G8R8A8_SRGB && swap_chain_support.formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR ) { @@ -423,7 +426,7 @@ void vulkan_swap_chain_create( // @todo switch from VK_PRESENT_MODE_MAILBOX_KHR to VK_PRESENT_MODE_FIFO_KHR VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR; - for (int32 i = 0; i < swap_chain_support.present_mode_size; ++i) { + for (uint32 i = 0; i < swap_chain_support.present_mode_size; ++i) { if (swap_chain_support.present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { present_mode = swap_chain_support.present_modes[i]; break; @@ -579,12 +582,10 @@ void vulkan_pipeline_create( VkDevice device, VkShaderModule vertex_shader, VkShaderModule fragment_shader, - VkShaderModule geometry_shader, + [[maybe_unused]] VkShaderModule geometry_shader, VkPipeline* pipeline, VkPipelineLayout* pipeline_layout, - VkRenderPass render_pass, - const char* source, - int32 source_size + VkRenderPass render_pass ) { uint32 stage_count = 0; diff --git a/image/Bitmap.h b/image/Bitmap.h index 5e07773..1d31d35 100644 --- a/image/Bitmap.h +++ b/image/Bitmap.h @@ -45,8 +45,8 @@ struct DIB_BITMAPCOREHEADER { #define DIB_BITMAP_TYPE_BITMAPINFOHEADER 40 struct DIB_BITMAPINFOHEADER { uint32 size; - int32 width; - int32 height; + uint32 width; + uint32 height; uint16 color_planes; uint16 bits_per_pixel; uint32 compression_method; @@ -61,8 +61,8 @@ struct DIB_BITMAPINFOHEADER { // OR BITMAPINFOHEADER2 struct DIB_OS22XBITMAPHEADER { uint32 size; - int32 width; - int32 height; + uint32 width; + uint32 height; uint16 color_planes; uint16 bits_per_pixel; uint32 compression_method; @@ -123,8 +123,8 @@ struct TOS_CIEXYZTRIPLE { #define DIB_BITMAP_TYPE_BITMAPV4HEADER 108 struct DIB_BITMAPV4HEADER { int32 size; - int32 width; - int32 height; + uint32 width; + uint32 height; uint16 color_planes; uint16 bits_per_pixel; int32 compression_method; @@ -148,8 +148,8 @@ struct DIB_BITMAPV4HEADER { #define DIB_BITMAP_TYPE_BITMAPV5HEADER 124 struct DIB_BITMAPV5HEADER { int32 size; - int32 width; - int32 height; + uint32 width; + uint32 height; uint16 color_planes; uint16 bits_per_pixel; int32 compression_method; diff --git a/image/Image.cpp b/image/Image.cpp index 5f80a7c..118c48e 100644 --- a/image/Image.cpp +++ b/image/Image.cpp @@ -20,7 +20,7 @@ void image_from_file(Image* __restrict image, const char* __restrict path, RingMemory* __restrict ring) { - FileBody file; + FileBody file = {}; file_read(path, &file, ring); if (str_ends_with(path, ".png")) { diff --git a/image/Png.h b/image/Png.h index 0ea302a..6337fcc 100644 --- a/image/Png.h +++ b/image/Png.h @@ -215,7 +215,7 @@ uint8 png_filter_4(const uint8* x, const uint8* a_full, const uint8* b_full, con return x[channel] + (uint8) paeth; } -void png_filter_reconstruct(uint32 width, uint32 height, uint32 color_type, const uint8* decompressed, uint8* finalized, int32 steps = 8) +void png_filter_reconstruct(uint32 width, uint32 height, uint32 color_type, const uint8* decompressed, uint8* finalized, [[maybe_unused]] int32 steps = 8) { uint64 zero = 0; uint8* prev_row = (uint8 *) &zero; @@ -225,7 +225,7 @@ void png_filter_reconstruct(uint32 width, uint32 height, uint32 color_type, cons uint8* dest = finalized; uint8 bytes_per_pixel = color_type == 2 ? 3 : 4; - uint8 out_bytes_per_pixel = bytes_per_pixel; // @todo needs changing for tRANS + //uint8 out_bytes_per_pixel = bytes_per_pixel; // @todo needs changing for tRANS for (uint32 y = 0; y < height; ++y) { uint8 filter = *decompressed; diff --git a/image/Qoi.h b/image/Qoi.h index 044e18a..8b379fb 100644 --- a/image/Qoi.h +++ b/image/Qoi.h @@ -198,7 +198,7 @@ int32 qoi_decode_4(const byte* data, Image* image) v4_byte index[64] = {0}; int32 run = 0; - for (int32 px_pos = 0; px_pos < px_len; px_pos += 4) { + for (uint32 px_pos = 0; px_pos < px_len; px_pos += 4) { if (run > 0) { --run; } else { @@ -247,7 +247,7 @@ int32 qoi_decode_3(const byte* data, Image* image) v3_byte px = {0, 0, 0}; int32 run = 0; - for (int32 px_pos = 0; px_pos < px_len; px_pos += 3) { + for (uint32 px_pos = 0; px_pos < px_len; px_pos += 3) { if (run > 0) { --run; } else { diff --git a/localization/Language.h b/localization/Language.h index e2b3f7c..29c7ecd 100644 --- a/localization/Language.h +++ b/localization/Language.h @@ -23,7 +23,7 @@ void language_from_file_txt( const char* path, RingMemory* ring ) { - FileBody file; + FileBody file = {}; file_read(path, &file, ring); ASSERT_SIMPLE(file.size); diff --git a/log/Debug.cpp b/log/Debug.cpp index 1851989..908055c 100644 --- a/log/Debug.cpp +++ b/log/Debug.cpp @@ -153,18 +153,30 @@ void update_timing_stat_reset(uint32 stat) inline void reset_counter(int32 id) { + if (!debug_container || !debug_container->counter) { + return; + } + atomic_set_acquire(&debug_container->counter[id], 0); } inline void log_increment(int32 id, int64 by = 1) { + if (!debug_container || !debug_container->counter) { + return; + } + atomic_add_acquire(&debug_container->counter[id], by); } inline void log_counter(int32 id, int64 value) { + if (!debug_container || !debug_container->counter) { + return; + } + atomic_set_acquire(&debug_container->counter[id], value); } @@ -273,7 +285,7 @@ void debug_memory_reserve(uintptr_t start, uint64 size, int32 type, const char* } // undo reserve -void debug_memory_free(uintptr_t start, uint64 size) +void debug_memory_free(uintptr_t start) { if (!start || !debug_container) { return; @@ -335,7 +347,7 @@ void log(const char* str, bool should_log, const char* file, const char* functio return; } - int64 len = strlen(str); + int64 len = str_length(str); while (len > 0) { LogMessage* msg = (LogMessage *) log_get_memory(); @@ -344,6 +356,7 @@ void log(const char* str, bool should_log, const char* file, const char* functio msg->function = function; msg->line = line; msg->message = (char *) (msg + 1); + msg->time = system_time(); int32 message_length = (int32) OMS_MIN(MAX_LOG_LENGTH - sizeof(LogMessage) - 1, len); @@ -361,7 +374,7 @@ void log(const char* str, bool should_log, const char* file, const char* functio void log(const char* format, LogDataArray data, bool should_log, const char* file, const char* function, int32 line) { - ASSERT_SIMPLE(strlen(format) + strlen(file) + strlen(function) + 50 < MAX_LOG_LENGTH); + ASSERT_SIMPLE(str_length(format) + str_length(file) + str_length(function) + 50 < MAX_LOG_LENGTH); if (!should_log || !debug_container) { return; @@ -377,6 +390,7 @@ void log(const char* format, LogDataArray data, bool should_log, const char* fil msg->function = function; msg->line = line; msg->message = (char *) (msg + 1); + msg->time = system_time(); char temp_format[MAX_LOG_LENGTH]; str_copy_short(msg->message, format); @@ -389,6 +403,8 @@ void log(const char* format, LogDataArray data, bool should_log, const char* fil str_copy_short(temp_format, msg->message); switch (data.data[i].type) { + case LOG_DATA_NONE: { + } break; case LOG_DATA_BYTE: { sprintf_fast_iter(msg->message, temp_format, (int32) *((byte *) data.data[i].value)); } break; diff --git a/log/Debug.h b/log/Debug.h index bb7e43a..f6c263d 100644 --- a/log/Debug.h +++ b/log/Debug.h @@ -83,21 +83,20 @@ struct LogDataArray{ }; struct DebugContainer { + // Used to log memory access (read, write) DebugMemoryContainer dmc; + LogMemory log_memory; // Used for logging timings for different sections TimingStat* perf_stats; spinlock32 perf_stats_spinlock; - // Required to calculate the "fps" - uint64 performance_count_frequency; - - // Used to log memory access (read, write) - LogMemory log_memory; - // Used to log general int values (e.g. counter for draw calls etc.) int64* counter; + // Required to calculate the "fps" + uint64 performance_count_frequency; + // We are not using FileHandle here since that would require us to include more files // These files in return require Debug.h #if _WIN32 diff --git a/log/DebugMemory.h b/log/DebugMemory.h index be0f298..8c62257 100644 --- a/log/DebugMemory.h +++ b/log/DebugMemory.h @@ -41,26 +41,36 @@ struct DebugMemoryContainer { DebugMemory* memory_stats; }; +enum MemoryDebugType { + MEMORY_DEBUG_TYPE_DELETE = -1, + MEMORY_DEBUG_TYPE_READ = 0, + MEMORY_DEBUG_TYPE_WRITE = 1, + MEMORY_DEBUG_TYPE_RESERVE = 2, + MEMORY_DEBUG_TYPE_SUBREGION = 3, +}; + #if DEBUG || INTERNAL void debug_memory_init(uintptr_t, uint64); void debug_memory_log(uintptr_t, uint64, int32, const char*); void debug_memory_reserve(uintptr_t, uint64, int32, const char*); - void debug_memory_free(uintptr_t, uint64); + void debug_memory_free(uintptr_t); void debug_memory_reset(); #define DEBUG_MEMORY_INIT(start, size) debug_memory_init((start), (size)) - #define DEBUG_MEMORY_READ(start, size) debug_memory_log((start), (size), 0, __func__) - #define DEBUG_MEMORY_WRITE(start, size) debug_memory_log((start), (size), 1, __func__) - #define DEBUG_MEMORY_DELETE(start, size) debug_memory_log((start), (size), -1, __func__) - #define DEBUG_MEMORY_RESERVE(start, size, type) debug_memory_reserve((start), (size), (type), __func__) - #define DEBUG_MEMORY_FREE(start, size) debug_memory_free((start), (size)) + #define DEBUG_MEMORY_READ(start, size) debug_memory_log((start), (size), MEMORY_DEBUG_TYPE_READ, __func__) + #define DEBUG_MEMORY_WRITE(start, size) debug_memory_log((start), (size), MEMORY_DEBUG_TYPE_WRITE, __func__) + #define DEBUG_MEMORY_DELETE(start, size) debug_memory_log((start), (size), MEMORY_DEBUG_TYPE_DELETE, __func__) + #define DEBUG_MEMORY_RESERVE(start, size) debug_memory_reserve((start), (size), MEMORY_DEBUG_TYPE_RESERVE, __func__) + #define DEBUG_MEMORY_SUBREGION(start, size) debug_memory_reserve((start), (size), MEMORY_DEBUG_TYPE_SUBREGION, __func__) + #define DEBUG_MEMORY_FREE(start, size) debug_memory_free((start)) #define DEBUG_MEMORY_RESET() debug_memory_reset() #else #define DEBUG_MEMORY_INIT(start, size) ((void) 0) #define DEBUG_MEMORY_READ(start, size) ((void) 0) #define DEBUG_MEMORY_WRITE(start, size) ((void) 0) #define DEBUG_MEMORY_DELETE(start, size) ((void) 0) - #define DEBUG_MEMORY_RESERVE(start, size, type) ((void) 0) + #define DEBUG_MEMORY_RESERVE(start, size) ((void) 0) + #define DEBUG_MEMORY_SUBREGION(start, size) ((void) 0) #define DEBUG_MEMORY_FREE(start, size) ((void) 0) #define DEBUG_MEMORY_RESET() ((void) 0) #endif diff --git a/log/Log.h b/log/Log.h index 6866fdf..b66ceab 100644 --- a/log/Log.h +++ b/log/Log.h @@ -9,7 +9,6 @@ #ifndef TOS_LOG_H #define TOS_LOG_H -#include #include "../stdlib/Types.h" #include "Debug.h" diff --git a/log/TimingStat.h b/log/TimingStat.h index 7650224..16c9116 100644 --- a/log/TimingStat.h +++ b/log/TimingStat.h @@ -9,7 +9,6 @@ #ifndef TOS_LOG_TIMING_STAT_H #define TOS_LOG_TIMING_STAT_H -#include #include "../stdlib/Types.h" #include "Debug.h" diff --git a/math/Evaluator.h b/math/Evaluator.h index c00f2d6..c0a6274 100644 --- a/math/Evaluator.h +++ b/math/Evaluator.h @@ -11,11 +11,12 @@ #include "../stdlib/Types.h" #include "../utils/StringUtils.h" +#include "../utils/TestUtils.h" #include "../compiler/CompilerUtils.h" -#include -#include +#include +#include -#define EVALUATOR_MAX_STACK_SIZE 256 +#define EVALUATOR_MAX_STACK_SIZE 16 // Stack for operators struct EvaluatorOperatorStack { @@ -30,19 +31,10 @@ struct EvaluatorValueStack { }; struct EvaluatorVariable { - char name[32]; + char name[8]; f32 value; }; -static inline -const char* evaluator_skip_whitespace(const char* str) { - while (*str && (*str == ' ' || *str == '\t')) { - ++str; - } - - return str; -} - // Stack operations void evaluator_push_operator(EvaluatorOperatorStack* stack, char op) { if (stack->top >= EVALUATOR_MAX_STACK_SIZE - 1) { @@ -89,12 +81,14 @@ int32 evaluator_precedence(char op) { case '*': case '/': return 2; + case 'u': // Unary minus + return 3; default: return 0; } } -// Apply an operator to two values +// Apply an operator to one or two values f32 evaluator_apply_operator(char op, f32 a, f32 b) { switch (op) { case '+': @@ -105,9 +99,10 @@ f32 evaluator_apply_operator(char op, f32 a, f32 b) { return a * b; case '/': return a / b; + case 'u': // Unary minus + return -a; default: { UNREACHABLE(); - return 0; } } } @@ -121,12 +116,10 @@ f32 evaluator_evaluate_expression(const char* expr) { const char* ptr = expr; while (*ptr) { - ptr = evaluator_skip_whitespace(ptr); - if (str_is_num(*ptr) || *ptr == '.') { // Parse number - char* end; - f32 value = strtof(ptr, &end); + const char* end; + f32 value = str_to_float(ptr, &end); evaluator_push_value(&values, value); ptr = end; } else if (str_is_alpha(*ptr)) { @@ -172,20 +165,33 @@ f32 evaluator_evaluate_expression(const char* expr) { while (evaluator_peek_operator(&operators) != '(') { char op = evaluator_pop_operator(&operators); f32 b = evaluator_pop_value(&values); - f32 a = evaluator_pop_value(&values); - evaluator_push_value(&values, evaluator_apply_operator(op, a, b)); + if (op == 'u') { + evaluator_push_value(&values, evaluator_apply_operator(op, b, 0)); + } else { + f32 a = evaluator_pop_value(&values); + evaluator_push_value(&values, evaluator_apply_operator(op, a, b)); + } } evaluator_pop_operator(&operators); // Remove '(' ++ptr; - } else if (strchr("+-*/", *ptr)) { + } else if (str_find("+-*/", *ptr)) { // Operator char op = *ptr; + // Check if the operator is unary + if (op == '-' && (ptr == expr || *(ptr - 1) == '(' || str_find("+-*/", *(ptr - 1)))) { + op = 'u'; // Unary minus + } + while (evaluator_precedence(evaluator_peek_operator(&operators)) >= evaluator_precedence(op)) { char top_op = evaluator_pop_operator(&operators); f32 b = evaluator_pop_value(&values); - f32 a = evaluator_pop_value(&values); - evaluator_push_value(&values, evaluator_apply_operator(top_op, a, b)); + if (top_op == 'u') { + evaluator_push_value(&values, evaluator_apply_operator(top_op, b, 0)); + } else { + f32 a = evaluator_pop_value(&values); + evaluator_push_value(&values, evaluator_apply_operator(top_op, a, b)); + } } evaluator_push_operator(&operators, op); @@ -199,8 +205,12 @@ f32 evaluator_evaluate_expression(const char* expr) { while (operators.top >= 0) { char op = evaluator_pop_operator(&operators); f32 b = evaluator_pop_value(&values); - f32 a = evaluator_pop_value(&values); - evaluator_push_value(&values, evaluator_apply_operator(op, a, b)); + if (op == 'u') { + evaluator_push_value(&values, evaluator_apply_operator(op, b, 0)); + } else { + f32 a = evaluator_pop_value(&values); + evaluator_push_value(&values, evaluator_apply_operator(op, a, b)); + } } return evaluator_pop_value(&values); @@ -209,82 +219,113 @@ f32 evaluator_evaluate_expression(const char* expr) { // Evaluate built-in functions f32 evaluator_evaluate_function(const char* name, const char* args) { if (str_compare(name, "min") == 0) { - const char* comma = strchr(args, ','); + const char* comma = str_find(args, ','); if (!comma) { - return 0.0; + return 0.0; // Invalid function call (min requires at least two arguments) } + // Split the arguments into two expressions char arg1[64], arg2[64]; memcpy(arg1, args, comma - args); arg1[comma - args] = '\0'; str_copy_short(arg2, comma + 1); + // Recursively evaluate the arguments f32 val1 = evaluator_evaluate_expression(arg1); f32 val2 = evaluator_evaluate_expression(arg2); - return OMS_MIN(val1, val2); + return (val1 < val2) ? val1 : val2; // Return the minimum value } else if (str_compare(name, "max") == 0) { - const char* comma = strchr(args, ','); + const char* comma = str_find(args, ','); if (!comma) { - return 0.0; + return 0.0; // Invalid function call (max requires at least two arguments) } + // Split the arguments into two expressions char arg1[64], arg2[64]; memcpy(arg1, args, comma - args); arg1[comma - args] = '\0'; str_copy_short(arg2, comma + 1); + // Recursively evaluate the arguments f32 val1 = evaluator_evaluate_expression(arg1); f32 val2 = evaluator_evaluate_expression(arg2); - return OMS_MAX(val1, val2); + return (val1 > val2) ? val1 : val2; // Return the maximum value + } else if (str_compare(name, "sqrt") == 0) { + // Evaluate the single argument + f32 val = evaluator_evaluate_expression(args); + return sqrtf(val); // Return the square root + } else if (str_compare(name, "abs") == 0) { + // Evaluate the single argument + f32 val = evaluator_evaluate_expression(args); + return OMS_ABS(val); // Return the absolute value } + // Handle unknown functions (you can add more functions as needed) return 0.0; } -f32 evaluator_evaluate(char* expr, int32 variable_count = 0, const EvaluatorVariable* variables = NULL) { +f32 evaluator_evaluate(const char* expr, int32 variable_count = 0, const EvaluatorVariable* variables = NULL) { // Handle variables - const char* ptr = expr; - int32 available_variables = variable_count; + char expr_internal[1024]; + char* dest = expr_internal; - while (*ptr && available_variables) { - // Skip none-alpha values - while (!str_is_alpha(*ptr) && *ptr != '\0') { - ++ptr; - } + if (variable_count) { + while (*expr != '\0') { + // Skip none-alpha values + while (!str_is_alpha(*expr) && *expr != '\0') { + if (*expr != ' ') { + *dest++ = *expr; + } - if (*ptr == '\0') { - continue; - } + ++expr; + } - // Potential variable name - for (int32 i = 0; i < variable_count; ++i) { - size_t len = strlen(variables[i].name); - - // Check if string is variable (must be followed by a whitespace or end of string) - if (str_compare(ptr, variables[i].name, len) == 0 && (ptr[len] == ' ' || ptr[len] == '\0')) { - // Remove variable - str_remove(expr, ptr - expr, len); - - // Replace variable with value - char value[25]; - int32 value_length = float_to_str(variables[i].value, value, 4); - str_insert(expr, ptr - expr, value); - - --available_variables; + if (*expr == '\0') { break; } - } - // Move past string, this should work regardless of whether we found a variable or not - while (str_is_alpha(*ptr) && *ptr != '\0') { - ++ptr; + // Potential variable name + bool found_variable = false; + for (int32 i = 0; i < variable_count; ++i) { + size_t len = str_length(variables[i].name); + + // Check if string is variable (must be followed by none-alpha value = string mustn't continue) + if (str_compare(expr, variables[i].name, len) == 0 + && !str_is_alphanum(expr[len]) && expr[len] != '(' + ) { + // Replace variable with value + dest += float_to_str(variables[i].value, dest, 4); + expr += len; + found_variable = true; + break; + } + } + + if (!found_variable) { + // If no variable is found we must skip the entire alpha string, + // otherwise a substring may match a variable name later on + while (str_is_alphanum(*expr)) { + *dest++ = *expr++; + } + } } } - // Evaluate math formula - return evaluator_evaluate_expression(expr); + // Copy remaining / or entire string over to internal expression + // We also ignore all whitespaces here for simplified handling later on + while (*expr != '\0') { + if (*expr != ' ') { + *dest++ = *expr; + } + + ++expr; + } + + *dest = '\0'; + + return evaluator_evaluate_expression(expr_internal); } #endif \ No newline at end of file diff --git a/math/matrix/MatrixFloat32.h b/math/matrix/MatrixFloat32.h index 67a4322..858c096 100644 --- a/math/matrix/MatrixFloat32.h +++ b/math/matrix/MatrixFloat32.h @@ -9,7 +9,6 @@ #ifndef TOS_MATH_MATRIX_FLOAT32_H #define TOS_MATH_MATRIX_FLOAT32_H -#include #include #include #include "../../utils/TestUtils.h" @@ -43,19 +42,19 @@ void vec2_add(v2_f32* __restrict vec, const v2_f32* b) { } inline -void vec2_sub(v2_f32* __restrict vec, const v2_f32* a, const v2_f32* b) { +void vec2_sub(v2_f32* __restrict vec, const v2_f32* __restrict a, const v2_f32* __restrict b) { vec->x = a->x - b->x; vec->y = a->y - b->y; } inline -void vec2_sub(v2_f32* __restrict vec, const v2_f32* b) { +void vec2_sub(v2_f32* __restrict vec, const v2_f32* __restrict b) { vec->x -= b->x; vec->y -= b->y; } inline -void vec2_mul(v2_f32* vec, const v2_f32* a, f32 s) { +void vec2_mul(v2_f32* __restrict vec, const v2_f32* __restrict a, f32 s) { vec->x = a->x * s; vec->y = a->y * s; } @@ -78,7 +77,7 @@ void vec2_mul(v2_f32* __restrict vec, const v2_f32* a, const v2_f32* b) { } inline -void vec2_mul(v2_f32* __restrict vec, const v2_f32* b) { +void vec2_mul(v2_f32* vec, const v2_f32* b) { vec->x *= b->x; vec->y *= b->y; } @@ -140,21 +139,21 @@ void vec3_add(v3_f32* __restrict vec, const v3_f32* b) { } inline -void vec3_sub(v3_f32* __restrict vec, const v3_f32* a, const v3_f32* b) { +void vec3_sub(v3_f32* __restrict vec, const v3_f32* __restrict a, const v3_f32* __restrict b) { vec->x = a->x - b->x; vec->y = a->y - b->y; vec->z = a->z - b->z; } inline -void vec3_sub(v3_f32* __restrict vec, const v3_f32* b) { +void vec3_sub(v3_f32* __restrict vec, const v3_f32* __restrict b) { vec->x -= b->x; vec->y -= b->y; vec->z -= b->z; } inline -void vec3_mul(v3_f32* vec, const v3_f32* a, f32 s) { +void vec3_mul(v3_f32* __restrict vec, const v3_f32* __restrict a, f32 s) { vec->x = a->x * s; vec->y = a->y * s; vec->z = a->z * s; @@ -180,7 +179,7 @@ void vec3_mul(v3_f32* __restrict vec, const v3_f32* a, const v3_f32* b) { } inline -void vec3_mul(v3_f32* __restrict vec, const v3_f32* b) { +void vec3_mul(v3_f32* vec, const v3_f32* b) { vec->x *= b->x; vec->y *= b->y; vec->z *= b->z; @@ -224,7 +223,7 @@ void vec4_add(v4_f32* __restrict vec, const v4_f32* b) { } inline -void vec4_sub(v4_f32* __restrict vec, const v4_f32* a, const v4_f32* b) { +void vec4_sub(v4_f32* __restrict vec, const v4_f32* __restrict a, const v4_f32* __restrict b) { vec->x = a->x - b->x; vec->y = a->y - b->y; vec->z = a->z - b->z; @@ -232,7 +231,7 @@ void vec4_sub(v4_f32* __restrict vec, const v4_f32* a, const v4_f32* b) { } inline -void vec4_sub(v4_f32* __restrict vec, const v4_f32* b) { +void vec4_sub(v4_f32* __restrict vec, const v4_f32* __restrict b) { vec->x -= b->x; vec->y -= b->y; vec->z -= b->z; @@ -240,7 +239,7 @@ void vec4_sub(v4_f32* __restrict vec, const v4_f32* b) { } inline -void vec4_mul(v4_f32* vec, const v4_f32* a, f32 s) { +void vec4_mul(v4_f32* __restrict vec, const v4_f32* __restrict a, f32 s) { vec->x = a->x * s; vec->y = a->y * s; vec->z = a->z * s; @@ -269,7 +268,7 @@ void vec4_mul(v4_f32* __restrict vec, const v4_f32* a, const v4_f32* b) { } inline -void vec4_mul(v4_f32* __restrict vec, const v4_f32* b) { +void vec4_mul(v4_f32* vec, const v4_f32* b) { vec->x *= b->x; vec->y *= b->y; vec->z *= b->z; diff --git a/memory/BufferMemory.h b/memory/BufferMemory.h index 1794458..23a9c21 100644 --- a/memory/BufferMemory.h +++ b/memory/BufferMemory.h @@ -77,7 +77,7 @@ void buffer_init(BufferMemory* buf, byte* data, uint64 size, int32 alignment = 6 buf->element_alignment = 0; DEBUG_MEMORY_INIT((uintptr_t) buf->memory, buf->size); - DEBUG_MEMORY_RESERVE((uintptr_t) buf->memory, buf->size, 187); + DEBUG_MEMORY_SUBREGION((uintptr_t) buf->memory, buf->size); } inline diff --git a/memory/ChunkMemory.h b/memory/ChunkMemory.h index 678b45f..fb23a3c 100644 --- a/memory/ChunkMemory.h +++ b/memory/ChunkMemory.h @@ -15,7 +15,7 @@ #include "../utils/EndianUtils.h" #include "../utils/BitUtils.h" #include "../log/Log.h" -#include "../log/DebugMemory.h" +#include "../log/Debug.cpp" #include "BufferMemory.h" #include "../system/Allocator.h" #include "../thread/Thread.h" @@ -85,7 +85,7 @@ void chunk_init(ChunkMemory* buf, BufferMemory* data, uint32 count, uint32 chunk buf->free = (uint64 *) (buf->memory + count * chunk_size); DEBUG_MEMORY_INIT((uintptr_t) buf->memory, buf->size); - DEBUG_MEMORY_RESERVE((uintptr_t) buf->memory, buf->size, 187); + DEBUG_MEMORY_SUBREGION((uintptr_t) buf->memory, buf->size); } inline @@ -111,18 +111,22 @@ void chunk_init(ChunkMemory* buf, byte* data, uint32 count, uint32 chunk_size, i buf->free = (uint64 *) (buf->memory + count * chunk_size); DEBUG_MEMORY_INIT((uintptr_t) buf->memory, buf->size); - DEBUG_MEMORY_RESERVE((uintptr_t) buf->memory, buf->size, 187); + DEBUG_MEMORY_SUBREGION((uintptr_t) buf->memory, buf->size); } inline void chunk_free(ChunkMemory* buf) { DEBUG_MEMORY_DELETE((uintptr_t) buf->memory, buf->size); + if (buf->alignment < 2) { platform_free((void **) &buf->memory); } else { platform_aligned_free((void **) &buf->memory); } + + buf->size = 0; + buf->memory = NULL; } inline @@ -133,6 +137,10 @@ uint32 chunk_id_from_memory(const ChunkMemory* buf, const byte* pos) { inline byte* chunk_get_element(ChunkMemory* buf, uint64 element, bool zeroed = false) { + if (element >= buf->count) { + return NULL; + } + byte* offset = buf->memory + element * buf->chunk_size; ASSERT_SIMPLE(offset); @@ -146,33 +154,35 @@ byte* chunk_get_element(ChunkMemory* buf, uint64 element, bool zeroed = false) } // @performance This is a very important function, revisit in the future for optimization (e.g. ABM) +// @performance Is _BitScanForward faster? +// @performance We could probably even reduce the number of iterations by only iterating until popcount is reached? int32 chunk_reserve(ChunkMemory* buf, uint32 elements = 1) { - int32 free_index = (buf->last_pos + 1) / 64; - int32 bit_index = (buf->last_pos + 1) & 63; + uint32 free_index = (buf->last_pos + 1) / 64; + uint32 bit_index = (buf->last_pos + 1) & 63; int32 free_element = -1; - int32 i = -1; - int32 consecutive_free_bits = 0; + uint32 i = 0; + uint32 consecutive_free_bits = 0; - while (free_element < 0 && ++i < buf->count) { + while (free_element < 0 && i++ <= buf->count) { // Skip fully filled ranges - if (free_index * 64 + bit_index + elements - consecutive_free_bits >= buf->count) { - free_index = 0; - bit_index = 0; + if (free_index * 64 + bit_index + elements - consecutive_free_bits > buf->count) { i += buf->count - (free_index * 64 + bit_index); consecutive_free_bits = 0; + free_index = 0; + bit_index = 0; } else if (buf->free[free_index] == 0xFFFFFFFFFFFFFFFF) { ++free_index; bit_index = 0; - i += 63; + i += 64; consecutive_free_bits = 0; continue; } // Find first free element - while (IS_BIT_SET_64_R2L(buf->free[free_index], bit_index)) { + while (IS_BIT_SET_64_R2L(buf->free[free_index], bit_index) && i <= buf->count) { consecutive_free_bits = 0; ++bit_index; ++i; @@ -187,17 +197,14 @@ int32 chunk_reserve(ChunkMemory* buf, uint32 elements = 1) } // The previous while may exit with an "overflow", that's why this check is required - if (IS_BIT_SET_64_R2L(buf->free[free_index], bit_index)) { + if (IS_BIT_SET_64_R2L(buf->free[free_index], bit_index) || i > buf->count) { consecutive_free_bits = 0; continue; } // We found our first free element, let's check if we have enough free space - while (!IS_BIT_SET_64_R2L(buf->free[free_index], bit_index) - && consecutive_free_bits != elements - && free_index * 64 + bit_index + elements - consecutive_free_bits < buf->count - ) { + do { ++i; ++consecutive_free_bits; ++bit_index; @@ -208,32 +215,36 @@ int32 chunk_reserve(ChunkMemory* buf, uint32 elements = 1) break; } - } + } while (!IS_BIT_SET_64_R2L(buf->free[free_index], bit_index) + && consecutive_free_bits != elements + && free_index * 64 + bit_index + elements - consecutive_free_bits <= buf->count + && i <= buf->count + ); // Do we have enough free bits? if (consecutive_free_bits == elements) { free_element = free_index * 64 + bit_index - elements; - int32 possible_free_index = free_element / 64; - int32 possible_bit_index = free_element & 63; + uint32 possible_free_index = free_element / 64; + uint32 possible_bit_index = free_element & 63; // Mark as used if (elements == 1) { - buf->free[possible_free_index] |= (1LL << possible_bit_index); + buf->free[possible_free_index] |= (1ULL << possible_bit_index); } else { uint32 elements_temp = elements; - int64 current_free_index = possible_free_index; - int32 current_bit_index = possible_bit_index; + uint64 current_free_index = possible_free_index; + uint32 current_bit_index = possible_bit_index; - while (elements > 0) { + while (elements_temp > 0) { // Calculate the number of bits we can set in the current 64-bit block - int32 bits_in_current_block = OMS_MIN(64 - current_bit_index, elements); + uint32 bits_in_current_block = OMS_MIN(64 - current_bit_index, elements_temp); // Create a mask to set the bits uint64 mask = ((1ULL << bits_in_current_block) - 1) << current_bit_index; buf->free[current_free_index] |= mask; // Update the counters and indices - elements -= bits_in_current_block; + elements_temp -= bits_in_current_block; ++current_free_index; current_bit_index = 0; } @@ -259,7 +270,7 @@ inline void chunk_free_element(ChunkMemory* buf, uint64 free_index, int32 bit_index) { DEBUG_MEMORY_DELETE((uintptr_t) (buf->memory + (free_index * 64 + bit_index) * buf->chunk_size), buf->chunk_size); - buf->free[free_index] &= ~(1LL << bit_index); + buf->free[free_index] &= ~(1ULL << bit_index); } inline @@ -267,8 +278,8 @@ void chunk_free_elements(ChunkMemory* buf, uint64 element, uint32 element_count { DEBUG_MEMORY_DELETE((uintptr_t) (buf->memory + element * buf->chunk_size), buf->chunk_size); - int64 free_index = element / 64; - int32 bit_index = element & 63; + uint64 free_index = element / 64; + uint32 bit_index = element & 63; if (element == 1) { chunk_free_element(buf, free_index, bit_index); @@ -356,9 +367,11 @@ int64 chunk_load(ChunkMemory* buf, const byte* data) return buf->size; } -#define chunk_iterate_start(buf, chunk_id) \ - int32 free_index = 0; \ - int32 bit_index = 0; \ +// @performance Is _BitScanForward faster? +// @performance We could probably even reduce the number of iterations by only iterating until popcount is reached? +#define chunk_iterate_start(buf, chunk_id) { \ + uint32 free_index = 0; \ + uint32 bit_index = 0; \ \ /* Iterate the chunk memory */ \ for (; chunk_id < (buf)->count; ++chunk_id) { \ @@ -378,6 +391,6 @@ int64 chunk_load(ChunkMemory* buf, const byte* data) bit_index = 0; \ ++free_index; \ } \ - } + }} #endif \ No newline at end of file diff --git a/memory/Queue.h b/memory/Queue.h index 635aa2f..046ed9a 100644 --- a/memory/Queue.h +++ b/memory/Queue.h @@ -91,7 +91,7 @@ void queue_enqueue_unique(Queue* queue, const byte* data) ASSERT_SIMPLE((uint64_t) tail % 4 == 0); // @performance we could probably make this faster since we don't need to compare the entire range - if (is_equal_aligned(tail, data, queue->element_size) == 0) { + if (is_equal(tail, data, queue->element_size) == 0) { return; } diff --git a/memory/RingMemory.h b/memory/RingMemory.h index d98152c..898368f 100644 --- a/memory/RingMemory.h +++ b/memory/RingMemory.h @@ -18,7 +18,7 @@ #include "BufferMemory.h" #include "../log/Log.h" -#include "../log/DebugMemory.h" +#include "../log/Debug.cpp" #include "../thread/Atomic.h" #include "../thread/Semaphore.h" #include "../thread/ThreadDefines.h" @@ -78,7 +78,7 @@ void ring_init(RingMemory* ring, BufferMemory* buf, uint64 size, uint32 alignmen ring->alignment = alignment; DEBUG_MEMORY_INIT((uintptr_t) ring->memory, ring->size); - DEBUG_MEMORY_RESERVE((uintptr_t) ring->memory, ring->size, 187); + DEBUG_MEMORY_SUBREGION((uintptr_t) ring->memory, ring->size); } inline @@ -97,17 +97,22 @@ void ring_init(RingMemory* ring, byte* buf, uint64 size, uint32 alignment = 64) memset(ring->memory, 0, ring->size); DEBUG_MEMORY_INIT((uintptr_t) ring->memory, ring->size); - DEBUG_MEMORY_RESERVE((uintptr_t) ring->memory, ring->size, 187); + DEBUG_MEMORY_SUBREGION((uintptr_t) ring->memory, ring->size); } inline void ring_free(RingMemory* ring) { + DEBUG_MEMORY_DELETE((uintptr_t) ring->memory, ring->size); + if (ring->alignment < 2) { platform_free((void **) &ring->memory); } else { platform_aligned_free((void **) &ring->memory); } + + ring->size = 0; + ring->memory = NULL; } inline @@ -141,6 +146,7 @@ void ring_reset(RingMemory* ring) } // Moves a pointer based on the size you want to consume (new position = after consuming size) +// Usually used to move head or tail pointer (= pos) void ring_move_pointer(RingMemory* ring, byte** pos, uint64 size, uint32 aligned = 4) { ASSERT_SIMPLE(size <= ring->size); @@ -234,13 +240,11 @@ byte* ring_get_memory_nomove(RingMemory* ring, uint64 size, uint32 aligned = 4, // Used if the ring only contains elements of a certain size // This way you can get a certain element inline -byte* ring_get_element(const RingMemory* ring, uint64 element_count, uint64 element, uint64 size) +byte* ring_get_element(const RingMemory* ring, uint64 element, uint64 size) { - int64 index = (element % element_count) - 1; + DEBUG_MEMORY_READ((uintptr_t) (ring->memory + element * size), 1); - DEBUG_MEMORY_READ((uintptr_t) (ring->memory + index * size), 1); - - return ring->memory + index * size; + return ring->memory + element * size; } /** @@ -250,14 +254,15 @@ inline bool ring_commit_safe(const RingMemory* ring, uint64 size, uint32 aligned = 4) { // aligned * 2 since that should be the maximum overhead for an element + // -1 since that is the worst case, we can't be missing a complete alignment because than it would be already aligned // This is not 100% correct BUT it is way faster than any correct version I can come up with - uint64 max_mem_required = size + aligned * 2; + uint64 max_mem_required = size + (aligned - 1) * 2; if (ring->tail < ring->head) { - return ((uint64) (ring->end - ring->head)) > max_mem_required - || ((uint64) (ring->tail - ring->memory)) > max_mem_required; + return ((uint64) (ring->end - ring->head)) >= max_mem_required + || ((uint64) (ring->tail - ring->memory)) >= max_mem_required; } else if (ring->tail > ring->head) { - return ((uint64) (ring->tail - ring->head)) > max_mem_required; + return ((uint64) (ring->tail - ring->head)) >= max_mem_required; } else { return true; } @@ -267,8 +272,9 @@ inline bool ring_commit_safe_atomic(const RingMemory* ring, uint64 size, uint32 aligned = 4) { // aligned * 2 since that should be the maximum overhead for an element + // -1 since that is the worst case, we can't be missing a complete alignment because than it would be already aligned // This is not 100% correct BUT it is way faster than any correct version I can come up with - uint64 max_mem_required = size + aligned * 2; + uint64 max_mem_required = size + (aligned - 1) * 2; // @todo consider to switch to uintptr_t uint64 tail = (uint64) atomic_get_relaxed((void **) &ring->tail); @@ -277,10 +283,10 @@ bool ring_commit_safe_atomic(const RingMemory* ring, uint64 size, uint32 aligned uint64 head = (uint64) ring->head; if (tail < head) { - return ((uint64) (ring->end - head)) > max_mem_required - || ((uint64) (tail - (uint64) ring->memory)) > max_mem_required; + return ((uint64) (ring->end - head)) >= max_mem_required + || ((uint64) (tail - (uint64) ring->memory)) >= max_mem_required; } else if (tail > head) { - return ((uint64) (tail - head)) > max_mem_required; + return ((uint64) (tail - head)) >= max_mem_required; } else { return true; } diff --git a/memory/ThreadedQueue.h b/memory/ThreadedQueue.h index 1a7dc50..916b969 100644 --- a/memory/ThreadedQueue.h +++ b/memory/ThreadedQueue.h @@ -114,7 +114,7 @@ void thrd_queue_enqueue_unique_wait(ThreadedQueue* queue, const byte* data) ASSERT_SIMPLE((uint64_t) tail % 4 == 0); // @performance we could probably make this faster since we don't need to compare the entire range - if (is_equal_aligned(tail, data, queue->element_size) == 0) { + if (is_equal(tail, data, queue->element_size) == 0) { pthread_mutex_unlock(&queue->mutex); return; @@ -145,7 +145,7 @@ void thrd_queue_enqueue_unique(ThreadedQueue* queue, const byte* data) ASSERT_SIMPLE((uint64_t) tail % 4 == 0); // @performance we could probably make this faster since we don't need to compare the entire range - if (is_equal_aligned(tail, data, queue->element_size) == 0) { + if (is_equal(tail, data, queue->element_size) == 0) { pthread_mutex_unlock(&queue->mutex); return; diff --git a/memory/ThreadedRingMemory.h b/memory/ThreadedRingMemory.h index 245145a..85bc3da 100644 --- a/memory/ThreadedRingMemory.h +++ b/memory/ThreadedRingMemory.h @@ -111,10 +111,10 @@ byte* thrd_ring_get_memory_nomove(ThreadedRingMemory* ring, uint64 size, byte al // Used if the ring only contains elements of a certain size // This way you can get a certain element inline -byte* thrd_ring_get_element(ThreadedRingMemory* ring, uint64 element_count, uint64 element, uint64 size) +byte* thrd_ring_get_element(ThreadedRingMemory* ring, uint64 element, uint64 size) { pthread_mutex_lock(&ring->mutex); - byte* result = ring_get_element((RingMemory *) ring, element_count, element, size); + byte* result = ring_get_element((RingMemory *) ring, element, size); pthread_mutex_unlock(&ring->mutex); return result; diff --git a/module/ModuleManager.h b/module/ModuleManager.h index a3b81e8..b14c4f1 100644 --- a/module/ModuleManager.h +++ b/module/ModuleManager.h @@ -30,7 +30,7 @@ void module_file_parse(const char* path, Module* module, RingMemory* ring) const char* space; while (line != NULL) { - space = strchr(line, ' '); + space = str_find(line, ' '); if (space != NULL) { size_t name_length = space - line; strncpy_s(name, MAX_LENGTH, line, name_length); @@ -40,7 +40,7 @@ void module_file_parse(const char* path, Module* module, RingMemory* ring) if (str_compare(name, "name") == 0) { strncpy_s(module->name, MAX_LENGTH, value, sizeof(module->name) - 1); - module->name[strlen(value)] = '\0'; + module->name[str_length(value)] = '\0'; } else if (str_compare(name, "version") == 0) { module->version = (byte) atol(value); } else if (str_compare(name, "type") == 0) { diff --git a/object/Mesh.h b/object/Mesh.h index 87820de..c857ae7 100644 --- a/object/Mesh.h +++ b/object/Mesh.h @@ -69,17 +69,17 @@ void mesh_from_file_txt( const char* path, RingMemory* ring ) { - FileBody file; + FileBody file = {}; file_read(path, &file, ring); ASSERT_SIMPLE(file.size); const char* pos = (char *) file.content; - // move past the version string + // move past the "version" string pos += 8; // @todo us version for different handling - int32 version = strtol(pos, (char **) &pos, 10); ++pos; + [[maybe_unused]] int32 version = (int32) str_to_int(pos, &pos); ++pos; int32 object_index = 0; int32 group_index = 0; @@ -97,8 +97,8 @@ void mesh_from_file_txt( int32 tex_coord_count = 0; f32* tex_coords = (f32 *) ring_get_memory(ring, 500000 * sizeof(f32)); - int32 color_count = 0; - f32* colors = (f32 *) ring_get_memory(ring, 500000 * sizeof(f32)); + //int32 color_count = 0; + // f32* colors = (f32 *) ring_get_memory(ring, 500000 * sizeof(f32)); int32 face_type = VERTEX_TYPE_POSITION; int32 face_count = 0; @@ -158,9 +158,10 @@ void mesh_from_file_txt( // move past whitespaces and newline bool is_next_line = false; - while (*pos == ' ' || *pos == '\n') { - is_next_line |= *pos == '\n'; - ++pos; + while (*pos == ' ' || is_eol(pos)) { + int32 eol_length = is_eol(pos); + is_next_line |= ((bool) eol_length); + pos += eol_length ? eol_length : 1; } if (*pos == '\0' || is_next_line) { @@ -180,9 +181,9 @@ void mesh_from_file_txt( mesh->vertex_type |= VERTEX_TYPE_POSITION; } - vertices[vertex_count * 3] = strtof(pos, (char **) &pos); ++pos; - vertices[vertex_count * 3 + 1] = strtof(pos, (char **) &pos); ++pos; - vertices[vertex_count * 3 + 2] = strtof(pos, (char **) &pos); ++pos; + vertices[vertex_count * 3] = str_to_float(pos, &pos); ++pos; + vertices[vertex_count * 3 + 1] = str_to_float(pos, &pos); ++pos; + vertices[vertex_count * 3 + 2] = str_to_float(pos, &pos); ++pos; // has color information // @todo Move to own case statement // 'co' @@ -191,13 +192,13 @@ void mesh_from_file_txt( mesh->vertex_type |= VERTEX_TYPE_COLOR; } - vertices[vertex_count * 12 + 8] = strtof(pos, (char **) &pos); ++pos; - vertices[vertex_count * 12 + 9] = strtof(pos, (char **) &pos); ++pos; - vertices[vertex_count * 12 + 10] = strtof(pos, (char **) &pos); ++pos; + vertices[vertex_count * 12 + 8] = str_to_float(pos, &pos); ++pos; + vertices[vertex_count * 12 + 9] = str_to_float(pos, &pos); ++pos; + vertices[vertex_count * 12 + 10] = str_to_float(pos, &pos); ++pos; // handle optional alpha [a] if (*pos != '\n' && pos[1] != ' ' && pos[1] != '\n') { - vertices[vertex_count * 12 + 11] = strtof(pos, (char **) &pos); ++pos; + vertices[vertex_count * 12 + 11] = str_to_float(pos, &pos); ++pos; } else { vertices[vertex_count * 12 + 11] = 1.0f; } @@ -209,30 +210,30 @@ void mesh_from_file_txt( } break; case 2: { // 'vn' - normals[normal_count * 3] = strtof(pos, (char **) &pos); ++pos; - normals[normal_count * 3 + 1] = strtof(pos, (char **) &pos); ++pos; - normals[normal_count * 3 + 2] = strtof(pos, (char **) &pos); ++pos; + normals[normal_count * 3] = str_to_float(pos, &pos); ++pos; + normals[normal_count * 3 + 1] = str_to_float(pos, &pos); ++pos; + normals[normal_count * 3 + 2] = str_to_float(pos, &pos); ++pos; ++normal_count; } break; case 3: { // 'vt' - tex_coords[tex_coord_count * 2] = strtof(pos, (char **) &pos); ++pos; - tex_coords[tex_coord_count * 2 + 1] = strtof(pos, (char **) &pos); ++pos; + tex_coords[tex_coord_count * 2] = str_to_float(pos, &pos); ++pos; + tex_coords[tex_coord_count * 2 + 1] = str_to_float(pos, &pos); ++pos; ++tex_coord_count; } break; case 4: { // 'vp' - strtof(pos, (char **) &pos); ++pos; + str_to_float(pos, &pos); ++pos; // handle optional [v] if (*pos != '\n' && pos[1] != ' ' && pos[1] != '\n') { - strtof(pos, (char **) &pos); ++pos; + str_to_float(pos, &pos); ++pos; // handle optional [w] if (*pos != '\n' && pos[1] != ' ' && pos[1] != '\n') { - strtof(pos, (char **) &pos); ++pos; + str_to_float(pos, &pos); ++pos; } } } break; @@ -249,7 +250,7 @@ void mesh_from_file_txt( } break; case 6: { // 's' - strtol(pos, (char **) &pos, 10); ++pos; + str_to_int(pos, &pos); ++pos; } break; case 7: { // 'f' @@ -269,40 +270,40 @@ void mesh_from_file_txt( const int32 max_blocks = 3; // @todo this could actually be N. Might have to change in the future int32 block = 0; - while (*pos != '\0' && *pos != '\n') { + while (*pos != '\0' && !is_eol(pos)) { if (ftype == 0) { // v1 v2 v3 ... if (face_count == 0) { face_type = VERTEX_TYPE_POSITION; } - faces[(face_count * max_blocks * 1) + block] = strtol(pos, (char **) &pos, 10) - 1; ++pos; + faces[(face_count * max_blocks * 1) + block] = (int32) str_to_int(pos, &pos) - 1; ++pos; } else if (ftype == 1) { // v1/vt1 v2/vt2 v3/vt3 ... if (face_count == 0) { face_type = VERTEX_TYPE_POSITION | VERTEX_TYPE_TEXTURE_COORD; } - faces[(face_count * max_blocks * 2) + block * 2] = strtol(pos, (char **) &pos, 10) - 1; ++pos; - faces[(face_count * max_blocks * 2) + block * 2 + 1] = strtol(pos, (char **) &pos, 10) - 1; ++pos; + faces[(face_count * max_blocks * 2) + block * 2] = (int32) str_to_int(pos, &pos) - 1; ++pos; + faces[(face_count * max_blocks * 2) + block * 2 + 1] = (int32) str_to_int(pos, &pos) - 1; ++pos; } else if (ftype == 2) { // v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3 ... if (face_count == 0) { face_type = VERTEX_TYPE_POSITION | VERTEX_TYPE_TEXTURE_COORD | VERTEX_TYPE_NORMAL; } - faces[(face_count * max_blocks * 3) + block * 3] = strtol(pos, (char **) &pos, 10) - 1; ++pos; - faces[(face_count * max_blocks * 3) + block * 3 + 1] = strtol(pos, (char **) &pos, 10) - 1; ++pos; - faces[(face_count * max_blocks * 3) + block * 3 + 2] = strtol(pos, (char **) &pos, 10) - 1; ++pos; + faces[(face_count * max_blocks * 3) + block * 3] = (int32) str_to_int(pos, &pos) - 1; ++pos; + faces[(face_count * max_blocks * 3) + block * 3 + 1] = (int32) str_to_int(pos, &pos) - 1; ++pos; + faces[(face_count * max_blocks * 3) + block * 3 + 2] = (int32) str_to_int(pos, &pos) - 1; ++pos; } else if (ftype == 3) { // v1//vn1 v2//vn2 v3//vn3 ... if (face_count == 0) { face_type = VERTEX_TYPE_POSITION | VERTEX_TYPE_NORMAL; } - faces[(face_count * max_blocks * 2) + block * 2] = strtol(pos, (char **) &pos, 10) - 1; ++pos; + faces[(face_count * max_blocks * 2) + block * 2] = (int32) str_to_int(pos, &pos) - 1; ++pos; ++pos; - faces[(face_count * max_blocks * 2) + block * 2 + 1] = strtol(pos, (char **) &pos, 10) - 1; ++pos; + faces[(face_count * max_blocks * 2) + block * 2 + 1] = (int32) str_to_int(pos, &pos) - 1; ++pos; } ++block; @@ -323,8 +324,8 @@ void mesh_from_file_txt( } break; case 9: { //l - while (*pos != '\0' && *pos != '\n') { - strtol(pos, (char **) &pos, 10); ++pos; + while (*pos != '\0' && !is_eol(pos)) { + str_to_int(pos, &pos); ++pos; } } break; case 10: { @@ -462,9 +463,8 @@ enum MeshLoadingRestriction { int32 mesh_from_data( const byte* data, Mesh* mesh, - const char* group = NULL, - int32 load_format = MESH_LOADING_RESTRICTION_EVERYTHING, - int32 steps = 8 + //int32 load_format = MESH_LOADING_RESTRICTION_EVERYTHING, + [[maybe_unused]] int32 steps = 8 ) { const byte* pos = data; @@ -480,7 +480,7 @@ int32 mesh_from_data( mesh->vertex_count = *((int32 *) pos); pos += sizeof(mesh->vertex_count); - #if !_WIN32 && !__LITTLE_ENDIAN + #if !_WIN32 && !__LITTLE_ENDIAN__ mesh->version = endian_swap(mesh->version); mesh->vertex_type = endian_swap(mesh->vertex_type); mesh->vertex_count = endian_swap(mesh->vertex_count); @@ -548,7 +548,7 @@ int32 mesh_to_data( const Mesh* mesh, byte* data, uint32 vertex_save_format = VERTEX_TYPE_ALL, - int32 steps = 8 + [[maybe_unused]] int32 steps = 8 ) { byte* pos = data; diff --git a/object/Vertex.h b/object/Vertex.h index ce7aab1..73b8484 100644 --- a/object/Vertex.h +++ b/object/Vertex.h @@ -51,14 +51,6 @@ struct Vertex2DColor { v4_f32 color; }; -struct Vertex2DColorIndex { - v2_f32 position; - // @bug opengl shaders don't support individual bytes, - // otherwise we would use byte here for 256 color palettes. - // Which is bad since the purpose of this was to save 3 bytes by using a color palette - f32 color; -}; - struct VertexRef { uint32 data_id; diff --git a/platform/linux/ExceptionHandler.h b/platform/linux/ExceptionHandler.h index d793e06..e15f97c 100644 --- a/platform/linux/ExceptionHandler.h +++ b/platform/linux/ExceptionHandler.h @@ -17,13 +17,14 @@ #define MAX_STACK_FRAMES 64 +// @todo fix nasty fprintf usage +// @todo should also log backtrace similar to windows version void signal_handler(int sig) { void *stack_frames[MAX_STACK_FRAMES]; char **stack_symbols; int num_frames; num_frames = backtrace(stack_frames, MAX_STACK_FRAMES); - stack_symbols = backtrace_symbols(stack_frames, num_frames); fprintf(stderr, "Error: signal %d:\n", sig); @@ -53,8 +54,25 @@ void setup_signal_handler() { sa.sa_flags = SA_RESTART; sigaction(SIGSEGV, &sa, NULL); - sigaction(SIGABRT, &sa, NULL); } +void print_stack_trace() { + void *buffer[100]; // Array to store the return addresses + int num_ptrs = backtrace(buffer, 100); // Capture the stack trace + char **symbols = backtrace_symbols(buffer, num_ptrs); // Resolve symbols + + if (symbols == NULL) { + perror("backtrace_symbols"); + return; + } + + printf("Stack trace:\n"); + for (int i = 0; i < num_ptrs; i++) { + printf("%s\n", symbols[i]); // Print each symbol + } + + free(symbols); // Free the memory allocated by backtrace_symbols +} + #endif \ No newline at end of file diff --git a/platform/linux/Library.cpp b/platform/linux/Library.cpp index 603b88b..ffa068d 100644 --- a/platform/linux/Library.cpp +++ b/platform/linux/Library.cpp @@ -29,7 +29,7 @@ bool library_load(Library* lib) // In debug mode, we create a copy at runtime, so we can recompile & reload it #if DEBUG || INTERNAL char src[PATH_MAX]; - size_t dst_len = strlen(dst); + size_t dst_len = str_length(dst); memcpy(src, dst, dst_len + 1); str_insert(dst, dst_len - (sizeof(".so") - 1), "_temp"); diff --git a/platform/linux/SystemInfo.cpp b/platform/linux/SystemInfo.cpp index 639bd7e..aec5049 100644 --- a/platform/linux/SystemInfo.cpp +++ b/platform/linux/SystemInfo.cpp @@ -72,7 +72,7 @@ uint16 system_country_code() } void mainboard_info_get(MainboardInfo* info) { - FileBody file; + FileBody file = {}; file.content = info->name; file.size = sizeof(info->name); @@ -94,7 +94,7 @@ int32 network_info_get(NetworkInfo* info) { struct stat st; int32 i = 0; - FileBody file; + FileBody file = {}; for (i = 0; i < 4; i++) { sprintf_fast(path, "/sys/class/net/eth%d", i); @@ -211,7 +211,7 @@ uint32 display_info_get(DisplayInfo* info) { uint32 count = 0; while (fgets(line, sizeof(line), fp)) { - if (strstr(line, "connected")) { + if (str_find(line, "connected")) { // Example: "HDMI-1 connected 1920x1080+0+0 60.00*+" char name[64]; uint32 width, height, hz; @@ -220,7 +220,7 @@ uint32 display_info_get(DisplayInfo* info) { info[count].width = width; info[count].height = height; info[count].hz = hz; - info[count].is_primary = strstr(line, "primary"); + info[count].is_primary = str_find(line, "primary"); count++; } } diff --git a/platform/linux/UtilsLinux.h b/platform/linux/UtilsLinux.h index c5b52d6..da03af0 100644 --- a/platform/linux/UtilsLinux.h +++ b/platform/linux/UtilsLinux.h @@ -16,28 +16,6 @@ #include #include - -int32 sprintf_s(char *buffer, size_t sizeOfBuffer, const char *format, ...) { - int32 result; - va_list args; - - if (buffer == NULL || format == NULL || sizeOfBuffer == 0) { - return -1; - } - - va_start(args, format); - result = vsnprintf(buffer, sizeOfBuffer, format, args); - va_end(args); - - if (result >= 0 && (size_t) result >= sizeOfBuffer) { - buffer[sizeOfBuffer - 1] = '\0'; - return 80; - } - - // Return the result - return result; -} - void clipboard_get(char* text, int32 max_length) { *text = '\0'; @@ -80,4 +58,8 @@ void clipboard_get(char* text, int32 max_length) XCloseDisplay(display); } +void output_char(char c) { + write(STDOUT_FILENO, &c, 1); +} + #endif \ No newline at end of file diff --git a/platform/linux/threading/Thread.h b/platform/linux/threading/Thread.h index 14fa8dc..fcc9de2 100644 --- a/platform/linux/threading/Thread.h +++ b/platform/linux/threading/Thread.h @@ -21,6 +21,7 @@ #include "../Allocator.h" #include "ThreadDefines.h" +inline int32 pthread_create(pthread_t* thread, void *(*start_routine)(void *), void* arg) { thread->stack = platform_alloc_aligned(1 * MEGABYTE, 64); if (!thread->stack) { @@ -43,6 +44,7 @@ int32 pthread_create(pthread_t* thread, void *(*start_routine)(void *), void* ar return 0; } +inline int32 pthread_join(pthread_t thread, void** retval) { int32 status; if (waitpid(thread->id, &status, 0) == -1) { @@ -60,12 +62,14 @@ int32 pthread_join(pthread_t thread, void** retval) { return 0; } +inline int32 pthread_mutex_init(pthread_mutex_t* mutex, pthread_mutexattr_t*) { atomic_set_acquire(mutex, 0); return 0; } +inline int32 pthread_mutex_lock(pthread_mutex_t* mutex) { int32 expected = 0; while (!atomic_compare_exchange_weak(mutex, &expected, 1)) { @@ -76,6 +80,7 @@ int32 pthread_mutex_lock(pthread_mutex_t* mutex) { return 0; } +inline int32 pthread_mutex_unlock(pthread_mutex_t* mutex) { atomic_set_release(mutex, 0); syscall(SYS_futex, mutex, FUTEX_WAKE, 1, NULL, NULL, 0); @@ -83,12 +88,14 @@ int32 pthread_mutex_unlock(pthread_mutex_t* mutex) { return 0; } +inline int32 pthread_cond_init(pthread_cond_t* cond, pthread_condattr_t*) { atomic_set_release(cond, 0); return 0; } +inline int32 pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex) { pthread_mutex_unlock(mutex); syscall(SYS_futex, cond, FUTEX_WAIT, atomic_get_acquire(cond), NULL, NULL, 0); @@ -97,6 +104,7 @@ int32 pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex) { return 0; } +inline int32 pthread_cond_signal(pthread_cond_t* cond) { atomic_fetch_add_acquire(cond, 1); syscall(SYS_futex, cond, FUTEX_WAKE, 1, NULL, NULL, 0); @@ -104,12 +112,14 @@ int32 pthread_cond_signal(pthread_cond_t* cond) { return 0; } +inline int32 pthread_rwlock_init(pthread_rwlock_t* rwlock, const pthread_rwlockattr_t*) { atomic_set_release((int64 *) &rwlock->readers, 0); return 0; } +inline int32 pthread_rwlock_rdlock(pthread_rwlock_t* rwlock) { while (atomic_get_acquire_release(&rwlock->writer)) {} @@ -118,12 +128,14 @@ int32 pthread_rwlock_rdlock(pthread_rwlock_t* rwlock) { return 0; } +inline int32 pthread_rwlock_wrlock(pthread_rwlock_t* rwlock) { while (!atomic_compare_exchange_weak(&rwlock->writer, 0, 1)) {} return 0; } +inline int32 pthread_rwlock_unlock(pthread_rwlock_t* rwlock) { if (atomic_get_acquire(&rwlock->writer)) { atomic_set_release(&rwlock->writer, 0); @@ -134,17 +146,20 @@ int32 pthread_rwlock_unlock(pthread_rwlock_t* rwlock) { return 0; } +inline int32 pthread_detach(pthread_t) { // For detached threads, the OS will clean up automatically. We do nothing here. // Optionally, mark this thread as detached in your data structure if tracking threads. return 0; } +inline int32 pthread_rwlock_destroy(pthread_rwlock_t*) { return 0; } +inline uint32 pthread_get_num_procs() { return (uint32) sysconf(_SC_NPROCESSORS_ONLN); diff --git a/platform/linux/threading/ThreadDefines.h b/platform/linux/threading/ThreadDefines.h index 3d4f1a7..f5119d8 100644 --- a/platform/linux/threading/ThreadDefines.h +++ b/platform/linux/threading/ThreadDefines.h @@ -36,8 +36,8 @@ struct pthread_cond_t { */ struct pthread_rwlock_t { - volatile int32 readers; - volatile int32 writer; + atomic_32 int32 readers; + atomic_32 int32 writer; }; typedef void pthread_mutexattr_t; diff --git a/platform/win32/Allocator.h b/platform/win32/Allocator.h index 632098a..da65e8d 100644 --- a/platform/win32/Allocator.h +++ b/platform/win32/Allocator.h @@ -15,7 +15,6 @@ #include "../../utils/TestUtils.h" // @todo Currently alignment only effects the starting position, but it should also effect the ending/size -// @todo Consider to rename file to Allocator.h inline void* platform_alloc(size_t size) diff --git a/platform/win32/Clipboard.h b/platform/win32/Clipboard.h index 525af67..c50f03a 100644 --- a/platform/win32/Clipboard.h +++ b/platform/win32/Clipboard.h @@ -11,7 +11,6 @@ #include "../../stdlib/Types.h" #include "../../utils/StringUtils.h" -#include #include #include diff --git a/platform/win32/ExceptionHandler.h b/platform/win32/ExceptionHandler.h index e409556..a136aa3 100644 --- a/platform/win32/ExceptionHandler.h +++ b/platform/win32/ExceptionHandler.h @@ -13,16 +13,16 @@ #include #include #include +#include "../../log/Debug.cpp" #ifdef _MSC_VER #pragma comment(lib, "dbghelp.lib") #endif void create_minidump(EXCEPTION_POINTERS *exception_pointers) { - // Open the dump file - HANDLE hFile = CreateFileA("crash_dump.dmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + HANDLE fp = CreateFileA("crash_dump.dmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == INVALID_HANDLE_VALUE) { + if (fp == INVALID_HANDLE_VALUE) { return; } @@ -35,7 +35,7 @@ void create_minidump(EXCEPTION_POINTERS *exception_pointers) { MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(), - hFile, + fp, (MINIDUMP_TYPE) (MiniDumpWithDataSegs | MiniDumpWithHandleData | MiniDumpWithModuleHeaders | MiniDumpWithUnloadedModules | MiniDumpWithProcessThreadData | MiniDumpWithFullMemoryInfo | MiniDumpWithThreadInfo | MiniDumpWithTokenInformation), @@ -44,62 +44,130 @@ void create_minidump(EXCEPTION_POINTERS *exception_pointers) { NULL ); - CloseHandle(hFile); + CloseHandle(fp); } -void print_stack_trace(CONTEXT *context) { - // Initialize the SYMBOL_INFO structure - SymInitialize(GetCurrentProcess(), NULL, TRUE); +void log_stack_trace(CONTEXT *context) { + HANDLE process = GetCurrentProcess(); + HANDLE thread = GetCurrentThread(); - STACKFRAME64 stack_frame; - memset(&stack_frame, 0, sizeof(STACKFRAME64)); + // Initialize symbols + SymInitialize(process, NULL, TRUE); - // Determine if we are running on x86 or x64 architecture - DWORD machine_type = IMAGE_FILE_MACHINE_I386; + // Set symbol options to load line numbers and undecorated names + SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); -#ifdef _M_X64 - machine_type = IMAGE_FILE_MACHINE_AMD64; + STACKFRAME64 stack_frame = {}; + DWORD machine_type = IMAGE_FILE_MACHINE_AMD64; + + // Initialize stack frame for x64 stack_frame.AddrPC.Offset = context->Rip; - stack_frame.AddrFrame.Offset = context->Rbp; - stack_frame.AddrStack.Offset = context->Rsp; -#elif _M_IX86 - stack_frame.AddrPC.Offset = context->Eip; - stack_frame.AddrFrame.Offset = context->Ebp; - stack_frame.AddrStack.Offset = context->Esp; -#endif - stack_frame.AddrPC.Mode = AddrModeFlat; + stack_frame.AddrFrame.Offset = context->Rbp; stack_frame.AddrFrame.Mode = AddrModeFlat; + stack_frame.AddrStack.Offset = context->Rsp; stack_frame.AddrStack.Mode = AddrModeFlat; - // Traverse the stack frames - while (StackWalk64( - machine_type, - GetCurrentProcess(), - GetCurrentThread(), - &stack_frame, - context, - NULL, - SymFunctionTableAccess64, - SymGetModuleBase64, - NULL) + LOG(true, "Stack trace:"); + + // Walk the stack + while (StackWalk64(machine_type, process, thread, &stack_frame, context, NULL, + SymFunctionTableAccess64, SymGetModuleBase64, NULL) ) { - if (stack_frame.AddrPC.Offset == 0) { + DWORD64 address = stack_frame.AddrPC.Offset; + + // Skip invalid addresses + if (address == 0) { break; } - // Get the symbol for the current stack frame - DWORD64 symbol_offset = 0; - SYMBOL_INFO *symbol = (SYMBOL_INFO *)malloc(sizeof(SYMBOL_INFO) + 256); - symbol->MaxNameLen = 255; + // Resolve symbol information + char symbol_buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; + PSYMBOL_INFO symbol = (PSYMBOL_INFO) symbol_buffer; symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + symbol->MaxNameLen = MAX_SYM_NAME; - SymFromAddr(GetCurrentProcess(), stack_frame.AddrPC.Offset, &symbol_offset, symbol); + if (SymFromAddr(process, address, NULL, symbol)) { + LOG_FORMAT(true, "Function: %s - Address: %l", {{LOG_DATA_CHAR_STR, symbol->Name}, {LOG_DATA_INT64, &symbol->Address}}); + } else { + LOG_FORMAT(true, "Function: (unknown) - Address: %l", {{LOG_DATA_INT64, &address}}); + } - free(symbol); + // Resolve file and line number + IMAGEHLP_LINE64 line; + DWORD displacement = 0; + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + + if (SymGetLineFromAddr64(process, address, &displacement, &line)) { + LOG_FORMAT(true, " File: %s, Line: %l", {{LOG_DATA_CHAR_STR, line.FileName}, {LOG_DATA_INT64, &line.LineNumber}}); + } else { + LOG(true, " File: (unknown), Line: (unknown)"); + } + + // Print module name + IMAGEHLP_MODULE64 module_info; + module_info.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); + if (SymGetModuleInfo64(process, address, &module_info)) { + LOG_FORMAT(true, " Module: %s", {{LOG_DATA_CHAR_STR, module_info.ModuleName}}); + } else { + LOG(true, " Module: (unknown)"); + } } - SymCleanup(GetCurrentProcess()); + LOG_TO_FILE(); + SymCleanup(process); +} + +void print_stack_trace(CONTEXT *context) { + HANDLE process = GetCurrentProcess(); + HANDLE thread = GetCurrentThread(); + + // Initialize symbols + SymInitialize(process, NULL, TRUE); + + STACKFRAME64 stack_frame = {}; + DWORD machine_type = IMAGE_FILE_MACHINE_AMD64; + + // Initialize stack frame for x64 + stack_frame.AddrPC.Offset = context->Rip; + stack_frame.AddrPC.Mode = AddrModeFlat; + stack_frame.AddrFrame.Offset = context->Rbp; + stack_frame.AddrFrame.Mode = AddrModeFlat; + stack_frame.AddrStack.Offset = context->Rsp; + stack_frame.AddrStack.Mode = AddrModeFlat; + + printf("Stack trace:\n"); + + while (StackWalk64(machine_type, process, thread, &stack_frame, context, NULL, + SymFunctionTableAccess64, SymGetModuleBase64, NULL) + ) { + DWORD64 address = stack_frame.AddrPC.Offset; + + // Resolve symbol information + char symbol_buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; + PSYMBOL_INFO symbol = (PSYMBOL_INFO)symbol_buffer; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + symbol->MaxNameLen = MAX_SYM_NAME; + + if (SymFromAddr(process, address, NULL, symbol)) { + printf("Function: %s - Address: 0x%llx\n", symbol->Name, symbol->Address); + } else { + printf("Function: (unknown) - Address: 0x%llx\n", address); + } + + // Resolve file and line number + IMAGEHLP_LINE64 line; + DWORD displacement = 0; + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + + if (SymGetLineFromAddr64(process, address, &displacement, &line)) { + printf(" File: %s, Line: %lu\n", line.FileName, line.LineNumber); + } else { + printf(" File: (unknown), Line: (unknown)\n"); + } + } + + SymCleanup(process); } #endif \ No newline at end of file diff --git a/platform/win32/FileUtils.cpp b/platform/win32/FileUtils.cpp index ee1e561..4c90c9c 100644 --- a/platform/win32/FileUtils.cpp +++ b/platform/win32/FileUtils.cpp @@ -28,7 +28,7 @@ typedef HANDLE MMFHandle; typedef OVERLAPPED file_overlapped; struct FileBodyAsync { - // doesn't include null termination (same as strlen) + // doesn't include null termination (same as str_length) uint64 size; byte* content; OVERLAPPED ov; @@ -772,7 +772,7 @@ bool file_append(const char* path, const char* file) } DWORD written; - DWORD length = (DWORD) strlen(file); + DWORD length = (DWORD) str_length(file); if (!WriteFile(fp, file, length, &written, NULL)) { CloseHandle(fp); return false; @@ -794,7 +794,7 @@ file_append(FileHandle fp, const char* file) } DWORD written; - DWORD length = (DWORD) strlen(file); + DWORD length = (DWORD) str_length(file); if (!WriteFile(fp, file, length, &written, NULL)) { ASSERT_SIMPLE(false); return false; diff --git a/platform/win32/Library.cpp b/platform/win32/Library.cpp index 1ccc00d..03df397 100644 --- a/platform/win32/Library.cpp +++ b/platform/win32/Library.cpp @@ -27,7 +27,7 @@ bool library_load(Library* lib) // In debug mode, we create a copy at runtime, so we can recompile & reload it #if DEBUG || INTERNAL char src[MAX_PATH]; - size_t dst_len = strlen(dst); + size_t dst_len = str_length(dst); memcpy(src, dst, dst_len + 1); str_insert(dst, dst_len - (sizeof(".dll") - 1), "_temp"); diff --git a/platform/win32/SystemInfo.cpp b/platform/win32/SystemInfo.cpp index 4aad4f2..9d4a9a0 100644 --- a/platform/win32/SystemInfo.cpp +++ b/platform/win32/SystemInfo.cpp @@ -44,7 +44,7 @@ uint64 system_private_memory_usage() PROCESS_MEMORY_COUNTERS_EX pmc; HANDLE process = GetCurrentProcess(); - GetProcessMemoryInfo(process, (PROCESS_MEMORY_COUNTERS*) &pmc, sizeof(pmc)); + GetProcessMemoryInfo(process, (PROCESS_MEMORY_COUNTERS *) &pmc, sizeof(pmc)); CloseHandle(process); diff --git a/platform/win32/TimeUtils.h b/platform/win32/TimeUtils.h index 933e53e..7915e0e 100644 --- a/platform/win32/TimeUtils.h +++ b/platform/win32/TimeUtils.h @@ -12,7 +12,7 @@ #include #include #include -#include "../../log/Debug.cpp" +#include "../../stdlib/Types.h" void usleep(uint64 microseconds) { @@ -34,7 +34,7 @@ void usleep(uint64 microseconds) } inline -time_t system_time() +uint64 system_time() { SYSTEMTIME systemTime; FILETIME fileTime; @@ -47,7 +47,7 @@ time_t system_time() largeInt.LowPart = fileTime.dwLowDateTime; largeInt.HighPart = fileTime.dwHighDateTime; - return ((time_t) (largeInt.QuadPart / 10000000ULL)) - ((time_t) 11644473600ULL); + return ((uint64) (largeInt.QuadPart / 10000000ULL)) - ((uint64) 11644473600ULL); } // doesn't return clock time, only to return time since program start @@ -58,11 +58,17 @@ uint64 time_mu() LARGE_INTEGER counter; QueryPerformanceCounter(&counter); - return (counter.QuadPart * 1000000) / debug_container->performance_count_frequency; + static LARGE_INTEGER frequency; + QueryPerformanceFrequency(&frequency); + + ASSERT_SIMPLE(counter.QuadPart != frequency.QuadPart); + ASSERT_SIMPLE(counter.QuadPart != 1); + + return (counter.QuadPart * 1000000) / frequency.QuadPart; } inline -time_t unix_epoch_s() +uint64 unix_epoch_s() { FILETIME ft; GetSystemTimeAsFileTime(&ft); @@ -71,18 +77,17 @@ time_t unix_epoch_s() li.LowPart = ft.dwLowDateTime; li.HighPart = ft.dwHighDateTime; - time_t seconds_since_epoch = (li.QuadPart - 116444736000000000ULL) / 10000000ULL; - - return seconds_since_epoch; + return (uint64) (li.QuadPart - 116444736000000000ULL) / 10000000ULL; } -static DWORD timespec_to_ms(const timespec* abstime) +inline +DWORD timespec_to_ms(const timespec* abstime) { if (abstime == NULL) { return INFINITE; } - time_t seconds_since_epoch = unix_epoch_s(); + uint64 seconds_since_epoch = unix_epoch_s(); DWORD t = (DWORD) (((abstime->tv_sec - seconds_since_epoch) * 1000) + (abstime->tv_nsec / 1000000)); return t < 0 ? 1 : t; diff --git a/platform/win32/UtilsWin32.h b/platform/win32/UtilsWin32.h index ba8ea86..d04a4a8 100644 --- a/platform/win32/UtilsWin32.h +++ b/platform/win32/UtilsWin32.h @@ -11,9 +11,7 @@ #include "../../stdlib/Types.h" #include "../../utils/StringUtils.h" -#include #include -#include #define strtok_r strtok_s @@ -33,4 +31,9 @@ uint32 key_to_unicode(byte scan_code, byte vkey, byte keyboard_state[256]) } } +void output_char(char c) { + HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); + WriteFile(hStdout, &c, 1, NULL, NULL); +} + #endif \ No newline at end of file diff --git a/platform/win32/UtilsWindows.h b/platform/win32/UtilsWindows.h index 4b54a3e..603da59 100644 --- a/platform/win32/UtilsWindows.h +++ b/platform/win32/UtilsWindows.h @@ -14,6 +14,7 @@ #include "../../stdlib/Types.h" #include "../../utils/TestUtils.h" +// @question Shouldn't this function and the next one accept a parameter of what to add/remove? inline void window_remove_style(Window* w) { diff --git a/platform/win32/audio/DirectSound.h b/platform/win32/audio/DirectSound.h index 2fcf85c..f3eb32b 100644 --- a/platform/win32/audio/DirectSound.h +++ b/platform/win32/audio/DirectSound.h @@ -99,7 +99,7 @@ void audio_load(HWND hwnd, AudioSetting* setting, DirectSoundSetting* api_settin } inline -void audio_play(AudioSetting* setting, DirectSoundSetting* api_setting) +void audio_play(AudioSetting*, DirectSoundSetting* api_setting) { if (!api_setting->secondary_buffer) { return; @@ -109,7 +109,7 @@ void audio_play(AudioSetting* setting, DirectSoundSetting* api_setting) } inline -void audio_stop(AudioSetting* setting, DirectSoundSetting* api_setting) { +void audio_stop(AudioSetting*, DirectSoundSetting* api_setting) { if (!api_setting->secondary_buffer) { return; } diff --git a/platform/win32/input/HidInput.h b/platform/win32/input/HidInput.h index 4dfab31..787a657 100644 --- a/platform/win32/input/HidInput.h +++ b/platform/win32/input/HidInput.h @@ -23,9 +23,7 @@ #pragma comment(lib, "hid.lib") #pragma comment(lib, "setupapi.lib") -void hid_init_controllers(Input* __restrict states, int32 state_count, RingMemory* ring) { - - HANDLE* controller_handles = NULL; +void hid_init_controllers(Input* __restrict states, RingMemory* ring) { // Get the GUID for HID devices GUID hid_guid; diff --git a/platform/win32/input/RawInput.h b/platform/win32/input/RawInput.h index ea36f0c..c5c7956 100644 --- a/platform/win32/input/RawInput.h +++ b/platform/win32/input/RawInput.h @@ -24,7 +24,7 @@ // Even if it is nowhere documented (at least not to our knowledge) the GetRawInputDeviceInfoA, GetRawInputBuffer functions required // aligned memory. So far we only figured out that 4 bytes works, maybe this needs to be 8 in the future?! -int rawinput_init_mousekeyboard(HWND hwnd, Input* __restrict states, RingMemory* ring) +uint32 rawinput_init_mousekeyboard(HWND hwnd, Input* __restrict states, RingMemory* ring) { uint32 device_count; GetRawInputDeviceList(NULL, &device_count, sizeof(RAWINPUTDEVICELIST)); @@ -46,7 +46,7 @@ int rawinput_init_mousekeyboard(HWND hwnd, Input* __restrict states, RingMemory* int32 mouse_found = 0; int32 keyboard_found = 0; - int32 i; + uint32 i; for (i = 0; i < device_count; ++i) { cb_size = sizeof(RID_DEVICE_INFO); RID_DEVICE_INFO rdi; @@ -100,7 +100,7 @@ int rawinput_init_mousekeyboard(HWND hwnd, Input* __restrict states, RingMemory* } // WARNING: While this works we highly recommend to use hid_init_controllers -int rawinput_init_controllers(HWND hwnd, Input* __restrict states, RingMemory* ring) +uint32 rawinput_init_controllers(HWND hwnd, Input* __restrict states, RingMemory* ring) { uint32 device_count; GetRawInputDeviceList(NULL, &device_count, sizeof(RAWINPUTDEVICELIST)); @@ -120,7 +120,7 @@ int rawinput_init_controllers(HWND hwnd, Input* __restrict states, RingMemory* r uint32 cb_size = 256; int32 controller_found = 0; - int32 i; + uint32 i; for (i = 0; i < device_count; ++i) { cb_size = sizeof(RID_DEVICE_INFO); RID_DEVICE_INFO rdi; diff --git a/platform/win32/threading/Thread.h b/platform/win32/threading/Thread.h index b986788..93a0071 100644 --- a/platform/win32/threading/Thread.h +++ b/platform/win32/threading/Thread.h @@ -12,9 +12,9 @@ #include "../../../stdlib/Types.h" #include "../TimeUtils.h" #include "ThreadDefines.h" - #include +inline int32 pthread_create(pthread_t* thread, void*, ThreadJobFunc start_routine, void* arg) { if (thread == NULL || start_routine == NULL) { @@ -29,6 +29,7 @@ int32 pthread_create(pthread_t* thread, void*, ThreadJobFunc start_routine, void return 0; } +inline int32 pthread_join(pthread_t thread, void**) { WaitForSingleObject(thread, INFINITE); @@ -37,6 +38,7 @@ int32 pthread_join(pthread_t thread, void**) return 0; } +inline int32 pthread_detach(pthread_t thread) { CloseHandle(thread); @@ -44,6 +46,7 @@ int32 pthread_detach(pthread_t thread) return 0; } +inline int32 pthread_mutex_init(pthread_mutex_t* mutex, pthread_mutexattr_t*) { if (mutex == NULL) { @@ -55,6 +58,7 @@ int32 pthread_mutex_init(pthread_mutex_t* mutex, pthread_mutexattr_t*) return 0; } +inline int32 pthread_mutex_destroy(pthread_mutex_t* mutex) { if (mutex == NULL) { @@ -66,6 +70,7 @@ int32 pthread_mutex_destroy(pthread_mutex_t* mutex) return 0; } +inline int32 pthread_mutex_lock(pthread_mutex_t* mutex) { if (mutex == NULL) { @@ -77,6 +82,7 @@ int32 pthread_mutex_lock(pthread_mutex_t* mutex) return 0; } +inline int32 pthread_mutex_unlock(pthread_mutex_t* mutex) { if (mutex == NULL) { @@ -88,6 +94,7 @@ int32 pthread_mutex_unlock(pthread_mutex_t* mutex) return 0; } +inline int32 pthread_cond_init(pthread_cond_t* cond, pthread_condattr_t*) { if (cond == NULL) { @@ -99,12 +106,15 @@ int32 pthread_cond_init(pthread_cond_t* cond, pthread_condattr_t*) return 0; } +inline int32 pthread_cond_destroy(pthread_cond_t*) { /* Windows does not have a destroy for conditionals */ return 0; } +// @question Can't we turn timespec in a typedef of uint64? I would like to avoid the time.h class +inline int32 pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t* mutex, const timespec* abstime) { if (cond == NULL || mutex == NULL) { @@ -118,6 +128,7 @@ int32 pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t* mutex, const return 0; } +inline int32 pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex) { if (cond == NULL || mutex == NULL) { @@ -127,6 +138,7 @@ int32 pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex) return pthread_cond_timedwait(cond, mutex, NULL); } +inline int32 pthread_cond_signal(pthread_cond_t* cond) { if (cond == NULL) { @@ -138,6 +150,7 @@ int32 pthread_cond_signal(pthread_cond_t* cond) return 0; } +inline int32 pthread_cond_broadcast(pthread_cond_t* cond) { if (cond == NULL) { @@ -149,6 +162,7 @@ int32 pthread_cond_broadcast(pthread_cond_t* cond) return 0; } +inline int32 pthread_rwlock_init(pthread_rwlock_t* rwlock, const pthread_rwlockattr_t*) { if (rwlock == NULL) { @@ -161,11 +175,13 @@ int32 pthread_rwlock_init(pthread_rwlock_t* rwlock, const pthread_rwlockattr_t*) return 0; } +inline int32 pthread_rwlock_destroy(pthread_rwlock_t*) { return 0; } +inline int32 pthread_rwlock_rdlock(pthread_rwlock_t* rwlock) { if (rwlock == NULL) { @@ -177,6 +193,7 @@ int32 pthread_rwlock_rdlock(pthread_rwlock_t* rwlock) return 0; } +inline int32 pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock) { if (rwlock == NULL) { @@ -186,6 +203,7 @@ int32 pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock) return !TryAcquireSRWLockShared(&rwlock->lock); } +inline int32 pthread_rwlock_wrlock(pthread_rwlock_t* rwlock) { if (rwlock == NULL) { @@ -198,6 +216,7 @@ int32 pthread_rwlock_wrlock(pthread_rwlock_t* rwlock) return 0; } +inline int32 pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) { if (rwlock == NULL) { @@ -212,6 +231,7 @@ int32 pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) return ret; } +inline int32 pthread_rwlock_unlock(pthread_rwlock_t* rwlock) { if (rwlock == NULL) { @@ -228,6 +248,7 @@ int32 pthread_rwlock_unlock(pthread_rwlock_t* rwlock) return 0; } +inline uint32 pcthread_get_num_procs() { SYSTEM_INFO sysinfo; @@ -236,6 +257,6 @@ uint32 pcthread_get_num_procs() return sysinfo.dwNumberOfProcessors; } -#define pthread_exit(a) {return (a);} +#define pthread_exit(a) { return (a); } #endif \ No newline at end of file diff --git a/platform/win32/threading/ThreadDefines.h b/platform/win32/threading/ThreadDefines.h index 3ebcd45..2d29868 100644 --- a/platform/win32/threading/ThreadDefines.h +++ b/platform/win32/threading/ThreadDefines.h @@ -9,7 +9,7 @@ #ifndef TOS_PLATFORM_WIN32_THREADING_THREAD_DEFINES_H #define TOS_PLATFORM_WIN32_THREADING_THREAD_DEFINES_H -#include +#include "../../../stdlib/Types.h" #include #define THREAD_RETURN DWORD WINAPI diff --git a/scene/SceneInfo.h b/scene/SceneInfo.h new file mode 100644 index 0000000..c899421 --- /dev/null +++ b/scene/SceneInfo.h @@ -0,0 +1,20 @@ +#ifndef TOS_SCENE_INFO_H +#define TOS_SCENE_INFO_H + +#include "../stdlib/Types.h" +#include "../ui/UILayout.h" +#include "../ui/UITheme.h" + +struct SceneInfo { + // @todo Find a better way to handle state data, the problem is we need the maximum scene size + // I'm pretty sure for the main scene we probably need a couple MB + // We also cannot pull the SceneGeneral out since it has different sizes based on gpuapi, unless we force it to a fixed size + byte data[8192]; + UILayout ui_layout; + + // This is scene specific theme data + // We also have global theme data, which is not defined in here + UIThemeStyle ui_theme; +}; + +#endif \ No newline at end of file diff --git a/sort/BinarySearch.h b/sort/BinarySearch.h new file mode 100644 index 0000000..932aa56 --- /dev/null +++ b/sort/BinarySearch.h @@ -0,0 +1,23 @@ +#ifndef TOS_SORT_BINARY_SEARCH_H +#define TOS_SORT_BINARY_SEARCH_H + +#include "../stdlib/Types.h" + +// WARNING: the prefetching is usually only useful, if we go into 512KB array size +/* +int32 lower_bound(int32* t, size_t len, int32 x) { + int32 *base = t; + while (len > 1) { + int32 half = len / 2; + len -= half; + + intrin_prefetch(&base[len / 2 - 1]); + intrin_prefetch(&base[half + len / 2 - 1]); + + base += (base[half - 1] < x) * half; + } + return *base; +} +*/ + +#endif \ No newline at end of file diff --git a/sort/EytzingerSearch.h b/sort/EytzingerSearch.h new file mode 100644 index 0000000..752faad --- /dev/null +++ b/sort/EytzingerSearch.h @@ -0,0 +1,74 @@ +#ifndef TOS_SORT_EYTZINGER_SEARCH_H +#define TOS_SORT_EYTZINGER_SEARCH_H + +#include "../stdlib/Types.h" +#include "../memory/RingMemory.h" + +// @performance We could optimize eytzinger by using 1 based index +// Consider this https://en.algorithmica.org/hpc/data-structures/binary-search/ + +void eytzinger_rearrange(byte* arr, byte* temp, size_t start, size_t* index, size_t num, size_t size) { + if (start >= num) { + return; + } + + // Fill the left child + eytzinger_rearrange(arr, temp, 2 * start + 1, index, num, size); + + // Assign the current element + memcpy(temp + start * size, arr + (*index) * size, size); + ++(*index); + + // Fill the right child + eytzinger_rearrange(arr, temp, 2 * start + 2, index, num, size); +} + +// arr MUST be sorted by a sorting algorithm of your choice +void eytzinger_create(byte* arr, size_t num, size_t size, RingMemory* ring) { + byte* temp = ring_get_memory(ring, size * num); + + size_t index = 0; + eytzinger_rearrange(arr, temp, 0, &index, num, size); + + // Copy the rearranged array back to the original array + for (size_t i = 0; i < size; ++i) { + memcpy(arr + i * size, temp + i * size, size); + } +} + +// Example search for structs with an int id +// WARNING: the prefetching is usually only useful, if we go into 256KB array size +/* +void* search_eytzinger(MyStruct* arr, size_t num, int32 target_id) { + int32 index = 0; + while (index < num) { + // Prefetch the left and right children + int32 left_child = 2 * index + 1; + int32 right_child = 2 * index + 2; + + if (left_child < num) { + // Prefetch left child + intrin_prefetch(&arr[left_child]); + } + if (right_child < num) { + // Prefetch right child + intrin_prefetch(&arr[right_child]); + } + + // Check the current node + if (arr[index].id == target_id) { + return &arr[index]; + } else if (arr[index].id < target_id) { + // Move to the right child + index = right_child; + } else { + // Move to the left child + index = left_child; + } + } + + return NULL; +} +*/ + +#endif \ No newline at end of file diff --git a/sort/HeapSort.h b/sort/HeapSort.h new file mode 100644 index 0000000..0c838b7 --- /dev/null +++ b/sort/HeapSort.h @@ -0,0 +1,50 @@ +#ifndef TOS_SORT_HEAP_SORT_H +#define TOS_SORT_HEAP_SORT_H + +#include "../stdlib/Types.h" +#include "../utils/Utils.h" + +void heapsort(void* arr, size_t num, size_t size, int32 (*compare)(const void*, const void*)) { + char* base = (char*)arr; + + // Build a max heap + for (size_t i = num / 2; i > 0; --i) { + size_t parent = i - 1; + size_t child = 2 * parent + 1; + while (child < num) { + if (child + 1 < num && compare(base + child * size, base + (child + 1) * size) < 0) { + child++; + } + + if (compare(base + parent * size, base + child * size) >= 0) { + break; + } + + swap_memory(base + parent * size, base + child * size, size); + parent = child; + child = 2 * parent + 1; + } + } + + // Extract elements from the heap + for (size_t i = num - 1; i > 0; --i) { + swap_memory(base, base + i * size, size); + size_t parent = 0; + size_t child = 1; + while (child < i) { + if (child + 1 < i && compare(base + child * size, base + (child + 1) * size) < 0) { + child++; + } + + if (compare(base + parent * size, base + child * size) >= 0) { + break; + } + + swap_memory(base + parent * size, base + child * size, size); + parent = child; + child = 2 * parent + 1; + } + } +} + +#endif \ No newline at end of file diff --git a/sort/InsertionSort.h b/sort/InsertionSort.h new file mode 100644 index 0000000..79d0aae --- /dev/null +++ b/sort/InsertionSort.h @@ -0,0 +1,16 @@ +#ifndef TOS_SORT_Insertion_SORT_H +#define TOS_SORT_Insertion_SORT_H + +#include "../stdlib/Types.h" +#include "../utils/Utils.h" + +void insertionsort(void* arr, size_t num, size_t size, int32 (*compare)(const void*, const void*)) { + char* base = (char*) arr; + for (size_t i = 1; i < num; ++i) { + for (size_t j = i; j > 0 && compare(base + j * size, base + (j - 1) * size) < 0; --j) { + swap_memory(base + j * size, base + (j - 1) * size, size); + } + } +} + +#endif \ No newline at end of file diff --git a/sort/IntroSort.h b/sort/IntroSort.h new file mode 100644 index 0000000..3019ae2 --- /dev/null +++ b/sort/IntroSort.h @@ -0,0 +1,37 @@ +#ifndef TOS_SORT_INTRO_SORT_H +#define TOS_SORT_INTRO_SORT_H + +#include "../stdlib/Types.h" +#include "InsertionSort.h" +#include "HeapSort.h" +#include "QuickSort.h" + +void introsort(void* arr, size_t num, size_t size, int32 (*compare)(const void*, const void*), size_t depth_limit) { + byte* base = (byte*) arr; + + // Use InsertionSort for small subarrays + if (num < 16) { + insertionsort(arr, num, size, compare); + return; + } + + // If the depth limit is reached, switch to HeapSort + if (depth_limit == 0) { + heapsort(arr, num, size, compare); + return; + } + + // Otherwise, perform QuickSort + size_t pi = quicksort_partition(arr, size, 0, num - 1, compare); + if (pi > 0) { + // Sort the left subarray + introsort(arr, pi, size, compare, depth_limit - 1); + } + + if (pi + 1 < num) { + // Sort the right subarray + introsort(base + (pi + 1) * size, num - (pi + 1), size, compare, depth_limit - 1); + } +} + +#endif \ No newline at end of file diff --git a/sort/QuickSort.h b/sort/QuickSort.h new file mode 100644 index 0000000..1a43464 --- /dev/null +++ b/sort/QuickSort.h @@ -0,0 +1,37 @@ +#ifndef TOS_SORT_QUICK_SORT_H +#define TOS_SORT_QUICK_SORT_H + +#include "../stdlib/Types.h" +#include "../utils/Utils.h" + +size_t quicksort_partition(void* arr, size_t size, size_t low, size_t high, int32 (*compare)(const void*, const void*)) { + char* base = (char*) arr; + void* pivot = base + high * size; + size_t i = low; + + for (size_t j = low; j < high; ++j) { + if (compare(base + j * size, pivot) < 0) { + swap_memory(base + i * size, base + j * size, size); + ++i; + } + } + + swap_memory(base + i * size, pivot, size); + return i; +} + +void quicksort(void* arr, size_t size, size_t low, size_t high, int32 (*compare)(const void*, const void*)) { + if (low < high) { + size_t pi = quicksort_partition(arr, size, low, high, compare); + + if (pi > 0) { + // Sort the left subarray + quicksort(arr, size, low, pi - 1, compare); + } + + // Sort the right subarray + quicksort(arr, size, pi + 1, high, compare); + } +} + +#endif \ No newline at end of file diff --git a/sort/Sort.h b/sort/Sort.h new file mode 100644 index 0000000..08c842c --- /dev/null +++ b/sort/Sort.h @@ -0,0 +1,34 @@ +#ifndef TOS_SORT_H +#define TOS_SORT_H + +#include "../stdlib/Types.h" +#include "QuickSort.h" +#include "HeapSort.h" +#include "IntroSort.h" +#include "InsertionSort.h" + +inline +void sort_introsort(void* arr, size_t num, size_t size, int32 (*compare)(const void*, const void*)) { + size_t depth_limit = 0; + for (size_t n = num; n > 0; n >>= 1) { + ++depth_limit; + } + + depth_limit *= 2; + + introsort(arr, num, size, compare, depth_limit); +} + +inline +void sort_quicksort(void* arr, size_t num, size_t size, int32 (*compare)(const void*, const void*)) { + quicksort(arr, size, 0, num - 1, compare); +} + +#define sort_heapsort heapsort +#define sort_insertionsort insertionsort + +int32 sort_compare_int32(const void* a, const void* b) { + return (*(int32 *) a) - (*(int32 *) b); +} + +#endif \ No newline at end of file diff --git a/stdlib/HashMap.h b/stdlib/HashMap.h index e61a5b5..2257a6e 100644 --- a/stdlib/HashMap.h +++ b/stdlib/HashMap.h @@ -16,6 +16,7 @@ #include "../memory/ChunkMemory.h" #include "../utils/StringUtils.h" #include "../stdlib/Simd.h" +#include "../system/Allocator.h" // If a hash key is longer than the max key length, we use the last N characters of that key // The key length is currently chosen to result in 32 byte size for the common case: HashEntryInt32 @@ -120,6 +121,33 @@ struct HashMap { ChunkMemory buf; }; +void hashmap_alloc(HashMap* hm, int32 count, int32 element_size) +{ + byte* data = (byte *) platform_alloc( + count * (sizeof(uint16) + element_size) + + CEIL_DIV(count, 64) * sizeof(hm->buf.free) + ); + + hm->table = (uint16 *) data; + chunk_init(&hm->buf, data + sizeof(uint16) * count, count, element_size, 8); + + DEBUG_MEMORY_INIT((uintptr_t) hm->buf.memory, hm->buf.size); + LOG_INCREMENT_BY(DEBUG_COUNTER_MEM_ALLOC, hm->buf.size); + LOG_LEVEL_2("Allocated HashMap for %n elements with %n B per element", {{LOG_DATA_INT32, &count}, {LOG_DATA_INT32, &element_size}}); +} + +inline +void hashmap_free(HashMap* hm) +{ + DEBUG_MEMORY_DELETE((uintptr_t) hm->buf.memory, hm->buf.size); + + platform_free((void **) &hm->table); + + hm->table = NULL; + hm->buf.size = 0; + hm->buf.memory = NULL; +} + // WARNING: element_size = element size + remaining HashEntry data size void hashmap_create(HashMap* hm, int32 count, int32 element_size, RingMemory* ring) { @@ -439,12 +467,7 @@ HashEntry* hashmap_get_reserve(HashMap* hm, const char* key) return entry_new; } -inline -HashEntry* hashmap_get_entry_by_index(HashMap* hm, uint32 index) -{ - return hm->table[index] ? (HashEntry *) chunk_get_element(&hm->buf, hm->table[index] - 1, false) : NULL; -} - +// @performance Some places use this in order to iterate the hashmap that is horrible!!! Use the actual iterate function! inline HashEntry* hashmap_get_entry_by_element(HashMap* hm, uint32 element) { @@ -777,7 +800,7 @@ int32 hashmap_value_size(const HashMap* hm) // @question Shouldn't we also store the chunk size etc? Currently not done and expected to be correctly initialized. inline -int64 hashmap_dump(const HashMap* hm, byte* data, int32 steps = 8) +int64 hashmap_dump(const HashMap* hm, byte* data, [[maybe_unused]] int32 steps = 8) { *((uint32 *) data) = SWAP_ENDIAN_LITTLE(hm->buf.count); data += sizeof(hm->buf.count); @@ -843,7 +866,7 @@ int64 hashmap_dump(const HashMap* hm, byte* data, int32 steps = 8) // WARNING: Requires hashmap_create first inline -int64 hashmap_load(HashMap* hm, const byte* data, int32 steps = 8) +int64 hashmap_load(HashMap* hm, const byte* data, [[maybe_unused]] int32 steps = 8) { uint64 count = SWAP_ENDIAN_LITTLE(*((uint32 *) data)); data += sizeof(uint16); @@ -870,7 +893,7 @@ int64 hashmap_load(HashMap* hm, const byte* data, int32 steps = 8) int32 value_size = hashmap_value_size(hm); // Switch endian AND turn offsets to pointers - int32 chunk_id = 0; + uint32 chunk_id = 0; chunk_iterate_start(&hm->buf, chunk_id) HashEntry* entry = (HashEntry *) chunk_get_element((ChunkMemory *) &hm->buf, chunk_id); diff --git a/stdlib/Simd.h b/stdlib/Simd.h index 1a00f26..0aee0aa 100644 --- a/stdlib/Simd.h +++ b/stdlib/Simd.h @@ -9,17 +9,31 @@ #ifndef TOS_STDLIB_SIMD_H #define TOS_STDLIB_SIMD_H -#if __aarch64__ +// Adjusts the step size based on the memory alignment +inline +int32 intrin_validate_steps(const byte* mem, int32 steps) { + if (steps >= 16 && ((uintptr_t) mem & 63) == 0) { + return 16; + } else if (steps >= 8 && ((uintptr_t) mem & 31) == 0) { + return 8; + } else if (steps >= 4 && ((uintptr_t) mem & 15) == 0) { + return 4; + } else { + return 1; + } +} +#if __aarch64__ + #include #else - // @todo Should get moved to architecture/x86/simd directory - #include "simd/SIMD_F32.h" - #include "simd/SIMD_F64.h" - #include "simd/SIMD_I8.h" - #include "simd/SIMD_I16.h" - #include "simd/SIMD_I32.h" - #include "simd/SIMD_I64.h" - #include "simd/SIMD_SVML.h" + #include "../architecture/x86/simd/SIMD_F32.h" + #include "../architecture/x86/simd/SIMD_F64.h" + #include "../architecture/x86/simd/SIMD_I8.h" + #include "../architecture/x86/simd/SIMD_I16.h" + #include "../architecture/x86/simd/SIMD_I32.h" + #include "../architecture/x86/simd/SIMD_I64.h" + #include "../architecture/x86/simd/SIMD_SVML.h" #endif + #endif \ No newline at end of file diff --git a/stdlib/Types.h b/stdlib/Types.h index 80c72ba..dee30b1 100644 --- a/stdlib/Types.h +++ b/stdlib/Types.h @@ -11,9 +11,12 @@ #include -#ifdef _MSC_VER +#if _WIN32 #include typedef SSIZE_T ssize_t; +#elif __linux__ + #include + #define MAX_PATH PATH_MAX #endif #define ARRAY_COUNT(a) (sizeof(a) / sizeof((a)[0])) @@ -38,6 +41,10 @@ typedef char sbyte; typedef uintptr_t umm; typedef intptr_t smm; +// @question consider to implement atomic_16 depending on intrinsic support +#define atomic_32 alignas(4) volatile +#define atomic_64 alignas(8) volatile + #define OMS_PI 3.14159265358979323846f #define OMS_PI_OVER_TWO (OMS_PI / 2.0f) #define OMS_PI_OVER_FOUR (OMS_PI / 4.0f) @@ -50,10 +57,10 @@ typedef intptr_t smm; #define OMS_CLAMP(val, high, low) ((val) < (low) ? (low) : ((val) > (high) ? (high) : (val))) #define OMS_ABS(a) ((a) > 0 ? (a) : -(a)) -#define OMS_ABS_INT8(a) ((a) & 0x7F) -#define OMS_ABS_INT16(a) ((a) & 0x7FFF) -#define OMS_ABS_INT32(a) ((a) & 0x7FFFFFFF) -#define OMS_ABS_INT64(a) ((a) & 0x7FFFFFFFFFFFFFFF) +#define OMS_ABS_INT8(a) ((uint8) ((a) & 0x7F)) +#define OMS_ABS_INT16(a) ((uint16) ((a) & 0x7FFF)) +#define OMS_ABS_INT32(a) ((uint32) ((a) & 0x7FFFFFFF)) +#define OMS_ABS_INT64(a) ((uint64) ((a) & 0x7FFFFFFFFFFFFFFF)) #define OMS_ABS_F32(a) ((f32) (((int32) (a)) & 0x7FFFFFFF)) #define OMS_ABS_F64(a) ((f64) (((int64) (a)) & 0x7FFFFFFFFFFFFFFF)) @@ -67,7 +74,20 @@ typedef intptr_t smm; #define CEIL_DIV(a, b) (((a) + (b) - 1) / (b)) #define OMS_CEIL(x) ((x) == (int32)(x) ? (int32)(x) : ((x) > 0 ? (int32)(x) + 1 : (int32)(x))) -#define FLOAT_CAST_EPS 0.001953125 +// Casting between e.g. f32 and int32 without changing bits +#define BITCAST(x, new_type) bitcast_impl_##new_type(x) +#define DEFINE_BITCAST_FUNCTION(from_type, to_type) \ + static inline to_type bitcast_impl_##to_type(from_type src) { \ + union { from_type src; to_type dst; } u; \ + u.src = src; \ + return u.dst; \ + } +DEFINE_BITCAST_FUNCTION(f32, uint32) +DEFINE_BITCAST_FUNCTION(uint32, f32) +DEFINE_BITCAST_FUNCTION(f64, uint64) +DEFINE_BITCAST_FUNCTION(uint64, f64) + +#define FLOAT_CAST_EPS 0.001953125f // Modulo function when b is a power of 2 #define MODULO_2(a, b) ((a) & (b - 1)) diff --git a/tests.bat b/tests.bat new file mode 100644 index 0000000..961413f --- /dev/null +++ b/tests.bat @@ -0,0 +1,82 @@ +@echo off +set "start_time=%TIME%" +cls + +set "EXE_NAME=tests" +set "DESTINATION_DIR=..\build\tests" + +IF NOT EXIST ..\build mkdir ..\build +IF NOT EXIST "%DESTINATION_DIR%" mkdir "%DESTINATION_DIR%" + +if not defined DevEnvDir (call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat") + +if "%Platform%" neq "x64" ( + echo ERROR: Platform is not "x64" - previous bat call failed. + exit /b 1 +) + +cd "%DESTINATION_DIR%" +del *.pdb > NUL 2> NUL +del *.idb > NUL 2> NUL +cd ..\..\GameEngine + +REM Use /showIncludes for include debugging + +set BUILD_TYPE=DEBUG +set BUILD_FLAGS=/Od /Z7 /WX /FC /RTC1 /DDEBUG + +set "DEBUG_DATA=/Fd"%DESTINATION_DIR%\%EXE_NAME%.pdb" /Fm"%DESTINATION_DIR%\%EXE_NAME%.map"" + +REM Parse command-line arguments +if "%1"=="-r" ( + set BUILD_TYPE=RELEASE + set BUILD_FLAGS=/O2 /D NDEBUG + + set DEBUG_DATA= +) +if "%1"=="-d" ( + set BUILD_TYPE=DEBUG + set BUILD_FLAGS=/Od /Z7 /WX /FC /RTC1 /DDEBUG + + set "DEBUG_DATA=/Fd"%DESTINATION_DIR%\%EXE_NAME%.pdb" /Fm"%DESTINATION_DIR%\%EXE_NAME%.map"" +) + +REM Compile each .cpp file into an executable +cl ^ + %BUILD_FLAGS% /MT /nologo /Gm- /GR- /EHsc /W4 /wd4201 /wd4706 /wd4324 ^ + /fp:precise /Zc:wchar_t /Zc:forScope /Zc:inline /std:c++20 ^ + /D WIN32 /D _WINDOWS /D _UNICODE /D UNICODE ^ + /D _CRT_SECURE_NO_WARNINGS ^ + /Fo"%DESTINATION_DIR%/" /Fe"%DESTINATION_DIR%\MainTest.exe" %DEBUG_DATA% ^ + tests\MainTest.cpp ^ + /link /INCREMENTAL:no ^ + /SUBSYSTEM:CONSOLE /MACHINE:X64 ^ + kernel32.lib user32.lib gdi32.lib winmm.lib + +REM Check if the compilation was successful +if errorlevel 1 ( + echo Compilation failed for MainTest.cpp + exit /b 1 +) + +REM Run the compiled executable +"%DESTINATION_DIR%\MainTest.exe" + +REM Calculate runtime +set end_time=%time% +set options="tokens=1-4 delims=:.," +for /f %options% %%a in ("%start_time%") do set start_h=%%a&set /a start_m=100%%b %% 100&set /a start_s=100%%c %% 100&set /a start_ms=100%%d %% 100 +for /f %options% %%a in ("%end_time%") do set end_h=%%a&set /a end_m=100%%b %% 100&set /a end_s=100%%c %% 100&set /a end_ms=100%%d %% 100 + +set /a hours=%end_h%-%start_h% +set /a mins=%end_m%-%start_m% +set /a secs=%end_s%-%start_s% +set /a ms=%end_ms%-%start_ms% +if %ms% lss 0 set /a secs = %secs% - 1 & set /a ms = 100%ms% +if %secs% lss 0 set /a mins = %mins% - 1 & set /a secs = 60%secs% +if %mins% lss 0 set /a hours = %hours% - 1 & set /a mins = 60%mins% +if %hours% lss 0 set /a hours = 24%hours% +if 1%ms% lss 100 set ms=0%ms% + +set /a totalsecs = %hours%*3600 + %mins%*60 + %secs% +echo Test (incl. build) time %hours%:%mins%:%secs%.%ms% (%totalsecs%.%ms%s total) \ No newline at end of file diff --git a/tests/.vscode/c_cpp_properties.json b/tests/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..9c3b912 --- /dev/null +++ b/tests/.vscode/c_cpp_properties.json @@ -0,0 +1,23 @@ +{ + "configurations": [ + { + "name": "windows-clang-x64", + "includePath": [ + "${workspaceFolder}/**" + ], + "compilerPath": "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.39.33519/bin/Hostx64/x64/cl.exe", + "cStandard": "c17", + "cppStandard": "c++20", + "intelliSenseMode": "windows-clang-x64", + "compilerArgs": [ + "-fpermissive", + "-lgdi32", + "-lwinmm" + ], + "defines": [ + "DEBUG" + ] + } + ], + "version": 4 +} \ No newline at end of file diff --git a/tests/.vscode/launch.json b/tests/.vscode/launch.json new file mode 100644 index 0000000..93eb546 --- /dev/null +++ b/tests/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "C/C++ Runner: Debug Session", + "type": "cppvsdbg", + "request": "launch", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "program": "${workspaceFolder}\\${fileBasenameNoExtension}.exe", + "preLaunchTask": "C/C++: msvc" + } + ] +} \ No newline at end of file diff --git a/tests/.vscode/settings.json b/tests/.vscode/settings.json new file mode 100644 index 0000000..0843d8b --- /dev/null +++ b/tests/.vscode/settings.json @@ -0,0 +1,322 @@ +{ + "C_Cpp_Runner.cCompilerPath": "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.39.33519/bin/Hostx64/x64/cl.exe", + "C_Cpp_Runner.cppCompilerPath": "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.39.33519/bin/Hostx64/x64/cl.exe", + "C_Cpp_Runner.debuggerPath": "gdb", + "C_Cpp_Runner.cStandard": "c17", + "C_Cpp_Runner.cppStandard": "c++20", + "C_Cpp_Runner.msvcBatchPath": "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvarsall.bat", + "C_Cpp_Runner.useMsvc": false, + "C_Cpp_Runner.warnings": [ + "-Wall", + "-Wextra", + "-Wpedantic", + "-Wshadow", + "-Wformat=2", + "-Wcast-align", + "-Wconversion", + "-Wsign-conversion", + "-Wnull-dereference" + ], + "C_Cpp_Runner.msvcWarnings": [ + "/W4", + "/permissive-", + "/w14242", + "/w14287", + "/w14296", + "/w14311", + "/w14826", + "/w44062", + "/w44242", + "/w14905", + "/w14906", + "/w14263", + "/w44265", + "/w14928" + ], + "C_Cpp_Runner.enableWarnings": true, + "C_Cpp_Runner.warningsAsError": false, + "C_Cpp_Runner.compilerArgs": [], + "C_Cpp_Runner.linkerArgs": [], + "C_Cpp_Runner.includePaths": [], + "C_Cpp_Runner.includeSearch": [ + "*", + "**/*" + ], + "C_Cpp_Runner.excludeSearch": [ + "**/build", + "**/build/**", + "**/.*", + "**/.*/**", + "**/.vscode", + "**/.vscode/**", + "**/EngineDependencies/**" + ], + "C_Cpp_Runner.useAddressSanitizer": false, + "C_Cpp_Runner.useUndefinedSanitizer": false, + "C_Cpp_Runner.useLeakSanitizer": false, + "C_Cpp_Runner.showCompilationTime": false, + "C_Cpp_Runner.useLinkTimeOptimization": false, + "C_Cpp_Runner.msvcSecureNoWarnings": true, + "files.associations": { + "array": "cpp", + "regex": "cpp", + "xlocale": "cpp", + "xstring": "cpp", + "bitset": "cpp", + "string_view": "cpp", + "ctime": "cpp", + "deque": "cpp", + "iterator": "cpp", + "list": "cpp", + "queue": "cpp", + "stack": "cpp", + "vector": "cpp", + "xhash": "cpp", + "xtree": "cpp", + "format": "cpp", + "initializer_list": "cpp", + "random": "cpp", + "ranges": "cpp", + "span": "cpp", + "utility": "cpp", + "valarray": "cpp", + "xutility": "cpp", + "chrono": "cpp", + "system_error": "cpp", + "typeinfo": "cpp", + "*.rh": "cpp", + "charconv": "cpp", + "codecvt": "cpp", + "forward_list": "cpp", + "istream": "cpp", + "optional": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "variant": "cpp", + "xmemory": "cpp", + "*.tcc": "cpp", + "streambuf": "cpp", + "algorithm": "cpp", + "map": "cpp", + "functional": "cpp", + "type_traits": "cpp", + "xlocmon": "cpp", + "xtr1common": "cpp", + "ratio": "cpp", + "tuple": "cpp", + "corecrt_memory.h": "c", + "corecrt_wstring.h": "c", + "xiosbase": "cpp", + "cstddef": "cpp", + "cmath": "cpp", + "string": "cpp", + "iosfwd": "cpp", + "xlocbuf": "cpp", + "databaseconnection.h": "c", + "databasetype.h": "c", + "ringmemory.h": "c", + "threadjob.h": "c", + "thread.h": "c", + "testutils.h": "c", + "editordbentrytype.h": "c", + "sqlite3.h": "c", + "editordbhelper.h": "c", + "database.h": "c", + "editordbentry.h": "c", + "atomic": "cpp", + "bit": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "compare": "cpp", + "concepts": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "cwchar": "cpp", + "exception": "cpp", + "ios": "cpp", + "iostream": "cpp", + "limits": "cpp", + "locale": "cpp", + "memory": "cpp", + "new": "cpp", + "stdexcept": "cpp", + "xfacet": "cpp", + "xlocinfo": "cpp", + "xlocmes": "cpp", + "xlocnum": "cpp", + "xloctime": "cpp", + "endianutils.h": "c", + "debugmemory.h": "c", + "threaddefines.h": "c", + "threadpool.h": "c", + "windows.h": "c", + "types.h": "c", + "allocation.h": "c", + "utilswin32.h": "c", + "debug.cpp": "c", + "debug.h": "c", + "timingstat.h": "c", + "log.h": "c", + "utils.h": "c", + "buffermemory.h": "c", + "semaphore.h": "c", + "atomic.h": "c", + "stdint.h": "c", + "allocator.h": "c", + "stdatomic.h": "c", + "time.h": "c", + "spinlock.h": "c", + "immintrin.h": "c", + "timeutils.h": "c", + "ui_opengl.h": "c", + "debug_opengl.h": "c", + "vertex.h": "c", + "openglutils.h": "c", + "asset.h": "c", + "expected": "cpp", + "set": "cpp", + "opengl.h": "c", + "openglwin32.h": "c", + "window.h": "c", + "image.cpp": "c", + "texture.h": "c", + "debug_directx.h": "c", + "opengllinux.h": "c", + "opengldefines.h": "c", + "dev_debug.h": "c", + "scenegeneral.h": "c", + "fileutils.cpp": "c", + "assetarchive.h": "c", + "library.h": "c", + "assettype.h": "c", + "stringutils.h": "c", + "mathutils.h": "c", + "spinlock.cpp": "c", + "font.h": "c", + "malloc.h": "c", + "shader.h": "c", + "general.h": "c", + "debug_vulkan.h": "c", + "gamestate.h": "c", + "uitheme.h": "c", + "uielementtype.h": "c", + "uiinput.h": "c", + "uielement.h": "c", + "uiwindow.h": "c", + "uiattributefont.h": "c", + "renderutils.h": "c", + "application.h": "c", + "shaderutils.h": "c", + "uiattributeshadow.h": "c", + "matrixfloat32.h": "c", + "uialignment.h": "c", + "intrinsics.h": "c", + "uianimation.h": "c", + "evaluator.h": "c", + "uicursor.h": "c", + "uitextarea.h": "c", + "uitext.h": "c", + "compilerutils.h": "c", + "thread": "c", + "string.h": "c", + "stdlib.h": "c", + "simd.h": "c", + "arm_neon.h": "c", + "simd_svml.h": "c", + "simd_f32.h": "c", + "simd_f64.h": "c", + "uilayout.h": "c", + "camera.h": "c", + "stdio.h": "c", + "uilabel.h": "c" + }, + "C_Cpp.default.cppStandard": "c++20", + "todo-tree.general.tags": [ + "SECURITY", + "BUG", + "FEATURE", + "FIXME", + "PERFORMANCE", + "TODO", + "QUESTION" + ], + "todo-tree.filtering.excludeGlobs": [ + "**/node_modules/*/**", + "**/Resources/*", + "**/EngineDependencies/*", + "**/*.md", + "**/findMissingApiFunctions.php", + "**/*.min.*" + ], + "todo-tree.regex.regex": "(//|\\*|#|