From ecbc0c850177a0a65abd3174010b0d3c4e0805a2 Mon Sep 17 00:00:00 2001 From: jacob Date: Mon, 1 Apr 2024 15:10:34 -0500 Subject: [PATCH] tweak byteio & ase to avoid unaligned access --- src/ase.c | 45 +++++++++++++++++++++++++++++---------------- src/ase.h | 17 +++++++++++++---- src/byteio.c | 32 ++++++++++++++++++++++++-------- src/common.h | 11 ++++++++--- src/log.c | 23 +++++------------------ src/memory.c | 2 +- src/memory.h | 2 +- src/sheet.c | 8 +++++--- src/texture.c | 8 +++++--- 9 files changed, 91 insertions(+), 57 deletions(-) diff --git a/src/ase.c b/src/ase.c index f87984e9..0ff70920 100644 --- a/src/ase.c +++ b/src/ase.c @@ -9,7 +9,6 @@ #include "scratch.h" #include "byteio.h" #include "string.h" -#include "log.h" /* ========================== * * Bitbuf @@ -26,8 +25,10 @@ INTERNAL u32 peek_bits(struct bitbuf *bb, u32 nbits) u64 cur_byte = bb->cur_bit >> 3; u8 bit_index = bb->cur_bit % 8; + u64 nbytes = (nbits + bit_index + 7) >> 3; - u64 val64 = *(u64 *)&bb->data[cur_byte]; + u64 val64 = 0; + MEMCPY(&val64, &bb->data[cur_byte], nbytes); u32 val32 = (u32)(val64 >> bit_index); val32 &= U32_MAX >> (32 - nbits); @@ -379,7 +380,7 @@ INTERNAL void inflate(struct arena *arena, u8 *dest, u8 *encoded) } /* ========================== * - * Decode image + * Decoder structs * ========================== */ #define LAYER_FLAG_NONE 0x0 @@ -441,6 +442,21 @@ struct frame_header { u32 chunks_new; } PACKED; +INTERNAL void push_error_copy_msg(struct arena *arena, struct ase_error_list *list, struct string msg_src) +{ + struct ase_error *e = arena_push(arena, struct ase_error); + *e = (struct ase_error) { + .msg = string_copy(arena, msg_src) + }; + if (!list->first) { + list->first = e; + } else { + list->last->next = e; + } + list->last = e; + ++list->count; +} + /* ========================== * * Image decoder * ========================== */ @@ -544,16 +560,15 @@ struct ase_decode_image_result ase_decode_image(struct arena *arena, struct buff br_read_to_struct(&br, &ase_header); if (ase_header.magic != 0xA5E0) { - res.valid = false; - res.error_msg = STR("Not a valid aseprite file"); + push_error_copy_msg(arena, &res.errors, STR("Not a valid aseprite file")); goto abort; } if (ase_header.color_depth != 32) { - res.valid = false; - res.error_msg = string_format(arena, - STR("Only 32 bit rgba color mode is supported (got %F)"), - FMT_UINT(ase_header.color_depth)); + struct string msg = string_format(scratch.arena, + STR("Only 32 bit rgba color mode is supported (got %F)"), + FMT_UINT(ase_header.color_depth)); + push_error_copy_msg(arena, &res.errors, msg); goto abort; } @@ -615,8 +630,9 @@ struct ase_decode_image_result ase_decode_image(struct arena *arena, struct buff layer->blend_mode = br_read_u16(&br); if (layer->blend_mode != 0) { - res.valid = false; - res.error_msg = STR("Layer has unsupported blend mode (only 'Normal' mode is supported). Tip: Try using 'merge down' to create a normal layer as a workaround"); + push_error_copy_msg(arena, + &res.errors, + STR("Layer has unsupported blend mode (only 'Normal' mode is supported). Tip: Try using 'merge down' to create a normal layer as a workaround")); goto abort; } @@ -685,8 +701,7 @@ struct ase_decode_image_result ase_decode_image(struct arena *arena, struct buff case CEL_TYPE_COMPRESSED_TILEMAP: { /* Unsupported */ - res.valid = false; - res.error_msg = STR("Tilemaps are not supported"); + push_error_copy_msg(arena, &res.errors, STR("Tilemaps are not supported")); goto abort; } break; } @@ -781,10 +796,9 @@ struct ase_decode_image_result ase_decode_image(struct arena *arena, struct buff } } - /* ASSERT all data was read */ ASSERT(br_bytes_left(&br) == 0); - res.valid = true; + abort: scratch_end(scratch); @@ -904,7 +918,6 @@ struct ase_decode_sheet_result ase_decode_sheet(struct arena *arena, struct buff /* ASSERT all data was read */ ASSERT(br_bytes_left(&br) == 0); - res.valid = true; scratch_end(scratch); diff --git a/src/ase.h b/src/ase.h index a59e59e8..cd013920 100644 --- a/src/ase.h +++ b/src/ase.h @@ -1,6 +1,17 @@ #ifndef ASE_H #define ASE_H +struct ase_error { + struct string msg; + struct ase_error *next; +}; + +struct ase_error_list { + u64 count; + struct ase_error *first; + struct ase_error *last; +}; + struct ase_tag { struct string name; u32 start; @@ -17,8 +28,7 @@ struct ase_frame { struct ase_decode_image_result { struct image_rgba image; - b32 valid; - struct string error_msg; + struct ase_error_list errors; }; struct ase_decode_sheet_result { @@ -28,8 +38,7 @@ struct ase_decode_sheet_result { u32 num_tags; struct ase_frame *frame_head; struct ase_tag *tag_head; - b32 valid; - struct string error_msg; + struct ase_error_list errors; }; struct ase_decode_image_result ase_decode_image(struct arena *arena, struct buffer encoded); diff --git a/src/byteio.c b/src/byteio.c index 0ceb9932..6cd2fcd2 100644 --- a/src/byteio.c +++ b/src/byteio.c @@ -145,7 +145,9 @@ u8 br_read_u8(struct byte_reader *br) if (br_overflow_check(br, sizeof(u8))) { return 0; } - return *(u8 *)read_unsafe(br, sizeof(u8)); + u8 res = 0; + MEMCPY(&res, read_unsafe(br, sizeof(u8)), sizeof(u8)); + return res; } u16 br_read_u16(struct byte_reader *br) @@ -153,7 +155,9 @@ u16 br_read_u16(struct byte_reader *br) if (br_overflow_check(br, sizeof(u16))) { return 0; } - return *(u16 *)read_unsafe(br, sizeof(u16)); + u16 res = 0; + MEMCPY(&res, read_unsafe(br, sizeof(u16)), sizeof(u16)); + return res; } u32 br_read_u32(struct byte_reader *br) @@ -161,7 +165,9 @@ u32 br_read_u32(struct byte_reader *br) if (br_overflow_check(br, sizeof(u32))) { return 0; } - return *(u32 *)read_unsafe(br, sizeof(u32)); + u32 res = 0; + MEMCPY(&res, read_unsafe(br, sizeof(u32)), sizeof(u32)); + return res; } u64 br_read_u64(struct byte_reader *br) @@ -169,7 +175,9 @@ u64 br_read_u64(struct byte_reader *br) if (br_overflow_check(br, sizeof(u64))) { return 0; } - return *(u64 *)read_unsafe(br, sizeof(u64)); + u64 res = 0; + MEMCPY(&res, read_unsafe(br, sizeof(u64)), sizeof(u64)); + return res; } i8 br_read_i8(struct byte_reader *br) @@ -177,7 +185,9 @@ i8 br_read_i8(struct byte_reader *br) if (br_overflow_check(br, sizeof(i8))) { return 0; } - return *(i8 *)read_unsafe(br, sizeof(i8)); + i8 res = 0; + MEMCPY(&res, read_unsafe(br, sizeof(i8)), sizeof(i8)); + return res; } i16 br_read_i16(struct byte_reader *br) @@ -185,7 +195,9 @@ i16 br_read_i16(struct byte_reader *br) if (br_overflow_check(br, sizeof(i16))) { return 0; } - return *(i16 *)read_unsafe(br, sizeof(i16)); + i16 res = 0; + MEMCPY(&res, read_unsafe(br, sizeof(i16)), sizeof(i16)); + return res; } i32 br_read_i32(struct byte_reader *br) @@ -193,7 +205,9 @@ i32 br_read_i32(struct byte_reader *br) if (br_overflow_check(br, sizeof(i32))) { return 0; } - return *(i32 *)read_unsafe(br, sizeof(i32)); + i32 res = 0; + MEMCPY(&res, read_unsafe(br, sizeof(i32)), sizeof(i32)); + return res; } i64 br_read_i64(struct byte_reader *br) @@ -201,7 +215,9 @@ i64 br_read_i64(struct byte_reader *br) if (br_overflow_check(br, sizeof(i64))) { return 0; } - return *(i64 *)read_unsafe(br, sizeof(i64)); + i64 res = 0; + MEMCPY(&res, read_unsafe(br, sizeof(i64)), sizeof(i64)); + return res; } u64 br_read_var_uint(struct byte_reader *br) diff --git a/src/common.h b/src/common.h index 2953a42b..c3911b8f 100644 --- a/src/common.h +++ b/src/common.h @@ -404,6 +404,8 @@ struct buffer { ((struct string) { .len = ARRAY_COUNT(a), .text = (u8 *)(a) }) \ ) +#define STRING_FROM_BUFFER(buff) ((struct string) { buff.size, buff.data}) + /* ========================== * * Math types * ========================== */ @@ -483,7 +485,8 @@ struct trs { * Common utilities * ========================== */ - +INLINE u8 min_u8(u8 a, u8 b) { return a <= b ? a : b; } +INLINE u8 max_u8(u8 a, u8 b) { return a >= b ? a : b; } INLINE u32 min_u32(u32 a, u32 b) { return a <= b ? a : b; } INLINE u32 max_u32(u32 a, u32 b) { return a >= b ? a : b; } INLINE u64 min_u64(u64 a, u64 b) { return a <= b ? a : b; } @@ -497,10 +500,12 @@ INLINE f32 max_f32(f32 a, f32 b) { return a >= b ? a : b; } INLINE f64 min_f64(f64 a, f64 b) { return a <= b ? a : b; } INLINE f64 max_f64(f64 a, f64 b) { return a >= b ? a : b; } -INLINE f32 clamp_f32(f32 v, f32 min, f32 max) { return v < min ? min : v > max ? max : v; } -INLINE f64 clamp_f64(f64 v, f64 min, f64 max) { return v < min ? min : v > max ? max : v; } +INLINE u32 clamp_u32(u32 v, u32 min, u32 max) { return v < min ? min : v > max ? max : v; } +INLINE u64 clamp_u64(u64 v, u64 min, u64 max) { return v < min ? min : v > max ? max : v; } INLINE i32 clamp_i32(i32 v, i32 min, i32 max) { return v < min ? min : v > max ? max : v; } INLINE i64 clamp_i64(i64 v, i64 min, i64 max) { return v < min ? min : v > max ? max : v; } +INLINE f32 clamp_f32(f32 v, f32 min, f32 max) { return v < min ? min : v > max ? max : v; } +INLINE f64 clamp_f64(f64 v, f64 min, f64 max) { return v < min ? min : v > max ? max : v; } INLINE u64 cstr_len(char *cstr) { diff --git a/src/log.c b/src/log.c index 1a50ef4a..9d60e698 100644 --- a/src/log.c +++ b/src/log.c @@ -3,12 +3,6 @@ #include "string.h" #include "atomic.h" -#if RTC -# define ASSERT_INITIALIZED ASSERT(atomic_i32_eval(&L.initialized) == 1) -#else -# define ASSERT_INITIALIZED -#endif - struct log_event_callback { log_event_callback_func *func; i32 level; @@ -20,10 +14,7 @@ struct log_event_callback { * ========================== */ GLOBAL struct { -#if RTC struct atomic_i32 initialized; -#endif - struct sys_mutex mutex; struct arena arena; log_event_callback_func *callbacks_head; @@ -75,11 +66,7 @@ struct log_startup_receipt log_startup(struct string logfile_path) L.file_valid = true; } } - -#if RTC atomic_i32_eval_exchange(&L.initialized, 1); -#endif - return (struct log_startup_receipt) { 0 }; } @@ -89,7 +76,7 @@ struct log_startup_receipt log_startup(struct string logfile_path) void log_register_callback(log_event_callback_func *func) { - ASSERT_INITIALIZED; + if (!atomic_i32_eval(&L.initialized)) { return; } sys_mutex_lock(&L.mutex); { /* TODO */ @@ -105,7 +92,7 @@ void log_register_callback(log_event_callback_func *func) INTERNAL void append_to_logfile(struct string msg) { __prof; - ASSERT_INITIALIZED; + if (!atomic_i32_eval(&L.initialized)) { return; } if (L.file_valid) { struct temp_arena scratch = scratch_begin_no_conflict(); @@ -122,7 +109,7 @@ void _log(i32 level, struct string msg) #endif { __prof; - ASSERT_INITIALIZED; + if (!atomic_i32_eval(&L.initialized)) { return; } if (level < 0 || level >= LOG_LEVEL_COUNT) { sys_panic_raw("Invalid log level"); @@ -192,7 +179,7 @@ void _logfv(i32 level, struct string file, u32 line, struct string fmt, va_list void _logfv(i32 level, struct string fmt, va_list args) #endif { - ASSERT_INITIALIZED; + if (!atomic_i32_eval(&L.initialized)) { return; } struct temp_arena scratch = scratch_begin_no_conflict(); struct string msg = string_formatv(scratch.arena, fmt, args); #if LOG_INCLUDE_SOURCE_LOCATION @@ -209,7 +196,7 @@ void _logf(i32 level, struct string file, u32 line, struct string fmt, ...) void _logf(i32 level, struct string fmt, ...) #endif { - ASSERT_INITIALIZED; + if (!atomic_i32_eval(&L.initialized)) { return; } va_list args; va_start(args, fmt); #if LOG_INCLUDE_SOURCE_LOCATION diff --git a/src/memory.c b/src/memory.c index 73e7bc0e..b21c294b 100644 --- a/src/memory.c +++ b/src/memory.c @@ -13,7 +13,7 @@ void *memcpy(void *restrict dest, const void *restrict src, u64 n) } __attribute((section(".text.memset"))) -void *memset(void *dest, int c, u64 n) +void *memset(void *dest, i32 c, u64 n) { /* TODO: Faster memset */ for (u64 i = 0; i < (n); ++i) { diff --git a/src/memory.h b/src/memory.h index 16b09c1b..ac2eed19 100644 --- a/src/memory.h +++ b/src/memory.h @@ -15,7 +15,7 @@ # include #else void *memcpy(void *__restrict dest, const void *__restrict src, u64 n); -void *memset(void *dest, int c, u64 n); +void *memset(void *dest, i32 c, u64 n); #endif #endif diff --git a/src/sheet.c b/src/sheet.c index 6b9b0c28..3603b4e3 100644 --- a/src/sheet.c +++ b/src/sheet.c @@ -165,9 +165,11 @@ INTERNAL WORK_TASK_FUNC_DEF(sheet_load_asset_task, vparams) resource_close(sheet_rs); /* Failure paths */ - if (!decoded.valid) { - if (decoded.error_msg.len > 0) { - error_msg = decoded.error_msg; + if (decoded.errors.count > 0) { + /* FIXME: Read all errors from decode */ + struct string msg = decoded.errors.first->msg; + if (msg.len > 0) { + error_msg = msg; } goto abort; } else { diff --git a/src/texture.c b/src/texture.c index 71342ce9..3d004504 100644 --- a/src/texture.c +++ b/src/texture.c @@ -152,9 +152,11 @@ INTERNAL WORK_TASK_FUNC_DEF(texture_load_asset_task, vparams) resource_close(texture_rs); /* Failure paths */ - if (!decoded.valid) { - if (decoded.error_msg.len > 0) { - error_msg = decoded.error_msg; + if (decoded.errors.count > 0) { + /* FIXME: Read all errors from decode */ + struct string msg = decoded.errors.first->msg; + if (msg.len > 0) { + error_msg = msg; } goto abort; } else if (decoded.image.width > RENDERER_TEXTURE_MAX_WIDTH || decoded.image.height > RENDERER_TEXTURE_MAX_HEIGHT) {