tweak byteio & ase to avoid unaligned access

This commit is contained in:
jacob 2024-04-01 15:10:34 -05:00
parent 900e841228
commit ecbc0c8501
9 changed files with 91 additions and 57 deletions

View File

@ -9,7 +9,6 @@
#include "scratch.h" #include "scratch.h"
#include "byteio.h" #include "byteio.h"
#include "string.h" #include "string.h"
#include "log.h"
/* ========================== * /* ========================== *
* Bitbuf * Bitbuf
@ -26,8 +25,10 @@ INTERNAL u32 peek_bits(struct bitbuf *bb, u32 nbits)
u64 cur_byte = bb->cur_bit >> 3; u64 cur_byte = bb->cur_bit >> 3;
u8 bit_index = bb->cur_bit % 8; 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); u32 val32 = (u32)(val64 >> bit_index);
val32 &= U32_MAX >> (32 - nbits); 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 #define LAYER_FLAG_NONE 0x0
@ -441,6 +442,21 @@ struct frame_header {
u32 chunks_new; u32 chunks_new;
} PACKED; } 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 * 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); br_read_to_struct(&br, &ase_header);
if (ase_header.magic != 0xA5E0) { if (ase_header.magic != 0xA5E0) {
res.valid = false; push_error_copy_msg(arena, &res.errors, STR("Not a valid aseprite file"));
res.error_msg = STR("Not a valid aseprite file");
goto abort; goto abort;
} }
if (ase_header.color_depth != 32) { if (ase_header.color_depth != 32) {
res.valid = false; struct string msg = string_format(scratch.arena,
res.error_msg = string_format(arena, STR("Only 32 bit rgba color mode is supported (got %F)"),
STR("Only 32 bit rgba color mode is supported (got %F)"), FMT_UINT(ase_header.color_depth));
FMT_UINT(ase_header.color_depth)); push_error_copy_msg(arena, &res.errors, msg);
goto abort; 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); layer->blend_mode = br_read_u16(&br);
if (layer->blend_mode != 0) { if (layer->blend_mode != 0) {
res.valid = false; push_error_copy_msg(arena,
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"); &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; goto abort;
} }
@ -685,8 +701,7 @@ struct ase_decode_image_result ase_decode_image(struct arena *arena, struct buff
case CEL_TYPE_COMPRESSED_TILEMAP: { case CEL_TYPE_COMPRESSED_TILEMAP: {
/* Unsupported */ /* Unsupported */
res.valid = false; push_error_copy_msg(arena, &res.errors, STR("Tilemaps are not supported"));
res.error_msg = STR("Tilemaps are not supported");
goto abort; goto abort;
} break; } break;
} }
@ -781,10 +796,9 @@ struct ase_decode_image_result ase_decode_image(struct arena *arena, struct buff
} }
} }
/* ASSERT all data was read */ /* ASSERT all data was read */
ASSERT(br_bytes_left(&br) == 0); ASSERT(br_bytes_left(&br) == 0);
res.valid = true;
abort: abort:
scratch_end(scratch); 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 all data was read */
ASSERT(br_bytes_left(&br) == 0); ASSERT(br_bytes_left(&br) == 0);
res.valid = true;
scratch_end(scratch); scratch_end(scratch);

View File

@ -1,6 +1,17 @@
#ifndef ASE_H #ifndef ASE_H
#define 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 ase_tag {
struct string name; struct string name;
u32 start; u32 start;
@ -17,8 +28,7 @@ struct ase_frame {
struct ase_decode_image_result { struct ase_decode_image_result {
struct image_rgba image; struct image_rgba image;
b32 valid; struct ase_error_list errors;
struct string error_msg;
}; };
struct ase_decode_sheet_result { struct ase_decode_sheet_result {
@ -28,8 +38,7 @@ struct ase_decode_sheet_result {
u32 num_tags; u32 num_tags;
struct ase_frame *frame_head; struct ase_frame *frame_head;
struct ase_tag *tag_head; struct ase_tag *tag_head;
b32 valid; struct ase_error_list errors;
struct string error_msg;
}; };
struct ase_decode_image_result ase_decode_image(struct arena *arena, struct buffer encoded); struct ase_decode_image_result ase_decode_image(struct arena *arena, struct buffer encoded);

View File

@ -145,7 +145,9 @@ u8 br_read_u8(struct byte_reader *br)
if (br_overflow_check(br, sizeof(u8))) { if (br_overflow_check(br, sizeof(u8))) {
return 0; 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) 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))) { if (br_overflow_check(br, sizeof(u16))) {
return 0; 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) 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))) { if (br_overflow_check(br, sizeof(u32))) {
return 0; 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) 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))) { if (br_overflow_check(br, sizeof(u64))) {
return 0; 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) 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))) { if (br_overflow_check(br, sizeof(i8))) {
return 0; 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) 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))) { if (br_overflow_check(br, sizeof(i16))) {
return 0; 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) 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))) { if (br_overflow_check(br, sizeof(i32))) {
return 0; 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) 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))) { if (br_overflow_check(br, sizeof(i64))) {
return 0; 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) u64 br_read_var_uint(struct byte_reader *br)

View File

@ -404,6 +404,8 @@ struct buffer {
((struct string) { .len = ARRAY_COUNT(a), .text = (u8 *)(a) }) \ ((struct string) { .len = ARRAY_COUNT(a), .text = (u8 *)(a) }) \
) )
#define STRING_FROM_BUFFER(buff) ((struct string) { buff.size, buff.data})
/* ========================== * /* ========================== *
* Math types * Math types
* ========================== */ * ========================== */
@ -483,7 +485,8 @@ struct trs {
* Common utilities * 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 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 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; } 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 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 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 u32 clamp_u32(u32 v, u32 min, u32 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 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 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 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) INLINE u64 cstr_len(char *cstr)
{ {

View File

@ -3,12 +3,6 @@
#include "string.h" #include "string.h"
#include "atomic.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 { struct log_event_callback {
log_event_callback_func *func; log_event_callback_func *func;
i32 level; i32 level;
@ -20,10 +14,7 @@ struct log_event_callback {
* ========================== */ * ========================== */
GLOBAL struct { GLOBAL struct {
#if RTC
struct atomic_i32 initialized; struct atomic_i32 initialized;
#endif
struct sys_mutex mutex; struct sys_mutex mutex;
struct arena arena; struct arena arena;
log_event_callback_func *callbacks_head; log_event_callback_func *callbacks_head;
@ -75,11 +66,7 @@ struct log_startup_receipt log_startup(struct string logfile_path)
L.file_valid = true; L.file_valid = true;
} }
} }
#if RTC
atomic_i32_eval_exchange(&L.initialized, 1); atomic_i32_eval_exchange(&L.initialized, 1);
#endif
return (struct log_startup_receipt) { 0 }; 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) void log_register_callback(log_event_callback_func *func)
{ {
ASSERT_INITIALIZED; if (!atomic_i32_eval(&L.initialized)) { return; }
sys_mutex_lock(&L.mutex); sys_mutex_lock(&L.mutex);
{ {
/* TODO */ /* TODO */
@ -105,7 +92,7 @@ void log_register_callback(log_event_callback_func *func)
INTERNAL void append_to_logfile(struct string msg) INTERNAL void append_to_logfile(struct string msg)
{ {
__prof; __prof;
ASSERT_INITIALIZED; if (!atomic_i32_eval(&L.initialized)) { return; }
if (L.file_valid) { if (L.file_valid) {
struct temp_arena scratch = scratch_begin_no_conflict(); struct temp_arena scratch = scratch_begin_no_conflict();
@ -122,7 +109,7 @@ void _log(i32 level, struct string msg)
#endif #endif
{ {
__prof; __prof;
ASSERT_INITIALIZED; if (!atomic_i32_eval(&L.initialized)) { return; }
if (level < 0 || level >= LOG_LEVEL_COUNT) { if (level < 0 || level >= LOG_LEVEL_COUNT) {
sys_panic_raw("Invalid log level"); 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) void _logfv(i32 level, struct string fmt, va_list args)
#endif #endif
{ {
ASSERT_INITIALIZED; if (!atomic_i32_eval(&L.initialized)) { return; }
struct temp_arena scratch = scratch_begin_no_conflict(); struct temp_arena scratch = scratch_begin_no_conflict();
struct string msg = string_formatv(scratch.arena, fmt, args); struct string msg = string_formatv(scratch.arena, fmt, args);
#if LOG_INCLUDE_SOURCE_LOCATION #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, ...) void _logf(i32 level, struct string fmt, ...)
#endif #endif
{ {
ASSERT_INITIALIZED; if (!atomic_i32_eval(&L.initialized)) { return; }
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
#if LOG_INCLUDE_SOURCE_LOCATION #if LOG_INCLUDE_SOURCE_LOCATION

View File

@ -13,7 +13,7 @@ void *memcpy(void *restrict dest, const void *restrict src, u64 n)
} }
__attribute((section(".text.memset"))) __attribute((section(".text.memset")))
void *memset(void *dest, int c, u64 n) void *memset(void *dest, i32 c, u64 n)
{ {
/* TODO: Faster memset */ /* TODO: Faster memset */
for (u64 i = 0; i < (n); ++i) { for (u64 i = 0; i < (n); ++i) {

View File

@ -15,7 +15,7 @@
# include <memory.h> # include <memory.h>
#else #else
void *memcpy(void *__restrict dest, const void *__restrict src, u64 n); 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
#endif #endif

View File

@ -165,9 +165,11 @@ INTERNAL WORK_TASK_FUNC_DEF(sheet_load_asset_task, vparams)
resource_close(sheet_rs); resource_close(sheet_rs);
/* Failure paths */ /* Failure paths */
if (!decoded.valid) { if (decoded.errors.count > 0) {
if (decoded.error_msg.len > 0) { /* FIXME: Read all errors from decode */
error_msg = decoded.error_msg; struct string msg = decoded.errors.first->msg;
if (msg.len > 0) {
error_msg = msg;
} }
goto abort; goto abort;
} else { } else {

View File

@ -152,9 +152,11 @@ INTERNAL WORK_TASK_FUNC_DEF(texture_load_asset_task, vparams)
resource_close(texture_rs); resource_close(texture_rs);
/* Failure paths */ /* Failure paths */
if (!decoded.valid) { if (decoded.errors.count > 0) {
if (decoded.error_msg.len > 0) { /* FIXME: Read all errors from decode */
error_msg = decoded.error_msg; struct string msg = decoded.errors.first->msg;
if (msg.len > 0) {
error_msg = msg;
} }
goto abort; goto abort;
} else if (decoded.image.width > RENDERER_TEXTURE_MAX_WIDTH || decoded.image.height > RENDERER_TEXTURE_MAX_HEIGHT) { } else if (decoded.image.width > RENDERER_TEXTURE_MAX_WIDTH || decoded.image.height > RENDERER_TEXTURE_MAX_HEIGHT) {