aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/gen_bindings.yml2
-rw-r--r--CHANGELOG.md64
-rw-r--r--README.md2
-rw-r--r--bindgen/gen_rust.py2
-rw-r--r--bindgen/gen_zig.py2
-rw-r--r--sokol_app.h132
-rw-r--r--sokol_args.h128
-rw-r--r--sokol_audio.h26
-rw-r--r--sokol_fetch.h46
-rw-r--r--sokol_gfx.h171
-rw-r--r--tests/functional/sokol_args_test.c48
-rw-r--r--tests/functional/sokol_fetch_test.c77
-rw-r--r--util/sokol_debugtext.h20
-rw-r--r--util/sokol_fontstash.h20
-rw-r--r--util/sokol_gfx_imgui.h22
-rw-r--r--util/sokol_gl.h18
-rw-r--r--util/sokol_imgui.h20
-rw-r--r--util/sokol_memtrack.h4
-rw-r--r--util/sokol_nuklear.h18
-rw-r--r--util/sokol_spine.h22
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
diff --git a/README.md b/README.md
index 90eba58d..8349a6d8 100644
--- a/README.md
+++ b/README.md
@@ -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)
[![Build](/../../actions/workflows/main.yml/badge.svg)](/../../actions/workflows/main.yml) [![Bindings](/../../actions/workflows/gen_bindings.yml/badge.svg)](/../../actions/workflows/gen_bindings.yml) [![build](https://github.com/floooh/sokol-zig/actions/workflows/main.yml/badge.svg)](https://github.com/floooh/sokol-zig/actions/workflows/main.yml) [![build](https://github.com/floooh/sokol-nim/actions/workflows/main.yml/badge.svg)](https://github.com/floooh/sokol-nim/actions/workflows/main.yml) [![Odin](https://github.com/floooh/sokol-odin/actions/workflows/main.yml/badge.svg)](https://github.com/floooh/sokol-odin/actions/workflows/main.yml)[![Rust](https://github.com/floooh/sokol-rust/actions/workflows/main.yml/badge.svg)](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);