mirror of
https://github.com/Karaka-Management/cOMS.git
synced 2026-01-10 19:08:39 +00:00
working again, ui layout not yet fully implemented. test framework functional.
This commit is contained in:
parent
fd47385162
commit
a8191a239a
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -4,4 +4,7 @@ bin/*
|
|||
*.obj
|
||||
*.log
|
||||
*.spv
|
||||
*.res
|
||||
*.res
|
||||
*.exe
|
||||
*.map
|
||||
*.pdb
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
#include <arm_acle.h>
|
||||
|
||||
#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
|
||||
109
architecture/arm/neon/utils/Utils.h
Normal file
109
architecture/arm/neon/utils/Utils.h
Normal file
|
|
@ -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 <stdlib.h>
|
||||
#include "../../../../stdlib/Types.h"
|
||||
#include "../../../../compiler/CompilerUtils.h"
|
||||
#include "../../../../stdlib/Simd.h"
|
||||
#include <arm_neon.h>
|
||||
|
||||
// @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
|
||||
110
architecture/arm/sve/utils/Utils.h
Normal file
110
architecture/arm/sve/utils/Utils.h
Normal file
|
|
@ -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 <stdlib.h>
|
||||
#include "../../../../stdlib/Types.h"
|
||||
#include "../../../../compiler/CompilerUtils.h"
|
||||
#include "../../../../stdlib/Simd.h"
|
||||
#include <arm_sve.h>
|
||||
|
||||
// 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
|
||||
|
|
@ -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
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
#include <immintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
|
||||
#include "../Types.h"
|
||||
#include "../../../stdlib/Types.h"
|
||||
#include "SIMD_SVML.h"
|
||||
|
||||
struct f32_4 {
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
#include <immintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
|
||||
#include "../Types.h"
|
||||
#include "../../../stdlib/Types.h"
|
||||
|
||||
struct f64_2 {
|
||||
union {
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
#include <immintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
|
||||
#include "../Types.h"
|
||||
#include "../../../stdlib/Types.h"
|
||||
|
||||
struct int16_8 {
|
||||
union {
|
||||
|
|
@ -13,8 +13,8 @@
|
|||
#include <xmmintrin.h>
|
||||
#include <emmintrin.h>
|
||||
|
||||
#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
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
#include <immintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
|
||||
#include "../Types.h"
|
||||
#include "../../../stdlib/Types.h"
|
||||
#include "SIMD_F64.h"
|
||||
|
||||
struct int64_2 {
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
#include <immintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
|
||||
#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) {
|
||||
|
|
@ -12,6 +12,8 @@
|
|||
#include <immintrin.h>
|
||||
#include <xmmintrin.h>
|
||||
|
||||
#include "../../../stdlib/Types.h"
|
||||
|
||||
#if __linux__
|
||||
#include "math.h"
|
||||
|
||||
84
architecture/x86/simd/utils/Utils.h
Normal file
84
architecture/x86/simd/utils/Utils.h
Normal file
|
|
@ -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 <stdlib.h>
|
||||
#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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
21
audio/Qoa.h
21
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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
28
font/Font.h
28
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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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")) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
11
log/Debug.h
11
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
#ifndef TOS_LOG_H
|
||||
#define TOS_LOG_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../stdlib/Types.h"
|
||||
#include "Debug.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
#ifndef TOS_LOG_TIMING_STAT_H
|
||||
#define TOS_LOG_TIMING_STAT_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../stdlib/Types.h"
|
||||
#include "Debug.h"
|
||||
|
||||
|
|
|
|||
169
math/Evaluator.h
169
math/Evaluator.h
|
|
@ -11,11 +11,12 @@
|
|||
|
||||
#include "../stdlib/Types.h"
|
||||
#include "../utils/StringUtils.h"
|
||||
#include "../utils/TestUtils.h"
|
||||
#include "../compiler/CompilerUtils.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#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
|
||||
|
|
@ -9,7 +9,6 @@
|
|||
#ifndef TOS_MATH_MATRIX_FLOAT32_H
|
||||
#define TOS_MATH_MATRIX_FLOAT32_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,28 +16,6 @@
|
|||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
|
||||
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
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
#include "../../stdlib/Types.h"
|
||||
#include "../../utils/StringUtils.h"
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include <string.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -13,16 +13,16 @@
|
|||
#include <dbghelp.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#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
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include <time.h>
|
||||
#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;
|
||||
|
|
|
|||
|
|
@ -11,9 +11,7 @@
|
|||
|
||||
#include "../../stdlib/Types.h"
|
||||
#include "../../utils/StringUtils.h"
|
||||
#include <stdio.h>
|
||||
#include <windows.h>
|
||||
#include <string.h>
|
||||
|
||||
#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
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@
|
|||
#include "../../../stdlib/Types.h"
|
||||
#include "../TimeUtils.h"
|
||||
#include "ThreadDefines.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
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
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
#ifndef TOS_PLATFORM_WIN32_THREADING_THREAD_DEFINES_H
|
||||
#define TOS_PLATFORM_WIN32_THREADING_THREAD_DEFINES_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../../../stdlib/Types.h"
|
||||
#include <windows.h>
|
||||
|
||||
#define THREAD_RETURN DWORD WINAPI
|
||||
|
|
|
|||
20
scene/SceneInfo.h
Normal file
20
scene/SceneInfo.h
Normal file
|
|
@ -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
|
||||
23
sort/BinarySearch.h
Normal file
23
sort/BinarySearch.h
Normal file
|
|
@ -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
|
||||
74
sort/EytzingerSearch.h
Normal file
74
sort/EytzingerSearch.h
Normal file
|
|
@ -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
|
||||
50
sort/HeapSort.h
Normal file
50
sort/HeapSort.h
Normal file
|
|
@ -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
|
||||
16
sort/InsertionSort.h
Normal file
16
sort/InsertionSort.h
Normal file
|
|
@ -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
|
||||
37
sort/IntroSort.h
Normal file
37
sort/IntroSort.h
Normal file
|
|
@ -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
|
||||
37
sort/QuickSort.h
Normal file
37
sort/QuickSort.h
Normal file
|
|
@ -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
|
||||
34
sort/Sort.h
Normal file
34
sort/Sort.h
Normal file
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <arm_neon.h>
|
||||
#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
|
||||
|
|
@ -11,9 +11,12 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if _WIN32
|
||||
#include <windows.h>
|
||||
typedef SSIZE_T ssize_t;
|
||||
#elif __linux__
|
||||
#include <linux/limits.h>
|
||||
#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))
|
||||
|
|
|
|||
82
tests.bat
Normal file
82
tests.bat
Normal file
|
|
@ -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)
|
||||
23
tests/.vscode/c_cpp_properties.json
vendored
Normal file
23
tests/.vscode/c_cpp_properties.json
vendored
Normal file
|
|
@ -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
|
||||
}
|
||||
16
tests/.vscode/launch.json
vendored
Normal file
16
tests/.vscode/launch.json
vendored
Normal file
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
322
tests/.vscode/settings.json
vendored
Normal file
322
tests/.vscode/settings.json
vendored
Normal file
|
|
@ -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": "(//|\\*|#|<!--|;|/\\*|^|^[ \\t]*(-|\\d+.))\\s*@($TAGS)",
|
||||
"todo-tree.highlights.customHighlight": {
|
||||
"SECURITY": {
|
||||
"icon": "flame"
|
||||
},
|
||||
"BUG": {
|
||||
"icon": "bug"
|
||||
},
|
||||
"FEATURE": {
|
||||
"icon": "tag"
|
||||
},
|
||||
"FIXME": {
|
||||
"icon": "tools"
|
||||
},
|
||||
"PERFORMANCE": {
|
||||
"icon": "clock"
|
||||
},
|
||||
"TODO": {
|
||||
"icon": "tasklist"
|
||||
},
|
||||
"QUESTION": {
|
||||
"icon": "question"
|
||||
},
|
||||
"[ ]": {
|
||||
"icon": "issue-draft"
|
||||
},
|
||||
"[x]": {
|
||||
"icon": "issue-closed"
|
||||
}
|
||||
},
|
||||
"todo-tree.highlights.useColourScheme": true,
|
||||
"todo-tree.highlights.backgroundColourScheme": [
|
||||
"red",
|
||||
"darkred",
|
||||
"orange",
|
||||
"yellow",
|
||||
"teal",
|
||||
"green",
|
||||
"pink"
|
||||
],
|
||||
"todo-tree.tree.showCountsInTree": true,
|
||||
"todo-tree.tree.labelFormat": "${after}",
|
||||
"todo-tree.highlights.foregroundColourScheme": [
|
||||
"white",
|
||||
"white",
|
||||
"black",
|
||||
"white",
|
||||
"white",
|
||||
"white",
|
||||
"black"
|
||||
],
|
||||
"cSpell.words": [
|
||||
"botting",
|
||||
"cooldown",
|
||||
"Deathmatch",
|
||||
"debuff",
|
||||
"directx",
|
||||
"Eichhorn",
|
||||
"interactable",
|
||||
"Jingga",
|
||||
"MMORPG",
|
||||
"opengl",
|
||||
"pathing",
|
||||
"replayability",
|
||||
"respawn",
|
||||
"Shapeshifting",
|
||||
"speedrun",
|
||||
"stackable"
|
||||
]
|
||||
}
|
||||
80
tests/.vscode/tasks.json
vendored
Normal file
80
tests/.vscode/tasks.json
vendored
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
{
|
||||
"tasks": [
|
||||
{
|
||||
"type": "cppbuild",
|
||||
"label": "C/C++: msvc",
|
||||
"command": "cl.exe",
|
||||
"args": [
|
||||
"/nologo",
|
||||
"/MT",
|
||||
"/nologo",
|
||||
"/Gm-",
|
||||
"/GR-",
|
||||
"/EHsc",
|
||||
"/Od",
|
||||
"/Oi",
|
||||
"/WX",
|
||||
"/W4",
|
||||
"/FC",
|
||||
"/Z7",
|
||||
"/RTC1",
|
||||
"/wd4100",
|
||||
"/wd4189",
|
||||
"/wd4201",
|
||||
"/wd4018",
|
||||
"/wd4389",
|
||||
"/wd4706",
|
||||
"/wd4324",
|
||||
"/wd4505",
|
||||
"/wd5054",
|
||||
"/fp:precise",
|
||||
"/Zc:wchar_t",
|
||||
"/Zc:forScope",
|
||||
"/Zc:inline",
|
||||
"/std:c++20",
|
||||
"/D",
|
||||
"DEBUG",
|
||||
"/D",
|
||||
"WIN32",
|
||||
"/D",
|
||||
"_WINDOWS",
|
||||
"/D",
|
||||
"_UNICODE",
|
||||
"/D",
|
||||
"_CRT_SECURE_NO_WARNINGS",
|
||||
"/D",
|
||||
"UNICODE",
|
||||
"/Fo:",
|
||||
"${fileBasenameNoExtension}",
|
||||
"/Fe:",
|
||||
"${fileBasenameNoExtension}.exe",
|
||||
"/Fd:",
|
||||
"${fileBasenameNoExtension}.pdb",
|
||||
"/Fm:",
|
||||
"${fileBasenameNoExtension}.map",
|
||||
"${file}",
|
||||
"/link",
|
||||
"/INCREMENTAL:no",
|
||||
"/OPT:ref",
|
||||
"/SUBSYSTEM:CONSOLE",
|
||||
"/MACHINE:X64",
|
||||
"kernel32.lib",
|
||||
"user32.lib",
|
||||
"gdi32.lib",
|
||||
"winmm.lib"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$msCompile"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"detail": "Task generated by Debugger."
|
||||
}
|
||||
],
|
||||
"version": "2.0.0"
|
||||
}
|
||||
44
tests/MainTest.cpp
Normal file
44
tests/MainTest.cpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#define UBER_TEST 1
|
||||
|
||||
#include "math/EvaluatorTest.cpp"
|
||||
#include "memory/ChunkMemoryTest.cpp"
|
||||
#include "memory/RingMemoryTest.cpp"
|
||||
#include "stdlib/HashMapTest.cpp"
|
||||
#include "ui/UILayoutTest.cpp"
|
||||
#include "ui/UIThemeTest.cpp"
|
||||
#include "utils/BitUtilsTest.cpp"
|
||||
#include "utils/EndianUtilsTest.cpp"
|
||||
#include "utils/StringUtilsTest.cpp"
|
||||
#include "utils/UtilsTest.cpp"
|
||||
|
||||
#ifdef UBER_TEST
|
||||
#ifdef main
|
||||
#undef main
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
printf("\nStat Tests Asserts Details\n");
|
||||
printf("========================================================================================================================\n");
|
||||
|
||||
MathEvaluatorTest();
|
||||
MemoryChunkMemoryTest();
|
||||
MemoryRingMemoryTest();
|
||||
StdlibHashMapTest();
|
||||
UIUILayoutTest();
|
||||
UIUIThemeTest();
|
||||
UtilsBitUtilsTest();
|
||||
UtilsStringUtilsTest();
|
||||
UtilsUtilsTest();
|
||||
|
||||
printf("========================================================================================================================\n");
|
||||
printf(
|
||||
"%s %5d (%5d/%5d)\n\n",
|
||||
_test_global_assert_count ? "[NG]" : "[OK]",
|
||||
_test_global_count,
|
||||
_test_global_assert_count - _test_global_assert_error_count,
|
||||
_test_global_assert_count
|
||||
);
|
||||
|
||||
return _test_global_assert_error_count ? 1 : 0;
|
||||
}
|
||||
354
tests/TestFramework.h
Normal file
354
tests/TestFramework.h
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
/**
|
||||
* Jingga
|
||||
*
|
||||
* @copyright Jingga
|
||||
* @license OMS License 2.0
|
||||
* @version 1.0.0
|
||||
* @link https://jingga.app
|
||||
*/
|
||||
#ifndef TOS_TEST_FRAMEWORK_H
|
||||
#define TOS_TEST_FRAMEWORK_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "../architecture/Intrinsics.h"
|
||||
|
||||
static char **_test_log;
|
||||
static int32_t _test_assert_count;
|
||||
static int32_t _test_assert_error_count;
|
||||
static int32_t _test_count = -1;
|
||||
|
||||
static int32_t _test_global_assert_count = 0;
|
||||
static int32_t _test_global_assert_error_count = 0;
|
||||
static int32_t _test_global_count = 0;
|
||||
|
||||
#if _WIN32
|
||||
#include "../platform/win32/ExceptionHandler.h"
|
||||
#include <windows.h>
|
||||
LONG WINAPI test_exception_handler(EXCEPTION_POINTERS *exception_info)
|
||||
{
|
||||
printf("Exception code: 0x%x\n", exception_info->ExceptionRecord->ExceptionCode);
|
||||
print_stack_trace(exception_info->ContextRecord);
|
||||
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
double test_measure_func_time_ns(void (*func)(void *), void *para)
|
||||
{
|
||||
LARGE_INTEGER frequency, start, end;
|
||||
QueryPerformanceFrequency(&frequency);
|
||||
QueryPerformanceCounter(&start);
|
||||
func(para);
|
||||
QueryPerformanceCounter(&end);
|
||||
return (double)(end.QuadPart - start.QuadPart) * 1e9 / frequency.QuadPart;
|
||||
}
|
||||
|
||||
#define TEST_INIT(test_count) \
|
||||
do \
|
||||
{ \
|
||||
SetUnhandledExceptionFilter(test_exception_handler); \
|
||||
_test_assert_error_count = 0; \
|
||||
_test_count = 0; \
|
||||
_test_assert_count = 0; \
|
||||
_test_log = (char **)calloc((test_count), sizeof(char *) + (test_count) * 1024); \
|
||||
if (_test_log) \
|
||||
{ \
|
||||
for (int i = 0; i < (test_count); i++) \
|
||||
{ \
|
||||
_test_log[i] = (char *)(_test_log + (test_count) * sizeof(char *) + i * 1024); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#include "../platform/linux/ExceptionHandler.h"
|
||||
void test_exception_handler(int signum)
|
||||
{
|
||||
printf("Received signal: %d\n", signum);
|
||||
print_stack_trace();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#include <time.h>
|
||||
double test_measure_func_time_ns(void (*func)(void *), void *para)
|
||||
{
|
||||
struct timespec start, end;
|
||||
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||
func(para);
|
||||
clock_gettime(CLOCK_MONOTONIC, &end);
|
||||
return (double)(end.tv_sec * 1e9 + end.tv_nsec) - (double)(start.tv_sec * 1e9 + start.tv_nsec);
|
||||
}
|
||||
|
||||
#define TEST_INIT(test_count) \
|
||||
do \
|
||||
{ \
|
||||
signal(SIGSEGV, test_exception_handler); \
|
||||
signal(SIGABRT, test_exception_handler); \
|
||||
_test_assert_error_count = 0; \
|
||||
_test_count = 0; \
|
||||
_test_assert_count = 0; \
|
||||
_test_log = (char **)calloc((test_count), sizeof(char *) + (test_count) * 1024); \
|
||||
if (_test_log) \
|
||||
{ \
|
||||
for (int i = 0; i < (test_count); i++) \
|
||||
{ \
|
||||
_test_log[i] = (char *)(_test_log + (test_count) * sizeof(char *) + i * 1024); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define TEST_FINALIZE() \
|
||||
do \
|
||||
{ \
|
||||
if (_test_assert_error_count) \
|
||||
{ \
|
||||
printf( \
|
||||
"[NG] %5d (%5d/%5d) %s\n", \
|
||||
_test_count, _test_assert_count - _test_assert_error_count, _test_assert_count, __FILE__); \
|
||||
for (int i = 0; i < _test_assert_error_count; ++i) \
|
||||
{ \
|
||||
printf(" %s\n", _test_log[i]); \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
printf( \
|
||||
"[OK] %5d (%5d/%5d) %s\n", \
|
||||
_test_count, _test_assert_count - _test_assert_error_count, _test_assert_count, __FILE__); \
|
||||
} \
|
||||
free(_test_log); \
|
||||
_test_log = NULL; \
|
||||
_test_assert_error_count = 0; \
|
||||
_test_count = 0; \
|
||||
_test_assert_count = 0; \
|
||||
} while (0)
|
||||
|
||||
#define RUN_TEST(func) \
|
||||
++_test_count; \
|
||||
++_test_global_count; \
|
||||
func()
|
||||
|
||||
#define ASSERT_EQUALS(a, b) \
|
||||
do \
|
||||
{ \
|
||||
++_test_assert_count; \
|
||||
++_test_global_assert_count; \
|
||||
if ((a) != (b)) \
|
||||
{ \
|
||||
++_test_global_assert_error_count; \
|
||||
snprintf( \
|
||||
_test_log[_test_assert_error_count++], 1024, \
|
||||
"%4i: %lld != %lld", __LINE__, (int64)(a), (int64)(b)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_NOT_EQUALS(a, b) \
|
||||
do \
|
||||
{ \
|
||||
++_test_assert_count; \
|
||||
++_test_global_assert_count; \
|
||||
if ((a) == (b)) \
|
||||
{ \
|
||||
++_test_global_assert_error_count; \
|
||||
snprintf( \
|
||||
_test_log[_test_assert_error_count++], 1024, \
|
||||
"%4i: %lld == %lld", __LINE__, (int64)(a), (int64)(b)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_EQUALS_WITH_DELTA(a, b, delta) \
|
||||
do \
|
||||
{ \
|
||||
++_test_assert_count; \
|
||||
++_test_global_assert_count; \
|
||||
if (OMS_ABS((a) - (b)) > (delta)) \
|
||||
{ \
|
||||
++_test_global_assert_error_count; \
|
||||
snprintf( \
|
||||
_test_log[_test_assert_error_count++], 1024, \
|
||||
"%4i: %lld != %lld", __LINE__, (int64)(a), (int64)(b)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_CONTAINS(a, b) \
|
||||
do \
|
||||
{ \
|
||||
++_test_assert_count; \
|
||||
++_test_global_assert_count; \
|
||||
if (str_find((a), (b)) == NULL) \
|
||||
{ \
|
||||
++_test_global_assert_error_count; \
|
||||
snprintf( \
|
||||
_test_log[_test_assert_error_count++], 1024, \
|
||||
"%4i: %s !contains %s", __LINE__, (a), (b)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_TRUE(a) \
|
||||
do \
|
||||
{ \
|
||||
++_test_assert_count; \
|
||||
++_test_global_assert_count; \
|
||||
if ((a) != true) \
|
||||
{ \
|
||||
++_test_global_assert_error_count; \
|
||||
snprintf( \
|
||||
_test_log[_test_assert_error_count++], 1024, \
|
||||
"%4i: is false", __LINE__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_FALSE(a) \
|
||||
do \
|
||||
{ \
|
||||
++_test_assert_count; \
|
||||
++_test_global_assert_count; \
|
||||
if ((a) != false) \
|
||||
{ \
|
||||
++_test_global_assert_error_count; \
|
||||
snprintf( \
|
||||
_test_log[_test_assert_error_count++], 1024, \
|
||||
"%4i: is true", __LINE__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_TRUE_CONST(a) \
|
||||
do \
|
||||
{ \
|
||||
++_test_assert_count; \
|
||||
++_test_global_assert_count; \
|
||||
if constexpr ((a) != true) \
|
||||
{ \
|
||||
++_test_global_assert_error_count; \
|
||||
snprintf( \
|
||||
_test_log[_test_assert_error_count++], 1024, \
|
||||
"%4i: is false", __LINE__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_FALSE_CONST(a) \
|
||||
do \
|
||||
{ \
|
||||
++_test_assert_count; \
|
||||
++_test_global_assert_count; \
|
||||
if constexpr ((a) != false) \
|
||||
{ \
|
||||
++_test_global_assert_error_count; \
|
||||
snprintf( \
|
||||
_test_log[_test_assert_error_count++], 1024, \
|
||||
"%4i: is true", __LINE__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define COMPARE_FUNCTION_TEST_CYCLE(func1, func2, x_percent) \
|
||||
do \
|
||||
{ \
|
||||
++_test_assert_count; \
|
||||
++_test_global_assert_count; \
|
||||
uint64_t cycles_func1, cycles_func2; \
|
||||
uint64_t start, end; \
|
||||
int64_t a = 0, b = 0; \
|
||||
\
|
||||
/* Measure func1 */ \
|
||||
start = intrin_timestamp_counter(); \
|
||||
func1((void *)&a); \
|
||||
end = intrin_timestamp_counter(); \
|
||||
cycles_func1 = end - start; \
|
||||
\
|
||||
/* Measure func2 */ \
|
||||
start = intrin_timestamp_counter(); \
|
||||
func2((void *)&b); \
|
||||
end = intrin_timestamp_counter(); \
|
||||
cycles_func2 = end - start; \
|
||||
\
|
||||
/* Calculate percentage difference */ \
|
||||
double percent_diff = 100.0 * ((double)cycles_func1 - (double)cycles_func2) / (double)cycles_func2; \
|
||||
\
|
||||
/* Check if within x% */ \
|
||||
if (isnormal(percent_diff) && percent_diff >= x_percent) \
|
||||
{ \
|
||||
++_test_global_assert_error_count; \
|
||||
snprintf( \
|
||||
_test_log[_test_assert_error_count++], 1024, \
|
||||
"%4i: %.2f%% (%s: %llu cycles, %s: %llu cycles)", \
|
||||
__LINE__, percent_diff + 100.0f, #func1, (uint64_t)cycles_func1, #func2, (uint64_t)cycles_func2); \
|
||||
} \
|
||||
ASSERT_EQUALS(a, b); \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_FUNCTION_TEST_CYCLE(func, cycles) \
|
||||
do \
|
||||
{ \
|
||||
++_test_assert_count; \
|
||||
++_test_global_assert_count; \
|
||||
uint64_t cycles_func; \
|
||||
uint64_t start, end; \
|
||||
int64_t para = 0; \
|
||||
\
|
||||
/* Measure func */ \
|
||||
start = intrin_timestamp_counter(); \
|
||||
func((void *)¶); \
|
||||
end = intrin_timestamp_counter(); \
|
||||
cycles_func = end - start; \
|
||||
\
|
||||
if (cycles_func >= cycles) \
|
||||
{ \
|
||||
++_test_global_assert_error_count; \
|
||||
snprintf( \
|
||||
_test_log[_test_assert_error_count++], 1024, \
|
||||
"%4i: %.2f%% (%s: %llu cycles)", \
|
||||
__LINE__, percent_diff + 100.0f, #func, (uint64_t)cycles_func); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define COMPARE_FUNCTION_TEST_TIME(func1, func2, x_percent) \
|
||||
do \
|
||||
{ \
|
||||
++_test_assert_count; \
|
||||
++_test_global_assert_count; \
|
||||
double time_func1, time_func2; \
|
||||
int64_t a = 0, b = 0; \
|
||||
\
|
||||
/* Measure func1 */ \
|
||||
time_func1 = test_measure_func_time_ns(func1, (void *)&a); \
|
||||
\
|
||||
/* Measure func2 */ \
|
||||
time_func2 = test_measure_func_time_ns(func2, (void *)&b); \
|
||||
\
|
||||
/* Calculate percentage difference */ \
|
||||
double percent_diff = 100.0 * (time_func1 - time_func2) / time_func2; \
|
||||
\
|
||||
/* Print results */ \
|
||||
if (isnormal(percent_diff) && percent_diff >= x_percent) \
|
||||
{ \
|
||||
++_test_global_assert_error_count; \
|
||||
snprintf( \
|
||||
_test_log[_test_assert_error_count++], 1024, \
|
||||
"%4i: %.2f%% (%s: %.2f ns, %s: %.2f ns)", \
|
||||
__LINE__, percent_diff + 100.0f, #func1, time_func1, #func2, time_func2); \
|
||||
} \
|
||||
ASSERT_EQUALS(a, b); \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_FUNCTION_TEST_TIME(func, duration) \
|
||||
do \
|
||||
{ \
|
||||
++_test_assert_count; \
|
||||
++_test_global_assert_count; \
|
||||
double time_func; \
|
||||
int64_t para = 0; \
|
||||
\
|
||||
/* Measure func */ \
|
||||
time_func = test_measure_func_time_ns(func, (void *)¶); \
|
||||
\
|
||||
if (time_func >= duration) \
|
||||
{ \
|
||||
++_test_global_assert_error_count; \
|
||||
snprintf( \
|
||||
_test_log[_test_assert_error_count++], 1024, \
|
||||
"%4i: %.2f%% (%s: %.2f ns, %s: %.2f ns)", \
|
||||
__LINE__, percent_diff + 100.0f, #func, time_func); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
57
tests/math/EvaluatorTest.cpp
Normal file
57
tests/math/EvaluatorTest.cpp
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#include "../TestFramework.h"
|
||||
#include "../../math/Evaluator.h"
|
||||
|
||||
static void test_evaluator_evaluate() {
|
||||
char expr[64];
|
||||
memcpy(expr, "(2 * 4 - 1 + 3) / 2", sizeof("(2 * 4 - 1 + 3) / 2"));
|
||||
|
||||
ASSERT_EQUALS(evaluator_evaluate(expr), 5);
|
||||
ASSERT_NOT_EQUALS(evaluator_evaluate(expr), 1);
|
||||
}
|
||||
|
||||
static void test_evaluator_evaluate_variables() {
|
||||
char expr[64];
|
||||
memcpy(expr, "(x * 4 + y + 3) / 2", sizeof("(x * 4 + y + 3) / 2"));
|
||||
|
||||
const EvaluatorVariable variables[2] = {
|
||||
{"x", 2},
|
||||
{"y", -1}
|
||||
};
|
||||
|
||||
ASSERT_EQUALS(evaluator_evaluate(expr, 2, (const EvaluatorVariable *) &variables), 5);
|
||||
}
|
||||
|
||||
static void test_evaluator_evaluate_function() {
|
||||
char expr[64];
|
||||
|
||||
memcpy(expr, "1 + min(2, 3)", sizeof("1 + min(2, 3)"));
|
||||
ASSERT_EQUALS(evaluator_evaluate(expr), 3);
|
||||
|
||||
memcpy(expr, "1 + max(2, 3)", sizeof("1 + max(2, 3)"));
|
||||
ASSERT_EQUALS(evaluator_evaluate(expr), 4);
|
||||
|
||||
const EvaluatorVariable variables[1] = {
|
||||
{"x", 2}
|
||||
};
|
||||
memcpy(expr, "x + max(x * 2, 3 * x) / x", sizeof("x + max(x * 2, 3 * x) / x"));
|
||||
ASSERT_EQUALS(evaluator_evaluate(expr, 1, (const EvaluatorVariable *) &variables), 5);
|
||||
}
|
||||
|
||||
#ifdef UBER_TEST
|
||||
#ifdef main
|
||||
#undef main
|
||||
#endif
|
||||
#define main MathEvaluatorTest
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
TEST_INIT(10);
|
||||
|
||||
RUN_TEST(test_evaluator_evaluate);
|
||||
RUN_TEST(test_evaluator_evaluate_variables);
|
||||
RUN_TEST(test_evaluator_evaluate_function);
|
||||
|
||||
TEST_FINALIZE();
|
||||
|
||||
return 0;
|
||||
}
|
||||
148
tests/memory/ChunkMemoryTest.cpp
Normal file
148
tests/memory/ChunkMemoryTest.cpp
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
#include "../TestFramework.h"
|
||||
#include "../../memory/ChunkMemory.h"
|
||||
|
||||
static void test_chunk_alloc() {
|
||||
ChunkMemory mem = {};
|
||||
chunk_alloc(&mem, 10, 10);
|
||||
|
||||
ASSERT_TRUE(memcmp(mem.memory, mem.memory + 1, 10 * 10) == 0);
|
||||
ASSERT_EQUALS(mem.size, 10 * 64 + 8 * 1); // chunks are aligned to 64
|
||||
ASSERT_EQUALS(*mem.free, 0);
|
||||
|
||||
chunk_free(&mem);
|
||||
ASSERT_EQUALS(mem.size, 0);
|
||||
ASSERT_EQUALS(mem.memory, NULL);
|
||||
}
|
||||
|
||||
static void test_chunk_id_from_memory() {
|
||||
ChunkMemory mem = {};
|
||||
chunk_alloc(&mem, 10, 10);
|
||||
|
||||
ASSERT_EQUALS(chunk_id_from_memory(&mem, mem.memory), 0);
|
||||
ASSERT_EQUALS(chunk_id_from_memory(&mem, mem.memory + 64), 1);
|
||||
ASSERT_EQUALS(chunk_id_from_memory(&mem, mem.memory + 127), 1);
|
||||
ASSERT_EQUALS(chunk_id_from_memory(&mem, mem.memory + 128), 2);
|
||||
|
||||
chunk_free(&mem);
|
||||
}
|
||||
|
||||
static void test_chunk_get_element() {
|
||||
ChunkMemory mem = {};
|
||||
chunk_alloc(&mem, 10, 10);
|
||||
|
||||
ASSERT_EQUALS(chunk_get_element(&mem, 2), mem.memory + 128);
|
||||
|
||||
chunk_free(&mem);
|
||||
}
|
||||
|
||||
static void test_chunk_reserve() {
|
||||
ChunkMemory mem = {};
|
||||
chunk_alloc(&mem, 10, 10);
|
||||
|
||||
ASSERT_EQUALS(chunk_reserve(&mem, 1), 0);
|
||||
ASSERT_EQUALS(chunk_reserve(&mem, 1), 1);
|
||||
ASSERT_TRUE(IS_BIT_SET_64_R2L(*mem.free, 0));
|
||||
ASSERT_TRUE(IS_BIT_SET_64_R2L(*mem.free, 1));
|
||||
ASSERT_FALSE(IS_BIT_SET_64_R2L(*mem.free, 2));
|
||||
|
||||
ASSERT_EQUALS(chunk_reserve(&mem, 2), 2);
|
||||
ASSERT_TRUE(IS_BIT_SET_64_R2L(*mem.free, 2));
|
||||
ASSERT_TRUE(IS_BIT_SET_64_R2L(*mem.free, 3));
|
||||
|
||||
chunk_free(&mem);
|
||||
}
|
||||
|
||||
static void test_chunk_free_elements() {
|
||||
ChunkMemory mem = {};
|
||||
chunk_alloc(&mem, 10, 10);
|
||||
|
||||
ASSERT_EQUALS(chunk_reserve(&mem, 3), 0);
|
||||
|
||||
chunk_free_elements(&mem, 0, 2);
|
||||
ASSERT_FALSE(IS_BIT_SET_64_R2L(*mem.free, 0));
|
||||
ASSERT_FALSE(IS_BIT_SET_64_R2L(*mem.free, 1));
|
||||
ASSERT_TRUE(IS_BIT_SET_64_R2L(*mem.free, 2));
|
||||
|
||||
chunk_free_elements(&mem, 2, 1);
|
||||
ASSERT_FALSE(IS_BIT_SET_64_R2L(*mem.free, 2));
|
||||
|
||||
chunk_free_elements(&mem, 0, 10);
|
||||
ASSERT_EQUALS(*mem.free, 0);
|
||||
|
||||
chunk_free(&mem);
|
||||
}
|
||||
|
||||
// To ensure there is no logical error we test memory wrapping specifically
|
||||
static void test_chunk_reserve_wrapping() {
|
||||
ChunkMemory mem = {};
|
||||
chunk_alloc(&mem, 10, 10);
|
||||
|
||||
mem.last_pos = 7;
|
||||
ASSERT_EQUALS(chunk_reserve(&mem, 5), 0);
|
||||
ASSERT_EQUALS((byte) BITS_GET_8_R2L(*mem.free, 0, 8), (byte) 0b00011111);
|
||||
|
||||
chunk_free(&mem);
|
||||
}
|
||||
|
||||
// To ensure there is no logical error we test the last element specifically
|
||||
static void test_chunk_reserve_last_element() {
|
||||
ChunkMemory mem = {};
|
||||
chunk_alloc(&mem, 10, 10);
|
||||
|
||||
// Get last element when the last_pos is the previous element
|
||||
mem.last_pos = 8;
|
||||
ASSERT_EQUALS(chunk_reserve(&mem, 1), 9);
|
||||
|
||||
// Get last element when the last element is not defined and all other elements are in use
|
||||
mem.last_pos = -1;
|
||||
*mem.free = 511;
|
||||
ASSERT_EQUALS(chunk_reserve(&mem, 1), 9);
|
||||
|
||||
chunk_free(&mem);
|
||||
}
|
||||
|
||||
#if !DEBUG
|
||||
static void test_chunk_reserve_full() {
|
||||
ChunkMemory mem = {};
|
||||
chunk_alloc(&mem, 10, 10);
|
||||
|
||||
ASSERT_EQUALS(chunk_reserve(&mem, 1), -1);
|
||||
}
|
||||
|
||||
static void test_chunk_reserve_invalid_size() {
|
||||
ChunkMemory mem = {};
|
||||
chunk_alloc(&mem, 10, 10);
|
||||
|
||||
ASSERT_EQUALS(chunk_reserve(&mem, 11), -1);
|
||||
|
||||
chunk_free(&mem);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef UBER_TEST
|
||||
#ifdef main
|
||||
#undef main
|
||||
#endif
|
||||
#define main MemoryChunkMemoryTest
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
TEST_INIT(25);
|
||||
|
||||
RUN_TEST(test_chunk_alloc);
|
||||
RUN_TEST(test_chunk_id_from_memory);
|
||||
RUN_TEST(test_chunk_get_element);
|
||||
RUN_TEST(test_chunk_reserve);
|
||||
RUN_TEST(test_chunk_free_elements);
|
||||
RUN_TEST(test_chunk_reserve_wrapping);
|
||||
RUN_TEST(test_chunk_reserve_last_element);
|
||||
|
||||
#if !DEBUG
|
||||
RUN_TEST(test_chunk_reserve_full);
|
||||
RUN_TEST(test_chunk_reserve_invalid_size);
|
||||
#endif
|
||||
|
||||
TEST_FINALIZE();
|
||||
|
||||
return 0;
|
||||
}
|
||||
108
tests/memory/RingMemoryTest.cpp
Normal file
108
tests/memory/RingMemoryTest.cpp
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
#include "../TestFramework.h"
|
||||
#include "../../memory/RingMemory.h"
|
||||
|
||||
static void test_ring_alloc() {
|
||||
RingMemory mem = {};
|
||||
ring_alloc(&mem, 50);
|
||||
|
||||
ASSERT_TRUE(memcmp(mem.memory, mem.memory + 1, 49) == 0);
|
||||
ASSERT_EQUALS(mem.size, 50);
|
||||
|
||||
ring_free(&mem);
|
||||
ASSERT_EQUALS(mem.size, 0);
|
||||
ASSERT_EQUALS(mem.memory, NULL);
|
||||
}
|
||||
|
||||
static void test_ring_get_memory() {
|
||||
RingMemory mem = {};
|
||||
ring_alloc(&mem, 50);
|
||||
|
||||
ASSERT_EQUALS(ring_get_memory(&mem, 20), mem.memory);
|
||||
ASSERT_EQUALS(mem.head, mem.memory + 20);
|
||||
|
||||
ring_free(&mem);
|
||||
}
|
||||
|
||||
static void test_ring_calculate_position() {
|
||||
RingMemory mem = {};
|
||||
ring_alloc(&mem, 50);
|
||||
|
||||
ring_get_memory(&mem, 20);
|
||||
ASSERT_EQUALS(ring_calculate_position(&mem, 20), mem.memory + 20);
|
||||
|
||||
ring_free(&mem);
|
||||
}
|
||||
|
||||
static void test_ring_reset() {
|
||||
RingMemory mem = {};
|
||||
ring_alloc(&mem, 50);
|
||||
|
||||
ring_get_memory(&mem, 20);
|
||||
ASSERT_NOT_EQUALS(mem.head, mem.memory);
|
||||
|
||||
ring_reset(&mem);
|
||||
ASSERT_EQUALS(mem.head, mem.memory);
|
||||
|
||||
ring_free(&mem);
|
||||
}
|
||||
|
||||
static void test_ring_get_memory_nomove() {
|
||||
RingMemory mem = {};
|
||||
ring_alloc(&mem, 50);
|
||||
|
||||
ASSERT_EQUALS(ring_get_memory_nomove(&mem, 20), mem.memory);
|
||||
ASSERT_EQUALS(mem.head, mem.memory);
|
||||
|
||||
ring_free(&mem);
|
||||
}
|
||||
|
||||
static void test_ring_move_pointer() {
|
||||
RingMemory mem = {};
|
||||
ring_alloc(&mem, 50);
|
||||
|
||||
ring_move_pointer(&mem, &mem.head, 20);
|
||||
ASSERT_EQUALS(mem.head, mem.memory + 20);
|
||||
|
||||
ring_free(&mem);
|
||||
}
|
||||
|
||||
static void test_ring_commit_safe() {
|
||||
RingMemory mem = {};
|
||||
ring_alloc(&mem, 50);
|
||||
|
||||
ring_get_memory(&mem, 20, 1);
|
||||
|
||||
ASSERT_TRUE(ring_commit_safe(&mem, 20));
|
||||
|
||||
// False because of alignment
|
||||
ASSERT_FALSE(ring_commit_safe(&mem, 30));
|
||||
|
||||
ASSERT_TRUE(ring_commit_safe(&mem, 30, 1));
|
||||
ASSERT_FALSE(ring_commit_safe(&mem, 45));
|
||||
ASSERT_FALSE(ring_commit_safe(&mem, 101));
|
||||
|
||||
ring_free(&mem);
|
||||
}
|
||||
|
||||
#ifdef UBER_TEST
|
||||
#ifdef main
|
||||
#undef main
|
||||
#endif
|
||||
#define main MemoryRingMemoryTest
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
TEST_INIT(25);
|
||||
|
||||
RUN_TEST(test_ring_alloc);
|
||||
RUN_TEST(test_ring_get_memory);
|
||||
RUN_TEST(test_ring_calculate_position);
|
||||
RUN_TEST(test_ring_reset);
|
||||
RUN_TEST(test_ring_get_memory_nomove);
|
||||
RUN_TEST(test_ring_move_pointer);
|
||||
RUN_TEST(test_ring_commit_safe);
|
||||
|
||||
TEST_FINALIZE();
|
||||
|
||||
return 0;
|
||||
}
|
||||
59
tests/stdlib/HashMapTest.cpp
Normal file
59
tests/stdlib/HashMapTest.cpp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#include "../TestFramework.h"
|
||||
#include "../../stdlib/HashMap.h"
|
||||
|
||||
static void test_hash_alloc() {
|
||||
HashMap hm = {};
|
||||
hashmap_alloc(&hm, 3, sizeof(HashEntryInt32));
|
||||
|
||||
ASSERT_NOT_EQUALS(hm.table, NULL);
|
||||
ASSERT_TRUE(hm.buf.count > 0);
|
||||
|
||||
hashmap_free(&hm);
|
||||
ASSERT_EQUALS(hm.buf.size, 0);
|
||||
ASSERT_EQUALS(hm.buf.memory, NULL);
|
||||
}
|
||||
|
||||
static void test_hash_insert_int32() {
|
||||
HashMap hm = {};
|
||||
hashmap_alloc(&hm, 3, sizeof(HashEntryInt32));
|
||||
|
||||
HashEntryInt32* entry;
|
||||
|
||||
hashmap_insert(&hm, "test1", 1);
|
||||
entry = (HashEntryInt32 *) hashmap_get_entry(&hm, "test1");
|
||||
ASSERT_NOT_EQUALS(entry, NULL);
|
||||
ASSERT_EQUALS(entry->value, 1);
|
||||
|
||||
hashmap_insert(&hm, "test2", 2);
|
||||
entry = (HashEntryInt32 *) hashmap_get_entry(&hm, "test2");
|
||||
ASSERT_NOT_EQUALS(entry, NULL);
|
||||
ASSERT_EQUALS(entry->value, 2);
|
||||
|
||||
hashmap_insert(&hm, "test3", 3);
|
||||
entry = (HashEntryInt32 *) hashmap_get_entry(&hm, "test3");
|
||||
ASSERT_NOT_EQUALS(entry, NULL);
|
||||
ASSERT_EQUALS(entry->value, 3);
|
||||
|
||||
entry = (HashEntryInt32 *) hashmap_get_entry(&hm, "invalid");
|
||||
ASSERT_EQUALS(entry, NULL);
|
||||
|
||||
hashmap_free(&hm);
|
||||
}
|
||||
|
||||
#ifdef UBER_TEST
|
||||
#ifdef main
|
||||
#undef main
|
||||
#endif
|
||||
#define main StdlibHashMapTest
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
TEST_INIT(25);
|
||||
|
||||
RUN_TEST(test_hash_alloc);
|
||||
RUN_TEST(test_hash_insert_int32);
|
||||
|
||||
TEST_FINALIZE();
|
||||
|
||||
return 0;
|
||||
}
|
||||
80
tests/ui/UILayoutTest.cpp
Normal file
80
tests/ui/UILayoutTest.cpp
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
#include "../TestFramework.h"
|
||||
#include "../../ui/UILayout.h"
|
||||
#include "../../ui/UILayout.cpp"
|
||||
#include "../../system/Allocator.h"
|
||||
|
||||
static void test_layout_from_file_txt() {
|
||||
RingMemory ui_layout_ring;
|
||||
ring_alloc(&ui_layout_ring, 10 * MEGABYTE, 64);
|
||||
|
||||
UILayout layout;
|
||||
layout.data = (byte *) platform_alloc(2 * MEGABYTE);
|
||||
|
||||
layout_from_file_txt(&layout, "./../../GameEditor/assets/themes/default/scene1.layouttxt", &ui_layout_ring);
|
||||
|
||||
UIElement* element = layout_get_element(&layout, "cmd_window");
|
||||
ASSERT_NOT_EQUALS(element, NULL);
|
||||
|
||||
platform_free((void **) &layout.data);
|
||||
ring_free(&ui_layout_ring);
|
||||
}
|
||||
|
||||
static void test_layout_to_data() {
|
||||
}
|
||||
|
||||
static void test_layout_from_data() {
|
||||
}
|
||||
|
||||
static void test_layout_from_theme() {
|
||||
RingMemory ui_layout_ring;
|
||||
ring_alloc(&ui_layout_ring, 10 * MEGABYTE, 64);
|
||||
|
||||
UILayout layout;
|
||||
layout.data = (byte *) platform_alloc(10 * MEGABYTE);
|
||||
layout_from_file_txt(&layout, "./../../GameEditor/assets/themes/default/scene1.layouttxt", &ui_layout_ring);
|
||||
|
||||
UIThemeStyle theme1;
|
||||
theme1.data = (byte *) platform_alloc(2 * MEGABYTE);
|
||||
theme_from_file_txt(&theme1, "./../../GameEditor/assets/themes/default/general.themetxt", &ui_layout_ring);
|
||||
|
||||
UIThemeStyle theme2;
|
||||
theme2.data = (byte *) platform_alloc(2 * MEGABYTE);
|
||||
theme_from_file_txt(&theme2, "./../../GameEditor/assets/themes/default/scene1.themetxt", &ui_layout_ring);
|
||||
|
||||
Camera camera = {};
|
||||
camera.viewport_width = 1024;
|
||||
camera.viewport_height = 768;
|
||||
layout_from_theme(&layout, &theme1, &camera);
|
||||
layout_from_theme(&layout, &theme2, &camera);
|
||||
|
||||
UIElement* element = layout_get_element(&layout, "cmd_window");
|
||||
ASSERT_NOT_EQUALS(element, NULL);
|
||||
ASSERT_TRUE(element->state > 0);
|
||||
ASSERT_TRUE(element->children_count > 0);
|
||||
ASSERT_EQUALS(element->type, UI_ELEMENT_TYPE_VIEW_WINDOW);
|
||||
|
||||
platform_free((void **) &layout.data);
|
||||
platform_free((void **) &theme1.data);
|
||||
platform_free((void **) &theme2.data);
|
||||
ring_free(&ui_layout_ring);
|
||||
}
|
||||
|
||||
#ifdef UBER_TEST
|
||||
#ifdef main
|
||||
#undef main
|
||||
#endif
|
||||
#define main UIUILayoutTest
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
TEST_INIT(10);
|
||||
|
||||
RUN_TEST(test_layout_from_file_txt);
|
||||
RUN_TEST(test_layout_to_data);
|
||||
RUN_TEST(test_layout_from_data);
|
||||
RUN_TEST(test_layout_from_theme);
|
||||
|
||||
TEST_FINALIZE();
|
||||
|
||||
return 0;
|
||||
}
|
||||
49
tests/ui/UIThemeTest.cpp
Normal file
49
tests/ui/UIThemeTest.cpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
#include "../TestFramework.h"
|
||||
#include "../../ui/UITheme.h"
|
||||
#include "../../system/Allocator.h"
|
||||
|
||||
static void test_theme_from_file_txt() {
|
||||
RingMemory ui_theme_ring;
|
||||
ring_alloc(&ui_theme_ring, 10 * MEGABYTE, 64);
|
||||
|
||||
UIThemeStyle theme;
|
||||
theme.data = (byte *) platform_alloc(2 * MEGABYTE);
|
||||
|
||||
theme_from_file_txt(&theme, "./../../GameEditor/assets/themes/default/scene1.themetxt", &ui_theme_ring);
|
||||
|
||||
UIAttributeGroup* group = theme_style_group(&theme, "#cmd_window");
|
||||
ASSERT_NOT_EQUALS(group, NULL);
|
||||
ASSERT_TRUE(group->attribute_count > 0);
|
||||
|
||||
UIAttribute* attr = ui_attribute_from_group(group, UI_ATTRIBUTE_TYPE_POSITION_X);
|
||||
ASSERT_NOT_EQUALS(attr, NULL);
|
||||
ASSERT_EQUALS(attr->datatype, UI_ATTRIBUTE_DATA_TYPE_F32);
|
||||
ASSERT_EQUALS_WITH_DELTA(attr->value_float, 0.0f, 0.001f);
|
||||
|
||||
ring_free(&ui_theme_ring);
|
||||
}
|
||||
|
||||
static void test_theme_to_data() {
|
||||
}
|
||||
|
||||
static void test_theme_from_data() {
|
||||
}
|
||||
|
||||
#ifdef UBER_TEST
|
||||
#ifdef main
|
||||
#undef main
|
||||
#endif
|
||||
#define main UIUIThemeTest
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
TEST_INIT(10);
|
||||
|
||||
RUN_TEST(test_theme_from_file_txt);
|
||||
RUN_TEST(test_theme_to_data);
|
||||
RUN_TEST(test_theme_from_data);
|
||||
|
||||
TEST_FINALIZE();
|
||||
|
||||
return 0;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user