aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md25
-rw-r--r--sokol_app.h742
-rw-r--r--sokol_gfx.h64
3 files changed, 588 insertions, 243 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5c19bf56..2474b037 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,30 @@
## Updates
+### 08-Sep-2025
+
+- sokol_app.h: added WebGPU support to the native desktop backends (Linux,
+ macOS, Windows), e.g. on those platforms you can now compile sokol_app.h with
+ `SOKOL_WGPU` and it will setup and manage a WebGPU swapchain surface,
+ depth-stencil-buffer and optional MSAA surface for you. You'll need to provide a
+ `<webgpu/webgpu.h> C header and link with a native WebGPU implementation (which
+ is currently only tested with Google's Dawn library). The WebGPU setup is
+ currently fairly hardwired, most notably that the device limits and features are
+ hardwired for what's required by sokol_gfx.h, but of course it's still possible
+ to use sokol_app.h without sokol_gfx.h and instead render directly via WebGPU
+ code. All in all you should currently still see the native WebGPU backend in
+ sokol_app.h as experimental, in some situations it's not as robust as the native
+ 3D API backends (such as window resizing). For me it's currently mainly useful
+ for easier debugging (unlike in the browser it's possible to debug-step into the
+ WebGPU implementation) and for benchmarking the sokol_gfx.h WebGPU backend
+ against the system-native 3D API backends. A nice side effect of this work is also
+ that the 3D API specific code has been better separated from the window system
+ specific code, and it's also a nice preparation for eventually dropping MTKView
+ from the sokol_app.h Metal backend.
+
+ More details in the PR: https://github.com/floooh/sokol/pull/1326
+
+ Also see this PR for what has changed in the sokol-samples: https://github.com/floooh/sokol-samples/pull/182
+
### 01-Sep-2025
- sokol_app.h: it's now possible to define custom mouse cursors via two new functions:
diff --git a/sokol_app.h b/sokol_app.h
index 87e44888..16ea4eeb 100644
--- a/sokol_app.h
+++ b/sokol_app.h
@@ -65,18 +65,30 @@
Link with the following system libraries:
- - on macOS with Metal: Cocoa, QuartzCore, Metal, MetalKit
- - on macOS with GL: Cocoa, QuartzCore, OpenGL
- - on iOS with Metal: Foundation, UIKit, Metal, MetalKit
- - on iOS with GL: Foundation, UIKit, OpenGLES, GLKit
- - on Linux with EGL: X11, Xi, Xcursor, EGL, GL (or GLESv2), dl, pthread, m(?)
- - on Linux with GLX: X11, Xi, Xcursor, GL, dl, pthread, m(?)
+ - on macOS:
+ - all backends: Foundation, Cocoa, QuartzCore
+ - with SOKOL_METAL: Metal, MetalKit
+ - with SOKOL_GLCORE: OpenGL
+ - with SOKOL_WGPU: a WebGPU implementation library (tested with webgpu_dawn)
+ - on iOS:
+ - all backends: Foundation, UIKit
+ - with SOKOL_METAL: Metal, MetalKit
+ - with SOKOL_GLES3: OpenGLES, GLKit
+ - on Linux:
+ - all backends: X11, Xi, Xcursor, dl, pthread, m
+ - with SOKOL_GLCORE: GL
+ - with SOKOL_GLES3: GLESv2
+ - with SOKOL_WGPU: a WebGPU implementation library (tested with webgpu_dawn)
+ - with EGL: EGL
- on Android: GLESv3, EGL, log, android
- - on Windows with the MSVC or Clang toolchains: no action needed, libs are defined in-source via pragma-comment-lib
- - on Windows with MINGW/MSYS2 gcc: compile with '-mwin32' so that _WIN32 is defined
- - link with the following libs: -lkernel32 -luser32 -lshell32
- - additionally with the GL backend: -lgdi32
- - additionally with the D3D11 backend: -ld3d11 -ldxgi
+ - on Windows:
+ - with MSVC or Clang: library dependencies are defined via `#pragma comment`
+ - with SOKOL_WGPU: a WebGPU implementation library (tested with webgpu_dawn)
+ - with MINGW/MSYS2 gcc:
+ - compile with '-mwin32' so that _WIN32 is defined
+ - link with the following libs: -lkernel32 -luser32 -lshell32
+ - additionally with the GL backend: -lgdi32
+ - additionally with the D3D11 backend: -ld3d11 -ldxgi
On Linux, you also need to use the -pthread compiler and linker option, otherwise weird
things will happen, see here for details: https://github.com/floooh/sokol/issues/376
@@ -86,7 +98,7 @@
On Emscripten:
- for WebGL2: add the linker option `-s USE_WEBGL2=1`
- for WebGPU: compile and link with `--use-port=emdawnwebgpu`
- (for more exotic situations, read: https://dawn.googlesource.com/dawn/+/refs/heads/main/src/emdawnwebgpu/pkg/README.md)
+ (for more exotic situations read: https://dawn.googlesource.com/dawn/+/refs/heads/main/src/emdawnwebgpu/pkg/README.md)
FEATURE OVERVIEW
================
@@ -94,11 +106,12 @@
implements the 'application-wrapper' parts of a 3D application:
- a common application entry function
- - creates a window and 3D-API context/device with a 'default framebuffer'
+ - creates a window and 3D-API context/device with a swapchain
+ surface, depth-stencil-buffer surface and optionally MSAA surface
- 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, GL4.1, GL4.3, GLES3, WebGL, WebGL2, NOAPI
+ - 3D-APIs: Metal, D3D11, GL4.1, GL4.3, GLES3, WebGL2, WebGPU, NOAPI
FEATURE/PLATFORM MATRIX
=======================
@@ -108,6 +121,7 @@
gles3/webgl2 | --- | --- | YES(2)| YES | YES | YES
metal | --- | YES | --- | YES | --- | ---
d3d11 | YES | --- | --- | --- | --- | ---
+ webgpu | YES(4) | YES(4)| YES(4)| NO | NO | YES
noapi | YES | TODO | TODO | --- | TODO | ---
KEY_DOWN | YES | YES | YES | SOME | TODO | YES
KEY_UP | YES | YES | YES | SOME | TODO | YES
@@ -148,6 +162,8 @@
(1) macOS has no regular window icons, instead the dock icon is changed
(2) supported with EGL only (not GLX)
(3) fullscreen in the browser not supported on iphones
+ (4) WebGPU on native desktop platforms should be considered experimental
+ and mainly useful for debugging and benchmarking
STEP BY STEP
============
@@ -1760,6 +1776,9 @@ typedef struct sapp_allocator {
_SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_ONCREATE, "NativeActivity onCreate") \
_SAPP_LOGITEM_XMACRO(ANDROID_CREATE_THREAD_PIPE_FAILED, "failed to create thread pipe") \
_SAPP_LOGITEM_XMACRO(ANDROID_NATIVE_ACTIVITY_CREATE_SUCCESS, "NativeActivity successfully created") \
+ _SAPP_LOGITEM_XMACRO(WGPU_DEVICE_LOST, "wgpu: device lost") \
+ _SAPP_LOGITEM_XMACRO(WGPU_DEVICE_LOG, "wgpu: device log") \
+ _SAPP_LOGITEM_XMACRO(WGPU_DEVICE_UNCAPTURED_ERROR, "wgpu: uncaptured error") \
_SAPP_LOGITEM_XMACRO(WGPU_SWAPCHAIN_CREATE_SURFACE_FAILED, "wgpu: failed to create surface for swapchain") \
_SAPP_LOGITEM_XMACRO(WGPU_SWAPCHAIN_SURFACE_GET_CAPABILITIES_FAILED, "wgpu: wgpuSurfaceGetCapabilities failed") \
_SAPP_LOGITEM_XMACRO(WGPU_SWAPCHAIN_CREATE_DEPTH_STENCIL_TEXTURE_FAILED, "wgpu: failed to create depth-stencil texture for swapchain") \
@@ -2120,8 +2139,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_GLCORE)
- #error("sokol_app.h: unknown 3D API selected for MacOS, must be SOKOL_METAL or SOKOL_GLCORE")
+ #if !defined(SOKOL_METAL) && !defined(SOKOL_GLCORE) && !defined(SOKOL_WGPU)
+ #error("sokol_app.h: unknown 3D API selected for MacOS, must be SOKOL_METAL, SOKOL_GLCORE or SOKOL_WGPU")
#endif
#else
/* iOS or iOS Simulator */
@@ -2139,8 +2158,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_GLCORE) && !defined(SOKOL_NOAPI)
- #error("sokol_app.h: unknown 3D API selected for Win32, must be SOKOL_D3D11, SOKOL_GLCORE or SOKOL_NOAPI")
+ #if !defined(SOKOL_D3D11) && !defined(SOKOL_GLCORE) && !defined(SOKOL_WGPU) && !defined(SOKOL_NOAPI)
+ #error("sokol_app.h: unknown 3D API selected for Win32, must be SOKOL_D3D11, SOKOL_GLCORE, SOKOL_WGPU or SOKOL_NOAPI")
#endif
#elif defined(__ANDROID__)
/* Android */
@@ -2154,17 +2173,21 @@ 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_GLCORE) && !defined(SOKOL_GLES3) && !defined(SOKOL_WGPU)
+ #error("sokol_app.h: unknown 3D API selected for Linux, must be SOKOL_GLCORE, SOKOL_GLES3 or SOKOL_WGPU")
+ #endif
#if defined(SOKOL_GLCORE)
- #if !defined(SOKOL_FORCE_EGL)
+ #if defined(SOKOL_FORCE_EGL)
+ #define _SAPP_EGL (1)
+ #else
#define _SAPP_GLX (1)
#endif
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#elif defined(SOKOL_GLES3)
+ #define _SAPP_EGL (1)
#include <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
- #else
- #error("sokol_app.h: unknown 3D API selected for Linux, must be SOKOL_GLCORE, SOKOL_GLES3")
#endif
#else
#error "sokol_app.h: Unknown platform"
@@ -2203,21 +2226,28 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); }
#if defined(SOKOL_WGPU)
#include <webgpu/webgpu.h>
+ #if !defined(__EMSCRIPTEN__)
+ #define _SAPP_WGPU_HAS_WAIT (1)
+ #endif
#endif
#if defined(_SAPP_APPLE)
+ #ifndef GL_SILENCE_DEPRECATION
+ #define GL_SILENCE_DEPRECATION
+ #endif
#if defined(SOKOL_METAL)
#import <Metal/Metal.h>
#import <MetalKit/MetalKit.h>
#endif
#if defined(_SAPP_MACOS)
+ #import <Cocoa/Cocoa.h>
#if defined(_SAPP_ANY_GL)
- #ifndef GL_SILENCE_DEPRECATION
- #define GL_SILENCE_DEPRECATION
- #endif
- #include <Cocoa/Cocoa.h>
#include <OpenGL/gl3.h>
#endif
+ #if defined(SOKOL_WGPU)
+ #import <QuartzCore/CAMetalLayer.h>
+ #import <QuartzCore/CADisplayLink.h>
+ #endif
#elif defined(_SAPP_IOS)
#import <UIKit/UIKit.h>
#if defined(_SAPP_ANY_GL)
@@ -2319,7 +2349,7 @@ inline void sapp_run(const sapp_desc& desc) { return sapp_run(&desc); }
#include <X11/Xcursor/Xcursor.h>
#include <X11/cursorfont.h> /* XC_* font cursors */
#include <X11/Xmd.h> /* CARD32 */
- #if !defined(_SAPP_GLX)
+ #if defined(_SAPP_EGL)
#include <EGL/egl.h>
#endif
#include <dlfcn.h> /* dlopen, dlsym, dlclose */
@@ -2576,7 +2606,7 @@ typedef struct {
WGPUTexture depth_stencil_tex;
WGPUTextureView depth_stencil_view;
WGPUTextureView swapchain_view;
- bool async_init_done;
+ bool init_done;
} _sapp_wgpu_t;
#endif
@@ -2594,6 +2624,10 @@ typedef struct {
@interface _sapp_macos_view : NSOpenGLView
- (void)timerFired:(id)sender;
@end
+#elif defined(SOKOL_WGPU)
+ @interface _sapp_macos_view : NSView
+ - (void)displayLinkFired:(id)sender;
+ @end
#endif // SOKOL_GLCORE
typedef struct {
@@ -2610,6 +2644,12 @@ typedef struct {
#if defined(SOKOL_METAL)
id<MTLDevice> mtl_device;
#endif
+ #if defined(SOKOL_WGPU)
+ struct {
+ CAMetalLayer* mtl_layer;
+ CADisplayLink* display_link;
+ } wgpu;
+ #endif
} _sapp_macos_t;
#endif // _SAPP_MACOS
@@ -2988,16 +3028,15 @@ typedef struct {
bool ARB_create_context;
bool ARB_create_context_profile;
} _sapp_glx_t;
+#endif // _SAPP_GLX
-#else
-
+#if defined(_SAPP_EGL)
typedef struct {
EGLDisplay display;
EGLContext context;
EGLSurface surface;
} _sapp_egl_t;
-
-#endif // _SAPP_GLX
+#endif // _SAPP_EGL
#endif // _SAPP_LINUX
#if defined(_SAPP_ANY_GL)
@@ -3079,7 +3118,7 @@ typedef struct {
_sapp_x11_t x11;
#if defined(_SAPP_GLX)
_sapp_glx_t glx;
- #else
+ #elif defined(_SAPP_EGL)
_sapp_egl_t egl;
#endif
#endif
@@ -3113,6 +3152,10 @@ static const char* _sapp_log_messages[] = {
#define _SAPP_ERROR(code) _sapp_log(SAPP_LOGITEM_ ##code, 1, 0, __LINE__)
#define _SAPP_WARN(code) _sapp_log(SAPP_LOGITEM_ ##code, 2, 0, __LINE__)
#define _SAPP_INFO(code) _sapp_log(SAPP_LOGITEM_ ##code, 3, 0, __LINE__)
+#define _SAPP_PANIC_MSG(code, msg) _sapp_log(SAPP_LOGITEM_ ##code, 0, msg, __LINE__)
+#define _SAPP_ERROR_MSG(code, msg) _sapp_log(SAPP_LOGITEM_ ##code, 1, msg, __LINE__)
+#define _SAPP_WARN_MSG(code, msg) _sapp_log(SAPP_LOGITEM_ ##code, 2, msg, __LINE__)
+#define _SAPP_INFO_MSG(code, msg) _sapp_log(SAPP_LOGITEM_ ##code, 3, msg, __LINE__)
static void _sapp_log(sapp_log_item log_item, uint32_t log_level, const char* msg, uint32_t line_nr) {
if (_sapp.desc.logger.func) {
@@ -3243,8 +3286,8 @@ _SOKOL_PRIVATE char* _sapp_dropped_file_path_ptr(int index) {
return &_sapp.drop.buffer[offset];
}
-/* Copy a string into a fixed size buffer with guaranteed zero-
- termination.
+/* Copy a string (either zero-terminated or with explicit length)
+ into a fixed size buffer with guaranteed zero-termination.
Return false if the string didn't fit into the buffer and had to be clamped.
@@ -3252,18 +3295,24 @@ _SOKOL_PRIVATE char* _sapp_dropped_file_path_ptr(int index) {
is clamped, because the last zero-byte might be written into
the middle of a multi-byte sequence.
*/
-_SOKOL_PRIVATE bool _sapp_strcpy(const char* src, char* dst, int max_len) {
- SOKOL_ASSERT(src && dst && (max_len > 0));
- char* const end = &(dst[max_len-1]);
+_SOKOL_PRIVATE bool _sapp_strcpy_range(const char* src, size_t src_len, char* dst, size_t dst_buf_len) {
+ SOKOL_ASSERT(src && dst && (dst_buf_len > 0));
+ if (0 == src_len) {
+ src_len = dst_buf_len;
+ }
+ char* const end = &(dst[dst_buf_len-1]);
char c = 0;
- for (int i = 0; i < max_len; i++) {
+ for (size_t i = 0; i < dst_buf_len; i++) {
c = *src;
+ if (i >= src_len) {
+ c = 0;
+ }
if (c != 0) {
src++;
}
*dst++ = c;
}
- /* truncated? */
+ // truncated?
if (c != 0) {
*end = 0;
return false;
@@ -3272,6 +3321,10 @@ _SOKOL_PRIVATE bool _sapp_strcpy(const char* src, char* dst, int max_len) {
}
}
+_SOKOL_PRIVATE bool _sapp_strcpy(const char* src, char* dst, size_t dst_buf_len) {
+ return _sapp_strcpy_range(src, 0, dst, dst_buf_len);
+}
+
_SOKOL_PRIVATE sapp_desc _sapp_desc_defaults(const sapp_desc* desc) {
SOKOL_ASSERT((desc->allocator.alloc_fn && desc->allocator.free_fn) || (!desc->allocator.alloc_fn && !desc->allocator.free_fn));
sapp_desc res = *desc;
@@ -3590,6 +3643,45 @@ _SOKOL_PRIVATE WGPUStringView _sapp_wgpu_stringview(const char* str) {
return res;
}
+_SOKOL_PRIVATE WGPUCallbackMode _sapp_wgpu_callbackmode(void) {
+ #if defined(_SAPP_WGPU_HAS_WAIT)
+ return WGPUCallbackMode_WaitAnyOnly;
+ #else
+ return WGPUCallbackMode_AllowProcessEvents;
+ #endif
+}
+
+_SOKOL_PRIVATE void _sapp_wgpu_await(WGPUFuture future) {
+ #if defined(_SAPP_WGPU_HAS_WAIT)
+ SOKOL_ASSERT(_sapp.wgpu.instance);
+ WGPUFutureWaitInfo wait_info;
+ _sapp_clear(&wait_info, sizeof(wait_info));
+ wait_info.future = future;
+ WGPUWaitStatus res = wgpuInstanceWaitAny(_sapp.wgpu.instance, 1, &wait_info, UINT64_MAX);
+ SOKOL_ASSERT(res == WGPUWaitStatus_Success); _SOKOL_UNUSED(res);
+ #else
+ // this code path should never be called
+ _SOKOL_UNUSED(future);
+ SOKOL_ASSERT(false);
+ #endif
+}
+
+_SOKOL_PRIVATE WGPUTextureFormat _sapp_wgpu_pick_render_format(size_t count, const WGPUTextureFormat* formats) {
+ // NOTE: only accept non-SRGB formats until sokol_app.h gets proper SRGB support
+ SOKOL_ASSERT((count > 0) && formats);
+ for (size_t i = 0; i < count; i++) {
+ const WGPUTextureFormat fmt = formats[i];
+ switch (fmt) {
+ case WGPUTextureFormat_RGBA8Unorm:
+ case WGPUTextureFormat_BGRA8Unorm:
+ return fmt;
+ default: break;
+ }
+ }
+ // FIXME: fallback might still return an SRGB format
+ return formats[0];
+}
+
_SOKOL_PRIVATE void _sapp_wgpu_create_swapchain(bool called_from_resize) {
SOKOL_ASSERT(_sapp.wgpu.instance);
SOKOL_ASSERT(_sapp.wgpu.device);
@@ -3597,7 +3689,6 @@ _SOKOL_PRIVATE void _sapp_wgpu_create_swapchain(bool called_from_resize) {
SOKOL_ASSERT(0 == _sapp.wgpu.msaa_view);
SOKOL_ASSERT(0 == _sapp.wgpu.depth_stencil_tex);
SOKOL_ASSERT(0 == _sapp.wgpu.depth_stencil_view);
- SOKOL_ASSERT(0 == _sapp.wgpu.swapchain_view);
if (!called_from_resize) {
SOKOL_ASSERT(0 == _sapp.wgpu.surface);
@@ -3609,8 +3700,28 @@ _SOKOL_PRIVATE void _sapp_wgpu_create_swapchain(bool called_from_resize) {
html_canvas_desc.chain.sType = WGPUSType_EmscriptenSurfaceSourceCanvasHTMLSelector;
html_canvas_desc.selector = _sapp_wgpu_stringview(_sapp.html5_canvas_selector);
surf_desc.nextInChain = &html_canvas_desc.chain;
+ #elif defined(_SAPP_MACOS)
+ WGPUSurfaceSourceMetalLayer from_metal_layer;
+ _sapp_clear(&from_metal_layer, sizeof(from_metal_layer));
+ from_metal_layer.chain.sType = WGPUSType_SurfaceSourceMetalLayer;
+ from_metal_layer.layer = _sapp.macos.view.layer;
+ surf_desc.nextInChain = &from_metal_layer.chain;
+ #elif defined(_SAPP_WIN32)
+ WGPUSurfaceSourceWindowsHWND from_hwnd;
+ _sapp_clear(&from_hwnd, sizeof(from_hwnd));
+ from_hwnd.chain.sType = WGPUSType_SurfaceSourceWindowsHWND;
+ from_hwnd.hinstance = GetModuleHandleW(NULL);
+ from_hwnd.hwnd = _sapp.win32.hwnd;
+ surf_desc.nextInChain = &from_hwnd.chain;
+ #elif defined(_SAPP_LINUX)
+ WGPUSurfaceSourceXlibWindow from_xlib;
+ _sapp_clear(&from_xlib, sizeof(from_xlib));
+ from_xlib.chain.sType = WGPUSType_SurfaceSourceXlibWindow;
+ from_xlib.display = _sapp.x11.display;
+ from_xlib.window = _sapp.x11.window;
+ surf_desc.nextInChain = &from_xlib.chain;
#else
- #error "Unsupported platform for SOKOL_WGPU"
+ #error "sokol_app.h: unsupported WebGPU platform"
#endif
_sapp.wgpu.surface = wgpuInstanceCreateSurface(_sapp.wgpu.instance, &surf_desc);
if (0 == _sapp.wgpu.surface) {
@@ -3622,7 +3733,7 @@ _SOKOL_PRIVATE void _sapp_wgpu_create_swapchain(bool called_from_resize) {
if (caps_status != WGPUStatus_Success) {
_SAPP_PANIC(WGPU_SWAPCHAIN_SURFACE_GET_CAPABILITIES_FAILED);
}
- _sapp.wgpu.render_format = surf_caps.formats[0];
+ _sapp.wgpu.render_format = _sapp_wgpu_pick_render_format(surf_caps.formatCount, surf_caps.formats);
}
SOKOL_ASSERT(_sapp.wgpu.surface);
@@ -3736,18 +3847,61 @@ _SOKOL_PRIVATE WGPUTextureView _sapp_wgpu_swapchain_next(void) {
return wgpuTextureCreateView(surf_tex.texture, 0);
}
-_SOKOL_PRIVATE void _sapp_wgpu_size_changed(void) {
+_SOKOL_PRIVATE void _sapp_wgpu_swapchain_size_changed(void) {
if (_sapp.wgpu.surface) {
_sapp_wgpu_discard_swapchain(true);
_sapp_wgpu_create_swapchain(true);
}
}
+_SOKOL_PRIVATE void _sapp_wgpu_device_lost_cb(const WGPUDevice* dev, WGPUDeviceLostReason reason, WGPUStringView msg, void* ud1, void* ud2) {
+ _SOKOL_UNUSED(dev); _SOKOL_UNUSED(reason); _SOKOL_UNUSED(ud1); _SOKOL_UNUSED(ud2);
+ // NOTE: on wgpuInstanceRelease(), the device lost callback is always called with
+ // WGPUDeviceLostReason_CallbackCancelled (even though no device should exist at that point)
+ if (reason != WGPUDeviceLostReason_CallbackCancelled) {
+ SOKOL_ASSERT(msg.data && (msg.length > 0));
+ char buf[1024];
+ _sapp_strcpy_range(msg.data, msg.length, buf, sizeof(buf));
+ _SAPP_ERROR_MSG(WGPU_DEVICE_LOST, buf);
+ }
+}
+
+// NOTE: emdawnwebgpu doesn't seem to have a device logging callback
+#if !defined(_SAPP_EMSCRIPTEN)
+_SOKOL_PRIVATE void _sapp_wgpu_device_logging_cb(WGPULoggingType log_type, WGPUStringView msg, void* ud1, void* ud2) {
+ _SOKOL_UNUSED(log_type); _SOKOL_UNUSED(ud1); _SOKOL_UNUSED(ud2);
+ SOKOL_ASSERT(msg.data && (msg.length > 0));
+ char buf[1024];
+ _sapp_strcpy_range(msg.data, msg.length, buf, sizeof(buf));
+ switch (log_type) {
+ case WGPULoggingType_Warning:
+ _SAPP_WARN_MSG(WGPU_DEVICE_LOG, buf);
+ break;
+ case WGPULoggingType_Error:
+ _SAPP_ERROR_MSG(WGPU_DEVICE_LOG, buf);
+ break;
+ default:
+ _SAPP_INFO_MSG(WGPU_DEVICE_LOG, buf);
+ break;
+ }
+}
+#endif
+
+_SOKOL_PRIVATE void _sapp_wgpu_uncaptured_error_cb(const WGPUDevice* dev, WGPUErrorType err_type, WGPUStringView msg, void* ud1, void* ud2) {
+ _SOKOL_UNUSED(dev); _SOKOL_UNUSED(ud1); _SOKOL_UNUSED(ud2);
+ if (err_type != WGPUErrorType_NoError) {
+ SOKOL_ASSERT(msg.data && (msg.length > 0));
+ char buf[1024];
+ _sapp_strcpy_range(msg.data, msg.length, buf, sizeof(buf));
+ _SAPP_ERROR_MSG(WGPU_DEVICE_UNCAPTURED_ERROR, buf);
+ }
+}
+
_SOKOL_PRIVATE void _sapp_wgpu_request_device_cb(WGPURequestDeviceStatus status, WGPUDevice device, WGPUStringView msg, void* userdata1, void* userdata2) {
_SOKOL_UNUSED(msg);
_SOKOL_UNUSED(userdata1);
_SOKOL_UNUSED(userdata2);
- SOKOL_ASSERT(!_sapp.wgpu.async_init_done);
+ SOKOL_ASSERT(!_sapp.wgpu.init_done);
if (status != WGPURequestDeviceStatus_Success) {
if (status == WGPURequestDeviceStatus_Error) {
_SAPP_PANIC(WGPU_REQUEST_DEVICE_STATUS_ERROR);
@@ -3757,42 +3911,37 @@ _SOKOL_PRIVATE void _sapp_wgpu_request_device_cb(WGPURequestDeviceStatus status,
}
SOKOL_ASSERT(device);
_sapp.wgpu.device = device;
+ #if !defined(_SAPP_EMSCRIPTEN)
+ WGPULoggingCallbackInfo cb_info;
+ _sapp_clear(&cb_info, sizeof(cb_info));
+ cb_info.callback = _sapp_wgpu_device_logging_cb;
+ wgpuDeviceSetLoggingCallback(_sapp.wgpu.device, cb_info);
+ #endif
_sapp_wgpu_create_swapchain(false);
- _sapp.wgpu.async_init_done = true;
+ _sapp.wgpu.init_done = true;
}
-_SOKOL_PRIVATE void _sapp_wgpu_request_adapter_cb(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView msg, void* userdata1, void* userdata2) {
- _SOKOL_UNUSED(msg);
- _SOKOL_UNUSED(userdata1);
- _SOKOL_UNUSED(userdata2);
- if (status != WGPURequestAdapterStatus_Success) {
- switch (status) {
- case WGPURequestAdapterStatus_Unavailable: _SAPP_PANIC(WGPU_REQUEST_ADAPTER_STATUS_UNAVAILABLE); break;
- case WGPURequestAdapterStatus_Error: _SAPP_PANIC(WGPU_REQUEST_ADAPTER_STATUS_ERROR); break;
- default: _SAPP_PANIC(WGPU_REQUEST_ADAPTER_STATUS_UNKNOWN); break;
- }
- }
- SOKOL_ASSERT(adapter);
- _sapp.wgpu.adapter = adapter;
+_SOKOL_PRIVATE void _sapp_wgpu_create_device_and_swapchain(void) {
+ SOKOL_ASSERT(_sapp.wgpu.adapter);
size_t cur_feature_index = 1;
#define _SAPP_WGPU_MAX_REQUESTED_FEATURES (8)
WGPUFeatureName requiredFeatures[_SAPP_WGPU_MAX_REQUESTED_FEATURES] = {
WGPUFeatureName_Depth32FloatStencil8,
};
// check for optional features we're interested in
- if (wgpuAdapterHasFeature(adapter, WGPUFeatureName_TextureCompressionBC)) {
+ if (wgpuAdapterHasFeature(_sapp.wgpu.adapter, WGPUFeatureName_TextureCompressionBC)) {
SOKOL_ASSERT(cur_feature_index < _SAPP_WGPU_MAX_REQUESTED_FEATURES);
requiredFeatures[cur_feature_index++] = WGPUFeatureName_TextureCompressionBC;
}
- if (wgpuAdapterHasFeature(adapter, WGPUFeatureName_TextureCompressionETC2)) {
+ if (wgpuAdapterHasFeature(_sapp.wgpu.adapter, WGPUFeatureName_TextureCompressionETC2)) {
SOKOL_ASSERT(cur_feature_index < _SAPP_WGPU_MAX_REQUESTED_FEATURES);
requiredFeatures[cur_feature_index++] = WGPUFeatureName_TextureCompressionETC2;
}
- if (wgpuAdapterHasFeature(adapter, WGPUFeatureName_TextureCompressionASTC)) {
+ if (wgpuAdapterHasFeature(_sapp.wgpu.adapter, WGPUFeatureName_TextureCompressionASTC)) {
SOKOL_ASSERT(cur_feature_index < _SAPP_WGPU_MAX_REQUESTED_FEATURES);
requiredFeatures[cur_feature_index++] = WGPUFeatureName_TextureCompressionASTC;
}
- if (wgpuAdapterHasFeature(adapter, WGPUFeatureName_Float32Filterable)) {
+ if (wgpuAdapterHasFeature(_sapp.wgpu.adapter, WGPUFeatureName_Float32Filterable)) {
SOKOL_ASSERT(cur_feature_index < _SAPP_WGPU_MAX_REQUESTED_FEATURES);
requiredFeatures[cur_feature_index++] = WGPUFeatureName_Float32Filterable;
}
@@ -3800,38 +3949,109 @@ _SOKOL_PRIVATE void _sapp_wgpu_request_adapter_cb(WGPURequestAdapterStatus statu
WGPURequestDeviceCallbackInfo cb_info;
_sapp_clear(&cb_info, sizeof(cb_info));
- cb_info.mode = WGPUCallbackMode_AllowProcessEvents;
+ cb_info.mode = _sapp_wgpu_callbackmode();
cb_info.callback = _sapp_wgpu_request_device_cb;
WGPUDeviceDescriptor dev_desc;
_sapp_clear(&dev_desc, sizeof(dev_desc));
dev_desc.requiredFeatureCount = cur_feature_index;
- dev_desc.requiredFeatures = requiredFeatures,
- wgpuAdapterRequestDevice(adapter, &dev_desc, cb_info);
+ dev_desc.requiredFeatures = requiredFeatures;
+ dev_desc.deviceLostCallbackInfo.mode = WGPUCallbackMode_AllowProcessEvents;
+ dev_desc.deviceLostCallbackInfo.callback = _sapp_wgpu_device_lost_cb;
+ dev_desc.uncapturedErrorCallbackInfo.callback = _sapp_wgpu_uncaptured_error_cb;
+ WGPUFuture future = wgpuAdapterRequestDevice(_sapp.wgpu.adapter, &dev_desc, cb_info);
+ #if defined(_SAPP_WGPU_HAS_WAIT)
+ _sapp_wgpu_await(future);
+ #else
+ _SOKOL_UNUSED(future);
+ #endif
}
-_SOKOL_PRIVATE void _sapp_wgpu_init(void) {
- SOKOL_ASSERT(0 == _sapp.wgpu.instance);
- SOKOL_ASSERT(!_sapp.wgpu.async_init_done);
- _sapp.wgpu.instance = wgpuCreateInstance(0);
- if (0 == _sapp.wgpu.instance) {
- _SAPP_PANIC(WGPU_CREATE_INSTANCE_FAILED);
+_SOKOL_PRIVATE void _sapp_wgpu_request_adapter_cb(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView msg, void* userdata1, void* userdata2) {
+ _SOKOL_UNUSED(msg);
+ _SOKOL_UNUSED(userdata1);
+ _SOKOL_UNUSED(userdata2);
+ if (status != WGPURequestAdapterStatus_Success) {
+ switch (status) {
+ case WGPURequestAdapterStatus_Unavailable: _SAPP_PANIC(WGPU_REQUEST_ADAPTER_STATUS_UNAVAILABLE); break;
+ case WGPURequestAdapterStatus_Error: _SAPP_PANIC(WGPU_REQUEST_ADAPTER_STATUS_ERROR); break;
+ default: _SAPP_PANIC(WGPU_REQUEST_ADAPTER_STATUS_UNKNOWN); break;
+ }
}
+ SOKOL_ASSERT(adapter);
+ _sapp.wgpu.adapter = adapter;
+ #if !defined(_SAPP_WGPU_HAS_WAIT)
+ // chain device creation
+ _sapp_wgpu_create_device_and_swapchain();
+ #endif
+}
+
+_SOKOL_PRIVATE void _sapp_wgpu_create_adapter(void) {
+ SOKOL_ASSERT(_sapp.wgpu.instance);
// FIXME: power preference?
WGPURequestAdapterCallbackInfo cb_info;
_sapp_clear(&cb_info, sizeof(cb_info));
- cb_info.mode = WGPUCallbackMode_AllowProcessEvents;
+ cb_info.mode = _sapp_wgpu_callbackmode();
cb_info.callback = _sapp_wgpu_request_adapter_cb;
- wgpuInstanceRequestAdapter(_sapp.wgpu.instance, 0, cb_info);
+ WGPUFuture future = wgpuInstanceRequestAdapter(_sapp.wgpu.instance, 0, cb_info);
+ #if defined(_SAPP_WGPU_HAS_WAIT)
+ _sapp_wgpu_await(future);
+ #else
+ _SOKOL_UNUSED(future);
+ #endif
+}
+
+_SOKOL_PRIVATE void _sapp_wgpu_init(void) {
+ SOKOL_ASSERT(0 == _sapp.wgpu.instance);
+ SOKOL_ASSERT(!_sapp.wgpu.init_done);
+
+ WGPUInstanceDescriptor desc;
+ _sapp_clear(&desc, sizeof(desc));
+ #if defined(_SAPP_WGPU_HAS_WAIT)
+ WGPUInstanceFeatureName inst_features[1] = {
+ WGPUInstanceFeatureName_TimedWaitAny,
+ };
+ desc.requiredFeatureCount = 1;
+ desc.requiredFeatures = inst_features;
+ #endif
+ _sapp.wgpu.instance = wgpuCreateInstance(&desc);
+ if (0 == _sapp.wgpu.instance) {
+ _SAPP_PANIC(WGPU_CREATE_INSTANCE_FAILED);
+ }
+ // NOTE: on Emscripten, device and swapchain creation are chained in the callacks
+ _sapp_wgpu_create_adapter();
+ #if defined(_SAPP_WGPU_HAS_WAIT)
+ _sapp_wgpu_create_device_and_swapchain();
+ SOKOL_ASSERT(_sapp.wgpu.init_done);
+ #endif
+}
+
+_SOKOL_PRIVATE void _sapp_wgpu_discard(void) {
+ _sapp_wgpu_discard_swapchain(false);
+ if (_sapp.wgpu.device) {
+ wgpuDeviceRelease(_sapp.wgpu.device);
+ _sapp.wgpu.device = 0;
+ }
+ if (_sapp.wgpu.adapter) {
+ wgpuAdapterRelease(_sapp.wgpu.adapter);
+ _sapp.wgpu.adapter = 0;
+ }
+ if (_sapp.wgpu.instance) {
+ wgpuInstanceRelease(_sapp.wgpu.instance);
+ _sapp.wgpu.instance = 0;
+ }
}
_SOKOL_PRIVATE void _sapp_wgpu_frame(void) {
wgpuInstanceProcessEvents(_sapp.wgpu.instance);
- if (_sapp.wgpu.async_init_done) {
+ if (_sapp.wgpu.init_done) {
_sapp.wgpu.swapchain_view = _sapp_wgpu_swapchain_next();
_sapp_frame();
wgpuTextureViewRelease(_sapp.wgpu.swapchain_view);
_sapp.wgpu.swapchain_view = 0;
+ #if !defined(_SAPP_EMSCRIPTEN)
+ wgpuSurfacePresent(_sapp.wgpu.surface);
+ #endif
}
}
#endif // SOKOL_WGPU
@@ -3860,14 +4080,21 @@ _SOKOL_PRIVATE void _sapp_wgpu_frame(void) {
// >>macos
#if defined(_SAPP_MACOS)
-#if defined(SOKOL_METAL)
-_SOKOL_PRIVATE void _sapp_macos_mtl_init(void) {
+NSInteger _sapp_macos_max_fps(void) {
NSInteger max_fps = 60;
#if (__MAC_OS_X_VERSION_MAX_ALLOWED >= 120000)
if (@available(macOS 12.0, *)) {
max_fps = [NSScreen.mainScreen maximumFramesPerSecond];
}
#endif
+ return max_fps;
+}
+
+#if defined(SOKOL_METAL)
+_SOKOL_PRIVATE void _sapp_macos_mtl_init(void) {
+ NSInteger max_fps = _sapp_macos_max_fps();
+ // NOTE: when eventually switching to CAMetalLayer, use the specialized
+ // CAMetalDisplayLink instead of CADisplayLink!
_sapp.macos.mtl_device = MTLCreateSystemDefaultDevice();
_sapp.macos.view = [[_sapp_macos_view alloc] init];
[_sapp.macos.view updateTrackingAreas];
@@ -3887,9 +4114,9 @@ _SOKOL_PRIVATE void _sapp_macos_mtl_discard_state(void) {
_SOKOL_PRIVATE bool _sapp_macos_mtl_update_framebuffer_dimensions(NSRect view_bounds) {
_sapp.framebuffer_width = _sapp_roundf_gzero(view_bounds.size.width * _sapp.dpi_scale);
_sapp.framebuffer_height = _sapp_roundf_gzero(view_bounds.size.height * _sapp.dpi_scale);
- const CGSize fb_size = _sapp.macos.view.drawableSize;
- int cur_fb_width = _sapp_roundf_gzero(fb_size.width);
- int cur_fb_height = _sapp_roundf_gzero(fb_size.height);
+ const CGSize cur_fb_size = _sapp.macos.view.drawableSize;
+ int cur_fb_width = _sapp_roundf_gzero(cur_fb_size.width);
+ int cur_fb_height = _sapp_roundf_gzero(cur_fb_size.height);
bool dim_changed = (_sapp.framebuffer_width != cur_fb_width) || (_sapp.framebuffer_height != cur_fb_height);
if (dim_changed) {
const CGSize drawable_size = { (CGFloat) _sapp.framebuffer_width, (CGFloat) _sapp.framebuffer_height };
@@ -3897,22 +4124,6 @@ _SOKOL_PRIVATE bool _sapp_macos_mtl_update_framebuffer_dimensions(NSRect view_bo
}
return dim_changed;
}
-
-_SOKOL_PRIVATE void _sapp_macos_mtl_on_window_will_start_live_resize(void) {
- // Work around the MTKView resizing glitch by "anchoring" the layer to the window corner opposite
- // to the currently manipulated corner (or edge). This prevents the content stretching back and
- // forth during resizing. This is a workaround for this issue: https://github.com/floooh/sokol/issues/700
- // Can be removed if/when migrating to CAMetalLayer: https://github.com/floooh/sokol/issues/727
- bool resizing_from_left = _sapp.mouse.x < _sapp.window_width/2;
- bool resizing_from_top = _sapp.mouse.y < _sapp.window_height/2;
- NSViewLayerContentsPlacement placement;
- if (resizing_from_left) {
- placement = resizing_from_top ? NSViewLayerContentsPlacementBottomRight : NSViewLayerContentsPlacementTopRight;
- } else {
- placement = resizing_from_top ? NSViewLayerContentsPlacementBottomLeft : NSViewLayerContentsPlacementTopLeft;
- }
- _sapp.macos.view.layerContentsPlacement = placement;
-}
#endif
#if defined(SOKOL_GLCORE)
@@ -3979,6 +4190,48 @@ _SOKOL_PRIVATE bool _sapp_macos_gl_update_framebuffer_dimensions(NSRect view_bou
}
#endif
+#if defined(SOKOL_WGPU)
+_SOKOL_PRIVATE void _sapp_macos_wgpu_init(void) {
+ NSInteger max_fps = _sapp_macos_max_fps();
+ _sapp.macos.wgpu.mtl_layer = [CAMetalLayer layer];
+ _sapp.macos.wgpu.mtl_layer.magnificationFilter = kCAFilterNearest;
+ _sapp.macos.wgpu.mtl_layer.opaque = true;
+ // NOTE: might experiment with this, valid values are 2 or 3 (default: 3), I don't see any difference tbh
+ // _sapp.macos.wgpu.mtl_layer.maximumDrawableCount = 2;
+ _sapp.macos.view = [[_sapp_macos_view alloc] init];
+ [_sapp.macos.view updateTrackingAreas];
+ _sapp.macos.view.wantsLayer = YES;
+ _sapp.macos.view.layer = _sapp.macos.wgpu.mtl_layer;
+ _sapp.macos.wgpu.display_link = [_sapp.macos.view displayLinkWithTarget:_sapp.macos.view selector:@selector(displayLinkFired:)];
+ float preferred_fps = max_fps / _sapp.swap_interval;
+ CAFrameRateRange frame_rate_range = { preferred_fps, preferred_fps, preferred_fps };
+ _sapp.macos.wgpu.display_link.preferredFrameRateRange = frame_rate_range;
+ [_sapp.macos.wgpu.display_link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
+ _sapp_wgpu_init();
+}
+
+_SOKOL_PRIVATE void _sapp_macos_wgpu_discard_state(void) {
+ _SAPP_OBJC_RELEASE(_sapp.macos.wgpu.display_link);
+ _SAPP_OBJC_RELEASE(_sapp.macos.wgpu.mtl_layer);
+ _sapp_wgpu_discard();
+}
+
+_SOKOL_PRIVATE bool _sapp_macos_wgpu_update_framebuffer_dimensions(NSRect view_bounds) {
+ _sapp.framebuffer_width = _sapp_roundf_gzero(view_bounds.size.width * _sapp.dpi_scale);
+ _sapp.framebuffer_height = _sapp_roundf_gzero(view_bounds.size.height * _sapp.dpi_scale);
+ const CGSize cur_fb_size = _sapp.macos.wgpu.mtl_layer.drawableSize;
+ int cur_fb_width = _sapp_roundf_gzero(cur_fb_size.width);
+ int cur_fb_height = _sapp_roundf_gzero(cur_fb_size.height);
+ bool dim_changed = (_sapp.framebuffer_width != cur_fb_width) || (_sapp.framebuffer_height != cur_fb_height);
+ if (dim_changed) {
+ const CGSize drawable_size = { (CGFloat) _sapp.framebuffer_width, (CGFloat) _sapp.framebuffer_height };
+ _sapp.macos.wgpu.mtl_layer.drawableSize = drawable_size;
+ _sapp_wgpu_swapchain_size_changed();
+ }
+ return dim_changed;
+}
+#endif
+
_SOKOL_PRIVATE void _sapp_macos_init_keytable(void) {
_sapp.keycodes[0x1D] = SAPP_KEYCODE_0;
_sapp.keycodes[0x12] = SAPP_KEYCODE_1;
@@ -4108,6 +4361,8 @@ _SOKOL_PRIVATE void _sapp_macos_discard_state(void) {
_sapp_macos_mtl_discard_state();
#elif defined(SOKOL_GLCORE)
_sapp_macos_gl_discard_state();
+ #elif defined(SOKOL_WGPU)
+ _sapp_macos_wgpu_discard_state();
#endif
_SAPP_OBJC_RELEASE(_sapp.macos.window);
}
@@ -4244,6 +4499,8 @@ _SOKOL_PRIVATE void _sapp_macos_update_dimensions(void) {
bool dim_changed = _sapp_macos_mtl_update_framebuffer_dimensions(bounds);
#elif defined(SOKOL_GLCORE)
bool dim_changed = _sapp_macos_gl_update_framebuffer_dimensions(bounds);
+ #elif defined(SOKOL_WGPU)
+ bool dim_changed = _sapp_macos_wgpu_update_framebuffer_dimensions(bounds);
#endif
if (dim_changed && !_sapp.first_frame) {
_sapp_macos_app_event(SAPP_EVENTTYPE_RESIZED);
@@ -4279,7 +4536,7 @@ _SOKOL_PRIVATE const char* _sapp_macos_get_clipboard_string(void) {
if (!str) {
return _sapp.clipboard.buffer;
}
- _sapp_strcpy([str UTF8String], _sapp.clipboard.buffer, _sapp.clipboard.buf_size);
+ _sapp_strcpy([str UTF8String], _sapp.clipboard.buffer, (size_t)_sapp.clipboard.buf_size);
}
return _sapp.clipboard.buffer;
}
@@ -4444,13 +4701,6 @@ _SOKOL_PRIVATE void _sapp_macos_set_icon(const sapp_icon_desc* icon_desc, int nu
CGImageRelease(cg_img);
}
-_SOKOL_PRIVATE void _sapp_macos_frame(void) {
- _sapp_frame();
- if (_sapp.quit_requested || _sapp.quit_ordered) {
- [_sapp.macos.window performClose:nil];
- }
-}
-
@implementation _sapp_macos_app_delegate
- (void)applicationDidFinishLaunching:(NSNotification*)aNotification {
_SOKOL_UNUSED(aNotification);
@@ -4487,6 +4737,8 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) {
_sapp_macos_mtl_init();
#elif defined(SOKOL_GLCORE)
_sapp_macos_gl_init(window_rect);
+ #elif defined(SOKOL_WGPU)
+ _sapp_macos_wgpu_init();
#endif
_sapp.macos.window.contentView = _sapp.macos.view;
[_sapp.macos.window makeFirstResponder:_sapp.macos.view];
@@ -4552,8 +4804,20 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) {
}
- (void)windowWillStartLiveResize:(NSNotification *)notification {
- #if defined(SOKOL_METAL)
- _sapp_macos_mtl_on_window_will_start_live_resize();
+ #if defined(SOKOL_METAL) || defined(SOKOL_WGPU)
+ // Work around the MTKView/CAMetalLayer resizing glitch by "anchoring" the layer to the window corner opposite
+ // to the currently manipulated corner (or edge). This prevents the content stretching back and
+ // forth during resizing. This is a workaround for this issue: https://github.com/floooh/sokol/issues/700
+ // Can be removed if/when migrating to CAMetalLayer: https://github.com/floooh/sokol/issues/727
+ bool resizing_from_left = _sapp.mouse.x < _sapp.window_width/2;
+ bool resizing_from_top = _sapp.mouse.y < _sapp.window_height/2;
+ NSViewLayerContentsPlacement placement;
+ if (resizing_from_left) {
+ placement = resizing_from_top ? NSViewLayerContentsPlacementBottomRight : NSViewLayerContentsPlacementTopRight;
+ } else {
+ placement = resizing_from_top ? NSViewLayerContentsPlacementBottomLeft : NSViewLayerContentsPlacementTopLeft;
+ }
+ _sapp.macos.view.layerContentsPlacement = placement;
#endif
}
@@ -4629,7 +4893,7 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) {
bool drop_failed = false;
for (int i = 0; i < _sapp.drop.num_files; i++) {
NSURL *fileUrl = [NSURL fileURLWithPath:[pboard.pasteboardItems[(NSUInteger)i] stringForType:NSPasteboardTypeFileURL]];
- if (!_sapp_strcpy(fileUrl.standardizedURL.path.UTF8String, _sapp_dropped_file_path_ptr(i), _sapp.drop.max_path_length)) {
+ if (!_sapp_strcpy(fileUrl.standardizedURL.path.UTF8String, _sapp_dropped_file_path_ptr(i), (size_t)_sapp.drop.max_path_length)) {
_SAPP_ERROR(DROPPED_FILE_PATH_TOO_LONG);
drop_failed = true;
break;
@@ -4668,18 +4932,38 @@ _SOKOL_PRIVATE void _sapp_macos_frame(void) {
}
#endif
+#if defined(SOKOL_WGPU)
+- (void)displayLinkFired:(id)sender {
+ _SOKOL_UNUSED(sender);
+ _sapp_timing_measure(&_sapp.timing);
+ @autoreleasepool {
+ _sapp_wgpu_frame();
+ }
+ if (_sapp.quit_requested || _sapp.quit_ordered) {
+ [_sapp.macos.window performClose:nil];
+ }
+}
+#endif
+
- (void)drawRect:(NSRect)rect {
_SOKOL_UNUSED(rect);
+ #if defined(SOKOL_WGPU)
+ // should never be called
+ return;
+ #endif
#if defined(_SAPP_ANY_GL)
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&_sapp.gl.framebuffer);
#endif
_sapp_timing_measure(&_sapp.timing);
@autoreleasepool {
- _sapp_macos_frame();
+ _sapp_frame();
}
#if defined(_SAPP_ANY_GL)
[[_sapp.macos.view openGLContext] flushBuffer];
#endif
+ if (_sapp.quit_requested || _sapp.quit_ordered) {
+ [_sapp.macos.window performClose:nil];
+ }
}
- (BOOL)isOpaque {
@@ -4878,6 +5162,7 @@ static void _sapp_gl_make_current(void) {
event.isARepeat,
_sapp_macos_mods(event));
}
+
- (void)flagsChanged:(NSEvent*)event {
const uint32_t old_f = _sapp.macos.flags_changed_store;
const uint32_t new_f = (uint32_t)event.modifierFlags;
@@ -5289,7 +5574,7 @@ typedef void (*_sapp_html5_fetch_callback) (const sapp_html5_fetch_response*);
EMSCRIPTEN_KEEPALIVE void _sapp_emsc_onpaste(const char* str) {
if (_sapp.clipboard.enabled) {
- _sapp_strcpy(str, _sapp.clipboard.buffer, _sapp.clipboard.buf_size);
+ _sapp_strcpy(str, _sapp.clipboard.buffer, (size_t)_sapp.clipboard.buf_size);
if (_sapp_events_enabled()) {
_sapp_init_event(SAPP_EVENTTYPE_CLIPBOARD_PASTED);
_sapp_call_event(&_sapp.event);
@@ -5328,7 +5613,7 @@ EMSCRIPTEN_KEEPALIVE void _sapp_emsc_drop(int i, const char* name) {
if ((i < 0) || (i >= _sapp.drop.num_files)) {
return;
}
- if (!_sapp_strcpy(name, _sapp_dropped_file_path_ptr(i), _sapp.drop.max_path_length)) {
+ if (!_sapp_strcpy(name, _sapp_dropped_file_path_ptr(i), (size_t)_sapp.drop.max_path_length)) {
_SAPP_ERROR(DROPPED_FILE_PATH_TOO_LONG);
_sapp.drop.num_files = 0;
}
@@ -5880,7 +6165,7 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_size_changed(int event_type, const EmscriptenU
emscripten_set_canvas_element_size(_sapp.html5_canvas_selector, _sapp.framebuffer_width, _sapp.framebuffer_height);
#if defined(SOKOL_WGPU)
// on WebGPU: recreate size-dependent rendering surfaces
- _sapp_wgpu_size_changed();
+ _sapp_wgpu_swapchain_size_changed();
#endif
if (_sapp_events_enabled()) {
_sapp_init_event(SAPP_EVENTTYPE_RESIZED);
@@ -6374,7 +6659,7 @@ _SOKOL_PRIVATE EM_BOOL _sapp_emsc_frame_animation_loop(double time, void* userDa
if (_sapp.quit_ordered) {
_sapp_emsc_unregister_eventhandlers();
#if defined(SOKOL_WGPU)
- _sapp_wgpu_discard_swapchain(false);
+ _sapp_wgpu_discard();
#endif
_sapp_call_cleanup();
_sapp_discard_state();
@@ -7888,6 +8173,26 @@ _SOKOL_PRIVATE void _sapp_win32_timing_measure(void) {
#endif
}
+_SOKOL_PRIVATE void _sapp_win32_frame(bool from_winproc) {
+ #if defined(SOKOL_WGPU)
+ _sapp_wgpu_frame();
+ #else
+ _sapp_frame();
+ #endif
+ #if defined(SOKOL_D3D11)
+ bool do_not_wait = from_winproc;
+ _sapp_d3d11_present(do_not_wait);
+ #endif
+ #if defined(SOKOL_GLCORE)
+ _sapp_wgl_swap_buffers();
+ #endif
+ if (!from_winproc) {
+ if (IsIconic(_sapp.win32.hwnd)) {
+ Sleep((DWORD)(16 * _sapp.swap_interval));
+ }
+ }
+}
+
_SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (!_sapp.win32.in_create_window) {
switch (uMsg) {
@@ -8079,14 +8384,7 @@ _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM
break;
case WM_TIMER:
_sapp_win32_timing_measure();
- _sapp_frame();
- #if defined(SOKOL_D3D11)
- // present with DXGI_PRESENT_DO_NOT_WAIT
- _sapp_d3d11_present(true);
- #endif
- #if defined(SOKOL_GLCORE)
- _sapp_wgl_swap_buffers();
- #endif
+ _sapp_win32_frame(true);
/* NOTE: resizing the swap-chain during resize leads to a substantial
memory spike (hundreds of megabytes for a few seconds).
@@ -8492,11 +8790,12 @@ _SOKOL_PRIVATE void _sapp_win32_run(const sapp_desc* desc) {
#if defined(SOKOL_D3D11)
_sapp_d3d11_create_device_and_swapchain();
_sapp_d3d11_create_default_render_target();
- #endif
- #if defined(SOKOL_GLCORE)
+ #elif defined(SOKOL_GLCORE)
_sapp_wgl_init();
_sapp_wgl_load_extensions();
_sapp_wgl_create_context();
+ #elif defined(SOKOL_WGPU)
+ _sapp_wgpu_init();
#endif
_sapp.valid = true;
@@ -8513,20 +8812,13 @@ _SOKOL_PRIVATE void _sapp_win32_run(const sapp_desc* desc) {
DispatchMessageW(&msg);
}
}
- _sapp_frame();
- #if defined(SOKOL_D3D11)
- _sapp_d3d11_present(false);
- if (IsIconic(_sapp.win32.hwnd)) {
- Sleep((DWORD)(16 * _sapp.swap_interval));
- }
- #endif
- #if defined(SOKOL_GLCORE)
- _sapp_wgl_swap_buffers();
- #endif
- /* check for window resized, this cannot happen in WM_SIZE as it explodes memory usage */
+ _sapp_win32_frame(false);
+ // check for window resized, this cannot happen in WM_SIZE as it explodes memory usage
if (_sapp_win32_update_dimensions()) {
#if defined(SOKOL_D3D11)
_sapp_d3d11_resize_default_render_target();
+ #elif defined(SOKOL_WGPU)
+ _sapp_wgpu_swapchain_size_changed();
#endif
_sapp_win32_app_event(SAPP_EVENTTYPE_RESIZED);
}
@@ -8550,6 +8842,8 @@ _SOKOL_PRIVATE void _sapp_win32_run(const sapp_desc* desc) {
#elif defined(SOKOL_GLCORE)
_sapp_wgl_destroy_context();
_sapp_wgl_shutdown();
+ #elif defined(SOKOL_WGPU)
+ _sapp_wgpu_discard();
#endif
_sapp_win32_destroy_window();
_sapp_win32_destroy_icons();
@@ -9296,7 +9590,7 @@ void ANativeActivity_onCreate(ANativeActivity* activity, void* saved_state, size
activity->callbacks->onInputQueueCreated = _sapp_android_on_input_queue_created;
activity->callbacks->onInputQueueDestroyed = _sapp_android_on_input_queue_destroyed;
/* activity->callbacks->onContentRectChanged = _sapp_android_on_content_rect_changed; */
- activity->callbacks->onConfigurationChanged = _sapp_android_on_config_changed;
+ /* activity->callbacks->onConfigurationChanged = _sapp_android_on_config_changed; */
activity->callbacks->onLowMemory = _sapp_android_on_low_memory;
_SAPP_INFO(ANDROID_NATIVE_ACTIVITY_CREATE_SUCCESS);
@@ -10843,7 +11137,7 @@ _SOKOL_PRIVATE void _sapp_glx_swapinterval(int interval) {
}
}
-#endif /* _SAPP_GLX */
+#endif // _SAPP_GLX
_SOKOL_PRIVATE void _sapp_x11_send_event(Atom type, int a, int b, int c, int d, int e) {
XEvent event;
@@ -10878,13 +11172,37 @@ _SOKOL_PRIVATE bool _sapp_x11_wait_for_event(int event_type, double timeout_sec,
return true;
}
-_SOKOL_PRIVATE void _sapp_x11_query_window_size(void) {
+_SOKOL_PRIVATE void _sapp_x11_app_event(sapp_event_type type) {
+ if (_sapp_events_enabled()) {
+ _sapp_init_event(type);
+ _sapp_call_event(&_sapp.event);
+ }
+}
+
+_SOKOL_PRIVATE void _sapp_x11_update_dimensions(int x11_window_width, int x11_window_height) {
+ // NOTE: do *NOT* use _sapp.dpi_scale for the window scale
+ const float window_scale = _sapp.x11.dpi / 96.0f;
+ _sapp.window_width = _sapp_roundf_gzero(x11_window_width / window_scale);
+ _sapp.window_height = _sapp_roundf_gzero(x11_window_height / window_scale);
+ int cur_fb_width = _sapp.framebuffer_width;
+ int cur_fb_height = _sapp.framebuffer_height;
+ _sapp.framebuffer_width = _sapp_roundf_gzero(_sapp.window_width * _sapp.dpi_scale);
+ _sapp.framebuffer_height = _sapp_roundf_gzero(_sapp.window_height * _sapp.dpi_scale);
+ bool dim_changed = (_sapp.framebuffer_width != cur_fb_width) || (_sapp.framebuffer_height != cur_fb_height);
+ if (dim_changed) {
+ #if defined(SOKOL_WGPU)
+ _sapp_wgpu_swapchain_size_changed();
+ #endif
+ if (!_sapp.first_frame) {
+ _sapp_x11_app_event(SAPP_EVENTTYPE_RESIZED);
+ }
+ }
+}
+
+_SOKOL_PRIVATE void _sapp_x11_update_dimensions_from_window_size(void) {
XWindowAttributes attribs;
XGetWindowAttributes(_sapp.x11.display, _sapp.x11.window, &attribs);
- _sapp.window_width = attribs.width;
- _sapp.window_height = attribs.height;
- _sapp.framebuffer_width = _sapp.window_width;
- _sapp.framebuffer_height = _sapp.window_height;
+ _sapp_x11_update_dimensions(attribs.width, attribs.height);
}
_SOKOL_PRIVATE void _sapp_x11_set_fullscreen(bool enable) {
@@ -10999,7 +11317,7 @@ _SOKOL_PRIVATE void _sapp_x11_destroy_custom_mouse_cursor(sapp_mouse_cursor curs
_SOKOL_PRIVATE void _sapp_x11_toggle_fullscreen(void) {
_sapp.fullscreen = !_sapp.fullscreen;
_sapp_x11_set_fullscreen(_sapp.fullscreen);
- _sapp_x11_query_window_size();
+ _sapp_x11_update_dimensions_from_window_size();
}
_SOKOL_PRIVATE void _sapp_x11_update_cursor(sapp_mouse_cursor cursor, bool shown) {
@@ -11121,7 +11439,7 @@ _SOKOL_PRIVATE const char* _sapp_x11_get_clipboard_string(void) {
XFree(data);
return NULL;
}
- _sapp_strcpy(data, _sapp.clipboard.buffer, _sapp.clipboard.buf_size);
+ _sapp_strcpy(data, _sapp.clipboard.buffer, (size_t)_sapp.clipboard.buf_size);
XFree(data);
return _sapp.clipboard.buffer;
}
@@ -11177,7 +11495,12 @@ _SOKOL_PRIVATE void _sapp_x11_set_icon(const sapp_icon_desc* icon_desc, int num_
XFlush(_sapp.x11.display);
}
-_SOKOL_PRIVATE void _sapp_x11_create_window(Visual* visual, int depth) {
+_SOKOL_PRIVATE void _sapp_x11_create_window(Visual* visual_or_null, int depth) {
+ Visual* visual = visual_or_null;
+ if (0 == visual_or_null) {
+ visual = DefaultVisual(_sapp.x11.display, _sapp.x11.screen);
+ depth = DefaultDepth(_sapp.x11.display, _sapp.x11.screen);
+ }
_sapp.x11.colormap = XCreateColormap(_sapp.x11.display, _sapp.x11.root, visual, AllocNone);
XSetWindowAttributes wa;
_sapp_clear(&wa, sizeof(wa));
@@ -11191,20 +11514,22 @@ _SOKOL_PRIVATE void _sapp_x11_create_window(Visual* visual, int depth) {
int display_width = DisplayWidth(_sapp.x11.display, _sapp.x11.screen);
int display_height = DisplayHeight(_sapp.x11.display, _sapp.x11.screen);
- int window_width = (int)(_sapp.window_width * _sapp.dpi_scale);
- int window_height = (int)(_sapp.window_height * _sapp.dpi_scale);
- if (0 == window_width) {
- window_width = (display_width * 4) / 5;
+ // NOTE: do *NOT* use _sapp.dpi_scale for the size multiplicator!
+ const float window_scale = _sapp.x11.dpi / 96.0f;
+ int x11_window_width = _sapp_roundf_gzero(_sapp.window_width * window_scale);
+ int x11_window_height = _sapp_roundf_gzero(_sapp.window_height * window_scale);
+ if (0 == _sapp.window_width) {
+ x11_window_width = (display_width * 4) / 5;
}
- if (0 == window_height) {
- window_height = (display_height * 4) / 5;
+ if (0 == _sapp.window_height) {
+ x11_window_height = (display_height * 4) / 5;
}
_sapp_x11_grab_error_handler();
_sapp.x11.window = XCreateWindow(_sapp.x11.display,
_sapp.x11.root,
0, 0,
- (uint32_t)window_width,
- (uint32_t)window_height,
+ (uint32_t)x11_window_width,
+ (uint32_t)x11_window_height,
0, /* border width */
depth, /* color depth */
InputOutput,
@@ -11233,7 +11558,7 @@ _SOKOL_PRIVATE void _sapp_x11_create_window(Visual* visual, int depth) {
XChangeProperty(_sapp.x11.display, _sapp.x11.window, _sapp.x11.xdnd.XdndAware, XA_ATOM, 32, PropModeReplace, (unsigned char*) &version, 1);
}
_sapp_x11_update_window_title();
- _sapp_x11_query_window_size();
+ _sapp_x11_update_dimensions_from_window_size();
}
_SOKOL_PRIVATE void _sapp_x11_destroy_window(void) {
@@ -11359,13 +11684,6 @@ _SOKOL_PRIVATE uint32_t _sapp_x11_mods(uint32_t x11_mods) {
return mods;
}
-_SOKOL_PRIVATE void _sapp_x11_app_event(sapp_event_type type) {
- if (_sapp_events_enabled()) {
- _sapp_init_event(type);
- _sapp_call_event(&_sapp.event);
- }
-}
-
_SOKOL_PRIVATE sapp_mousebutton _sapp_x11_translate_button(const XEvent* event) {
switch (event->xbutton.button) {
case Button1: return SAPP_MOUSEBUTTON_LEFT;
@@ -11377,8 +11695,8 @@ _SOKOL_PRIVATE sapp_mousebutton _sapp_x11_translate_button(const XEvent* event)
_SOKOL_PRIVATE void _sapp_x11_mouse_update(int x, int y, bool clear_dxdy) {
if (!_sapp.mouse.locked) {
- const float new_x = (float) x;
- const float new_y = (float) y;
+ const float new_x = (float)x;
+ const float new_y = (float)y;
if (clear_dxdy) {
_sapp.mouse.dx = 0.0f;
_sapp.mouse.dy = 0.0f;
@@ -11695,16 +12013,6 @@ _SOKOL_PRIVATE void _sapp_x11_on_motionnotify(XEvent* event) {
}
}
-_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) {
@@ -11922,9 +12230,6 @@ _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) {
case MotionNotify:
_sapp_x11_on_motionnotify(event);
break;
- case ConfigureNotify:
- _sapp_x11_on_configurenotify(event);
- break;
case PropertyNotify:
_sapp_x11_on_propertynotify(event);
break;
@@ -11943,18 +12248,18 @@ _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) {
}
}
-#if !defined(_SAPP_GLX)
+#if defined(_SAPP_EGL)
_SOKOL_PRIVATE void _sapp_egl_init(void) {
-#if defined(SOKOL_GLCORE)
- if (!eglBindAPI(EGL_OPENGL_API)) {
- _SAPP_PANIC(LINUX_EGL_BIND_OPENGL_API_FAILED);
- }
-#else
- if (!eglBindAPI(EGL_OPENGL_ES_API)) {
- _SAPP_PANIC(LINUX_EGL_BIND_OPENGL_ES_API_FAILED);
- }
-#endif
+ #if defined(SOKOL_GLCORE)
+ if (!eglBindAPI(EGL_OPENGL_API)) {
+ _SAPP_PANIC(LINUX_EGL_BIND_OPENGL_API_FAILED);
+ }
+ #else
+ if (!eglBindAPI(EGL_OPENGL_ES_API)) {
+ _SAPP_PANIC(LINUX_EGL_BIND_OPENGL_ES_API_FAILED);
+ }
+ #endif
_sapp.egl.display = eglGetDisplay((EGLNativeDisplayType)_sapp.x11.display);
if (EGL_NO_DISPLAY == _sapp.egl.display) {
@@ -12073,7 +12378,21 @@ _SOKOL_PRIVATE void _sapp_egl_destroy(void) {
}
}
-#endif /* _SAPP_GLX */
+#endif // _SAPP_EGL
+
+_SOKOL_PRIVATE void _sapp_linux_frame(void) {
+ _sapp_x11_update_dimensions_from_window_size();
+ #if defined(SOKOL_WGPU)
+ _sapp_wgpu_frame();
+ #else
+ _sapp_frame();
+ #if defined(_SAPP_GLX)
+ _sapp_glx_swap_buffers();
+ #elif defined(_SAPP_EGL)
+ eglSwapBuffers(_sapp.egl.display, _sapp.egl.surface);
+ #endif
+ #endif
+}
_SOKOL_PRIVATE void _sapp_linux_run(const sapp_desc* desc) {
/* The following lines are here to trigger a linker error instead of an
@@ -12096,22 +12415,26 @@ _SOKOL_PRIVATE void _sapp_linux_run(const sapp_desc* desc) {
_sapp.x11.screen = DefaultScreen(_sapp.x11.display);
_sapp.x11.root = DefaultRootWindow(_sapp.x11.display);
_sapp_x11_query_system_dpi();
+ // NOTE: on Linux system-window-size to frame-buffer-size mapping is always 1:1
_sapp.dpi_scale = _sapp.x11.dpi / 96.0f;
_sapp_x11_init_extensions();
_sapp_x11_create_standard_cursors();
XkbSetDetectableAutoRepeat(_sapp.x11.display, true, NULL);
_sapp_x11_init_keytable();
-#if defined(_SAPP_GLX)
- _sapp_glx_init();
- Visual* visual = 0;
- int depth = 0;
- _sapp_glx_choose_visual(&visual, &depth);
- _sapp_x11_create_window(visual, depth);
- _sapp_glx_create_context();
- _sapp_glx_swapinterval(_sapp.swap_interval);
-#else
- _sapp_egl_init();
-#endif
+ #if defined(_SAPP_GLX)
+ _sapp_glx_init();
+ Visual* visual = 0;
+ int depth = 0;
+ _sapp_glx_choose_visual(&visual, &depth);
+ _sapp_x11_create_window(visual, depth);
+ _sapp_glx_create_context();
+ _sapp_glx_swapinterval(_sapp.swap_interval);
+ #elif defined(_SAPP_EGL)
+ _sapp_egl_init();
+ #elif defined(SOKOL_WGPU)
+ _sapp_x11_create_window(0, 0);
+ _sapp_wgpu_init();
+ #endif
sapp_set_icon(&desc->icon);
_sapp.valid = true;
_sapp_x11_show_window();
@@ -12128,16 +12451,11 @@ _SOKOL_PRIVATE void _sapp_linux_run(const sapp_desc* desc) {
XNextEvent(_sapp.x11.display, &event);
_sapp_x11_process_event(&event);
}
- _sapp_frame();
-#if defined(_SAPP_GLX)
- _sapp_glx_swap_buffers();
-#else
- eglSwapBuffers(_sapp.egl.display, _sapp.egl.surface);
-#endif
+ _sapp_linux_frame();
XFlush(_sapp.x11.display);
- /* handle quit-requested, either from window or from sapp_request_quit() */
+ // handle quit-requested, either from window or from sapp_request_quit()
if (_sapp.quit_requested && !_sapp.quit_ordered) {
- /* give user code a chance to intervene */
+ // give user code a chance to intervene
_sapp_x11_app_event(SAPP_EVENTTYPE_QUIT_REQUESTED);
/* if user code hasn't intervened, quit the app */
if (_sapp.quit_requested) {
@@ -12146,11 +12464,13 @@ _SOKOL_PRIVATE void _sapp_linux_run(const sapp_desc* desc) {
}
}
_sapp_call_cleanup();
-#if defined(_SAPP_GLX)
- _sapp_glx_destroy_context();
-#else
- _sapp_egl_destroy();
-#endif
+ #if defined(_SAPP_GLX)
+ _sapp_glx_destroy_context();
+ #elif defined(_SAPP_EGL)
+ _sapp_egl_destroy();
+ #elif defined(SOKOL_WGPU)
+ _sapp_wgpu_discard();
+ #endif
_sapp_x11_destroy_window();
_sapp_x11_destroy_standard_cursors();
XCloseDisplay(_sapp.x11.display);
@@ -12280,7 +12600,7 @@ SOKOL_API_IMPL const void* sapp_egl_get_display(void) {
SOKOL_ASSERT(_sapp.valid);
#if defined(_SAPP_ANDROID)
return _sapp.android.display;
- #elif defined(_SAPP_LINUX) && !defined(_SAPP_GLX)
+ #elif defined(_SAPP_LINUX) && defined(_SAPP_EGL)
return _sapp.egl.display;
#else
return 0;
@@ -12291,7 +12611,7 @@ SOKOL_API_IMPL const void* sapp_egl_get_context(void) {
SOKOL_ASSERT(_sapp.valid);
#if defined(_SAPP_ANDROID)
return _sapp.android.context;
- #elif defined(_SAPP_LINUX) && !defined(_SAPP_GLX)
+ #elif defined(_SAPP_LINUX) && defined(_SAPP_EGL)
return _sapp.egl.context;
#else
return 0;
@@ -12470,7 +12790,7 @@ SOKOL_API_IMPL void sapp_set_clipboard_string(const char* str) {
#else
/* not implemented */
#endif
- _sapp_strcpy(str, _sapp.clipboard.buffer, _sapp.clipboard.buf_size);
+ _sapp_strcpy(str, _sapp.clipboard.buffer, (size_t)_sapp.clipboard.buf_size);
}
SOKOL_API_IMPL const char* sapp_get_clipboard_string(void) {
diff --git a/sokol_gfx.h b/sokol_gfx.h
index 48b1dc6e..b73ae516 100644
--- a/sokol_gfx.h
+++ b/sokol_gfx.h
@@ -15852,16 +15852,16 @@ _SOKOL_PRIVATE WGPUOptionalBool _sg_wgpu_optional_bool(bool b) {
_SOKOL_PRIVATE WGPUBufferUsage _sg_wgpu_buffer_usage(const sg_buffer_usage* usg) {
int res = 0;
if (usg->vertex_buffer) {
- res |= WGPUBufferUsage_Vertex;
+ res |= (int)WGPUBufferUsage_Vertex;
}
if (usg->index_buffer) {
- res |= WGPUBufferUsage_Index;
+ res |= (int)WGPUBufferUsage_Index;
}
if (usg->storage_buffer) {
- res |= WGPUBufferUsage_Storage;
+ res |= (int)WGPUBufferUsage_Storage;
}
if (!usg->immutable) {
- res |= WGPUBufferUsage_CopyDst;
+ res |= (int)WGPUBufferUsage_CopyDst;
}
return (WGPUBufferUsage)res;
}
@@ -16211,20 +16211,19 @@ _SOKOL_PRIVATE WGPUBlendFactor _sg_wgpu_blendfactor(sg_blend_factor f) {
}
}
-_SOKOL_PRIVATE WGPUColorWriteMask _sg_wgpu_colorwritemask(uint8_t m) {
- // FIXME: change to WGPUColorWriteMask once Emscripten and Dawn webgpu.h agree
+_SOKOL_PRIVATE WGPUColorWriteMask _sg_wgpu_colorwritemask(sg_color_mask m) {
int res = 0;
if (0 != (m & SG_COLORMASK_R)) {
- res |= WGPUColorWriteMask_Red;
+ res |= (int)WGPUColorWriteMask_Red;
}
if (0 != (m & SG_COLORMASK_G)) {
- res |= WGPUColorWriteMask_Green;
+ res |= (int)WGPUColorWriteMask_Green;
}
if (0 != (m & SG_COLORMASK_B)) {
- res |= WGPUColorWriteMask_Blue;
+ res |= (int)WGPUColorWriteMask_Blue;
}
if (0 != (m & SG_COLORMASK_A)) {
- res |= WGPUColorWriteMask_Alpha;
+ res |= (int)WGPUColorWriteMask_Alpha;
}
return (WGPUColorWriteMask)res;
}
@@ -16488,8 +16487,11 @@ _SOKOL_PRIVATE uint64_t _sg_wgpu_hash(const void* key, int len, uint64_t seed) {
}
switch(len) {
case 3: h2 ^= (uint32_t)(((unsigned char*)data)[2] << 16);
+ // fall through
case 2: h2 ^= (uint32_t)(((unsigned char*)data)[1] << 8);
+ // fall through
case 1: h2 ^= ((unsigned char*)data)[0];
+ // fall through
h2 *= m;
};
h1 ^= h2 >> 18; h1 *= m;
@@ -16733,7 +16735,7 @@ _SOKOL_PRIVATE void _sg_wgpu_bindings_cache_clear(void) {
}
_SOKOL_PRIVATE bool _sg_wgpu_bindings_cache_vb_dirty(size_t index, const _sg_buffer_t* vb, uint64_t offset) {
- SOKOL_ASSERT((index >= 0) && (index < SG_MAX_VERTEXBUFFER_BINDSLOTS));
+ SOKOL_ASSERT(index < SG_MAX_VERTEXBUFFER_BINDSLOTS);
if (vb) {
return (_sg.wgpu.bindings_cache.vbs[index].buffer.id != vb->slot.id)
|| (_sg.wgpu.bindings_cache.vbs[index].offset != offset);
@@ -16743,7 +16745,7 @@ _SOKOL_PRIVATE bool _sg_wgpu_bindings_cache_vb_dirty(size_t index, const _sg_buf
}
_SOKOL_PRIVATE void _sg_wgpu_bindings_cache_vb_update(size_t index, const _sg_buffer_t* vb, uint64_t offset) {
- SOKOL_ASSERT((index >= 0) && (index < SG_MAX_VERTEXBUFFER_BINDSLOTS));
+ SOKOL_ASSERT(index < SG_MAX_VERTEXBUFFER_BINDSLOTS);
if (vb) {
_sg.wgpu.bindings_cache.vbs[index].buffer.id = vb->slot.id;
_sg.wgpu.bindings_cache.vbs[index].offset = offset;
@@ -16788,7 +16790,7 @@ _SOKOL_PRIVATE void _sg_wgpu_bindings_cache_bg_update(const _sg_wgpu_bindgroup_t
}
}
-_SOKOL_PRIVATE void _sg_wgpu_set_bindgroup(size_t bg_idx, _sg_wgpu_bindgroup_t* bg) {
+_SOKOL_PRIVATE void _sg_wgpu_set_bindgroup(uint32_t bg_idx, _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);
@@ -16939,24 +16941,20 @@ _SOKOL_PRIVATE void _sg_wgpu_setup_backend(const sg_desc* desc) {
_sg.wgpu.empty_bind_group = wgpuDeviceCreateBindGroup(_sg.wgpu.dev, &bg_desc);
SOKOL_ASSERT(_sg.wgpu.empty_bind_group);
wgpuBindGroupLayoutRelease(empty_bgl);
-
- // create initial per-frame command encoder
- WGPUCommandEncoderDescriptor cmd_enc_desc;
- _sg_clear(&cmd_enc_desc, sizeof(cmd_enc_desc));
- _sg.wgpu.cmd_enc = wgpuDeviceCreateCommandEncoder(_sg.wgpu.dev, &cmd_enc_desc);
- SOKOL_ASSERT(_sg.wgpu.cmd_enc);
}
_SOKOL_PRIVATE void _sg_wgpu_discard_backend(void) {
SOKOL_ASSERT(_sg.wgpu.valid);
- SOKOL_ASSERT(_sg.wgpu.cmd_enc);
_sg.wgpu.valid = false;
_sg_wgpu_discard_all_bindgroups();
_sg_wgpu_bindgroups_cache_discard();
_sg_wgpu_bindgroups_pool_discard();
_sg_wgpu_uniform_buffer_discard();
wgpuBindGroupRelease(_sg.wgpu.empty_bind_group); _sg.wgpu.empty_bind_group = 0;
- wgpuCommandEncoderRelease(_sg.wgpu.cmd_enc); _sg.wgpu.cmd_enc = 0;
+ // the command encoder is usually released in sg_commit()
+ if (_sg.wgpu.cmd_enc) {
+ wgpuCommandEncoderRelease(_sg.wgpu.cmd_enc); _sg.wgpu.cmd_enc = 0;
+ }
wgpuQueueRelease(_sg.wgpu.queue); _sg.wgpu.queue = 0;
}
@@ -17020,11 +17018,11 @@ _SOKOL_PRIVATE void _sg_wgpu_copy_buffer_data(const _sg_buffer_t* buf, uint64_t
const uint64_t extra_src_offset = clamped_size;
const uint64_t extra_dst_offset = offset + clamped_size;
uint8_t extra_data[4] = { 0 };
- uint8_t* extra_src_ptr = ((uint8_t*)data->ptr) + extra_src_offset;
+ const uint8_t* extra_src_ptr = ((uint8_t*)data->ptr) + extra_src_offset;
for (size_t i = 0; i < extra_size; i++) {
extra_data[i] = extra_src_ptr[i];
}
- wgpuQueueWriteBuffer(_sg.wgpu.queue, buf->wgpu.buf, extra_dst_offset, extra_src_ptr, 4);
+ wgpuQueueWriteBuffer(_sg.wgpu.queue, buf->wgpu.buf, extra_dst_offset, extra_data, 4);
}
}
@@ -17308,8 +17306,8 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_shader(_sg_shader_t* shd, const
bg_entry->binding = bgl_entry->binding;
bg_entry->buffer = _sg.wgpu.uniform.buf;
bg_entry->size = _SG_WGPU_MAX_UNIFORM_UPDATE_SIZE;
- dynoffset_map[i].sokol_slot = i;
- dynoffset_map[i].wgpu_slot = bgl_entry->binding;
+ dynoffset_map[i].sokol_slot = (uint8_t)i;
+ dynoffset_map[i].wgpu_slot = (uint8_t)bgl_entry->binding;
bgl_index += 1;
}
bgl_desc.entryCount = bgl_index;
@@ -17326,7 +17324,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_wgpu_create_shader(_sg_shader_t* shd, const
// dynamic offsets of the WebGPU setBindGroup call must be in
// 'binding order', not 'bindgroup entry order'
qsort(dynoffset_map, bgl_index, sizeof(_sg_wgpu_dynoffset_mapping_t), _sg_wgpu_dynoffset_cmp);
- shd->wgpu.ub_num_dynoffsets = bgl_index;
+ shd->wgpu.ub_num_dynoffsets = (uint8_t)bgl_index;
for (uint8_t i = 0; i < bgl_index; i++) {
const uint8_t sokol_slot = dynoffset_map[i].sokol_slot;
shd->wgpu.ub_dynoffsets[sokol_slot] = i;
@@ -17710,10 +17708,17 @@ _SOKOL_PRIVATE void _sg_wgpu_begin_render_pass(const sg_pass* pass, const _sg_at
_SOKOL_PRIVATE void _sg_wgpu_begin_pass(const sg_pass* pass, const _sg_attachments_ptrs_t* atts) {
SOKOL_ASSERT(pass && atts);
SOKOL_ASSERT(_sg.wgpu.dev);
- SOKOL_ASSERT(_sg.wgpu.cmd_enc);
SOKOL_ASSERT(0 == _sg.wgpu.rpass_enc);
SOKOL_ASSERT(0 == _sg.wgpu.cpass_enc);
+ // first pass in the frame? create command encoder
+ if (0 == _sg.wgpu.cmd_enc) {
+ WGPUCommandEncoderDescriptor cmd_enc_desc;
+ _sg_clear(&cmd_enc_desc, sizeof(cmd_enc_desc));
+ _sg.wgpu.cmd_enc = wgpuDeviceCreateCommandEncoder(_sg.wgpu.dev, &cmd_enc_desc);
+ SOKOL_ASSERT(_sg.wgpu.cmd_enc);
+ }
+
_sg_wgpu_bindings_cache_clear();
if (pass->compute) {
_sg_wgpu_begin_compute_pass(pass);
@@ -17750,11 +17755,6 @@ _SOKOL_PRIVATE void _sg_wgpu_commit(void) {
wgpuQueueSubmit(_sg.wgpu.queue, 1, &wgpu_cmd_buf);
wgpuCommandBufferRelease(wgpu_cmd_buf);
-
- // create a new render-command-encoder for next frame
- WGPUCommandEncoderDescriptor cmd_enc_desc;
- _sg_clear(&cmd_enc_desc, sizeof(cmd_enc_desc));
- _sg.wgpu.cmd_enc = wgpuDeviceCreateCommandEncoder(_sg.wgpu.dev, &cmd_enc_desc);
}
_SOKOL_PRIVATE void _sg_wgpu_apply_viewport(int x, int y, int w, int h, bool origin_top_left) {