diff options
| -rw-r--r-- | .github/workflows/gen_bindings.yml | 2 | ||||
| -rw-r--r-- | CHANGELOG.md | 64 | ||||
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | bindgen/gen_rust.py | 2 | ||||
| -rw-r--r-- | bindgen/gen_zig.py | 2 | ||||
| -rw-r--r-- | sokol_app.h | 132 | ||||
| -rw-r--r-- | sokol_args.h | 128 | ||||
| -rw-r--r-- | sokol_audio.h | 26 | ||||
| -rw-r--r-- | sokol_fetch.h | 46 | ||||
| -rw-r--r-- | sokol_gfx.h | 171 | ||||
| -rw-r--r-- | tests/functional/sokol_args_test.c | 48 | ||||
| -rw-r--r-- | tests/functional/sokol_fetch_test.c | 77 | ||||
| -rw-r--r-- | util/sokol_debugtext.h | 20 | ||||
| -rw-r--r-- | util/sokol_fontstash.h | 20 | ||||
| -rw-r--r-- | util/sokol_gfx_imgui.h | 22 | ||||
| -rw-r--r-- | util/sokol_gl.h | 18 | ||||
| -rw-r--r-- | util/sokol_imgui.h | 20 | ||||
| -rw-r--r-- | util/sokol_memtrack.h | 4 | ||||
| -rw-r--r-- | util/sokol_nuklear.h | 18 | ||||
| -rw-r--r-- | util/sokol_spine.h | 22 |
20 files changed, 607 insertions, 237 deletions
diff --git a/.github/workflows/gen_bindings.yml b/.github/workflows/gen_bindings.yml index 57e7d271..5d39900f 100644 --- a/.github/workflows/gen_bindings.yml +++ b/.github/workflows/gen_bindings.yml @@ -227,7 +227,7 @@ jobs: - uses: actions/download-artifact@v3 with: name: ignore-me-rust - path: src/sokol + path: src - uses: dtolnay/rust-toolchain@master with: toolchain: stable diff --git a/CHANGELOG.md b/CHANGELOG.md index 59e389bd..d5af7653 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,69 @@ ## Updates +#### 03-Oct-2023 + +- sokol_app.h win/gl: PR https://github.com/floooh/sokol/pull/886 has been merged, this makes + GL context initialization on Windows slightly more efficient. Many thanks to @dtrebilco! + +#### 25-Sep-2023 + +- The allocator callback functions in all headers that support custom allocators have been renamed + from `alloc` and `free` to `alloc_fn` and `free_fn`, this is because the symbol `free` is quite + likely to collide with a preprocessor macro of the same name if the standard C allocator is + replaced with a custom allocator. + + This is a breaking change only if you've been providing your own allocator functions to + the sokol headers. + + See issue https://github.com/floooh/sokol/issues/903 and PR https://github.com/floooh/sokol/pull/908 + for details. + +#### 23-Sep-2023 + +- sokol_gfx.h gl: Allow to inject an external GL framebuffer id into the sokol-gfx default + pass. See PR https://github.com/floooh/sokol/pull/899 and issue https://github.com/floooh/sokol/issues/892 + for details. Many thanks to @danielchasehooper for the discussion and PR! + + Further down the road I want to make the whole topic more flexible while at the same time + simplifying the sokol-gfx API, see here: https://github.com/floooh/sokol/issues/904 + +#### 22-Sep-2023 + +- sokol_gfx.h: Fixed a Metal validation error on Intel Macs when creating textures (Intel Macs + have unified memory, but don't support textures in shared storage mode). This was a regression + in the image/sampler split update in mid-July 2023. Fixes issue https://github.com/floooh/sokol/issues/905 + via PR https://github.com/floooh/sokol/pull/907. + +#### 19-Sep-2023 + +- sokol_fetch.h: fixed a minor issue where a request that was cancelled before it was dispatched + had an incomplete response state set in the response callback (the `finished`, `failed` and + `error_code` fields were not set). This fixes issue https://github.com/floooh/sokol/issues/882 + via PR https://github.com/floooh/sokol/pull/898 + +#### 18-Sep-2023 + +- PR https://github.com/floooh/sokol/pull/893 has been merged, this fixes a minor issue + in the GL backend when using an injected texture as framebuffer attachment. +- Issue https://github.com/floooh/sokol/issues/884 has been fixed via PR https://github.com/floooh/sokol/pull/894, + this adds missing error code paths in the Metal backend when Metal object creation fails. +- Clarified `sapp_run()` behaviour in the sokol_app.h documentation header (search for `OPTIONAL: DON'T HIJACK main()`) +- sokol_args.h now fully supports "key-only args", see issue https://github.com/floooh/sokol/issues/876 for details, + fixed via PR https://github.com/floooh/sokol/pull/896 + +#### 17-Sep-2023 + +- The sokol-gfx Metal backend now adds debug labels to Metal resource objects and + also passes through the `sg_push/pop_debug_group()` calls. If you use the push/pop + debug group calls, please be aware of the following limitations: + + - a push inside a render pass must have an associated pop inside the same render pass + - a push outside any render pass must have an associated pop outside any render pass + - Metal will ignore any push/pop calls outside render passes (this is because in Metal + these are MTLCommandEncoder methods) + + Associated issue: https://github.com/floooh/sokol/issues/889, and PR: https://github.com/floooh/sokol/pull/890. + #### 09-Sep-2023 - a small PR has been merged which fixes a redundant glBindFramebuffer() in the GLES3 backend @@ -4,7 +4,7 @@ Simple [STB-style](https://github.com/nothings/stb/blob/master/docs/stb_howto.txt) cross-platform libraries for C and C++, written in C. -[**See what's new**](https://github.com/floooh/sokol/blob/master/CHANGELOG.md) (**26-Jul-2023** proper image/sampler pair support in sokol_nuklear.h) +[**See what's new**](https://github.com/floooh/sokol/blob/master/CHANGELOG.md) (**25-Sep-2023** POTENTIALLY BREAKING: allocator callbacks have been renamed) [](/../../actions/workflows/main.yml) [](/../../actions/workflows/gen_bindings.yml) [](https://github.com/floooh/sokol-zig/actions/workflows/main.yml) [](https://github.com/floooh/sokol-nim/actions/workflows/main.yml) [](https://github.com/floooh/sokol-odin/actions/workflows/main.yml)[](https://github.com/floooh/sokol-rust/actions/workflows/main.yml) diff --git a/bindgen/gen_rust.py b/bindgen/gen_rust.py index 5578d083..0b6384c4 100644 --- a/bindgen/gen_rust.py +++ b/bindgen/gen_rust.py @@ -355,6 +355,8 @@ def funcptr_result_c(field_type): res_type = field_type[: field_type.index("(*)")].strip() if res_type == "void": return "" + elif is_prim_type(res_type): + return f" -> {as_rust_prim_type(res_type)}" elif util.is_const_void_ptr(res_type): return " -> *const core::ffi::c_void" elif util.is_void_ptr(res_type): diff --git a/bindgen/gen_zig.py b/bindgen/gen_zig.py index b1631ebc..cef75e9e 100644 --- a/bindgen/gen_zig.py +++ b/bindgen/gen_zig.py @@ -271,6 +271,8 @@ def funcptr_result_c(field_type): res_type = field_type[:field_type.index('(*)')].strip() if res_type == 'void': return 'void' + elif is_prim_type(res_type): + return as_zig_prim_type(res_type) elif util.is_const_void_ptr(res_type): return '?*const anyopaque' elif util.is_void_ptr(res_type): diff --git a/sokol_app.h b/sokol_app.h index 7055653b..32b41daa 100644 --- a/sokol_app.h +++ b/sokol_app.h @@ -951,9 +951,11 @@ OPTIONAL: DON'T HIJACK main() (#define SOKOL_NO_ENTRY) ====================================================== + NOTE: SOKOL_NO_ENTRY and sapp_run() is currently not supported on Android. + In its default configuration, sokol_app.h "hijacks" the platform's standard main() function. This was done because different platforms - have different main functions which are not compatible with + have different entry point conventions which are not compatible with C's main() (for instance WinMain on Windows has completely different arguments). However, this "main hijacking" posed a problem for usage scenarios like integrating sokol_app.h with other languages than @@ -965,12 +967,30 @@ - instead provide the standard main() function of the platform - from the main function, call the function ```sapp_run()``` which takes a pointer to an ```sapp_desc``` structure. - - ```sapp_run()``` takes over control and calls the provided init-, frame-, - shutdown- and event-callbacks just like in the default model, it - will only return when the application quits (or not at all on some - platforms, like emscripten) + - from here on```sapp_run()``` takes over control and calls the provided + init-, frame-, event- and cleanup-callbacks just like in the default model. + + sapp_run() behaves differently across platforms: + + - on some platforms, sapp_run() will return when the application quits + - on other platforms, sapp_run() will never return, even when the + application quits (the operating system is free to simply terminate + the application at any time) + - on Emscripten specifically, sapp_run() will return immediately while + the frame callback keeps being called + + This different behaviour of sapp_run() essentially means that there shouldn't + be any code *after* sapp_run(), because that may either never be called, or in + case of Emscripten will be called at an unexpected time (at application start). - NOTE: SOKOL_NO_ENTRY is currently not supported on Android. + An application also should not depend on the cleanup-callback being called + when cross-platform compatibility is required. + + Since sapp_run() returns immediately on Emscripten you shouldn't activate + the 'EXIT_RUNTIME' linker option (this is disabled by default when compiling + for the browser target), since the C/C++ exit runtime would be called immediately at + application start, causing any global objects to be destroyed and global + variables to be zeroed. WINDOWS CONSOLE OUTPUT ====================== @@ -1019,8 +1039,8 @@ return (sapp_desc){ // ... .allocator = { - .alloc = my_alloc, - .free = my_free, + .alloc_fn = my_alloc, + .free_fn = my_free, .user_data = ..., } }; @@ -1473,12 +1493,12 @@ typedef struct sapp_icon_desc { Used in sapp_desc to provide custom memory-alloc and -free functions to sokol_app.h. If memory management should be overridden, both the - alloc and free function must be provided (e.g. it's not valid to + alloc_fb and free_fn function must be provided (e.g. it's not valid to override one function but not the other). */ typedef struct sapp_allocator { - void* (*alloc)(size_t size, void* user_data); - void (*free)(void* ptr, void* user_data); + void* (*alloc_fn)(size_t size, void* user_data); + void (*free_fn)(void* ptr, void* user_data); void* user_data; } sapp_allocator; @@ -2857,10 +2877,9 @@ _SOKOL_PRIVATE void _sapp_clear(void* ptr, size_t size) { _SOKOL_PRIVATE void* _sapp_malloc(size_t size) { SOKOL_ASSERT(size > 0); void* ptr; - if (_sapp.desc.allocator.alloc) { - ptr = _sapp.desc.allocator.alloc(size, _sapp.desc.allocator.user_data); - } - else { + if (_sapp.desc.allocator.alloc_fn) { + ptr = _sapp.desc.allocator.alloc_fn(size, _sapp.desc.allocator.user_data); + } else { ptr = malloc(size); } if (0 == ptr) { @@ -2876,8 +2895,8 @@ _SOKOL_PRIVATE void* _sapp_malloc_clear(size_t size) { } _SOKOL_PRIVATE void _sapp_free(void* ptr) { - if (_sapp.desc.allocator.free) { - _sapp.desc.allocator.free(ptr, _sapp.desc.allocator.user_data); + if (_sapp.desc.allocator.free_fn) { + _sapp.desc.allocator.free_fn(ptr, _sapp.desc.allocator.user_data); } else { free(ptr); @@ -2981,7 +3000,7 @@ _SOKOL_PRIVATE bool _sapp_strcpy(const char* src, char* dst, int max_len) { } _SOKOL_PRIVATE sapp_desc _sapp_desc_defaults(const sapp_desc* desc) { - SOKOL_ASSERT((desc->allocator.alloc && desc->allocator.free) || (!desc->allocator.alloc && !desc->allocator.free)); + SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); sapp_desc res = *desc; res.sample_count = _sapp_def(res.sample_count, 1); res.swap_interval = _sapp_def(res.swap_interval, 1); @@ -6626,11 +6645,54 @@ _SOKOL_PRIVATE int _sapp_wgl_attrib(int pixel_format, int attrib) { return value; } +_SOKOL_PRIVATE void _sapp_wgl_attribiv(int pixel_format, int num_attribs, const int* attribs, int* results) { + SOKOL_ASSERT(_sapp.wgl.arb_pixel_format); + if (!_sapp.wgl.GetPixelFormatAttribivARB(_sapp.win32.dc, pixel_format, 0, num_attribs, attribs, results)) { + _SAPP_PANIC(WIN32_GET_PIXELFORMAT_ATTRIB_FAILED); + } +} + _SOKOL_PRIVATE int _sapp_wgl_find_pixel_format(void) { SOKOL_ASSERT(_sapp.win32.dc); SOKOL_ASSERT(_sapp.wgl.arb_pixel_format); const _sapp_gl_fbconfig* closest; + #define _sapp_wgl_num_query_tags (12) + const int query_tags[_sapp_wgl_num_query_tags] = { + WGL_SUPPORT_OPENGL_ARB, + WGL_DRAW_TO_WINDOW_ARB, + WGL_PIXEL_TYPE_ARB, + WGL_ACCELERATION_ARB, + WGL_DOUBLE_BUFFER_ARB, + WGL_RED_BITS_ARB, + WGL_GREEN_BITS_ARB, + WGL_BLUE_BITS_ARB, + WGL_ALPHA_BITS_ARB, + WGL_DEPTH_BITS_ARB, + WGL_STENCIL_BITS_ARB, + WGL_SAMPLES_ARB, + }; + const int result_support_opengl_index = 0; + const int result_draw_to_window_index = 1; + const int result_pixel_type_index = 2; + const int result_acceleration_index = 3; + const int result_double_buffer_index = 4; + const int result_red_bits_index = 5; + const int result_green_bits_index = 6; + const int result_blue_bits_index = 7; + const int result_alpha_bits_index = 8; + const int result_depth_bits_index = 9; + const int result_stencil_bits_index = 10; + const int result_samples_index = 11; + + int query_results[_sapp_wgl_num_query_tags] = {0}; + // Drop the last item if multisample extension is not supported. + // If in future querying with multiple extensions, will have to shuffle index values to have active extensions on the end. + int query_count = _sapp_wgl_num_query_tags; + if (!_sapp.wgl.arb_multisample) { + query_count = _sapp_wgl_num_query_tags - 1; + } + int native_count = _sapp_wgl_attrib(1, WGL_NUMBER_PIXEL_FORMATS_ARB); _sapp_gl_fbconfig* usable_configs = (_sapp_gl_fbconfig*) _sapp_malloc_clear((size_t)native_count * sizeof(_sapp_gl_fbconfig)); SOKOL_ASSERT(usable_configs); @@ -6639,27 +6701,27 @@ _SOKOL_PRIVATE int _sapp_wgl_find_pixel_format(void) { const int n = i + 1; _sapp_gl_fbconfig* u = usable_configs + usable_count; _sapp_gl_init_fbconfig(u); - if (!_sapp_wgl_attrib(n, WGL_SUPPORT_OPENGL_ARB) || !_sapp_wgl_attrib(n, WGL_DRAW_TO_WINDOW_ARB)) { - continue; - } - if (_sapp_wgl_attrib(n, WGL_PIXEL_TYPE_ARB) != WGL_TYPE_RGBA_ARB) { - continue; - } - if (_sapp_wgl_attrib(n, WGL_ACCELERATION_ARB) == WGL_NO_ACCELERATION_ARB) { + _sapp_wgl_attribiv(n, query_count, query_tags, query_results); + + if (query_results[result_support_opengl_index] == 0 + || query_results[result_draw_to_window_index] == 0 + || query_results[result_pixel_type_index] != WGL_TYPE_RGBA_ARB + || query_results[result_acceleration_index] == WGL_NO_ACCELERATION_ARB) + { continue; } - u->red_bits = _sapp_wgl_attrib(n, WGL_RED_BITS_ARB); - u->green_bits = _sapp_wgl_attrib(n, WGL_GREEN_BITS_ARB); - u->blue_bits = _sapp_wgl_attrib(n, WGL_BLUE_BITS_ARB); - u->alpha_bits = _sapp_wgl_attrib(n, WGL_ALPHA_BITS_ARB); - u->depth_bits = _sapp_wgl_attrib(n, WGL_DEPTH_BITS_ARB); - u->stencil_bits = _sapp_wgl_attrib(n, WGL_STENCIL_BITS_ARB); - if (_sapp_wgl_attrib(n, WGL_DOUBLE_BUFFER_ARB)) { + u->red_bits = query_results[result_red_bits_index]; + u->green_bits = query_results[result_green_bits_index]; + u->blue_bits = query_results[result_blue_bits_index]; + u->alpha_bits = query_results[result_alpha_bits_index]; + u->depth_bits = query_results[result_depth_bits_index]; + u->stencil_bits = query_results[result_stencil_bits_index]; + if (query_results[result_double_buffer_index]) { u->doublebuffer = true; } - if (_sapp.wgl.arb_multisample) { - u->samples = _sapp_wgl_attrib(n, WGL_SAMPLES_ARB); - } + + u->samples = query_results[result_samples_index]; // NOTE: If arb_multisample is not supported - just takes the default 0 + u->handle = (uintptr_t)n; usable_count++; } diff --git a/sokol_args.h b/sokol_args.h index 4d37907c..bce6bbad 100644 --- a/sokol_args.h +++ b/sokol_args.h @@ -35,11 +35,22 @@ When running as WebAssembly app, arguments are taken from the page URL: - https://floooh.github.io/tiny8bit/kc85.html?type=kc85_3&mod=m022&snapshot=kc85/jungle.kcc + https://floooh.github.io/tiny8bit/kc85.html?type=kc85_3&mod=m022&snapshot=kc85/jungle.kcc The same arguments provided to a command line app: - kc85 type=kc85_3 mod=m022 snapshot=kc85/jungle.kcc + kc85 type=kc85_3 mod=m022 snapshot=kc85/jungle.kcc + + You can also use standalone keys without value: + + https://floooh.github.io/tiny8bit/kc85.html?bla&blub + + On the command line: + + kc85 bla blub + + Such value-less keys are reported as the value being an empty string, but they + can be tested with `sapp_exists("bla")` or `sapp_boolean("blub")`. ARGUMENT FORMATTING =================== @@ -57,6 +68,12 @@ key=value + or + + key + + When a key has no value, the value will be assigned an empty string. + Key/value pairs are separated by 'whitespace', valid whitespace characters are space and tab. @@ -71,9 +88,6 @@ The 'key' string must be a simple string without escape sequences or whitespace. - Currently 'single keys' without values are not allowed, but may be - in the future. - The 'value' string can be quoted, and quoted value strings can contain whitespace: @@ -123,7 +137,7 @@ ... } - // check if a key's value is "true", "yes" or "on" + // check if a key's value is "true", "yes" or "on" or if this is a standalone key if (sargs_boolean("joystick_enabled")) { ... } @@ -183,23 +197,23 @@ Return true between sargs_setup() and sargs_shutdown() bool sargs_exists(const char* key) - Test if a key arg exists. + Test if an argument exists by its key name. const char* sargs_value(const char* key) - Return value associated with key. Returns an empty - string ("") if the key doesn't exist. + Return value associated with key. Returns an empty string ("") if the + key doesn't exist, or if the key doesn't have a value. const char* sargs_value_def(const char* key, const char* default) - Return value associated with key, or the provided default - value if the value doesn't exist. + Return value associated with key, or the provided default value if the + key doesn't exist, or this is a value-less key. bool sargs_equals(const char* key, const char* val); Return true if the value associated with key matches the 'val' argument. bool sargs_boolean(const char* key) - Return true if the value string of 'key' is one - of 'true', 'yes', 'on'. + Return true if the value string of 'key' is one of 'true', 'yes', 'on', + or this is a key without value. int sargs_find(const char* key) Find argument by key name and return its index, or -1 if not found. @@ -213,7 +227,7 @@ const char* sargs_value_at(int index) Return the value of argument at index. Returns empty string - if index is outside range. + if the key at index has no value, or the index is out-of-range. MEMORY ALLOCATION OVERRIDE @@ -233,8 +247,8 @@ sargs_setup(&(sargs_desc){ // ... .allocator = { - .alloc = my_alloc, - .free = my_free, + .alloc_fn = my_alloc, + .free_fn = my_free, .user_data = ..., } }); @@ -302,12 +316,12 @@ extern "C" { Used in sargs_desc to provide custom memory-alloc and -free functions to sokol_args.h. If memory management should be overridden, both the - alloc and free function must be provided (e.g. it's not valid to + alloc_fn and free_fn function must be provided (e.g. it's not valid to override one function but not the other). */ typedef struct sargs_allocator { - void* (*alloc)(size_t size, void* user_data); - void (*free)(void* ptr, void* user_data); + void* (*alloc_fn)(size_t size, void* user_data); + void (*free_fn)(void* ptr, void* user_data); void* user_data; } sargs_allocator; @@ -327,13 +341,13 @@ SOKOL_ARGS_API_DECL void sargs_shutdown(void); SOKOL_ARGS_API_DECL bool sargs_isvalid(void); /* test if an argument exists by key name */ SOKOL_ARGS_API_DECL bool sargs_exists(const char* key); -/* get value by key name, return empty string if key doesn't exist */ +/* get value by key name, return empty string if key doesn't exist or an existing key has no value */ SOKOL_ARGS_API_DECL const char* sargs_value(const char* key); -/* get value by key name, return provided default if key doesn't exist */ +/* get value by key name, return provided default if key doesn't exist or has no value */ SOKOL_ARGS_API_DECL const char* sargs_value_def(const char* key, const char* def); /* return true if val arg matches the value associated with key */ SOKOL_ARGS_API_DECL bool sargs_equals(const char* key, const char* val); -/* return true if key's value is "true", "yes" or "on" */ +/* return true if key's value is "true", "yes", "on" or an existing key has no value */ SOKOL_ARGS_API_DECL bool sargs_boolean(const char* key); /* get index of arg by key name, return -1 if not exists */ SOKOL_ARGS_API_DECL int sargs_find(const char* key); @@ -433,10 +447,9 @@ _SOKOL_PRIVATE void _sargs_clear(void* ptr, size_t size) { _SOKOL_PRIVATE void* _sargs_malloc(size_t size) { SOKOL_ASSERT(size > 0); void* ptr; - if (_sargs.allocator.alloc) { - ptr = _sargs.allocator.alloc(size, _sargs.allocator.user_data); - } - else { + if (_sargs.allocator.alloc_fn) { + ptr = _sargs.allocator.alloc_fn(size, _sargs.allocator.user_data); + } else { ptr = malloc(size); } SOKOL_ASSERT(ptr); @@ -450,10 +463,9 @@ _SOKOL_PRIVATE void* _sargs_malloc_clear(size_t size) { } _SOKOL_PRIVATE void _sargs_free(void* ptr) { - if (_sargs.allocator.free) { - _sargs.allocator.free(ptr, _sargs.allocator.user_data); - } - else { + if (_sargs.allocator.free_fn) { + _sargs.allocator.free_fn(ptr, _sargs.allocator.user_data); + } else { free(ptr); } } @@ -486,8 +498,8 @@ _SOKOL_PRIVATE bool _sargs_val_expected(void) { return 0 != (_sargs.parse_state & _SARGS_EXPECT_VAL); } -_SOKOL_PRIVATE void _sargs_expect_sep(void) { - _sargs.parse_state = _SARGS_EXPECT_SEP; +_SOKOL_PRIVATE void _sargs_expect_sep_or_key(void) { + _sargs.parse_state = _SARGS_EXPECT_SEP | _SARGS_EXPECT_KEY; } _SOKOL_PRIVATE bool _sargs_any_expected(void) { @@ -524,14 +536,17 @@ _SOKOL_PRIVATE bool _sargs_is_whitespace(char c) { } _SOKOL_PRIVATE void _sargs_start_key(void) { - SOKOL_ASSERT(_sargs.num_args < _sargs.max_args); + SOKOL_ASSERT((_sargs.num_args >= 0) && (_sargs.num_args < _sargs.max_args)); _sargs.parse_state = _SARGS_PARSING_KEY; _sargs.args[_sargs.num_args].key = _sargs.buf_pos; } _SOKOL_PRIVATE void _sargs_end_key(void) { - SOKOL_ASSERT(_sargs.num_args < _sargs.max_args); + SOKOL_ASSERT((_sargs.num_args >= 0) && (_sargs.num_args < _sargs.max_args)); _sargs_putc(0); + // declare val as empty string in case this is a key-only arg + _sargs.args[_sargs.num_args].val = _sargs.buf_pos - 1; + _sargs.num_args++; _sargs.parse_state = 0; } @@ -540,15 +555,13 @@ _SOKOL_PRIVATE bool _sargs_parsing_key(void) { } _SOKOL_PRIVATE void _sargs_start_val(void) { - SOKOL_ASSERT(_sargs.num_args < _sargs.max_args); + SOKOL_ASSERT((_sargs.num_args > 0) && (_sargs.num_args <= _sargs.max_args)); _sargs.parse_state = _SARGS_PARSING_VAL; - _sargs.args[_sargs.num_args].val = _sargs.buf_pos; + _sargs.args[_sargs.num_args - 1].val = _sargs.buf_pos; } _SOKOL_PRIVATE void _sargs_end_val(void) { - SOKOL_ASSERT(_sargs.num_args < _sargs.max_args); _sargs_putc(0); - _sargs.num_args++; _sargs.parse_state = 0; } @@ -596,7 +609,12 @@ _SOKOL_PRIVATE bool _sargs_parse_carg(const char* src) { if (_sargs_any_expected()) { if (!_sargs_is_whitespace(c)) { /* start of key, value or separator */ - if (_sargs_key_expected()) { + if (_sargs_is_separator(c)) { + /* skip separator and expect value */ + _sargs_expect_val(); + continue; + } + else if (_sargs_key_expected()) { /* start of new key */ _sargs_start_key(); } @@ -608,13 +626,6 @@ _SOKOL_PRIVATE bool _sargs_parse_carg(const char* src) { } _sargs_start_val(); } - else { - /* separator */ - if (_sargs_is_separator(c)) { - _sargs_expect_val(); - continue; - } - } } else { /* skip white space */ @@ -629,7 +640,7 @@ _SOKOL_PRIVATE bool _sargs_parse_carg(const char* src) { _sargs_expect_val(); } else { - _sargs_expect_sep(); + _sargs_expect_sep_or_key(); } continue; } @@ -657,7 +668,7 @@ _SOKOL_PRIVATE bool _sargs_parse_carg(const char* src) { } if (_sargs_parsing_key()) { _sargs_end_key(); - _sargs_expect_sep(); + _sargs_expect_sep_or_key(); } else if (_sargs_parsing_val() && !_sargs_in_quotes()) { _sargs_end_val(); @@ -823,7 +834,13 @@ SOKOL_API_IMPL const char* sargs_value_def(const char* key, const char* def) { SOKOL_ASSERT(_sargs.valid && key && def); int arg_index = sargs_find(key); if (-1 != arg_index) { - return sargs_value_at(arg_index); + const char* res = sargs_value_at(arg_index); + SOKOL_ASSERT(res); + if (res[0] == 0) { + return def; + } else { + return res; + } } else { return def; @@ -836,10 +853,15 @@ SOKOL_API_IMPL bool sargs_equals(const char* key, const char* val) { } SOKOL_API_IMPL bool sargs_boolean(const char* key) { - const char* val = sargs_value(key); - return (0 == strcmp("true", val)) || - (0 == strcmp("yes", val)) || - (0 == strcmp("on", val)); + if (sargs_exists(key)) { + const char* val = sargs_value(key); + return (0 == strcmp("true", val)) || + (0 == strcmp("yes", val)) || + (0 == strcmp("on", val)) || + (0 == strcmp("", val)); + } else { + return false; + } } #endif /* SOKOL_ARGS_IMPL */ diff --git a/sokol_audio.h b/sokol_audio.h index bdd69530..6b60937c 100644 --- a/sokol_audio.h +++ b/sokol_audio.h @@ -397,8 +397,8 @@ saudio_setup(&(saudio_desc){ // ... .allocator = { - .alloc = my_alloc, - .free = my_free, + .alloc_fn = my_alloc, + .free_fn = my_free, .user_data = ..., } }); @@ -575,12 +575,12 @@ typedef struct saudio_logger { Used in saudio_desc to provide custom memory-alloc and -free functions to sokol_audio.h. If memory management should be overridden, both the - alloc and free function must be provided (e.g. it's not valid to + alloc_fn and free_fn function must be provided (e.g. it's not valid to override one function but not the other). */ typedef struct saudio_allocator { - void* (*alloc)(size_t size, void* user_data); - void (*free)(void* ptr, void* user_data); + void* (*alloc_fn)(size_t size, void* user_data); + void (*free_fn)(void* ptr, void* user_data); void* user_data; } saudio_allocator; @@ -1146,10 +1146,9 @@ _SOKOL_PRIVATE void _saudio_clear(void* ptr, size_t size) { _SOKOL_PRIVATE void* _saudio_malloc(size_t size) { SOKOL_ASSERT(size > 0); void* ptr; - if (_saudio.desc.allocator.alloc) { - ptr = _saudio.desc.allocator.alloc(size, _saudio.desc.allocator.user_data); - } - else { + if (_saudio.desc.allocator.alloc_fn) { + ptr = _saudio.desc.allocator.alloc_fn(size, _saudio.desc.allocator.user_data); + } else { ptr = malloc(size); } if (0 == ptr) { @@ -1165,10 +1164,9 @@ _SOKOL_PRIVATE void* _saudio_malloc_clear(size_t size) { } _SOKOL_PRIVATE void _saudio_free(void* ptr) { - if (_saudio.desc.allocator.free) { - _saudio.desc.allocator.free(ptr, _saudio.desc.allocator.user_data); - } - else { + if (_saudio.desc.allocator.free_fn) { + _saudio.desc.allocator.free_fn(ptr, _saudio.desc.allocator.user_data); + } else { free(ptr); } } @@ -2485,7 +2483,7 @@ void _saudio_backend_shutdown(void) { SOKOL_API_IMPL void saudio_setup(const saudio_desc* desc) { SOKOL_ASSERT(!_saudio.valid); SOKOL_ASSERT(desc); - SOKOL_ASSERT((desc->allocator.alloc && desc->allocator.free) || (!desc->allocator.alloc && !desc->allocator.free)); + SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); _saudio_clear(&_saudio, sizeof(_saudio)); _saudio.desc = *desc; _saudio.stream_cb = desc->stream_cb; diff --git a/sokol_fetch.h b/sokol_fetch.h index 21e9b5d1..510c5b5b 100644 --- a/sokol_fetch.h +++ b/sokol_fetch.h @@ -820,8 +820,8 @@ sfetch_setup(&(sfetch_desc_t){ // ... .allocator = { - .alloc = my_alloc, - .free = my_free, + .alloc_fn = my_alloc, + .free_fn = my_free, .user_data = ..., } }); @@ -1024,8 +1024,8 @@ typedef struct sfetch_range_t { override one function but not the other). */ typedef struct sfetch_allocator_t { - void* (*alloc)(size_t size, void* user_data); - void (*free)(void* ptr, void* user_data); + void* (*alloc_fn)(size_t size, void* user_data); + void (*free_fn)(void* ptr, void* user_data); void* user_data; } sfetch_allocator_t; @@ -1424,10 +1424,9 @@ _SOKOL_PRIVATE void _sfetch_clear(void* ptr, size_t size) { _SOKOL_PRIVATE void* _sfetch_malloc_with_allocator(const sfetch_allocator_t* allocator, size_t size) { SOKOL_ASSERT(size > 0); void* ptr; - if (allocator->alloc) { - ptr = allocator->alloc(size, allocator->user_data); - } - else { + if (allocator->alloc_fn) { + ptr = allocator->alloc_fn(size, allocator->user_data); + } else { ptr = malloc(size); } if (0 == ptr) { @@ -1447,10 +1446,9 @@ _SOKOL_PRIVATE void* _sfetch_malloc_clear(size_t size) { } _SOKOL_PRIVATE void _sfetch_free(void* ptr) { - if (_sfetch->desc.allocator.free) { - _sfetch->desc.allocator.free(ptr, _sfetch->desc.allocator.user_data); - } - else { + if (_sfetch->desc.allocator.free_fn) { + _sfetch->desc.allocator.free_fn(ptr, _sfetch->desc.allocator.user_data); + } else { free(ptr); } } @@ -2457,6 +2455,12 @@ _SOKOL_PRIVATE void _sfetch_invoke_response_callback(_sfetch_item_t* item) { item->callback(&response); } +_SOKOL_PRIVATE void _sfetch_cancel_item(_sfetch_item_t* item) { + item->state = _SFETCH_STATE_FAILED; + item->user.finished = true; + item->user.error_code = SFETCH_ERROR_CANCELLED; +} + /* per-frame channel stuff: move requests in and out of the IO threads, call response callbacks */ _SOKOL_PRIVATE void _sfetch_channel_dowork(_sfetch_channel_t* chn, _sfetch_pool_t* pool) { @@ -2469,9 +2473,16 @@ _SOKOL_PRIVATE void _sfetch_channel_dowork(_sfetch_channel_t* chn, _sfetch_pool_ _sfetch_item_t* item = _sfetch_pool_item_lookup(pool, slot_id); SOKOL_ASSERT(item); SOKOL_ASSERT(item->state == _SFETCH_STATE_ALLOCATED); + // if the item was cancelled early, kick it out immediately + if (item->user.cancel) { + _sfetch_cancel_item(item); + _sfetch_invoke_response_callback(item); + _sfetch_pool_item_free(pool, slot_id); + continue; + } item->state = _SFETCH_STATE_DISPATCHED; item->lane = _sfetch_ring_dequeue(&chn->free_lanes); - /* if no buffer provided yet, invoke response callback to do so */ + // if no buffer provided yet, invoke response callback to do so if (0 == item->buffer.ptr) { _sfetch_invoke_response_callback(item); } @@ -2498,8 +2509,7 @@ _SOKOL_PRIVATE void _sfetch_channel_dowork(_sfetch_channel_t* chn, _sfetch_pool_ item->user.cont = false; } if (item->user.cancel) { - item->state = _SFETCH_STATE_FAILED; - item->user.finished = true; + _sfetch_cancel_item(item); } switch (item->state) { case _SFETCH_STATE_DISPATCHED: @@ -2541,7 +2551,7 @@ _SOKOL_PRIVATE void _sfetch_channel_dowork(_sfetch_channel_t* chn, _sfetch_pool_ item->user.fetched_offset = item->thread.fetched_offset; item->user.fetched_size = item->thread.fetched_size; if (item->user.cancel) { - item->user.error_code = SFETCH_ERROR_CANCELLED; + _sfetch_cancel_item(item); } else { item->user.error_code = item->thread.error_code; @@ -2558,7 +2568,7 @@ _SOKOL_PRIVATE void _sfetch_channel_dowork(_sfetch_channel_t* chn, _sfetch_pool_ } _sfetch_invoke_response_callback(item); - /* when the request is finish, free the lane for another request, + /* when the request is finished, free the lane for another request, otherwise feed it back into the incoming queue */ if (item->user.finished) { @@ -2608,7 +2618,7 @@ _SOKOL_PRIVATE bool _sfetch_validate_request(_sfetch_t* ctx, const sfetch_reques } _SOKOL_PRIVATE sfetch_desc_t _sfetch_desc_defaults(const sfetch_desc_t* desc) { - SOKOL_ASSERT((desc->allocator.alloc && desc->allocator.free) || (!desc->allocator.alloc && !desc->allocator.free)); + SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); sfetch_desc_t res = *desc; res.max_requests = _sfetch_def(desc->max_requests, 128); res.num_channels = _sfetch_def(desc->num_channels, 1); diff --git a/sokol_gfx.h b/sokol_gfx.h index cf3ee1a5..11035bad 100644 --- a/sokol_gfx.h +++ b/sokol_gfx.h @@ -946,8 +946,8 @@ sg_setup(&(sg_desc){ // ... .allocator = { - .alloc = my_alloc, - .free = my_free, + .alloc_fn = my_alloc, + .free_fn = my_free, .user_data = ..., } }); @@ -3059,7 +3059,10 @@ typedef struct sg_frame_stats { _SG_LOGITEM_XMACRO(D3D11_MAP_FOR_UPDATE_BUFFER_FAILED, "Map() failed when updating buffer (d3d11)") \ _SG_LOGITEM_XMACRO(D3D11_MAP_FOR_APPEND_BUFFER_FAILED, "Map() failed when appending to buffer (d3d11)") \ _SG_LOGITEM_XMACRO(D3D11_MAP_FOR_UPDATE_IMAGE_FAILED, "Map() failed when updating image (d3d11)") \ + _SG_LOGITEM_XMACRO(METAL_CREATE_BUFFER_FAILED, "failed to create buffer object (metal)") \ _SG_LOGITEM_XMACRO(METAL_TEXTURE_FORMAT_NOT_SUPPORTED, "pixel format not supported for texture (metal)") \ + _SG_LOGITEM_XMACRO(METAL_CREATE_TEXTURE_FAILED, "failed to create texture object (metal)") \ + _SG_LOGITEM_XMACRO(METAL_CREATE_SAMPLER_FAILED, "failed to create sampler object (metal)") \ _SG_LOGITEM_XMACRO(METAL_SHADER_COMPILATION_FAILED, "shader compilation failed (metal)") \ _SG_LOGITEM_XMACRO(METAL_SHADER_CREATION_FAILED, "shader creation failed (metal)") \ _SG_LOGITEM_XMACRO(METAL_SHADER_COMPILATION_OUTPUT, "") \ @@ -3067,6 +3070,7 @@ typedef struct sg_frame_stats { _SG_LOGITEM_XMACRO(METAL_FRAGMENT_SHADER_ENTRY_NOT_FOUND, "fragment shader entry not found (metal)") \ _SG_LOGITEM_XMACRO(METAL_CREATE_RPS_FAILED, "failed to create render pipeline state (metal)") \ _SG_LOGITEM_XMACRO(METAL_CREATE_RPS_OUTPUT, "") \ + _SG_LOGITEM_XMACRO(METAL_CREATE_DSS_FAILED, "failed to create depth stencil state (metal)") \ _SG_LOGITEM_XMACRO(WGPU_BINDGROUPS_POOL_EXHAUSTED, "bindgroups pool exhausted (increase sg_desc.bindgroups_cache_size) (wgpu)") \ _SG_LOGITEM_XMACRO(WGPU_BINDGROUPSCACHE_SIZE_GREATER_ONE, "sg_desc.wgpu_bindgroups_cache_size must be > 1 (wgpu)") \ _SG_LOGITEM_XMACRO(WGPU_BINDGROUPSCACHE_SIZE_POW2, "sg_desc.wgpu_bindgroups_cache_size must be a power of 2 (wgpu)") \ @@ -3266,7 +3270,7 @@ typedef struct sg_frame_stats { _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_IMG_SMP_MIPMAPS, "sg_apply_bindings: image bound to fragment stage has mipmap_count == 1, but associated sampler mipmap filer is not SG_MIPMAPFILTER_NONE") \ _SG_LOGITEM_XMACRO(VALIDATE_AUB_NO_PIPELINE, "sg_apply_uniforms: must be called after sg_apply_pipeline()") \ _SG_LOGITEM_XMACRO(VALIDATE_AUB_NO_UB_AT_SLOT, "sg_apply_uniforms: no uniform block declaration at this shader stage UB slot") \ - _SG_LOGITEM_XMACRO(VALIDATE_AUB_SIZE, "sg_apply_uniforms: data size exceeds declared uniform block size") \ + _SG_LOGITEM_XMACRO(VALIDATE_AUB_SIZE, "sg_apply_uniforms: data size doesn't match declared uniform block size") \ _SG_LOGITEM_XMACRO(VALIDATE_UPDATEBUF_USAGE, "sg_update_buffer: cannot update immutable buffer") \ _SG_LOGITEM_XMACRO(VALIDATE_UPDATEBUF_SIZE, "sg_update_buffer: update size is bigger than buffer size") \ _SG_LOGITEM_XMACRO(VALIDATE_UPDATEBUF_ONCE, "sg_update_buffer: only one update allowed per buffer and frame") \ @@ -3310,8 +3314,8 @@ typedef enum sg_log_item { .max_commit_listeners 1024 .disable_validation false - .allocator.alloc 0 (in this case, malloc() will be called) - .allocator.free 0 (in this case, free() will be called) + .allocator.alloc_fn 0 (in this case, malloc() will be called) + .allocator.free_fn 0 (in this case, free() will be called) .allocator.user_data 0 .context.color_format: default value depends on selected backend: @@ -3424,6 +3428,12 @@ typedef struct sg_wgpu_context_desc { void* user_data; } sg_wgpu_context_desc; +typedef struct sg_gl_context_desc { + uint32_t (*default_framebuffer_cb)(void); + uint32_t (*default_framebuffer_userdata_cb)(void*); + void* user_data; +} sg_gl_context_desc; + typedef struct sg_context_desc { sg_pixel_format color_format; sg_pixel_format depth_format; @@ -3431,6 +3441,7 @@ typedef struct sg_context_desc { sg_metal_context_desc metal; sg_d3d11_context_desc d3d11; sg_wgpu_context_desc wgpu; + sg_gl_context_desc gl; } sg_context_desc; /* @@ -3452,12 +3463,12 @@ typedef struct sg_commit_listener { Used in sg_desc to provide custom memory-alloc and -free functions to sokol_gfx.h. If memory management should be overridden, both the - alloc and free function must be provided (e.g. it's not valid to + alloc_fn and free_fn function must be provided (e.g. it's not valid to override one function but not the other). */ typedef struct sg_allocator { - void* (*alloc)(size_t size, void* user_data); - void (*free)(void* ptr, void* user_data); + void* (*alloc_fn)(size_t size, void* user_data); + void (*free_fn)(void* ptr, void* user_data); void* user_data; } sg_allocator; @@ -4978,8 +4989,7 @@ typedef struct { typedef struct { bool valid; - bool has_unified_memory; - bool force_managed_storage_mode; + bool use_shared_storage_mode; const void*(*renderpass_descriptor_cb)(void); const void*(*renderpass_descriptor_userdata_cb)(void*); const void*(*drawable_cb)(void); @@ -5317,8 +5327,8 @@ _SOKOL_PRIVATE void _sg_clear(void* ptr, size_t size) { _SOKOL_PRIVATE void* _sg_malloc(size_t size) { SOKOL_ASSERT(size > 0); void* ptr; - if (_sg.desc.allocator.alloc) { - ptr = _sg.desc.allocator.alloc(size, _sg.desc.allocator.user_data); + if (_sg.desc.allocator.alloc_fn) { + ptr = _sg.desc.allocator.alloc_fn(size, _sg.desc.allocator.user_data); } else { ptr = malloc(size); } @@ -5335,8 +5345,8 @@ _SOKOL_PRIVATE void* _sg_malloc_clear(size_t size) { } _SOKOL_PRIVATE void _sg_free(void* ptr) { - if (_sg.desc.allocator.free) { - _sg.desc.allocator.free(ptr, _sg.desc.allocator.user_data); + if (_sg.desc.allocator.free_fn) { + _sg.desc.allocator.free_fn(ptr, _sg.desc.allocator.user_data); } else { free(ptr); } @@ -7308,6 +7318,8 @@ _SOKOL_PRIVATE void _sg_gl_reset_state_cache(void) { _SOKOL_PRIVATE void _sg_gl_setup_backend(const sg_desc* desc) { _SOKOL_UNUSED(desc); + SOKOL_ASSERT(desc->context.gl.default_framebuffer_cb == 0 || desc->context.gl.default_framebuffer_userdata_cb == 0); + // assumes that _sg.gl is already zero-initialized _sg.gl.valid = true; @@ -7798,11 +7810,13 @@ _SOKOL_PRIVATE void _sg_gl_fb_attach_texture(const _sg_gl_attachment_t* gl_att, SOKOL_ASSERT(img); const GLuint gl_tex = img->gl.tex[0]; SOKOL_ASSERT(gl_tex); + const GLuint gl_target = img->gl.target; + SOKOL_ASSERT(gl_target); const int mip_level = cmn_att->mip_level; const int slice = cmn_att->slice; switch (img->cmn.type) { case SG_IMAGETYPE_2D: - glFramebufferTexture2D(GL_FRAMEBUFFER, gl_att_type, GL_TEXTURE_2D, gl_tex, mip_level); + glFramebufferTexture2D(GL_FRAMEBUFFER, gl_att_type, gl_target, gl_tex, mip_level); break; case SG_IMAGETYPE_CUBE: glFramebufferTexture2D(GL_FRAMEBUFFER, gl_att_type, _sg_gl_cubeface_target(slice), gl_tex, mip_level); @@ -7994,6 +8008,12 @@ _SOKOL_PRIVATE void _sg_gl_begin_pass(_sg_pass_t* pass, const sg_pass_action* ac #if defined(SOKOL_GLCORE33) glDisable(GL_FRAMEBUFFER_SRGB); #endif + if (_sg.desc.context.gl.default_framebuffer_userdata_cb) { + _sg.gl.cur_context->default_framebuffer = _sg.desc.context.gl.default_framebuffer_userdata_cb(_sg.desc.context.gl.user_data); + } else if (_sg.desc.context.gl.default_framebuffer_cb) { + _sg.gl.cur_context->default_framebuffer = _sg.desc.context.gl.default_framebuffer_cb(); + } + glBindFramebuffer(GL_FRAMEBUFFER, _sg.gl.cur_context->default_framebuffer); } glViewport(0, 0, w, h); @@ -10576,12 +10596,13 @@ _SOKOL_PRIVATE MTLStoreAction _sg_mtl_store_action(sg_store_action a, bool resol _SOKOL_PRIVATE MTLResourceOptions _sg_mtl_resource_options_storage_mode_managed_or_shared(void) { #if defined(_SG_TARGET_MACOS) - if (_sg.mtl.force_managed_storage_mode || !_sg.mtl.has_unified_memory) { - return MTLResourceStorageModeManaged; - } else { + if (_sg.mtl.use_shared_storage_mode) { return MTLResourceStorageModeShared; + } else { + return MTLResourceStorageModeManaged; } #else + // MTLResourceStorageModeManaged is not even defined on iOS SDK return MTLResourceStorageModeShared; #endif } @@ -11046,16 +11067,20 @@ _SOKOL_PRIVATE void _sg_mtl_init_caps(void) { _sg.features.mrt_independent_write_mask = true; _sg.features.image_clamp_to_border = false; + #if (MAC_OS_X_VERSION_MAX_ALLOWED >= 120000) || (__IPHONE_OS_VERSION_MAX_ALLOWED >= 140000) if (@available(macOS 12.0, iOS 14.0, *)) { _sg.features.image_clamp_to_border = [_sg.mtl.device supportsFamily:MTLGPUFamilyApple7] || [_sg.mtl.device supportsFamily:MTLGPUFamilyApple8] || [_sg.mtl.device supportsFamily:MTLGPUFamilyMac2]; + #if (MAC_OS_X_VERSION_MAX_ALLOWED >= 130000) || (__IPHONE_OS_VERSION_MAX_ALLOWED >= 160000) if (!_sg.features.image_clamp_to_border) { if (@available(macOS 13.0, iOS 16.0, *)) { _sg.features.image_clamp_to_border = [_sg.mtl.device supportsFamily:MTLGPUFamilyMetal3]; } } + #endif } + #endif #if defined(_SG_TARGET_MACOS) _sg.limits.max_image_size_2d = 16 * 1024; @@ -11195,22 +11220,35 @@ _SOKOL_PRIVATE void _sg_mtl_setup_backend(const sg_desc* desc) { _sg.mtl.sem = dispatch_semaphore_create(SG_NUM_INFLIGHT_FRAMES); _sg.mtl.device = (__bridge id<MTLDevice>) desc->context.metal.device; _sg.mtl.cmd_queue = [_sg.mtl.device newCommandQueue]; + for (int i = 0; i < SG_NUM_INFLIGHT_FRAMES; i++) { _sg.mtl.uniform_buffers[i] = [_sg.mtl.device newBufferWithLength:(NSUInteger)_sg.mtl.ub_size options:MTLResourceCPUCacheModeWriteCombined|MTLResourceStorageModeShared ]; + #if defined(SOKOL_DEBUG) + _sg.mtl.uniform_buffers[i].label = [NSString stringWithFormat:@"sg-uniform-buffer.%d", i]; + #endif } - if (@available(macOS 10.15, iOS 13.0, *)) { - _sg.mtl.has_unified_memory = _sg.mtl.device.hasUnifiedMemory; + + if (desc->mtl_force_managed_storage_mode) { + _sg.mtl.use_shared_storage_mode = false; + } else if (@available(macOS 10.15, iOS 13.0, *)) { + // on Intel Macs, always use managed resources even though the + // device says it supports unified memory (because of texture restrictions) + const bool is_apple_gpu = [_sg.mtl.device supportsFamily:MTLGPUFamilyApple1]; + if (!is_apple_gpu) { + _sg.mtl.use_shared_storage_mode = false; + } else { + _sg.mtl.use_shared_storage_mode = true; + } } else { #if defined(_SG_TARGET_MACOS) - _sg.mtl.has_unified_memory = false; + _sg.mtl.use_shared_storage_mode = false; #else - _sg.mtl.has_unified_memory = true; + _sg.mtl.use_shared_storage_mode = true; #endif } - _sg.mtl.force_managed_storage_mode = desc->mtl_force_managed_storage_mode; _sg_mtl_init_caps(); } @@ -11294,7 +11332,16 @@ _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_buffer(_sg_buffer_t* buf, const } else { mtl_buf = [_sg.mtl.device newBufferWithLength:(NSUInteger)buf->cmn.size options:mtl_options]; } + if (nil == mtl_buf) { + _SG_ERROR(METAL_CREATE_BUFFER_FAILED); + return SG_RESOURCESTATE_FAILED; + } } + #if defined(SOKOL_DEBUG) + if (desc->label) { + mtl_buf.label = [NSString stringWithFormat:@"%s.%d", desc->label, slot]; + } + #endif buf->mtl.buf[slot] = _sg_mtl_add_resource(mtl_buf); _SG_OBJC_RELEASE(mtl_buf); } @@ -11434,10 +11481,20 @@ _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_image(_sg_image_t* img, const sg mtl_tex = (__bridge id<MTLTexture>) desc->mtl_textures[slot]; } else { mtl_tex = [_sg.mtl.device newTextureWithDescriptor:mtl_desc]; + if (nil == mtl_tex) { + _SG_OBJC_RELEASE(mtl_desc); + _SG_ERROR(METAL_CREATE_TEXTURE_FAILED); + return SG_RESOURCESTATE_FAILED; + } if ((img->cmn.usage == SG_USAGE_IMMUTABLE) && !img->cmn.render_target) { _sg_mtl_copy_image_data(img, mtl_tex, &desc->data); } } + #if defined(SOKOL_DEBUG) + if (desc->label) { + mtl_tex.label = [NSString stringWithFormat:@"%s.%d", desc->label, slot]; + } + #endif img->mtl.tex[slot] = _sg_mtl_add_resource(mtl_tex); _SG_OBJC_RELEASE(mtl_tex); } @@ -11479,8 +11536,17 @@ _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_sampler(_sg_sampler_t* smp, cons mtl_desc.maxAnisotropy = desc->max_anisotropy; mtl_desc.normalizedCoordinates = YES; mtl_desc.compareFunction = _sg_mtl_compare_func(desc->compare); + #if defined(SOKOL_DEBUG) + if (desc->label) { + mtl_desc.label = [NSString stringWithUTF8String:desc->label]; + } + #endif mtl_smp = [_sg.mtl.device newSamplerStateWithDescriptor:mtl_desc]; _SG_OBJC_RELEASE(mtl_desc); + if (nil == mtl_smp) { + _SG_ERROR(METAL_CREATE_SAMPLER_FAILED); + return SG_RESOURCESTATE_FAILED; + } } smp->mtl.sampler_state = _sg_mtl_add_resource(mtl_smp); _SG_OBJC_RELEASE(mtl_smp); @@ -11558,6 +11624,12 @@ _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_shader(_sg_shader_t* shd, const _SG_ERROR(METAL_FRAGMENT_SHADER_ENTRY_NOT_FOUND); goto failed; } + #if defined(SOKOL_DEBUG) + if (desc->label) { + vs_lib.label = [NSString stringWithFormat:@"%s.vs", desc->label]; + fs_lib.label = [NSString stringWithFormat:@"%s.fs", desc->label]; + } + #endif // it is legal to call _sg_mtl_add_resource with a nil value, this will return a special 0xFFFFFFFF index shd->mtl.stage[SG_SHADERSTAGE_VS].mtl_lib = _sg_mtl_add_resource(vs_lib); _SG_OBJC_RELEASE(vs_lib); @@ -11673,6 +11745,11 @@ _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_pipeline(_sg_pipeline_t* pip, _s rp_desc.colorAttachments[i].sourceAlphaBlendFactor = _sg_mtl_blend_factor(cs->blend.src_factor_alpha); rp_desc.colorAttachments[i].sourceRGBBlendFactor = _sg_mtl_blend_factor(cs->blend.src_factor_rgb); } + #if defined(SOKOL_DEBUG) + if (desc->label) { + rp_desc.label = [NSString stringWithFormat:@"%s", desc->label]; + } + #endif NSError* err = NULL; id<MTLRenderPipelineState> mtl_rps = [_sg.mtl.device newRenderPipelineStateWithDescriptor:rp_desc error:&err]; _SG_OBJC_RELEASE(rp_desc); @@ -11682,6 +11759,8 @@ _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_pipeline(_sg_pipeline_t* pip, _s _SG_LOGMSG(METAL_CREATE_RPS_OUTPUT, [err.localizedDescription UTF8String]); return SG_RESOURCESTATE_FAILED; } + pip->mtl.rps = _sg_mtl_add_resource(mtl_rps); + _SG_OBJC_RELEASE(mtl_rps); // depth-stencil-state MTLDepthStencilDescriptor* ds_desc = [[MTLDepthStencilDescriptor alloc] init]; @@ -11705,11 +11784,17 @@ _SOKOL_PRIVATE sg_resource_state _sg_mtl_create_pipeline(_sg_pipeline_t* pip, _s ds_desc.frontFaceStencil.readMask = desc->stencil.read_mask; ds_desc.frontFaceStencil.writeMask = desc->stencil.write_mask; } - // FIXME: can this actually fail? + #if defined(SOKOL_DEBUG) + if (desc->label) { + ds_desc.label = [NSString stringWithFormat:@"%s.dss", desc->label]; + } + #endif id<MTLDepthStencilState> mtl_dss = [_sg.mtl.device newDepthStencilStateWithDescriptor:ds_desc]; _SG_OBJC_RELEASE(ds_desc); - pip->mtl.rps = _sg_mtl_add_resource(mtl_rps); - _SG_OBJC_RELEASE(mtl_rps); + if (nil == mtl_dss) { + _SG_ERROR(METAL_CREATE_DSS_FAILED); + return SG_RESOURCESTATE_FAILED; + } pip->mtl.dss = _sg_mtl_add_resource(mtl_dss); _SG_OBJC_RELEASE(mtl_dss); return SG_RESOURCESTATE_VALID; @@ -12249,6 +12334,19 @@ _SOKOL_PRIVATE void _sg_mtl_update_image(_sg_image_t* img, const sg_image_data* _sg_mtl_copy_image_data(img, mtl_tex, data); } +_SOKOL_PRIVATE void _sg_mtl_push_debug_group(const char* name) { + SOKOL_ASSERT(name); + if (_sg.mtl.cmd_encoder) { + [_sg.mtl.cmd_encoder pushDebugGroup:[NSString stringWithUTF8String:name]]; + } +} + +_SOKOL_PRIVATE void _sg_mtl_pop_debug_group(void) { + if (_sg.mtl.cmd_encoder) { + [_sg.mtl.cmd_encoder popDebugGroup]; + } +} + // ██ ██ ███████ ██████ ██████ ██████ ██ ██ ██████ █████ ██████ ██ ██ ███████ ███ ██ ██████ // ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ // ██ █ ██ █████ ██████ ██ ███ ██████ ██ ██ ██████ ███████ ██ █████ █████ ██ ██ ██ ██ ██ @@ -14592,6 +14690,20 @@ static inline void _sg_update_image(_sg_image_t* img, const sg_image_data* data) #endif } +static inline void _sg_push_debug_group(const char* name) { + #if defined(SOKOL_METAL) + _sg_mtl_push_debug_group(name); + #else + _SOKOL_UNUSED(name); + #endif +} + +static inline void _sg_pop_debug_group(void) { + #if defined(SOKOL_METAL) + _sg_mtl_pop_debug_group(); + #endif +} + // ██████ ██████ ██████ ██ // ██ ██ ██ ██ ██ ██ ██ // ██████ ██ ██ ██ ██ ██ @@ -15769,7 +15881,7 @@ _SOKOL_PRIVATE bool _sg_validate_apply_uniforms(sg_shader_stage stage_index, int const _sg_shader_stage_t* stage = &pip->shader->cmn.stage[stage_index]; _SG_VALIDATE(ub_index < stage->num_uniform_blocks, VALIDATE_AUB_NO_UB_AT_SLOT); - // check that the provided data size doesn't exceed the uniform block size + // check that the provided data size matches the uniform block size _SG_VALIDATE(data->size == stage->uniform_blocks[ub_index].size, VALIDATE_AUB_SIZE); return _sg_validate_end(); @@ -16431,7 +16543,7 @@ _SOKOL_PRIVATE sg_desc _sg_desc_defaults(const sg_desc* desc) { SOKOL_API_IMPL void sg_setup(const sg_desc* desc) { SOKOL_ASSERT(desc); SOKOL_ASSERT((desc->_start_canary == 0) && (desc->_end_canary == 0)); - SOKOL_ASSERT((desc->allocator.alloc && desc->allocator.free) || (!desc->allocator.alloc && !desc->allocator.free)); + SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); _SG_CLEAR_ARC_STRUCT(_sg_state_t, _sg); _sg.desc = _sg_desc_defaults(desc); _sg_setup_pools(&_sg.pools, &_sg.desc); @@ -17530,12 +17642,13 @@ SOKOL_API_IMPL void sg_update_image(sg_image img_id, const sg_image_data* data) SOKOL_API_IMPL void sg_push_debug_group(const char* name) { SOKOL_ASSERT(_sg.valid); SOKOL_ASSERT(name); - _SOKOL_UNUSED(name); + _sg_push_debug_group(name); _SG_TRACE_ARGS(push_debug_group, name); } SOKOL_API_IMPL void sg_pop_debug_group(void) { SOKOL_ASSERT(_sg.valid); + _sg_pop_debug_group(); _SG_TRACE_NOARGS(pop_debug_group); } diff --git a/tests/functional/sokol_args_test.c b/tests/functional/sokol_args_test.c index 097395f2..e2928d10 100644 --- a/tests/functional/sokol_args_test.c +++ b/tests/functional/sokol_args_test.c @@ -252,3 +252,51 @@ UTEST(sokol_args, escape_sequence) { TSTR(sargs_value_at(2), "val2\tval3"); sargs_shutdown(); } + +static char* argv_11[] = { "exe_name", "kvp0 kvp1", "kvp2 = val2", "kvp3", "kvp4=val4" }; +UTEST(sokol_args, key_only_args) { + sargs_setup(&(sargs_desc){ + .argc = NUM_ARGS(argv_11), + .argv = argv_11, + }); + T(sargs_isvalid()); + T(sargs_num_args() == 5); + T(0 == sargs_find("kvp0")); + T(1 == sargs_find("kvp1")); + T(2 == sargs_find("kvp2")); + T(3 == sargs_find("kvp3")); + T(4 == sargs_find("kvp4")) + T(-1 == sargs_find("kvp5")); + T(-1 == sargs_find("val2")); + T(-1 == sargs_find("val4")); + T(sargs_exists("kvp0")); + T(sargs_exists("kvp1")); + T(sargs_exists("kvp2")); + T(sargs_exists("kvp3")); + T(sargs_exists("kvp4")); + T(!sargs_exists("kvp5")); + TSTR(sargs_value("kvp0"), ""); + TSTR(sargs_value("kvp1"), ""); + TSTR(sargs_value("kvp2"), "val2"); + TSTR(sargs_value("kvp3"), ""); + TSTR(sargs_value("kvp4"), "val4"); + TSTR(sargs_value("kvp5"), ""); + TSTR(sargs_value_def("kvp0", "bla0"), "bla0"); + TSTR(sargs_value_def("kvp1", "bla1"), "bla1"); + TSTR(sargs_value_def("kvp2", "bla2"), "val2"); + TSTR(sargs_value_def("kvp3", "bla3"), "bla3"); + TSTR(sargs_value_def("kvp4", "bla4"), "val4"); + TSTR(sargs_value_def("kvp5", "bla5"), "bla5"); + TSTR(sargs_key_at(0), "kvp0"); + TSTR(sargs_key_at(1), "kvp1"); + TSTR(sargs_key_at(2), "kvp2"); + TSTR(sargs_key_at(3), "kvp3"); + TSTR(sargs_key_at(4), "kvp4"); + TSTR(sargs_key_at(5), ""); + TSTR(sargs_value_at(0), ""); + TSTR(sargs_value_at(1), ""); + TSTR(sargs_value_at(2), "val2"); + TSTR(sargs_value_at(3), ""); + TSTR(sargs_value_at(4), "val4"); + TSTR(sargs_value_at(5), ""); +} diff --git a/tests/functional/sokol_fetch_test.c b/tests/functional/sokol_fetch_test.c index 417979d5..8318a9e2 100644 --- a/tests/functional/sokol_fetch_test.c +++ b/tests/functional/sokol_fetch_test.c @@ -612,9 +612,9 @@ UTEST(sokol_fetch, load_file_chunked) { /* load N big files in small chunks interleaved on the same channel via lanes */ #define LOAD_FILE_LANES_NUM_LANES (4) -uint8_t load_file_lanes_chunk_buf[LOAD_FILE_LANES_NUM_LANES][8192]; -uint8_t load_file_lanes_content[LOAD_FILE_LANES_NUM_LANES][500000]; -int load_file_lanes_passed[LOAD_FILE_LANES_NUM_LANES]; +static uint8_t load_file_lanes_chunk_buf[LOAD_FILE_LANES_NUM_LANES][8192]; +static uint8_t load_file_lanes_content[LOAD_FILE_LANES_NUM_LANES][500000]; +static int load_file_lanes_passed[LOAD_FILE_LANES_NUM_LANES]; static void load_file_lanes_callback(const sfetch_response_t* response) { assert((response->channel == 0) && (response->lane < LOAD_FILE_LANES_NUM_LANES)); if (response->fetched) { @@ -669,9 +669,9 @@ UTEST(sokol_fetch, load_file_lanes) { #define LOAD_FILE_THROTTLE_NUM_PASSES (3) #define LOAD_FILE_THROTTLE_NUM_REQUESTS (12) // lanes * passes -uint8_t load_file_throttle_chunk_buf[LOAD_FILE_THROTTLE_NUM_LANES][128000]; -uint8_t load_file_throttle_content[LOAD_FILE_THROTTLE_NUM_PASSES][LOAD_FILE_THROTTLE_NUM_LANES][500000]; -int load_file_throttle_passed[LOAD_FILE_THROTTLE_NUM_LANES]; +static uint8_t load_file_throttle_chunk_buf[LOAD_FILE_THROTTLE_NUM_LANES][128000]; +static uint8_t load_file_throttle_content[LOAD_FILE_THROTTLE_NUM_PASSES][LOAD_FILE_THROTTLE_NUM_LANES][500000]; +static int load_file_throttle_passed[LOAD_FILE_THROTTLE_NUM_LANES]; static void load_file_throttle_callback(const sfetch_response_t* response) { assert((response->channel == 0) && (response->lane < LOAD_FILE_LANES_NUM_LANES)); @@ -733,8 +733,8 @@ UTEST(sokol_fetch, load_file_throttle) { /* test parallel fetches on multiple channels */ #define LOAD_CHANNEL_NUM_CHANNELS (16) -uint8_t load_channel_buf[LOAD_CHANNEL_NUM_CHANNELS][500000]; -bool load_channel_passed[LOAD_CHANNEL_NUM_CHANNELS]; +static uint8_t load_channel_buf[LOAD_CHANNEL_NUM_CHANNELS][500000]; +static bool load_channel_passed[LOAD_CHANNEL_NUM_CHANNELS]; void load_channel_callback(const sfetch_response_t* response) { assert(response->channel < LOAD_CHANNEL_NUM_CHANNELS); @@ -781,15 +781,13 @@ UTEST(sokol_fetch, load_channel) { sfetch_shutdown(); } -bool load_file_cancel_passed = false; -void load_file_cancel_callback(const sfetch_response_t* response) { +static bool load_file_cancel_passed = false; +static void load_file_cancel_callback(const sfetch_response_t* response) { if (response->dispatched) { sfetch_cancel(response->handle); } - if (response->failed) { - if (response->cancelled && response->finished && (response->error_code == SFETCH_ERROR_CANCELLED)) { - load_file_cancel_passed = true; - } + if (response->cancelled && response->finished && response->failed && (response->error_code == SFETCH_ERROR_CANCELLED)) { + load_file_cancel_passed = true; } } @@ -811,3 +809,54 @@ UTEST(sokol_fetch, load_file_cancel) { T(load_file_cancel_passed); sfetch_shutdown(); } + +static bool load_file_cancel_before_dispatch_passed = false; +static void load_file_cancel_before_dispatch_callback(const sfetch_response_t* response) { + // cancelled, finished, failed and error code must all be set + if (response->cancelled && response->finished && response->failed && (response->error_code == SFETCH_ERROR_CANCELLED)) { + load_file_cancel_before_dispatch_passed = true; + } +} + +UTEST(sokol_fetch, load_file_cancel_before_dispatch) { + sfetch_setup(&(sfetch_desc_t){ + .num_channels = 1, + }); + sfetch_handle_t h = sfetch_send(&(sfetch_request_t){ + .path = "comsi.s3m", + .callback = load_file_cancel_before_dispatch_callback, + }); + sfetch_cancel(h); + sfetch_dowork(); + T(load_file_cancel_before_dispatch_passed); + sfetch_shutdown(); +} + +static bool load_file_cancel_after_dispatch_passed = false; +static void load_file_cancel_after_dispatch_callback(const sfetch_response_t* response) { + // when cancelled, then finished, failed and error code must all be set + if (response->cancelled && response->finished && response->failed && (response->error_code == SFETCH_ERROR_CANCELLED)) { + load_file_cancel_after_dispatch_passed = true; + } +} + +UTEST(sokol_fetch, load_file_cancel_after_dispatch) { + sfetch_setup(&(sfetch_desc_t){ + .num_channels = 1, + }); + sfetch_handle_t h = sfetch_send(&(sfetch_request_t){ + .path = "comsi.s3m", + .callback = load_file_cancel_after_dispatch_callback, + .buffer = SFETCH_RANGE(load_file_buf), + }); + int frame_count = 0; + const int max_frames = 10000; + while (sfetch_handle_valid(h) && (frame_count++ < max_frames)) { + sfetch_dowork(); + sfetch_cancel(h); + sleep_ms(1); + } + T(frame_count < max_frames); + T(load_file_cancel_after_dispatch_passed); + sfetch_shutdown(); +} diff --git a/util/sokol_debugtext.h b/util/sokol_debugtext.h index 981cab46..09da6019 100644 --- a/util/sokol_debugtext.h +++ b/util/sokol_debugtext.h @@ -427,8 +427,8 @@ sdtx_setup(&(sdtx_desc_t){ // ... .allocator = { - .alloc = my_alloc, - .free = my_free, + .alloc_fn = my_alloc, + .free_fn = my_free, .user_data = ...; } }); @@ -658,12 +658,12 @@ typedef struct sdtx_context_desc_t { Used in sdtx_desc_t to provide custom memory-alloc and -free functions to sokol_debugtext.h. If memory management should be overridden, both the - alloc and free function must be provided (e.g. it's not valid to + alloc_fn and free_fn function must be provided (e.g. it's not valid to override one function but not the other). */ typedef struct sdtx_allocator_t { - void* (*alloc)(size_t size, void* user_data); - void (*free)(void* ptr, void* user_data); + void* (*alloc_fn)(size_t size, void* user_data); + void (*free_fn)(void* ptr, void* user_data); void* user_data; } sdtx_allocator_t; @@ -3598,8 +3598,8 @@ static void _sdtx_clear(void* ptr, size_t size) { static void* _sdtx_malloc(size_t size) { SOKOL_ASSERT(size > 0); void* ptr; - if (_sdtx.desc.allocator.alloc) { - ptr = _sdtx.desc.allocator.alloc(size, _sdtx.desc.allocator.user_data); + if (_sdtx.desc.allocator.alloc_fn) { + ptr = _sdtx.desc.allocator.alloc_fn(size, _sdtx.desc.allocator.user_data); } else { ptr = malloc(size); } @@ -3616,8 +3616,8 @@ static void* _sdtx_malloc_clear(size_t size) { } static void _sdtx_free(void* ptr) { - if (_sdtx.desc.allocator.free) { - _sdtx.desc.allocator.free(ptr, _sdtx.desc.allocator.user_data); + if (_sdtx.desc.allocator.free_fn) { + _sdtx.desc.allocator.free_fn(ptr, _sdtx.desc.allocator.user_data); } else { free(ptr); } @@ -4197,7 +4197,7 @@ SOKOL_API_IMPL void _sdtx_draw_layer(_sdtx_context_t* ctx, int layer_id) { static sdtx_desc_t _sdtx_desc_defaults(const sdtx_desc_t* desc) { - SOKOL_ASSERT((desc->allocator.alloc && desc->allocator.free) || (!desc->allocator.alloc && !desc->allocator.free)); + SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); sdtx_desc_t res = *desc; res.context_pool_size = _sdtx_def(res.context_pool_size, _SDTX_DEFAULT_CONTEXT_POOL_SIZE); res.printf_buf_size = _sdtx_def(res.printf_buf_size, _SDTX_DEFAULT_PRINTF_BUF_SIZE); diff --git a/util/sokol_fontstash.h b/util/sokol_fontstash.h index c6e9b5f6..048c8215 100644 --- a/util/sokol_fontstash.h +++ b/util/sokol_fontstash.h @@ -147,8 +147,8 @@ FONScontext* fons_context = sfons_create(&(sfons_desc_t){ ... .allocator = { - .alloc = my_alloc, - .free = my_free, + .alloc_fn = my_alloc, + .free_fn = my_free, .user_data = ..., } }); @@ -213,15 +213,15 @@ extern "C" { Used in sfons_desc_t to provide custom memory-alloc and -free functions to sokol_fontstash.h. If memory management should be overridden, both the - alloc and free function must be provided (e.g. it's not valid to + alloc_fn and free_fn function must be provided (e.g. it's not valid to override one function but not the other). NOTE that this does not affect memory allocation calls inside fontstash.h */ typedef struct sfons_allocator_t { - void* (*alloc)(size_t size, void* user_data); - void (*free)(void* ptr, void* user_data); + void* (*alloc_fn)(size_t size, void* user_data); + void (*free_fn)(void* ptr, void* user_data); void* user_data; } sfons_allocator_t; @@ -1542,8 +1542,8 @@ static void _sfons_clear(void* ptr, size_t size) { static void* _sfons_malloc(const sfons_allocator_t* allocator, size_t size) { SOKOL_ASSERT(allocator && (size > 0)); void* ptr; - if (allocator->alloc) { - ptr = allocator->alloc(size, allocator->user_data); + if (allocator->alloc_fn) { + ptr = allocator->alloc_fn(size, allocator->user_data); } else { ptr = malloc(size); } @@ -1559,8 +1559,8 @@ static void* _sfons_malloc_clear(const sfons_allocator_t* allocator, size_t size static void _sfons_free(const sfons_allocator_t* allocator, void* ptr) { SOKOL_ASSERT(allocator); - if (allocator->free) { - allocator->free(ptr, allocator->user_data); + if (allocator->free_fn) { + allocator->free_fn(ptr, allocator->user_data); } else { free(ptr); } @@ -1739,7 +1739,7 @@ static sfons_desc_t _sfons_desc_defaults(const sfons_desc_t* desc) { SOKOL_API_IMPL FONScontext* sfons_create(const sfons_desc_t* desc) { SOKOL_ASSERT(desc); - SOKOL_ASSERT((desc->allocator.alloc && desc->allocator.free) || (!desc->allocator.alloc && !desc->allocator.free)); + SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); _sfons_t* sfons = (_sfons_t*) _sfons_malloc_clear(&desc->allocator, sizeof(_sfons_t)); sfons->desc = _sfons_desc_defaults(desc); FONSparams params; diff --git a/util/sokol_gfx_imgui.h b/util/sokol_gfx_imgui.h index 4d29a741..ec919384 100644 --- a/util/sokol_gfx_imgui.h +++ b/util/sokol_gfx_imgui.h @@ -73,8 +73,8 @@ sg_imgui_init(&sg_imgui, &(sg_imgui_desc_t){ .allocator = { - .alloc = my_malloc, - .free = my_free, + .alloc_fn = my_malloc, + .free_fn = my_free, } }); @@ -179,8 +179,8 @@ sg_imgui_init(&(&ctx, &(sg_imgui_desc_t){ // ... .allocator = { - .alloc = my_alloc, - .free = my_free, + .alloc_fn = my_alloc, + .free_fn = my_free, .user_data = ...; } }); @@ -736,8 +736,8 @@ typedef struct sg_imgui_frame_stats_t { override one function but not the other). */ typedef struct sg_imgui_allocator_t { - void* (*alloc)(size_t size, void* user_data); - void (*free)(void* ptr, void* user_data); + void* (*alloc_fn)(size_t size, void* user_data); + void (*free_fn)(void* ptr, void* user_data); void* user_data; } sg_imgui_allocator_t; @@ -972,8 +972,8 @@ _SOKOL_PRIVATE void _sg_imgui_clear(void* ptr, size_t size) { _SOKOL_PRIVATE void* _sg_imgui_malloc(const sg_imgui_allocator_t* allocator, size_t size) { SOKOL_ASSERT(allocator && (size > 0)); void* ptr; - if (allocator->alloc) { - ptr = allocator->alloc(size, allocator->user_data); + if (allocator->alloc_fn) { + ptr = allocator->alloc_fn(size, allocator->user_data); } else { ptr = malloc(size); } @@ -989,8 +989,8 @@ _SOKOL_PRIVATE void* _sg_imgui_malloc_clear(const sg_imgui_allocator_t* allocato _SOKOL_PRIVATE void _sg_imgui_free(const sg_imgui_allocator_t* allocator, void* ptr) { SOKOL_ASSERT(allocator); - if (allocator->free) { - allocator->free(ptr, allocator->user_data); + if (allocator->free_fn) { + allocator->free_fn(ptr, allocator->user_data); } else { free(ptr); } @@ -4343,7 +4343,7 @@ _SOKOL_PRIVATE void _sg_imgui_draw_frame_stats_panel(sg_imgui_t* ctx) { #define _sg_imgui_def(val, def) (((val) == 0) ? (def) : (val)) _SOKOL_PRIVATE sg_imgui_desc_t _sg_imgui_desc_defaults(const sg_imgui_desc_t* desc) { - SOKOL_ASSERT((desc->allocator.alloc && desc->allocator.free) || (!desc->allocator.alloc && !desc->allocator.free)); + SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); sg_imgui_desc_t res = *desc; // FIXME: any additional default overrides would go here return res; diff --git a/util/sokol_gl.h b/util/sokol_gl.h index 32cc07f5..d1a3c4e1 100644 --- a/util/sokol_gl.h +++ b/util/sokol_gl.h @@ -606,8 +606,8 @@ sgl_setup(&(sgl_desc_t){ // ... .allocator = { - .alloc = my_alloc, - .free = my_free, + .alloc_fn = my_alloc, + .free_fn = my_free, .user_data = ...; } }); @@ -796,8 +796,8 @@ typedef struct sgl_context_desc_t { override one function but not the other). */ typedef struct sgl_allocator_t { - void* (*alloc)(size_t size, void* user_data); - void (*free)(void* ptr, void* user_data); + void* (*alloc_fn)(size_t size, void* user_data); + void (*free_fn)(void* ptr, void* user_data); void* user_data; } sgl_allocator_t; @@ -2437,8 +2437,8 @@ static void _sgl_clear(void* ptr, size_t size) { static void* _sgl_malloc(size_t size) { SOKOL_ASSERT(size > 0); void* ptr; - if (_sgl.desc.allocator.alloc) { - ptr = _sgl.desc.allocator.alloc(size, _sgl.desc.allocator.user_data); + if (_sgl.desc.allocator.alloc_fn) { + ptr = _sgl.desc.allocator.alloc_fn(size, _sgl.desc.allocator.user_data); } else { ptr = malloc(size); } @@ -2455,8 +2455,8 @@ static void* _sgl_malloc_clear(size_t size) { } static void _sgl_free(void* ptr) { - if (_sgl.desc.allocator.free) { - _sgl.desc.allocator.free(ptr, _sgl.desc.allocator.user_data); + if (_sgl.desc.allocator.free_fn) { + _sgl.desc.allocator.free_fn(ptr, _sgl.desc.allocator.user_data); } else { free(ptr); } @@ -3217,7 +3217,7 @@ static _sgl_matrix_t* _sgl_matrix(_sgl_context_t* ctx) { // return sg_context_desc_t with patched defaults static sgl_desc_t _sgl_desc_defaults(const sgl_desc_t* desc) { - SOKOL_ASSERT((desc->allocator.alloc && desc->allocator.free) || (!desc->allocator.alloc && !desc->allocator.free)); + SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); sgl_desc_t res = *desc; res.max_vertices = _sgl_def(desc->max_vertices, _SGL_DEFAULT_MAX_VERTICES); res.max_commands = _sgl_def(desc->max_commands, _SGL_DEFAULT_MAX_COMMANDS); diff --git a/util/sokol_imgui.h b/util/sokol_imgui.h index b64dda44..83af392e 100644 --- a/util/sokol_imgui.h +++ b/util/sokol_imgui.h @@ -288,8 +288,8 @@ simgui_setup(&(simgui_desc_t){ // ... .allocator = { - .alloc = my_alloc, - .free = my_free, + .alloc_fn = my_alloc, + .free_fn = my_free, .user_data = ...; } }); @@ -467,12 +467,12 @@ typedef enum simgui_log_item_t { Used in simgui_desc_t to provide custom memory-alloc and -free functions to sokol_imgui.h. If memory management should be overridden, both the - alloc and free function must be provided (e.g. it's not valid to + alloc_fn and free_fn function must be provided (e.g. it's not valid to override one function but not the other). */ typedef struct simgui_allocator_t { - void* (*alloc)(size_t size, void* user_data); - void (*free)(void* ptr, void* user_data); + void* (*alloc_fn)(size_t size, void* user_data); + void (*free_fn)(void* ptr, void* user_data); void* user_data; } simgui_allocator_t; @@ -1903,8 +1903,8 @@ static void _simgui_clear(void* ptr, size_t size) { static void* _simgui_malloc(size_t size) { SOKOL_ASSERT(size > 0); void* ptr; - if (_simgui.desc.allocator.alloc) { - ptr = _simgui.desc.allocator.alloc(size, _simgui.desc.allocator.user_data); + if (_simgui.desc.allocator.alloc_fn) { + ptr = _simgui.desc.allocator.alloc_fn(size, _simgui.desc.allocator.user_data); } else { ptr = malloc(size); } @@ -1921,8 +1921,8 @@ static void* _simgui_malloc_clear(size_t size) { } static void _simgui_free(void* ptr) { - if (_simgui.desc.allocator.free) { - _simgui.desc.allocator.free(ptr, _simgui.desc.allocator.user_data); + if (_simgui.desc.allocator.free_fn) { + _simgui.desc.allocator.free_fn(ptr, _simgui.desc.allocator.user_data); } else { free(ptr); } @@ -2143,7 +2143,7 @@ static bool _simgui_is_osx(void) { } static simgui_desc_t _simgui_desc_defaults(const simgui_desc_t* desc) { - SOKOL_ASSERT((desc->allocator.alloc && desc->allocator.free) || (!desc->allocator.alloc && !desc->allocator.free)); + SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); simgui_desc_t res = *desc; res.max_vertices = _simgui_def(res.max_vertices, 65536); res.image_pool_size = _simgui_def(res.image_pool_size, 256); diff --git a/util/sokol_memtrack.h b/util/sokol_memtrack.h index dc0b469f..47f70fca 100644 --- a/util/sokol_memtrack.h +++ b/util/sokol_memtrack.h @@ -27,8 +27,8 @@ sg_setup(&(sg_desc){ //... .allocator = { - .alloc = smemtrack_alloc, - .free = smemtrack_free, + .alloc_fn = smemtrack_alloc, + .free_fn = smemtrack_free, } }); diff --git a/util/sokol_nuklear.h b/util/sokol_nuklear.h index 74f6fee2..92db25e9 100644 --- a/util/sokol_nuklear.h +++ b/util/sokol_nuklear.h @@ -223,8 +223,8 @@ snk_setup(&(snk_desc_t){ // ... .allocator = { - .alloc = my_alloc, - .free = my_free, + .alloc_fn = my_alloc, + .free_fn = my_free, .user_data = ...; } }); @@ -383,12 +383,12 @@ typedef enum snk_log_item_t { Used in snk_desc_t to provide custom memory-alloc and -free functions to sokol_nuklear.h. If memory management should be overridden, both the - alloc and free function must be provided (e.g. it's not valid to + alloc_fn and free_fn function must be provided (e.g. it's not valid to override one function but not the other). */ typedef struct snk_allocator_t { - void* (*alloc)(size_t size, void* user_data); - void (*free)(void* ptr, void* user_data); + void* (*alloc_fn)(size_t size, void* user_data); + void (*free_fn)(void* ptr, void* user_data); void* user_data; } snk_allocator_t; @@ -1825,8 +1825,8 @@ static void _snk_clear(void* ptr, size_t size) { static void* _snk_malloc(size_t size) { SOKOL_ASSERT(size > 0); void* ptr; - if (_snuklear.desc.allocator.alloc) { - ptr = _snuklear.desc.allocator.alloc(size, _snuklear.desc.allocator.user_data); + if (_snuklear.desc.allocator.alloc_fn) { + ptr = _snuklear.desc.allocator.alloc_fn(size, _snuklear.desc.allocator.user_data); } else { ptr = malloc(size); } @@ -1843,8 +1843,8 @@ static void* _snk_malloc_clear(size_t size) { } static void _snk_free(void* ptr) { - if (_snuklear.desc.allocator.free) { - _snuklear.desc.allocator.free(ptr, _snuklear.desc.allocator.user_data); + if (_snuklear.desc.allocator.free_fn) { + _snuklear.desc.allocator.free_fn(ptr, _snuklear.desc.allocator.user_data); } else { free(ptr); } diff --git a/util/sokol_spine.h b/util/sokol_spine.h index 8bdbc87b..12203bcd 100644 --- a/util/sokol_spine.h +++ b/util/sokol_spine.h @@ -202,8 +202,8 @@ sspine_setup(&(sspine_desc){ .allocator = { - .alloc = my_alloc, - .free = my_free, + .alloc_fn = my_alloc, + .free_fn = my_free, .user_data = ..., }, .logger = { @@ -908,8 +908,8 @@ sspine_setup(&(sspine_desc){ // ... .allocator = { - .alloc = my_alloc, - .free = my_free, + .alloc_fn = my_alloc, + .free_fn = my_free, .user_data = ...; } }); @@ -1198,8 +1198,8 @@ typedef struct sspine_instance_desc { } sspine_instance_desc; typedef struct sspine_allocator { - void* (*alloc)(size_t size, void* user_data); - void (*free)(void* ptr, void* user_data); + void* (*alloc_fn)(size_t size, void* user_data); + void (*free_fn)(void* ptr, void* user_data); void* user_data; } sspine_allocator; @@ -3030,8 +3030,8 @@ static sspine_string _sspine_string(const char* cstr) { static void* _sspine_malloc(size_t size) { SOKOL_ASSERT(size > 0); void* ptr; - if (_sspine.desc.allocator.alloc) { - ptr = _sspine.desc.allocator.alloc(size, _sspine.desc.allocator.user_data); + if (_sspine.desc.allocator.alloc_fn) { + ptr = _sspine.desc.allocator.alloc_fn(size, _sspine.desc.allocator.user_data); } else { ptr = malloc(size); } @@ -3048,8 +3048,8 @@ static void* _sspine_malloc_clear(size_t size) { } static void _sspine_free(void* ptr) { - if (_sspine.desc.allocator.free) { - _sspine.desc.allocator.free(ptr, _sspine.desc.allocator.user_data); + if (_sspine.desc.allocator.free_fn) { + _sspine.desc.allocator.free_fn(ptr, _sspine.desc.allocator.user_data); } else { free(ptr); } @@ -4529,7 +4529,7 @@ static void _sspine_draw_layer(_sspine_context_t* ctx, int layer, const sspine_l // return sspine_desc with patched defaults static sspine_desc _sspine_desc_defaults(const sspine_desc* desc) { - SOKOL_ASSERT((desc->allocator.alloc && desc->allocator.free) || (!desc->allocator.alloc && !desc->allocator.free)); + SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn)); sspine_desc res = *desc; res.max_vertices = _sspine_def(desc->max_vertices, _SSPINE_DEFAULT_MAX_VERTICES); res.max_commands = _sspine_def(desc->max_commands, _SSPINE_DEFAULT_MAX_COMMANDS); |