working again, ui layout not yet fully implemented. test framework functional.

This commit is contained in:
Dennis Eichhorn 2025-02-09 19:01:41 +01:00
parent fd47385162
commit a8191a239a
126 changed files with 4670 additions and 1158 deletions

5
.gitignore vendored
View File

@ -4,4 +4,7 @@ bin/*
*.obj
*.log
*.spv
*.res
*.res
*.exe
*.map
*.pdb

View File

@ -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

View 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

View 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

View File

@ -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

View File

@ -12,7 +12,7 @@
#include <immintrin.h>
#include <xmmintrin.h>
#include "../Types.h"
#include "../../../stdlib/Types.h"
#include "SIMD_SVML.h"
struct f32_4 {

View File

@ -12,7 +12,7 @@
#include <immintrin.h>
#include <xmmintrin.h>
#include "../Types.h"
#include "../../../stdlib/Types.h"
struct f64_2 {
union {

View File

@ -12,7 +12,7 @@
#include <immintrin.h>
#include <xmmintrin.h>
#include "../Types.h"
#include "../../../stdlib/Types.h"
struct int16_8 {
union {

View File

@ -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

View File

@ -12,7 +12,7 @@
#include <immintrin.h>
#include <xmmintrin.h>
#include "../Types.h"
#include "../../../stdlib/Types.h"
#include "SIMD_F64.h"
struct int64_2 {

View File

@ -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) {

View File

@ -12,6 +12,8 @@
#include <immintrin.h>
#include <xmmintrin.h>
#include "../../../stdlib/Types.h"
#if __linux__
#include "math.h"

View 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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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) {

View File

@ -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);

View File

@ -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;
}

View File

@ -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();
}
}
}

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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;
}

View File

@ -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;
}
/**

View File

@ -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;

View File

@ -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
);
}

View File

@ -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;
}

View File

@ -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,

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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")) {

View File

@ -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;

View File

@ -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 {

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -9,7 +9,6 @@
#ifndef TOS_LOG_H
#define TOS_LOG_H
#include <stdio.h>
#include "../stdlib/Types.h"
#include "Debug.h"

View File

@ -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"

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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) {

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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");

View File

@ -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++;
}
}

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -11,7 +11,6 @@
#include "../../stdlib/Types.h"
#include "../../utils/StringUtils.h"
#include <stdio.h>
#include <windows.h>
#include <string.h>

View File

@ -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

View File

@ -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;

View File

@ -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");

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View File

@ -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);

View File

@ -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

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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 *)&para); \
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 *)&para); \
\
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

View 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;
}

View 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;
}

View 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;
}

View 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
View 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
View 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