diff --git a/lib/shy_gl_read_pixels.h b/lib/shy_gl_read_pixels.h index 253ddb1..53dd796 100644 --- a/lib/shy_gl_read_pixels.h +++ b/lib/shy_gl_read_pixels.h @@ -1,4 +1,4 @@ -#if defined(SOKOL_GLCORE33) || defined(SOKOL_GLES2) || defined(SOKOL_GLES3) +#if defined(SOKOL_GLCORE) || defined(SOKOL_GLES3) void shy_gl_read_rgba_pixels(int x, int y, int width, int height, unsigned char* pixels) { glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); } diff --git a/thirdparty/sokol/CHANGELOG.md b/thirdparty/sokol/CHANGELOG.md index 31d0865..11253ac 100644 --- a/thirdparty/sokol/CHANGELOG.md +++ b/thirdparty/sokol/CHANGELOG.md @@ -1,5 +1,619 @@ ## Updates +### 30-Jul-2024 + +Merged PR https://github.com/floooh/sokol/pull/1086 which adds Emscripten target platform +support for the Nim bindings. Please also see PR https://github.com/floooh/sokol-nim/pull/31 +and the sokol-nim readme for details: https://github.com/floooh/sokol-nim + +Many thanks to @Nazariglez for the PRs! + +### 28-Jul-2024 + +sokol_gfx.h WebGL2: An important hotfix/workaround for a regression +in Chrome v127 on macOS and Safari Technology Preview 199 which broke all offscreen +rendering in sokol_gfx.h on WebGL2. The details are here https://github.com/floooh/sokol/issues/1085 +and in this Chromium ticket: https://issues.chromium.org/issues/355605685. + +The PR is here: https://github.com/floooh/sokol/pull/1087 + +It might take a little bit before the Chrome/Safari fix lands, and I fully expect +that the breakage will very slowly crawl through all sorts of other products +depending on Chromium (like VSCode, or the Qt WebView widget), so it made sense +to implement a workaround instead of waiting for the upstream fix to arrive. + +The TL;DR is: A regression in the Chrome and Safari WebGL2 Metal backends +subtly breaks offscreen rendering for render target textures which have their +GL_TEXTURE_MAX_LEVEL set, but don't explicitly allocate texture storage +via the glTexStorage calls (this is entirely valid GL and WebGL2 though). + +The breakage manifests as a 'stuck' offscreen rendering in Chrome, and as +a lost WebGL context in Safari Tech Preview (ok, that one isn't exactly 'subtle'). + +The workaround in the sokol_gfx.h GL backend is: + +- on Emscripten only: +- for textures without initial data, explicitly allocate texture storage + via the glTexStorage functions +- and otherwise call the glTexImage functions as before + +A better fix which I'll tackle later would be to rewrite the GL texture initialization +to generally use glTexStorage + glTexSubImage, but this will require a separate +fallback code path for macOS which doesn't have the glTexStorage calls because +GL on macOS is stuck at version 4.1, while glTexStorage has only been added in GL 4.2. + +> NOTE: if you are affected by the breakage but cannot update to the most recent +sokol_gfx.h version, a simpler hotfix might be to just comment out this call +in `_sg_gl_create_image`, but this will only work for render target textures +with a single mip level (which is the common case though): + +```c +glTexParameteri(img->gl.target, GL_TEXTURE_MAX_LEVEL, img->cmn.num_mipmaps - 1); +``` + + + +### 16-Jul-2024 + +sokol_app.h Linux: Fixed a long-standing issue on Linux where sokol-app key +up/down events were not keyboard layout independent. Instead the first keyboard +layout in the system settings would be used (this was responsible for why the +bug slipped through for so long, because on my Linux laptop I have a US layout +first in the list, followed by the German layout - this caused sokol-app key +codes to always be consistent with the US layout, even when the German layout +was selected, which is the intended behaviour. The bug only manifested itself +when moving the German layout into the top spot. + +The fix has been adapted from GLFW by building a runtime-dynamic mapping table +from keyboard scan codes to sokol-app key codes at application start. As always, +big kudos to GLFW for investigating and implementing a fix after running into +the same issue before. + +Also many thanks to GH user @marekmaskarinec for providing an initial PR +(https://github.com/floooh/sokol/pull/1078) which unfortunately couldn't be +used because it doesn't work on XWayland. + +For more details see issue https://github.com/floooh/sokol/issues/1080 and +PR https://github.com/floooh/sokol/pull/1081. + +### 04-Jul-2024 + +The public sokol_audio.h functions now have an assert to make sure that saudio_setup() +has already been called. + +### 19-Jun-2024 + +Bugfix in the sokol_gfx.h D3D11 backend: calling `sg_update_image()` with a 3D texture +didn't take the 'depth pitch' into account which then caused invalid texture content +in small-ish textures. This happened at a specific size cutoff which seems to be GPU +specific (on my laptop with integrated Intel GPU only for textures smaller than +32x32xN). + +Related ticket: https://github.com/floooh/sokol/issues/1066 +...and PR: https://github.com/floooh/sokol/pull/1065 + +I also wrote a new sample for investigating the issue and to protect from +future regressions: https://floooh.github.io/sokol-html5/dyntex3d-sapp.html + +### 01-Jun-2024 + +sokol_imgui.h is now officially supported in the [sokol-zig bindings](https://github.com/floooh/sokol-zig). + +This caused a very minor breaking change in the sokol_imgui.h function +`simgui_add_key_event()`: previously this took a callback function pointer +which mapped the incoming key code to a Dear ImGui compatible keycode, +this is now expected to be performed by the caller before calling +`simgui_add_key_event()`. + +Other than the minor API change there's an equally minor internal code cleanup: +The ImGuiIO method `SetKeyEventNativeData()` is no longer called. This change shouldn't +have any side effects. + +For more details about the Zig sokol_imgui.h also see this example project: + +https://github.com/floooh/sokol-zig-imgui-sample + +### 14-May-2024 + +sokol_fetch.h: A minor breaking change in which hopefully doesn't affect anybody: + +The function typedef `sfetch_callback_t` has been removed and the type signature +for the callback has been directly embedded in the `sfetch_request_t` struct. This +is a preparation for adding sokol_fetch.h to the language bindings (first in +sokol-zig, see this PR for details: https://github.com/floooh/sokol/pull/1048). + +### 13-May-2024 + +Official bindings for the **D language** have been added, like the other official +bindings those will be automatically updated on commits to the main repository: + +https://github.com/kassane/sokol-d + +...this also includes a matching output format `sokol_d` in the sokol-shdc shader +compiler. + +Also see PR https://github.com/floooh/sokol/pull/955. + +Many thanks to @kassane for the hard work! + +...and a couple minor texture format related fixes in the WebGPU backends in sokol_gfx.h and sokol_app.h: + +- merged PR https://github.com/floooh/sokol/pull/1045, this sets 32-bit float textures + to filterable if supported (depending on `WGPUFeatureName_Float32Filterable`), many + thanks to @jdah! +- in sokol_app.h, the WebGPU feature detection code has been fixed: + - previously, BC and ETC2 texture compression support was mutually exclusive, which + was a bug (for instance on Apple Silicon, both formats are available) + - the missing ASTC texture compression detection has been added (sokol_gfx.h already + checked the WebGPU device for support of ASTC compression, but this code never + worked because the feature was not requested when the WebGPU device was created + in sokol_app.h + +### 10-May-2024 + +A minor breaking change regarding ETC2/EAC pixel formats: + +- `SG_PIXELFORMAT_ETC2_RG11` has been renamed to `SG_PIXELFORMAT_EAC_RG11` +- `SG_PIXELFORMAT_ETC2_RG11SN` has been renamed to `SG_PIXELFORMAT_EAC_RG11SN` +- the pixel formats `SG_PIXELFORMAT_EAC_R11` and `SG_PIXELFORMAT_EAC_R11SN` have been added +- fixed a pixel format mapping bug in WebGPU (the EAC RG11 formats were actually mapped to R11) + +See ticket https://github.com/floooh/sokol/issues/1041, and PR https://github.com/floooh/sokol/pull/1044 for details. + +### 09-May-2024 + +The 'storage buffer update'. sokol_gfx.h now has (readonly) storage buffer support, providing +a more flexible way to pass array-like random access data from the CPU to the GPU side. + +Please see the following [blog post](https://floooh.github.io/2024/05/06/sokol-storage-buffers.html) +and the [associated PR #1007](https://github.com/floooh/sokol/pull/1007) for details. + +Please also note the new documentation section `ON STORAGE BUFFERS` in sokol_gfx.h. + +Also see the related [changes in sokol-shdc](https://github.com/floooh/sokol-tools/blob/master/CHANGELOG.md). + +...and finally the following new samples (note that the demos are running on WebGPU and currently +require a recent Chrome on macOS or Windows): + +- rendering without buffer bindings (this sample actually also runs on WebGL2): + - WebGPU: https://floooh.github.io/sokol-webgpu/triangle-bufferless-sapp.html + - WebGL2: https://floooh.github.io/sokol-html5/triangle-bufferless-sapp.html + - C source: https://github.com/floooh/sokol-samples/blob/master/sapp/triangle-bufferless-sapp.c + - GLSL source: https://github.com/floooh/sokol-samples/blob/master/sapp/triangle-bufferless-sapp.glsl +- vertex pulling from a storage buffer: + - WebGPU: https://floooh.github.io/sokol-webgpu/vertexpull-sapp.html + - C source: https://github.com/floooh/sokol-samples/tree/master/sapp/vertexpull-sapp.c + - GLSL source: https://github.com/floooh/sokol-samples/tree/master/sapp/vertexpull-sapp.glsl +- reading storage buffer content in fragment shader: + - WebGPU: https://floooh.github.io/sokol-webgpu/sbuftex-sapp.html + - C source: https://github.com/floooh/sokol-samples/tree/master/sapp/sbuftex-sapp.c + - GLSL source: https://github.com/floooh/sokol-samples/tree/master/sapp/sbuftex-sapp.glsl +- instanced rendering via storage buffer: + - WebGPU: https://floooh.github.io/sokol-webgpu/instancing-pull-sapp.html + - C source: https://github.com/floooh/sokol-samples/tree/master/sapp/instancing-pull-sapp.c + - GLSL source: https://github.com/floooh/sokol-samples/tree/master/sapp/instancing-pull-sapp.glsl +- skinned character rendering via storage buffers: + - WebGPU: https://floooh.github.io/sokol-webgpu/ozz-storagebuffer-sapp.html + - C source: https://github.com/floooh/sokol-samples/tree/master/sapp/ozz-storagebuffer-sapp.cc + - GLSL source: https://github.com/floooh/sokol-samples/tree/master/sapp/ozz-storagebuffer-sapp.glsl + +Also see the following backend-specific samples which don't use sokol-shdc: + +- D3D11: https://github.com/floooh/sokol-samples/blob/master/d3d11/vertexpulling-d3d11.c +- Metal: https://github.com/floooh/sokol-samples/blob/master/metal/vertexpulling-metal.c +- WebGPU: https://github.com/floooh/sokol-samples/blob/master/wgpu/vertexpulling-wgpu.c +- Desktop GL: https://github.com/floooh/sokol-samples/blob/master/glfw/vertexpulling-glfw.c + +Storage buffer support is not available on the following platform/backend combos: + +- macOS + GL (stuck at GL 4.1) +- iOS + GL (stuck at GLES 3.0) +- WebGL2 (stuck at GLES 3.0) +- Android (support may be implemented at a later time) + +#### **BREAKING CHANGES** + +- the config define `SOKOL_GLCORE33` has been renamed to `SOKOL_GLCORE`, this affects + the following headers: + - sokol_gfx.h + - sokol_app.h + - sokol_debugtext.h + - sokol_fontstash.h + - sokol_gl.h + - sokol_imgui.h + - sokol_nuklear.h + - sokol_spine.h +- likewise in the sokol_gfx.h enum `sg_backend` the enum item `SG_BACKEND_GLCORE33` has been + renamed to `SG_BACKEND_GLCORE` +- sokol_gfx.h now expects a minimal desktop GL version of 4.1 on macOS, and 4.3 on other + platforms (this only matters if you don't use sokol_app.h), storage buffer support is only + available on GL 4.3 contexts +- likewise, shaders passed into sokol_gfx.h when the desktop GL backend is active are now expected + to be `#version 410` or `#version 430` (`#version 330` may still work but is untested) +- likewise, by default sokol_app.h now creates a GL 4.1 context on macOS and a GL 4.3 context on other + desktop platforms when `SOKOL_GLCORE` is defined +- if you're passing WGSL shaders directly into sokol_gfx.h (instead of using sokol-shdc), please + be aware that the binding offets for the different shader resource types have moved: + - vertex shader stage: + - textures: `@group(1) @binding(0..15)` + - samplers: `@group(1) @binding(16..31)` + - storage buffers: `@group(1) @binding(32..47)` + - fragment shader stage: + - textures: `@group(1) @binding(48..63)` + - samplers: `@group(1) @binding(64..79)` + - storage buffers `@group(1) @binding(80..95)` + +#### **NON-BREAKING CHANGES** + +- **sokol_app.h** learned two new functions to get the desktop GL version (note that on GLES + these return 0, this behaviour may change at a later time): + - `int sapp_gl_get_major_version(void)` + - `int sapp_gl_get_minor_version(void)` + +- **sokol_gfx.h**: + - The enum `sg_buffer_type` has a new member `SG_BUFFERTYPE_STORAGEBUFFER`, used + in the `sg_make_buffer()` call to create a storage buffer + - The struct `sg_features` has a new member `bool storage_buffer`, used to indicate + that the current 3D backend supports storage buffers + - The stats struct `sg_frame_stats_metal_bindings` has a new member `num_set_fragment_buffer` + - There are various new error codes and validation checks related to storage buffers + - A new struct `sg_shader_storage_buffer_desc`, nested in `sg_shader_desc`. + This is used in the `sg_make_shader()` call to communicate to sokol_gfx.h + what storage buffer bind slots are used in a shader + +- **sokol_gfx_imgui.h**: The debug UI panels have been updated to visualize the new + storage buffer related state + +- in the following headers, the embedded shaders have been updated via the new + sokol-shdc version, switching the embedded GLSL shaders to `#version 410` + - sokol_debugtext.h + - sokol_fontstash.h + - sokol_gl.h + - sokol_imgui.h + - sokol_nuklear.h + - sokol_spine.h + + +### 03-May-2024: + +- sokol_app.h win32: Merged PR https://github.com/floooh/sokol/pull/1034, this adds a NOAPI mode + to the sokol_app.h Windows backend by defining SOKOL_NOAPI before including the implementation. + Same thing as GLFW's NOAPI mode basically, to allow using the sokol_app.h windowing features + without setting up D3D11 or OpenGL. NOAPI implementations for other platforms will follow in the + future. Many thanks to @pplux and @castano! + +### 13-Apr-2024: + +- sokol_gfx.h d3d11: resource label strings are now communicated to D3D11 resource objects, + making it easier to identify those resources in tools like the Visual Studio Graphics Debugger + or RenderDoc. See PR https://github.com/floooh/sokol/pull/1025 for details. Many thanks to + @jakubtomsu for the PR! +- Odin bindings: merged https://github.com/floooh/sokol/pull/1023 (and related PR + https://github.com/floooh/sokol-odin/pull/11 in the actual bindings repo). This changes + the directory structure of the bindings to make them a bit friendlier to integrate + with Odin projects, and also adds a couple of smaller improvements and fixes. + Many thanks to @jakubtomsu for the PRs! +- Also a couple of smaller 'drive-by PRs' I merged over the last couple of days but didn't mention + yet in the changelog: + - https://github.com/floooh/sokol/pull/1029: exclude NUM enum items in Odin bindings, many thanks to @jakubtomsu + - https://github.com/floooh/sokol/pull/1028: in sokol_gfx.h fix GCC warnings in the d3d11 backend (when compiling + via mingw on Windows), many thanks @edubart + - https://github.com/floooh/sokol/pull/1026: in sokol_gfx.h increase the internal `_SG_STRING_SIZE` from + 16 to 32, by @jakubtomsu + - https://github.com/floooh/sokol/pull/1021, https://github.com/floooh/sokol-odin/pull/10: re-enable Odin CI builds + for macOS (by linking against LLVM 17), also by @jakubtomsu + +### 21-Mar-2024: + +- sokol_imgui.h: merged PR https://github.com/floooh/sokol/pull/1010, this will automatically + re-create the sokol-gfx font texture resources in the `simgui_new_frame()` call + when the Dear ImGui texture atlas has changed. This is an alternative to calling the + functions `simgui_create_fonts_texture()` and `simgui_destroy_fonts_texture()` manually. + One important reason why you'd want to call those functions manually is to create the fonts texture + with custom texture sampler attributes (the new implicit re-creation inside `simgui_new_frame()` + calls `sg_make_sampler()` with default attributes). + + Many thanks to @elloramir for the PR! + +### 02-Mar-2024: + +- sokol_app.h emscripten: two new flags in `sapp_desc` to configure the Emscripten main loop: + - `.html5_use_emsc_set_main_loop`: when this is true, the function `emscripten_set_main_loop()` will be used + to drive the sokol-app frame callback (otherwise `emscripten_request_animation_frame()` as before) + - `.html5_emsc_set_main_loop_simulate_infinite_loop`: this is passed as the `simulate_infinite_loop` parameter + into the `emscripten_set_main_loop()` function. + + In general you should stick with sokol_app.h's default behaviour and only use those settings if you run + into specific problems, for instance as discussed here: https://github.com/floooh/sokol/issues/843 + + Related PR: https://github.com/floooh/sokol/pull/997 + + Many thanks to @Dvad for the PR, and also to @ambrusc for an alternative PR that hadn't been used, @voidware + for kicking off the discussion and all contributors! + + The sample `texcube-sapp` has been updated to use the set-main-loop method: + + https://floooh.github.io/sokol-html5/texcube-sapp.html + +- sokol_imgui.h: PR https://github.com/floooh/sokol/pull/994 has been merged, this adds two + font management helper functions which drastically reduce boilerplate code + when injecting a custom font into Dear ImGui via sokol_imgui.h. + + See the PR for details, and the updated sample https://floooh.github.io/sokol-html5/imgui-highdpi-sapp.html + via this PR: https://github.com/floooh/sokol-samples/pull/135 + + Many thanks to @Dvad for the PR! + +### 01-Mar-2024: + +Minor regression fix for yesterdays merge in the sokol_gfx.h Metal backend: + +A swapchain render pass with an SG_PIXELFORMAT_DEPTH depth-buffer would try +to set a stencil surface (currently this only matters if you use your own +window system glue since sokol_app.h always creates a depth+stencil-buffer). + +See https://github.com/floooh/sokol/issues/1004 for details. + +The [Metal samples in the sokol-samples project](https://github.com/floooh/sokol-samples/tree/master/metal) have been updated to use all variants +of SG_PIXELFORMAT_NONE, SG_PIXELFORMAT_DEPTH and SG_PIXELFORMAT_DEPTH_STENCIL +now to catch similar regressions in the future. + +Plus 2 minor drive-by fixes: + +- fix the sokol_gfx.h WebGPU backend for a spec-fix in Chrome (see https://github.com/floooh/sokol/issues/1003) +- in the Emscripten backends of sokol_app.h and sokol_args.h, replace the deprecated JS helper function + `allocateUTF8OnStack` with its replacement `stringToUTF8OnStack` (see: https://github.com/floooh/sokol/commit/49a75e1476153cb2605d3b3ebd2f07e3eb0536d9) + +### 29-Feb-2024: + +**BREAKING CHANGES** in sokol_gfx.h, sokol_app.h, sokol_glue.h and sokol_gfx_imgui.h +(the 'big render pass cleanup'). + +- In sokol_gfx.h, the concepts of 'render contexts' and 'default render passes' have + been removed and replaced with a unified `sg_begin_pass()` which handles both + rendering into 'offscreen-passes' and 'swapchain-passes'. + + [Please read this blog + post](https://floooh.github.io/2024/02/26/sokol-spring-cleaning-2024.html) + carefully for a detailed overview what has changed, why the changes make + sense, and how existing code needs to be updated. + + Also see the related PR for further details: https://github.com/floooh/sokol/pull/985 + +- There are also minimal related changes in the sokol_app.h and a complete + rewrite of the sokol_glue.h APIs, also detailed in the above blog post. + +- The namespace-prefix for the header sokol_gfx_imgui.h has been changed from + `sg_imgui_` to `sgimgui_`. + +- In sokol_gfx.h with the Metal backend, a runtime configuration flag has been + added to `sg_desc` to create a Metal command buffer with + 'retained-references'. See issue + [#981](https://github.com/floooh/sokol/issues/981) for details. + +- Also in sokol_gfx.h, the struct item `sg_limits.gl_max_vertex_uniform_vectors` has been changed + to `sg_limits.gl_max_vertex_uniform_components` (note that there are 4x more 'components' + than 'vectors'). See issue [#714](https://github.com/floooh/sokol/issues/714) for details. + +- All sampples, language binding examples and 'side projects' have been updated, see the above blog post + for links to the respective PRs. + +### 27-Feb-2024: + +- Merged PR https://github.com/floooh/sokol/pull/1001, this is a small fix for GLES3 to avoid + calling glInvalidateFramebuffer() on non-existing depth/stencil surfaces. + + Many thanks to @danielchasehooper! + +#### 26-Feb-2024: + +- Minor fix in sokol_imgui.h: The drawing code now detects and skips the special + `ImDrawCallback_ResetRenderState` constant, not doing so would try to call a function + at address (-8) which then results in a crash. + + See for what this is: https://github.com/ocornut/imgui/blob/277ae93c41314ba5f4c7444f37c4319cdf07e8cf/imgui.h#L2583-L2587 + + sokol_imgui.h doesn't have any handling for this special callback, it will just ignore it. + + As a minor additional behaviour change, any user callback will now also cause `sg_reset_state_cache()` + to be called. This is just a precaution in case the user callback code calls any native 3D backend API + functions. + + Related issue: https://github.com/floooh/sokol/issues/1000 + +#### 21-Feb-2024: + +- PR https://github.com/floooh/sokol/pull/993 has been merged, this allows to inject + additional GL functions into the Win32 GL loader of sokol_gfx.h (TBH, it's a very specialized + feature for people who know what they're doing, but it also fixes a very specific problem + while at the same time resolving to 'nothing' when not used). + + Many thanks for @kcbanner for the PR! + +#### 31-Jan-2024: + +- sokol_app.h macOS: merged a workaround for the application window not being focused + if the init callback takes a while (not reproducible on my M1 Mac with latest Sonoma, + but might fix the issue for older Macs, and the change seems harmless enough - + sokol_app.h essentially sends a focusEvent to itself) + + Related issue: https://github.com/floooh/sokol/issues/757 + Implemented in PR: https://github.com/floooh/sokol/pull/982 + + Many thanks to @zoo-3d for investigating the issue and the PR! + +#### 28-Jan-2024: + +- sokol_app.h web: the canvas resize callback is now unregistered on cleanup. + + Related issue: https://github.com/floooh/sokol/issues/983 and PR: https://github.com/floooh/sokol/pull/984 + Many thanks to @edubart! + +#### 27-Jan-2024 + +- sokol_app.h web: The HTML5 event bubbling changes introduced in the 02-Jan-2024 + update have been reverted because they introduced some undesired side effects. + By default, most input events now *don't* bubble up (which restores the + old behaviour), but it's now possible to enable bubbling for categories + of input events (mouse, touch, wheel, keys and chars) during sokol-app setup. + It's then possible to control bubbling of individual events by calling + `sapp_consume_event()` from within the sokol-app event callback. + + See issue https://github.com/floooh/sokol/issues/972 for details and + PR https://github.com/floooh/sokol/pull/975 for the actual changes. + + Also check out the new doc section `INPUT EVENT BUBBLING ON THE WEB PLATFORM` + in the sokol_app.h header documentation block. + +- sokol_gfx.h metal: Merged PR https://github.com/floooh/sokol/pull/980. When + only the offset changes in a vertex buffer binding, only the buffer offset + is now updated (e.g. instead of the Metal method `setVertexBuffer:offset:atIndex`, + the leaner method `setVertexBufferOffset:atIndex` is called. Apart from the + actual PR I also removed a couple of actually unused items from the Metal + backend state cache. Many thanks to @staminajim for the PR! + + Related issue: https://github.com/floooh/sokol/issues/979 + +#### 23-Jan-2024 + +- sokol_app.h android: Touch event coordinates are now using AMotionEvent_getX/Y() instead + of AMotionEvent_getRawX/Y(). The raw functions don't work well in multi-window + scenarios. See PR https://github.com/floooh/sokol/pull/974 for details. + Many thanks to GitHub user @Comanx! + +#### 19-Jan-2024 + +- sokol_app.h wgpu: tiny fix for a breaking API change in webgpu.h in the Emscripten 3.1.52 SDK +- Merged PR https://github.com/floooh/sokol/pull/970 (many thanks to @waywardmonkeys) which + fixes a couple of strict-prototype warnings (e.g. C functions using func() instead of func(void)). + I also enabled `-Wstrict-prototypes` now in the CI tests for GCC and Clang, so such cases + should be caught in the future. + +#### 18-Jan-2024 + +- sokol_gfx.h: added support for the following pixel formats: + - BC3_SRGBA + - BC7_SRGBA + - ETC2_SRGB8 + - ETC2_SRGB8A8 + - ASTC_4x4_RGBA + - ASTC_4x4_SRGBA + + Related PR: https://github.com/floooh/sokol/pull/967 + + Many thanks to GH user @allcreater! + +#### 07-Jan-2024 + +- sokol_app.h (macos+metal): window content no longer 'wobbles' during window resizing. Many + thanks to @Seb-degraff for picking up and investigating this longstanding issue + (https://github.com/floooh/sokol/issues/700), finding a fix for the remaining problem + and providing a really nice PR (https://github.com/floooh/sokol/pull/963) + +#### 06-Jan-2024 + +> NOTE: if you use sokol_gfx.h and sokol_app.h together, make sure to update both. This is +because the pixel format enum in sokol_gfx.h has been shuffled around a bit, and as a result, some internal +pixel format constants in sokol_app.h had to move too! + +- sokol_gfx.h: some minor new features (non-breaking): + - the struct `sg_pixel_format` has two new items: + - `bool compressed`: true if this is a hardware-compressed pixel format + - `int bytes_per_pixel`: as the name says, with the caveat that this is + zero for compressed pixel formats (because the smallest element in compressed formats is a block, not a pixel) + - two previously private helper functions have been exposed to help with size computations + for texture data, these may be useful when preparing image data for consumption by `sg_make_image()` + and `sg_update_image()`: + - `int sg_query_row_pitch(sg_pixel_format fmt, int width, int row_align_bytes)`: + Computes the number of bytes in a texture row for a given pixel format. A 'row' has + different meanings for uncompressed vs compressed formats: For uncompressed pixel + formats, a row is a single line of pixels, while for compressed formats, a row is + a line of 'compression blocks'. `width` is always in pixels. + - `int sg_query_surface_pitch(sg_pixel_format fmt, int width, int height, int row_align_bytes)`: + Computes number of bytes in a texture surface (e.g. a single mipmap) for a given + pixel format. `width` and `height` are always in pixels. + + The `row_align_bytes` parameter is for added flexibility. For image data that goes into + the `sg_make_image()` or `sg_update_image()` functions this should generally be 1, because these + functions take tightly packed image data as input no matter what alignment restrictions + exist in the backend 3D APIs. +- Related issue: https://github.com/floooh/sokol/issues/946, and PR: https://github.com/floooh/sokol/pull/962 + +#### 03-Jan-2024 + +- sokol_nuklear.h: `snk_handle_event()` now returns a bool to indicate whether the + event was handled by Nuklear (this allows an application to skip its own event + handling if Nuklear already handled the event). Issue link: https://github.com/floooh/sokol/issues/958, + fixed in PR: https://github.com/floooh/sokol/pull/959. Many thanks to @adamrt for the PR! + +#### 02-Jan-2024 + +Happy New Year! A couple of input-related changes in the sokol_app.h Emscripten backend: + +- Mouse and touch events now bubble up to the HTML document instead of being consumed, in some scenarios this + allows better integration with the surrounding web page. To prevent event bubbling, + call `sapp_consume_event()` from within the sokol_app.h event callback function. +- **NOTE**: wheel/scroll events behave as before and are always consumed. This prevents + an ugly "scroll bumping" effect when a wheel event bubbles up on a page where + scrolling shouldn't be possible. +- The hidden HTML text input field hack for text input on mobile browsers has been + removed. This idea never really worked across all browsers, and it actually + interfered with Dear ImGui text input fields because the hidden HTML text field + generated focus-in/out events which confused the Dear ImGui input handling code. + +Those changes fix a couple of problem when trying to integrate sokol_app.h applications +into VSCode webview panels, see: https://marketplace.visualstudio.com/items?itemName=floooh.vscode-kcide + +Related PR: https://github.com/floooh/sokol/pull/939 + +#### 10-Nov-2023 + +A small change in the sokol_gfx.h GL backend on Windows only: + +PR https://github.com/floooh/sokol/pull/839 has been merged, in debug mode this creates +the GL context with WGL_CONTEXT_DEBUG_BIT_ARB. Thanks to @castano for the PR! + +#### 06-Nov-2023 + +A bugfix in the sokol_gfx.h D3D11 backend, and some related cleanup when creating depth-stencil +render target images and resource views: + +- fixed: render target images with format SG_PIXELFORMAT_DEPTH_STENCIL triggered a validation + error because the pixel format capabilities code marked them as non-renderable. Now + the SG_PIXELFORMAT_DEPTH_STENCIL pixel format is properly reported as renderable. +- the DXGIFormats for SG_PIXELFORMAT_DEPTH_STENCIL images are now as follows: + - D3D11 texture object: DXGI_FORMAT_R24G8_TYPELESS + - D3D11 shader-resource-view object: DXGI_FORMAT_R24_UNORM_X8_TYPELESS + - D3D11 depth-stencil-view object: DXGI_FORMAT_D24_UNORM_S8_UINT + +Related PR: https://github.com/floooh/sokol/pull/937 + +#### 30-Oct-2023 + +Some sokol_gfx.h backend-specific updates and tweaks (very minor chance that this is breaking if you are injecting textures into the D3D11 backend). + +- a new set of public API functions to access the native backend 3D-API resource objects of + sokol-gfx resource objects: + + ``` + sg_[api]_[type]_info sg_[api]_query_[type]_info(sg_[type]) + ``` + ...where `[api]` is any of `[gl, d3d11, mtl, wgpu]` and `[type]` is any of `[buffer, image, sampler, shader, pipeline, pass]`. + + This is mainly useful when mixing native 3D-API code with sokol-gfx code. + + See issue https://github.com/floooh/sokol/issues/931 for details. + +- WebGPU backend: `sg_make_image()` will no longer automatically create a WebGPU texture-view object when injecting a WebGPU texture object, instead +this must now be explicitly provided. + +- D3D11 backend: `sg_make_image()` will no longer automatically create a +shader-resource-view object when injecting a D3D11 texture object, and +vice versa, a texture object will no longer be looked up from an injected +shader-resource-view object (e.g. the injection rules are now more straightforward and explicit). See issue https://github.com/floooh/sokol/issues/930 for details. + +For the detailed changes, see PR https://github.com/floooh/sokol/pull/932. + #### 27-Oct-2023 Fix broken render-to-mipmap in the sokol_gfx.h GL backend. @@ -134,7 +748,7 @@ The major topic of this update is the 'finalized' WebGPU support in sokol_gfx.h `sg_frame_stats` returned by the new sokol_gfx.h function `sg_query_frame_stats()`. - The sokol-samples repository gained 3 new samples: - - cubemap-jpeg-sapp.c (load a cubemap from seperate JPEG files) + - cubemap-jpeg-sapp.c (load a cubemap from separate JPEG files) - cubemaprt-sapp.c (render into cubemap faces - this demo actually existed a while but wasn't "official" so far) - drawcallperf-sapp.c (a sample to explore the performance overhead of sg_apply_bindings, sg_apply_uniforms and sg_draw) @@ -281,7 +895,7 @@ The main topic of this update is to separate sampler state from image state in sokol_gfx.h which became possible after GLES2 support had been removed from sokol_gfx.h. -This also causes some 'colateral changes' in shader authoring and +This also causes some 'collateral changes' in shader authoring and other sokol headers, but there was opportunity to fill a few feature gaps in sokol_gfx.h as well: @@ -706,7 +1320,7 @@ GLES2/WebGL1 support has been removed from the sokol headers (now that A new header ```sokol_log.h``` has been added to provide a standard logging callback implementation which provides logging output on all platforms to stderr and/or platform specific logging facilities. ```sokol_log.h``` only uses fputs() and platform specific logging function instead - of fprintf() to preverse some executable size. + of fprintf() to preserve some executable size. **QUESTION**: Why are the sokol headers now silent, unless a logging callback is installed? This is mainly because a standard logging function which does something meaningful on all @@ -793,7 +1407,7 @@ GLES2/WebGL1 support has been removed from the sokol headers (now that buffer with retained references). - **15-Dec-2022**: A small but important update in sokol_imgui.h which fixes - touch input handling on mobile devices. Many thanks to github user @Xadiant + touch input handling on mobile devices. Many thanks to GitHub user @Xadiant for the bug investigation and [PR](https://github.com/floooh/sokol/pull/760). - **25-Nov-2022**: Some code cleanup around resource creation and destruction in sokol_gfx.h: @@ -869,7 +1483,7 @@ GLES2/WebGL1 support has been removed from the sokol headers (now that - **03-Nov-2022** The language bindings generation has been updated for Zig 0.10.0, and clang-14 (there was a minor change in the JSON ast-dump format). - Many thanks to github user @kcbanner for the Zig PR! + Many thanks to GitHub user @kcbanner for the Zig PR! - **02-Nov-2022** A new header sokol_spine.h (in the util dir), this is a renderer and 'handle wrapper' around the spine-c runtime (Spine is a popular 2D @@ -882,14 +1496,14 @@ GLES2/WebGL1 support has been removed from the sokol headers (now that - **22-Oct-2022** All sokol headers now allow to override logging with a callback function (installed in the setup call) instead of defining a SOKOL_LOG macro. Overriding SOKOL_LOG still works as default fallback, but this is no - longer documented, consider this deprecated. Many thanks to github user + longer documented, consider this deprecated. Many thanks to GitHub user @Manuzor for the PR (see https://github.com/floooh/sokol/pull/721 for details) - **21-Oct-2022** RGB9E5 pixel format support in sokol_gfx.h and a GLES2 related bugfix in the sokol_app.h Android backend: - sokol_gfx.h now supports RGB9E5 textures (3*9 bit RGB + 5 bit shared exponent), this works in all backends except GLES2 and WebGL1 (use ```sg_query_pixelformat()``` - to check for runtime support). Many thanks to github user @allcreater for the PR! + to check for runtime support). Many thanks to GitHub user @allcreater for the PR! - a bugfix in the sokol_app.h Android backend: when forcing a GLES2 context via sapp_desc.gl_force_gles2, the Android backend correctly created a GLES2 context, but then didn't communicate this through the function ```sapp_gles2()``` (which @@ -941,8 +1555,8 @@ GLES2/WebGL1 support has been removed from the sokol headers (now that GLX for the window system glue code and can create a GLES2 or GLES3 context instead of a 'desktop GL' context. To get EGL+GLES2/GLES3, just define SOKOL_GLES2 or SOKOL_GLES3 to compile the - implementation. To get EGL+GL, define SOKOL_GLCORE33 *and* SOKOL_FORCE_EGL. - By default, defining just SOKOL_GLCORE33 uses GLX for the window system glue + implementation. To get EGL+GL, define SOKOL_GLCORE *and* SOKOL_FORCE_EGL. + By default, defining just SOKOL_GLCORE uses GLX for the window system glue (just as before). Many thanks to GH user @billzez for the PR! - **10-Sep-2022**: sokol_app.h and sokol_args.h has been fixed for Emscripten 3.21, those headers @@ -992,7 +1606,7 @@ work. - **29-May-2022**: The code generation scripts for the [sokol-nim](https://github.com/floooh/sokol-nim) language bindings have been revised and updated, many thanks to Gustav Olsson for the PR! (I'm planning to -spend a few more days integrating the bindings generation with Github Actions, +spend a few more days integrating the bindings generation with GitHub Actions, so that it's easier to publish new bindings after updates to the sokol headers). - **26-May-2022**: The GL backend in sokol_app.h now allows to override the GL @@ -1005,7 +1619,7 @@ so that it's easier to publish new bindings after updates to the sokol headers). (Android, iOS, web). Furthermore, on macOS only the GL versions 3.2 and 4.1 are available (plus the special config major=1 minor=0 creates an NSOpenGLProfileVersionLegacy context). In general: use at your risk :) Many - thanks to Github user @pplux for the PR! + thanks to GitHub user @pplux for the PR! - **15-May-2022**: The way internal memory allocation can be overridden with your own functions has been changed from global macros to callbacks @@ -1191,7 +1805,7 @@ so that it's easier to publish new bindings after updates to the sokol headers). of uniform block members. The default (SG_UNIFORMLAYOUT_NATIVE) keeps the same behaviour, so existing code shouldn't need to be changed. With the packing rule SG_UNIFORMLAYOUT_STD140 the uniform block interior is expected to be - layed out according to the OpenGL std140 packing rule. + laid out according to the OpenGL std140 packing rule. - Note that the SG_UNIFORMLAYOUT_STD140 only allows a subset of the actual std140 packing rule: arrays are only allowed for the types vec4, int4 and mat4. This is because the uniform data must still be compatible with @@ -1243,7 +1857,7 @@ so that it's easier to publish new bindings after updates to the sokol headers). - **19-Dec-2021**: some sokol_audio.h changes: - on Windows, sokol_audio.h no longer converts audio samples from float to int16_t, but instead configures WASAPI to directly accept - float samples. Many thanks to github user iOrange for the PR! + float samples. Many thanks to GitHub user iOrange for the PR! - sokol_audio.h has a new public function ```saudio_suspended()``` which returns true if the audio device/context is currently in suspended mode. On all backends except WebAudio this always returns false. This allows diff --git a/thirdparty/sokol/sokol_app.h b/thirdparty/sokol/sokol_app.h index 5f6d874..790e9de 100644 --- a/thirdparty/sokol/sokol_app.h +++ b/thirdparty/sokol/sokol_app.h @@ -18,11 +18,12 @@ the backend selected for sokol_gfx.h if both are used in the same project): - #define SOKOL_GLCORE33 + #define SOKOL_GLCORE #define SOKOL_GLES3 #define SOKOL_D3D11 #define SOKOL_METAL #define SOKOL_WGPU + #define SOKOL_NOAPI Optionally provide the following defines with your own implementations: @@ -47,13 +48,13 @@ On Windows, SOKOL_DLL will define SOKOL_APP_API_DECL as __declspec(dllexport) or __declspec(dllimport) as needed. - On Linux, SOKOL_GLCORE33 can use either GLX or EGL. + On Linux, SOKOL_GLCORE can use either GLX or EGL. GLX is default, set SOKOL_FORCE_EGL to override. For example code, see https://github.com/floooh/sokol-samples/tree/master/sapp Portions of the Windows and Linux GL initialization, event-, icon- etc... code - have been taken from GLFW (http://www.glfw.org/) + have been taken from GLFW (http://www.glfw.org/). iOS onscreen keyboard support 'inspired' by libgdx. @@ -87,7 +88,7 @@ - makes the rendered frame visible - provides keyboard-, mouse- and low-level touch-events - platforms: MacOS, iOS, HTML5, Win32, Linux/RaspberryPi, Android - - 3D-APIs: Metal, D3D11, GL3.2, GLES3, WebGL, WebGL2 + - 3D-APIs: Metal, D3D11, GL4.1, GL4.3, GLES3, WebGL, WebGL2, NOAPI FEATURE/PLATFORM MATRIX ======================= @@ -97,6 +98,7 @@ gles3/webgl2 | --- | --- | YES(2)| YES | YES | YES metal | --- | YES | --- | YES | --- | --- d3d11 | YES | --- | --- | --- | --- | --- + noapi | YES | TODO | TODO | --- | TODO | --- KEY_DOWN | YES | YES | YES | SOME | TODO | YES KEY_UP | YES | YES | YES | SOME | TODO | YES CHAR | YES | YES | YES | YES | TODO | YES @@ -313,10 +315,15 @@ objects and values required for rendering. If sokol_app.h is not compiled with SOKOL_WGPU, these functions return null. - const uint32_t sapp_gl_get_framebuffer(void) + uint32_t sapp_gl_get_framebuffer(void) This returns the 'default framebuffer' of the GL context. Typically this will be zero. + int sapp_gl_get_major_version(void) + int sapp_gl_get_minor_version(void) + Returns the major and minor version of the GL context + (only for SOKOL_GLCORE, all other backends return zero here, including SOKOL_GLES3) + const void* sapp_android_get_native_activity(void); On Android, get the native activity ANativeActivity pointer, otherwise a null pointer. @@ -348,7 +355,7 @@ sapp_consume_event() from inside the event handler (NOTE that this behaviour is currently only implemented for some HTML5 events, support for other platforms and event types will - be added as needed, please open a github ticket and/or provide + be added as needed, please open a GitHub ticket and/or provide a PR if needed). NOTE: Do *not* call any 3D API rendering functions in the event @@ -1547,7 +1554,7 @@ typedef struct sapp_allocator { #define _SAPP_LOG_ITEMS \ _SAPP_LOGITEM_XMACRO(OK, "Ok") \ _SAPP_LOGITEM_XMACRO(MALLOC_FAILED, "memory allocation failed") \ - _SAPP_LOGITEM_XMACRO(MACOS_INVALID_NSOPENGL_PROFILE, "macos: invalid NSOpenGLProfile (valid choices are 1.0, 3.2 and 4.1)") \ + _SAPP_LOGITEM_XMACRO(MACOS_INVALID_NSOPENGL_PROFILE, "macos: invalid NSOpenGLProfile (valid choices are 1.0 and 4.1)") \ _SAPP_LOGITEM_XMACRO(WIN32_LOAD_OPENGL32_DLL_FAILED, "failed loading opengl32.dll") \ _SAPP_LOGITEM_XMACRO(WIN32_CREATE_HELPER_WINDOW_FAILED, "failed to create helper window") \ _SAPP_LOGITEM_XMACRO(WIN32_HELPER_WINDOW_GETDC_FAILED, "failed to get helper window DC") \ @@ -1560,7 +1567,7 @@ typedef struct sapp_allocator { _SAPP_LOGITEM_XMACRO(WIN32_WGL_SET_PIXELFORMAT_FAILED, "failed to set selected pixel format") \ _SAPP_LOGITEM_XMACRO(WIN32_WGL_ARB_CREATE_CONTEXT_REQUIRED, "ARB_create_context required") \ _SAPP_LOGITEM_XMACRO(WIN32_WGL_ARB_CREATE_CONTEXT_PROFILE_REQUIRED, "ARB_create_context_profile required") \ - _SAPP_LOGITEM_XMACRO(WIN32_WGL_OPENGL_3_2_NOT_SUPPORTED, "OpenGL 3.2 not supported by GL driver (ERROR_INVALID_VERSION_ARB)") \ + _SAPP_LOGITEM_XMACRO(WIN32_WGL_OPENGL_VERSION_NOT_SUPPORTED, "requested OpenGL version not supported by GL driver (ERROR_INVALID_VERSION_ARB)") \ _SAPP_LOGITEM_XMACRO(WIN32_WGL_OPENGL_PROFILE_NOT_SUPPORTED, "requested OpenGL profile not support by GL driver (ERROR_INVALID_PROFILE_ARB)") \ _SAPP_LOGITEM_XMACRO(WIN32_WGL_INCOMPATIBLE_DEVICE_CONTEXT, "CreateContextAttribsARB failed with ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB") \ _SAPP_LOGITEM_XMACRO(WIN32_WGL_CREATE_CONTEXT_ATTRIBS_FAILED_OTHER, "CreateContextAttribsARB failed for other reason") \ @@ -1701,7 +1708,7 @@ typedef struct sapp_desc { sapp_logger logger; // logging callback override (default: NO LOGGING!) // backend-specific options - int gl_major_version; // override GL major and minor version (the default GL version is 3.2) + int gl_major_version; // override GL major and minor version (the default GL version is 4.1 on macOS, 4.3 elsewhere) int gl_minor_version; bool win32_console_utf8; // if true, set the output console codepage to UTF-8 bool win32_console_create; // if true, attach stdout/stderr to a new console window @@ -1892,6 +1899,10 @@ SOKOL_APP_API_DECL const void* sapp_wgpu_get_depth_stencil_view(void); /* GL: get framebuffer object */ SOKOL_APP_API_DECL uint32_t sapp_gl_get_framebuffer(void); +/* GL: get major version (only valid for desktop GL) */ +SOKOL_APP_API_DECL int sapp_gl_get_major_version(void); +/* GL: get minor version (only valid for desktop GL) */ +SOKOL_APP_API_DECL int sapp_gl_get_minor_version(void); /* Android: get native activity handle */ SOKOL_APP_API_DECL const void* sapp_android_get_native_activity(void); @@ -1929,7 +1940,7 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #endif #include // malloc, free -#include // memset +#include // memset, strncmp #include // size_t #include // roundf @@ -1959,8 +1970,8 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #if defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE /* MacOS */ #define _SAPP_MACOS (1) - #if !defined(SOKOL_METAL) && !defined(SOKOL_GLCORE33) - #error("sokol_app.h: unknown 3D API selected for MacOS, must be SOKOL_METAL or SOKOL_GLCORE33") + #if !defined(SOKOL_METAL) && !defined(SOKOL_GLCORE) + #error("sokol_app.h: unknown 3D API selected for MacOS, must be SOKOL_METAL or SOKOL_GLCORE") #endif #else /* iOS or iOS Simulator */ @@ -1978,8 +1989,8 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #elif defined(_WIN32) /* Windows (D3D11 or GL) */ #define _SAPP_WIN32 (1) - #if !defined(SOKOL_D3D11) && !defined(SOKOL_GLCORE33) - #error("sokol_app.h: unknown 3D API selected for Win32, must be SOKOL_D3D11 or SOKOL_GLCORE33") + #if !defined(SOKOL_D3D11) && !defined(SOKOL_GLCORE) && !defined(SOKOL_NOAPI) + #error("sokol_app.h: unknown 3D API selected for Win32, must be SOKOL_D3D11, SOKOL_GLCORE or SOKOL_NOAPI") #endif #elif defined(__ANDROID__) /* Android */ @@ -1993,7 +2004,7 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #elif defined(__linux__) || defined(__unix__) /* Linux */ #define _SAPP_LINUX (1) - #if defined(SOKOL_GLCORE33) + #if defined(SOKOL_GLCORE) #if !defined(SOKOL_FORCE_EGL) #define _SAPP_GLX (1) #endif @@ -2003,13 +2014,13 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); } #include #include #else - #error("sokol_app.h: unknown 3D API selected for Linux, must be SOKOL_GLCORE33, SOKOL_GLES3") + #error("sokol_app.h: unknown 3D API selected for Linux, must be SOKOL_GLCORE, SOKOL_GLES3") #endif #else #error "sokol_app.h: Unknown platform" #endif -#if defined(SOKOL_GLCORE33) || defined(SOKOL_GLES3) +#if defined(SOKOL_GLCORE) || defined(SOKOL_GLES3) #define _SAPP_ANY_GL (1) #endif @@ -2399,11 +2410,11 @@ _SOKOL_PRIVATE double _sapp_timing_get_avg(_sapp_timing_t* t) { #if defined(SOKOL_METAL) @interface _sapp_macos_view : MTKView @end -#elif defined(SOKOL_GLCORE33) +#elif defined(SOKOL_GLCORE) @interface _sapp_macos_view : NSOpenGLView - (void)timerFired:(id)sender; @end -#endif // SOKOL_GLCORE33 +#endif // SOKOL_GLCORE typedef struct { uint32_t flags_changed_store; @@ -2545,7 +2556,7 @@ typedef struct { uint8_t raw_input_data[256]; } _sapp_win32_t; -#if defined(SOKOL_GLCORE33) +#if defined(SOKOL_GLCORE) #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 #define WGL_SUPPORT_OPENGL_ARB 0x2010 #define WGL_DRAW_TO_WINDOW_ARB 0x2001 @@ -2596,7 +2607,7 @@ typedef struct { PFNWGLGETEXTENSIONSSTRINGARBPROC GetExtensionsStringARB; PFNWGLCREATECONTEXTATTRIBSARBPROC CreateContextAttribsARB; // special case glGetIntegerv - void (*GetIntegerv)(uint32_t pname, int32_t* data); + void (WINAPI *GetIntegerv)(uint32_t pname, int32_t* data); bool ext_swap_control; bool arb_multisample; bool arb_pixel_format; @@ -2605,7 +2616,7 @@ typedef struct { HWND msg_hwnd; HDC msg_dc; } _sapp_wgl_t; -#endif // SOKOL_GLCORE33 +#endif // SOKOL_GLCORE #endif // _SAPP_WIN32 @@ -2657,6 +2668,7 @@ typedef struct { #if defined(_SAPP_LINUX) #define _SAPP_X11_XDND_VERSION (5) +#define _SAPP_X11_MAX_X11_KEYCODES (256) #define GLX_VENDOR 1 #define GLX_RGBA_BIT 0x00000001 @@ -2750,6 +2762,9 @@ typedef struct { Atom NET_WM_STATE_FULLSCREEN; _sapp_xi_t xi; _sapp_xdnd_t xdnd; + // XLib manual says keycodes are in the range [8, 255] inclusive. + // https://tronche.com/gui/x/xlib/input/keyboard-encoding.html + bool key_repeat[_SAPP_X11_MAX_X11_KEYCODES]; } _sapp_x11_t; #if defined(_SAPP_GLX) @@ -2876,7 +2891,7 @@ typedef struct { _sapp_win32_t win32; #if defined(SOKOL_D3D11) _sapp_d3d11_t d3d11; - #elif defined(SOKOL_GLCORE33) + #elif defined(SOKOL_GLCORE) _sapp_wgl_t wgl; #endif #elif defined(_SAPP_ANDROID) @@ -3085,8 +3100,13 @@ _SOKOL_PRIVATE sapp_desc _sapp_desc_defaults(const sapp_desc* desc) { // (or expressed differently: zero is a valid value for gl_minor_version // and can't be used to indicate 'default') if (0 == res.gl_major_version) { - res.gl_major_version = 3; - res.gl_minor_version = 2; + #if defined(_SAPP_APPLE) + res.gl_major_version = 4; + res.gl_minor_version = 1; + #else + res.gl_major_version = 4; + res.gl_minor_version = 3; + #endif } res.html5_canvas_name = _sapp_def(res.html5_canvas_name, "canvas"); res.clipboard_size = _sapp_def(res.clipboard_size, 8192); @@ -3650,7 +3670,7 @@ _SOKOL_PRIVATE void _sapp_macos_update_dimensions(void) { const int cur_fb_height = (int)roundf(fb_size.height); const bool dim_changed = (_sapp.framebuffer_width != cur_fb_width) || (_sapp.framebuffer_height != cur_fb_height); - #elif defined(SOKOL_GLCORE33) + #elif defined(SOKOL_GLCORE) const int cur_fb_width = (int)roundf(bounds.size.width * _sapp.dpi_scale); const int cur_fb_height = (int)roundf(bounds.size.height * _sapp.dpi_scale); const bool dim_changed = (_sapp.framebuffer_width != cur_fb_width) || @@ -3892,7 +3912,7 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { _sapp.macos.window.contentView = _sapp.macos.view; [_sapp.macos.window makeFirstResponder:_sapp.macos.view]; _sapp.macos.view.layer.magnificationFilter = kCAFilterNearest; - #elif defined(SOKOL_GLCORE33) + #elif defined(SOKOL_GLCORE) NSOpenGLPixelFormatAttribute attrs[32]; int i = 0; attrs[i++] = NSOpenGLPFAAccelerated; @@ -4124,7 +4144,7 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) { @end @implementation _sapp_macos_view -#if defined(SOKOL_GLCORE33) +#if defined(SOKOL_GLCORE) - (void)timerFired:(id)sender { _SOKOL_UNUSED(sender); [self setNeedsDisplay:YES]; @@ -4224,7 +4244,7 @@ _SOKOL_PRIVATE void _sapp_macos_poll_input_events(void) { // helper function to make GL context active static void _sapp_gl_make_current(void) { - #if defined(SOKOL_GLCORE33) + #if defined(SOKOL_GLCORE) [[_sapp.macos.view openGLContext] makeCurrentContext]; #endif } @@ -5749,16 +5769,28 @@ _SOKOL_PRIVATE void _sapp_emsc_wgpu_request_adapter_cb(WGPURequestAdapterStatus SOKOL_ASSERT(adapter); _sapp.wgpu.adapter = adapter; size_t cur_feature_index = 1; - WGPUFeatureName requiredFeatures[8] = { + #define _SAPP_WGPU_MAX_REQUESTED_FEATURES (8) + WGPUFeatureName requiredFeatures[_SAPP_WGPU_MAX_REQUESTED_FEATURES] = { WGPUFeatureName_Depth32FloatStencil8, }; // check for optional features we're interested in - // FIXME: ASTC texture compression if (wgpuAdapterHasFeature(adapter, WGPUFeatureName_TextureCompressionBC)) { + SOKOL_ASSERT(cur_feature_index < _SAPP_WGPU_MAX_REQUESTED_FEATURES); requiredFeatures[cur_feature_index++] = WGPUFeatureName_TextureCompressionBC; - } else if (wgpuAdapterHasFeature(adapter, WGPUFeatureName_TextureCompressionETC2)) { + } + if (wgpuAdapterHasFeature(adapter, WGPUFeatureName_TextureCompressionETC2)) { + SOKOL_ASSERT(cur_feature_index < _SAPP_WGPU_MAX_REQUESTED_FEATURES); requiredFeatures[cur_feature_index++] = WGPUFeatureName_TextureCompressionETC2; } + if (wgpuAdapterHasFeature(adapter, WGPUFeatureName_TextureCompressionASTC)) { + SOKOL_ASSERT(cur_feature_index < _SAPP_WGPU_MAX_REQUESTED_FEATURES); + requiredFeatures[cur_feature_index++] = WGPUFeatureName_TextureCompressionASTC; + } + if (wgpuAdapterHasFeature(adapter, WGPUFeatureName_Float32Filterable)) { + SOKOL_ASSERT(cur_feature_index < _SAPP_WGPU_MAX_REQUESTED_FEATURES); + requiredFeatures[cur_feature_index++] = WGPUFeatureName_Float32Filterable; + } + #undef _SAPP_WGPU_MAX_REQUESTED_FEATURES WGPUDeviceDescriptor dev_desc; _sapp_clear(&dev_desc, sizeof(dev_desc)); @@ -5945,7 +5977,7 @@ int main(int argc, char* argv[]) { // ██████ ███████ ██ ██ ███████ ███████ ██ ███████ ██ ██ ███████ // // >>gl helpers -#if defined(SOKOL_GLCORE33) +#if defined(SOKOL_GLCORE) typedef struct { int red_bits; int green_bits; @@ -6275,6 +6307,7 @@ _SOKOL_PRIVATE void _sapp_win32_init_keytable(void) { _sapp.keycodes[0x138] = SAPP_KEYCODE_RIGHT_ALT; _sapp.keycodes[0x11D] = SAPP_KEYCODE_RIGHT_CONTROL; _sapp.keycodes[0x036] = SAPP_KEYCODE_RIGHT_SHIFT; + _sapp.keycodes[0x136] = SAPP_KEYCODE_RIGHT_SHIFT; _sapp.keycodes[0x15C] = SAPP_KEYCODE_RIGHT_SUPER; _sapp.keycodes[0x150] = SAPP_KEYCODE_DOWN; _sapp.keycodes[0x14B] = SAPP_KEYCODE_LEFT; @@ -6596,7 +6629,7 @@ _SOKOL_PRIVATE void _sapp_d3d11_present(bool do_not_wait) { #endif /* SOKOL_D3D11 */ -#if defined(SOKOL_GLCORE33) +#if defined(SOKOL_GLCORE) _SOKOL_PRIVATE void _sapp_wgl_init(void) { _sapp.wgl.opengl32 = LoadLibraryA("opengl32.dll"); if (!_sapp.wgl.opengl32) { @@ -6613,7 +6646,7 @@ _SOKOL_PRIVATE void _sapp_wgl_init(void) { SOKOL_ASSERT(_sapp.wgl.GetCurrentDC); _sapp.wgl.MakeCurrent = (PFN_wglMakeCurrent)(void*) GetProcAddress(_sapp.wgl.opengl32, "wglMakeCurrent"); SOKOL_ASSERT(_sapp.wgl.MakeCurrent); - _sapp.wgl.GetIntegerv = (void(*)(uint32_t, int32_t*)) GetProcAddress(_sapp.wgl.opengl32, "glGetIntegerv"); + _sapp.wgl.GetIntegerv = (void(WINAPI*)(uint32_t, int32_t*)) GetProcAddress(_sapp.wgl.opengl32, "glGetIntegerv"); SOKOL_ASSERT(_sapp.wgl.GetIntegerv); _sapp.wgl.msg_hwnd = CreateWindowExW(WS_EX_OVERLAPPEDWINDOW, @@ -6862,7 +6895,7 @@ _SOKOL_PRIVATE void _sapp_wgl_create_context(void) { if (!_sapp.wgl.gl_ctx) { const DWORD err = GetLastError(); if (err == (0xc0070000 | ERROR_INVALID_VERSION_ARB)) { - _SAPP_PANIC(WIN32_WGL_OPENGL_3_2_NOT_SUPPORTED); + _SAPP_PANIC(WIN32_WGL_OPENGL_VERSION_NOT_SUPPORTED); } else if (err == (0xc0070000 | ERROR_INVALID_PROFILE_ARB)) { _SAPP_PANIC(WIN32_WGL_OPENGL_PROFILE_NOT_SUPPORTED); @@ -6894,7 +6927,7 @@ _SOKOL_PRIVATE void _sapp_wgl_swap_buffers(void) { /* FIXME: DwmIsCompositionEnabled? (see GLFW) */ SwapBuffers(_sapp.win32.dc); } -#endif /* SOKOL_GLCORE33 */ +#endif /* SOKOL_GLCORE */ _SOKOL_PRIVATE bool _sapp_win32_wide_to_utf8(const wchar_t* src, char* dst, int dst_num_bytes) { SOKOL_ASSERT(src && dst && (dst_num_bytes > 1)); @@ -7311,7 +7344,10 @@ _SOKOL_PRIVATE void _sapp_win32_timing_measure(void) { // fallback if swap model isn't "flip-discard" or GetFrameStatistics failed for another reason _sapp_timing_measure(&_sapp.timing); #endif - #if defined(SOKOL_GLCORE33) + #if defined(SOKOL_GLCORE) + _sapp_timing_measure(&_sapp.timing); + #endif + #if defined(SOKOL_NOAPI) _sapp_timing_measure(&_sapp.timing); #endif } @@ -7513,7 +7549,7 @@ _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM // present with DXGI_PRESENT_DO_NOT_WAIT _sapp_d3d11_present(true); #endif - #if defined(SOKOL_GLCORE33) + #if defined(SOKOL_GLCORE) _sapp_wgl_swap_buffers(); #endif /* NOTE: resizing the swap-chain during resize leads to a substantial @@ -7926,7 +7962,7 @@ _SOKOL_PRIVATE void _sapp_win32_run(const sapp_desc* desc) { _sapp_d3d11_create_device_and_swapchain(); _sapp_d3d11_create_default_render_target(); #endif - #if defined(SOKOL_GLCORE33) + #if defined(SOKOL_GLCORE) _sapp_wgl_init(); _sapp_wgl_load_extensions(); _sapp_wgl_create_context(); @@ -7954,7 +7990,7 @@ _SOKOL_PRIVATE void _sapp_win32_run(const sapp_desc* desc) { Sleep((DWORD)(16 * _sapp.swap_interval)); } #endif - #if defined(SOKOL_GLCORE33) + #if defined(SOKOL_GLCORE) _sapp_wgl_swap_buffers(); #endif /* check for window resized, this cannot happen in WM_SIZE as it explodes memory usage */ @@ -9605,6 +9641,354 @@ _SOKOL_PRIVATE void _sapp_x11_init_extensions(void) { } } +// translate the X11 KeySyms for a key to sokol-app key code +// NOTE: this is only used as a fallback, in case the XBK method fails +// it is layout-dependent and will fail partially on most non-US layouts. +// +_SOKOL_PRIVATE sapp_keycode _sapp_x11_translate_keysyms(const KeySym* keysyms, int width) { + if (width > 1) { + switch (keysyms[1]) { + case XK_KP_0: return SAPP_KEYCODE_KP_0; + case XK_KP_1: return SAPP_KEYCODE_KP_1; + case XK_KP_2: return SAPP_KEYCODE_KP_2; + case XK_KP_3: return SAPP_KEYCODE_KP_3; + case XK_KP_4: return SAPP_KEYCODE_KP_4; + case XK_KP_5: return SAPP_KEYCODE_KP_5; + case XK_KP_6: return SAPP_KEYCODE_KP_6; + case XK_KP_7: return SAPP_KEYCODE_KP_7; + case XK_KP_8: return SAPP_KEYCODE_KP_8; + case XK_KP_9: return SAPP_KEYCODE_KP_9; + case XK_KP_Separator: + case XK_KP_Decimal: return SAPP_KEYCODE_KP_DECIMAL; + case XK_KP_Equal: return SAPP_KEYCODE_KP_EQUAL; + case XK_KP_Enter: return SAPP_KEYCODE_KP_ENTER; + default: break; + } + } + + switch (keysyms[0]) { + case XK_Escape: return SAPP_KEYCODE_ESCAPE; + case XK_Tab: return SAPP_KEYCODE_TAB; + case XK_Shift_L: return SAPP_KEYCODE_LEFT_SHIFT; + case XK_Shift_R: return SAPP_KEYCODE_RIGHT_SHIFT; + case XK_Control_L: return SAPP_KEYCODE_LEFT_CONTROL; + case XK_Control_R: return SAPP_KEYCODE_RIGHT_CONTROL; + case XK_Meta_L: + case XK_Alt_L: return SAPP_KEYCODE_LEFT_ALT; + case XK_Mode_switch: // Mapped to Alt_R on many keyboards + case XK_ISO_Level3_Shift: // AltGr on at least some machines + case XK_Meta_R: + case XK_Alt_R: return SAPP_KEYCODE_RIGHT_ALT; + case XK_Super_L: return SAPP_KEYCODE_LEFT_SUPER; + case XK_Super_R: return SAPP_KEYCODE_RIGHT_SUPER; + case XK_Menu: return SAPP_KEYCODE_MENU; + case XK_Num_Lock: return SAPP_KEYCODE_NUM_LOCK; + case XK_Caps_Lock: return SAPP_KEYCODE_CAPS_LOCK; + case XK_Print: return SAPP_KEYCODE_PRINT_SCREEN; + case XK_Scroll_Lock: return SAPP_KEYCODE_SCROLL_LOCK; + case XK_Pause: return SAPP_KEYCODE_PAUSE; + case XK_Delete: return SAPP_KEYCODE_DELETE; + case XK_BackSpace: return SAPP_KEYCODE_BACKSPACE; + case XK_Return: return SAPP_KEYCODE_ENTER; + case XK_Home: return SAPP_KEYCODE_HOME; + case XK_End: return SAPP_KEYCODE_END; + case XK_Page_Up: return SAPP_KEYCODE_PAGE_UP; + case XK_Page_Down: return SAPP_KEYCODE_PAGE_DOWN; + case XK_Insert: return SAPP_KEYCODE_INSERT; + case XK_Left: return SAPP_KEYCODE_LEFT; + case XK_Right: return SAPP_KEYCODE_RIGHT; + case XK_Down: return SAPP_KEYCODE_DOWN; + case XK_Up: return SAPP_KEYCODE_UP; + case XK_F1: return SAPP_KEYCODE_F1; + case XK_F2: return SAPP_KEYCODE_F2; + case XK_F3: return SAPP_KEYCODE_F3; + case XK_F4: return SAPP_KEYCODE_F4; + case XK_F5: return SAPP_KEYCODE_F5; + case XK_F6: return SAPP_KEYCODE_F6; + case XK_F7: return SAPP_KEYCODE_F7; + case XK_F8: return SAPP_KEYCODE_F8; + case XK_F9: return SAPP_KEYCODE_F9; + case XK_F10: return SAPP_KEYCODE_F10; + case XK_F11: return SAPP_KEYCODE_F11; + case XK_F12: return SAPP_KEYCODE_F12; + case XK_F13: return SAPP_KEYCODE_F13; + case XK_F14: return SAPP_KEYCODE_F14; + case XK_F15: return SAPP_KEYCODE_F15; + case XK_F16: return SAPP_KEYCODE_F16; + case XK_F17: return SAPP_KEYCODE_F17; + case XK_F18: return SAPP_KEYCODE_F18; + case XK_F19: return SAPP_KEYCODE_F19; + case XK_F20: return SAPP_KEYCODE_F20; + case XK_F21: return SAPP_KEYCODE_F21; + case XK_F22: return SAPP_KEYCODE_F22; + case XK_F23: return SAPP_KEYCODE_F23; + case XK_F24: return SAPP_KEYCODE_F24; + case XK_F25: return SAPP_KEYCODE_F25; + + // numeric keypad + case XK_KP_Divide: return SAPP_KEYCODE_KP_DIVIDE; + case XK_KP_Multiply: return SAPP_KEYCODE_KP_MULTIPLY; + case XK_KP_Subtract: return SAPP_KEYCODE_KP_SUBTRACT; + case XK_KP_Add: return SAPP_KEYCODE_KP_ADD; + + // these should have been detected in secondary keysym test above! + case XK_KP_Insert: return SAPP_KEYCODE_KP_0; + case XK_KP_End: return SAPP_KEYCODE_KP_1; + case XK_KP_Down: return SAPP_KEYCODE_KP_2; + case XK_KP_Page_Down: return SAPP_KEYCODE_KP_3; + case XK_KP_Left: return SAPP_KEYCODE_KP_4; + case XK_KP_Right: return SAPP_KEYCODE_KP_6; + case XK_KP_Home: return SAPP_KEYCODE_KP_7; + case XK_KP_Up: return SAPP_KEYCODE_KP_8; + case XK_KP_Page_Up: return SAPP_KEYCODE_KP_9; + case XK_KP_Delete: return SAPP_KEYCODE_KP_DECIMAL; + case XK_KP_Equal: return SAPP_KEYCODE_KP_EQUAL; + case XK_KP_Enter: return SAPP_KEYCODE_KP_ENTER; + + // last resort: Check for printable keys (should not happen if the XKB + // extension is available). This will give a layout dependent mapping + // (which is wrong, and we may miss some keys, especially on non-US + // keyboards), but it's better than nothing... + case XK_a: return SAPP_KEYCODE_A; + case XK_b: return SAPP_KEYCODE_B; + case XK_c: return SAPP_KEYCODE_C; + case XK_d: return SAPP_KEYCODE_D; + case XK_e: return SAPP_KEYCODE_E; + case XK_f: return SAPP_KEYCODE_F; + case XK_g: return SAPP_KEYCODE_G; + case XK_h: return SAPP_KEYCODE_H; + case XK_i: return SAPP_KEYCODE_I; + case XK_j: return SAPP_KEYCODE_J; + case XK_k: return SAPP_KEYCODE_K; + case XK_l: return SAPP_KEYCODE_L; + case XK_m: return SAPP_KEYCODE_M; + case XK_n: return SAPP_KEYCODE_N; + case XK_o: return SAPP_KEYCODE_O; + case XK_p: return SAPP_KEYCODE_P; + case XK_q: return SAPP_KEYCODE_Q; + case XK_r: return SAPP_KEYCODE_R; + case XK_s: return SAPP_KEYCODE_S; + case XK_t: return SAPP_KEYCODE_T; + case XK_u: return SAPP_KEYCODE_U; + case XK_v: return SAPP_KEYCODE_V; + case XK_w: return SAPP_KEYCODE_W; + case XK_x: return SAPP_KEYCODE_X; + case XK_y: return SAPP_KEYCODE_Y; + case XK_z: return SAPP_KEYCODE_Z; + case XK_1: return SAPP_KEYCODE_1; + case XK_2: return SAPP_KEYCODE_2; + case XK_3: return SAPP_KEYCODE_3; + case XK_4: return SAPP_KEYCODE_4; + case XK_5: return SAPP_KEYCODE_5; + case XK_6: return SAPP_KEYCODE_6; + case XK_7: return SAPP_KEYCODE_7; + case XK_8: return SAPP_KEYCODE_8; + case XK_9: return SAPP_KEYCODE_9; + case XK_0: return SAPP_KEYCODE_0; + case XK_space: return SAPP_KEYCODE_SPACE; + case XK_minus: return SAPP_KEYCODE_MINUS; + case XK_equal: return SAPP_KEYCODE_EQUAL; + case XK_bracketleft: return SAPP_KEYCODE_LEFT_BRACKET; + case XK_bracketright: return SAPP_KEYCODE_RIGHT_BRACKET; + case XK_backslash: return SAPP_KEYCODE_BACKSLASH; + case XK_semicolon: return SAPP_KEYCODE_SEMICOLON; + case XK_apostrophe: return SAPP_KEYCODE_APOSTROPHE; + case XK_grave: return SAPP_KEYCODE_GRAVE_ACCENT; + case XK_comma: return SAPP_KEYCODE_COMMA; + case XK_period: return SAPP_KEYCODE_PERIOD; + case XK_slash: return SAPP_KEYCODE_SLASH; + case XK_less: return SAPP_KEYCODE_WORLD_1; // At least in some layouts... + default: break; + } + + // no matching translation was found + return SAPP_KEYCODE_INVALID; +} + + +// setup dynamic keycode/scancode mapping tables, this is required +// for getting layout-independent keycodes on X11. +// +// see GLFW x11_init.c/createKeyTables() +_SOKOL_PRIVATE void _sapp_x11_init_keytable(void) { + for (int i = 0; i < SAPP_MAX_KEYCODES; i++) { + _sapp.keycodes[i] = SAPP_KEYCODE_INVALID; + } + // use XKB to determine physical key locations independently of the current keyboard layout + XkbDescPtr desc = XkbGetMap(_sapp.x11.display, 0, XkbUseCoreKbd); + SOKOL_ASSERT(desc); + XkbGetNames(_sapp.x11.display, XkbKeyNamesMask | XkbKeyAliasesMask, desc); + + const int scancode_min = desc->min_key_code; + const int scancode_max = desc->max_key_code; + + const struct { sapp_keycode key; const char* name; } keymap[] = { + { SAPP_KEYCODE_GRAVE_ACCENT, "TLDE" }, + { SAPP_KEYCODE_1, "AE01" }, + { SAPP_KEYCODE_2, "AE02" }, + { SAPP_KEYCODE_3, "AE03" }, + { SAPP_KEYCODE_4, "AE04" }, + { SAPP_KEYCODE_5, "AE05" }, + { SAPP_KEYCODE_6, "AE06" }, + { SAPP_KEYCODE_7, "AE07" }, + { SAPP_KEYCODE_8, "AE08" }, + { SAPP_KEYCODE_9, "AE09" }, + { SAPP_KEYCODE_0, "AE10" }, + { SAPP_KEYCODE_MINUS, "AE11" }, + { SAPP_KEYCODE_EQUAL, "AE12" }, + { SAPP_KEYCODE_Q, "AD01" }, + { SAPP_KEYCODE_W, "AD02" }, + { SAPP_KEYCODE_E, "AD03" }, + { SAPP_KEYCODE_R, "AD04" }, + { SAPP_KEYCODE_T, "AD05" }, + { SAPP_KEYCODE_Y, "AD06" }, + { SAPP_KEYCODE_U, "AD07" }, + { SAPP_KEYCODE_I, "AD08" }, + { SAPP_KEYCODE_O, "AD09" }, + { SAPP_KEYCODE_P, "AD10" }, + { SAPP_KEYCODE_LEFT_BRACKET, "AD11" }, + { SAPP_KEYCODE_RIGHT_BRACKET, "AD12" }, + { SAPP_KEYCODE_A, "AC01" }, + { SAPP_KEYCODE_S, "AC02" }, + { SAPP_KEYCODE_D, "AC03" }, + { SAPP_KEYCODE_F, "AC04" }, + { SAPP_KEYCODE_G, "AC05" }, + { SAPP_KEYCODE_H, "AC06" }, + { SAPP_KEYCODE_J, "AC07" }, + { SAPP_KEYCODE_K, "AC08" }, + { SAPP_KEYCODE_L, "AC09" }, + { SAPP_KEYCODE_SEMICOLON, "AC10" }, + { SAPP_KEYCODE_APOSTROPHE, "AC11" }, + { SAPP_KEYCODE_Z, "AB01" }, + { SAPP_KEYCODE_X, "AB02" }, + { SAPP_KEYCODE_C, "AB03" }, + { SAPP_KEYCODE_V, "AB04" }, + { SAPP_KEYCODE_B, "AB05" }, + { SAPP_KEYCODE_N, "AB06" }, + { SAPP_KEYCODE_M, "AB07" }, + { SAPP_KEYCODE_COMMA, "AB08" }, + { SAPP_KEYCODE_PERIOD, "AB09" }, + { SAPP_KEYCODE_SLASH, "AB10" }, + { SAPP_KEYCODE_BACKSLASH, "BKSL" }, + { SAPP_KEYCODE_WORLD_1, "LSGT" }, + { SAPP_KEYCODE_SPACE, "SPCE" }, + { SAPP_KEYCODE_ESCAPE, "ESC" }, + { SAPP_KEYCODE_ENTER, "RTRN" }, + { SAPP_KEYCODE_TAB, "TAB" }, + { SAPP_KEYCODE_BACKSPACE, "BKSP" }, + { SAPP_KEYCODE_INSERT, "INS" }, + { SAPP_KEYCODE_DELETE, "DELE" }, + { SAPP_KEYCODE_RIGHT, "RGHT" }, + { SAPP_KEYCODE_LEFT, "LEFT" }, + { SAPP_KEYCODE_DOWN, "DOWN" }, + { SAPP_KEYCODE_UP, "UP" }, + { SAPP_KEYCODE_PAGE_UP, "PGUP" }, + { SAPP_KEYCODE_PAGE_DOWN, "PGDN" }, + { SAPP_KEYCODE_HOME, "HOME" }, + { SAPP_KEYCODE_END, "END" }, + { SAPP_KEYCODE_CAPS_LOCK, "CAPS" }, + { SAPP_KEYCODE_SCROLL_LOCK, "SCLK" }, + { SAPP_KEYCODE_NUM_LOCK, "NMLK" }, + { SAPP_KEYCODE_PRINT_SCREEN, "PRSC" }, + { SAPP_KEYCODE_PAUSE, "PAUS" }, + { SAPP_KEYCODE_F1, "FK01" }, + { SAPP_KEYCODE_F2, "FK02" }, + { SAPP_KEYCODE_F3, "FK03" }, + { SAPP_KEYCODE_F4, "FK04" }, + { SAPP_KEYCODE_F5, "FK05" }, + { SAPP_KEYCODE_F6, "FK06" }, + { SAPP_KEYCODE_F7, "FK07" }, + { SAPP_KEYCODE_F8, "FK08" }, + { SAPP_KEYCODE_F9, "FK09" }, + { SAPP_KEYCODE_F10, "FK10" }, + { SAPP_KEYCODE_F11, "FK11" }, + { SAPP_KEYCODE_F12, "FK12" }, + { SAPP_KEYCODE_F13, "FK13" }, + { SAPP_KEYCODE_F14, "FK14" }, + { SAPP_KEYCODE_F15, "FK15" }, + { SAPP_KEYCODE_F16, "FK16" }, + { SAPP_KEYCODE_F17, "FK17" }, + { SAPP_KEYCODE_F18, "FK18" }, + { SAPP_KEYCODE_F19, "FK19" }, + { SAPP_KEYCODE_F20, "FK20" }, + { SAPP_KEYCODE_F21, "FK21" }, + { SAPP_KEYCODE_F22, "FK22" }, + { SAPP_KEYCODE_F23, "FK23" }, + { SAPP_KEYCODE_F24, "FK24" }, + { SAPP_KEYCODE_F25, "FK25" }, + { SAPP_KEYCODE_KP_0, "KP0" }, + { SAPP_KEYCODE_KP_1, "KP1" }, + { SAPP_KEYCODE_KP_2, "KP2" }, + { SAPP_KEYCODE_KP_3, "KP3" }, + { SAPP_KEYCODE_KP_4, "KP4" }, + { SAPP_KEYCODE_KP_5, "KP5" }, + { SAPP_KEYCODE_KP_6, "KP6" }, + { SAPP_KEYCODE_KP_7, "KP7" }, + { SAPP_KEYCODE_KP_8, "KP8" }, + { SAPP_KEYCODE_KP_9, "KP9" }, + { SAPP_KEYCODE_KP_DECIMAL, "KPDL" }, + { SAPP_KEYCODE_KP_DIVIDE, "KPDV" }, + { SAPP_KEYCODE_KP_MULTIPLY, "KPMU" }, + { SAPP_KEYCODE_KP_SUBTRACT, "KPSU" }, + { SAPP_KEYCODE_KP_ADD, "KPAD" }, + { SAPP_KEYCODE_KP_ENTER, "KPEN" }, + { SAPP_KEYCODE_KP_EQUAL, "KPEQ" }, + { SAPP_KEYCODE_LEFT_SHIFT, "LFSH" }, + { SAPP_KEYCODE_LEFT_CONTROL, "LCTL" }, + { SAPP_KEYCODE_LEFT_ALT, "LALT" }, + { SAPP_KEYCODE_LEFT_SUPER, "LWIN" }, + { SAPP_KEYCODE_RIGHT_SHIFT, "RTSH" }, + { SAPP_KEYCODE_RIGHT_CONTROL, "RCTL" }, + { SAPP_KEYCODE_RIGHT_ALT, "RALT" }, + { SAPP_KEYCODE_RIGHT_ALT, "LVL3" }, + { SAPP_KEYCODE_RIGHT_ALT, "MDSW" }, + { SAPP_KEYCODE_RIGHT_SUPER, "RWIN" }, + { SAPP_KEYCODE_MENU, "MENU" } + }; + const int num_keymap_items = (int)(sizeof(keymap) / sizeof(keymap[0])); + + // find X11 keycode to sokol-app key code mapping + for (int scancode = scancode_min; scancode <= scancode_max; scancode++) { + sapp_keycode key = SAPP_KEYCODE_INVALID; + for (int i = 0; i < num_keymap_items; i++) { + if (strncmp(desc->names->keys[scancode].name, keymap[i].name, XkbKeyNameLength) == 0) { + key = keymap[i].key; + break; + } + } + + // fall back to key aliases in case the key name did not match + for (int i = 0; i < desc->names->num_key_aliases; i++) { + if (key != SAPP_KEYCODE_INVALID) { + break; + } + if (strncmp(desc->names->key_aliases[i].real, desc->names->keys[scancode].name, XkbKeyNameLength) != 0) { + continue; + } + for (int j = 0; j < num_keymap_items; j++) { + if (strncmp(desc->names->key_aliases[i].alias, keymap[i].name, XkbKeyNameLength) == 0) { + key = keymap[i].key; + break; + } + } + } + _sapp.keycodes[scancode] = key; + } + XkbFreeNames(desc, XkbKeyNamesMask, True); + XkbFreeKeyboard(desc, 0, True); + + int width = 0; + KeySym* keysyms = XGetKeyboardMapping(_sapp.x11.display, scancode_min, scancode_max - scancode_min + 1, &width); + for (int scancode = scancode_min; scancode <= scancode_max; scancode++) { + // translate untranslated key codes using the traditional X11 KeySym lookups + if (_sapp.keycodes[scancode] == SAPP_KEYCODE_INVALID) { + const size_t base = (size_t)((scancode - scancode_min) * width); + _sapp.keycodes[scancode] = _sapp_x11_translate_keysyms(&keysyms[base], width); + } + } + XFree(keysyms); +} + _SOKOL_PRIVATE void _sapp_x11_query_system_dpi(void) { /* from GLFW: @@ -10404,139 +10788,10 @@ _SOKOL_PRIVATE void _sapp_x11_char_event(uint32_t chr, bool repeat, uint32_t mod } _SOKOL_PRIVATE sapp_keycode _sapp_x11_translate_key(int scancode) { - int dummy; - KeySym* keysyms = XGetKeyboardMapping(_sapp.x11.display, scancode, 1, &dummy); - SOKOL_ASSERT(keysyms); - KeySym keysym = keysyms[0]; - XFree(keysyms); - switch (keysym) { - case XK_Escape: return SAPP_KEYCODE_ESCAPE; - case XK_Tab: return SAPP_KEYCODE_TAB; - case XK_Shift_L: return SAPP_KEYCODE_LEFT_SHIFT; - case XK_Shift_R: return SAPP_KEYCODE_RIGHT_SHIFT; - case XK_Control_L: return SAPP_KEYCODE_LEFT_CONTROL; - case XK_Control_R: return SAPP_KEYCODE_RIGHT_CONTROL; - case XK_Meta_L: - case XK_Alt_L: return SAPP_KEYCODE_LEFT_ALT; - case XK_Mode_switch: /* Mapped to Alt_R on many keyboards */ - case XK_ISO_Level3_Shift: /* AltGr on at least some machines */ - case XK_Meta_R: - case XK_Alt_R: return SAPP_KEYCODE_RIGHT_ALT; - case XK_Super_L: return SAPP_KEYCODE_LEFT_SUPER; - case XK_Super_R: return SAPP_KEYCODE_RIGHT_SUPER; - case XK_Menu: return SAPP_KEYCODE_MENU; - case XK_Num_Lock: return SAPP_KEYCODE_NUM_LOCK; - case XK_Caps_Lock: return SAPP_KEYCODE_CAPS_LOCK; - case XK_Print: return SAPP_KEYCODE_PRINT_SCREEN; - case XK_Scroll_Lock: return SAPP_KEYCODE_SCROLL_LOCK; - case XK_Pause: return SAPP_KEYCODE_PAUSE; - case XK_Delete: return SAPP_KEYCODE_DELETE; - case XK_BackSpace: return SAPP_KEYCODE_BACKSPACE; - case XK_Return: return SAPP_KEYCODE_ENTER; - case XK_Home: return SAPP_KEYCODE_HOME; - case XK_End: return SAPP_KEYCODE_END; - case XK_Page_Up: return SAPP_KEYCODE_PAGE_UP; - case XK_Page_Down: return SAPP_KEYCODE_PAGE_DOWN; - case XK_Insert: return SAPP_KEYCODE_INSERT; - case XK_Left: return SAPP_KEYCODE_LEFT; - case XK_Right: return SAPP_KEYCODE_RIGHT; - case XK_Down: return SAPP_KEYCODE_DOWN; - case XK_Up: return SAPP_KEYCODE_UP; - case XK_F1: return SAPP_KEYCODE_F1; - case XK_F2: return SAPP_KEYCODE_F2; - case XK_F3: return SAPP_KEYCODE_F3; - case XK_F4: return SAPP_KEYCODE_F4; - case XK_F5: return SAPP_KEYCODE_F5; - case XK_F6: return SAPP_KEYCODE_F6; - case XK_F7: return SAPP_KEYCODE_F7; - case XK_F8: return SAPP_KEYCODE_F8; - case XK_F9: return SAPP_KEYCODE_F9; - case XK_F10: return SAPP_KEYCODE_F10; - case XK_F11: return SAPP_KEYCODE_F11; - case XK_F12: return SAPP_KEYCODE_F12; - case XK_F13: return SAPP_KEYCODE_F13; - case XK_F14: return SAPP_KEYCODE_F14; - case XK_F15: return SAPP_KEYCODE_F15; - case XK_F16: return SAPP_KEYCODE_F16; - case XK_F17: return SAPP_KEYCODE_F17; - case XK_F18: return SAPP_KEYCODE_F18; - case XK_F19: return SAPP_KEYCODE_F19; - case XK_F20: return SAPP_KEYCODE_F20; - case XK_F21: return SAPP_KEYCODE_F21; - case XK_F22: return SAPP_KEYCODE_F22; - case XK_F23: return SAPP_KEYCODE_F23; - case XK_F24: return SAPP_KEYCODE_F24; - case XK_F25: return SAPP_KEYCODE_F25; - - case XK_KP_Divide: return SAPP_KEYCODE_KP_DIVIDE; - case XK_KP_Multiply: return SAPP_KEYCODE_KP_MULTIPLY; - case XK_KP_Subtract: return SAPP_KEYCODE_KP_SUBTRACT; - case XK_KP_Add: return SAPP_KEYCODE_KP_ADD; - - case XK_KP_Insert: return SAPP_KEYCODE_KP_0; - case XK_KP_End: return SAPP_KEYCODE_KP_1; - case XK_KP_Down: return SAPP_KEYCODE_KP_2; - case XK_KP_Page_Down: return SAPP_KEYCODE_KP_3; - case XK_KP_Left: return SAPP_KEYCODE_KP_4; - case XK_KP_Begin: return SAPP_KEYCODE_KP_5; - case XK_KP_Right: return SAPP_KEYCODE_KP_6; - case XK_KP_Home: return SAPP_KEYCODE_KP_7; - case XK_KP_Up: return SAPP_KEYCODE_KP_8; - case XK_KP_Page_Up: return SAPP_KEYCODE_KP_9; - case XK_KP_Delete: return SAPP_KEYCODE_KP_DECIMAL; - case XK_KP_Equal: return SAPP_KEYCODE_KP_EQUAL; - case XK_KP_Enter: return SAPP_KEYCODE_KP_ENTER; - - case XK_a: return SAPP_KEYCODE_A; - case XK_b: return SAPP_KEYCODE_B; - case XK_c: return SAPP_KEYCODE_C; - case XK_d: return SAPP_KEYCODE_D; - case XK_e: return SAPP_KEYCODE_E; - case XK_f: return SAPP_KEYCODE_F; - case XK_g: return SAPP_KEYCODE_G; - case XK_h: return SAPP_KEYCODE_H; - case XK_i: return SAPP_KEYCODE_I; - case XK_j: return SAPP_KEYCODE_J; - case XK_k: return SAPP_KEYCODE_K; - case XK_l: return SAPP_KEYCODE_L; - case XK_m: return SAPP_KEYCODE_M; - case XK_n: return SAPP_KEYCODE_N; - case XK_o: return SAPP_KEYCODE_O; - case XK_p: return SAPP_KEYCODE_P; - case XK_q: return SAPP_KEYCODE_Q; - case XK_r: return SAPP_KEYCODE_R; - case XK_s: return SAPP_KEYCODE_S; - case XK_t: return SAPP_KEYCODE_T; - case XK_u: return SAPP_KEYCODE_U; - case XK_v: return SAPP_KEYCODE_V; - case XK_w: return SAPP_KEYCODE_W; - case XK_x: return SAPP_KEYCODE_X; - case XK_y: return SAPP_KEYCODE_Y; - case XK_z: return SAPP_KEYCODE_Z; - case XK_1: return SAPP_KEYCODE_1; - case XK_2: return SAPP_KEYCODE_2; - case XK_3: return SAPP_KEYCODE_3; - case XK_4: return SAPP_KEYCODE_4; - case XK_5: return SAPP_KEYCODE_5; - case XK_6: return SAPP_KEYCODE_6; - case XK_7: return SAPP_KEYCODE_7; - case XK_8: return SAPP_KEYCODE_8; - case XK_9: return SAPP_KEYCODE_9; - case XK_0: return SAPP_KEYCODE_0; - case XK_space: return SAPP_KEYCODE_SPACE; - case XK_minus: return SAPP_KEYCODE_MINUS; - case XK_equal: return SAPP_KEYCODE_EQUAL; - case XK_bracketleft: return SAPP_KEYCODE_LEFT_BRACKET; - case XK_bracketright: return SAPP_KEYCODE_RIGHT_BRACKET; - case XK_backslash: return SAPP_KEYCODE_BACKSLASH; - case XK_semicolon: return SAPP_KEYCODE_SEMICOLON; - case XK_apostrophe: return SAPP_KEYCODE_APOSTROPHE; - case XK_grave: return SAPP_KEYCODE_GRAVE_ACCENT; - case XK_comma: return SAPP_KEYCODE_COMMA; - case XK_period: return SAPP_KEYCODE_PERIOD; - case XK_slash: return SAPP_KEYCODE_SLASH; - case XK_less: return SAPP_KEYCODE_WORLD_1; /* At least in some layouts... */ - default: return SAPP_KEYCODE_INVALID; + if ((scancode >= 0) && (scancode < _SAPP_X11_MAX_X11_KEYCODES)) { + return _sapp.keycodes[scancode]; + } else { + return SAPP_KEYCODE_INVALID; } } @@ -10575,6 +10830,21 @@ _SOKOL_PRIVATE int32_t _sapp_x11_keysym_to_unicode(KeySym keysym) { return -1; } +_SOKOL_PRIVATE bool _sapp_x11_keypress_repeat(int keycode) { + bool repeat = false; + if ((keycode >= 0) && (keycode < _SAPP_X11_MAX_X11_KEYCODES)) { + repeat = _sapp.x11.key_repeat[keycode]; + _sapp.x11.key_repeat[keycode] = true; + } + return repeat; +} + +_SOKOL_PRIVATE void _sapp_x11_keyrelease_repeat(int keycode) { + if ((keycode >= 0) && (keycode < _SAPP_X11_MAX_X11_KEYCODES)) { + _sapp.x11.key_repeat[keycode] = false; + } +} + _SOKOL_PRIVATE bool _sapp_x11_parse_dropped_files_list(const char* src) { SOKOL_ASSERT(src); SOKOL_ASSERT(_sapp.drop.buffer); @@ -10653,293 +10923,331 @@ _SOKOL_PRIVATE bool _sapp_x11_parse_dropped_files_list(const char* src) { } } -// XLib manual says keycodes are in the range [8, 255] inclusive. -// https://tronche.com/gui/x/xlib/input/keyboard-encoding.html -static bool _sapp_x11_keycodes[256]; - -_SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { - Bool filtered = XFilterEvent(event, None); - switch (event->type) { - case GenericEvent: - if (_sapp.mouse.locked && _sapp.x11.xi.available) { - if (event->xcookie.extension == _sapp.x11.xi.major_opcode) { - if (XGetEventData(_sapp.x11.display, &event->xcookie)) { - if (event->xcookie.evtype == XI_RawMotion) { - XIRawEvent* re = (XIRawEvent*) event->xcookie.data; - if (re->valuators.mask_len) { - const double* values = re->raw_values; - if (XIMaskIsSet(re->valuators.mask, 0)) { - _sapp.mouse.dx = (float) *values; - values++; - } - if (XIMaskIsSet(re->valuators.mask, 1)) { - _sapp.mouse.dy = (float) *values; - } - _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mods(event->xmotion.state)); - } +_SOKOL_PRIVATE void _sapp_x11_on_genericevent(XEvent* event) { + if (_sapp.mouse.locked && _sapp.x11.xi.available) { + if (event->xcookie.extension == _sapp.x11.xi.major_opcode) { + if (XGetEventData(_sapp.x11.display, &event->xcookie)) { + if (event->xcookie.evtype == XI_RawMotion) { + XIRawEvent* re = (XIRawEvent*) event->xcookie.data; + if (re->valuators.mask_len) { + const double* values = re->raw_values; + if (XIMaskIsSet(re->valuators.mask, 0)) { + _sapp.mouse.dx = (float) *values; + values++; + } + if (XIMaskIsSet(re->valuators.mask, 1)) { + _sapp.mouse.dy = (float) *values; } - XFreeEventData(_sapp.x11.display, &event->xcookie); + _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mods(event->xmotion.state)); } } + XFreeEventData(_sapp.x11.display, &event->xcookie); + } + } + } +} + +_SOKOL_PRIVATE void _sapp_x11_on_focusin(XEvent* event) { + // NOTE: ignoring NotifyGrab and NotifyUngrab is same behaviour as GLFW + if ((event->xfocus.mode != NotifyGrab) && (event->xfocus.mode != NotifyUngrab)) { + _sapp_x11_app_event(SAPP_EVENTTYPE_FOCUSED); + } +} + +_SOKOL_PRIVATE void _sapp_x11_on_focusout(XEvent* event) { + // if focus is lost for any reason, and we're in mouse locked mode, disable mouse lock + if (_sapp.mouse.locked) { + _sapp_x11_lock_mouse(false); + } + // NOTE: ignoring NotifyGrab and NotifyUngrab is same behaviour as GLFW + if ((event->xfocus.mode != NotifyGrab) && (event->xfocus.mode != NotifyUngrab)) { + _sapp_x11_app_event(SAPP_EVENTTYPE_UNFOCUSED); + } +} + +_SOKOL_PRIVATE void _sapp_x11_on_keypress(XEvent* event) { + int keycode = (int)event->xkey.keycode; + + const sapp_keycode key = _sapp_x11_translate_key(keycode); + const bool repeat = _sapp_x11_keypress_repeat(keycode); + uint32_t mods = _sapp_x11_mods(event->xkey.state); + // X11 doesn't set modifier bit on key down, so emulate that + mods |= _sapp_x11_key_modifier_bit(key); + if (key != SAPP_KEYCODE_INVALID) { + _sapp_x11_key_event(SAPP_EVENTTYPE_KEY_DOWN, key, repeat, mods); + } + KeySym keysym; + XLookupString(&event->xkey, NULL, 0, &keysym, NULL); + int32_t chr = _sapp_x11_keysym_to_unicode(keysym); + if (chr > 0) { + _sapp_x11_char_event((uint32_t)chr, repeat, mods); + } +} + +_SOKOL_PRIVATE void _sapp_x11_on_keyrelease(XEvent* event) { + int keycode = (int)event->xkey.keycode; + const sapp_keycode key = _sapp_x11_translate_key(keycode); + _sapp_x11_keyrelease_repeat(keycode); + if (key != SAPP_KEYCODE_INVALID) { + uint32_t mods = _sapp_x11_mods(event->xkey.state); + // X11 doesn't clear modifier bit on key up, so emulate that + mods &= ~_sapp_x11_key_modifier_bit(key); + _sapp_x11_key_event(SAPP_EVENTTYPE_KEY_UP, key, false, mods); + } +} + +_SOKOL_PRIVATE void _sapp_x11_on_buttonpress(XEvent* event) { + _sapp_x11_mouse_update(event->xbutton.x, event->xbutton.y, false); + const sapp_mousebutton btn = _sapp_x11_translate_button(event); + uint32_t mods = _sapp_x11_mods(event->xbutton.state); + // X11 doesn't set modifier bit on button down, so emulate that + mods |= _sapp_x11_button_modifier_bit(btn); + if (btn != SAPP_MOUSEBUTTON_INVALID) { + _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, btn, mods); + _sapp.x11.mouse_buttons |= (1 << btn); + } + else { + // might be a scroll event + switch (event->xbutton.button) { + case 4: _sapp_x11_scroll_event(0.0f, 1.0f, mods); break; + case 5: _sapp_x11_scroll_event(0.0f, -1.0f, mods); break; + case 6: _sapp_x11_scroll_event(1.0f, 0.0f, mods); break; + case 7: _sapp_x11_scroll_event(-1.0f, 0.0f, mods); break; + } + } +} + +_SOKOL_PRIVATE void _sapp_x11_on_buttonrelease(XEvent* event) { + _sapp_x11_mouse_update(event->xbutton.x, event->xbutton.y, false); + const sapp_mousebutton btn = _sapp_x11_translate_button(event); + if (btn != SAPP_MOUSEBUTTON_INVALID) { + uint32_t mods = _sapp_x11_mods(event->xbutton.state); + // X11 doesn't clear modifier bit on button up, so emulate that + mods &= ~_sapp_x11_button_modifier_bit(btn); + _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_UP, btn, mods); + _sapp.x11.mouse_buttons &= ~(1 << btn); + } +} + +_SOKOL_PRIVATE void _sapp_x11_on_enternotify(XEvent* event) { + // don't send enter/leave events while mouse button held down + if (0 == _sapp.x11.mouse_buttons) { + _sapp_x11_mouse_update(event->xcrossing.x, event->xcrossing.y, true); + _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_ENTER, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mods(event->xcrossing.state)); + } +} + +_SOKOL_PRIVATE void _sapp_x11_on_leavenotify(XEvent* event) { + if (0 == _sapp.x11.mouse_buttons) { + _sapp_x11_mouse_update(event->xcrossing.x, event->xcrossing.y, true); + _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mods(event->xcrossing.state)); + } +} + +_SOKOL_PRIVATE void _sapp_x11_on_motionnotify(XEvent* event) { + if (!_sapp.mouse.locked) { + _sapp_x11_mouse_update(event->xmotion.x, event->xmotion.y, false); + _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mods(event->xmotion.state)); + } +} + +_SOKOL_PRIVATE void _sapp_x11_on_configurenotify(XEvent* event) { + if ((event->xconfigure.width != _sapp.window_width) || (event->xconfigure.height != _sapp.window_height)) { + _sapp.window_width = event->xconfigure.width; + _sapp.window_height = event->xconfigure.height; + _sapp.framebuffer_width = _sapp.window_width; + _sapp.framebuffer_height = _sapp.window_height; + _sapp_x11_app_event(SAPP_EVENTTYPE_RESIZED); + } +} + +_SOKOL_PRIVATE void _sapp_x11_on_propertynotify(XEvent* event) { + if (event->xproperty.state == PropertyNewValue) { + if (event->xproperty.atom == _sapp.x11.WM_STATE) { + const int state = _sapp_x11_get_window_state(); + if (state != _sapp.x11.window_state) { + _sapp.x11.window_state = state; + if (state == IconicState) { + _sapp_x11_app_event(SAPP_EVENTTYPE_ICONIFIED); + } + else if (state == NormalState) { + _sapp_x11_app_event(SAPP_EVENTTYPE_RESTORED); + } } + } + } +} + +_SOKOL_PRIVATE void _sapp_x11_on_selectionnotify(XEvent* event) { + if (event->xselection.property == _sapp.x11.xdnd.XdndSelection) { + char* data = 0; + uint32_t result = _sapp_x11_get_window_property(event->xselection.requestor, + event->xselection.property, + event->xselection.target, + (unsigned char**) &data); + if (_sapp.drop.enabled && result) { + if (_sapp_x11_parse_dropped_files_list(data)) { + _sapp.mouse.dx = 0.0f; + _sapp.mouse.dy = 0.0f; + if (_sapp_events_enabled()) { + // FIXME: Figure out how to get modifier key state here. + // The XSelection event has no 'state' item, and + // XQueryKeymap() always returns a zeroed array. + _sapp_init_event(SAPP_EVENTTYPE_FILES_DROPPED); + _sapp_call_event(&_sapp.event); + } + } + } + if (_sapp.x11.xdnd.version >= 2) { + XEvent reply; + _sapp_clear(&reply, sizeof(reply)); + reply.type = ClientMessage; + reply.xclient.window = _sapp.x11.xdnd.source; + reply.xclient.message_type = _sapp.x11.xdnd.XdndFinished; + reply.xclient.format = 32; + reply.xclient.data.l[0] = (long)_sapp.x11.window; + reply.xclient.data.l[1] = result; + reply.xclient.data.l[2] = (long)_sapp.x11.xdnd.XdndActionCopy; + XSendEvent(_sapp.x11.display, _sapp.x11.xdnd.source, False, NoEventMask, &reply); + XFlush(_sapp.x11.display); + } + } +} + +_SOKOL_PRIVATE void _sapp_x11_on_clientmessage(XEvent* event) { + if (XFilterEvent(event, None)) { + return; + } + if (event->xclient.message_type == _sapp.x11.WM_PROTOCOLS) { + const Atom protocol = (Atom)event->xclient.data.l[0]; + if (protocol == _sapp.x11.WM_DELETE_WINDOW) { + _sapp.quit_requested = true; + } + } else if (event->xclient.message_type == _sapp.x11.xdnd.XdndEnter) { + const bool is_list = 0 != (event->xclient.data.l[1] & 1); + _sapp.x11.xdnd.source = (Window)event->xclient.data.l[0]; + _sapp.x11.xdnd.version = event->xclient.data.l[1] >> 24; + _sapp.x11.xdnd.format = None; + if (_sapp.x11.xdnd.version > _SAPP_X11_XDND_VERSION) { + return; + } + uint32_t count = 0; + Atom* formats = 0; + if (is_list) { + count = _sapp_x11_get_window_property(_sapp.x11.xdnd.source, _sapp.x11.xdnd.XdndTypeList, XA_ATOM, (unsigned char**)&formats); + } else { + count = 3; + formats = (Atom*) event->xclient.data.l + 2; + } + for (uint32_t i = 0; i < count; i++) { + if (formats[i] == _sapp.x11.xdnd.text_uri_list) { + _sapp.x11.xdnd.format = _sapp.x11.xdnd.text_uri_list; + break; + } + } + if (is_list && formats) { + XFree(formats); + } + } else if (event->xclient.message_type == _sapp.x11.xdnd.XdndDrop) { + if (_sapp.x11.xdnd.version > _SAPP_X11_XDND_VERSION) { + return; + } + Time time = CurrentTime; + if (_sapp.x11.xdnd.format) { + if (_sapp.x11.xdnd.version >= 1) { + time = (Time)event->xclient.data.l[2]; + } + XConvertSelection(_sapp.x11.display, + _sapp.x11.xdnd.XdndSelection, + _sapp.x11.xdnd.format, + _sapp.x11.xdnd.XdndSelection, + _sapp.x11.window, + time); + } else if (_sapp.x11.xdnd.version >= 2) { + XEvent reply; + _sapp_clear(&reply, sizeof(reply)); + reply.type = ClientMessage; + reply.xclient.window = _sapp.x11.xdnd.source; + reply.xclient.message_type = _sapp.x11.xdnd.XdndFinished; + reply.xclient.format = 32; + reply.xclient.data.l[0] = (long)_sapp.x11.window; + reply.xclient.data.l[1] = 0; // drag was rejected + reply.xclient.data.l[2] = None; + XSendEvent(_sapp.x11.display, _sapp.x11.xdnd.source, False, NoEventMask, &reply); + XFlush(_sapp.x11.display); + } + } else if (event->xclient.message_type == _sapp.x11.xdnd.XdndPosition) { + // drag operation has moved over the window + // FIXME: we could track the mouse position here, but + // this isn't implemented on other platforms either so far + if (_sapp.x11.xdnd.version > _SAPP_X11_XDND_VERSION) { + return; + } + XEvent reply; + _sapp_clear(&reply, sizeof(reply)); + reply.type = ClientMessage; + reply.xclient.window = _sapp.x11.xdnd.source; + reply.xclient.message_type = _sapp.x11.xdnd.XdndStatus; + reply.xclient.format = 32; + reply.xclient.data.l[0] = (long)_sapp.x11.window; + if (_sapp.x11.xdnd.format) { + /* reply that we are ready to copy the dragged data */ + reply.xclient.data.l[1] = 1; // accept with no rectangle + if (_sapp.x11.xdnd.version >= 2) { + reply.xclient.data.l[4] = (long)_sapp.x11.xdnd.XdndActionCopy; + } + } + XSendEvent(_sapp.x11.display, _sapp.x11.xdnd.source, False, NoEventMask, &reply); + XFlush(_sapp.x11.display); + } +} + +_SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { + switch (event->type) { + case GenericEvent: + _sapp_x11_on_genericevent(event); break; case FocusIn: - // NOTE: ignoring NotifyGrab and NotifyUngrab is same behaviour as GLFW - if ((event->xfocus.mode != NotifyGrab) && (event->xfocus.mode != NotifyUngrab)) { - _sapp_x11_app_event(SAPP_EVENTTYPE_FOCUSED); - } + _sapp_x11_on_focusin(event); break; case FocusOut: - /* if focus is lost for any reason, and we're in mouse locked mode, disable mouse lock */ - if (_sapp.mouse.locked) { - _sapp_x11_lock_mouse(false); - } - // NOTE: ignoring NotifyGrab and NotifyUngrab is same behaviour as GLFW - if ((event->xfocus.mode != NotifyGrab) && (event->xfocus.mode != NotifyUngrab)) { - _sapp_x11_app_event(SAPP_EVENTTYPE_UNFOCUSED); - } + _sapp_x11_on_focusout(event); break; case KeyPress: - { - int keycode = (int)event->xkey.keycode; - const sapp_keycode key = _sapp_x11_translate_key(keycode); - bool repeat = _sapp_x11_keycodes[keycode & 0xFF]; - _sapp_x11_keycodes[keycode & 0xFF] = true; - uint32_t mods = _sapp_x11_mods(event->xkey.state); - // X11 doesn't set modifier bit on key down, so emulate that - mods |= _sapp_x11_key_modifier_bit(key); - if (key != SAPP_KEYCODE_INVALID) { - _sapp_x11_key_event(SAPP_EVENTTYPE_KEY_DOWN, key, repeat, mods); - } - KeySym keysym; - XLookupString(&event->xkey, NULL, 0, &keysym, NULL); - int32_t chr = _sapp_x11_keysym_to_unicode(keysym); - if (chr > 0) { - _sapp_x11_char_event((uint32_t)chr, repeat, mods); - } - } + _sapp_x11_on_keypress(event); break; case KeyRelease: - { - int keycode = (int)event->xkey.keycode; - const sapp_keycode key = _sapp_x11_translate_key(keycode); - _sapp_x11_keycodes[keycode & 0xFF] = false; - if (key != SAPP_KEYCODE_INVALID) { - uint32_t mods = _sapp_x11_mods(event->xkey.state); - // X11 doesn't clear modifier bit on key up, so emulate that - mods &= ~_sapp_x11_key_modifier_bit(key); - _sapp_x11_key_event(SAPP_EVENTTYPE_KEY_UP, key, false, mods); - } - } + _sapp_x11_on_keyrelease(event); break; case ButtonPress: - { - _sapp_x11_mouse_update(event->xbutton.x, event->xbutton.y, false); - const sapp_mousebutton btn = _sapp_x11_translate_button(event); - uint32_t mods = _sapp_x11_mods(event->xbutton.state); - // X11 doesn't set modifier bit on button down, so emulate that - mods |= _sapp_x11_button_modifier_bit(btn); - if (btn != SAPP_MOUSEBUTTON_INVALID) { - _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, btn, mods); - _sapp.x11.mouse_buttons |= (1 << btn); - } - else { - /* might be a scroll event */ - switch (event->xbutton.button) { - case 4: _sapp_x11_scroll_event(0.0f, 1.0f, mods); break; - case 5: _sapp_x11_scroll_event(0.0f, -1.0f, mods); break; - case 6: _sapp_x11_scroll_event(1.0f, 0.0f, mods); break; - case 7: _sapp_x11_scroll_event(-1.0f, 0.0f, mods); break; - } - } - } + _sapp_x11_on_buttonpress(event); break; case ButtonRelease: - { - _sapp_x11_mouse_update(event->xbutton.x, event->xbutton.y, false); - const sapp_mousebutton btn = _sapp_x11_translate_button(event); - if (btn != SAPP_MOUSEBUTTON_INVALID) { - uint32_t mods = _sapp_x11_mods(event->xbutton.state); - // X11 doesn't clear modifier bit on button up, so emulate that - mods &= ~_sapp_x11_button_modifier_bit(btn); - _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_UP, btn, mods); - _sapp.x11.mouse_buttons &= ~(1 << btn); - } - } + _sapp_x11_on_buttonrelease(event); break; case EnterNotify: - /* don't send enter/leave events while mouse button held down */ - if (0 == _sapp.x11.mouse_buttons) { - _sapp_x11_mouse_update(event->xcrossing.x, event->xcrossing.y, true); - _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_ENTER, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mods(event->xcrossing.state)); - } + _sapp_x11_on_enternotify(event); break; case LeaveNotify: - if (0 == _sapp.x11.mouse_buttons) { - _sapp_x11_mouse_update(event->xcrossing.x, event->xcrossing.y, true); - _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mods(event->xcrossing.state)); - } + _sapp_x11_on_leavenotify(event); break; case MotionNotify: - if (!_sapp.mouse.locked) { - _sapp_x11_mouse_update(event->xmotion.x, event->xmotion.y, false); - _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mods(event->xmotion.state)); - } + _sapp_x11_on_motionnotify(event); break; case ConfigureNotify: - if ((event->xconfigure.width != _sapp.window_width) || (event->xconfigure.height != _sapp.window_height)) { - _sapp.window_width = event->xconfigure.width; - _sapp.window_height = event->xconfigure.height; - _sapp.framebuffer_width = _sapp.window_width; - _sapp.framebuffer_height = _sapp.window_height; - _sapp_x11_app_event(SAPP_EVENTTYPE_RESIZED); - } + _sapp_x11_on_configurenotify(event); break; case PropertyNotify: - if (event->xproperty.state == PropertyNewValue) { - if (event->xproperty.atom == _sapp.x11.WM_STATE) { - const int state = _sapp_x11_get_window_state(); - if (state != _sapp.x11.window_state) { - _sapp.x11.window_state = state; - if (state == IconicState) { - _sapp_x11_app_event(SAPP_EVENTTYPE_ICONIFIED); - } - else if (state == NormalState) { - _sapp_x11_app_event(SAPP_EVENTTYPE_RESTORED); - } - } - } - } - break; - case ClientMessage: - if (filtered) { - return; - } - if (event->xclient.message_type == _sapp.x11.WM_PROTOCOLS) { - const Atom protocol = (Atom)event->xclient.data.l[0]; - if (protocol == _sapp.x11.WM_DELETE_WINDOW) { - _sapp.quit_requested = true; - } - } - else if (event->xclient.message_type == _sapp.x11.xdnd.XdndEnter) { - const bool is_list = 0 != (event->xclient.data.l[1] & 1); - _sapp.x11.xdnd.source = (Window)event->xclient.data.l[0]; - _sapp.x11.xdnd.version = event->xclient.data.l[1] >> 24; - _sapp.x11.xdnd.format = None; - if (_sapp.x11.xdnd.version > _SAPP_X11_XDND_VERSION) { - return; - } - uint32_t count = 0; - Atom* formats = 0; - if (is_list) { - count = _sapp_x11_get_window_property(_sapp.x11.xdnd.source, _sapp.x11.xdnd.XdndTypeList, XA_ATOM, (unsigned char**)&formats); - } - else { - count = 3; - formats = (Atom*) event->xclient.data.l + 2; - } - for (uint32_t i = 0; i < count; i++) { - if (formats[i] == _sapp.x11.xdnd.text_uri_list) { - _sapp.x11.xdnd.format = _sapp.x11.xdnd.text_uri_list; - break; - } - } - if (is_list && formats) { - XFree(formats); - } - } - else if (event->xclient.message_type == _sapp.x11.xdnd.XdndDrop) { - if (_sapp.x11.xdnd.version > _SAPP_X11_XDND_VERSION) { - return; - } - Time time = CurrentTime; - if (_sapp.x11.xdnd.format) { - if (_sapp.x11.xdnd.version >= 1) { - time = (Time)event->xclient.data.l[2]; - } - XConvertSelection(_sapp.x11.display, - _sapp.x11.xdnd.XdndSelection, - _sapp.x11.xdnd.format, - _sapp.x11.xdnd.XdndSelection, - _sapp.x11.window, - time); - } - else if (_sapp.x11.xdnd.version >= 2) { - XEvent reply; - _sapp_clear(&reply, sizeof(reply)); - reply.type = ClientMessage; - reply.xclient.window = _sapp.x11.xdnd.source; - reply.xclient.message_type = _sapp.x11.xdnd.XdndFinished; - reply.xclient.format = 32; - reply.xclient.data.l[0] = (long)_sapp.x11.window; - reply.xclient.data.l[1] = 0; // drag was rejected - reply.xclient.data.l[2] = None; - XSendEvent(_sapp.x11.display, _sapp.x11.xdnd.source, False, NoEventMask, &reply); - XFlush(_sapp.x11.display); - } - } - else if (event->xclient.message_type == _sapp.x11.xdnd.XdndPosition) { - /* drag operation has moved over the window - FIXME: we could track the mouse position here, but - this isn't implemented on other platforms either so far - */ - if (_sapp.x11.xdnd.version > _SAPP_X11_XDND_VERSION) { - return; - } - XEvent reply; - _sapp_clear(&reply, sizeof(reply)); - reply.type = ClientMessage; - reply.xclient.window = _sapp.x11.xdnd.source; - reply.xclient.message_type = _sapp.x11.xdnd.XdndStatus; - reply.xclient.format = 32; - reply.xclient.data.l[0] = (long)_sapp.x11.window; - if (_sapp.x11.xdnd.format) { - /* reply that we are ready to copy the dragged data */ - reply.xclient.data.l[1] = 1; // accept with no rectangle - if (_sapp.x11.xdnd.version >= 2) { - reply.xclient.data.l[4] = (long)_sapp.x11.xdnd.XdndActionCopy; - } - } - XSendEvent(_sapp.x11.display, _sapp.x11.xdnd.source, False, NoEventMask, &reply); - XFlush(_sapp.x11.display); - } + _sapp_x11_on_propertynotify(event); break; case SelectionNotify: - if (event->xselection.property == _sapp.x11.xdnd.XdndSelection) { - char* data = 0; - uint32_t result = _sapp_x11_get_window_property(event->xselection.requestor, - event->xselection.property, - event->xselection.target, - (unsigned char**) &data); - if (_sapp.drop.enabled && result) { - if (_sapp_x11_parse_dropped_files_list(data)) { - _sapp.mouse.dx = 0.0f; - _sapp.mouse.dy = 0.0f; - if (_sapp_events_enabled()) { - // FIXME: Figure out how to get modifier key state here. - // The XSelection event has no 'state' item, and - // XQueryKeymap() always returns a zeroed array. - _sapp_init_event(SAPP_EVENTTYPE_FILES_DROPPED); - _sapp_call_event(&_sapp.event); - } - } - } - if (_sapp.x11.xdnd.version >= 2) { - XEvent reply; - _sapp_clear(&reply, sizeof(reply)); - reply.type = ClientMessage; - reply.xclient.window = _sapp.x11.xdnd.source; - reply.xclient.message_type = _sapp.x11.xdnd.XdndFinished; - reply.xclient.format = 32; - reply.xclient.data.l[0] = (long)_sapp.x11.window; - reply.xclient.data.l[1] = result; - reply.xclient.data.l[2] = (long)_sapp.x11.xdnd.XdndActionCopy; - XSendEvent(_sapp.x11.display, _sapp.x11.xdnd.source, False, NoEventMask, &reply); - XFlush(_sapp.x11.display); - } - } + _sapp_x11_on_selectionnotify(event); break; case DestroyNotify: + // not a bug + break; + case ClientMessage: + _sapp_x11_on_clientmessage(event); break; } } @@ -10947,7 +11255,7 @@ _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) { #if !defined(_SAPP_GLX) _SOKOL_PRIVATE void _sapp_egl_init(void) { -#if defined(SOKOL_GLCORE33) +#if defined(SOKOL_GLCORE) if (!eglBindAPI(EGL_OPENGL_API)) { _SAPP_PANIC(LINUX_EGL_BIND_OPENGL_API_FAILED); } @@ -10971,7 +11279,7 @@ _SOKOL_PRIVATE void _sapp_egl_init(void) { EGLint alpha_size = _sapp.desc.alpha ? 8 : 0; const EGLint config_attrs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - #if defined(SOKOL_GLCORE33) + #if defined(SOKOL_GLCORE) EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, #elif defined(SOKOL_GLES3) EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT, @@ -11034,7 +11342,7 @@ _SOKOL_PRIVATE void _sapp_egl_init(void) { } EGLint ctx_attrs[] = { - #if defined(SOKOL_GLCORE33) + #if defined(SOKOL_GLCORE) EGL_CONTEXT_MAJOR_VERSION, _sapp.desc.gl_major_version, EGL_CONTEXT_MINOR_VERSION, _sapp.desc.gl_minor_version, EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, @@ -11098,11 +11406,12 @@ _SOKOL_PRIVATE void _sapp_linux_run(const sapp_desc* desc) { } _sapp.x11.screen = DefaultScreen(_sapp.x11.display); _sapp.x11.root = DefaultRootWindow(_sapp.x11.display); - XkbSetDetectableAutoRepeat(_sapp.x11.display, true, NULL); _sapp_x11_query_system_dpi(); _sapp.dpi_scale = _sapp.x11.dpi / 96.0f; _sapp_x11_init_extensions(); _sapp_x11_create_cursors(); + XkbSetDetectableAutoRepeat(_sapp.x11.display, true, NULL); + _sapp_x11_init_keytable(); #if defined(_SAPP_GLX) _sapp_glx_init(); Visual* visual = 0; @@ -11753,6 +12062,24 @@ SOKOL_API_IMPL uint32_t sapp_gl_get_framebuffer(void) { #endif } +SOKOL_API_IMPL int sapp_gl_get_major_version(void) { + SOKOL_ASSERT(_sapp.valid); + #if defined(SOKOL_GLCORE) + return _sapp.desc.gl_major_version; + #else + return 0; + #endif +} + +SOKOL_API_IMPL int sapp_gl_get_minor_version(void) { + SOKOL_ASSERT(_sapp.valid); + #if defined(SOKOL_GLCORE) + return _sapp.desc.gl_minor_version; + #else + return 0; + #endif +} + SOKOL_API_IMPL const void* sapp_android_get_native_activity(void) { // NOTE: _sapp.valid is not asserted here because sapp_android_get_native_activity() // needs to be callable from within sokol_main() (see: https://github.com/floooh/sokol/issues/708) diff --git a/thirdparty/sokol/sokol_gfx.h b/thirdparty/sokol/sokol_gfx.h index 3f9b961..df133d1 100644 --- a/thirdparty/sokol/sokol_gfx.h +++ b/thirdparty/sokol/sokol_gfx.h @@ -17,19 +17,19 @@ In the same place define one of the following to select the rendering backend: - #define SOKOL_GLCORE33 + #define SOKOL_GLCORE #define SOKOL_GLES3 #define SOKOL_D3D11 #define SOKOL_METAL #define SOKOL_WGPU #define SOKOL_DUMMY_BACKEND - I.e. for the GL 3.3 Core Profile it should look like this: + I.e. for the desktop GL it should look like this: #include ... #include ... #define SOKOL_IMPL - #define SOKOL_GLCORE33 + #define SOKOL_GLCORE #include "sokol_gfx.h" The dummy backend replaces the platform-specific backend code with empty @@ -141,16 +141,15 @@ object handle is required instead of an sg_swapchain struct. An offscreen pass is started like this (assuming attachments is an sg_attachments handle): - sg_begin_pass(&(sg_pass){ .action = { ... }, .attachments = attachemnts }); + sg_begin_pass(&(sg_pass){ .action = { ... }, .attachments = attachments }); --- set the render pipeline state for the next draw call with: sg_apply_pipeline(sg_pipeline pip) --- fill an sg_bindings struct with the resource bindings for the next - draw call (1..N vertex buffers, 0 or 1 index buffer, 0..N image objects and - 0..N sampler objects on the vertex-shader- and fragment-shader-stage - and then call + draw call (0..N vertex buffers, 0 or 1 index buffer, 0..N image-objects, + samplers and storage-buffers), and call: sg_apply_bindings(const sg_bindings* bindings) @@ -718,7 +717,9 @@ the sg_make_shader() function requires the following information: - Shader code or shader binary blobs for the vertex- and fragment- shader-stage: - - for the desktop GL backend, source code must be provided in '#version 330' syntax + - for the desktop GL backend, source code can be provided in '#version 410' or + '#version 430', version 430 is required for storage buffer support, but note + that this is not available on macOS - for the GLES3 backend, source code must be provided in '#version 300 es' syntax - for the D3D11 backend, shaders can be provided as source or binary blobs, the source code should be in HLSL4.0 (for best compatibility) or alternatively @@ -757,6 +758,12 @@ - please also NOTE the documentation sections about UNIFORM DATA LAYOUT and CROSS-BACKEND COMMON UNIFORM DATA LAYOUT below! + - A description of each storage buffer used in the shader: + - a boolean 'readonly' flag, note that currently only + readonly storage buffers are supported + - note that storage buffers are not supported on all backends + and platforms + - A description of each texture/image used in the shader: - the expected image type: - SG_IMAGETYPE_2D @@ -773,7 +780,7 @@ (currently it's not supported to fetch data from multisampled textures in shaders, but this is planned for a later time) - - A description of each sampler used in the shader: + - A description of each texture sampler used in the shader: - SG_SAMPLERTYPE_FILTERING, - SG_SAMPLERTYPE_NONFILTERING, - SG_SAMPLERTYPE_COMPARISON, @@ -953,6 +960,126 @@ The by far easiest way to tackle the common uniform block layout problem is to use the sokol-shdc shader cross-compiler tool! + ON STORAGE BUFFERS + ================== + Storage buffers can be used to pass large amounts of random access structured + data fromt the CPU side to the shaders. They are similar to data textures, but are + more convenient to use both on the CPU and shader side since they can be accessed + in shaders as as a 1-dimensional array of struct items. + + Storage buffers are *NOT* supported on the following platform/backend combos: + + - macOS+GL (because storage buffers require GL 4.3, while macOS only goes up to GL 4.1) + - all GLES3 platforms (WebGL2, iOS, Android - with the option that support on + Android may be added at a later point) + + Currently only 'readonly' storage buffers are supported (meaning it's not possible + to write to storage buffers from shaders). + + To use storage buffers, the following steps are required: + + - write a shader which uses storage buffers (also see the example links below) + - create one or more storage buffers via sg_make_buffer() with the + buffer type SG_BUFFERTYPE_STORAGEBUFFER + - when creating a shader via sg_make_shader(), populate the sg_shader_desc + struct with binding info (when using sokol-shdc, this step will be taken care + of automatically) + - which storage buffer bind slots on the vertex- and fragment-stage + are occupied + - whether the storage buffer on that bind slot is readonly (this is currently required + to be true) + - when calling sg_apply_bindings(), apply the matching bind slots with the previously + created storage buffers + - ...and that's it. + + For more details, see the following backend-agnostic sokol samples: + + - simple vertex pulling from a storage buffer: + - C code: https://github.com/floooh/sokol-samples/blob/master/sapp/vertexpull-sapp.c + - shader: https://github.com/floooh/sokol-samples/blob/master/sapp/vertexpull-sapp.glsl + - instanced rendering via storage buffers (vertex- and instance-pulling): + - C code: https://github.com/floooh/sokol-samples/blob/master/sapp/instancing-pull-sapp.c + - shader: https://github.com/floooh/sokol-samples/blob/master/sapp/instancing-pull-sapp.glsl + - storage buffers both on the vertex- and fragment-stage: + - C code: https://github.com/floooh/sokol-samples/blob/master/sapp/sbuftex-sapp.c + - shader: https://github.com/floooh/sokol-samples/blob/master/sapp/sbuftex-sapp.glsl + - the Ozz animation sample rewritten to pull all rendering data from storage buffers: + - C code: https://github.com/floooh/sokol-samples/blob/master/sapp/ozz-storagebuffer-sapp.cc + - shader: https://github.com/floooh/sokol-samples/blob/master/sapp/ozz-storagebuffer-sapp.glsl + + ...also see the following backend-specific vertex pulling samples (those also don't use sokol-shdc): + + - D3D11: https://github.com/floooh/sokol-samples/blob/master/d3d11/vertexpulling-d3d11.c + - desktop GL: https://github.com/floooh/sokol-samples/blob/master/glfw/vertexpulling-glfw.c + - Metal: https://github.com/floooh/sokol-samples/blob/master/metal/vertexpulling-metal.c + - WebGPU: https://github.com/floooh/sokol-samples/blob/master/wgpu/vertexpulling-wgpu.c + + Storage buffer shader authoring caveats when using sokol-shdc: + + - declare a storage buffer interface block with `readonly buffer [name] { ... }` + - do NOT annotate storage buffers with `layout(...)`, sokol-shdc will take care of that + - declare a struct which describes a single array item in the storage buffer interface block + - only put a single flexible array member into the storage buffer interface block + + E.g. a complete example in 'sokol-shdc GLSL': + + ```glsl + // declare a struct: + struct sb_vertex { + vec3 pos; + vec4 color; + } + // declare a buffer interface block with a single flexible struct array: + readonly buffer vertices { + sb_vertex vtx[]; + } + // in the shader function, access the storage buffer like this: + void main() { + vec3 pos = vtx[gl_VertexIndex].pos; + ... + } + ``` + + Backend-specific storage-buffer caveats (not relevant when using sokol-shdc): + + D3D11: + - storage buffers are created as 'raw' Byte Address Buffers + (https://learn.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-resources-intro#raw-views-of-buffers) + - in HLSL, use a ByteAddressBuffer to access the buffer content + (https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/sm5-object-byteaddressbuffer) + - in D3D11, storage buffers and textures share the same bind slots, sokol-gfx reserves + shader resource slots 0..15 for textures and 16..23 for storage buffers. + - e.g. in HLSL, storage buffer bindings start at register(t16) no matter the shader stage + + Metal: + - in Metal there is no internal difference between vertex-, uniform- and + storage-buffers, all are bound to the same 'buffer bind slots' with the + following reserved ranges: + - vertex shader stage: + - uniform buffers (internal): slots 0..3 + - vertex buffers: slots 4..11 + - storage buffers: slots 12..19 + - fragment shader stage: + - uniform buffers (internal): slots 0..3 + - storage buffers: slots 4..11 + - this means in MSL, storage buffer bindings start at [[buffer(12)]] in the vertex + shaders, and at [[buffer(4)]] in fragment shaders + + GL: + - the GL backend doesn't use name-lookup to find storage buffer bindings, this + means you must annotate buffers with `layout(std430, binding=N)` in GLSL + - ...where N is 0..7 in the vertex shader, and 8..15 in the fragment shader + + WebGPU: + - in WGSL, use the following bind locations for the various shader resource types: + - vertex shader stage: + - textures `@group(1) @binding(0..15)` + - samplers `@group(1) @binding(16..31)` + - storage buffers `@group(1) @binding(32..47)` + - fragment shader stage: + - textures `@group(1) @binding(48..63)` + - samplers `@group(1) @binding(64..79)` + - storage buffers `@group(1) @binding(80..95)` TRACE HOOKS: ============ @@ -1334,12 +1461,14 @@ offsets depending on resource type and shader stage. - Vertex shader textures must start at `@group(1) @binding(0)` - Vertex shader samplers must start at `@group(1) @binding(16)` - - Fragment shader textures must start at `@group(1) @binding(32)` - - Fragment shader samplers must start at `@group(1) @binding(48)` + - Vertex shader storage buffers must start at `@group(1) @binding(32)` + - Fragment shader textures must start at `@group(1) @binding(48)` + - Fragment shader samplers must start at `@group(1) @binding(64)` + - Fragment shader storage buffers must start at `@group(1) @binding(80)` Note that the actual number of allowed per-stage texture- and sampler-bindings in sokol-gfx is currently lower than the above ranges (currently only up to - 12 textures and 8 samplers per shader stage are allowed). + 12 textures, 8 samplers and 8 storage buffers are allowed per shader stage). If you use sokol-shdc to generate WGSL shader code, you don't need to worry about the above binding convention since sokol-shdc assigns bind slots @@ -1516,6 +1645,7 @@ enum { SG_MAX_SHADERSTAGE_IMAGES = 12, SG_MAX_SHADERSTAGE_SAMPLERS = 8, SG_MAX_SHADERSTAGE_IMAGESAMPLERPAIRS = 12, + SG_MAX_SHADERSTAGE_STORAGEBUFFERS = 8, SG_MAX_SHADERSTAGE_UBS = 4, SG_MAX_UB_MEMBERS = 16, SG_MAX_VERTEX_ATTRIBUTES = 16, @@ -1537,7 +1667,7 @@ typedef struct sg_color { float r, g, b, a; } sg_color; to get the currently active backend. */ typedef enum sg_backend { - SG_BACKEND_GLCORE33, + SG_BACKEND_GLCORE, SG_BACKEND_GLES3, SG_BACKEND_D3D11, SG_BACKEND_METAL_IOS, @@ -1666,8 +1796,10 @@ typedef enum sg_pixel_format { SG_PIXELFORMAT_ETC2_RGB8A1, SG_PIXELFORMAT_ETC2_RGBA8, SG_PIXELFORMAT_ETC2_SRGB8A8, - SG_PIXELFORMAT_ETC2_RG11, - SG_PIXELFORMAT_ETC2_RG11SN, + SG_PIXELFORMAT_EAC_R11, + SG_PIXELFORMAT_EAC_R11SN, + SG_PIXELFORMAT_EAC_RG11, + SG_PIXELFORMAT_EAC_RG11SN, SG_PIXELFORMAT_ASTC_4x4_RGBA, SG_PIXELFORMAT_ASTC_4x4_SRGBA, @@ -1700,6 +1832,7 @@ typedef struct sg_features { bool image_clamp_to_border; // border color and clamp-to-border UV-wrap mode is supported bool mrt_independent_blend_state; // multiple-render-target rendering can use per-render-target blend state bool mrt_independent_write_mask; // multiple-render-target rendering can use per-render-target color write masks + bool storage_buffer; // storage buffers are supported } sg_features; /* @@ -1789,8 +1922,10 @@ typedef enum sg_usage { /* sg_buffer_type - This indicates whether a buffer contains vertex- or index-data, - used in the sg_buffer_desc.type member when creating a buffer. + Indicates whether a buffer will be bound as vertex-, + index- or storage-buffer. + + Used in the sg_buffer_desc.type member when creating a buffer. The default value is SG_BUFFERTYPE_VERTEXBUFFER. */ @@ -1798,6 +1933,7 @@ typedef enum sg_buffer_type { _SG_BUFFERTYPE_DEFAULT, // value 0 reserved for default-init SG_BUFFERTYPE_VERTEXBUFFER, SG_BUFFERTYPE_INDEXBUFFER, + SG_BUFFERTYPE_STORAGEBUFFER, _SG_BUFFERTYPE_NUM, _SG_BUFFERTYPE_FORCE_U32 = 0x7FFFFFFF } sg_buffer_type; @@ -1851,7 +1987,7 @@ typedef enum sg_image_type { is compatible with what the shader expects. Apart from the sokol-gfx validation layer, WebGPU is the only backend API which actually requires matching texture and sampler type to be provided upfront for validation - (after 3D APIs treat texture/sampler type mismatches as undefined behaviour). + (other 3D APIs treat texture/sampler type mismatches as undefined behaviour). NOTE that the following texture pixel formats require the use of SG_IMAGESAMPLETYPE_UNFILTERABLE_FLOAT, combined with a sampler @@ -1921,12 +2057,12 @@ typedef enum sg_cube_face { sg_shader_stage There are 2 shader stages: vertex- and fragment-shader-stage. - Each shader stage consists of: + Each shader stage - - one slot for a shader function (provided as source- or byte-code) - - SG_MAX_SHADERSTAGE_UBS slots for uniform blocks - - SG_MAX_SHADERSTAGE_IMAGES slots for images used as textures by - the shader function + - SG_MAX_SHADERSTAGE_UBS slots for applying uniform data + - SG_MAX_SHADERSTAGE_IMAGES slots for images used as textures + - SG_MAX_SHADERSTAGE_SAMPLERS slots for texture samplers + - SG_MAX_SHADERSTAGE_STORAGEBUFFERS slots for storage buffer bindings */ typedef enum sg_shader_stage { SG_SHADERSTAGE_VS, @@ -2432,7 +2568,7 @@ typedef struct sg_pass_action { as 'type erased' void pointers: GL: on all GL backends, a GL framebuffer object must be provided. This - can be zero for the defaul framebuffer. + can be zero for the default framebuffer. D3D11: - an ID3D11RenderTargetView for the rendering surface, without @@ -2562,12 +2698,17 @@ typedef struct sg_pass { - 0..1 index buffer offsets - 0..N vertex shader stage images - 0..N vertex shader stage samplers + - 0..N vertex shader storage buffers - 0..N fragment shader stage images - 0..N fragment shader stage samplers + - 0..N fragment shader storage buffers + + For the max number of bindings, see the constant definitions: - The max number of vertex buffer and shader stage images - are defined by the SG_MAX_VERTEX_BUFFERS and - SG_MAX_SHADERSTAGE_IMAGES configuration constants. + - SG_MAX_VERTEX_BUFFERS + - SG_MAX_SHADERSTAGE_IMAGES + - SG_MAX_SHADERSTAGE_SAMPLERS + - SG_MAX_SHADERSTAGE_STORAGEBUFFERS The optional buffer offsets can be used to put different unrelated chunks of vertex- and/or index-data into the same buffer objects. @@ -2575,6 +2716,7 @@ typedef struct sg_pass { typedef struct sg_stage_bindings { sg_image images[SG_MAX_SHADERSTAGE_IMAGES]; sg_sampler samplers[SG_MAX_SHADERSTAGE_SAMPLERS]; + sg_buffer storage_buffers[SG_MAX_SHADERSTAGE_STORAGEBUFFERS]; } sg_stage_bindings; typedef struct sg_bindings { @@ -2601,11 +2743,7 @@ typedef struct sg_bindings { .usage: SG_USAGE_IMMUTABLE .data.ptr 0 (*must* be valid for immutable buffers) .data.size 0 (*must* be > 0 for immutable buffers) - .label 0 (optional string label for trace hooks) - - The label will be ignored by sokol_gfx.h, it is only useful - when hooking into sg_make_buffer() or sg_init_buffer() via - the sg_install_trace_hooks() function. + .label 0 (optional string label) For immutable buffers which are initialized with initial data, keep the .size item zero-initialized, and set the size together with the @@ -2818,6 +2956,9 @@ typedef struct sg_sampler_desc { - the texture slot of the involved texture - the sampler slot of the involved sampler - for GLSL only: the name of the combined image-sampler object + - reflection info for each storage-buffer used by the shader: + - whether the storage buffer is readonly (currently this + must be true) For all GL backends, shader source-code must be provided. For D3D11 and Metal, either shader source-code or byte-code can be provided. @@ -2846,6 +2987,11 @@ typedef struct sg_shader_uniform_block_desc { sg_shader_uniform_desc uniforms[SG_MAX_UB_MEMBERS]; } sg_shader_uniform_block_desc; +typedef struct sg_shader_storage_buffer_desc { + bool used; + bool readonly; +} sg_shader_storage_buffer_desc; + typedef struct sg_shader_image_desc { bool used; bool multisampled; @@ -2871,6 +3017,7 @@ typedef struct sg_shader_stage_desc { const char* entry; const char* d3d11_target; sg_shader_uniform_block_desc uniform_blocks[SG_MAX_SHADERSTAGE_UBS]; + sg_shader_storage_buffer_desc storage_buffers[SG_MAX_SHADERSTAGE_STORAGEBUFFERS]; sg_shader_image_desc images[SG_MAX_SHADERSTAGE_IMAGES]; sg_shader_sampler_desc samplers[SG_MAX_SHADERSTAGE_SAMPLERS]; sg_shader_image_sampler_pair_desc image_sampler_pairs[SG_MAX_SHADERSTAGE_IMAGESAMPLERPAIRS]; @@ -3214,9 +3361,9 @@ typedef struct sg_attachments_info { /* sg_frame_stats - Allows to track generic and backend-specific tracking stats about a + Allows to track generic and backend-specific stats about a render frame. Obtained by calling sg_query_frame_stats(). The returned - struct will contains information about the *previous* frame. + struct contains information about the *previous* frame. */ typedef struct sg_frame_stats_gl { uint32_t num_bind_buffer; @@ -3301,6 +3448,7 @@ typedef struct sg_frame_stats_metal_bindings { uint32_t num_set_vertex_buffer; uint32_t num_set_vertex_texture; uint32_t num_set_vertex_sampler_state; + uint32_t num_set_fragment_buffer; uint32_t num_set_fragment_texture; uint32_t num_set_fragment_sampler_state; } sg_frame_stats_metal_bindings; @@ -3390,6 +3538,7 @@ typedef struct sg_frame_stats { _SG_LOGITEM_XMACRO(GL_FRAMEBUFFER_STATUS_INCOMPLETE_MULTISAMPLE, "framebuffer completeness check failed with GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE (gl)") \ _SG_LOGITEM_XMACRO(GL_FRAMEBUFFER_STATUS_UNKNOWN, "framebuffer completeness check failed (unknown reason) (gl)") \ _SG_LOGITEM_XMACRO(D3D11_CREATE_BUFFER_FAILED, "CreateBuffer() failed (d3d11)") \ + _SG_LOGITEM_XMACRO(D3D11_CREATE_BUFFER_SRV_FAILED, "CreateShaderResourceView() failed for storage buffer (d3d11)") \ _SG_LOGITEM_XMACRO(D3D11_CREATE_DEPTH_TEXTURE_UNSUPPORTED_PIXEL_FORMAT, "pixel format not supported for depth-stencil texture (d3d11)") \ _SG_LOGITEM_XMACRO(D3D11_CREATE_DEPTH_TEXTURE_FAILED, "CreateTexture2D() failed for depth-stencil texture (d3d11)") \ _SG_LOGITEM_XMACRO(D3D11_CREATE_2D_TEXTURE_UNSUPPORTED_PIXEL_FORMAT, "pixel format not supported for 2d-, cube- or array-texture (d3d11)") \ @@ -3436,13 +3585,14 @@ typedef struct sg_frame_stats { _SG_LOGITEM_XMACRO(WGPU_CREATE_SHADER_MODULE_FAILED, "wgpuDeviceCreateShaderModule() failed") \ _SG_LOGITEM_XMACRO(WGPU_SHADER_TOO_MANY_IMAGES, "shader uses too many sampled images on shader stage (wgpu)") \ _SG_LOGITEM_XMACRO(WGPU_SHADER_TOO_MANY_SAMPLERS, "shader uses too many samplers on shader stage (wgpu)") \ + _SG_LOGITEM_XMACRO(WGPU_SHADER_TOO_MANY_STORAGEBUFFERS, "shader uses too many storage buffer bindings on shader stage (wgpu)") \ _SG_LOGITEM_XMACRO(WGPU_SHADER_CREATE_BINDGROUP_LAYOUT_FAILED, "wgpuDeviceCreateBindGroupLayout() for shader stage failed") \ _SG_LOGITEM_XMACRO(WGPU_CREATE_PIPELINE_LAYOUT_FAILED, "wgpuDeviceCreatePipelineLayout() failed") \ _SG_LOGITEM_XMACRO(WGPU_CREATE_RENDER_PIPELINE_FAILED, "wgpuDeviceCreateRenderPipeline() failed") \ _SG_LOGITEM_XMACRO(WGPU_ATTACHMENTS_CREATE_TEXTURE_VIEW_FAILED, "wgpuTextureCreateView() failed in create attachments") \ _SG_LOGITEM_XMACRO(IDENTICAL_COMMIT_LISTENER, "attempting to add identical commit listener") \ _SG_LOGITEM_XMACRO(COMMIT_LISTENER_ARRAY_FULL, "commit listener array full") \ - _SG_LOGITEM_XMACRO(TRACE_HOOKS_NOT_ENABLED, "sg_install_trace_hooks() called, but SG_TRACE_HOOKS is not defined") \ + _SG_LOGITEM_XMACRO(TRACE_HOOKS_NOT_ENABLED, "sg_install_trace_hooks() called, but SOKOL_TRACE_HOOKS is not defined") \ _SG_LOGITEM_XMACRO(DEALLOC_BUFFER_INVALID_STATE, "sg_dealloc_buffer(): buffer must be in ALLOC state") \ _SG_LOGITEM_XMACRO(DEALLOC_IMAGE_INVALID_STATE, "sg_dealloc_image(): image must be in alloc state") \ _SG_LOGITEM_XMACRO(DEALLOC_SAMPLER_INVALID_STATE, "sg_dealloc_sampler(): sampler must be in alloc state") \ @@ -3480,6 +3630,8 @@ typedef struct sg_frame_stats { _SG_LOGITEM_XMACRO(VALIDATE_BUFFERDESC_DATA, "immutable buffers must be initialized with data (sg_buffer_desc.data.ptr and sg_buffer_desc.data.size)") \ _SG_LOGITEM_XMACRO(VALIDATE_BUFFERDESC_DATA_SIZE, "immutable buffer data size differs from buffer size") \ _SG_LOGITEM_XMACRO(VALIDATE_BUFFERDESC_NO_DATA, "dynamic/stream usage buffers cannot be initialized with data") \ + _SG_LOGITEM_XMACRO(VALIDATE_BUFFERDESC_STORAGEBUFFER_SUPPORTED, "storage buffers not supported by the backend 3D API (requires OpenGL >= 4.3)") \ + _SG_LOGITEM_XMACRO(VALIDATE_BUFFERDESC_STORAGEBUFFER_SIZE_MULTIPLE_4, "size of storage buffers must be a multiple of 4") \ _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDATA_NODATA, "sg_image_data: no data (.ptr and/or .size is zero)") \ _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDATA_DATA_SIZE, "sg_image_data: data size doesn't match expected surface size") \ _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_CANARY, "sg_image_desc not initialized") \ @@ -3513,6 +3665,8 @@ typedef struct sg_frame_stats { _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_UB_SIZE_MISMATCH, "size of uniform block members doesn't match uniform block size") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_UB_ARRAY_COUNT, "uniform array count must be >= 1") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_UB_STD140_ARRAY_TYPE, "uniform arrays only allowed for FLOAT4, INT4, MAT4 in std140 layout") \ + _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_NO_CONT_STORAGEBUFFERS, "shader stage storage buffers must occupy continuous slots (sg_shader_desc.vs|fs.storage_buffers[])") \ + _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_STORAGEBUFFER_READONLY, "shader stage storage buffers must be readonly (sg_shader_desc.vs|fs.storage_buffers[].readonly)") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_NO_CONT_IMAGES, "shader stage images must occupy continuous slots (sg_shader_desc.vs|fs.images[])") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_NO_CONT_SAMPLERS, "shader stage samplers must occupy continuous slots (sg_shader_desc.vs|fs.samplers[])") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_IMAGE_SAMPLER_PAIR_IMAGE_SLOT_OUT_OF_RANGE, "shader stage: image-sampler-pair image slot index is out of range (sg_shader_desc.vs|fs.image_sampler_pairs[].image_slot)") \ @@ -3526,11 +3680,10 @@ typedef struct sg_frame_stats { _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_IMAGE_NOT_REFERENCED_BY_IMAGE_SAMPLER_PAIRS, "shader stage: one or more images are note referenced by (sg_shader_desc.vs|fs.image_sampler_pairs[].image_slot)") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_SAMPLER_NOT_REFERENCED_BY_IMAGE_SAMPLER_PAIRS, "shader stage: one or more samplers are not referenced by image-sampler-pairs (sg_shader_desc.vs|fs.image_sampler_pairs[].sampler_slot)") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_NO_CONT_IMAGE_SAMPLER_PAIRS, "shader stage image-sampler-pairs must occupy continuous slots (sg_shader_desc.vs|fs.image_samplers[])") \ - _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_ATTR_SEMANTICS, "D3D11 backend requires vertex attribute semantics") \ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_ATTR_STRING_TOO_LONG, "vertex attribute name/semantic string too long (max len 16)") \ _SG_LOGITEM_XMACRO(VALIDATE_PIPELINEDESC_CANARY, "sg_pipeline_desc not initialized") \ _SG_LOGITEM_XMACRO(VALIDATE_PIPELINEDESC_SHADER, "sg_pipeline_desc.shader missing or invalid") \ - _SG_LOGITEM_XMACRO(VALIDATE_PIPELINEDESC_NO_ATTRS, "sg_pipeline_desc.layout.attrs is empty or not continuous") \ + _SG_LOGITEM_XMACRO(VALIDATE_PIPELINEDESC_NO_CONT_ATTRS, "sg_pipeline_desc.layout.attrs is not continuous") \ _SG_LOGITEM_XMACRO(VALIDATE_PIPELINEDESC_LAYOUT_STRIDE4, "sg_pipeline_desc.layout.buffers[].stride must be multiple of 4") \ _SG_LOGITEM_XMACRO(VALIDATE_PIPELINEDESC_ATTR_SEMANTICS, "D3D11 missing vertex attribute semantics in shader") \ _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_CANARY, "sg_attachments_desc not initialized") \ @@ -3566,7 +3719,7 @@ typedef struct sg_frame_stats { _SG_LOGITEM_XMACRO(VALIDATE_ATTACHMENTSDESC_DEPTH_IMAGE_SAMPLE_COUNT, "pass depth attachment sample count must match color attachment sample count") \ _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_CANARY, "sg_begin_pass: pass struct not initialized") \ _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_ATTACHMENTS_EXISTS, "sg_begin_pass: attachments object no longer alive") \ - _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_ATTACHMENTS_VALID, "sg_begin_pass: attachemnts object not in resource state VALID") \ + _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_ATTACHMENTS_VALID, "sg_begin_pass: attachments object not in resource state VALID") \ _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_COLOR_ATTACHMENT_IMAGE, "sg_begin_pass: one or more color attachment images are not valid") \ _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_RESOLVE_ATTACHMENT_IMAGE, "sg_begin_pass: one or more resolve attachment images are not valid") \ _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_DEPTHSTENCIL_ATTACHMENT_IMAGE, "sg_begin_pass: one or more depth-stencil attachment images are not valid") \ @@ -3634,6 +3787,10 @@ typedef struct sg_frame_stats { _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_EXPECTED_NONFILTERING_SAMPLER, "sg_apply_bindings: shader expected SG_SAMPLERTYPE_NONFILTERING on vertex stage, but sampler has SG_FILTER_LINEAR filters") \ _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_UNEXPECTED_SAMPLER_BINDING, "sg_apply_bindings: unexpected sampler binding on vertex stage") \ _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_SMP_EXISTS, "sg_apply_bindings: sampler bound to vertex stage no longer alive") \ + _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_EXPECTED_STORAGEBUFFER_BINDING, "sg_apply_bindings: storage buffer binding on vertex stage is missing or the buffer handle is invalid") \ + _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_STORAGEBUFFER_EXISTS, "sg_apply_bindings: storage buffer bound to vertex stage no longer alive") \ + _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_STORAGEBUFFER_BINDING_BUFFERTYPE, "sg_apply_bindings: buffer bound to vertex stage storage buffer slot is not of type storage buffer") \ + _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_UNEXPECTED_STORAGEBUFFER_BINDING, "sg_apply_bindings: unexpected storage buffer binding on vertex stage") \ _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_EXPECTED_IMAGE_BINDING, "sg_apply_bindings: image binding on fragment stage is missing or the image handle is invalid") \ _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_IMG_EXISTS, "sg_apply_bindings: image bound to fragment stage no longer alive") \ _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_IMAGE_TYPE_MISMATCH, "sg_apply_bindings: type of image bound to fragment stage doesn't match shader desc") \ @@ -3647,6 +3804,10 @@ typedef struct sg_frame_stats { _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_EXPECTED_NONFILTERING_SAMPLER, "sg_apply_bindings: shader expected SG_SAMPLERTYPE_NONFILTERING on fragment stage, but sampler has SG_FILTER_LINEAR filters") \ _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_UNEXPECTED_SAMPLER_BINDING, "sg_apply_bindings: unexpected sampler binding on fragment stage") \ _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_SMP_EXISTS, "sg_apply_bindings: sampler bound to fragment stage no longer alive") \ + _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_EXPECTED_STORAGEBUFFER_BINDING, "sg_apply_bindings: storage buffer binding on fragment stage is missing or the buffer handle is invalid") \ + _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_STORAGEBUFFER_EXISTS, "sg_apply_bindings: storage buffer bound to fragment stage no longer alive") \ + _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_STORAGEBUFFER_BINDING_BUFFERTYPE, "sg_apply_bindings: buffer bound to frahment stage storage buffer slot is not of type storage buffer") \ + _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_UNEXPECTED_STORAGEBUFFER_BINDING, "sg_apply_bindings: unexpected storage buffer binding on fragment stage") \ _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 doesn't match declared uniform block size") \ @@ -3673,11 +3834,6 @@ typedef enum sg_log_item { The sg_desc struct contains configuration values for sokol_gfx, it is used as parameter to the sg_setup() call. - NOTE that all callback function pointers come in two versions, one without - a userdata pointer, and one with a userdata pointer. You would - either initialize one or the other depending on whether you pass data - to your callbacks. - The default configuration is: .buffer_pool_size 128 @@ -3771,7 +3927,7 @@ typedef struct sg_d3d11_environment { } sg_d3d11_environment; typedef struct sg_wgpu_environment { - const void* device; // WGPUDevice + const void* device; } sg_wgpu_environment; typedef struct sg_environment { @@ -3816,8 +3972,9 @@ typedef struct sg_allocator { that without logging function, sokol-gfx will be completely silent, e.g. it will not report errors, warnings and validation layer messages. For maximum error verbosity, - compile in debug mode (e.g. NDEBUG *not* defined) and install - a logger (for instance the standard logging function from sokol_log.h). + compile in debug mode (e.g. NDEBUG *not* defined) and provide a + compatible logger function in the sg_setup() call + (for instance the standard logging function from sokol_log.h). */ typedef struct sg_logger { void (*func)( @@ -4166,7 +4323,7 @@ inline sg_image sg_make_image(const sg_image_desc& desc) { return sg_make_image( inline sg_sampler sg_make_sampler(const sg_sampler_desc& desc) { return sg_make_sampler(&desc); } inline sg_shader sg_make_shader(const sg_shader_desc& desc) { return sg_make_shader(&desc); } inline sg_pipeline sg_make_pipeline(const sg_pipeline_desc& desc) { return sg_make_pipeline(&desc); } -inline sg_attachments sg_make_attchments(const sg_attachments_desc& desc) { return sg_make_attachments(&desc); } +inline sg_attachments sg_make_attachments(const sg_attachments_desc& desc) { return sg_make_attachments(&desc); } inline void sg_update_image(sg_image img, const sg_image_data& data) { return sg_update_image(img, &data); } inline void sg_begin_pass(const sg_pass& pass) { return sg_begin_pass(&pass); } @@ -4202,8 +4359,8 @@ inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_ #ifdef SOKOL_GFX_IMPL #define SOKOL_GFX_IMPL_INCLUDED (1) -#if !(defined(SOKOL_GLCORE33)||defined(SOKOL_GLES3)||defined(SOKOL_D3D11)||defined(SOKOL_METAL)||defined(SOKOL_WGPU)||defined(SOKOL_DUMMY_BACKEND)) -#error "Please select a backend with SOKOL_GLCORE33, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU or SOKOL_DUMMY_BACKEND" +#if !(defined(SOKOL_GLCORE)||defined(SOKOL_GLES3)||defined(SOKOL_D3D11)||defined(SOKOL_METAL)||defined(SOKOL_WGPU)||defined(SOKOL_DUMMY_BACKEND)) +#error "Please select a backend with SOKOL_GLCORE, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU or SOKOL_DUMMY_BACKEND" #endif #if defined(SOKOL_MALLOC) || defined(SOKOL_CALLOC) || defined(SOKOL_FREE) #error "SOKOL_MALLOC/CALLOC/FREE macros are no longer supported, please use sg_desc.allocator to override memory allocation functions" @@ -4320,13 +4477,13 @@ inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_ #if defined(__EMSCRIPTEN__) #include #endif -#elif defined(SOKOL_GLCORE33) || defined(SOKOL_GLES3) +#elif defined(SOKOL_GLCORE) || defined(SOKOL_GLES3) #define _SOKOL_ANY_GL (1) // include platform specific GL headers (or on Win32: use an embedded GL loader) #if !defined(SOKOL_EXTERNAL_GL_LOADER) #if defined(_WIN32) - #if defined(SOKOL_GLCORE33) && !defined(SOKOL_EXTERNAL_GL_LOADER) + #if defined(SOKOL_GLCORE) && !defined(SOKOL_EXTERNAL_GL_LOADER) #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif @@ -4353,7 +4510,7 @@ inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_ #include #endif #elif defined(__linux__) || defined(__unix__) - #if defined(SOKOL_GLCORE33) + #if defined(SOKOL_GLCORE) #define GL_GLEXT_PROTOTYPES #include #else @@ -4610,6 +4767,8 @@ inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_ #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 #define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 + #define GL_MAJOR_VERSION 0x821B + #define GL_MINOR_VERSION 0x821C #endif #ifndef GL_UNSIGNED_INT_2_10_10_10_REV @@ -4687,6 +4846,12 @@ inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_ #ifndef GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 #define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 #endif + #ifndef GL_COMPRESSED_R11_EAC + #define GL_COMPRESSED_R11_EAC 0x9270 + #endif + #ifndef GL_COMPRESSED_SIGNED_R11_EAC + #define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 + #endif #ifndef GL_COMPRESSED_RG11_EAC #define GL_COMPRESSED_RG11_EAC 0x9272 #endif @@ -4725,6 +4890,12 @@ inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_ #endif #endif +// make some GL constants generally available to simplify compilation, +// use of those constants will be filtered by runtime flags +#ifndef GL_SHADER_STORAGE_BUFFER +#define GL_SHADER_STORAGE_BUFFER 0x90D2 +#endif + // ███████ ████████ ██████ ██ ██ ██████ ████████ ███████ // ██ ██ ██ ██ ██ ██ ██ ██ ██ // ███████ ██ ██████ ██ ██ ██ ██ ███████ @@ -4756,7 +4927,7 @@ _SOKOL_PRIVATE int _sg_slot_index(uint32_t id); // constants enum { - _SG_STRING_SIZE = 16, + _SG_STRING_SIZE = 32, _SG_SLOT_SHIFT = 16, _SG_SLOT_MASK = (1<<_SG_SLOT_SHIFT)-1, _SG_MAX_POOL_SIZE = (1<<_SG_SLOT_SHIFT), @@ -4876,6 +5047,11 @@ typedef struct { size_t size; } _sg_shader_uniform_block_t; +typedef struct { + bool used; + bool readonly; +} _sg_shader_storage_buffer_t; + typedef struct { sg_image_type image_type; sg_image_sample_type sample_type; @@ -4894,10 +5070,12 @@ typedef struct { typedef struct { int num_uniform_blocks; + int num_storage_buffers; int num_images; int num_samplers; int num_image_samplers; _sg_shader_uniform_block_t uniform_blocks[SG_MAX_SHADERSTAGE_UBS]; + _sg_shader_storage_buffer_t storage_buffers[SG_MAX_SHADERSTAGE_STORAGEBUFFERS]; _sg_shader_image_t images[SG_MAX_SHADERSTAGE_IMAGES]; _sg_shader_sampler_t samplers[SG_MAX_SHADERSTAGE_SAMPLERS]; _sg_shader_image_sampler_t image_samplers[SG_MAX_SHADERSTAGE_IMAGESAMPLERPAIRS]; @@ -4952,6 +5130,16 @@ _SOKOL_PRIVATE void _sg_shader_common_init(_sg_shader_common_t* cmn, const sg_sh stage->image_samplers[img_smp_index].sampler_slot = img_smp_desc->sampler_slot; stage->num_image_samplers++; } + SOKOL_ASSERT(stage->num_storage_buffers == 0); + for (int sbuf_index = 0; sbuf_index < SG_MAX_SHADERSTAGE_STORAGEBUFFERS; sbuf_index++) { + const sg_shader_storage_buffer_desc* sbuf_desc = &stage_desc->storage_buffers[sbuf_index]; + if (!sbuf_desc->used) { + break; + } + stage->storage_buffers[sbuf_index].used = sbuf_desc->used; + stage->storage_buffers[sbuf_index].readonly = sbuf_desc->readonly; + stage->num_storage_buffers++; + } } } @@ -5081,6 +5269,10 @@ typedef struct { typedef _sg_dummy_attachments_t _sg_attachments_t; #elif defined(_SOKOL_ANY_GL) + +#define _SG_GL_TEXTURE_SAMPLER_CACHE_SIZE (SG_MAX_SHADERSTAGE_IMAGESAMPLERPAIRS * SG_NUM_SHADER_STAGES) +#define _SG_GL_STORAGEBUFFER_STAGE_INDEX_PITCH (SG_MAX_SHADERSTAGE_STORAGEBUFFERS) + typedef struct { _sg_slot_t slot; _sg_buffer_common_t cmn; @@ -5206,8 +5398,6 @@ typedef struct { GLuint sampler; } _sg_gl_cache_texture_sampler_bind_slot; -#define _SG_GL_TEXTURE_SAMPLER_CACHE_SIZE (SG_MAX_SHADERSTAGE_IMAGESAMPLERPAIRS * SG_NUM_SHADER_STAGES) - typedef struct { sg_depth_state depth; sg_stencil_state stencil; @@ -5222,8 +5412,11 @@ typedef struct { _sg_gl_cache_attr_t attrs[SG_MAX_VERTEX_ATTRIBUTES]; GLuint vertex_buffer; GLuint index_buffer; + GLuint storage_buffer; // general bind point + GLuint stage_storage_buffers[SG_NUM_SHADER_STAGES][SG_MAX_SHADERSTAGE_STORAGEBUFFERS]; GLuint stored_vertex_buffer; GLuint stored_index_buffer; + GLuint stored_storage_buffer; GLuint prog; _sg_gl_cache_texture_sampler_bind_slot texture_samplers[_SG_GL_TEXTURE_SAMPLER_CACHE_SIZE]; _sg_gl_cache_texture_sampler_bind_slot stored_texture_sampler; @@ -5256,6 +5449,7 @@ typedef struct { _sg_buffer_common_t cmn; struct { ID3D11Buffer* buf; + ID3D11ShaderResourceView* srv; } d3d11; } _sg_d3d11_buffer_t; typedef _sg_d3d11_buffer_t _sg_buffer_t; @@ -5471,6 +5665,8 @@ typedef struct { sg_image cur_fs_image_ids[SG_MAX_SHADERSTAGE_IMAGES]; sg_sampler cur_vs_sampler_ids[SG_MAX_SHADERSTAGE_SAMPLERS]; sg_sampler cur_fs_sampler_ids[SG_MAX_SHADERSTAGE_SAMPLERS]; + sg_buffer cur_vs_storagebuffer_ids[SG_MAX_SHADERSTAGE_STORAGEBUFFERS]; + sg_buffer cur_fs_storagebuffer_ids[SG_MAX_SHADERSTAGE_STORAGEBUFFERS]; } _sg_mtl_state_cache_t; typedef struct { @@ -5498,6 +5694,7 @@ typedef struct { #define _SG_WGPU_NUM_BINDGROUPS (2) // 0: uniforms, 1: images and sampler on both shader stages #define _SG_WGPU_UNIFORM_BINDGROUP_INDEX (0) #define _SG_WGPU_IMAGE_SAMPLER_BINDGROUP_INDEX (1) +#define _SG_WGPU_MAX_BINDGROUP_ENTRIES (SG_NUM_SHADER_STAGES * (SG_MAX_SHADERSTAGE_IMAGES + SG_MAX_SHADERSTAGE_SAMPLERS + SG_MAX_SHADERSTAGE_STORAGEBUFFERS)) typedef struct { _sg_slot_t slot; @@ -5586,7 +5783,7 @@ typedef struct { uint32_t id; } _sg_wgpu_bindgroup_handle_t; -#define _SG_WGPU_BINDGROUPSCACHE_NUM_ITEMS (1 + SG_NUM_SHADER_STAGES * (SG_MAX_SHADERSTAGE_IMAGES + SG_MAX_SHADERSTAGE_SAMPLERS)) +#define _SG_WGPU_BINDGROUPSCACHE_NUM_ITEMS (1 + _SG_WGPU_MAX_BINDGROUP_ENTRIES) typedef struct { uint64_t hash; uint32_t items[_SG_WGPU_BINDGROUPSCACHE_NUM_ITEMS]; @@ -5672,16 +5869,20 @@ typedef struct { int num_vbs; int num_vs_imgs; int num_vs_smps; + int num_vs_sbufs; int num_fs_imgs; int num_fs_smps; + int num_fs_sbufs; int vb_offsets[SG_MAX_VERTEX_BUFFERS]; int ib_offset; _sg_buffer_t* vbs[SG_MAX_VERTEX_BUFFERS]; _sg_buffer_t* ib; _sg_image_t* vs_imgs[SG_MAX_SHADERSTAGE_IMAGES]; _sg_sampler_t* vs_smps[SG_MAX_SHADERSTAGE_SAMPLERS]; + _sg_buffer_t* vs_sbufs[SG_MAX_SHADERSTAGE_STORAGEBUFFERS]; _sg_image_t* fs_imgs[SG_MAX_SHADERSTAGE_IMAGES]; _sg_sampler_t* fs_smps[SG_MAX_SHADERSTAGE_SAMPLERS]; + _sg_buffer_t* fs_sbufs[SG_MAX_SHADERSTAGE_STORAGEBUFFERS]; } _sg_bindings_t; typedef struct { @@ -5711,7 +5912,6 @@ typedef struct { } swapchain; } cur_pass; sg_pipeline cur_pipeline; - bool apply_bindings_called; bool next_draw_valid; #if defined(SOKOL_DEBUG) sg_log_item validate_error; @@ -6026,8 +6226,10 @@ _SOKOL_PRIVATE bool _sg_is_compressed_pixel_format(sg_pixel_format fmt) { case SG_PIXELFORMAT_ETC2_RGB8A1: case SG_PIXELFORMAT_ETC2_RGBA8: case SG_PIXELFORMAT_ETC2_SRGB8A8: - case SG_PIXELFORMAT_ETC2_RG11: - case SG_PIXELFORMAT_ETC2_RG11SN: + case SG_PIXELFORMAT_EAC_R11: + case SG_PIXELFORMAT_EAC_R11SN: + case SG_PIXELFORMAT_EAC_RG11: + case SG_PIXELFORMAT_EAC_RG11SN: case SG_PIXELFORMAT_ASTC_4x4_RGBA: case SG_PIXELFORMAT_ASTC_4x4_SRGBA: return true; @@ -6155,6 +6357,8 @@ _SOKOL_PRIVATE int _sg_row_pitch(sg_pixel_format fmt, int width, int row_align) case SG_PIXELFORMAT_ETC2_RGB8: case SG_PIXELFORMAT_ETC2_SRGB8: case SG_PIXELFORMAT_ETC2_RGB8A1: + case SG_PIXELFORMAT_EAC_R11: + case SG_PIXELFORMAT_EAC_R11SN: pitch = ((width + 3) / 4) * 8; pitch = pitch < 8 ? 8 : pitch; break; @@ -6169,8 +6373,8 @@ _SOKOL_PRIVATE int _sg_row_pitch(sg_pixel_format fmt, int width, int row_align) case SG_PIXELFORMAT_BC7_SRGBA: case SG_PIXELFORMAT_ETC2_RGBA8: case SG_PIXELFORMAT_ETC2_SRGB8A8: - case SG_PIXELFORMAT_ETC2_RG11: - case SG_PIXELFORMAT_ETC2_RG11SN: + case SG_PIXELFORMAT_EAC_RG11: + case SG_PIXELFORMAT_EAC_RG11SN: case SG_PIXELFORMAT_ASTC_4x4_RGBA: case SG_PIXELFORMAT_ASTC_4x4_SRGBA: pitch = ((width + 3) / 4) * 16; @@ -6204,8 +6408,10 @@ _SOKOL_PRIVATE int _sg_num_rows(sg_pixel_format fmt, int height) { case SG_PIXELFORMAT_ETC2_RGB8A1: case SG_PIXELFORMAT_ETC2_RGBA8: case SG_PIXELFORMAT_ETC2_SRGB8A8: - case SG_PIXELFORMAT_ETC2_RG11: - case SG_PIXELFORMAT_ETC2_RG11SN: + case SG_PIXELFORMAT_EAC_R11: + case SG_PIXELFORMAT_EAC_R11SN: + case SG_PIXELFORMAT_EAC_RG11: + case SG_PIXELFORMAT_EAC_RG11SN: case SG_PIXELFORMAT_BC2_RGBA: case SG_PIXELFORMAT_BC3_RGBA: case SG_PIXELFORMAT_BC3_SRGBA: @@ -6277,6 +6483,12 @@ _SOKOL_PRIVATE void _sg_pixelformat_sr(_sg_pixelformat_info_t* pfi) { pfi->render = true; } +_SOKOL_PRIVATE void _sg_pixelformat_sfr(_sg_pixelformat_info_t* pfi) { + pfi->sample = true; + pfi->filter = true; + pfi->render = true; +} + _SOKOL_PRIVATE void _sg_pixelformat_srmd(_sg_pixelformat_info_t* pfi) { pfi->sample = true; pfi->render = true; @@ -6701,7 +6913,8 @@ _SOKOL_PRIVATE void _sg_dummy_update_image(_sg_image_t* img, const sg_image_data _SG_XMACRO(glSamplerParameteri, void, (GLuint sampler, GLenum pname, GLint param)) \ _SG_XMACRO(glSamplerParameterf, void, (GLuint sampler, GLenum pname, GLfloat param)) \ _SG_XMACRO(glSamplerParameterfv, void, (GLuint sampler, GLenum pname, const GLfloat* params)) \ - _SG_XMACRO(glDeleteSamplers, void, (GLsizei n, const GLuint* samplers)) + _SG_XMACRO(glDeleteSamplers, void, (GLsizei n, const GLuint* samplers)) \ + _SG_XMACRO(glBindBufferBase, void, (GLenum target, GLuint index, GLuint buffer)) // generate GL function pointer typedefs #define _SG_XMACRO(name, ret, args) typedef ret (GL_APIENTRY* PFN_ ## name) args; @@ -6748,6 +6961,7 @@ _SOKOL_PRIVATE GLenum _sg_gl_buffer_target(sg_buffer_type t) { switch (t) { case SG_BUFFERTYPE_VERTEXBUFFER: return GL_ARRAY_BUFFER; case SG_BUFFERTYPE_INDEXBUFFER: return GL_ELEMENT_ARRAY_BUFFER; + case SG_BUFFERTYPE_STORAGEBUFFER: return GL_SHADER_STORAGE_BUFFER; default: SOKOL_UNREACHABLE; return 0; } } @@ -6957,7 +7171,7 @@ _SOKOL_PRIVATE GLenum _sg_gl_mag_filter(sg_filter mag_f) { _SOKOL_PRIVATE GLenum _sg_gl_wrap(sg_wrap w) { switch (w) { case SG_WRAP_CLAMP_TO_EDGE: return GL_CLAMP_TO_EDGE; - #if defined(SOKOL_GLCORE33) + #if defined(SOKOL_GLCORE) case SG_WRAP_CLAMP_TO_BORDER: return GL_CLAMP_TO_BORDER; #else case SG_WRAP_CLAMP_TO_BORDER: return GL_CLAMP_TO_EDGE; @@ -7126,9 +7340,13 @@ _SOKOL_PRIVATE GLenum _sg_gl_teximage_format(sg_pixel_format fmt) { return GL_COMPRESSED_RGBA8_ETC2_EAC; case SG_PIXELFORMAT_ETC2_SRGB8A8: return GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC; - case SG_PIXELFORMAT_ETC2_RG11: + case SG_PIXELFORMAT_EAC_R11: + return GL_COMPRESSED_R11_EAC; + case SG_PIXELFORMAT_EAC_R11SN: + return GL_COMPRESSED_SIGNED_R11_EAC; + case SG_PIXELFORMAT_EAC_RG11: return GL_COMPRESSED_RG11_EAC; - case SG_PIXELFORMAT_ETC2_RG11SN: + case SG_PIXELFORMAT_EAC_RG11SN: return GL_COMPRESSED_SIGNED_RG11_EAC; case SG_PIXELFORMAT_ASTC_4x4_RGBA: return GL_COMPRESSED_RGBA_ASTC_4x4_KHR; @@ -7210,8 +7428,10 @@ _SOKOL_PRIVATE GLenum _sg_gl_teximage_internal_format(sg_pixel_format fmt) { case SG_PIXELFORMAT_ETC2_RGB8A1: return GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; case SG_PIXELFORMAT_ETC2_RGBA8: return GL_COMPRESSED_RGBA8_ETC2_EAC; case SG_PIXELFORMAT_ETC2_SRGB8A8: return GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC; - case SG_PIXELFORMAT_ETC2_RG11: return GL_COMPRESSED_RG11_EAC; - case SG_PIXELFORMAT_ETC2_RG11SN: return GL_COMPRESSED_SIGNED_RG11_EAC; + case SG_PIXELFORMAT_EAC_R11: return GL_COMPRESSED_R11_EAC; + case SG_PIXELFORMAT_EAC_R11SN: return GL_COMPRESSED_SIGNED_R11_EAC; + case SG_PIXELFORMAT_EAC_RG11: return GL_COMPRESSED_RG11_EAC; + case SG_PIXELFORMAT_EAC_RG11SN: return GL_COMPRESSED_SIGNED_RG11_EAC; case SG_PIXELFORMAT_ASTC_4x4_RGBA: return GL_COMPRESSED_RGBA_ASTC_4x4_KHR; case SG_PIXELFORMAT_ASTC_4x4_SRGBA: return GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR; default: SOKOL_UNREACHABLE; return 0; @@ -7356,8 +7576,10 @@ _SOKOL_PRIVATE void _sg_gl_init_pixelformats_etc2(void) { _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGB8A1]); _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGBA8]); _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_SRGB8A8]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RG11]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RG11SN]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_R11]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_R11SN]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_RG11]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_RG11SN]); } _SOKOL_PRIVATE void _sg_gl_init_pixelformats_astc(void) { @@ -7402,14 +7624,20 @@ _SOKOL_PRIVATE void _sg_gl_init_limits(void) { _sg.limits.gl_max_combined_texture_image_units = gl_int; } -#if defined(SOKOL_GLCORE33) -_SOKOL_PRIVATE void _sg_gl_init_caps_glcore33(void) { - _sg.backend = SG_BACKEND_GLCORE33; +#if defined(SOKOL_GLCORE) +_SOKOL_PRIVATE void _sg_gl_init_caps_glcore(void) { + _sg.backend = SG_BACKEND_GLCORE; + GLint major_version = 0; + GLint minor_version = 0; + glGetIntegerv(GL_MAJOR_VERSION, &major_version); + glGetIntegerv(GL_MINOR_VERSION, &minor_version); + const int version = major_version * 100 + minor_version * 10; _sg.features.origin_top_left = false; _sg.features.image_clamp_to_border = true; _sg.features.mrt_independent_blend_state = false; _sg.features.mrt_independent_write_mask = true; + _sg.features.storage_buffer = version >= 430; // scan extensions bool has_s3tc = false; // BC1..BC3 @@ -7482,6 +7710,7 @@ _SOKOL_PRIVATE void _sg_gl_init_caps_gles3(void) { _sg.features.image_clamp_to_border = false; _sg.features.mrt_independent_blend_state = false; _sg.features.mrt_independent_write_mask = false; + _sg.features.storage_buffer = false; bool has_s3tc = false; // BC1..BC3 bool has_rgtc = false; // BC4 and BC5 @@ -7571,6 +7800,12 @@ _SOKOL_PRIVATE void _sg_gl_init_caps_gles3(void) { #endif //-- state cache implementation ------------------------------------------------ +_SOKOL_PRIVATE GLuint _sg_gl_storagebuffer_bind_index(int stage, int slot) { + SOKOL_ASSERT((stage >= 0) && (stage < SG_NUM_SHADER_STAGES)); + SOKOL_ASSERT((slot >= 0) && (slot < SG_MAX_SHADERSTAGE_STORAGEBUFFERS)); + return (GLuint) (stage * _SG_GL_STORAGEBUFFER_STAGE_INDEX_PITCH + slot); +} + _SOKOL_PRIVATE void _sg_gl_cache_clear_buffer_bindings(bool force) { if (force || (_sg.gl.cache.vertex_buffer != 0)) { glBindBuffer(GL_ARRAY_BUFFER, 0); @@ -7582,30 +7817,77 @@ _SOKOL_PRIVATE void _sg_gl_cache_clear_buffer_bindings(bool force) { _sg.gl.cache.index_buffer = 0; _sg_stats_add(gl.num_bind_buffer, 1); } + if (force || (_sg.gl.cache.storage_buffer != 0)) { + if (_sg.features.storage_buffer) { + glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); + } + _sg.gl.cache.storage_buffer = 0; + _sg_stats_add(gl.num_bind_buffer, 1); + } + for (int stage = 0; stage < SG_NUM_SHADER_STAGES; stage++) { + for (int i = 0; i < SG_MAX_SHADERSTAGE_STORAGEBUFFERS; i++) { + if (force || (_sg.gl.cache.stage_storage_buffers[stage][i] != 0)) { + const GLuint bind_index = _sg_gl_storagebuffer_bind_index(stage, i); + if (_sg.features.storage_buffer) { + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, bind_index, 0); + } + _sg.gl.cache.stage_storage_buffers[stage][i] = 0; + _sg_stats_add(gl.num_bind_buffer, 1); + } + } + } } _SOKOL_PRIVATE void _sg_gl_cache_bind_buffer(GLenum target, GLuint buffer) { - SOKOL_ASSERT((GL_ARRAY_BUFFER == target) || (GL_ELEMENT_ARRAY_BUFFER == target)); + SOKOL_ASSERT((GL_ARRAY_BUFFER == target) || (GL_ELEMENT_ARRAY_BUFFER == target) || (GL_SHADER_STORAGE_BUFFER == target)); if (target == GL_ARRAY_BUFFER) { if (_sg.gl.cache.vertex_buffer != buffer) { _sg.gl.cache.vertex_buffer = buffer; glBindBuffer(target, buffer); _sg_stats_add(gl.num_bind_buffer, 1); } - } else { + } else if (target == GL_ELEMENT_ARRAY_BUFFER) { if (_sg.gl.cache.index_buffer != buffer) { _sg.gl.cache.index_buffer = buffer; glBindBuffer(target, buffer); _sg_stats_add(gl.num_bind_buffer, 1); } + } else if (target == GL_SHADER_STORAGE_BUFFER) { + if (_sg.gl.cache.storage_buffer != buffer) { + _sg.gl.cache.storage_buffer = buffer; + if (_sg.features.storage_buffer) { + glBindBuffer(target, buffer); + } + _sg_stats_add(gl.num_bind_buffer, 1); + } + } else { + SOKOL_UNREACHABLE; + } +} + +_SOKOL_PRIVATE void _sg_gl_cache_bind_storage_buffer(int stage, int slot, GLuint buffer) { + SOKOL_ASSERT((stage >= 0) && (stage < SG_NUM_SHADER_STAGES)); + SOKOL_ASSERT((slot >= 0) && (slot < SG_MAX_SHADERSTAGE_STORAGEBUFFERS)); + if (_sg.gl.cache.stage_storage_buffers[stage][slot] != buffer) { + _sg.gl.cache.stage_storage_buffers[stage][slot] = buffer; + _sg.gl.cache.storage_buffer = buffer; // not a bug + GLuint bind_index = _sg_gl_storagebuffer_bind_index(stage, slot); + if (_sg.features.storage_buffer) { + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, bind_index, buffer); + } + _sg_stats_add(gl.num_bind_buffer, 1); } } _SOKOL_PRIVATE void _sg_gl_cache_store_buffer_binding(GLenum target) { if (target == GL_ARRAY_BUFFER) { _sg.gl.cache.stored_vertex_buffer = _sg.gl.cache.vertex_buffer; - } else { + } else if (target == GL_ELEMENT_ARRAY_BUFFER) { _sg.gl.cache.stored_index_buffer = _sg.gl.cache.index_buffer; + } else if (target == GL_SHADER_STORAGE_BUFFER) { + _sg.gl.cache.stored_storage_buffer = _sg.gl.cache.storage_buffer; + } else { + SOKOL_UNREACHABLE; } } @@ -7616,12 +7898,20 @@ _SOKOL_PRIVATE void _sg_gl_cache_restore_buffer_binding(GLenum target) { _sg_gl_cache_bind_buffer(target, _sg.gl.cache.stored_vertex_buffer); _sg.gl.cache.stored_vertex_buffer = 0; } - } else { + } else if (target == GL_ELEMENT_ARRAY_BUFFER) { if (_sg.gl.cache.stored_index_buffer != 0) { // we only care about restoring valid ids _sg_gl_cache_bind_buffer(target, _sg.gl.cache.stored_index_buffer); _sg.gl.cache.stored_index_buffer = 0; } + } else if (target == GL_SHADER_STORAGE_BUFFER) { + if (_sg.gl.cache.stored_storage_buffer != 0) { + // we only care about restoring valid ids + _sg_gl_cache_bind_buffer(target, _sg.gl.cache.stored_storage_buffer); + _sg.gl.cache.stored_storage_buffer = 0; + } + } else { + SOKOL_UNREACHABLE; } } @@ -7637,12 +7927,31 @@ _SOKOL_PRIVATE void _sg_gl_cache_invalidate_buffer(GLuint buf) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); _sg_stats_add(gl.num_bind_buffer, 1); } + if (buf == _sg.gl.cache.storage_buffer) { + _sg.gl.cache.storage_buffer = 0; + glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); + _sg_stats_add(gl.num_bind_buffer, 1); + } + for (int stage = 0; stage < SG_NUM_SHADER_STAGES; stage++) { + for (int i = 0; i < SG_MAX_SHADERSTAGE_STORAGEBUFFERS; i++) { + if (buf == _sg.gl.cache.stage_storage_buffers[stage][i]) { + _sg.gl.cache.stage_storage_buffers[stage][i] = 0; + _sg.gl.cache.storage_buffer = 0; // not a bug! + const GLuint bind_index = _sg_gl_storagebuffer_bind_index(stage, i); + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, bind_index, 0); + _sg_stats_add(gl.num_bind_buffer, 1); + } + } + } if (buf == _sg.gl.cache.stored_vertex_buffer) { _sg.gl.cache.stored_vertex_buffer = 0; } if (buf == _sg.gl.cache.stored_index_buffer) { _sg.gl.cache.stored_index_buffer = 0; } + if (buf == _sg.gl.cache.stored_storage_buffer) { + _sg.gl.cache.stored_storage_buffer = 0; + } for (int i = 0; i < SG_MAX_VERTEX_ATTRIBUTES; i++) { if (buf == _sg.gl.cache.attrs[i].gl_vbuf) { _sg.gl.cache.attrs[i].gl_vbuf = 0; @@ -7852,7 +8161,7 @@ _SOKOL_PRIVATE void _sg_gl_reset_state_cache(void) { glEnable(GL_DITHER); glDisable(GL_POLYGON_OFFSET_FILL); _sg_stats_add(gl.num_render_state, 10); - #if defined(SOKOL_GLCORE33) + #if defined(SOKOL_GLCORE) glEnable(GL_MULTISAMPLE); glEnable(GL_PROGRAM_POINT_SIZE); _sg_stats_add(gl.num_render_state, 2); @@ -7873,8 +8182,8 @@ _SOKOL_PRIVATE void _sg_gl_setup_backend(const sg_desc* desc) { #if defined(SOKOL_DEBUG) while (glGetError() != GL_NO_ERROR); #endif - #if defined(SOKOL_GLCORE33) - _sg_gl_init_caps_glcore33(); + #if defined(SOKOL_GLCORE) + _sg_gl_init_caps_glcore(); #elif defined(SOKOL_GLES3) _sg_gl_init_caps_gles3(); #endif @@ -7884,7 +8193,7 @@ _SOKOL_PRIVATE void _sg_gl_setup_backend(const sg_desc* desc) { _SG_GL_CHECK_ERROR(); // incoming texture data is generally expected to be packed tightly glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - #if defined(SOKOL_GLCORE33) + #if defined(SOKOL_GLCORE) // enable seamless cubemap sampling (only desktop GL) glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); #endif @@ -7991,40 +8300,57 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_image(_sg_image_t* img, const sg_ _sg_gl_cache_store_texture_sampler_binding(0); _sg_gl_cache_bind_texture_sampler(0, img->gl.target, img->gl.tex[slot], 0); glTexParameteri(img->gl.target, GL_TEXTURE_MAX_LEVEL, img->cmn.num_mipmaps - 1); - const int num_faces = img->cmn.type == SG_IMAGETYPE_CUBE ? 6 : 1; - int data_index = 0; - for (int face_index = 0; face_index < num_faces; face_index++) { - for (int mip_index = 0; mip_index < img->cmn.num_mipmaps; mip_index++, data_index++) { - GLenum gl_img_target = img->gl.target; - if (SG_IMAGETYPE_CUBE == img->cmn.type) { - gl_img_target = _sg_gl_cubeface_target(face_index); - } - const GLvoid* data_ptr = desc->data.subimage[face_index][mip_index].ptr; - const int mip_width = _sg_miplevel_dim(img->cmn.width, mip_index); - const int mip_height = _sg_miplevel_dim(img->cmn.height, mip_index); + + // NOTE: workaround for https://issues.chromium.org/issues/355605685 + // FIXME: on GLES3 and GL 4.3 (e.g. not macOS) the texture initialization + // should be rewritten to use glTexStorage + glTexSubImage + bool tex_storage_allocated = false; + #if defined(__EMSCRIPTEN__) + if (desc->data.subimage[0][0].ptr == 0) { + tex_storage_allocated = true; if ((SG_IMAGETYPE_2D == img->cmn.type) || (SG_IMAGETYPE_CUBE == img->cmn.type)) { - if (is_compressed) { - const GLsizei data_size = (GLsizei) desc->data.subimage[face_index][mip_index].size; - glCompressedTexImage2D(gl_img_target, mip_index, gl_internal_format, - mip_width, mip_height, 0, data_size, data_ptr); - } else { - const GLenum gl_type = _sg_gl_teximage_type(img->cmn.pixel_format); - glTexImage2D(gl_img_target, mip_index, (GLint)gl_internal_format, - mip_width, mip_height, 0, gl_format, gl_type, data_ptr); - } + glTexStorage2D(img->gl.target, img->cmn.num_mipmaps, gl_internal_format, img->cmn.width, img->cmn.height); } else if ((SG_IMAGETYPE_3D == img->cmn.type) || (SG_IMAGETYPE_ARRAY == img->cmn.type)) { - int mip_depth = img->cmn.num_slices; - if (SG_IMAGETYPE_3D == img->cmn.type) { - mip_depth = _sg_miplevel_dim(mip_depth, mip_index); + glTexStorage3D(img->gl.target, img->cmn.num_mipmaps, gl_internal_format, img->cmn.width, img->cmn.height, img->cmn.num_slices); + } + } + #endif + if (!tex_storage_allocated) { + const int num_faces = img->cmn.type == SG_IMAGETYPE_CUBE ? 6 : 1; + int data_index = 0; + for (int face_index = 0; face_index < num_faces; face_index++) { + for (int mip_index = 0; mip_index < img->cmn.num_mipmaps; mip_index++, data_index++) { + GLenum gl_img_target = img->gl.target; + if (SG_IMAGETYPE_CUBE == img->cmn.type) { + gl_img_target = _sg_gl_cubeface_target(face_index); } - if (is_compressed) { - const GLsizei data_size = (GLsizei) desc->data.subimage[face_index][mip_index].size; - glCompressedTexImage3D(gl_img_target, mip_index, gl_internal_format, - mip_width, mip_height, mip_depth, 0, data_size, data_ptr); - } else { - const GLenum gl_type = _sg_gl_teximage_type(img->cmn.pixel_format); - glTexImage3D(gl_img_target, mip_index, (GLint)gl_internal_format, - mip_width, mip_height, mip_depth, 0, gl_format, gl_type, data_ptr); + const GLvoid* data_ptr = desc->data.subimage[face_index][mip_index].ptr; + const int mip_width = _sg_miplevel_dim(img->cmn.width, mip_index); + const int mip_height = _sg_miplevel_dim(img->cmn.height, mip_index); + if ((SG_IMAGETYPE_2D == img->cmn.type) || (SG_IMAGETYPE_CUBE == img->cmn.type)) { + if (is_compressed) { + const GLsizei data_size = (GLsizei) desc->data.subimage[face_index][mip_index].size; + glCompressedTexImage2D(gl_img_target, mip_index, gl_internal_format, + mip_width, mip_height, 0, data_size, data_ptr); + } else { + const GLenum gl_type = _sg_gl_teximage_type(img->cmn.pixel_format); + glTexImage2D(gl_img_target, mip_index, (GLint)gl_internal_format, + mip_width, mip_height, 0, gl_format, gl_type, data_ptr); + } + } else if ((SG_IMAGETYPE_3D == img->cmn.type) || (SG_IMAGETYPE_ARRAY == img->cmn.type)) { + int mip_depth = img->cmn.num_slices; + if (SG_IMAGETYPE_3D == img->cmn.type) { + mip_depth = _sg_miplevel_dim(mip_depth, mip_index); + } + if (is_compressed) { + const GLsizei data_size = (GLsizei) desc->data.subimage[face_index][mip_index].size; + glCompressedTexImage3D(gl_img_target, mip_index, gl_internal_format, + mip_width, mip_height, mip_depth, 0, data_size, data_ptr); + } else { + const GLenum gl_type = _sg_gl_teximage_type(img->cmn.pixel_format); + glTexImage3D(gl_img_target, mip_index, (GLint)gl_internal_format, + mip_width, mip_height, mip_depth, 0, gl_format, gl_type, data_ptr); + } } } } @@ -8075,7 +8401,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_sampler(_sg_sampler_t* smp, const glSamplerParameteri(smp->gl.smp, GL_TEXTURE_WRAP_S, (GLint)_sg_gl_wrap(smp->cmn.wrap_u)); glSamplerParameteri(smp->gl.smp, GL_TEXTURE_WRAP_T, (GLint)_sg_gl_wrap(smp->cmn.wrap_v)); glSamplerParameteri(smp->gl.smp, GL_TEXTURE_WRAP_R, (GLint)_sg_gl_wrap(smp->cmn.wrap_w)); - #if defined(SOKOL_GLCORE33) + #if defined(SOKOL_GLCORE) float border[4]; switch (smp->cmn.border_color) { case SG_BORDERCOLOR_TRANSPARENT_BLACK: @@ -8559,13 +8885,13 @@ _SOKOL_PRIVATE void _sg_gl_begin_pass(const sg_pass* pass) { if (atts) { // offscreen pass SOKOL_ASSERT(atts->gl.fb); - #if defined(SOKOL_GLCORE33) + #if defined(SOKOL_GLCORE) glEnable(GL_FRAMEBUFFER_SRGB); #endif glBindFramebuffer(GL_FRAMEBUFFER, atts->gl.fb); } else { // default pass - #if defined(SOKOL_GLCORE33) + #if defined(SOKOL_GLCORE) glDisable(GL_FRAMEBUFFER_SRGB); #endif // NOTE: on some platforms, the default framebuffer of a context @@ -8865,7 +9191,7 @@ _SOKOL_PRIVATE void _sg_gl_apply_pipeline(_sg_pipeline_t* pip) { if (pip->gl.color_write_mask[i] != _sg.gl.cache.color_write_mask[i]) { const sg_color_mask cm = pip->gl.color_write_mask[i]; _sg.gl.cache.color_write_mask[i] = cm; - #ifdef SOKOL_GLCORE33 + #ifdef SOKOL_GLCORE glColorMaski(i, (cm & SG_COLORMASK_R) != 0, (cm & SG_COLORMASK_G) != 0, @@ -8922,7 +9248,7 @@ _SOKOL_PRIVATE void _sg_gl_apply_pipeline(_sg_pipeline_t* pip) { } _sg_stats_add(gl.num_render_state, 1); } - #ifdef SOKOL_GLCORE33 + #ifdef SOKOL_GLCORE if (pip->gl.sample_count != _sg.gl.cache.sample_count) { _sg.gl.cache.sample_count = pip->gl.sample_count; if (pip->gl.sample_count > 1) { @@ -8978,6 +9304,18 @@ _SOKOL_PRIVATE bool _sg_gl_apply_bindings(_sg_bindings_t* bnd) { } _SG_GL_CHECK_ERROR(); + // bind storage buffers + for (int slot = 0; slot < bnd->num_vs_sbufs; slot++) { + _sg_buffer_t* sb = bnd->vs_sbufs[slot]; + GLuint gl_sb = sb->gl.buf[sb->cmn.active_slot]; + _sg_gl_cache_bind_storage_buffer(SG_SHADERSTAGE_VS, slot, gl_sb); + } + for (int slot = 0; slot < bnd->num_fs_sbufs; slot++) { + _sg_buffer_t* sb = bnd->fs_sbufs[slot]; + GLuint gl_sb = sb->gl.buf[sb->cmn.active_slot]; + _sg_gl_cache_bind_storage_buffer(SG_SHADERSTAGE_FS, slot, gl_sb); + } + // index buffer (can be 0) const GLuint gl_ib = bnd->ib ? bnd->ib->gl.buf[bnd->ib->cmn.active_slot] : 0; _sg_gl_cache_bind_buffer(GL_ELEMENT_ARRAY_BUFFER, gl_ib); @@ -9093,19 +9431,20 @@ _SOKOL_PRIVATE void _sg_gl_draw(int base_element, int num_elements, int num_inst SOKOL_ASSERT(_sg.gl.cache.cur_pipeline); const GLenum i_type = _sg.gl.cache.cur_index_type; const GLenum p_type = _sg.gl.cache.cur_primitive_type; + const bool use_instanced_draw = (num_instances > 1) || (_sg.gl.cache.cur_pipeline->cmn.use_instanced_draw); if (0 != i_type) { // indexed rendering const int i_size = (i_type == GL_UNSIGNED_SHORT) ? 2 : 4; const int ib_offset = _sg.gl.cache.cur_ib_offset; const GLvoid* indices = (const GLvoid*)(GLintptr)(base_element*i_size+ib_offset); - if (_sg.gl.cache.cur_pipeline->cmn.use_instanced_draw) { + if (use_instanced_draw) { glDrawElementsInstanced(p_type, num_elements, i_type, indices, num_instances); } else { glDrawElements(p_type, num_elements, i_type, indices); } } else { // non-indexed rendering - if (_sg.gl.cache.cur_pipeline->cmn.use_instanced_draw) { + if (use_instanced_draw) { glDrawArraysInstanced(p_type, base_element, num_elements, num_instances); } else { glDrawArrays(p_type, base_element, num_elements); @@ -9211,6 +9550,10 @@ _SOKOL_PRIVATE void _sg_gl_update_image(_sg_image_t* img, const sg_image_data* d // >>d3d11 backend #elif defined(SOKOL_D3D11) +#define _SG_D3D11_MAX_SHADERSTAGE_SRVS (32) +#define _SG_D3D11_SHADERSTAGE_IMAGE_SRV_OFFSET (0) +#define _SG_D3D11_SHADERSTAGE_BUFFER_SRV_OFFSET (16) + #if defined(__cplusplus) #define _sg_d3d11_AddRef(self) (self)->AddRef() #else @@ -9223,6 +9566,29 @@ _SOKOL_PRIVATE void _sg_gl_update_image(_sg_image_t* img, const sg_image_data* d #define _sg_d3d11_Release(self) (self)->lpVtbl->Release(self) #endif +// NOTE: This needs to be a macro since we can't use the polymorphism in C. It's called on many kinds of resources. +// NOTE: Based on microsoft docs, it's fine to call this with pData=NULL if DataSize is also zero. +#if defined(__cplusplus) +#define _sg_d3d11_SetPrivateData(self, guid, DataSize, pData) (self)->SetPrivateData(guid, DataSize, pData) +#else +#define _sg_d3d11_SetPrivateData(self, guid, DataSize, pData) (self)->lpVtbl->SetPrivateData(self, guid, DataSize, pData) +#endif + +#if defined(__cplusplus) +#define _sg_win32_refguid(guid) guid +#else +#define _sg_win32_refguid(guid) &guid +#endif + +static const GUID _sg_d3d11_WKPDID_D3DDebugObjectName = { 0x429b8c22,0x9188,0x4b0c, {0x87,0x42,0xac,0xb0,0xbf,0x85,0xc2,0x00} }; + +#if defined(SOKOL_DEBUG) +#define _sg_d3d11_setlabel(self, label) _sg_d3d11_SetPrivateData(self, _sg_win32_refguid(_sg_d3d11_WKPDID_D3DDebugObjectName), label ? (UINT)strlen(label) : 0, label) +#else +#define _sg_d3d11_setlabel(self, label) +#endif + + //-- D3D11 C/C++ wrappers ------------------------------------------------------ static inline HRESULT _sg_d3d11_CheckFormatSupport(ID3D11Device* self, DXGI_FORMAT Format, UINT* pFormatSupport) { #if defined(__cplusplus) @@ -9606,6 +9972,34 @@ _SOKOL_PRIVATE D3D11_USAGE _sg_d3d11_usage(sg_usage usg) { } } +_SOKOL_PRIVATE UINT _sg_d3d11_buffer_bind_flags(sg_buffer_type t) { + switch (t) { + case SG_BUFFERTYPE_VERTEXBUFFER: + return D3D11_BIND_VERTEX_BUFFER; + case SG_BUFFERTYPE_INDEXBUFFER: + return D3D11_BIND_INDEX_BUFFER; + case SG_BUFFERTYPE_STORAGEBUFFER: + // FIXME: for compute shaders we'd want UNORDERED_ACCESS? + return D3D11_BIND_SHADER_RESOURCE; + default: + SOKOL_UNREACHABLE; + return 0; + } +} + +_SOKOL_PRIVATE UINT _sg_d3d11_buffer_misc_flags(sg_buffer_type t) { + switch (t) { + case SG_BUFFERTYPE_VERTEXBUFFER: + case SG_BUFFERTYPE_INDEXBUFFER: + return 0; + case SG_BUFFERTYPE_STORAGEBUFFER: + return D3D11_RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS; + default: + SOKOL_UNREACHABLE; + return 0; + } +} + _SOKOL_PRIVATE UINT _sg_d3d11_cpu_access_flags(sg_usage usg) { switch (usg) { case SG_USAGE_IMMUTABLE: @@ -9914,6 +10308,7 @@ _SOKOL_PRIVATE void _sg_d3d11_init_caps(void) { _sg.features.image_clamp_to_border = true; _sg.features.mrt_independent_blend_state = true; _sg.features.mrt_independent_write_mask = true; + _sg.features.storage_buffer = true; _sg.limits.max_image_size_2d = 16 * 1024; _sg.limits.max_image_size_cube = 16 * 1024; @@ -9972,13 +10367,15 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_buffer(_sg_buffer_t* buf, cons if (injected) { buf->d3d11.buf = (ID3D11Buffer*) desc->d3d11_buffer; _sg_d3d11_AddRef(buf->d3d11.buf); + // FIXME: for storage buffers also need to inject resource view } else { - D3D11_BUFFER_DESC d3d11_desc; - _sg_clear(&d3d11_desc, sizeof(d3d11_desc)); - d3d11_desc.ByteWidth = (UINT)buf->cmn.size; - d3d11_desc.Usage = _sg_d3d11_usage(buf->cmn.usage); - d3d11_desc.BindFlags = buf->cmn.type == SG_BUFFERTYPE_VERTEXBUFFER ? D3D11_BIND_VERTEX_BUFFER : D3D11_BIND_INDEX_BUFFER; - d3d11_desc.CPUAccessFlags = _sg_d3d11_cpu_access_flags(buf->cmn.usage); + D3D11_BUFFER_DESC d3d11_buf_desc; + _sg_clear(&d3d11_buf_desc, sizeof(d3d11_buf_desc)); + d3d11_buf_desc.ByteWidth = (UINT)buf->cmn.size; + d3d11_buf_desc.Usage = _sg_d3d11_usage(buf->cmn.usage); + d3d11_buf_desc.BindFlags = _sg_d3d11_buffer_bind_flags(buf->cmn.type); + d3d11_buf_desc.CPUAccessFlags = _sg_d3d11_cpu_access_flags(buf->cmn.usage); + d3d11_buf_desc.MiscFlags = _sg_d3d11_buffer_misc_flags(buf->cmn.type); D3D11_SUBRESOURCE_DATA* init_data_ptr = 0; D3D11_SUBRESOURCE_DATA init_data; _sg_clear(&init_data, sizeof(init_data)); @@ -9987,11 +10384,31 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_buffer(_sg_buffer_t* buf, cons init_data.pSysMem = desc->data.ptr; init_data_ptr = &init_data; } - HRESULT hr = _sg_d3d11_CreateBuffer(_sg.d3d11.dev, &d3d11_desc, init_data_ptr, &buf->d3d11.buf); + HRESULT hr = _sg_d3d11_CreateBuffer(_sg.d3d11.dev, &d3d11_buf_desc, init_data_ptr, &buf->d3d11.buf); if (!(SUCCEEDED(hr) && buf->d3d11.buf)) { _SG_ERROR(D3D11_CREATE_BUFFER_FAILED); return SG_RESOURCESTATE_FAILED; } + + // for storage buffers need to create a view object + if (buf->cmn.type == SG_BUFFERTYPE_STORAGEBUFFER) { + // FIXME: currently only shader-resource-view, in future also UAV + // storage buffer size must be multiple of 4 + SOKOL_ASSERT(_sg_multiple_u64(buf->cmn.size, 4)); + D3D11_SHADER_RESOURCE_VIEW_DESC d3d11_srv_desc; + _sg_clear(&d3d11_srv_desc, sizeof(d3d11_srv_desc)); + d3d11_srv_desc.Format = DXGI_FORMAT_R32_TYPELESS; + d3d11_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX; + d3d11_srv_desc.BufferEx.FirstElement = 0; + d3d11_srv_desc.BufferEx.NumElements = buf->cmn.size / 4; + d3d11_srv_desc.BufferEx.Flags = D3D11_BUFFEREX_SRV_FLAG_RAW; + hr = _sg_d3d11_CreateShaderResourceView(_sg.d3d11.dev, (ID3D11Resource*)buf->d3d11.buf, &d3d11_srv_desc, &buf->d3d11.srv); + if (!(SUCCEEDED(hr) && buf->d3d11.srv)) { + _SG_ERROR(D3D11_CREATE_BUFFER_SRV_FAILED); + return SG_RESOURCESTATE_FAILED; + } + } + _sg_d3d11_setlabel(buf->d3d11.buf, desc->label); } return SG_RESOURCESTATE_VALID; } @@ -10001,6 +10418,9 @@ _SOKOL_PRIVATE void _sg_d3d11_discard_buffer(_sg_buffer_t* buf) { if (buf->d3d11.buf) { _sg_d3d11_Release(buf->d3d11.buf); } + if (buf->d3d11.srv) { + _sg_d3d11_Release(buf->d3d11.srv); + } } _SOKOL_PRIVATE void _sg_d3d11_fill_subres_data(const _sg_image_t* img, const sg_image_data* data) { @@ -10098,6 +10518,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const _SG_ERROR(D3D11_CREATE_2D_TEXTURE_FAILED); return SG_RESOURCESTATE_FAILED; } + _sg_d3d11_setlabel(img->d3d11.tex2d, desc->label); // create shader-resource-view for 2D texture // FIXME: currently we don't support setting MSAA texture as shader resource @@ -10127,6 +10548,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const _SG_ERROR(D3D11_CREATE_2D_SRV_FAILED); return SG_RESOURCESTATE_FAILED; } + _sg_d3d11_setlabel(img->d3d11.srv, desc->label); } } SOKOL_ASSERT(img->d3d11.tex2d); @@ -10168,6 +10590,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const _SG_ERROR(D3D11_CREATE_3D_TEXTURE_FAILED); return SG_RESOURCESTATE_FAILED; } + _sg_d3d11_setlabel(img->d3d11.tex3d, desc->label); // create shader-resource-view for 3D texture if (!msaa) { @@ -10181,6 +10604,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const _SG_ERROR(D3D11_CREATE_3D_SRV_FAILED); return SG_RESOURCESTATE_FAILED; } + _sg_d3d11_setlabel(img->d3d11.srv, desc->label); } } SOKOL_ASSERT(img->d3d11.tex3d); @@ -10244,6 +10668,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_sampler(_sg_sampler_t* smp, co _SG_ERROR(D3D11_CREATE_SAMPLER_STATE_FAILED); return SG_RESOURCESTATE_FAILED; } + _sg_d3d11_setlabel(smp->d3d11.smp, desc->label); } return SG_RESOURCESTATE_VALID; } @@ -10338,6 +10763,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_shader(_sg_shader_t* shd, cons _SG_ERROR(D3D11_CREATE_CONSTANT_BUFFER_FAILED); return SG_RESOURCESTATE_FAILED; } + _sg_d3d11_setlabel(d3d11_stage->cbufs[ub_index], desc->label); } } @@ -10376,6 +10802,8 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_shader(_sg_shader_t* shd, cons SOKOL_ASSERT(shd->d3d11.vs_blob); memcpy(shd->d3d11.vs_blob, vs_ptr, vs_length); result = SG_RESOURCESTATE_VALID; + _sg_d3d11_setlabel(shd->d3d11.vs, desc->label); + _sg_d3d11_setlabel(shd->d3d11.fs, desc->label); } } if (vs_blob) { @@ -10457,15 +10885,18 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pipeline(_sg_pipeline_t* pip, pip->d3d11.vb_strides[layout_index] = 0; } } - hr = _sg_d3d11_CreateInputLayout(_sg.d3d11.dev, - d3d11_comps, // pInputElementDesc - (UINT)attr_index, // NumElements - shd->d3d11.vs_blob, // pShaderByteCodeWithInputSignature - shd->d3d11.vs_blob_length, // BytecodeLength - &pip->d3d11.il); - if (!(SUCCEEDED(hr) && pip->d3d11.il)) { - _SG_ERROR(D3D11_CREATE_INPUT_LAYOUT_FAILED); - return SG_RESOURCESTATE_FAILED; + if (attr_index > 0) { + hr = _sg_d3d11_CreateInputLayout(_sg.d3d11.dev, + d3d11_comps, // pInputElementDesc + (UINT)attr_index, // NumElements + shd->d3d11.vs_blob, // pShaderByteCodeWithInputSignature + shd->d3d11.vs_blob_length, // BytecodeLength + &pip->d3d11.il); + if (!(SUCCEEDED(hr) && pip->d3d11.il)) { + _SG_ERROR(D3D11_CREATE_INPUT_LAYOUT_FAILED); + return SG_RESOURCESTATE_FAILED; + } + _sg_d3d11_setlabel(pip->d3d11.il, desc->label); } // create rasterizer state @@ -10486,6 +10917,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pipeline(_sg_pipeline_t* pip, _SG_ERROR(D3D11_CREATE_RASTERIZER_STATE_FAILED); return SG_RESOURCESTATE_FAILED; } + _sg_d3d11_setlabel(pip->d3d11.rs, desc->label); // create depth-stencil state D3D11_DEPTH_STENCIL_DESC dss_desc; @@ -10511,6 +10943,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pipeline(_sg_pipeline_t* pip, _SG_ERROR(D3D11_CREATE_DEPTH_STENCIL_STATE_FAILED); return SG_RESOURCESTATE_FAILED; } + _sg_d3d11_setlabel(pip->d3d11.dss, desc->label); // create blend state D3D11_BLEND_DESC bs_desc; @@ -10545,6 +10978,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_pipeline(_sg_pipeline_t* pip, _SG_ERROR(D3D11_CREATE_BLEND_STATE_FAILED); return SG_RESOURCESTATE_FAILED; } + _sg_d3d11_setlabel(pip->d3d11.bs, desc->label); return SG_RESOURCESTATE_VALID; } @@ -10640,6 +11074,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_attachments(_sg_attachments_t* _SG_ERROR(D3D11_CREATE_RTV_FAILED); return SG_RESOURCESTATE_FAILED; } + _sg_d3d11_setlabel(atts->d3d11.colors[i].view.rtv, desc->label); } SOKOL_ASSERT(0 == atts->d3d11.depth_stencil.view.dsv); if (ds_desc->image.id != SG_INVALID_ID) { @@ -10674,6 +11109,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_attachments(_sg_attachments_t* _SG_ERROR(D3D11_CREATE_DSV_FAILED); return SG_RESOURCESTATE_FAILED; } + _sg_d3d11_setlabel(atts->d3d11.depth_stencil.view.dsv, desc->label); } return SG_RESOURCESTATE_VALID; } @@ -10756,7 +11192,7 @@ _SOKOL_PRIVATE void _sg_d3d11_begin_pass(const sg_pass* pass) { // perform clear action for (int i = 0; i < num_rtvs; i++) { if (action->colors[i].load_action == SG_LOADACTION_CLEAR) { - _sg_d3d11_ClearRenderTargetView(_sg.d3d11.ctx, rtvs[i], &action->colors[i].clear_value.r); + _sg_d3d11_ClearRenderTargetView(_sg.d3d11.ctx, rtvs[i], (float*)&action->colors[i].clear_value); _sg_stats_add(d3d11.pass.num_clear_render_target_view, 1); } } @@ -10864,7 +11300,7 @@ _SOKOL_PRIVATE void _sg_d3d11_apply_pipeline(_sg_pipeline_t* pip) { SOKOL_ASSERT(pip); SOKOL_ASSERT(pip->shader && (pip->cmn.shader_id.id == pip->shader->slot.id)); SOKOL_ASSERT(_sg.d3d11.ctx); - SOKOL_ASSERT(pip->d3d11.rs && pip->d3d11.bs && pip->d3d11.dss && pip->d3d11.il); + SOKOL_ASSERT(pip->d3d11.rs && pip->d3d11.bs && pip->d3d11.dss); _sg.d3d11.cur_pipeline = pip; _sg.d3d11.cur_pipeline_id.id = pip->slot.id; @@ -10873,7 +11309,7 @@ _SOKOL_PRIVATE void _sg_d3d11_apply_pipeline(_sg_pipeline_t* pip) { _sg_d3d11_RSSetState(_sg.d3d11.ctx, pip->d3d11.rs); _sg_d3d11_OMSetDepthStencilState(_sg.d3d11.ctx, pip->d3d11.dss, pip->d3d11.stencil_ref); - _sg_d3d11_OMSetBlendState(_sg.d3d11.ctx, pip->d3d11.bs, &pip->cmn.blend_color.r, 0xFFFFFFFF); + _sg_d3d11_OMSetBlendState(_sg.d3d11.ctx, pip->d3d11.bs, (float*)&pip->cmn.blend_color, 0xFFFFFFFF); _sg_d3d11_IASetPrimitiveTopology(_sg.d3d11.ctx, pip->d3d11.topology); _sg_d3d11_IASetInputLayout(_sg.d3d11.ctx, pip->d3d11.il); _sg_d3d11_VSSetShader(_sg.d3d11.ctx, pip->shader->d3d11.vs, NULL, 0); @@ -10900,8 +11336,8 @@ _SOKOL_PRIVATE bool _sg_d3d11_apply_bindings(_sg_bindings_t* bnd) { ID3D11Buffer* d3d11_ib = bnd->ib ? bnd->ib->d3d11.buf : 0; ID3D11Buffer* d3d11_vbs[SG_MAX_VERTEX_BUFFERS] = {0}; UINT d3d11_vb_offsets[SG_MAX_VERTEX_BUFFERS] = {0}; - ID3D11ShaderResourceView* d3d11_vs_srvs[SG_MAX_SHADERSTAGE_IMAGES] = {0}; - ID3D11ShaderResourceView* d3d11_fs_srvs[SG_MAX_SHADERSTAGE_IMAGES] = {0}; + ID3D11ShaderResourceView* d3d11_vs_srvs[_SG_D3D11_MAX_SHADERSTAGE_SRVS] = {0}; + ID3D11ShaderResourceView* d3d11_fs_srvs[_SG_D3D11_MAX_SHADERSTAGE_SRVS] = {0}; ID3D11SamplerState* d3d11_vs_smps[SG_MAX_SHADERSTAGE_SAMPLERS] = {0}; ID3D11SamplerState* d3d11_fs_smps[SG_MAX_SHADERSTAGE_SAMPLERS] = {0}; for (int i = 0; i < bnd->num_vbs; i++) { @@ -10911,11 +11347,19 @@ _SOKOL_PRIVATE bool _sg_d3d11_apply_bindings(_sg_bindings_t* bnd) { } for (int i = 0; i < bnd->num_vs_imgs; i++) { SOKOL_ASSERT(bnd->vs_imgs[i]->d3d11.srv); - d3d11_vs_srvs[i] = bnd->vs_imgs[i]->d3d11.srv; + d3d11_vs_srvs[_SG_D3D11_SHADERSTAGE_IMAGE_SRV_OFFSET + i] = bnd->vs_imgs[i]->d3d11.srv; + } + for (int i = 0; i < bnd->num_vs_sbufs; i++) { + SOKOL_ASSERT(bnd->vs_sbufs[i]->d3d11.srv); + d3d11_vs_srvs[_SG_D3D11_SHADERSTAGE_BUFFER_SRV_OFFSET + i] = bnd->vs_sbufs[i]->d3d11.srv; } for (int i = 0; i < bnd->num_fs_imgs; i++) { SOKOL_ASSERT(bnd->fs_imgs[i]->d3d11.srv); - d3d11_fs_srvs[i] = bnd->fs_imgs[i]->d3d11.srv; + d3d11_fs_srvs[_SG_D3D11_SHADERSTAGE_IMAGE_SRV_OFFSET + i] = bnd->fs_imgs[i]->d3d11.srv; + } + for (int i = 0; i < bnd->num_fs_sbufs; i++) { + SOKOL_ASSERT(bnd->fs_sbufs[i]->d3d11.srv); + d3d11_fs_srvs[_SG_D3D11_SHADERSTAGE_BUFFER_SRV_OFFSET + i] = bnd->fs_sbufs[i]->d3d11.srv; } for (int i = 0; i < bnd->num_vs_smps; i++) { SOKOL_ASSERT(bnd->vs_smps[i]->d3d11.smp); @@ -10927,8 +11371,8 @@ _SOKOL_PRIVATE bool _sg_d3d11_apply_bindings(_sg_bindings_t* bnd) { } _sg_d3d11_IASetVertexBuffers(_sg.d3d11.ctx, 0, SG_MAX_VERTEX_BUFFERS, d3d11_vbs, bnd->pip->d3d11.vb_strides, d3d11_vb_offsets); _sg_d3d11_IASetIndexBuffer(_sg.d3d11.ctx, d3d11_ib, bnd->pip->d3d11.index_format, (UINT)bnd->ib_offset); - _sg_d3d11_VSSetShaderResources(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_IMAGES, d3d11_vs_srvs); - _sg_d3d11_PSSetShaderResources(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_IMAGES, d3d11_fs_srvs); + _sg_d3d11_VSSetShaderResources(_sg.d3d11.ctx, 0, _SG_D3D11_MAX_SHADERSTAGE_SRVS, d3d11_vs_srvs); + _sg_d3d11_PSSetShaderResources(_sg.d3d11.ctx, 0, _SG_D3D11_MAX_SHADERSTAGE_SRVS, d3d11_fs_srvs); _sg_d3d11_VSSetSamplers(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_SAMPLERS, d3d11_vs_smps); _sg_d3d11_PSSetSamplers(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_SAMPLERS, d3d11_fs_smps); _sg_stats_add(d3d11.bindings.num_ia_set_vertex_buffers, 1); @@ -10953,8 +11397,9 @@ _SOKOL_PRIVATE void _sg_d3d11_apply_uniforms(sg_shader_stage stage_index, int ub } _SOKOL_PRIVATE void _sg_d3d11_draw(int base_element, int num_elements, int num_instances) { + const bool use_instanced_draw = (num_instances > 1) || (_sg.d3d11.use_instanced_draw); if (_sg.d3d11.use_indexed_draw) { - if (_sg.d3d11.use_instanced_draw) { + if (use_instanced_draw) { _sg_d3d11_DrawIndexedInstanced(_sg.d3d11.ctx, (UINT)num_elements, (UINT)num_instances, (UINT)base_element, 0, 0); _sg_stats_add(d3d11.draw.num_draw_indexed_instanced, 1); } else { @@ -10962,7 +11407,7 @@ _SOKOL_PRIVATE void _sg_d3d11_draw(int base_element, int num_elements, int num_i _sg_stats_add(d3d11.draw.num_draw_indexed, 1); } } else { - if (_sg.d3d11.use_instanced_draw) { + if (use_instanced_draw) { _sg_d3d11_DrawInstanced(_sg.d3d11.ctx, (UINT)num_elements, (UINT)num_instances, (UINT)base_element, 0); _sg_stats_add(d3d11.draw.num_draw_instanced, 1); } else { @@ -11010,12 +11455,15 @@ _SOKOL_PRIVATE void _sg_d3d11_append_buffer(_sg_buffer_t* buf, const sg_range* d } } +// see: https://learn.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-resources-subresources +// also see: https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-d3d11calcsubresource _SOKOL_PRIVATE void _sg_d3d11_update_image(_sg_image_t* img, const sg_image_data* data) { SOKOL_ASSERT(img && data); SOKOL_ASSERT(_sg.d3d11.ctx); SOKOL_ASSERT(img->d3d11.res); const int num_faces = (img->cmn.type == SG_IMAGETYPE_CUBE) ? 6:1; const int num_slices = (img->cmn.type == SG_IMAGETYPE_ARRAY) ? img->cmn.num_slices:1; + const int num_depth_slices = (img->cmn.type == SG_IMAGETYPE_3D) ? img->cmn.num_slices:1; UINT subres_index = 0; HRESULT hr; D3D11_MAPPED_SUBRESOURCE d3d11_msr; @@ -11025,26 +11473,35 @@ _SOKOL_PRIVATE void _sg_d3d11_update_image(_sg_image_t* img, const sg_image_data SOKOL_ASSERT(subres_index < (SG_MAX_MIPMAPS * SG_MAX_TEXTUREARRAY_LAYERS)); const int mip_width = _sg_miplevel_dim(img->cmn.width, mip_index); const int mip_height = _sg_miplevel_dim(img->cmn.height, mip_index); - const int src_pitch = _sg_row_pitch(img->cmn.pixel_format, mip_width, 1); + const int src_row_pitch = _sg_row_pitch(img->cmn.pixel_format, mip_width, 1); + const int src_depth_pitch = _sg_surface_pitch(img->cmn.pixel_format, mip_width, mip_height, 1); const sg_range* subimg_data = &(data->subimage[face_index][mip_index]); const size_t slice_size = subimg_data->size / (size_t)num_slices; + SOKOL_ASSERT(slice_size == (size_t)(src_depth_pitch * num_depth_slices)); const size_t slice_offset = slice_size * (size_t)slice_index; const uint8_t* slice_ptr = ((const uint8_t*)subimg_data->ptr) + slice_offset; hr = _sg_d3d11_Map(_sg.d3d11.ctx, img->d3d11.res, subres_index, D3D11_MAP_WRITE_DISCARD, 0, &d3d11_msr); _sg_stats_add(d3d11.num_map, 1); if (SUCCEEDED(hr)) { - // FIXME: need to handle difference in depth-pitch for 3D textures as well! - if (src_pitch == (int)d3d11_msr.RowPitch) { - memcpy(d3d11_msr.pData, slice_ptr, slice_size); - } else { - SOKOL_ASSERT(src_pitch < (int)d3d11_msr.RowPitch); - const uint8_t* src_ptr = slice_ptr; - uint8_t* dst_ptr = (uint8_t*) d3d11_msr.pData; - for (int row_index = 0; row_index < mip_height; row_index++) { - memcpy(dst_ptr, src_ptr, (size_t)src_pitch); - src_ptr += src_pitch; - dst_ptr += d3d11_msr.RowPitch; + const uint8_t* src_ptr = slice_ptr; + uint8_t* dst_ptr = (uint8_t*)d3d11_msr.pData; + for (int depth_index = 0; depth_index < num_depth_slices; depth_index++) { + if (src_row_pitch == (int)d3d11_msr.RowPitch) { + const size_t copy_size = slice_size / (size_t)num_depth_slices; + SOKOL_ASSERT((copy_size * (size_t)num_depth_slices) == slice_size); + memcpy(dst_ptr, src_ptr, copy_size); + } else { + SOKOL_ASSERT(src_row_pitch < (int)d3d11_msr.RowPitch); + const uint8_t* src_row_ptr = src_ptr; + uint8_t* dst_row_ptr = dst_ptr; + for (int row_index = 0; row_index < mip_height; row_index++) { + memcpy(dst_row_ptr, src_row_ptr, (size_t)src_row_pitch); + src_row_ptr += src_row_pitch; + dst_row_ptr += d3d11_msr.RowPitch; + } } + src_ptr += src_depth_pitch; + dst_ptr += d3d11_msr.DepthPitch; } _sg_d3d11_Unmap(_sg.d3d11.ctx, img->d3d11.res, subres_index); _sg_stats_add(d3d11.num_unmap, 1); @@ -11239,8 +11696,10 @@ _SOKOL_PRIVATE MTLPixelFormat _sg_mtl_pixel_format(sg_pixel_format fmt) { case SG_PIXELFORMAT_ETC2_RGB8A1: return MTLPixelFormatETC2_RGB8A1; case SG_PIXELFORMAT_ETC2_RGBA8: return MTLPixelFormatEAC_RGBA8; case SG_PIXELFORMAT_ETC2_SRGB8A8: return MTLPixelFormatEAC_RGBA8_sRGB; - case SG_PIXELFORMAT_ETC2_RG11: return MTLPixelFormatEAC_RG11Unorm; - case SG_PIXELFORMAT_ETC2_RG11SN: return MTLPixelFormatEAC_RG11Snorm; + case SG_PIXELFORMAT_EAC_R11: return MTLPixelFormatEAC_R11Unorm; + case SG_PIXELFORMAT_EAC_R11SN: return MTLPixelFormatEAC_R11Snorm; + case SG_PIXELFORMAT_EAC_RG11: return MTLPixelFormatEAC_RG11Unorm; + case SG_PIXELFORMAT_EAC_RG11SN: return MTLPixelFormatEAC_RG11Snorm; case SG_PIXELFORMAT_ASTC_4x4_RGBA: return MTLPixelFormatASTC_4x4_LDR; case SG_PIXELFORMAT_ASTC_4x4_SRGBA: return MTLPixelFormatASTC_4x4_sRGB; #endif @@ -11580,6 +12039,7 @@ _SOKOL_PRIVATE void _sg_mtl_init_caps(void) { _sg.features.origin_top_left = true; _sg.features.mrt_independent_blend_state = true; _sg.features.mrt_independent_write_mask = true; + _sg.features.storage_buffer = true; _sg.features.image_clamp_to_border = false; #if (MAC_OS_X_VERSION_MAX_ALLOWED >= 120000) || (__IPHONE_OS_VERSION_MAX_ALLOWED >= 140000) @@ -11713,8 +12173,10 @@ _SOKOL_PRIVATE void _sg_mtl_init_caps(void) { _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGB8A1]); _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGBA8]); _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_SRGB8A8]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RG11]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RG11SN]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_R11]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_R11SN]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_RG11]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_RG11SN]); _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ASTC_4x4_RGBA]); _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ASTC_4x4_SRGBA]); @@ -12684,7 +13146,7 @@ _SOKOL_PRIVATE bool _sg_mtl_apply_bindings(_sg_bindings_t* bnd) { } } - // apply vertex shader images + // apply vertex stage images for (NSUInteger slot = 0; slot < (NSUInteger)bnd->num_vs_imgs; slot++) { const _sg_image_t* img = bnd->vs_imgs[slot]; if (_sg.mtl.state_cache.cur_vs_image_ids[slot].id != img->slot.id) { @@ -12695,7 +13157,7 @@ _SOKOL_PRIVATE bool _sg_mtl_apply_bindings(_sg_bindings_t* bnd) { } } - // apply vertex shader samplers + // apply vertex stage samplers for (NSUInteger slot = 0; slot < (NSUInteger)bnd->num_vs_smps; slot++) { const _sg_sampler_t* smp = bnd->vs_smps[slot]; if (_sg.mtl.state_cache.cur_vs_sampler_ids[slot].id != smp->slot.id) { @@ -12706,7 +13168,19 @@ _SOKOL_PRIVATE bool _sg_mtl_apply_bindings(_sg_bindings_t* bnd) { } } - // apply fragment shader images + // apply vertex stage storage buffers + for (NSUInteger slot = 0; slot < (NSUInteger)bnd->num_vs_sbufs; slot++) { + const _sg_buffer_t* sbuf = bnd->vs_sbufs[slot]; + if (_sg.mtl.state_cache.cur_vs_storagebuffer_ids[slot].id != sbuf->slot.id) { + _sg.mtl.state_cache.cur_vs_storagebuffer_ids[slot].id = sbuf->slot.id; + SOKOL_ASSERT(sbuf->mtl.buf[sbuf->cmn.active_slot] != _SG_MTL_INVALID_SLOT_INDEX); + const NSUInteger mtl_slot = SG_MAX_SHADERSTAGE_UBS + SG_MAX_VERTEX_BUFFERS + slot; + [_sg.mtl.cmd_encoder setVertexBuffer:_sg_mtl_id(sbuf->mtl.buf[sbuf->cmn.active_slot]) offset:0 atIndex:mtl_slot]; + _sg_stats_add(metal.bindings.num_set_vertex_buffer, 1); + } + } + + // apply fragment stage images for (NSUInteger slot = 0; slot < (NSUInteger)bnd->num_fs_imgs; slot++) { const _sg_image_t* img = bnd->fs_imgs[slot]; if (_sg.mtl.state_cache.cur_fs_image_ids[slot].id != img->slot.id) { @@ -12717,7 +13191,7 @@ _SOKOL_PRIVATE bool _sg_mtl_apply_bindings(_sg_bindings_t* bnd) { } } - // apply fragment shader samplers + // apply fragment stage samplers for (NSUInteger slot = 0; slot < (NSUInteger)bnd->num_fs_smps; slot++) { const _sg_sampler_t* smp = bnd->fs_smps[slot]; if (_sg.mtl.state_cache.cur_fs_sampler_ids[slot].id != smp->slot.id) { @@ -12727,6 +13201,19 @@ _SOKOL_PRIVATE bool _sg_mtl_apply_bindings(_sg_bindings_t* bnd) { _sg_stats_add(metal.bindings.num_set_fragment_sampler_state, 1); } } + + // apply fragment stage storage buffers + for (NSUInteger slot = 0; slot < (NSUInteger)bnd->num_fs_sbufs; slot++) { + const _sg_buffer_t* sbuf = bnd->fs_sbufs[slot]; + if (_sg.mtl.state_cache.cur_fs_storagebuffer_ids[slot].id != sbuf->slot.id) { + _sg.mtl.state_cache.cur_fs_storagebuffer_ids[slot].id = sbuf->slot.id; + SOKOL_ASSERT(sbuf->mtl.buf[sbuf->cmn.active_slot] != _SG_MTL_INVALID_SLOT_INDEX); + const NSUInteger mtl_slot = SG_MAX_SHADERSTAGE_UBS + slot; + [_sg.mtl.cmd_encoder setFragmentBuffer:_sg_mtl_id(sbuf->mtl.buf[sbuf->cmn.active_slot]) offset:0 atIndex:mtl_slot]; + _sg_stats_add(metal.bindings.num_set_fragment_buffer, 1); + } + } + return true; } @@ -12845,9 +13332,11 @@ _SOKOL_PRIVATE void _sg_mtl_pop_debug_group(void) { _SOKOL_PRIVATE WGPUBufferUsageFlags _sg_wgpu_buffer_usage(sg_buffer_type t, sg_usage u) { WGPUBufferUsageFlags res = 0; if (SG_BUFFERTYPE_VERTEXBUFFER == t) { - res |= WGPUBufferUsage_Vertex; + res = WGPUBufferUsage_Vertex; + } else if (SG_BUFFERTYPE_STORAGEBUFFER == t) { + res = WGPUBufferUsage_Storage; } else { - res |= WGPUBufferUsage_Index; + res = WGPUBufferUsage_Index; } if (SG_USAGE_IMMUTABLE != u) { res |= WGPUBufferUsage_CopyDst; @@ -13091,8 +13580,10 @@ _SOKOL_PRIVATE WGPUTextureFormat _sg_wgpu_textureformat(sg_pixel_format p) { case SG_PIXELFORMAT_ETC2_RGBA8: return WGPUTextureFormat_ETC2RGBA8Unorm; case SG_PIXELFORMAT_ETC2_SRGB8: return WGPUTextureFormat_ETC2RGB8UnormSrgb; case SG_PIXELFORMAT_ETC2_SRGB8A8: return WGPUTextureFormat_ETC2RGBA8UnormSrgb; - case SG_PIXELFORMAT_ETC2_RG11: return WGPUTextureFormat_EACR11Unorm; - case SG_PIXELFORMAT_ETC2_RG11SN: return WGPUTextureFormat_EACR11Snorm; + case SG_PIXELFORMAT_EAC_R11: return WGPUTextureFormat_EACR11Unorm; + case SG_PIXELFORMAT_EAC_R11SN: return WGPUTextureFormat_EACR11Snorm; + case SG_PIXELFORMAT_EAC_RG11: return WGPUTextureFormat_EACRG11Unorm; + case SG_PIXELFORMAT_EAC_RG11SN: return WGPUTextureFormat_EACRG11Snorm; case SG_PIXELFORMAT_RGB9E5: return WGPUTextureFormat_RGB9E5Ufloat; case SG_PIXELFORMAT_ASTC_4x4_RGBA: return WGPUTextureFormat_ASTC4x4Unorm; case SG_PIXELFORMAT_ASTC_4x4_SRGBA: return WGPUTextureFormat_ASTC4x4UnormSrgb; @@ -13204,15 +13695,17 @@ _SOKOL_PRIVATE WGPUColorWriteMaskFlags _sg_wgpu_colorwritemask(uint8_t m) { // - all images and sampler are in @group(1) // - vertex stage images start at @binding(0) // - vertex stage samplers start at @binding(16) -// - fragment stage images start at @binding(32) -// - fragment stage samplers start at @binding(48) +// - vertex stage storage buffers start at @binding(32) +// - fragment stage images start at @binding(48) +// - fragment stage samplers start at @binding(64) +// - fragment stage storage buffers start at @binding(80) // _SOKOL_PRIVATE uint32_t _sg_wgpu_image_binding(sg_shader_stage stage, int img_slot) { SOKOL_ASSERT((img_slot >= 0) && (img_slot < 16)); if (SG_SHADERSTAGE_VS == stage) { return 0 + (uint32_t)img_slot; } else { - return 32 + (uint32_t)img_slot; + return 48 + (uint32_t)img_slot; } } @@ -13221,7 +13714,16 @@ _SOKOL_PRIVATE uint32_t _sg_wgpu_sampler_binding(sg_shader_stage stage, int smp_ if (SG_SHADERSTAGE_VS == stage) { return 16 + (uint32_t)smp_slot; } else { - return 48 + (uint32_t)smp_slot; + return 64 + (uint32_t)smp_slot; + } +} + +_SOKOL_PRIVATE uint32_t _sg_wgpu_storagebuffer_binding(sg_shader_stage stage, int sbuf_slot) { + SOKOL_ASSERT((sbuf_slot >= 0) && (sbuf_slot < 16)); + if (SG_SHADERSTAGE_VS == stage) { + return 32 + (uint32_t)sbuf_slot; + } else { + return 80 + (uint32_t)sbuf_slot; } } @@ -13239,6 +13741,7 @@ _SOKOL_PRIVATE void _sg_wgpu_init_caps(void) { _sg.features.image_clamp_to_border = false; _sg.features.mrt_independent_blend_state = true; _sg.features.mrt_independent_write_mask = true; + _sg.features.storage_buffer = true; wgpuDeviceGetLimits(_sg.wgpu.dev, &_sg.wgpu.limits); @@ -13289,10 +13792,15 @@ _SOKOL_PRIVATE void _sg_wgpu_init_caps(void) { _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA32UI]); _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA32SI]); - // FIXME: can be made filterable with extension - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R32F]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RG32F]); - _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); + if (wgpuDeviceHasFeature(_sg.wgpu.dev, WGPUFeatureName_Float32Filterable)) { + _sg_pixelformat_sfr(&_sg.formats[SG_PIXELFORMAT_R32F]); + _sg_pixelformat_sfr(&_sg.formats[SG_PIXELFORMAT_RG32F]); + _sg_pixelformat_sfr(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); + } else { + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R32F]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RG32F]); + _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_RGBA32F]); + } _sg_pixelformat_srmd(&_sg.formats[SG_PIXELFORMAT_DEPTH]); _sg_pixelformat_srmd(&_sg.formats[SG_PIXELFORMAT_DEPTH_STENCIL]); @@ -13319,8 +13827,10 @@ _SOKOL_PRIVATE void _sg_wgpu_init_caps(void) { _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGB8A1]); _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGBA8]); _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_SRGB8A8]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RG11]); - _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RG11SN]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_R11]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_R11SN]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_RG11]); + _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_EAC_RG11SN]); } if (wgpuDeviceHasFeature(_sg.wgpu.dev, WGPUFeatureName_TextureCompressionASTC)) { @@ -13530,16 +14040,20 @@ _SOKOL_PRIVATE void _sg_wgpu_init_bindgroups_cache_key(_sg_wgpu_bindgroups_cache SOKOL_ASSERT(bnd->pip); SOKOL_ASSERT(bnd->num_vs_imgs <= SG_MAX_SHADERSTAGE_IMAGES); SOKOL_ASSERT(bnd->num_vs_smps <= SG_MAX_SHADERSTAGE_SAMPLERS); + SOKOL_ASSERT(bnd->num_vs_sbufs <= SG_MAX_SHADERSTAGE_STORAGEBUFFERS); SOKOL_ASSERT(bnd->num_fs_imgs <= SG_MAX_SHADERSTAGE_IMAGES); SOKOL_ASSERT(bnd->num_fs_smps <= SG_MAX_SHADERSTAGE_SAMPLERS); + SOKOL_ASSERT(bnd->num_fs_sbufs <= SG_MAX_SHADERSTAGE_STORAGEBUFFERS); _sg_clear(key->items, sizeof(key->items)); key->items[0] = bnd->pip->slot.id; const int vs_imgs_offset = 1; const int vs_smps_offset = vs_imgs_offset + SG_MAX_SHADERSTAGE_IMAGES; - const int fs_imgs_offset = vs_smps_offset + SG_MAX_SHADERSTAGE_SAMPLERS; + const int vs_sbufs_offset = vs_smps_offset + SG_MAX_SHADERSTAGE_SAMPLERS; + const int fs_imgs_offset = vs_sbufs_offset + SG_MAX_SHADERSTAGE_STORAGEBUFFERS; const int fs_smps_offset = fs_imgs_offset + SG_MAX_SHADERSTAGE_IMAGES; - SOKOL_ASSERT((fs_smps_offset + SG_MAX_SHADERSTAGE_SAMPLERS) == _SG_WGPU_BINDGROUPSCACHE_NUM_ITEMS); + const int fs_sbufs_offset = fs_smps_offset + SG_MAX_SHADERSTAGE_SAMPLERS; + SOKOL_ASSERT((fs_sbufs_offset + SG_MAX_SHADERSTAGE_STORAGEBUFFERS) == _SG_WGPU_BINDGROUPSCACHE_NUM_ITEMS); for (int i = 0; i < bnd->num_vs_imgs; i++) { SOKOL_ASSERT(bnd->vs_imgs[i]); key->items[vs_imgs_offset + i] = bnd->vs_imgs[i]->slot.id; @@ -13548,6 +14062,10 @@ _SOKOL_PRIVATE void _sg_wgpu_init_bindgroups_cache_key(_sg_wgpu_bindgroups_cache SOKOL_ASSERT(bnd->vs_smps[i]); key->items[vs_smps_offset + i] = bnd->vs_smps[i]->slot.id; } + for (int i = 0; i < bnd->num_vs_sbufs; i++) { + SOKOL_ASSERT(bnd->vs_sbufs[i]); + key->items[vs_sbufs_offset + i] = bnd->vs_sbufs[i]->slot.id; + } for (int i = 0; i < bnd->num_fs_imgs; i++) { SOKOL_ASSERT(bnd->fs_imgs[i]); key->items[fs_imgs_offset + i] = bnd->fs_imgs[i]->slot.id; @@ -13556,6 +14074,10 @@ _SOKOL_PRIVATE void _sg_wgpu_init_bindgroups_cache_key(_sg_wgpu_bindgroups_cache SOKOL_ASSERT(bnd->fs_smps[i]); key->items[fs_smps_offset + i] = bnd->fs_smps[i]->slot.id; } + for (int i = 0; i < bnd->num_fs_sbufs; i++) { + SOKOL_ASSERT(bnd->fs_sbufs[i]); + key->items[fs_sbufs_offset + i] = bnd->fs_sbufs[i]->slot.id; + } key->hash = _sg_wgpu_hash(&key->items, (int)sizeof(key->items), 0x1234567887654321); } @@ -13586,7 +14108,7 @@ _SOKOL_PRIVATE _sg_wgpu_bindgroup_t* _sg_wgpu_create_bindgroup(_sg_bindings_t* b // create wgpu bindgroup object WGPUBindGroupLayout bgl = bnd->pip->shader->wgpu.bind_group_layout; SOKOL_ASSERT(bgl); - WGPUBindGroupEntry wgpu_entries[SG_NUM_SHADER_STAGES * SG_MAX_SHADERSTAGE_IMAGES + SG_MAX_SHADERSTAGE_SAMPLERS]; + WGPUBindGroupEntry wgpu_entries[_SG_WGPU_MAX_BINDGROUP_ENTRIES]; _sg_clear(&wgpu_entries, sizeof(wgpu_entries)); int bge_index = 0; for (int i = 0; i < bnd->num_vs_imgs; i++) { @@ -13599,6 +14121,12 @@ _SOKOL_PRIVATE _sg_wgpu_bindgroup_t* _sg_wgpu_create_bindgroup(_sg_bindings_t* b wgpu_entry->binding = _sg_wgpu_sampler_binding(SG_SHADERSTAGE_VS, i); wgpu_entry->sampler = bnd->vs_smps[i]->wgpu.smp; } + for (int i = 0; i < bnd->num_vs_sbufs; i++) { + WGPUBindGroupEntry* wgpu_entry = &wgpu_entries[bge_index++]; + wgpu_entry->binding = _sg_wgpu_storagebuffer_binding(SG_SHADERSTAGE_VS, i); + wgpu_entry->buffer = bnd->vs_sbufs[i]->wgpu.buf; + wgpu_entry->size = (uint64_t) bnd->vs_sbufs[i]->cmn.size; + } for (int i = 0; i < bnd->num_fs_imgs; i++) { WGPUBindGroupEntry* wgpu_entry = &wgpu_entries[bge_index++]; wgpu_entry->binding = _sg_wgpu_image_binding(SG_SHADERSTAGE_FS, i); @@ -13609,6 +14137,12 @@ _SOKOL_PRIVATE _sg_wgpu_bindgroup_t* _sg_wgpu_create_bindgroup(_sg_bindings_t* b wgpu_entry->binding = _sg_wgpu_sampler_binding(SG_SHADERSTAGE_FS, i); wgpu_entry->sampler = bnd->fs_smps[i]->wgpu.smp; } + for (int i = 0; i < bnd->num_fs_sbufs; i++) { + WGPUBindGroupEntry* wgpu_entry = &wgpu_entries[bge_index++]; + wgpu_entry->binding = _sg_wgpu_storagebuffer_binding(SG_SHADERSTAGE_FS, i); + wgpu_entry->buffer = bnd->fs_sbufs[i]->wgpu.buf; + wgpu_entry->size = (uint64_t) bnd->fs_sbufs[i]->cmn.size; + } WGPUBindGroupDescriptor bg_desc; _sg_clear(&bg_desc, sizeof(bg_desc)); bg_desc.layout = bgl; @@ -13755,7 +14289,7 @@ _SOKOL_PRIVATE void _sg_wgpu_bindings_cache_bg_update(const _sg_wgpu_bindgroup_t } } -_SOKOL_PRIVATE void _sg_wgpu_set_image_sampler_bindgroup(_sg_wgpu_bindgroup_t* bg) { +_SOKOL_PRIVATE void _sg_wgpu_set_bindings_bindgroup(_sg_wgpu_bindgroup_t* bg) { if (_sg_wgpu_bindings_cache_bg_dirty(bg)) { _sg_wgpu_bindings_cache_bg_update(bg); _sg_stats_add(wgpu.bindings.num_set_bindgroup, 1); @@ -13773,7 +14307,7 @@ _SOKOL_PRIVATE void _sg_wgpu_set_image_sampler_bindgroup(_sg_wgpu_bindgroup_t* b } _SOKOL_PRIVATE bool _sg_wgpu_apply_bindgroup(_sg_bindings_t* bnd) { - if ((bnd->num_vs_imgs + bnd->num_vs_smps + bnd->num_fs_imgs + bnd->num_fs_smps) > 0) { + if ((bnd->num_vs_imgs + bnd->num_vs_smps + bnd->num_vs_sbufs + bnd->num_fs_imgs + bnd->num_fs_smps + bnd->num_fs_sbufs) > 0) { if (!_sg.desc.wgpu_disable_bindgroups_cache) { _sg_wgpu_bindgroup_t* bg = 0; _sg_wgpu_bindgroups_cache_key_t key; @@ -13801,7 +14335,7 @@ _SOKOL_PRIVATE bool _sg_wgpu_apply_bindgroup(_sg_bindings_t* bnd) { _sg_wgpu_bindgroups_cache_set(key.hash, bg->slot.id); } if (bg && bg->slot.state == SG_RESOURCESTATE_VALID) { - _sg_wgpu_set_image_sampler_bindgroup(bg); + _sg_wgpu_set_bindings_bindgroup(bg); } else { return false; } @@ -13810,7 +14344,7 @@ _SOKOL_PRIVATE bool _sg_wgpu_apply_bindgroup(_sg_bindings_t* bnd) { _sg_wgpu_bindgroup_t* bg = _sg_wgpu_create_bindgroup(bnd); if (bg) { if (bg->slot.state == SG_RESOURCESTATE_VALID) { - _sg_wgpu_set_image_sampler_bindgroup(bg); + _sg_wgpu_set_bindings_bindgroup(bg); } _sg_wgpu_discard_bindgroup(bg); } else { @@ -13818,10 +14352,11 @@ _SOKOL_PRIVATE bool _sg_wgpu_apply_bindgroup(_sg_bindings_t* bnd) { } } } else { - _sg_wgpu_set_image_sampler_bindgroup(0); + _sg_wgpu_set_bindings_bindgroup(0); } return true; } + _SOKOL_PRIVATE bool _sg_wgpu_apply_index_buffer(_sg_bindings_t* bnd) { if (_sg_wgpu_bindings_cache_ib_dirty(bnd->ib, bnd->ib_offset)) { _sg_wgpu_bindings_cache_ib_update(bnd->ib, bnd->ib_offset); @@ -14143,8 +14678,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_shader(_sg_shader_t* shd, const SOKOL_ASSERT(shd && desc); SOKOL_ASSERT(desc->vs.source && desc->fs.source); - #define _sg_wgpu_create_shader_max_bgl_entries (SG_NUM_SHADER_STAGES * (SG_MAX_SHADERSTAGE_IMAGES + SG_MAX_SHADERSTAGE_SAMPLERS)) - WGPUBindGroupLayoutEntry wgpu_bgl_entries[_sg_wgpu_create_shader_max_bgl_entries]; + WGPUBindGroupLayoutEntry wgpu_bgl_entries[_SG_WGPU_MAX_BINDGROUP_ENTRIES]; _sg_clear(wgpu_bgl_entries, sizeof(wgpu_bgl_entries)); int bgl_index = 0; for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { @@ -14180,8 +14714,13 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_shader(_sg_shader_t* shd, const _SG_ERROR(WGPU_SHADER_TOO_MANY_SAMPLERS); return SG_RESOURCESTATE_FAILED; } + const int num_sbufs = cmn_stage->num_storage_buffers; + if (num_sbufs > (int)_sg.wgpu.limits.limits.maxStorageBuffersPerShaderStage) { + _SG_ERROR(WGPU_SHADER_TOO_MANY_STORAGEBUFFERS); + return SG_RESOURCESTATE_FAILED; + } for (int img_index = 0; img_index < num_images; img_index++) { - SOKOL_ASSERT(bgl_index < _sg_wgpu_create_shader_max_bgl_entries); + SOKOL_ASSERT(bgl_index < _SG_WGPU_MAX_BINDGROUP_ENTRIES); WGPUBindGroupLayoutEntry* wgpu_bgl_entry = &wgpu_bgl_entries[bgl_index++]; const sg_shader_image_desc* img_desc = &stage_desc->images[img_index]; wgpu_bgl_entry->binding = _sg_wgpu_image_binding((sg_shader_stage)stage_index, img_index); @@ -14191,13 +14730,21 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_shader(_sg_shader_t* shd, const wgpu_bgl_entry->texture.multisampled = img_desc->multisampled; } for (int smp_index = 0; smp_index < num_samplers; smp_index++) { - SOKOL_ASSERT(bgl_index < _sg_wgpu_create_shader_max_bgl_entries); + SOKOL_ASSERT(bgl_index < _SG_WGPU_MAX_BINDGROUP_ENTRIES); WGPUBindGroupLayoutEntry* wgpu_bgl_entry = &wgpu_bgl_entries[bgl_index++]; const sg_shader_sampler_desc* smp_desc = &stage_desc->samplers[smp_index]; - wgpu_bgl_entry->binding =_sg_wgpu_sampler_binding((sg_shader_stage)stage_index, smp_index); + wgpu_bgl_entry->binding = _sg_wgpu_sampler_binding((sg_shader_stage)stage_index, smp_index); wgpu_bgl_entry->visibility = _sg_wgpu_shader_stage((sg_shader_stage)stage_index); wgpu_bgl_entry->sampler.type = _sg_wgpu_sampler_binding_type(smp_desc->sampler_type); } + for (int sbuf_index = 0; sbuf_index < num_sbufs; sbuf_index++) { + SOKOL_ASSERT(bgl_index < _SG_WGPU_MAX_BINDGROUP_ENTRIES); + WGPUBindGroupLayoutEntry* wgpu_bgl_entry = &wgpu_bgl_entries[bgl_index++]; + const sg_shader_storage_buffer_desc* sbuf_desc = &stage_desc->storage_buffers[sbuf_index]; + wgpu_bgl_entry->binding = _sg_wgpu_storagebuffer_binding((sg_shader_stage)stage_index, sbuf_index); + wgpu_bgl_entry->visibility = _sg_wgpu_shader_stage((sg_shader_stage)stage_index); + wgpu_bgl_entry->buffer.type = sbuf_desc->readonly ? WGPUBufferBindingType_ReadOnlyStorage : WGPUBufferBindingType_Storage; + } } WGPUBindGroupLayoutDescriptor wgpu_bgl_desc; @@ -14209,8 +14756,6 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_shader(_sg_shader_t* shd, const _SG_ERROR(WGPU_SHADER_CREATE_BINDGROUP_LAYOUT_FAILED); return SG_RESOURCESTATE_FAILED; } - - #undef _sg_wgpu_create_shader_max_bgl_entries return SG_RESOURCESTATE_VALID; } @@ -15588,6 +16133,10 @@ _SOKOL_PRIVATE bool _sg_validate_buffer_desc(const sg_buffer_desc* desc) { } else { _SG_VALIDATE(0 == desc->data.ptr, VALIDATE_BUFFERDESC_NO_DATA); } + if (desc->type == SG_BUFFERTYPE_STORAGEBUFFER) { + _SG_VALIDATE(_sg.features.storage_buffer, VALIDATE_BUFFERDESC_STORAGEBUFFER_SUPPORTED); + _SG_VALIDATE(_sg_multiple_u64(desc->size, 4), VALIDATE_BUFFERDESC_STORAGEBUFFER_SIZE_MULTIPLE_4); + } return _sg_validate_end(); #endif } @@ -15725,10 +16274,7 @@ _SOKOL_PRIVATE bool _sg_validate_shader_desc(const sg_shader_desc* desc) { _sg_validate_begin(); _SG_VALIDATE(desc->_start_canary == 0, VALIDATE_SHADERDESC_CANARY); _SG_VALIDATE(desc->_end_canary == 0, VALIDATE_SHADERDESC_CANARY); - #if defined(SOKOL_D3D11) - _SG_VALIDATE(0 != desc->attrs[0].sem_name, VALIDATE_SHADERDESC_ATTR_SEMANTICS); - #endif - #if defined(SOKOL_GLCORE33) || defined(SOKOL_GLES3) || defined(SOKOL_WGPU) + #if defined(SOKOL_GLCORE) || defined(SOKOL_GLES3) || defined(SOKOL_WGPU) // on GL or WebGPU, must provide shader source code _SG_VALIDATE(0 != desc->vs.source, VALIDATE_SHADERDESC_SOURCE); _SG_VALIDATE(0 != desc->fs.source, VALIDATE_SHADERDESC_SOURCE); @@ -15799,6 +16345,16 @@ _SOKOL_PRIVATE bool _sg_validate_shader_desc(const sg_shader_desc* desc) { uniform_blocks_continuous = false; } } + bool storage_buffers_continuous = true; + for (int sbuf_index = 0; sbuf_index < SG_MAX_SHADERSTAGE_STORAGEBUFFERS; sbuf_index++) { + const sg_shader_storage_buffer_desc* sbuf_desc = &stage_desc->storage_buffers[sbuf_index]; + if (sbuf_desc->used) { + _SG_VALIDATE(storage_buffers_continuous, VALIDATE_SHADERDESC_NO_CONT_STORAGEBUFFERS); + _SG_VALIDATE(sbuf_desc->readonly, VALIDATE_SHADERDESC_STORAGEBUFFER_READONLY); + } else { + storage_buffers_continuous = false; + } + } bool images_continuous = true; int num_images = 0; for (int img_index = 0; img_index < SG_MAX_SHADERSTAGE_IMAGES; img_index++) { @@ -15893,7 +16449,6 @@ _SOKOL_PRIVATE bool _sg_validate_pipeline_desc(const sg_pipeline_desc* desc) { } _SG_VALIDATE(_sg_multiple_u64((uint64_t)l_state->stride, 4), VALIDATE_PIPELINEDESC_LAYOUT_STRIDE4); } - _SG_VALIDATE(desc->layout.attrs[0].format != SG_VERTEXFORMAT_INVALID, VALIDATE_PIPELINEDESC_NO_ATTRS); const _sg_shader_t* shd = _sg_lookup_shader(&_sg.pools, desc->shader.id); _SG_VALIDATE(0 != shd, VALIDATE_PIPELINEDESC_SHADER); if (shd) { @@ -15905,7 +16460,7 @@ _SOKOL_PRIVATE bool _sg_validate_pipeline_desc(const sg_pipeline_desc* desc) { attrs_cont = false; continue; } - _SG_VALIDATE(attrs_cont, VALIDATE_PIPELINEDESC_NO_ATTRS); + _SG_VALIDATE(attrs_cont, VALIDATE_PIPELINEDESC_NO_CONT_ATTRS); SOKOL_ASSERT(a_state->buffer_index < SG_MAX_VERTEX_BUFFERS); #if defined(SOKOL_D3D11) // on D3D11, semantic names (and semantic indices) must be provided @@ -16292,6 +16847,23 @@ _SOKOL_PRIVATE bool _sg_validate_apply_bindings(const sg_bindings* bindings) { } } + // has expected vertex shader storage buffers + for (int i = 0; i < SG_MAX_SHADERSTAGE_STORAGEBUFFERS; i++) { + const _sg_shader_stage_t* stage = &pip->shader->cmn.stage[SG_SHADERSTAGE_VS]; + if (stage->storage_buffers[i].used) { + _SG_VALIDATE(bindings->vs.storage_buffers[i].id != SG_INVALID_ID, VALIDATE_ABND_VS_EXPECTED_STORAGEBUFFER_BINDING); + if (bindings->vs.storage_buffers[i].id != SG_INVALID_ID) { + const _sg_buffer_t* sbuf = _sg_lookup_buffer(&_sg.pools, bindings->vs.storage_buffers[i].id); + _SG_VALIDATE(sbuf != 0, VALIDATE_ABND_VS_STORAGEBUFFER_EXISTS); + if (sbuf) { + _SG_VALIDATE(sbuf->cmn.type == SG_BUFFERTYPE_STORAGEBUFFER, VALIDATE_ABND_VS_STORAGEBUFFER_BINDING_BUFFERTYPE); + } + } + } else { + _SG_VALIDATE(bindings->vs.storage_buffers[i].id == SG_INVALID_ID, VALIDATE_ABND_VS_UNEXPECTED_STORAGEBUFFER_BINDING); + } + } + // has expected fragment shader images for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGES; i++) { const _sg_shader_stage_t* stage = &pip->shader->cmn.stage[SG_SHADERSTAGE_FS]; @@ -16347,6 +16919,24 @@ _SOKOL_PRIVATE bool _sg_validate_apply_bindings(const sg_bindings* bindings) { _SG_VALIDATE(bindings->fs.samplers[i].id == SG_INVALID_ID, VALIDATE_ABND_FS_UNEXPECTED_SAMPLER_BINDING); } } + + // has expected fragment shader storage buffers + for (int i = 0; i < SG_MAX_SHADERSTAGE_STORAGEBUFFERS; i++) { + const _sg_shader_stage_t* stage = &pip->shader->cmn.stage[SG_SHADERSTAGE_FS]; + if (stage->storage_buffers[i].used) { + _SG_VALIDATE(bindings->fs.storage_buffers[i].id != SG_INVALID_ID, VALIDATE_ABND_FS_EXPECTED_STORAGEBUFFER_BINDING); + if (bindings->fs.storage_buffers[i].id != SG_INVALID_ID) { + const _sg_buffer_t* sbuf = _sg_lookup_buffer(&_sg.pools, bindings->fs.storage_buffers[i].id); + _SG_VALIDATE(sbuf != 0, VALIDATE_ABND_FS_STORAGEBUFFER_EXISTS); + if (sbuf) { + _SG_VALIDATE(sbuf->cmn.type == SG_BUFFERTYPE_STORAGEBUFFER, VALIDATE_ABND_FS_STORAGEBUFFER_BINDING_BUFFERTYPE); + } + } + } else { + _SG_VALIDATE(bindings->fs.storage_buffers[i].id == SG_INVALID_ID, VALIDATE_ABND_FS_UNEXPECTED_STORAGEBUFFER_BINDING); + } + } + return _sg_validate_end(); #endif } @@ -17786,7 +18376,6 @@ SOKOL_API_IMPL void sg_apply_pipeline(sg_pipeline pip_id) { SOKOL_ASSERT(_sg.valid); SOKOL_ASSERT(_sg.cur_pass.in_pass); _sg_stats_add(num_apply_pipeline, 1); - _sg.apply_bindings_called = false; if (!_sg_validate_apply_pipeline(pip_id)) { _sg.next_draw_valid = false; return; @@ -17809,7 +18398,6 @@ SOKOL_API_IMPL void sg_apply_bindings(const sg_bindings* bindings) { SOKOL_ASSERT(bindings); SOKOL_ASSERT((bindings->_start_canary == 0) && (bindings->_end_canary==0)); _sg_stats_add(num_apply_bindings, 1); - _sg.apply_bindings_called = true; if (!_sg_validate_apply_bindings(bindings)) { _sg.next_draw_valid = false; return; @@ -17877,6 +18465,19 @@ SOKOL_API_IMPL void sg_apply_bindings(const sg_bindings* bindings) { } } + for (int i = 0; i < SG_MAX_SHADERSTAGE_STORAGEBUFFERS; i++, bnd.num_vs_sbufs++) { + if (bindings->vs.storage_buffers[i].id) { + bnd.vs_sbufs[i] = _sg_lookup_buffer(&_sg.pools, bindings->vs.storage_buffers[i].id); + if (bnd.vs_sbufs[i]) { + _sg.next_draw_valid &= (SG_RESOURCESTATE_VALID == bnd.vs_sbufs[i]->slot.state); + } else { + _sg.next_draw_valid = false; + } + } else { + break; + } + } + for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGES; i++, bnd.num_fs_imgs++) { if (bindings->fs.images[i].id) { bnd.fs_imgs[i] = _sg_lookup_image(&_sg.pools, bindings->fs.images[i].id); @@ -17903,6 +18504,18 @@ SOKOL_API_IMPL void sg_apply_bindings(const sg_bindings* bindings) { } } + for (int i = 0; i < SG_MAX_SHADERSTAGE_STORAGEBUFFERS; i++, bnd.num_fs_sbufs++) { + if (bindings->fs.storage_buffers[i].id) { + bnd.fs_sbufs[i] = _sg_lookup_buffer(&_sg.pools, bindings->fs.storage_buffers[i].id); + if (bnd.fs_sbufs[i]) { + _sg.next_draw_valid &= (SG_RESOURCESTATE_VALID == bnd.fs_sbufs[i]->slot.state); + } else { + _sg.next_draw_valid = false; + } + } else { + break; + } + } if (_sg.next_draw_valid) { _sg.next_draw_valid &= _sg_apply_bindings(&bnd); _SG_TRACE_ARGS(apply_bindings, bindings); @@ -17938,20 +18551,12 @@ SOKOL_API_IMPL void sg_draw(int base_element, int num_elements, int num_instance SOKOL_ASSERT(num_elements >= 0); SOKOL_ASSERT(num_instances >= 0); _sg_stats_add(num_draw, 1); - #if defined(SOKOL_DEBUG) - if (!_sg.apply_bindings_called) { - _SG_WARN(DRAW_WITHOUT_BINDINGS); - } - #endif if (!_sg.cur_pass.valid) { return; } if (!_sg.next_draw_valid) { return; } - if (!_sg.apply_bindings_called) { - return; - } /* attempting to draw with zero elements or instances is not technically an error, but might be handled as an error in the backend API (e.g. on Metal) */ diff --git a/thirdparty/sokol/upstream_commit b/thirdparty/sokol/upstream_commit index dce6e59..d579025 100644 --- a/thirdparty/sokol/upstream_commit +++ b/thirdparty/sokol/upstream_commit @@ -1 +1 @@ -058a4c5d +c0e0563 diff --git a/thirdparty/sokol/util/sokol_fontstash.h b/thirdparty/sokol/util/sokol_fontstash.h index 048c821..a650585 100644 --- a/thirdparty/sokol/util/sokol_fontstash.h +++ b/thirdparty/sokol/util/sokol_fontstash.h @@ -19,7 +19,7 @@ platform-specific embedded shader code (these are the same defines as used by sokol_gfx.h and sokol_app.h): - SOKOL_GLCORE33 + SOKOL_GLCORE SOKOL_GLES3 SOKOL_D3D11 SOKOL_METAL @@ -278,11 +278,11 @@ SOKOL_FONTSTASH_API_DECL uint32_t sfons_rgba(uint8_t r, uint8_t g, uint8_t b, ui #define _SOKOL_UNUSED(x) (void)(x) #endif -#if defined(SOKOL_GLCORE33) +#if defined(SOKOL_GLCORE) /* Embedded source code compiled with: - sokol-shdc -i sfons.glsl -o sfons.h -l glsl330:glsl300es:hlsl4:metal_macos:metal_ios:metal_sim:wgsl -b + sokol-shdc -i sfons.glsl -o sfons.h -l glsl410:glsl300es:hlsl4:metal_macos:metal_ios:metal_sim:wgsl -b (not that for Metal and D3D11 byte code, sokol-shdc must be run on macOS and Windows) @@ -321,55 +321,61 @@ SOKOL_FONTSTASH_API_DECL uint32_t sfons_rgba(uint8_t r, uint8_t g, uint8_t b, ui @program sfontstash vs fs */ -static const char _sfons_vs_source_glsl330[478] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x33,0x30,0x0a,0x0a,0x75,0x6e, +static const uint8_t _sfons_vs_source_glsl410[520] = { + 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x34,0x31,0x30,0x0a,0x0a,0x75,0x6e, 0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x73,0x5f,0x70,0x61, 0x72,0x61,0x6d,0x73,0x5b,0x38,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28, 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e, 0x20,0x76,0x65,0x63,0x34,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a, 0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20, 0x3d,0x20,0x33,0x29,0x20,0x69,0x6e,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x70,0x73, - 0x69,0x7a,0x65,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x75,0x76, - 0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f, - 0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x74, - 0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65, - 0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74, - 0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32,0x29,0x20,0x69, - 0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x0a, - 0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20, - 0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20, - 0x6d,0x61,0x74,0x34,0x28,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x30, - 0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x2c, - 0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x32,0x5d,0x2c,0x20,0x76, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x33,0x5d,0x29,0x20,0x2a,0x20,0x70, - 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f, - 0x50,0x6f,0x69,0x6e,0x74,0x53,0x69,0x7a,0x65,0x20,0x3d,0x20,0x70,0x73,0x69,0x7a, - 0x65,0x3b,0x0a,0x20,0x20,0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x6d,0x61,0x74,0x34, - 0x28,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x34,0x5d,0x2c,0x20,0x76, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x35,0x5d,0x2c,0x20,0x76,0x73,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x36,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61, - 0x72,0x61,0x6d,0x73,0x5b,0x37,0x5d,0x29,0x20,0x2a,0x20,0x76,0x65,0x63,0x34,0x28, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20, - 0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20, - 0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, + 0x69,0x7a,0x65,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, + 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x76,0x65, + 0x63,0x34,0x20,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f, + 0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76, + 0x65,0x63,0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x6c, + 0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d, + 0x20,0x31,0x29,0x20,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c, + 0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74, + 0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34, + 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d, + 0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f,0x50, + 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x6d,0x61,0x74,0x34,0x28,0x76, + 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x30,0x5d,0x2c,0x20,0x76,0x73,0x5f, + 0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61, + 0x72,0x61,0x6d,0x73,0x5b,0x32,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61, + 0x6d,0x73,0x5b,0x33,0x5d,0x29,0x20,0x2a,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, + 0x6e,0x3b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74,0x53, + 0x69,0x7a,0x65,0x20,0x3d,0x20,0x70,0x73,0x69,0x7a,0x65,0x3b,0x0a,0x20,0x20,0x20, + 0x20,0x75,0x76,0x20,0x3d,0x20,0x6d,0x61,0x74,0x34,0x28,0x76,0x73,0x5f,0x70,0x61, + 0x72,0x61,0x6d,0x73,0x5b,0x34,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61, + 0x6d,0x73,0x5b,0x35,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73, + 0x5b,0x36,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x37, + 0x5d,0x29,0x20,0x2a,0x20,0x76,0x65,0x63,0x34,0x28,0x74,0x65,0x78,0x63,0x6f,0x6f, + 0x72,0x64,0x30,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a, + 0x20,0x20,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f, + 0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, }; -static const char _sfons_fs_source_glsl330[203] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x33,0x30,0x0a,0x0a,0x75,0x6e, +static const uint8_t _sfons_fs_source_glsl410[245] = { + 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x34,0x31,0x30,0x0a,0x0a,0x75,0x6e, 0x69,0x66,0x6f,0x72,0x6d,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x32,0x44,0x20, 0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x3b,0x0a,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74, 0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f, 0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c, - 0x6f,0x72,0x3b,0x0a,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x75,0x76,0x3b,0x0a, - 0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a, - 0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20, - 0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x76, - 0x65,0x63,0x34,0x28,0x31,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x2c,0x20,0x31,0x2e, - 0x30,0x2c,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x74,0x65,0x78,0x5f,0x73, - 0x6d,0x70,0x2c,0x20,0x75,0x76,0x2e,0x78,0x79,0x29,0x2e,0x78,0x29,0x20,0x2a,0x20, - 0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, + 0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74, + 0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34, + 0x20,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, + 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63, + 0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d, + 0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67, + 0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x76,0x65,0x63,0x34,0x28,0x31,0x2e, + 0x30,0x2c,0x20,0x31,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x2c,0x20,0x74,0x65,0x78, + 0x74,0x75,0x72,0x65,0x28,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x75,0x76, + 0x2e,0x78,0x79,0x29,0x2e,0x78,0x29,0x20,0x2a,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b, + 0x0a,0x7d,0x0a,0x0a,0x00, }; #elif defined(SOKOL_GLES3) -static const char _sfons_vs_source_glsl300es[481] = { +static const uint8_t _sfons_vs_source_glsl300es[481] = { 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, 0x0a,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x73, 0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x38,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f, @@ -402,7 +408,7 @@ static const char _sfons_vs_source_glsl300es[481] = { 0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a, 0x00, }; -static const char _sfons_fs_source_glsl300es[276] = { +static const uint8_t _sfons_fs_source_glsl300es[276] = { 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, 0x70,0x72,0x65,0x63,0x69,0x73,0x69,0x6f,0x6e,0x20,0x6d,0x65,0x64,0x69,0x75,0x6d, 0x70,0x20,0x66,0x6c,0x6f,0x61,0x74,0x3b,0x0a,0x70,0x72,0x65,0x63,0x69,0x73,0x69, @@ -1204,7 +1210,7 @@ static const uint8_t _sfons_fs_bytecode_metal_ios[2841] = { 0xc8,0x70,0x04,0x8d,0x05,0x91,0x7c,0x66,0x1b,0x94,0x00,0xc8,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, }; -static const char _sfons_vs_source_metal_sim[756] = { +static const uint8_t _sfons_vs_source_metal_sim[756] = { 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, @@ -1254,7 +1260,7 @@ static const char _sfons_vs_source_metal_sim[756] = { 0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a, 0x7d,0x0a,0x0a,0x00, }; -static const char _sfons_fs_source_metal_sim[464] = { +static const uint8_t _sfons_fs_source_metal_sim[464] = { 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, @@ -1397,7 +1403,7 @@ static const uint8_t _sfons_fs_bytecode_hlsl4[628] = { 0x00,0x00,0x00,0x00, }; #elif defined(SOKOL_WGPU) -static const char _sfons_vs_source_wgsl[1162] = { +static const uint8_t _sfons_vs_source_wgsl[1162] = { 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20, @@ -1472,17 +1478,17 @@ static const char _sfons_vs_source_wgsl[1162] = { 0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x75,0x76,0x2c,0x20,0x63,0x6f, 0x6c,0x6f,0x72,0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, }; -static const char _sfons_fs_source_wgsl[674] = { +static const uint8_t _sfons_fs_source_wgsl[674] = { 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, 0x76,0x61,0x74,0x65,0x3e,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, 0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75, - 0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x33,0x32, + 0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x34,0x38, 0x29,0x20,0x76,0x61,0x72,0x20,0x74,0x65,0x78,0x20,0x3a,0x20,0x74,0x65,0x78,0x74, 0x75,0x72,0x65,0x5f,0x32,0x64,0x3c,0x66,0x33,0x32,0x3e,0x3b,0x0a,0x0a,0x40,0x67, 0x72,0x6f,0x75,0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67, - 0x28,0x34,0x38,0x29,0x20,0x76,0x61,0x72,0x20,0x73,0x6d,0x70,0x20,0x3a,0x20,0x73, + 0x28,0x36,0x34,0x29,0x20,0x76,0x61,0x72,0x20,0x73,0x6d,0x70,0x20,0x3a,0x20,0x73, 0x61,0x6d,0x70,0x6c,0x65,0x72,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, 0x76,0x61,0x74,0x65,0x3e,0x20,0x75,0x76,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66, 0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20, @@ -1521,7 +1527,7 @@ static const char _sfons_fs_source_wgsl[674] = { static const char* _sfons_vs_source_dummy = ""; static const char* _sfons_fs_source_dummy = ""; #else -#error "Please define one of SOKOL_GLCORE33, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU or SOKOL_DUMMY_BACKEND!" +#error "Please define one of SOKOL_GLCORE, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU or SOKOL_DUMMY_BACKEND!" #endif typedef struct _sfons_t { @@ -1601,12 +1607,12 @@ static int _sfons_render_create(void* user_ptr, int width, int height) { shd_desc.fs.image_sampler_pairs[0].image_slot = 0; shd_desc.fs.image_sampler_pairs[0].sampler_slot = 0; shd_desc.label = "sokol-fontstash-shader"; - #if defined(SOKOL_GLCORE33) - shd_desc.vs.source = _sfons_vs_source_glsl330; - shd_desc.fs.source = _sfons_fs_source_glsl330; + #if defined(SOKOL_GLCORE) + shd_desc.vs.source = (const char*)_sfons_vs_source_glsl410; + shd_desc.fs.source = (const char*)_sfons_fs_source_glsl410; #elif defined(SOKOL_GLES3) - shd_desc.vs.source = _sfons_vs_source_glsl300es; - shd_desc.fs.source = _sfons_fs_source_glsl300es; + shd_desc.vs.source = (const char*)_sfons_vs_source_glsl300es; + shd_desc.fs.source = (const char*)_sfons_fs_source_glsl300es; #elif defined(SOKOL_METAL) shd_desc.vs.entry = "main0"; shd_desc.fs.entry = "main0"; @@ -1620,16 +1626,16 @@ static int _sfons_render_create(void* user_ptr, int width, int height) { shd_desc.fs.bytecode = SG_RANGE(_sfons_fs_bytecode_metal_ios); break; default: - shd_desc.vs.source = _sfons_vs_source_metal_sim; - shd_desc.fs.source = _sfons_fs_source_metal_sim; + shd_desc.vs.source = (const char*)_sfons_vs_source_metal_sim; + shd_desc.fs.source = (const char*)_sfons_fs_source_metal_sim; break; } #elif defined(SOKOL_D3D11) shd_desc.vs.bytecode = SG_RANGE(_sfons_vs_bytecode_hlsl4); shd_desc.fs.bytecode = SG_RANGE(_sfons_fs_bytecode_hlsl4); #elif defined(SOKOL_WGPU) - shd_desc.vs.source = _sfons_vs_source_wgsl; - shd_desc.fs.source = _sfons_fs_source_wgsl; + shd_desc.vs.source = (const char*)_sfons_vs_source_wgsl; + shd_desc.fs.source = (const char*)_sfons_fs_source_wgsl; #else shd_desc.vs.source = _sfons_vs_source_dummy; shd_desc.fs.source = _sfons_fs_source_dummy; diff --git a/thirdparty/sokol/util/sokol_gl.h b/thirdparty/sokol/util/sokol_gl.h index 997ddea..15b3880 100644 --- a/thirdparty/sokol/util/sokol_gl.h +++ b/thirdparty/sokol/util/sokol_gl.h @@ -17,7 +17,7 @@ platform-specific embedded shader code (these are the same defines as used by sokol_gfx.h and sokol_app.h): - SOKOL_GLCORE33 + SOKOL_GLCORE SOKOL_GLES3 SOKOL_D3D11 SOKOL_METAL @@ -973,7 +973,7 @@ inline sgl_pipeline sgl_context_make_pipeline(sgl_context ctx, const sg_pipeline /* Embedded source code compiled with: - sokol-shdc -i sgl.glsl -o sgl.h -l glsl330:glsl300es:hlsl4:metal_macos:metal_ios:metal_sim:wgpu -b + sokol-shdc -i sgl.glsl -o sgl.h -l glsl410:glsl300es:hlsl4:metal_macos:metal_ios:metal_sim:wgpu -b (not that for Metal and D3D11 byte code, sokol-shdc must be run on macOS and Windows) @@ -1013,55 +1013,60 @@ inline sgl_pipeline sgl_context_make_pipeline(sgl_context ctx, const sg_pipeline @program sgl vs fs */ -#if defined(SOKOL_GLCORE33) -static const char _sgl_vs_source_glsl330[478] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x33,0x30,0x0a,0x0a,0x75,0x6e, +#if defined(SOKOL_GLCORE) +static const uint8_t _sgl_vs_source_glsl410[520] = { + 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x34,0x31,0x30,0x0a,0x0a,0x75,0x6e, 0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x73,0x5f,0x70,0x61, 0x72,0x61,0x6d,0x73,0x5b,0x38,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28, 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e, 0x20,0x76,0x65,0x63,0x34,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a, 0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20, 0x3d,0x20,0x33,0x29,0x20,0x69,0x6e,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x70,0x73, - 0x69,0x7a,0x65,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x75,0x76, - 0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f, - 0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x32,0x20,0x74, - 0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65, - 0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74, - 0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32,0x29,0x20,0x69, - 0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x0a, - 0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20, - 0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20, - 0x6d,0x61,0x74,0x34,0x28,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x30, - 0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x2c, - 0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x32,0x5d,0x2c,0x20,0x76, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x33,0x5d,0x29,0x20,0x2a,0x20,0x70, - 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f, - 0x50,0x6f,0x69,0x6e,0x74,0x53,0x69,0x7a,0x65,0x20,0x3d,0x20,0x70,0x73,0x69,0x7a, - 0x65,0x3b,0x0a,0x20,0x20,0x20,0x20,0x75,0x76,0x20,0x3d,0x20,0x6d,0x61,0x74,0x34, - 0x28,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x34,0x5d,0x2c,0x20,0x76, - 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x35,0x5d,0x2c,0x20,0x76,0x73,0x5f, - 0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x36,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61, - 0x72,0x61,0x6d,0x73,0x5b,0x37,0x5d,0x29,0x20,0x2a,0x20,0x76,0x65,0x63,0x34,0x28, - 0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20, - 0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20, - 0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, + 0x69,0x7a,0x65,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, + 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x76,0x65, + 0x63,0x34,0x20,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f, + 0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76, + 0x65,0x63,0x32,0x20,0x74,0x65,0x78,0x63,0x6f,0x6f,0x72,0x64,0x30,0x3b,0x0a,0x6c, + 0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d, + 0x20,0x31,0x29,0x20,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c, + 0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74, + 0x69,0x6f,0x6e,0x20,0x3d,0x20,0x32,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34, + 0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d, + 0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f,0x50, + 0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x6d,0x61,0x74,0x34,0x28,0x76, + 0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x30,0x5d,0x2c,0x20,0x76,0x73,0x5f, + 0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x31,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61, + 0x72,0x61,0x6d,0x73,0x5b,0x32,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61, + 0x6d,0x73,0x5b,0x33,0x5d,0x29,0x20,0x2a,0x20,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, + 0x6e,0x3b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74,0x53, + 0x69,0x7a,0x65,0x20,0x3d,0x20,0x70,0x73,0x69,0x7a,0x65,0x3b,0x0a,0x20,0x20,0x20, + 0x20,0x75,0x76,0x20,0x3d,0x20,0x6d,0x61,0x74,0x34,0x28,0x76,0x73,0x5f,0x70,0x61, + 0x72,0x61,0x6d,0x73,0x5b,0x34,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61, + 0x6d,0x73,0x5b,0x35,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73, + 0x5b,0x36,0x5d,0x2c,0x20,0x76,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x37, + 0x5d,0x29,0x20,0x2a,0x20,0x76,0x65,0x63,0x34,0x28,0x74,0x65,0x78,0x63,0x6f,0x6f, + 0x72,0x64,0x30,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a, + 0x20,0x20,0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f, + 0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, }; -static const char _sgl_fs_source_glsl330[180] = { - 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x33,0x30,0x0a,0x0a,0x75,0x6e, +static const uint8_t _sgl_fs_source_glsl410[222] = { + 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x34,0x31,0x30,0x0a,0x0a,0x75,0x6e, 0x69,0x66,0x6f,0x72,0x6d,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x32,0x44,0x20, 0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x3b,0x0a,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74, 0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f, 0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c, - 0x6f,0x72,0x3b,0x0a,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x75,0x76,0x3b,0x0a, - 0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a, - 0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20, - 0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74, - 0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x2c,0x20, - 0x75,0x76,0x2e,0x78,0x79,0x29,0x20,0x2a,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a, - 0x7d,0x0a,0x0a,0x00, + 0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74, + 0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34, + 0x20,0x75,0x76,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, + 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63, + 0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d, + 0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67, + 0x5f,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65, + 0x28,0x74,0x65,0x78,0x5f,0x73,0x6d,0x70,0x2c,0x20,0x75,0x76,0x2e,0x78,0x79,0x29, + 0x20,0x2a,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, }; #elif defined(SOKOL_GLES3) -static const char _sgl_vs_source_glsl300es[481] = { +static const uint8_t _sgl_vs_source_glsl300es[481] = { 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, 0x0a,0x75,0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x76,0x65,0x63,0x34,0x20,0x76,0x73, 0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x5b,0x38,0x5d,0x3b,0x0a,0x6c,0x61,0x79,0x6f, @@ -1094,7 +1099,7 @@ static const char _sgl_vs_source_glsl300es[481] = { 0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x30,0x3b,0x0a,0x7d,0x0a,0x0a, 0x00, }; -static const char _sgl_fs_source_glsl300es[253] = { +static const uint8_t _sgl_fs_source_glsl300es[253] = { 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, 0x70,0x72,0x65,0x63,0x69,0x73,0x69,0x6f,0x6e,0x20,0x6d,0x65,0x64,0x69,0x75,0x6d, 0x70,0x20,0x66,0x6c,0x6f,0x61,0x74,0x3b,0x0a,0x70,0x72,0x65,0x63,0x69,0x73,0x69, @@ -1890,7 +1895,7 @@ static const uint8_t _sgl_fs_bytecode_metal_ios[2809] = { 0x42,0x40,0x29,0x49,0x50,0x20,0x86,0x60,0x01,0x23,0x9f,0xd9,0x06,0x23,0x00,0x32, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, }; -static const char _sgl_vs_source_metal_sim[756] = { +static const uint8_t _sgl_vs_source_metal_sim[756] = { 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, @@ -1940,7 +1945,7 @@ static const char _sgl_vs_source_metal_sim[756] = { 0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a, 0x7d,0x0a,0x0a,0x00, }; -static const char _sgl_fs_source_metal_sim[439] = { +static const uint8_t _sgl_fs_source_metal_sim[439] = { 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, @@ -2080,7 +2085,7 @@ static const uint8_t _sgl_fs_bytecode_hlsl4[608] = { }; #elif defined(SOKOL_WGPU) -static const char _sgl_vs_source_wgsl[1162] = { +static const uint8_t _sgl_vs_source_wgsl[1162] = { 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20, @@ -2155,17 +2160,17 @@ static const char _sgl_vs_source_wgsl[1162] = { 0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x2c,0x20,0x75,0x76,0x2c,0x20,0x63,0x6f, 0x6c,0x6f,0x72,0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, }; -static const char _sgl_fs_source_wgsl[647] = { +static const uint8_t _sgl_fs_source_wgsl[647] = { 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, 0x76,0x61,0x74,0x65,0x3e,0x20,0x66,0x72,0x61,0x67,0x5f,0x63,0x6f,0x6c,0x6f,0x72, 0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75, - 0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x33,0x32, + 0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x34,0x38, 0x29,0x20,0x76,0x61,0x72,0x20,0x74,0x65,0x78,0x20,0x3a,0x20,0x74,0x65,0x78,0x74, 0x75,0x72,0x65,0x5f,0x32,0x64,0x3c,0x66,0x33,0x32,0x3e,0x3b,0x0a,0x0a,0x40,0x67, 0x72,0x6f,0x75,0x70,0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67, - 0x28,0x34,0x38,0x29,0x20,0x76,0x61,0x72,0x20,0x73,0x6d,0x70,0x20,0x3a,0x20,0x73, + 0x28,0x36,0x34,0x29,0x20,0x76,0x61,0x72,0x20,0x73,0x6d,0x70,0x20,0x3a,0x20,0x73, 0x61,0x6d,0x70,0x6c,0x65,0x72,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, 0x76,0x61,0x74,0x65,0x3e,0x20,0x75,0x76,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66, 0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20, @@ -2202,7 +2207,7 @@ static const char _sgl_fs_source_wgsl[647] = { static const char* _sgl_vs_source_dummy = ""; static const char* _sgl_fs_source_dummy = ""; #else -#error "Please define one of SOKOL_GLCORE33, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU or SOKOL_DUMMY_BACKEND!" +#error "Please define one of SOKOL_GLCORE, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU or SOKOL_DUMMY_BACKEND!" #endif // ████████ ██ ██ ██████ ███████ ███████ @@ -3284,12 +3289,12 @@ static void _sgl_setup_common(void) { shd_desc.fs.image_sampler_pairs[0].sampler_slot = 0; shd_desc.fs.image_sampler_pairs[0].glsl_name = "tex_smp"; shd_desc.label = "sgl-shader"; - #if defined(SOKOL_GLCORE33) - shd_desc.vs.source = _sgl_vs_source_glsl330; - shd_desc.fs.source = _sgl_fs_source_glsl330; + #if defined(SOKOL_GLCORE) + shd_desc.vs.source = (const char*)_sgl_vs_source_glsl410; + shd_desc.fs.source = (const char*)_sgl_fs_source_glsl410; #elif defined(SOKOL_GLES3) - shd_desc.vs.source = _sgl_vs_source_glsl300es; - shd_desc.fs.source = _sgl_fs_source_glsl300es; + shd_desc.vs.source = (const char*)_sgl_vs_source_glsl300es; + shd_desc.fs.source = (const char*)_sgl_fs_source_glsl300es; #elif defined(SOKOL_METAL) shd_desc.vs.entry = "main0"; shd_desc.fs.entry = "main0"; @@ -3303,16 +3308,16 @@ static void _sgl_setup_common(void) { shd_desc.fs.bytecode = SG_RANGE(_sgl_fs_bytecode_metal_ios); break; default: - shd_desc.vs.source = _sgl_vs_source_metal_sim; - shd_desc.fs.source = _sgl_fs_source_metal_sim; + shd_desc.vs.source = (const char*)_sgl_vs_source_metal_sim; + shd_desc.fs.source = (const char*)_sgl_fs_source_metal_sim; break; } #elif defined(SOKOL_D3D11) shd_desc.vs.bytecode = SG_RANGE(_sgl_vs_bytecode_hlsl4); shd_desc.fs.bytecode = SG_RANGE(_sgl_fs_bytecode_hlsl4); #elif defined(SOKOL_WGPU) - shd_desc.vs.source = _sgl_vs_source_wgsl; - shd_desc.fs.source = _sgl_fs_source_wgsl; + shd_desc.vs.source = (const char*)_sgl_vs_source_wgsl; + shd_desc.fs.source = (const char*)_sgl_fs_source_wgsl; #else shd_desc.vs.source = _sgl_vs_source_dummy; shd_desc.fs.source = _sgl_fs_source_dummy; diff --git a/wraps/sokol/c/sokol.c.v b/wraps/sokol/c/sokol.c.v index 4cc0d0a..0f51ce9 100644 --- a/wraps/sokol/c/sokol.c.v +++ b/wraps/sokol/c/sokol.c.v @@ -34,7 +34,7 @@ $if macos { #flag -DSOKOL_METAL #flag -framework Metal -framework Cocoa -framework MetalKit -framework QuartzCore } $else { - #flag darwin -DSOKOL_GLCORE33 -framework OpenGL -framework Cocoa -framework QuartzCore + #flag darwin -DSOKOL_GLCORE -framework OpenGL -framework Cocoa -framework QuartzCore } } $if ios { @@ -52,12 +52,12 @@ $if emscripten ? { } // OPENGL -#flag linux -DSOKOL_GLCORE33 -#flag freebsd -DSOKOL_GLCORE33 -#flag openbsd -DSOKOL_GLCORE33 +#flag linux -DSOKOL_GLCORE +#flag freebsd -DSOKOL_GLCORE +#flag openbsd -DSOKOL_GLCORE //#flag darwin -framework OpenGL -framework Cocoa -framework QuartzCore // D3D -#flag windows -DSOKOL_GLCORE33 +#flag windows -DSOKOL_GLCORE //#flag windows -DSOKOL_D3D11 // for simplicity, all header includes are here because import order matters and we dont have any way // to ensure import order with V yet diff --git a/wraps/sokol/gfx/sokol_gfx.auto.c.v b/wraps/sokol/gfx/sokol_gfx.auto.c.v index 0b7c9b4..2ab090d 100644 --- a/wraps/sokol/gfx/sokol_gfx.auto.c.v +++ b/wraps/sokol/gfx/sokol_gfx.auto.c.v @@ -112,7 +112,7 @@ pub type Color = C.sg_color // Backend is C.sg_backend pub enum Backend { - glcore33 = C.SG_BACKEND_GLCORE33 + glcore33 = C.SG_BACKEND_GLCORE gles3 = C.SG_BACKEND_GLES3 d3d11 = C.SG_BACKEND_D3D11 metal_ios = C.SG_BACKEND_METAL_IOS @@ -192,8 +192,10 @@ pub enum PixelFormat { etc2_rgb8a1 = C.SG_PIXELFORMAT_ETC2_RGB8A1 etc2_rgba8 = C.SG_PIXELFORMAT_ETC2_RGBA8 etc2_srgb8a8 = C.SG_PIXELFORMAT_ETC2_SRGB8A8 - etc2_rg11 = C.SG_PIXELFORMAT_ETC2_RG11 - etc2_rg11sn = C.SG_PIXELFORMAT_ETC2_RG11SN + eac_r11 = C.SG_PIXELFORMAT_EAC_R11 + eac_r11sn = C.SG_PIXELFORMAT_EAC_R11SN + eac_rg11 = C.SG_PIXELFORMAT_EAC_RG11 + eac_rg11sn = C.SG_PIXELFORMAT_EAC_RG11SN astc_4x4_rgba = C.SG_PIXELFORMAT_ASTC_4x4_RGBA astc_4x4_srgba = C.SG_PIXELFORMAT_ASTC_4x4_SRGBA num = C._SG_PIXELFORMAT_NUM @@ -215,6 +217,7 @@ pub mut: image_clamp_to_border bool // border color and clamp-to-border UV-wrap mode is supported mrt_independent_blend_state bool // multiple-render-target rendering can use per-render-target blend state mrt_independent_write_mask bool // multiple-render-target rendering can use per-render-target color write masks + storage_buffer bool // storage buffers are supported } pub type Features = C.sg_features @@ -256,11 +259,12 @@ pub enum Usage as u32 { // BufferType is C.sg_buffer_type pub enum BufferType as u32 { - _default = C._SG_BUFFERTYPE_DEFAULT // value 0 reserved for default-init - vertexbuffer = C.SG_BUFFERTYPE_VERTEXBUFFER - indexbuffer = C.SG_BUFFERTYPE_INDEXBUFFER - _num = C._SG_BUFFERTYPE_NUM - _force_u32 = C._SG_BUFFERTYPE_FORCE_U32 // 0x7FFFFFFF, + _default = C._SG_BUFFERTYPE_DEFAULT // value 0 reserved for default-init + vertexbuffer = C.SG_BUFFERTYPE_VERTEXBUFFER + indexbuffer = C.SG_BUFFERTYPE_INDEXBUFFER + storagebuffer = C.SG_BUFFERTYPE_STORAGEBUFFER + _num = C._SG_BUFFERTYPE_NUM + _force_u32 = C._SG_BUFFERTYPE_FORCE_U32 // 0x7FFFFFFF, } // IndexType is C.sg_index_type @@ -802,6 +806,15 @@ pub mut: pub type ShaderImageDesc = C.sg_shader_image_desc +@[typedef] +pub struct C.sg_shader_storage_buffer_desc { +pub mut: + used bool + readonly bool +} + +pub type ShaderStorageBufferDesc = C.sg_shader_storage_buffer_desc + @[typedef] pub struct C.sg_shader_sampler_desc { pub mut: @@ -830,6 +843,7 @@ pub mut: entry &char = unsafe { nil } d3d11_target &char = unsafe { nil } // TODO uniform_blocks [SG_MAX_SHADERSTAGE_UBS]ShaderUniformBlockDesc + // TODO storage_buffers[SG_MAX_SHADERSTAGE_STORAGEBUFFERS]ShaderStorageBufferDesc; // TODO images [SG_MAX_SHADERSTAGE_IMAGES]ShaderImageDesc // TODO samplers [SG_MAX_SHADERSTAGE_SAMPLERS]ShaderSamplerDesc // TODO image_sampler_pairs [SG_MAX_SHADERSTAGE_IMAGESAMPLERPAIRS]ShaderImageSamplerPairDesc @@ -1239,6 +1253,7 @@ pub mut: num_set_vertex_buffer u32 num_set_vertex_texture u32 num_set_vertex_sampler_state u32 + num_set_fragment_buffer u32 num_set_fragment_texture u32 num_set_fragment_sampler_state u32 }