diff --git a/base/sources/backends/data/wasm/start.js b/base/sources/backends/data/wasm/start.js index 43b121b05..ea319a35e 100644 --- a/base/sources/backends/data/wasm/start.js +++ b/base/sources/backends/data/wasm/start.js @@ -180,17 +180,22 @@ function id_to_filter_mode(id) { return "linear"; } -async function init() { - let wasm_bytes = null; - await fetch("./start.wasm").then(res => res.arrayBuffer()).then(buffer => wasm_bytes = new Uint8Array(buffer)); - - memory = new WebAssembly.Memory({initial : 10240, maximum : 10240, shared : true}); // * 65536 = 671088640 (amake --initial-memory) +function update_heap_views() { heapu8 = new Uint8Array(memory.buffer); heapu16 = new Uint16Array(memory.buffer); heapu32 = new Uint32Array(memory.buffer); heapi32 = new Int32Array(memory.buffer); heapf32 = new Float32Array(memory.buffer); heapf64 = new Float64Array(memory.buffer); +} + +async function init() { + let wasm_bytes = null; + await fetch("./start.wasm").then(res => res.arrayBuffer()).then(buffer => wasm_bytes = new Uint8Array(buffer)); + + // * 65536 = amake --initial-memory=268435456, --max-memory=4294967296, malloc grows it + memory = new WebAssembly.Memory({initial : 4096, maximum : 65536, shared : true}); + update_heap_views(); if (!navigator.gpu) { throw new Error('WebGPU not supported'); @@ -716,6 +721,9 @@ async function init() { surface.configure(config); }, + js_memory_grow : function() { + update_heap_views(); + }, js_printf : function(format) { console.log(read_string(format)); }, @@ -775,8 +783,8 @@ async function init() { js_time : function() { return window.performance.now(); }, - js_pow : function(x) { - return Math.pow(x); + js_pow : function(base, exponent) { + return Math.pow(base, exponent); }, js_sin : function(x) { return Math.sin(x); @@ -787,8 +795,8 @@ async function init() { js_tan : function(x) { return Math.tan(x); }, - js_log : function(base, exponent) { - return Math.log(base, exponent); + js_log : function(x) { + return Math.log(x); }, js_exp : function(x) { return Math.exp(x); diff --git a/base/sources/iron_audio.c b/base/sources/iron_audio.c index 669804219..3721f287a 100644 --- a/base/sources/iron_audio.c +++ b/base/sources/iron_audio.c @@ -355,6 +355,11 @@ iron_a1_sound_t *iron_a1_sound_create_from_bytes(uint8_t *filedata, int filedata if (strncmp(format, ".ogg", 4) == 0) { int channels, sample_rate; int samples = stb_vorbis_decode_memory(filedata, (int)filedata_size, &channels, &sample_rate, (short **)&data); + if (samples <= 0) { + free(data); + sound->in_use = false; + return NULL; + } sound->channel_count = (uint8_t)channels; sound->samples_per_second = (uint32_t)sample_rate; sound->size = samples * 2 * sound->channel_count; @@ -571,48 +576,48 @@ float *iron_a1_sound_stream_next_frame(iron_a1_sound_stream_t *stream) { return stream->samples; } -static iron_mutex_t mutex; +static iron_mutex_t a2_mutex; static void (*a2_callback)(iron_a2_buffer_t *buffer, uint32_t samples, void *userdata) = NULL; static void *a2_userdata = NULL; void iron_a2_set_callback(void (*iron_a2_audio_callback)(iron_a2_buffer_t *buffer, uint32_t samples, void *userdata), void *userdata) { - iron_mutex_lock(&mutex); + iron_mutex_lock(&a2_mutex); a2_callback = iron_a2_audio_callback; a2_userdata = userdata; - iron_mutex_unlock(&mutex); + iron_mutex_unlock(&a2_mutex); } static void (*a2_sample_rate_callback)(void *userdata) = NULL; static void *a2_sample_rate_userdata = NULL; void iron_a2_set_sample_rate_callback(void (*iron_a2_sample_rate_callback)(void *userdata), void *userdata) { - iron_mutex_lock(&mutex); + iron_mutex_lock(&a2_mutex); a2_sample_rate_callback = iron_a2_sample_rate_callback; a2_sample_rate_userdata = userdata; - iron_mutex_unlock(&mutex); + iron_mutex_unlock(&a2_mutex); } void iron_a2_internal_init(void) { - iron_mutex_init(&mutex); + iron_mutex_init(&a2_mutex); } bool iron_a2_internal_callback(iron_a2_buffer_t *buffer, int samples) { - iron_mutex_lock(&mutex); + iron_mutex_lock(&a2_mutex); bool has_callback = a2_callback != NULL; if (has_callback) { a2_callback(buffer, samples, a2_userdata); } - iron_mutex_unlock(&mutex); + iron_mutex_unlock(&a2_mutex); return has_callback; } void iron_a2_internal_sample_rate_callback(void) { - iron_mutex_lock(&mutex); + iron_mutex_lock(&a2_mutex); if (a2_sample_rate_callback != NULL) { a2_sample_rate_callback(a2_sample_rate_userdata); } - iron_mutex_unlock(&mutex); + iron_mutex_unlock(&a2_mutex); } #endif diff --git a/base/sources/miniclib/math.c b/base/sources/miniclib/math.c index e8d2f654f..252e8115b 100644 --- a/base/sources/miniclib/math.c +++ b/base/sources/miniclib/math.c @@ -1,17 +1,17 @@ #include "math.h" #ifdef IRON_WASM -__attribute__((import_module("imports"), import_name("js_pow"))) float js_pow(float base, float exponent); -__attribute__((import_module("imports"), import_name("js_sin"))) float js_sin(float x); -__attribute__((import_module("imports"), import_name("js_cos"))) float js_cos(float x); -__attribute__((import_module("imports"), import_name("js_tan"))) float js_tan(float x); -__attribute__((import_module("imports"), import_name("js_log"))) float js_log(float x); -__attribute__((import_module("imports"), import_name("js_exp"))) float js_exp(float x); -__attribute__((import_module("imports"), import_name("js_sqrt"))) float js_sqrt(float x); -__attribute__((import_module("imports"), import_name("js_acos"))) float js_acos(float x); -__attribute__((import_module("imports"), import_name("js_asin"))) float js_asin(float x); -__attribute__((import_module("imports"), import_name("js_atan"))) float js_atan(float x); -__attribute__((import_module("imports"), import_name("js_atan2"))) float js_atan2(float x, float y); +__attribute__((import_module("imports"), import_name("js_pow"))) double js_pow(double base, double exponent); +__attribute__((import_module("imports"), import_name("js_sin"))) double js_sin(double x); +__attribute__((import_module("imports"), import_name("js_cos"))) double js_cos(double x); +__attribute__((import_module("imports"), import_name("js_tan"))) double js_tan(double x); +__attribute__((import_module("imports"), import_name("js_log"))) double js_log(double x); +__attribute__((import_module("imports"), import_name("js_exp"))) double js_exp(double x); +__attribute__((import_module("imports"), import_name("js_sqrt"))) double js_sqrt(double x); +__attribute__((import_module("imports"), import_name("js_acos"))) double js_acos(double x); +__attribute__((import_module("imports"), import_name("js_asin"))) double js_asin(double x); +__attribute__((import_module("imports"), import_name("js_atan"))) double js_atan(double x); +__attribute__((import_module("imports"), import_name("js_atan2"))) double js_atan2(double x, double y); #endif double fabs(double n) { @@ -38,8 +38,25 @@ float fminf(float x, float y) { return x < y ? x : y; } +static double exp2_int(int exp) { + union { + double d; + unsigned long long u; + } v; + v.u = (unsigned long long)(exp + 1023) << 52; + return v.d; +} + double ldexp(double x, int exp) { - return x * pow(2.0, exp); + while (exp > 1023) { + x *= exp2_int(1023); + exp -= 1023; + } + while (exp < -1022) { + x *= exp2_int(-1022); + exp += 1022; + } + return x * exp2_int(exp); } double pow(double base, double exponent) { @@ -224,7 +241,14 @@ float expf(float x) { } double exp2(double x) { - return pow(2.0, x); +#ifdef IRON_WASM + return js_pow(2.0, x); +#endif + double r = 1.0; + int n = (int)x; + for (int i = 0; i < n; i++) + r *= 2.0; + return r; } float exp2f(float x) { @@ -236,6 +260,8 @@ double frexp(double x, int *exp) { *exp = 0; return 0.0; } + double sign = x < 0.0 ? -1.0 : 1.0; + x *= sign; *exp = 0; while (x >= 1.0) { x /= 2.0; @@ -245,7 +271,7 @@ double frexp(double x, int *exp) { x *= 2.0; (*exp)--; } - return x; + return x * sign; } float frexpf(float x, int *exp) { diff --git a/base/sources/miniclib/stdlib.c b/base/sources/miniclib/stdlib.c index 47d3a0afe..bca6a620a 100644 --- a/base/sources/miniclib/stdlib.c +++ b/base/sources/miniclib/stdlib.c @@ -1,5 +1,6 @@ #include "stdlib.h" #include "ctype.h" +#include "stdbool.h" #include "stddef.h" #include "stdio.h" #include "string.h" @@ -7,9 +8,36 @@ #define ALIGNMENT 8 #define ALIGN(size) (((size) + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1)) +#ifdef IRON_WASM +__attribute__((import_module("imports"), import_name("js_memory_grow"))) void js_memory_grow(void); +extern unsigned char __heap_base; +#define heap (&__heap_base) +#define WASM_PAGE_SIZE 65536ULL +#define HEAP_GROW_PAGES 1024 // 64MB steps + +static bool heap_reserve(unsigned long long end) { + unsigned long long size = __builtin_wasm_memory_size(0) * WASM_PAGE_SIZE - (size_t)heap; + if (end <= size) { + return true; + } + size_t pages = (size_t)((end - size + WASM_PAGE_SIZE - 1) / WASM_PAGE_SIZE); + if (__builtin_wasm_memory_grow(0, pages < HEAP_GROW_PAGES ? HEAP_GROW_PAGES : pages) == (size_t)-1 && + __builtin_wasm_memory_grow(0, pages) == (size_t)-1) { + return false; + } + js_memory_grow(); + return true; +} +#else #define HEAP_SIZE 1024 * 1024 * 512 static unsigned char heap[HEAP_SIZE] __attribute__((aligned(ALIGNMENT))); -static size_t heap_top = ALIGNMENT; + +static bool heap_reserve(unsigned long long end) { + return end <= HEAP_SIZE; +} +#endif + +static size_t heap_top = ALIGNMENT; typedef struct block { size_t size; @@ -21,6 +49,9 @@ static block_t *free_list = NULL; __attribute__((export_name("wasm_malloc"))) #endif void *malloc(size_t size) { + if (size > (size_t)-1 - ALIGNMENT) { + return NULL; + } size = ALIGN(size); block_t **link = &free_list; block_t *curr = free_list; @@ -41,8 +72,8 @@ void *malloc(size_t size) { link = &curr->next; curr = curr->next; } - if (heap_top + sizeof(block_t) + size > HEAP_SIZE) { - printf("malloc: out of memory"); + if (!heap_reserve((unsigned long long)heap_top + sizeof(block_t) + size)) { + printf("malloc: out of memory (%u bytes requested)\n", (unsigned)size); return NULL; } block_t *ptr = (block_t *)&heap[heap_top]; diff --git a/base/tools/amake/exporters.c b/base/tools/amake/exporters.c index fc9f1e8e7..7f4b13b46 100644 --- a/base/tools/amake/exporters.c +++ b/base/tools/amake/exporters.c @@ -1548,7 +1548,7 @@ void export_solution(project_t *project) { char *compiler = "clang --target=wasm32 -nostdlib -matomics -mbulk-memory"; char *linker = "--target=wasm32 -nostdlib -matomics -mbulk-memory " - "\"-Wl,--import-memory,--shared-memory,--allow-undefined,--no-entry,--initial-memory=671088640,--max-memory=671088640,-z,stack-size=256000\""; + "\"-Wl,--import-memory,--shared-memory,--allow-undefined,--no-entry,--initial-memory=268435456,--max-memory=4294967296,-z,stack-size=256000\""; if (!goptions.debug) { linker = string("%s -Wl,--strip-all", linker); }