aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndre Weissflog <floooh@gmail.com>2025-11-19 13:29:12 +0100
committerAndre Weissflog <floooh@gmail.com>2025-11-19 13:29:12 +0100
commitbf8ebc538e6b6edf2d30892f657c4d3a34c040c6 (patch)
tree73fbe160da6fe6a48c1474ef244f1dee5f92c0cb
parent09a31200a381974c0ecd2b1e94be9f66f62a35a5 (diff)
parentb517f27e7d6bdefc7883110e42dab27cba800b50 (diff)
Merge branch 'master' into experimental-vulkan
-rw-r--r--.github/workflows/gen_bindings.yml10
-rw-r--r--.gitignore1
-rw-r--r--CHANGELOG.md73
-rw-r--r--README.md12
-rw-r--r--bindgen/README.md2
-rw-r--r--bindgen/gen_c3.py2
-rw-r--r--sokol_app.h59
-rw-r--r--sokol_args.h2
-rw-r--r--sokol_audio.h346
-rw-r--r--sokol_gfx.h78
-rw-r--r--tests/functional/sokol_args_test.c12
-rw-r--r--util/sokol_gfx_imgui.h4
-rw-r--r--util/sokol_imgui.h3
-rw-r--r--util/sokol_spine.h10
14 files changed, 562 insertions, 52 deletions
diff --git a/.github/workflows/gen_bindings.yml b/.github/workflows/gen_bindings.yml
index b7f6b4c4..713a7367 100644
--- a/.github/workflows/gen_bindings.yml
+++ b/.github/workflows/gen_bindings.yml
@@ -60,7 +60,7 @@ jobs:
path: bindgen/sokol-rust
- uses: actions/checkout@main
with:
- repository: kassane/sokol-d
+ repository: floooh/sokol-d
path: bindgen/sokol-d
- uses: actions/checkout@main
with:
@@ -131,7 +131,7 @@ jobs:
repository: floooh/sokol-zig
- uses: mlugg/setup-zig@v2
with:
- version: master
+ version: 0.15.2
- uses: actions/download-artifact@main
with:
name: ignore-me-zig
@@ -293,7 +293,7 @@ jobs:
steps:
- uses: actions/checkout@main
with:
- repository: kassane/sokol-d
+ repository: floooh/sokol-d
- uses: egor-tensin/vs-shell@v2 # get cl.exe (default for Windows)
- uses: dlang-community/setup-dlang@v2
with:
@@ -374,7 +374,7 @@ jobs:
repository: floooh/sokol-c3
- uses: radekm/setup-c3@v2
with:
- version: v0.7.5
+ version: v0.7.7
- uses: actions/download-artifact@main
with:
name: ignore-me-c3
@@ -488,7 +488,7 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
- repository: kassane/sokol-d
+ repository: floooh/sokol-d
ssh-key: ${{ secrets.GHACTIONS_D_PUSH }}
- uses: actions/download-artifact@v4
with:
diff --git a/.gitignore b/.gitignore
index 58627d69..f094f9b9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@ build/
.fips-*
*.pyc
#<fips
+**/.DS_Store
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e7968fa5..e87785cf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,78 @@
## Updates
+### 13-Nov-2025
+
+- sokol_audio.h gained a new backend for the Nintendo 3DS.
+ See PR https://github.com/floooh/sokol/pull/1372 for details.
+ Many thanks again to @CrackedPixel!
+
+### 27-Oct-2025
+
+- The repository for the D bindings has moved from https://github.com/kassane/sokol-d
+ to https://github.com/floooh/sokol-d, see https://github.com/floooh/sokol-d/discussions/36#discussioncomment-14790873
+ for details, this also means that the level of support for the D bindings
+ will need to be reduced unfortunately (especially when it comes to Dub packaging),
+ the automatic bindings generation will continue to work though.
+
+### 24-Oct-2025
+
+- sokol_gfx.h: add a missing validation layer check in sg_begin_pass():
+ when providing a resolve attachment, the associated color attachment must
+ have a sample_count > 1.
+
+ PR: https://github.com/floooh/sokol/pull/1366
+
+- sokol_app.h ios: the iOS backend now suports some tvOS features
+ via PR https://github.com/floooh/sokol/pull/1346, many thanks
+ to @tomasandrle!
+
+### 23-Oct-2025
+
+- sokol_gfx.h webgpu: the viewport rectangle is no longer clipped against
+ the visible area. This was a design wart in an older version of the
+ WebGPU spec which has been relaxed by now.
+
+ PR: https://github.com/floooh/sokol/pull/1362
+
+- sokol_gfx.h gl: fix a somewhat esoteric regression in the GL backend
+ feature detection code when an external GL loader is used which provides
+ a GL version older than 4.6. This regression was introduced in PR
+ https://github.com/floooh/sokol/pull/1347.
+
+ Fix PR: https://github.com/floooh/sokol/pull/1363
+
+### 21-Oct-2025
+
+- sokol_spine.h: merged PR https://github.com/floooh/sokol/pull/1361 which
+ fixes multiply-blend-mode and a validation layer issue when switching
+ between blend modes. Many thanks to @bryanjeal!
+
+### 20-Oct-2025
+
+- sokol_args.h: key-args-strings are no longer escaped (the documentation actually
+ stated this, but the implementation behaved differently)
+
+ PR: https://github.com/floooh/sokol/pull/1355
+ Ticket: https://github.com/floooh/sokol/issues/1353
+
+ Many thanks to @cloudwu for identifying and fixing the issue!
+
+- sokol_audio.h: added a new backend for the PS Vita via PR https://github.com/floooh/sokol/pull/1358
+ Please note that I cannot maintain the backend or help with any issues, and
+ normally I wouldn't merge a PR under such circumstances, but since it is very
+ little and straightforward code an exception is justified I guess :)
+
+ Many thanks to @CrackedPixel for the PR!
+
+### 10-Oct-2025
+
+sokol_gfx.h gl: fix breakage in the GL backend when `SOKOL_EXTERNAL_GL_LOADER`
+is defined.
+
+Issue: https://github.com/floooh/sokol/issues/1345
+
+PR: https://github.com/floooh/sokol/pull/1347
+
### 06-Oct-2025
sokol_app.h macos: minor code cleanup to unify the per-frame
diff --git a/README.md b/README.md
index 381fa53b..0d713fbb 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@
[**See what's new**](https://github.com/floooh/sokol/blob/master/CHANGELOG.md) (**04-Oct-2025**: new sokol_gfx.h function sg_draw_ex() added)
-[![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)[![Dlang](https://github.com/kassane/sokol-d/actions/workflows/build.yml/badge.svg)](https://github.com/kassane/sokol-d/actions/workflows/build.yml)[![C3](https://github.com/floooh/sokol-c3/actions/workflows/build.yml/badge.svg)](https://github.com/floooh/sokol-c3/actions/workflows/build.yml)
+[![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)[![Dlang](https://github.com/floooh/sokol-d/actions/workflows/build.yml/badge.svg)](https://github.com/floooh/sokol-d/actions/workflows/build.yml)[![C3](https://github.com/floooh/sokol-c3/actions/workflows/build.yml/badge.svg)](https://github.com/floooh/sokol-c3/actions/workflows/build.yml)
## Examples and Related Projects
@@ -21,8 +21,6 @@ Aras Pranckevičius, PC/web port via sokol ([source](https://github.com/aras-p/d
- [sokol_gp.h](https://github.com/edubart/sokol_gp) a 2D shape drawing library on top of sokol_gfx.h
-- [LearnOpenGL examples ported to sokol-gfx](https://zeromake.github.io/learnopengl-examples/) ([git repo](https://github.com/zeromake/learnopengl-examples))
-
- [Dear ImGui starterkit](https://github.com/floooh/cimgui-sokol-starterkit) a self-contained starterkit for writing Dear ImGui apps in C.
- [qoiview](https://github.com/floooh/qoiview) a basic viewer for the new QOI image file format
@@ -31,6 +29,10 @@ Aras Pranckevičius, PC/web port via sokol ([source](https://github.com/aras-p/d
- A 'single-file' [Pacman clone in C99](https://github.com/floooh/pacman.c/), also available in [Zig](https://github.com/floooh/pacman.zig/)
+- [Soluna](https://github.com/cloudwu/soluna), a framework to make 2D games in Lua by @cloudwu
+
+- [Deep Future](https://github.com/cloudwu/deepfuture): ...and a game implemented with Soluna
+
- [Solar Storm](https://store.steampowered.com/app/2754920/Solar_Storm/), a turn-based scifi artillery game built with Odin and Sokol, released on Steam.
- [Spanking Runners (Samogonki)](https://store.steampowered.com/app/2599800/Spanking_Runners/), arcade racing in a bright and unusual world, released on Steam.
@@ -46,6 +48,8 @@ Aras Pranckevičius, PC/web port via sokol ([source](https://github.com/aras-p/d
- ['Dealer's Dungeon'](https://dealers-dungeon.com/demo/) ([lower graphics quality](https://dealers-dungeon.com/demo/?q=3),
[source](https://github.com/bqqbarbhg/spear))
+- [LearnOpenGL examples ported to sokol-gfx (may be outdated)](https://zeromake.github.io/learnopengl-examples/) ([git repo](https://github.com/zeromake/learnopengl-examples))
+
- [Command line tools](https://github.com/floooh/sokol-tools) (shader compiler)
- [How to build without a build system](https://github.com/floooh/sokol-samples#how-to-build-without-a-build-system):
@@ -82,7 +86,7 @@ These are automatically updated on changes to the C headers:
- [sokol-odin](https://github.com/floooh/sokol-odin)
- [sokol-nim](https://github.com/floooh/sokol-nim)
- [sokol-rust](https://github.com/floooh/sokol-rust)
-- [sokol-d](https://github.com/kassane/sokol-d)
+- [sokol-d](https://github.com/floooh/sokol-d)
- [sokol-jai](https://github.com/colinbellino/sokol-jai)
- [sokol-c3](https://github.com/floooh/sokol-c3)
diff --git a/bindgen/README.md b/bindgen/README.md
index 8d4805e9..95c12fe1 100644
--- a/bindgen/README.md
+++ b/bindgen/README.md
@@ -24,7 +24,7 @@ To update the Zig bindings:
> git clone https://github.com/floooh/sokol-nim
> git clone https://github.com/floooh/sokol-odin
> git clone https://github.com/floooh/sokol-rust
-> git clone https://github.com/kassane/sokol-d
+> git clone https://github.com/floooh/sokol-d
> git clone https://github.com/colinbellino/sokol-jai
> git clone https://github.com/floooh/sokol-c3
> python3 gen_all.py
diff --git a/bindgen/gen_c3.py b/bindgen/gen_c3.py
index 1259e6d9..b2e5f437 100644
--- a/bindgen/gen_c3.py
+++ b/bindgen/gen_c3.py
@@ -327,7 +327,7 @@ def gen_c_imports(inp, c_prefix, prefix):
args = funcdecl_args_c(decl, prefix)
res_type = funcdecl_result_c(decl, prefix)
res_str = 'void' if res_type == '' else res_type
- l(f'extern fn {res_str} {check_override(as_snake_case(decl["name"], c_prefix))}({args}) @extern("{decl["name"]}");')
+ l(f'extern fn {res_str} {check_override(as_snake_case(decl["name"], c_prefix))}({args}) @cname("{decl["name"]}");')
l('')
def gen_consts(decl, prefix):
diff --git a/sokol_app.h b/sokol_app.h
index 2edc2891..b6638088 100644
--- a/sokol_app.h
+++ b/sokol_app.h
@@ -1206,6 +1206,11 @@
doesn't matter if the application is started from the command
line or via double-click.
+ NOTE: setting both win32_console_attach and win32_console_create
+ to true also makes sense and has the effect that output
+ will appear in the existing terminal when started from the cmdline, and
+ otherwise (when started via double-click) will open a console window.
+
MEMORY ALLOCATION OVERRIDE
==========================
You can override the memory allocation functions at initialization time
@@ -2278,6 +2283,9 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); }
#if !defined(SOKOL_METAL) && !defined(SOKOL_GLES3)
#error("sokol_app.h: unknown 3D API selected for iOS, must be SOKOL_METAL or SOKOL_GLES3")
#endif
+ #if TARGET_OS_TV
+ #define _SAPP_TVOS (1)
+ #endif
#endif
#elif defined(__EMSCRIPTEN__)
// Emscripten
@@ -6098,7 +6106,9 @@ _SOKOL_PRIVATE void _sapp_ios_mtl_init(void) {
*/
_sapp.ios.view.autoResizeDrawable = false;
_sapp.ios.view.userInteractionEnabled = YES;
+#if !defined(_SAPP_TVOS)
_sapp.ios.view.multipleTouchEnabled = YES;
+#endif
_sapp.ios.view_ctrl = [[UIViewController alloc] init];
_sapp.ios.view_ctrl.modalPresentationStyle = UIModalPresentationFullScreen;
_sapp.ios.view_ctrl.view = _sapp.ios.view;
@@ -6201,6 +6211,31 @@ _SOKOL_PRIVATE void _sapp_ios_app_event(sapp_event_type type) {
}
}
+_SOKOL_PRIVATE void _sapp_tvos_press_event(sapp_event_type type, NSSet<UIPress *>* presses) {
+ if (_sapp_events_enabled()) {
+ for (UIPress *press in presses) {
+ sapp_keycode key = SAPP_KEYCODE_INVALID;
+ switch (press.type) {
+ case UIPressTypeUpArrow: key = SAPP_KEYCODE_UP; break;
+ case UIPressTypeDownArrow: key = SAPP_KEYCODE_DOWN; break;
+ case UIPressTypeLeftArrow: key = SAPP_KEYCODE_LEFT; break;
+ case UIPressTypeRightArrow: key = SAPP_KEYCODE_RIGHT; break;
+ case UIPressTypeSelect: key = SAPP_KEYCODE_ENTER; break;
+ case UIPressTypeMenu: key = SAPP_KEYCODE_MENU; break;
+ case UIPressTypePlayPause: key = SAPP_KEYCODE_PAUSE; break;
+ default: break;
+ }
+ if (key != SAPP_KEYCODE_INVALID) {
+ _sapp_init_event(type);
+ _sapp.event.key_code = key;
+ _sapp.event.key_repeat = false;
+ _sapp.event.modifiers = 0;
+ _sapp_call_event(&_sapp.event);
+ }
+ }
+ }
+}
+
_SOKOL_PRIVATE void _sapp_ios_touch_event(sapp_event_type type, NSSet<UITouch *>* touches, UIEvent* event) {
if (_sapp_events_enabled()) {
_sapp_init_event(type);
@@ -6256,6 +6291,7 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) {
_sapp.ios.textfield.delegate = _sapp.ios.textfield_dlg;
[_sapp.ios.view_ctrl.view addSubview:_sapp.ios.textfield];
+#if !defined(_SAPP_TVOS)
[[NSNotificationCenter defaultCenter] addObserver:_sapp.ios.textfield_dlg
selector:@selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
@@ -6265,6 +6301,7 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) {
[[NSNotificationCenter defaultCenter] addObserver:_sapp.ios.textfield_dlg
selector:@selector(keyboardDidChangeFrame:)
name:UIKeyboardDidChangeFrameNotification object:nil];
+#endif
}
if (shown) {
// setting the text field as first responder brings up the onscreen keyboard
@@ -6327,6 +6364,7 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) {
- (void)keyboardWasShown:(NSNotification*)notif {
_sapp.onscreen_keyboard_shown = true;
/* query the keyboard's size, and modify the content view's size */
+#if !defined(_SAPP_TVOS)
if (_sapp.desc.ios.keyboard_resizes_canvas) {
NSDictionary* info = notif.userInfo;
CGFloat kbd_h = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
@@ -6334,6 +6372,7 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) {
view_frame.size.height -= kbd_h;
_sapp.ios.view.frame = view_frame;
}
+#endif
}
- (void)keyboardWillBeHidden:(NSNotification*)notif {
_sapp.onscreen_keyboard_shown = false;
@@ -6343,6 +6382,7 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) {
}
- (void)keyboardDidChangeFrame:(NSNotification*)notif {
/* this is for the case when the screen rotation changes while the keyboard is open */
+#if !defined(_SAPP_TVOS)
if (_sapp.onscreen_keyboard_shown && _sapp.desc.ios.keyboard_resizes_canvas) {
NSDictionary* info = notif.userInfo;
CGFloat kbd_h = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
@@ -6350,6 +6390,7 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) {
view_frame.size.height -= kbd_h;
_sapp.ios.view.frame = view_frame;
}
+#endif
}
- (BOOL)textField:(UITextField*)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString*)string {
if (_sapp_events_enabled()) {
@@ -6410,6 +6451,17 @@ _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) {
- (BOOL)isOpaque {
return YES;
}
+- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event {
+ _sapp_tvos_press_event(SAPP_EVENTTYPE_KEY_DOWN, presses);
+}
+- (void)pressesChanged:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event {
+}
+- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event {
+ _sapp_tvos_press_event(SAPP_EVENTTYPE_KEY_UP, presses);
+}
+- (void)pressesCancelled:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event {
+ _sapp_tvos_press_event(SAPP_EVENTTYPE_KEY_UP, presses);
+}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent*)event {
_sapp_ios_touch_event(SAPP_EVENTTYPE_TOUCHES_BEGAN, touches, event);
}
@@ -9372,11 +9424,12 @@ _SOKOL_PRIVATE void _sapp_win32_destroy_icons(void) {
_SOKOL_PRIVATE void _sapp_win32_init_console(void) {
if (_sapp.desc.win32.console_create || _sapp.desc.win32.console_attach) {
BOOL con_valid = FALSE;
- if (_sapp.desc.win32.console_create) {
- con_valid = AllocConsole();
- } else if (_sapp.desc.win32.console_attach) {
+ if (_sapp.desc.win32.console_attach) {
con_valid = AttachConsole(ATTACH_PARENT_PROCESS);
}
+ if (!con_valid && _sapp.desc.win32.console_create) {
+ con_valid = AllocConsole();
+ }
if (con_valid) {
FILE* res_fp = 0;
errno_t err;
diff --git a/sokol_args.h b/sokol_args.h
index e39b6f29..b532c90e 100644
--- a/sokol_args.h
+++ b/sokol_args.h
@@ -600,7 +600,7 @@ _SOKOL_PRIVATE bool _sargs_parse_carg(const char* src) {
if (_sargs_in_escape()) {
c = _sargs_escape(c);
_sargs_end_escape();
- } else if (_sargs_is_escape(c)) {
+ } else if (_sargs_is_escape(c) && _sargs_parsing_val()) {
_sargs_start_escape();
continue;
}
diff --git a/sokol_audio.h b/sokol_audio.h
index a64eabc9..bce5631a 100644
--- a/sokol_audio.h
+++ b/sokol_audio.h
@@ -42,6 +42,8 @@
- on Android: aaudio
- on Windows with MSVC or Clang toolchain: no action needed, libs are defined in-source via pragma-comment-lib
- on Windows with MINGW/MSYS2 gcc: compile with '-mwin32' and link with -lole32
+ - on Vita: SceAudio
+ - on 3DS: NDSP (libctru)
FEATURE OVERVIEW
================
@@ -55,6 +57,8 @@
- iOS: CoreAudio+AVAudioSession
- emscripten: WebAudio with ScriptProcessorNode
- Android: AAudio
+ - Vita: SceAudio
+ - 3DS: NDSP (libctru)
Sokol Audio will not do any buffer mixing or volume control, if you have
multiple independent input streams of sample data you need to perform the
@@ -379,6 +383,52 @@
header must be present (usually both are installed with some sort
of ALSA development package).
+ THE VITA BACKEND
+ ================
+ The VITA backend is automatically selected when compiling with vitasdk
+ ('PSP2_SDK_VERSION' is defined).
+
+ For thread synchronisation, the pthread_mutex_* functions are used.
+
+ Samples are converted from float to short (uint16_t) to maintain
+ all the same interface/api as other platforms.
+
+ You may use any supported sample rate you wish, but all audio MUST
+ match the same sample rate you choose.
+
+ This uses the "BGM" port to allow selecting the sample rate ("Main"
+ port is restricted to 48000 only).
+
+ You need to link with the 'SceAudio' library, and the <psp2/audioout.h>
+ header must be present (usually both are installed with the vitasdk).
+
+ THE 3DS BACKEND
+ ================
+ The 3DS backend is automatically selected when compiling with libctru
+ ('__3DS__' is defined).
+
+ Running a separate thread on the older 3ds is not a good idea and I
+ was not able to get it working without slowing down the main thread
+ too much (it has a single core available with cooperative threads).
+
+ The NDSP seems to work better by using its ndspSetCallback method.
+
+ You may use any supported sample rate you wish, but all audio MUST
+ match the same sample rate you choose or it will sound slowed down
+ or sped up.
+
+ The queue size and other NDSP specific parameters can be chosen by
+ the provided 'saudio_n3ds_desc' type. Defaults will be used if
+ nothing is provided.
+
+ There is a known issue of a noticeable delay when starting a new
+ sound on emulators. I was not able to improve this to my liking
+ and ~300ms can be expected. This can be improved by using a lower
+ buffer size than the 2048 default but I would not suggest under
+ 1536. It may crash under 1408, and they must be in multiples of 128.
+ Note: I was NOT able to reproduce this issue on a real device and
+ the audio worked perfectly.
+
MEMORY ALLOCATION OVERRIDE
==========================
@@ -537,6 +587,9 @@ extern "C" {
_SAUDIO_LOGITEM_XMACRO(COREAUDIO_ALLOCATE_BUFFER_FAILED, "AudioQueueAllocateBuffer() failed") \
_SAUDIO_LOGITEM_XMACRO(COREAUDIO_START_FAILED, "AudioQueueStart() failed") \
_SAUDIO_LOGITEM_XMACRO(BACKEND_BUFFER_SIZE_ISNT_MULTIPLE_OF_PACKET_SIZE, "backend buffer size isn't multiple of packet size") \
+ _SAUDIO_LOGITEM_XMACRO(VITA_SCEAUDIO_OPEN_FAILED, "sceAudioOutOpenPort() failed") \
+ _SAUDIO_LOGITEM_XMACRO(VITA_PTHREAD_CREATE_FAILED, "pthread_create() failed") \
+ _SAUDIO_LOGITEM_XMACRO(N3DS_NDSP_OPEN_FAILED, "ndspInit() failed") \
#define _SAUDIO_LOGITEM_XMACRO(item,msg) SAUDIO_LOGITEM_##item,
typedef enum saudio_log_item {
@@ -576,6 +629,31 @@ typedef struct saudio_allocator {
void* user_data;
} saudio_allocator;
+typedef enum saudio_n3ds_ndspinterptype {
+ SAUDIO_N3DS_DSP_INTERP_POLYPHASE = 0,
+ SAUDIO_N3DS_DSP_INTERP_LINEAR = 1,
+ SAUDIO_N3DS_DSP_INTERP_NONE = 2,
+} saudio_n3ds_ndspinterptype;
+
+typedef struct saudio_n3ds_desc {
+ /* the 3DS requires multiple queues that it alternates between. */
+ /* a single buffer will "work" but is choppy due to a slight */
+ /* delay when it changes queues. */
+ int queue_count; /* default value = 2 */
+
+ /* NDSP_INTERP_POLYPHASE = 0 (high quality, slower) */
+ /* NDSP_INTERP_LINEAR = 1 (med quality, medium) */
+ /* NDSP_INTERP_NONE = 2 (low quality, fast) */
+ saudio_n3ds_ndspinterptype interpolation_type; /* default value = 0 */
+
+ /* 3DS supports different audio channels. they can be used */
+ /* in a variety of ways as independent streams etc. */
+ /* this implementation in sokol does NOT allow multiple */
+ /* due to calling the global ndspInit/ndspExit functions. */
+ /* valid range 0-23 */
+ int channel_id; /* default value = 0 */
+} saudio_n3ds_desc;
+
typedef struct saudio_desc {
int sample_rate; // requested sample rate
int num_channels; // number of channels, default: 1 (mono)
@@ -585,6 +663,7 @@ typedef struct saudio_desc {
void (*stream_cb)(float* buffer, int num_frames, int num_channels); // optional streaming callback (no user data)
void (*stream_userdata_cb)(float* buffer, int num_frames, int num_channels, void* user_data); //... and with user data
void* user_data; // optional user data argument for stream_userdata_cb
+ saudio_n3ds_desc n3ds; // optional data for use on n3ds
saudio_allocator allocator; // optional allocation override functions
saudio_logger logger; // optional logging function (default: NO LOGGING!)
} saudio_desc;
@@ -687,6 +766,12 @@ inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc);
#define _SAUDIO_ANDROID (1)
#elif defined(__linux__) || defined(__unix__)
#define _SAUDIO_LINUX (1)
+#elif defined(PSP2_SDK_VERSION)
+ #define _SAUDIO_VITA (1)
+ #include <psp2/audioout.h>
+#elif defined(__3DS__)
+ #define _SAUDIO_N3DS (1)
+ #include <3ds.h>
#else
#error "sokol_audio.h: Unknown platform"
#endif
@@ -782,6 +867,11 @@ inline void saudio_setup(const saudio_desc& desc) { return saudio_setup(&desc);
#elif defined(__EMSCRIPTEN__)
#define _SAUDIO_NOTHREADS (1)
#include <emscripten/emscripten.h>
+#elif defined(_SAUDIO_VITA)
+ #define _SAUDIO_PTHREADS (1)
+ #include <pthread.h>
+#elif defined(_SAUDIO_N3DS)
+ #define _SAUDIO_NOTHREADS (1)
#endif
#define _saudio_def(val, def) (((val) == 0) ? (def) : (val))
@@ -982,6 +1072,30 @@ typedef struct {
uint8_t* buffer;
} _saudio_web_backend_t;
+#elif defined(_SAUDIO_VITA)
+
+typedef struct {
+ int device;
+ float* buffer;
+ int16_t* buffer_vita;
+ int buffer_byte_size;
+ int buffer_frames;
+ pthread_t thread;
+ bool thread_stop;
+} _saudio_vita_backend_t;
+
+#elif defined(_SAUDIO_N3DS)
+
+typedef struct {
+ saudio_n3ds_desc n3ds_desc; /* n3ds specific data */
+ float* buffer; /* used by sokol as floats */
+ int16_t* buffer_n3ds; /* sokol buffer converted to int16 */
+ ndspWaveBuf* queue_n3ds; /* device queues on 3DS */
+ int samples_per_buffer; /* frames * channel count */
+ int buffer_byte_size;
+ bool thread_stop;
+} _saudio_n3ds_backend_t;
+
#else
#error "unknown platform"
#endif
@@ -998,6 +1112,10 @@ typedef _saudio_wasapi_backend_t _saudio_backend_t;
typedef _saudio_aaudio_backend_t _saudio_backend_t;
#elif defined(_SAUDIO_LINUX)
typedef _saudio_alsa_backend_t _saudio_backend_t;
+#elif defined(_SAUDIO_VITA)
+typedef _saudio_vita_backend_t _saudio_backend_t;
+#elif defined(_SAUDIO_N3DS)
+typedef _saudio_n3ds_backend_t _saudio_backend_t;
#endif
/* a ringbuffer structure */
@@ -1184,6 +1302,26 @@ _SOKOL_PRIVATE void _saudio_mutex_lock(_saudio_mutex_t* m) {
_SOKOL_PRIVATE void _saudio_mutex_unlock(_saudio_mutex_t* m) {
LeaveCriticalSection(&m->critsec);
}
+#elif defined(_SAUDIO_VITA)
+
+_SOKOL_PRIVATE void _saudio_mutex_init(_saudio_mutex_t* m) {
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutex_init(&m->mutex, &attr);
+}
+
+_SOKOL_PRIVATE void _saudio_mutex_destroy(_saudio_mutex_t* m) {
+ pthread_mutex_destroy(&m->mutex);
+}
+
+_SOKOL_PRIVATE void _saudio_mutex_lock(_saudio_mutex_t* m) {
+ pthread_mutex_lock(&m->mutex);
+}
+
+_SOKOL_PRIVATE void _saudio_mutex_unlock(_saudio_mutex_t* m) {
+ pthread_mutex_unlock(&m->mutex);
+}
+
#else
#error "sokol_audio.h: unknown platform!"
#endif
@@ -2144,6 +2282,206 @@ _SOKOL_PRIVATE bool _saudio_coreaudio_backend_init(void) {
return true;
}
+// ██ ██ ██ ████████ █████
+// ██ ██ ██ ██ ██ ██
+// ██ ██ ██ ██ ███████
+// ██ ██ ██ ██ ██ ██
+// █████ ██ ██ ██ ██
+//
+// >>vita
+#elif defined(_SAUDIO_VITA)
+
+/* the streaming callback runs in a separate thread */
+_SOKOL_PRIVATE void* _saudio_vita_cb(void* param) {
+ _SOKOL_UNUSED(param);
+ while (!_saudio.backend.thread_stop) {
+ for (int i = 0; i < (_saudio.buffer_frames * _saudio.num_channels); i++) {
+ _saudio.backend.buffer_vita[i] = (int16_t)(_saudio.backend.buffer[i] * 32767.0f);
+ }
+ int write_res = sceAudioOutOutput(_saudio.backend.device, _saudio.backend.buffer_vita);
+ if (write_res < 0) {
+ /* underrun occurred */
+ }
+ else {
+ /* fill the streaming buffer with new data */
+ if (_saudio_has_callback()) {
+ _saudio_stream_callback(_saudio.backend.buffer, _saudio.backend.buffer_frames, _saudio.num_channels);
+ }
+ else {
+ if (0 == _saudio_fifo_read(&_saudio.fifo, (uint8_t*)_saudio.backend.buffer, _saudio.backend.buffer_byte_size)) {
+ /* not enough read data available, fill the entire buffer with silence */
+ _saudio_clear(_saudio.backend.buffer, (size_t)_saudio.backend.buffer_byte_size);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+_SOKOL_PRIVATE bool _saudio_vita_backend_init(void) {
+ SceAudioOutMode sceAudioOutMode = _saudio.num_channels == 1 ? SCE_AUDIO_OUT_MODE_MONO : SCE_AUDIO_OUT_MODE_STEREO;
+ int rc = sceAudioOutOpenPort(SCE_AUDIO_OUT_PORT_TYPE_BGM, _saudio.buffer_frames, _saudio.sample_rate, sceAudioOutMode);
+ if (rc < 0) {
+ _SAUDIO_ERROR(VITA_SCEAUDIO_OPEN_FAILED);
+ return false;
+ }
+ _saudio.backend.device = rc;
+
+ /* read back actual sample rate and channels */
+ _saudio.sample_rate = (int)_saudio.sample_rate;
+ _saudio.bytes_per_frame = _saudio.num_channels * (int)sizeof(float);
+
+ /* allocate the streaming buffer */
+ _saudio.backend.buffer_byte_size = _saudio.buffer_frames * _saudio.bytes_per_frame;
+ _saudio.backend.buffer_frames = _saudio.buffer_frames;
+ _saudio.backend.buffer = (float*) _saudio_malloc_clear((size_t)_saudio.backend.buffer_byte_size);
+ _saudio.backend.buffer_vita = (int16_t*) _saudio_malloc_clear((size_t)(_saudio.buffer_frames * _saudio.num_channels * (int)sizeof(int16_t)));
+
+ /* create the buffer-streaming start thread */
+ if (0 != pthread_create(&_saudio.backend.thread, 0, _saudio_vita_cb, 0)) {
+ _SAUDIO_ERROR(VITA_PTHREAD_CREATE_FAILED);
+ if (_saudio.backend.device >= 0) {
+ sceAudioOutReleasePort(_saudio.backend.device);
+ _saudio.backend.device = -1;
+ }
+ return false;
+ }
+
+ return true;
+}
+
+_SOKOL_PRIVATE void _saudio_vita_backend_shutdown(void) {
+ _saudio.backend.thread_stop = true;
+ pthread_join(_saudio.backend.thread, 0);
+ sceAudioOutReleasePort(_saudio.backend.device);
+ _saudio_free(_saudio.backend.buffer_vita);
+ _saudio_free(_saudio.backend.buffer);
+}
+
+// ███████ ██████ ███████
+// ██ ██ ██ ██
+// ██████ ██ ██ ███████
+// ██ ██ ██ ██
+// ███████ ██████ ███████
+//
+// >>3ds
+#elif defined(_SAUDIO_N3DS)
+
+/* NDSP triggers a callback for _saudio_n3ds_cb on the main thread */
+_SOKOL_PRIVATE void _saudio_n3ds_cb(void*) {
+ if(_saudio.backend.thread_stop) {
+ return;
+ }
+
+ const float scale = 32767.0f;
+
+ ndspWaveBuf* bufferPtr = 0;
+ bufferPtr = 0;
+ int i = 0;
+
+ /* pick an available queue */
+ for (i = 0; i < _saudio.backend.n3ds_desc.queue_count; ++i) {
+ if (_saudio.backend.queue_n3ds[i].status == NDSP_WBUF_DONE) {
+ bufferPtr = &_saudio.backend.queue_n3ds[i];
+ break;
+ }
+ }
+
+ if (!bufferPtr) {
+ /* no buffers are available. we don't want to play */
+ /* anything, but we also don't want to drain the queue */
+ return;
+ }
+
+ int16_t* target_buffer = bufferPtr->data_pcm16;
+ const float* source_buffer = _saudio.backend.buffer;
+ for (i = 0; i < _saudio.backend.samples_per_buffer; i++) {
+ /* data_pcm16 points to a region in the linear alloc _saudio.backend.buffer_n3ds */
+ target_buffer[i] = (int16_t)(source_buffer[i] * scale);
+ }
+
+ bufferPtr->nsamples = _saudio.buffer_frames; /* nsamples is actually frames */
+ ndspChnWaveBufAdd(_saudio.backend.n3ds_desc.channel_id, bufferPtr);
+ DSP_FlushDataCache(target_buffer, bufferPtr->nsamples * sizeof(int16_t));
+
+ /* fill the streaming buffer with new data */
+ if (_saudio_has_callback()) {
+ _saudio_stream_callback(_saudio.backend.buffer, _saudio.buffer_frames, _saudio.num_channels);
+ }
+ else {
+ if (0 == _saudio_fifo_read(&_saudio.fifo, (uint8_t*)_saudio.backend.buffer, _saudio.backend.buffer_byte_size)) {
+ /* not enough read data available, fill the entire buffer with silence */
+ _saudio_clear(_saudio.backend.buffer, (size_t)_saudio.backend.buffer_byte_size);
+ }
+ }
+}
+
+_SOKOL_PRIVATE bool _saudio_n3ds_backend_init(void) {
+ int rc = ndspInit();
+ if (rc != 0) {
+ _SAUDIO_ERROR(N3DS_NDSP_OPEN_FAILED);
+ return false;
+ }
+
+ /* set defaults if not provided */
+ _saudio.backend.n3ds_desc.queue_count = _saudio_def(_saudio.desc.n3ds.queue_count, 2);
+ _saudio.backend.n3ds_desc.interpolation_type = _saudio_def(_saudio.desc.n3ds.interpolation_type, SAUDIO_N3DS_DSP_INTERP_POLYPHASE);
+ _saudio.backend.n3ds_desc.channel_id = _saudio_def(_saudio.desc.n3ds.channel_id, 0);
+
+ /* clamp to 2 channels max */
+ if (_saudio.num_channels > 2) {
+ _saudio.num_channels = 2;
+ }
+
+ ndspChnReset(_saudio.backend.n3ds_desc.channel_id);
+ ndspChnWaveBufClear(_saudio.backend.n3ds_desc.channel_id);
+ ndspChnSetInterp(_saudio.backend.n3ds_desc.channel_id, (ndspInterpType)_saudio.backend.n3ds_desc.interpolation_type); /* cast to n3ds enum */
+ ndspChnSetRate(_saudio.backend.n3ds_desc.channel_id, _saudio.sample_rate);
+ ndspChnSetFormat(_saudio.backend.n3ds_desc.channel_id, _saudio.num_channels == 1 ? NDSP_FORMAT_MONO_PCM16 : NDSP_FORMAT_STEREO_PCM16);
+ ndspSetOutputMode(_saudio.num_channels == 1 ? NDSP_OUTPUT_MONO : NDSP_OUTPUT_STEREO);
+
+ /* read back actual sample rate and channels */
+ _saudio.sample_rate = (int)_saudio.sample_rate;
+ _saudio.bytes_per_frame = _saudio.num_channels * (int)sizeof(float);
+
+ /* allocate the streaming buffer */
+ _saudio.backend.samples_per_buffer = _saudio.buffer_frames * _saudio.num_channels;
+ _saudio.backend.buffer_byte_size = _saudio.buffer_frames * _saudio.bytes_per_frame;
+ _saudio.backend.buffer = (float*) _saudio_malloc_clear((size_t)_saudio.backend.buffer_byte_size);
+ _saudio.backend.buffer_n3ds = (int16_t*)linearAlloc(_saudio.backend.n3ds_desc.queue_count * _saudio.backend.samples_per_buffer * sizeof(int16_t));
+ _saudio.backend.queue_n3ds = (ndspWaveBuf*)_saudio_malloc(_saudio.backend.n3ds_desc.queue_count * sizeof(ndspWaveBuf));
+
+ /* prepare the 3ds audio queues */
+ int16_t* bufferPtrCopy = _saudio.backend.buffer_n3ds;
+ for (int i = 0; i < _saudio.backend.n3ds_desc.queue_count; ++i) {
+ _saudio.backend.queue_n3ds[i].data_vaddr = bufferPtrCopy; /* point the queue at the section of the linear buffer */
+ _saudio.backend.queue_n3ds[i].looping = false; /* the user should handle looping on their end */
+ _saudio.backend.queue_n3ds[i].status = NDSP_WBUF_DONE; /* default to done status for buffering logic */
+
+ bufferPtrCopy += _saudio.backend.samples_per_buffer;
+ }
+
+ /* instead of a thread, ndsp will trigger a callback */
+ /* when it needs more data. */
+ ndspSetCallback(_saudio_n3ds_cb, 0);
+
+ return true;
+}
+
+_SOKOL_PRIVATE void _saudio_n3ds_backend_shutdown(void) {
+ _saudio.backend.thread_stop = true;
+
+ if (_saudio.backend.n3ds_desc.channel_id >= 0) {
+ ndspChnWaveBufClear(_saudio.backend.n3ds_desc.channel_id);
+ _saudio.backend.n3ds_desc.channel_id = -1;
+ }
+
+ ndspExit();
+
+ _saudio_free(_saudio.backend.queue_n3ds);
+ _saudio_free(_saudio.backend.buffer_n3ds);
+ _saudio_free(_saudio.backend.buffer);
+}
#else
#error "unsupported platform"
#endif
@@ -2161,6 +2499,10 @@ bool _saudio_backend_init(void) {
return _saudio_aaudio_backend_init();
#elif defined(_SAUDIO_APPLE)
return _saudio_coreaudio_backend_init();
+ #elif defined(_SAUDIO_VITA)
+ return _saudio_vita_backend_init();
+ #elif defined(_SAUDIO_N3DS)
+ return _saudio_n3ds_backend_init();
#else
#error "unknown platform"
#endif
@@ -2179,6 +2521,10 @@ void _saudio_backend_shutdown(void) {
_saudio_aaudio_backend_shutdown();
#elif defined(_SAUDIO_APPLE)
_saudio_coreaudio_backend_shutdown();
+ #elif defined(_SAUDIO_VITA)
+ _saudio_vita_backend_shutdown();
+ #elif defined(_SAUDIO_N3DS)
+ _saudio_n3ds_backend_shutdown();
#else
#error "unknown platform"
#endif
diff --git a/sokol_gfx.h b/sokol_gfx.h
index c0c45268..2ceb9f19 100644
--- a/sokol_gfx.h
+++ b/sokol_gfx.h
@@ -4657,7 +4657,8 @@ typedef struct sg_frame_stats {
_SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_IMAGE_ALIVE, "sg_begin_pass: color attachment view's image object is uninitialized or no longer alive") \
_SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_IMAGE_VALID, "sg_begin_pass: color attachment view's image is not in valid state (SG_RESOURCESTATE_VALID)") \
_SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_SIZES, "sg_begin_pass: all color attachments must have the same width and height") \
- _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_SAMPLECOUNTS, "sg_begin_pass: all color attachments must have the same sample count") \
+ _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_SAMPLECOUNT, "sg_begin_pass: when resolve attachments are provided, the color attachment sample count must be 1") \
+ _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_SAMPLECOUNTS_EQUAL, "sg_begin_pass: all color attachments must have the same sample count") \
_SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_RESOLVEATTACHMENTVIEW_NO_COLORATTACHMENTVIEW, "sg_begin_pass: a resolve attachment view must have an associated color attachment view at the same index") \
_SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_RESOLVEATTACHMENTVIEW_ALIVE, "sg_begin_pass: resolve attachment view no longer alive") \
_SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_RESOLVEATTACHMENTVIEW_VALID, "sg_begin_pass: resolve attachment view not in valid state (SG_RESOURCESTATE_VALID)") \
@@ -5491,11 +5492,6 @@ inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_
#endif
#include <windows.h>
#pragma comment (lib, "kernel32") // GetProcAddress()
- #define _SOKOL_GL_HAS_COMPUTE (1)
- #define _SOKOL_GL_HAS_TEXSTORAGE (1)
- #define _SOKOL_GL_HAS_TEXVIEWS (1)
- #define _SOKOL_GL_HAS_BASEVERTEX (1)
- #define _SOKOL_GL_HAS_BASEINSTANCE (1)
#endif
#elif defined(__APPLE__)
#include <TargetConditionals.h>
@@ -5504,30 +5500,20 @@ inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_
#endif
#if defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE
#include <OpenGL/gl3.h>
- #define _SOKOL_GL_HAS_BASEVERTEX (1)
#else
#include <OpenGLES/ES3/gl.h>
#include <OpenGLES/ES3/glext.h>
- #define _SOKOL_GL_HAS_TEXSTORAGE (1)
#endif
#elif defined(__EMSCRIPTEN__)
#if defined(SOKOL_GLES3)
#include <GLES3/gl3.h>
- #define _SOKOL_GL_HAS_TEXSTORAGE (1)
#endif
#elif defined(__ANDROID__)
#include <GLES3/gl31.h>
- #define _SOKOL_GL_HAS_COMPUTE (1)
- #define _SOKOL_GL_HAS_TEXSTORAGE (1)
#elif defined(__linux__) || defined(__unix__)
- #define _SOKOL_GL_HAS_COMPUTE (1)
- #define _SOKOL_GL_HAS_TEXSTORAGE (1)
- #define _SOKOL_GL_HAS_BASEVERTEX (1)
#if defined(SOKOL_GLCORE)
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
- #define _SOKOL_GL_HAS_TEXVIEWS (1)
- #define _SOKOL_GL_HAS_BASEINSTANCE (1)
#else
#include <GLES3/gl32.h>
#include <GLES3/gl3ext.h>
@@ -5535,6 +5521,50 @@ inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_
#endif
#endif
+ // broad GL feature availability defines (DON'T merge this into the above ifdef-block!)
+ #if defined(_WIN32)
+ #if defined(GL_VERSION_4_3) || defined(_SOKOL_USE_WIN32_GL_LOADER)
+ #define _SOKOL_GL_HAS_COMPUTE (1)
+ #define _SOKOL_GL_HAS_TEXVIEWS (1)
+ #endif
+ #if defined(GL_VERSION_4_2) || defined(_SOKOL_USE_WIN32_GL_LOADER)
+ #define _SOKOL_GL_HAS_TEXSTORAGE (1)
+ #define _SOKOL_GL_HAS_BASEINSTANCE (1)
+ #endif
+ #if defined(GL_VERSION_3_2) || defined(_SOKOL_USE_WIN32_GL_LOADER)
+ #define _SOKOL_GL_HAS_BASEVERTEX (1)
+ #endif
+ #elif defined(__APPLE__)
+ #if defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE
+ #define _SOKOL_GL_HAS_BASEVERTEX (1)
+ #else
+ #define _SOKOL_GL_HAS_TEXSTORAGE (1)
+ #endif
+ #elif defined(__EMSCRIPTEN__)
+ #define _SOKOL_GL_HAS_TEXSTORAGE (1)
+ #elif defined(__ANDROID__)
+ #define _SOKOL_GL_HAS_COMPUTE (1)
+ #define _SOKOL_GL_HAS_TEXSTORAGE (1)
+ #elif defined(__linux__) || defined(__unix__)
+ #if defined(SOKOL_GLCORE)
+ #if defined(GL_VERSION_4_3)
+ #define _SOKOL_GL_HAS_COMPUTE (1)
+ #define _SOKOL_GL_HAS_TEXVIEWS (1)
+ #endif
+ #if defined(GL_VERSION_4_2)
+ #define _SOKOL_GL_HAS_TEXSTORAGE (1)
+ #define _SOKOL_GL_HAS_BASEINSTANCE (1)
+ #endif
+ #if defined(GL_VERSION_3_2)
+ #define _SOKOL_GL_HAS_BASEVERTEX (1)
+ #endif
+ #else
+ #define _SOKOL_GL_HAS_COMPUTE (1)
+ #define _SOKOL_GL_HAS_TEXSTORAGE (1)
+ #define _SOKOL_GL_HAS_BASEVERTEX (1)
+ #endif
+ #endif
+
// optional GL loader definitions (only on Win32)
#if defined(_SOKOL_USE_WIN32_GL_LOADER)
#define __gl_h_ 1
@@ -18378,15 +18408,10 @@ _SOKOL_PRIVATE void _sg_wgpu_commit(void) {
_SOKOL_PRIVATE void _sg_wgpu_apply_viewport(int x, int y, int w, int h, bool origin_top_left) {
SOKOL_ASSERT(_sg.wgpu.rpass_enc);
- // FIXME FIXME FIXME: CLIPPING THE VIEWPORT HERE IS WRONG!!!
- // (but currently required because WebGPU insists that the viewport rectangle must be
- // fully contained inside the framebuffer, but this doesn't make any sense, and also
- // isn't required by the backend APIs)
- const _sg_recti_t clip = _sg_clipi(x, y, w, h, _sg.cur_pass.dim.width, _sg.cur_pass.dim.height);
- float xf = (float) clip.x;
- float yf = (float) (origin_top_left ? clip.y : (_sg.cur_pass.dim.height - (clip.y + clip.h)));
- float wf = (float) clip.w;
- float hf = (float) clip.h;
+ float xf = (float) x;
+ float yf = (float) (origin_top_left ? y : (_sg.cur_pass.dim.height - (y + h)));
+ float wf = (float) w;
+ float hf = (float) h;
wgpuRenderPassEncoderSetViewport(_sg.wgpu.rpass_enc, xf, yf, wf, hf, 0.0f, 1.0f);
}
@@ -23075,7 +23100,7 @@ _SOKOL_PRIVATE bool _sg_validate_begin_pass(const sg_pass* pass) {
} else {
_SG_VALIDATE(color_width == _sg_image_view_dim(view).width, VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_SIZES);
_SG_VALIDATE(color_height == _sg_image_view_dim(view).height, VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_SIZES);
- _SG_VALIDATE(color_sample_count == img->cmn.sample_count, VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_SAMPLECOUNTS);
+ _SG_VALIDATE(color_sample_count == img->cmn.sample_count, VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_SAMPLECOUNTS_EQUAL);
}
}
}
@@ -23104,6 +23129,7 @@ _SOKOL_PRIVATE bool _sg_validate_begin_pass(const sg_pass* pass) {
_SG_VALIDATE(img->slot.state == SG_RESOURCESTATE_VALID, VALIDATE_BEGINPASS_RESOLVEATTACHMENTVIEW_IMAGE_VALID);
if (img->slot.state == SG_RESOURCESTATE_VALID) {
if (color_width != -1) {
+ _SG_VALIDATE(color_sample_count > 1, VALIDATE_BEGINPASS_COLORATTACHMENTVIEW_SAMPLECOUNT);
_SG_VALIDATE(color_width == _sg_image_view_dim(view).width, VALIDATE_BEGINPASS_RESOLVEATTACHMENTVIEW_SIZES);
_SG_VALIDATE(color_height == _sg_image_view_dim(view).height, VALIDATE_BEGINPASS_RESOLVEATTACHMENTVIEW_SIZES);
}
diff --git a/tests/functional/sokol_args_test.c b/tests/functional/sokol_args_test.c
index e2928d10..affa3bc0 100644
--- a/tests/functional/sokol_args_test.c
+++ b/tests/functional/sokol_args_test.c
@@ -253,7 +253,7 @@ UTEST(sokol_args, escape_sequence) {
sargs_shutdown();
}
-static char* argv_11[] = { "exe_name", "kvp0 kvp1", "kvp2 = val2", "kvp3", "kvp4=val4" };
+static char* argv_11[] = { "exe_name", "kvp0 kvp\\1", "kvp2 = val2", "kvp3", "kvp4=val4" };
UTEST(sokol_args, key_only_args) {
sargs_setup(&(sargs_desc){
.argc = NUM_ARGS(argv_11),
@@ -262,7 +262,7 @@ UTEST(sokol_args, key_only_args) {
T(sargs_isvalid());
T(sargs_num_args() == 5);
T(0 == sargs_find("kvp0"));
- T(1 == sargs_find("kvp1"));
+ T(1 == sargs_find("kvp\\1"));
T(2 == sargs_find("kvp2"));
T(3 == sargs_find("kvp3"));
T(4 == sargs_find("kvp4"))
@@ -270,25 +270,25 @@ UTEST(sokol_args, key_only_args) {
T(-1 == sargs_find("val2"));
T(-1 == sargs_find("val4"));
T(sargs_exists("kvp0"));
- T(sargs_exists("kvp1"));
+ T(sargs_exists("kvp\\1"));
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("kvp\\1"), "");
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("kvp\\1", "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(1), "kvp\\1");
TSTR(sargs_key_at(2), "kvp2");
TSTR(sargs_key_at(3), "kvp3");
TSTR(sargs_key_at(4), "kvp4");
diff --git a/util/sokol_gfx_imgui.h b/util/sokol_gfx_imgui.h
index fd025087..58481cee 100644
--- a/util/sokol_gfx_imgui.h
+++ b/util/sokol_gfx_imgui.h
@@ -4488,7 +4488,8 @@ _SOKOL_PRIVATE void _sgimgui_draw_capture_panel(sgimgui_t* ctx) {
}
_SOKOL_PRIVATE void _sgimgui_draw_caps_panel(void) {
- _sgimgui_igtext("Backend: %s\n\n", _sgimgui_backend_string(sg_query_backend()));
+ _sgimgui_igtext("Backend: %s\n", _sgimgui_backend_string(sg_query_backend()));
+ _sgimgui_igtext("Dear ImGui Version: %s\n\n", IMGUI_VERSION);
sg_features f = sg_query_features();
_sgimgui_igtext("Features:");
_sgimgui_igtext(" origin_top_left: %s", _sgimgui_bool_string(f.origin_top_left));
@@ -4500,6 +4501,7 @@ _SOKOL_PRIVATE void _sgimgui_draw_caps_panel(void) {
_sgimgui_igtext(" separate_buffer_types: %s", _sgimgui_bool_string(f.separate_buffer_types));
_sgimgui_igtext(" draw_base_vertex: %s", _sgimgui_bool_string(f.draw_base_vertex));
_sgimgui_igtext(" draw_base_instance: %s", _sgimgui_bool_string(f.draw_base_instance));
+ _sgimgui_igtext(" gl_texture_views: %s", _sgimgui_bool_string(f.gl_texture_views));
sg_limits l = sg_query_limits();
_sgimgui_igtext("\nLimits:\n");
_sgimgui_igtext(" max_image_size_2d: %d", l.max_image_size_2d);
diff --git a/util/sokol_imgui.h b/util/sokol_imgui.h
index a1fd4d34..89c47890 100644
--- a/util/sokol_imgui.h
+++ b/util/sokol_imgui.h
@@ -3145,9 +3145,12 @@ SOKOL_API_IMPL void simgui_new_frame(const simgui_frame_desc_t* desc) {
static sg_pipeline _simgui_bind_texture_sampler(sg_bindings* bindings, ImTextureID imtex_id) {
const sg_view tex_view = simgui_texture_view_from_imtextureid(imtex_id);
+ SOKOL_ASSERT(tex_view.id != SG_INVALID_ID);
const sg_image img = sg_query_view_image(tex_view);
+ SOKOL_ASSERT(img.id != SG_INVALID_ID);
bindings->views[0] = tex_view;
bindings->samplers[0] = simgui_sampler_from_imtextureid(imtex_id);
+ SOKOL_ASSERT(bindings->samplers[0].id != SG_INVALID_ID);
if (sg_query_pixelformat(sg_query_image_pixelformat(img)).filter) {
return _simgui.def_pip;
} else {
diff --git a/util/sokol_spine.h b/util/sokol_spine.h
index f8f1e0e1..ec142545 100644
--- a/util/sokol_spine.h
+++ b/util/sokol_spine.h
@@ -4097,10 +4097,11 @@ static sspine_resource_state _sspine_init_context(_sspine_context_t* ctx, const
pip_desc.label = "sspine-pip-normal/additive";
ctx->pip.normal_additive = sg_make_pipeline(&pip_desc);
- pip_desc.colors[0].blend.src_factor_rgb = SG_BLENDFACTOR_ZERO;
- pip_desc.colors[0].blend.dst_factor_rgb = SG_BLENDFACTOR_SRC_COLOR;
- pip_desc.colors[0].blend.src_factor_alpha = SG_BLENDFACTOR_ZERO;
- pip_desc.colors[0].blend.dst_factor_alpha = SG_BLENDFACTOR_ONE;
+ pip_desc.colors[0].blend.src_factor_rgb = SG_BLENDFACTOR_DST_COLOR;
+ pip_desc.colors[0].blend.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_COLOR;
+ pip_desc.colors[0].blend.src_factor_alpha = SG_BLENDFACTOR_DST_ALPHA;
+ pip_desc.colors[0].blend.dst_factor_alpha = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA;
+
pip_desc.label = "sspine-pip-multiply";
ctx->pip.multiply = sg_make_pipeline(&pip_desc);
@@ -5257,6 +5258,7 @@ static void _sspine_draw_layer(_sspine_context_t* ctx, int layer, const sspine_l
sg_apply_pipeline(cmd->pip);
cur_pip_id = cmd->pip.id;
sg_apply_uniforms(0, &vsparams_range);
+ sg_apply_uniforms(1, &fsparams_range);
cur_view_id = SG_INVALID_ID;
}
if ((cur_view_id != cmd->view.id) || (cur_smp_id != cmd->smp.id)) {