Commitb97e8deeRecorded20 Sep 2026Repositorysigil-graphics

Load GL through sigil-desktop and drop libGL, sokol_app.h and sokol_glue

Message

sigil-app is sigil-desktop 0.10 (GLFW; native Wayland or X11). This package now depends on it as name: "sigil-desktop" at the old URL (sigil-build derives a dependency's name from the URL until the Codeberg repository is renamed) and stops linking GL: sokol_gfx runs with SOKOL_EXTERNAL_GL_LOADER on every native target, and src/c/gl_native_loader.h, generated from the vendored sokol_gfx.h by scripts/gen-gl-loader.sh (sokol's own list of 122 entry points, the GL types and constants, the header guards), fills sokol's GL function pointers through sigil_desktop_gl_get_proc_address in gfx-setup. Linux link-flags are empty (were -lGL); darwin keeps OpenGL.framework and drops Metal and MetalKit, which nothing used.

graphics.c builds the environment and swapchain from sigil_desktop_framebuffer_size with the values sokol_app's GL backend reported, so sokol_glue.h and the sokol_app.h declaration include go; sokol_log's implementation moves here. gfx-setup raises a runtime error instead of crashing when there is no GL context.

test-shader-limits moves to (sigil desktop) and gains verify-wl.mjs, the same assertions captured through a headless sway. Measured: GREEN on Xvfb and on sway, both captures 0 pixels different from the sokol_app baseline; the binary's NEEDED list is libm, libc, ld-linux; under guix shell --pure -m guix/run-wayland.scm (mesa, wayland, libxkbcommon) it runs as a Wayland client with no LD_LIBRARY_PATH. manifest.scm lists the GLFW compile-time headers and drops libglvnd, whose vendorless libGLX.so.0 breaks GLFW's GLX on Guix. Version 0.11.4.

Changed
 CHANGELOG.md                                                    |    38 +
 README.md                                                       |    10 +-
 dev-redirects.sgl                                               |     6 +-
 manifest.scm                                                    |    32 +-
 package.sgl                                                     |    37 +-
 scripts/gen-gl-loader.sh                                        |   138 ++
 src/c/gl_native_loader.h                                        |   451 +++++
 src/c/graphics.c                                                |    77 +-
 src/c/sokol-graphics.c                                          |    62 +-
 test/test-shader-limits/README.md                               |    17 +
 test/test-shader-limits/dev-redirects.sgl                       |     9 +-
 test/test-shader-limits/package.sgl                             |     4 +-
 test/test-shader-limits/src/test-shader-limits/shell-native.sgl |     4 +-
 test/test-shader-limits/verify-wl.mjs                           |   446 ++++
 vendor/sokol/sokol_app.h                                        | 14047 ------------------------------------------------------------------------------------------------------------------------------
 vendor/sokol/sokol_glue.h                                       |   206 --
 16 files changed, 1250 insertions(+), 14334 deletions(-)
Diff
CHANGELOG.mdmodified
@@ -5,6 +5,44 @@ All notable changes to this project will be documented in this file.
5
The format is based on [Keep a Changelog](https://keepachangelog.com/),
6
and this project adheres to [Semantic Versioning](https://semver.org/).
7
+8
## [0.11.4] - unreleased
+9
+10
### Changed
+11
+12
- The window package is **sigil-desktop 0.10** (sigil-app renamed and
+13
rebuilt on GLFW: native Wayland or X11 on Linux, picked at startup).
+14
The dependency is `(from-git url: "codeberg:sigil/sigil-app"
+15
name: "sigil-desktop" version: "^0.10.0")` until the repository rename
+16
lands; the Sigil API of this package is unchanged.
+17
- **No libGL link, no GL headers.** sokol_gfx runs with
+18
`SOKOL_EXTERNAL_GL_LOADER` on every native target: `src/c/gl_native_loader.h`
+19
(generated from the vendored `sokol_gfx.h` by `scripts/gen-gl-loader.sh`,
+20
122 entry points) fills sokol's GL function pointers through
+21
`sigil_desktop_gl_get_proc_address` in `gfx-setup`. Linux `link-flags`
+22
are empty (were `-lGL`); Windows unchanged (none); darwin keeps
+23
`OpenGL.framework` and drops `Metal` and `MetalKit`, which nothing used.
+24
A game's NEEDED list is now libm, libc and the loader (plus whatever
+25
sigil-audio links).
+26
- `sokol_glue.h` and the `sokol_app.h` declaration include are gone. The
+27
native environment and swapchain are built in `graphics.c` from
+28
`sigil_desktop_framebuffer_size` with the values sokol_app's GL backend
+29
reported (RGBA8, depth-stencil, no MSAA, framebuffer 0). `sokol_log`'s
+30
implementation moved into this package.
+31
- `gfx-setup` raises `gfx-setup: no OpenGL context` when called outside
+32
`app-run` / `run-game` instead of crashing inside sokol.
+33
- `manifest.scm` lists the GLFW compile-time headers and drops `libglvnd`
+34
(Guix's mesa is built without it, and a vendorless `libGLX.so.0` on the
+35
library path breaks GLX at run time).
+36
+37
### Requires
+38
+39
- Sigil 0.20+ and sigil-desktop 0.10.0+.
+40
+41
### Upgrade notes
+42
+43
- Relock, delete `build/` once (a stale `sokol-app.o` otherwise stays in
+44
the consumer's `libsigil-app.a` archive), rebuild.
+45
46
## [0.11.0] - 2026-06-25
47
48
### Changed
README.mdmodified
@@ -14,12 +14,18 @@ Provides 2D rendering capabilities via sokol_gfx and sokol_gp, image loading (st
14
15
## System Prerequisites
16
−17
- OpenGL development headers (`libgl-dev` / `mesa-dev` on Linux, included with Xcode on macOS)
+17
- No GL headers: the GL entry points sokol_gfx calls are loaded at run
+18
time through sigil-desktop (`src/c/gl_native_loader.h`, generated from the
+19
vendored `sokol_gfx.h` by `scripts/gen-gl-loader.sh`), and nothing links
+20
libGL. Building sigil-desktop needs the X11 and Wayland headers listed in
+21
`manifest.scm`.
22
23
## Dependencies
24
25
- sigil-stdlib
−22
- sigil-app (sokol_app windowing)
+26
- sigil-desktop (the window, GL context and input; GLFW. Named sigil-app
+27
through 0.9.x, pinned here as `name: "sigil-desktop"` at the old URL until
+28
the Codeberg repository is renamed)
29
30
## Build
31
dev-redirects.sglmodified
@@ -1,4 +1,6 @@
−1
;; Development redirects — point dependencies at local checkouts
+1
;; Development redirects — point dependencies at local checkouts.
+2
;; sigil-desktop was named sigil-app through 0.9.x; the Codeberg repo is
+3
;; being renamed in place, so its URL stays until then.
4
(redirects
5
repos: (list
6
(for-repo
@@ -6,4 +8,4 @@
8
use: (from-path dir: "../sigil"))
9
(for-repo
10
url: "codeberg:sigil/sigil-app"
−9
use: (from-path dir: "../sigil-app"))))
+11
use: (from-path dir: "../sigil-desktop"))))
manifest.scmmodified
@@ -1,25 +1,33 @@
1
;; sigil-graphics - Development Environment
2
;; Use with: guix shell -m manifest.scm
3
;;
−4
;; Mirrors cinder-cantata's runtime surface (mesa, X11 stack, alsa,
−5
;; ogg/vorbis) so the smoke tests under test/ launch cleanly under
−6
;; sokol_app on Guix. libglvnd is what supplies <GL/gl.h> on modern
−7
;; Guix; mesa alone is not enough for headers, only for the runtime
−8
;; libGL.
+4
;; Build side: the X11 and Wayland headers sigil-desktop's vendored GLFW
+5
;; compiles against (it links none of them). No GL headers: the GL entry
+6
;; points come from src/c/gl_native_loader.h and are loaded at run time.
+7
;;
+8
;; Run side, for the smoke tests under test/: mesa (libGL, libEGL and the
+9
;; llvmpipe driver GLFW loads at run time), the X libraries GLFW dlopens
+10
;; under Xvfb, wayland + libxkbcommon for a Wayland compositor. libglvnd
+11
;; must NOT be here: Guix's mesa is built without it, and a vendorless
+12
;; libGLX.so.0 on the library path makes GLFW's GLX fail ("No GLXFBConfigs
+13
;; returned"). LD_LIBRARY_PATH=$GUIX_ENVIRONMENT/lib is still needed for
+14
;; libasound until sigil-audio stops linking it; the rest resolve through
+15
;; sigil-desktop's dlopen fallback ($GUIX_ENVIRONMENT/lib).
16
17
(specifications->manifest
18
'("gcc-toolchain"
19
"pkg-config"
20
"binutils"
21
−15
;; Graphics (sokol_gfx + sokol_app on Linux)
−16
"mesa" ; OpenGL implementation (libGL)
−17
"libglvnd" ; OpenGL dispatcher; provides GL/gl.h on modern Guix
−18
"libx11"
−19
"libxi"
−20
"libxcursor"
+22
;; GLFW compile-time headers (sigil-desktop)
+23
"libx11" "libxcursor" "libxrandr" "libxinerama" "libxi" "libxext" "xorgproto"
+24
"wayland" "libxkbcommon"
+25
+26
;; Run time: GL and the platform libraries GLFW loads
+27
"mesa"
+28
"libxrender"
29
−22
;; Audio (sokol_audio runtime — sigil-app pulls it in transitively)
+30
;; Audio (sokol_audio runtime — pulled in by test apps that use sigil-audio)
31
"alsa-lib"
32
33
;; OGG Vorbis (carried for parity with cinder's manifest, since
package.sglmodified
@@ -5,7 +5,7 @@
5
6
(package
7
name: "sigil-graphics"
−8
version: "0.11.3"
+8
version: "0.11.4"
9
sigil: "0.20"
10
description: "2D graphics, image loading, and font rendering for Sigil"
11
url: "https://codeberg.org/sigil/sigil-graphics"
@@ -39,7 +39,7 @@
39
40
;; Web (wasm32-wasi): the first-class graphics-on-web build. sokol_gfx's
41
;; GLES3 backend over the sigil-wasm-gles3 raw-WebGL2 binding, no Emscripten,
−42
;; no sokol_app (the app shell comes from the wasm bridge). sigil-app is
+42
;; no window package (the app shell comes from the wasm bridge). sigil-desktop is
43
;; excluded from this config's deps (config-conditional gating); the sokol
44
;; backend is self-selected in sokol-graphics.c via __wasm__.
45
(config
@@ -52,12 +52,16 @@
52
features: '(web wasm graphics)))
53
54
dependencies: (list
−55
;; sigil-app provides the native sokol_app window/loop + slog_func. It is a
−56
;; NATIVE-ONLY dep: its C (SOKOL_GLCORE + X11/Cocoa) cannot build for
−57
;; wasm32-wasi, and on web sigil-graphics needs nothing from it (the app
−58
;; shell + slog_func come from the wasm path). Config-conditional gating
−59
;; excludes it from the `web` build.
−60
(from-git url: "codeberg:sigil/sigil-app" version: "^0.9.0"
+55
;; sigil-desktop (the package named sigil-app through 0.9.x; the repo is
+56
;; being renamed in place on Codeberg, the old URL redirects) provides
+57
;; the window and GL context (GLFW) and the C surface this package
+58
;; builds its swapchain and GL loader on (include/sigil-desktop.h). It
+59
;; is a NATIVE-ONLY dep: its C cannot build for wasm32-wasi, and on web
+60
;; sigil-graphics needs nothing from it (the app shell comes from the
+61
;; wasm path). Config-conditional gating excludes it from `web`.
+62
;; name: is needed while the URL still says sigil-app: sigil-build derives
+63
;; the dependency name from the URL and looks the package up by it.
+64
(from-git url: "codeberg:sigil/sigil-app" name: "sigil-desktop" version: "^0.10.0"
65
configs: '(dev release windows-amd64))
66
;; Web-only: the raw-GLES3 WebGL2 binding. sigil-graphics' web C
67
;; (sokol-graphics.c under __wasm__) includes gl_shim.h — propagated here via
@@ -74,10 +78,15 @@
78
"src/c/graphics.c" "src/c/image.c" "src/c/font.c")
79
c-include-dirs: '("vendor/sokol" "vendor/stb")
80
native-init: "sigil__init_sigil_graphics_module"
−77
;; Platform-specific linker flags for OpenGL.
−78
;; Windows: sokol_gfx's GL backend loads opengl32.dll dynamically via
−79
;; LoadLibraryA + GetProcAddress (kernel32 — linked via sigil-app), so no
−80
;; extra link libs are needed beyond what sigil-app provides.
+81
;; Platform linker flags.
+82
;;
+83
;; Linux and Windows: none. GL entry points are loaded through
+84
;; sigil-desktop's proc loader (GLFW's glfwGetProcAddress) into
+85
;; gl_native_loader.h's pointers, and GLFW dlopens libGL / libEGL /
+86
;; opengl32.dll itself, so nothing GL-related is linked (was -lGL on
+87
;; Linux). Darwin: OpenGL.framework stays so GLFW's NSGL finds the
+88
;; bundle loaded (CFBundleGetBundleWithIdentifier); Metal and MetalKit
+89
;; are gone, nothing here is Metal (no macOS build has run yet).
90
;;
91
;; Procedural (lambda ctx) form so cross-compile configs evaluate
92
;; the right branch at link time. (case (host-os) ...) was evaluated
@@ -85,8 +94,8 @@
94
;; cross builds.
95
link-flags: (lambda (ctx)
96
(case (target-os ctx)
−88
((linux) '("-lGL"))
−89
((darwin) '("-framework" "OpenGL" "-framework" "Metal" "-framework" "MetalKit"))
+97
((linux) '())
+98
((darwin) '("-framework" "OpenGL"))
99
((windows) '())
100
(else '())))))
101
scripts/gen-gl-loader.shadded
@@ -0,0 +1,138 @@
+1
#!/bin/sh
+2
# gen-gl-loader.sh - regenerate src/c/gl_native_loader.h from vendor/sokol/sokol_gfx.h
+3
#
+4
# sokol_gfx's GL backend either includes the system GL headers (and links
+5
# libGL) or, on Win32, carries its own loader: GL types, constants and an
+6
# X-macro list of every GL function it calls. This script lifts those two
+7
# blocks out of the vendored header and emits a loader that fills the same
+8
# function pointers through a caller-supplied proc loader
+9
# (sigil_desktop_gl_get_proc_address, i.e. glfwGetProcAddress). The result
+10
# is what SOKOL_EXTERNAL_GL_LOADER expects on every native target, so no
+11
# GL header is needed to build and no libGL is linked.
+12
#
+13
# Run after every sokol_gfx.h bump; the counts below refuse a header whose
+14
# shape moved. Anchors are patterns, and each extraction is guarded by a
+15
# line count so a silent no-match cannot produce an empty header.
+16
set -eu
+17
cd "$(dirname "$0")/.."
+18
SRC=vendor/sokol/sokol_gfx.h
+19
OUT=src/c/gl_native_loader.h
+20
T=$(mktemp -d); trap 'rm -rf "$T"' EXIT
+21
+22
# 1. the types + constants block: from the first GL typedef after
+23
# "#define GL_APIENTRY APIENTRY" to the "#endif" that closes the
+24
# win32-loader-definitions block
+25
awk '
+26
/#define GL_APIENTRY APIENTRY/ { armed = 1; next }
+27
armed && !started && /typedef unsigned int GLenum;/ { started = 1 }
+28
started && /^ #endif/ { exit }
+29
started { sub(/^ /, ""); print }
+30
' "$SRC" > "$T/defs.h"
+31
N1=$(wc -l < "$T/defs.h")
+32
[ "$N1" -gt 200 ] && [ "$N1" -lt 400 ] || { echo "REFUSING: types+constants block is $N1 lines (expected 200..400)"; exit 1; }
+33
grep -q '^typedef unsigned int GLenum;' "$T/defs.h" || { echo "REFUSING: no GLenum typedef"; exit 1; }
+34
grep -q '^#define GL_RGBA16 ' "$T/defs.h" || { echo "REFUSING: constants block does not end where expected"; exit 1; }
+35
+36
# 2. the X-macro list: the body of _SG_GL_FUNCS, minus the SG_GL_FUNCS_EXT hook
+37
awk '
+38
/^#define _SG_GL_FUNCS \\$/ { started = 1; next }
+39
started && /SG_GL_FUNCS_EXT/ { next }
+40
started { print; if ($0 !~ /\\$/) exit }
+41
' "$SRC" | sed 's/_SG_XMACRO(/SIGIL_GL_XMACRO(/' > "$T/funcs.h"
+42
N2=$(grep -c 'SIGIL_GL_XMACRO(' "$T/funcs.h")
+43
[ "$N2" -gt 100 ] && [ "$N2" -lt 200 ] || { echo "REFUSING: function list has $N2 entries (expected 100..200)"; exit 1; }
+44
grep -q 'SIGIL_GL_XMACRO(glGenBuffers,' "$T/funcs.h" || { echo "REFUSING: glGenBuffers not in the function list"; exit 1; }
+45
# the last line must not end in a backslash (the macro closes there)
+46
tail -1 "$T/funcs.h" | grep -q '\\$' && { echo "REFUSING: function list did not close"; exit 1; }
+47
+48
{
+49
cat <<HDR
+50
/*
+51
* gl_native_loader.h - GL types, constants and entry points for sokol_gfx
+52
* without a system GL header or a libGL link.
+53
*
+54
* GENERATED by scripts/gen-gl-loader.sh from vendor/sokol/sokol_gfx.h
+55
* (sokol's own Win32 loader block); do not edit, regenerate after a sokol
+56
* bump. Included once, by sokol-graphics.c, ahead of sokol_gfx.h with
+57
* SOKOL_EXTERNAL_GL_LOADER defined. Every gl* sokol_gfx calls is a static
+58
* function pointer here, filled by sigil_gl_load() through a proc loader
+59
* (sigil_desktop_gl_get_proc_address, GLFW's glfwGetProcAddress) once the
+60
* window's GL context is current. $N2 functions, $N1 lines of definitions.
+61
*/
+62
#ifndef SIGIL_GL_NATIVE_LOADER_H
+63
#define SIGIL_GL_NATIVE_LOADER_H
+64
+65
#include <stddef.h>
+66
#include <stdint.h>
+67
+68
#if defined(_WIN32) && !defined(_WIN64)
+69
#define GL_APIENTRY __stdcall
+70
#else
+71
#define GL_APIENTRY
+72
#endif
+73
+74
/* The guards the system GL headers use, so a later include of any of them
+75
* (glfw3.h without GLFW_INCLUDE_NONE, say) defines nothing twice. */
+76
#define __gl_h_ 1
+77
#define __gl32_h_ 1
+78
#define __gl31_h_ 1
+79
#define __GL_H__ 1
+80
#define __glext_h_ 1
+81
#define __GLEXT_H_ 1
+82
#define __gltypes_h_ 1
+83
#define __glcorearb_h_ 1
+84
#define __gl_glcorearb_h_ 1
+85
+86
/* sokol_gfx enables its 3.2 / 4.2 / 4.3 code paths on these, as the system
+87
* headers (Mesa's glext.h) defined them before; the runtime check on the
+88
* context's reported version still gates their use. */
+89
#define GL_VERSION_3_2 1
+90
#define GL_VERSION_4_2 1
+91
#define GL_VERSION_4_3 1
+92
+93
/* ---- types and constants (from sokol_gfx.h) ---- */
+94
HDR
+95
cat "$T/defs.h"
+96
cat <<MID
+97
+98
/* ---- the entry points sokol_gfx calls (from sokol_gfx.h) ---- */
+99
#define SIGIL_GL_FUNCS \\
+100
MID
+101
cat "$T/funcs.h"
+102
cat <<'FTR'
+103
+104
#define SIGIL_GL_XMACRO(name, ret, args) typedef ret (GL_APIENTRY* PFN_ ## name) args;
+105
SIGIL_GL_FUNCS
+106
#undef SIGIL_GL_XMACRO
+107
+108
#define SIGIL_GL_XMACRO(name, ret, args) static PFN_ ## name name;
+109
SIGIL_GL_FUNCS
+110
#undef SIGIL_GL_XMACRO
+111
+112
typedef void *(*sigil_gl_proc_loader)(const char *name);
+113
+114
/* Fill every pointer through `load`. Returns the number left NULL: entry
+115
* points newer than the context (glTextureView on a 4.1 context, the
+116
* base-instance draws before 4.2) are expected to be missing and sokol_gfx
+117
* only calls them behind its feature checks; glGenBuffers or glGetIntegerv
+118
* missing means there is no usable context, and sigil_gl_ready() says so. */
+119
static int sigil_gl_load(sigil_gl_proc_loader load)
+120
{
+121
int missing = 0;
+122
#define SIGIL_GL_XMACRO(name, ret, args) \
+123
name = (PFN_ ## name)load(#name); if (!name) missing++;
+124
SIGIL_GL_FUNCS
+125
#undef SIGIL_GL_XMACRO
+126
return missing;
+127
}
+128
+129
static int sigil_gl_ready(void)
+130
{
+131
return glGetIntegerv != NULL && glClearBufferfv != NULL && glGenBuffers != NULL
+132
&& glCreateShader != NULL && glBindFramebuffer != NULL;
+133
}
+134
+135
#endif /* SIGIL_GL_NATIVE_LOADER_H */
+136
FTR
+137
} > "$OUT"
+138
echo "wrote $OUT: $N1 definition lines, $N2 functions, $(wc -l < "$OUT") lines total"
src/c/gl_native_loader.hadded
@@ -0,0 +1,451 @@
+1
/*
+2
* gl_native_loader.h - GL types, constants and entry points for sokol_gfx
+3
* without a system GL header or a libGL link.
+4
*
+5
* GENERATED by scripts/gen-gl-loader.sh from vendor/sokol/sokol_gfx.h
+6
* (sokol's own Win32 loader block); do not edit, regenerate after a sokol
+7
* bump. Included once, by sokol-graphics.c, ahead of sokol_gfx.h with
+8
* SOKOL_EXTERNAL_GL_LOADER defined. Every gl* sokol_gfx calls is a static
+9
* function pointer here, filled by sigil_gl_load() through a proc loader
+10
* (sigil_desktop_gl_get_proc_address, GLFW's glfwGetProcAddress) once the
+11
* window's GL context is current. 122 functions, 249 lines of definitions.
+12
*/
+13
#ifndef SIGIL_GL_NATIVE_LOADER_H
+14
#define SIGIL_GL_NATIVE_LOADER_H
+15
+16
#include <stddef.h>
+17
#include <stdint.h>
+18
+19
#if defined(_WIN32) && !defined(_WIN64)
+20
#define GL_APIENTRY __stdcall
+21
#else
+22
#define GL_APIENTRY
+23
#endif
+24
+25
/* The guards the system GL headers use, so a later include of any of them
+26
* (glfw3.h without GLFW_INCLUDE_NONE, say) defines nothing twice. */
+27
#define __gl_h_ 1
+28
#define __gl32_h_ 1
+29
#define __gl31_h_ 1
+30
#define __GL_H__ 1
+31
#define __glext_h_ 1
+32
#define __GLEXT_H_ 1
+33
#define __gltypes_h_ 1
+34
#define __glcorearb_h_ 1
+35
#define __gl_glcorearb_h_ 1
+36
+37
/* sokol_gfx enables its 3.2 / 4.2 / 4.3 code paths on these, as the system
+38
* headers (Mesa's glext.h) defined them before; the runtime check on the
+39
* context's reported version still gates their use. */
+40
#define GL_VERSION_3_2 1
+41
#define GL_VERSION_4_2 1
+42
#define GL_VERSION_4_3 1
+43
+44
/* ---- types and constants (from sokol_gfx.h) ---- */
+45
typedef unsigned int GLenum;
+46
typedef unsigned int GLuint;
+47
typedef int GLsizei;
+48
typedef char GLchar;
+49
typedef ptrdiff_t GLintptr;
+50
typedef ptrdiff_t GLsizeiptr;
+51
typedef double GLclampd;
+52
typedef unsigned short GLushort;
+53
typedef unsigned char GLubyte;
+54
typedef unsigned char GLboolean;
+55
typedef uint64_t GLuint64;
+56
typedef double GLdouble;
+57
typedef unsigned short GLhalf;
+58
typedef float GLclampf;
+59
typedef unsigned int GLbitfield;
+60
typedef signed char GLbyte;
+61
typedef short GLshort;
+62
typedef void GLvoid;
+63
typedef int64_t GLint64;
+64
typedef float GLfloat;
+65
typedef int GLint;
+66
#define GL_INT_2_10_10_10_REV 0x8D9F
+67
#define GL_R32F 0x822E
+68
#define GL_PROGRAM_POINT_SIZE 0x8642
+69
#define GL_DEPTH_ATTACHMENT 0x8D00
+70
#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
+71
#define GL_COLOR_ATTACHMENT0 0x8CE0
+72
#define GL_R16F 0x822D
+73
#define GL_DRAW_FRAMEBUFFER 0x8CA9
+74
#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
+75
#define GL_NUM_EXTENSIONS 0x821D
+76
#define GL_INFO_LOG_LENGTH 0x8B84
+77
#define GL_VERTEX_SHADER 0x8B31
+78
#define GL_INCR 0x1E02
+79
#define GL_DYNAMIC_DRAW 0x88E8
+80
#define GL_STATIC_DRAW 0x88E4
+81
#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
+82
#define GL_TEXTURE_CUBE_MAP 0x8513
+83
#define GL_FUNC_SUBTRACT 0x800A
+84
#define GL_FUNC_REVERSE_SUBTRACT 0x800B
+85
#define GL_CONSTANT_COLOR 0x8001
+86
#define GL_DECR_WRAP 0x8508
+87
#define GL_R8 0x8229
+88
#define GL_LINEAR_MIPMAP_LINEAR 0x2703
+89
#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+90
#define GL_SHORT 0x1402
+91
#define GL_DEPTH_TEST 0x0B71
+92
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
+93
#define GL_LINK_STATUS 0x8B82
+94
#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
+95
#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
+96
#define GL_RGBA16F 0x881A
+97
#define GL_CONSTANT_ALPHA 0x8003
+98
#define GL_READ_FRAMEBUFFER 0x8CA8
+99
#define GL_TEXTURE0 0x84C0
+100
#define GL_TEXTURE_MIN_LOD 0x813A
+101
#define GL_CLAMP_TO_EDGE 0x812F
+102
#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+103
#define GL_TEXTURE_WRAP_R 0x8072
+104
#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
+105
#define GL_NEAREST_MIPMAP_NEAREST 0x2700
+106
#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
+107
#define GL_SRC_ALPHA_SATURATE 0x0308
+108
#define GL_STREAM_DRAW 0x88E0
+109
#define GL_ONE 1
+110
#define GL_NEAREST_MIPMAP_LINEAR 0x2702
+111
#define GL_RGB10_A2 0x8059
+112
#define GL_RGBA8 0x8058
+113
#define GL_SRGB8_ALPHA8 0x8C43
+114
#define GL_RGBA4 0x8056
+115
#define GL_RGB8 0x8051
+116
#define GL_ARRAY_BUFFER 0x8892
+117
#define GL_STENCIL 0x1802
+118
#define GL_TEXTURE_2D 0x0DE1
+119
#define GL_DEPTH 0x1801
+120
#define GL_FRONT 0x0404
+121
#define GL_STENCIL_BUFFER_BIT 0x00000400
+122
#define GL_REPEAT 0x2901
+123
#define GL_RGBA 0x1908
+124
#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
+125
#define GL_DECR 0x1E03
+126
#define GL_FRAGMENT_SHADER 0x8B30
+127
#define GL_COMPUTE_SHADER 0x91B9
+128
#define GL_FLOAT 0x1406
+129
#define GL_TEXTURE_MAX_LOD 0x813B
+130
#define GL_DEPTH_COMPONENT 0x1902
+131
#define GL_ONE_MINUS_DST_ALPHA 0x0305
+132
#define GL_COLOR 0x1800
+133
#define GL_TEXTURE_2D_ARRAY 0x8C1A
+134
#define GL_TRIANGLES 0x0004
+135
#define GL_UNSIGNED_BYTE 0x1401
+136
#define GL_TEXTURE_MAG_FILTER 0x2800
+137
#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
+138
#define GL_NONE 0
+139
#define GL_SRC_COLOR 0x0300
+140
#define GL_BYTE 0x1400
+141
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
+142
#define GL_LINE_STRIP 0x0003
+143
#define GL_TEXTURE_3D 0x806F
+144
#define GL_CW 0x0900
+145
#define GL_LINEAR 0x2601
+146
#define GL_RENDERBUFFER 0x8D41
+147
#define GL_GEQUAL 0x0206
+148
#define GL_COLOR_BUFFER_BIT 0x00004000
+149
#define GL_RGBA32F 0x8814
+150
#define GL_BLEND 0x0BE2
+151
#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+152
#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
+153
#define GL_TEXTURE_WRAP_T 0x2803
+154
#define GL_TEXTURE_WRAP_S 0x2802
+155
#define GL_TEXTURE_MIN_FILTER 0x2801
+156
#define GL_LINEAR_MIPMAP_NEAREST 0x2701
+157
#define GL_EXTENSIONS 0x1F03
+158
#define GL_NO_ERROR 0
+159
#define GL_REPLACE 0x1E01
+160
#define GL_KEEP 0x1E00
+161
#define GL_CCW 0x0901
+162
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
+163
#define GL_RGB 0x1907
+164
#define GL_TRIANGLE_STRIP 0x0005
+165
#define GL_FALSE 0
+166
#define GL_ZERO 0
+167
#define GL_CULL_FACE 0x0B44
+168
#define GL_INVERT 0x150A
+169
#define GL_INT 0x1404
+170
#define GL_UNSIGNED_INT 0x1405
+171
#define GL_UNSIGNED_SHORT 0x1403
+172
#define GL_NEAREST 0x2600
+173
#define GL_SCISSOR_TEST 0x0C11
+174
#define GL_LEQUAL 0x0203
+175
#define GL_STENCIL_TEST 0x0B90
+176
#define GL_DITHER 0x0BD0
+177
#define GL_DEPTH_COMPONENT32F 0x8CAC
+178
#define GL_EQUAL 0x0202
+179
#define GL_FRAMEBUFFER 0x8D40
+180
#define GL_RGB5 0x8050
+181
#define GL_LINES 0x0001
+182
#define GL_DEPTH_BUFFER_BIT 0x00000100
+183
#define GL_SRC_ALPHA 0x0302
+184
#define GL_INCR_WRAP 0x8507
+185
#define GL_LESS 0x0201
+186
#define GL_MULTISAMPLE 0x809D
+187
#define GL_FRAMEBUFFER_BINDING 0x8CA6
+188
#define GL_BACK 0x0405
+189
#define GL_ALWAYS 0x0207
+190
#define GL_FUNC_ADD 0x8006
+191
#define GL_ONE_MINUS_DST_COLOR 0x0307
+192
#define GL_NOTEQUAL 0x0205
+193
#define GL_DST_COLOR 0x0306
+194
#define GL_COMPILE_STATUS 0x8B81
+195
#define GL_RED 0x1903
+196
#define GL_DST_ALPHA 0x0304
+197
#define GL_RGB5_A1 0x8057
+198
#define GL_GREATER 0x0204
+199
#define GL_POLYGON_OFFSET_FILL 0x8037
+200
#define GL_TRUE 1
+201
#define GL_NEVER 0x0200
+202
#define GL_POINTS 0x0000
+203
#define GL_ONE_MINUS_SRC_COLOR 0x0301
+204
#define GL_MIRRORED_REPEAT 0x8370
+205
#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+206
#define GL_R11F_G11F_B10F 0x8C3A
+207
#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B
+208
#define GL_RGB9_E5 0x8C3D
+209
#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E
+210
#define GL_RGBA32UI 0x8D70
+211
#define GL_RGB32UI 0x8D71
+212
#define GL_RGBA16UI 0x8D76
+213
#define GL_RGB16UI 0x8D77
+214
#define GL_RGBA8UI 0x8D7C
+215
#define GL_RGB8UI 0x8D7D
+216
#define GL_RGBA32I 0x8D82
+217
#define GL_RGB32I 0x8D83
+218
#define GL_RGBA16I 0x8D88
+219
#define GL_RGB16I 0x8D89
+220
#define GL_RGBA8I 0x8D8E
+221
#define GL_RGB8I 0x8D8F
+222
#define GL_RED_INTEGER 0x8D94
+223
#define GL_RG 0x8227
+224
#define GL_RG_INTEGER 0x8228
+225
#define GL_R8 0x8229
+226
#define GL_R16 0x822A
+227
#define GL_RG8 0x822B
+228
#define GL_RG16 0x822C
+229
#define GL_R16F 0x822D
+230
#define GL_R32F 0x822E
+231
#define GL_RG16F 0x822F
+232
#define GL_RG32F 0x8230
+233
#define GL_R8I 0x8231
+234
#define GL_R8UI 0x8232
+235
#define GL_R16I 0x8233
+236
#define GL_R16UI 0x8234
+237
#define GL_R32I 0x8235
+238
#define GL_R32UI 0x8236
+239
#define GL_RG8I 0x8237
+240
#define GL_RG8UI 0x8238
+241
#define GL_RG16I 0x8239
+242
#define GL_RG16UI 0x823A
+243
#define GL_RG32I 0x823B
+244
#define GL_RG32UI 0x823C
+245
#define GL_RGBA_INTEGER 0x8D99
+246
#define GL_R8_SNORM 0x8F94
+247
#define GL_RG8_SNORM 0x8F95
+248
#define GL_RGB8_SNORM 0x8F96
+249
#define GL_RGBA8_SNORM 0x8F97
+250
#define GL_R16_SNORM 0x8F98
+251
#define GL_RG16_SNORM 0x8F99
+252
#define GL_RGB16_SNORM 0x8F9A
+253
#define GL_RGBA16_SNORM 0x8F9B
+254
#define GL_RGBA16 0x805B
+255
#define GL_MAX_TEXTURE_SIZE 0x0D33
+256
#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
+257
#define GL_MAX_3D_TEXTURE_SIZE 0x8073
+258
#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF
+259
#define GL_MAX_VERTEX_ATTRIBS 0x8869
+260
#define GL_CLAMP_TO_BORDER 0x812D
+261
#define GL_TEXTURE_BORDER_COLOR 0x1004
+262
#define GL_CURRENT_PROGRAM 0x8B8D
+263
#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A
+264
#define GL_UNPACK_ALIGNMENT 0x0CF5
+265
#define GL_FRAMEBUFFER_SRGB 0x8DB9
+266
#define GL_TEXTURE_COMPARE_MODE 0x884C
+267
#define GL_TEXTURE_COMPARE_FUNC 0x884D
+268
#define GL_COMPARE_REF_TO_TEXTURE 0x884E
+269
#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F
+270
#define GL_TEXTURE_MAX_LEVEL 0x813D
+271
#define GL_FRAMEBUFFER_UNDEFINED 0x8219
+272
#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
+273
#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
+274
#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
+275
#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56
+276
#define GL_MAJOR_VERSION 0x821B
+277
#define GL_MINOR_VERSION 0x821C
+278
#define GL_TEXTURE_2D_MULTISAMPLE 0x9100
+279
#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102
+280
#define GL_SHADER_STORAGE_BARRIER_BIT 0x2000
+281
#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001
+282
#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002
+283
#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008
+284
#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
+285
#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400
+286
#define GL_MIN 0x8007
+287
#define GL_MAX 0x8008
+288
#define GL_WRITE_ONLY 0x88B9
+289
#define GL_READ_WRITE 0x88BA
+290
#define GL_MAX_DRAW_BUFFERS 0x8824
+291
#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
+292
#define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD
+293
#define GL_MAX_IMAGE_UNITS 0x8F38
+294
+295
/* ---- the entry points sokol_gfx calls (from sokol_gfx.h) ---- */
+296
#define SIGIL_GL_FUNCS \
+297
SIGIL_GL_XMACRO(glBindVertexArray, void, (GLuint array)) \
+298
SIGIL_GL_XMACRO(glFramebufferTextureLayer, void, (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer)) \
+299
SIGIL_GL_XMACRO(glGenFramebuffers, void, (GLsizei n, GLuint * framebuffers)) \
+300
SIGIL_GL_XMACRO(glBindFramebuffer, void, (GLenum target, GLuint framebuffer)) \
+301
SIGIL_GL_XMACRO(glBindRenderbuffer, void, (GLenum target, GLuint renderbuffer)) \
+302
SIGIL_GL_XMACRO(glGetStringi, const GLubyte *, (GLenum name, GLuint index)) \
+303
SIGIL_GL_XMACRO(glClearBufferfi, void, (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)) \
+304
SIGIL_GL_XMACRO(glClearBufferfv, void, (GLenum buffer, GLint drawbuffer, const GLfloat * value)) \
+305
SIGIL_GL_XMACRO(glClearBufferuiv, void, (GLenum buffer, GLint drawbuffer, const GLuint * value)) \
+306
SIGIL_GL_XMACRO(glClearBufferiv, void, (GLenum buffer, GLint drawbuffer, const GLint * value)) \
+307
SIGIL_GL_XMACRO(glDeleteRenderbuffers, void, (GLsizei n, const GLuint * renderbuffers)) \
+308
SIGIL_GL_XMACRO(glUniform1fv, void, (GLint location, GLsizei count, const GLfloat * value)) \
+309
SIGIL_GL_XMACRO(glUniform2fv, void, (GLint location, GLsizei count, const GLfloat * value)) \
+310
SIGIL_GL_XMACRO(glUniform3fv, void, (GLint location, GLsizei count, const GLfloat * value)) \
+311
SIGIL_GL_XMACRO(glUniform4fv, void, (GLint location, GLsizei count, const GLfloat * value)) \
+312
SIGIL_GL_XMACRO(glUniform1iv, void, (GLint location, GLsizei count, const GLint * value)) \
+313
SIGIL_GL_XMACRO(glUniform2iv, void, (GLint location, GLsizei count, const GLint * value)) \
+314
SIGIL_GL_XMACRO(glUniform3iv, void, (GLint location, GLsizei count, const GLint * value)) \
+315
SIGIL_GL_XMACRO(glUniform4iv, void, (GLint location, GLsizei count, const GLint * value)) \
+316
SIGIL_GL_XMACRO(glUniformMatrix4fv, void, (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value)) \
+317
SIGIL_GL_XMACRO(glUseProgram, void, (GLuint program)) \
+318
SIGIL_GL_XMACRO(glShaderSource, void, (GLuint shader, GLsizei count, const GLchar *const* string, const GLint * length)) \
+319
SIGIL_GL_XMACRO(glLinkProgram, void, (GLuint program)) \
+320
SIGIL_GL_XMACRO(glGetUniformLocation, GLint, (GLuint program, const GLchar * name)) \
+321
SIGIL_GL_XMACRO(glGetShaderiv, void, (GLuint shader, GLenum pname, GLint * params)) \
+322
SIGIL_GL_XMACRO(glGetProgramInfoLog, void, (GLuint program, GLsizei bufSize, GLsizei * length, GLchar * infoLog)) \
+323
SIGIL_GL_XMACRO(glGetAttribLocation, GLint, (GLuint program, const GLchar * name)) \
+324
SIGIL_GL_XMACRO(glDisableVertexAttribArray, void, (GLuint index)) \
+325
SIGIL_GL_XMACRO(glDeleteShader, void, (GLuint shader)) \
+326
SIGIL_GL_XMACRO(glDeleteProgram, void, (GLuint program)) \
+327
SIGIL_GL_XMACRO(glCompileShader, void, (GLuint shader)) \
+328
SIGIL_GL_XMACRO(glStencilFuncSeparate, void, (GLenum face, GLenum func, GLint ref, GLuint mask)) \
+329
SIGIL_GL_XMACRO(glStencilOpSeparate, void, (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass)) \
+330
SIGIL_GL_XMACRO(glRenderbufferStorageMultisample, void, (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)) \
+331
SIGIL_GL_XMACRO(glDrawBuffers, void, (GLsizei n, const GLenum * bufs)) \
+332
SIGIL_GL_XMACRO(glVertexAttribDivisor, void, (GLuint index, GLuint divisor)) \
+333
SIGIL_GL_XMACRO(glBufferSubData, void, (GLenum target, GLintptr offset, GLsizeiptr size, const void * data)) \
+334
SIGIL_GL_XMACRO(glGenBuffers, void, (GLsizei n, GLuint * buffers)) \
+335
SIGIL_GL_XMACRO(glCheckFramebufferStatus, GLenum, (GLenum target)) \
+336
SIGIL_GL_XMACRO(glFramebufferRenderbuffer, void, (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)) \
+337
SIGIL_GL_XMACRO(glCompressedTexImage2D, void, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void * data)) \
+338
SIGIL_GL_XMACRO(glCompressedTexImage3D, void, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void * data)) \
+339
SIGIL_GL_XMACRO(glActiveTexture, void, (GLenum texture)) \
+340
SIGIL_GL_XMACRO(glTexSubImage3D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * pixels)) \
+341
SIGIL_GL_XMACRO(glRenderbufferStorage, void, (GLenum target, GLenum internalformat, GLsizei width, GLsizei height)) \
+342
SIGIL_GL_XMACRO(glGenTextures, void, (GLsizei n, GLuint * textures)) \
+343
SIGIL_GL_XMACRO(glPolygonOffset, void, (GLfloat factor, GLfloat units)) \
+344
SIGIL_GL_XMACRO(glDrawElements, void, (GLenum mode, GLsizei count, GLenum type, const void * indices)) \
+345
SIGIL_GL_XMACRO(glDeleteFramebuffers, void, (GLsizei n, const GLuint * framebuffers)) \
+346
SIGIL_GL_XMACRO(glBlendEquationSeparate, void, (GLenum modeRGB, GLenum modeAlpha)) \
+347
SIGIL_GL_XMACRO(glDeleteTextures, void, (GLsizei n, const GLuint * textures)) \
+348
SIGIL_GL_XMACRO(glGetProgramiv, void, (GLuint program, GLenum pname, GLint * params)) \
+349
SIGIL_GL_XMACRO(glBindTexture, void, (GLenum target, GLuint texture)) \
+350
SIGIL_GL_XMACRO(glTexImage3D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void * pixels)) \
+351
SIGIL_GL_XMACRO(glCreateShader, GLuint, (GLenum type)) \
+352
SIGIL_GL_XMACRO(glTexSubImage2D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels)) \
+353
SIGIL_GL_XMACRO(glFramebufferTexture2D, void, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)) \
+354
SIGIL_GL_XMACRO(glCreateProgram, GLuint, (void)) \
+355
SIGIL_GL_XMACRO(glViewport, void, (GLint x, GLint y, GLsizei width, GLsizei height)) \
+356
SIGIL_GL_XMACRO(glDeleteBuffers, void, (GLsizei n, const GLuint * buffers)) \
+357
SIGIL_GL_XMACRO(glDrawArrays, void, (GLenum mode, GLint first, GLsizei count)) \
+358
SIGIL_GL_XMACRO(glDrawElementsInstanced, void, (GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount)) \
+359
SIGIL_GL_XMACRO(glVertexAttribPointer, void, (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer)) \
+360
SIGIL_GL_XMACRO(glVertexAttribIPointer, void, (GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer)) \
+361
SIGIL_GL_XMACRO(glUniform1i, void, (GLint location, GLint v0)) \
+362
SIGIL_GL_XMACRO(glDisable, void, (GLenum cap)) \
+363
SIGIL_GL_XMACRO(glColorMask, void, (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)) \
+364
SIGIL_GL_XMACRO(glColorMaski, void, (GLuint buf, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)) \
+365
SIGIL_GL_XMACRO(glBindBuffer, void, (GLenum target, GLuint buffer)) \
+366
SIGIL_GL_XMACRO(glDeleteVertexArrays, void, (GLsizei n, const GLuint * arrays)) \
+367
SIGIL_GL_XMACRO(glDepthMask, void, (GLboolean flag)) \
+368
SIGIL_GL_XMACRO(glDrawArraysInstanced, void, (GLenum mode, GLint first, GLsizei count, GLsizei instancecount)) \
+369
SIGIL_GL_XMACRO(glScissor, void, (GLint x, GLint y, GLsizei width, GLsizei height)) \
+370
SIGIL_GL_XMACRO(glGenRenderbuffers, void, (GLsizei n, GLuint * renderbuffers)) \
+371
SIGIL_GL_XMACRO(glBufferData, void, (GLenum target, GLsizeiptr size, const void * data, GLenum usage)) \
+372
SIGIL_GL_XMACRO(glBlendFuncSeparate, void, (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha)) \
+373
SIGIL_GL_XMACRO(glTexParameteri, void, (GLenum target, GLenum pname, GLint param)) \
+374
SIGIL_GL_XMACRO(glGetIntegerv, void, (GLenum pname, GLint * data)) \
+375
SIGIL_GL_XMACRO(glEnable, void, (GLenum cap)) \
+376
SIGIL_GL_XMACRO(glBlitFramebuffer, void, (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)) \
+377
SIGIL_GL_XMACRO(glStencilMask, void, (GLuint mask)) \
+378
SIGIL_GL_XMACRO(glAttachShader, void, (GLuint program, GLuint shader)) \
+379
SIGIL_GL_XMACRO(glGetError, GLenum, (void)) \
+380
SIGIL_GL_XMACRO(glBlendColor, void, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)) \
+381
SIGIL_GL_XMACRO(glTexParameterf, void, (GLenum target, GLenum pname, GLfloat param)) \
+382
SIGIL_GL_XMACRO(glTexParameterfv, void, (GLenum target, GLenum pname, const GLfloat* params)) \
+383
SIGIL_GL_XMACRO(glGetShaderInfoLog, void, (GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * infoLog)) \
+384
SIGIL_GL_XMACRO(glDepthFunc, void, (GLenum func)) \
+385
SIGIL_GL_XMACRO(glStencilOp , void, (GLenum fail, GLenum zfail, GLenum zpass)) \
+386
SIGIL_GL_XMACRO(glStencilFunc, void, (GLenum func, GLint ref, GLuint mask)) \
+387
SIGIL_GL_XMACRO(glEnableVertexAttribArray, void, (GLuint index)) \
+388
SIGIL_GL_XMACRO(glBlendFunc, void, (GLenum sfactor, GLenum dfactor)) \
+389
SIGIL_GL_XMACRO(glReadBuffer, void, (GLenum src)) \
+390
SIGIL_GL_XMACRO(glTexImage2D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * pixels)) \
+391
SIGIL_GL_XMACRO(glGenVertexArrays, void, (GLsizei n, GLuint * arrays)) \
+392
SIGIL_GL_XMACRO(glFrontFace, void, (GLenum mode)) \
+393
SIGIL_GL_XMACRO(glCullFace, void, (GLenum mode)) \
+394
SIGIL_GL_XMACRO(glPixelStorei, void, (GLenum pname, GLint param)) \
+395
SIGIL_GL_XMACRO(glBindSampler, void, (GLuint unit, GLuint sampler)) \
+396
SIGIL_GL_XMACRO(glGenSamplers, void, (GLsizei n, GLuint* samplers)) \
+397
SIGIL_GL_XMACRO(glSamplerParameteri, void, (GLuint sampler, GLenum pname, GLint param)) \
+398
SIGIL_GL_XMACRO(glSamplerParameterf, void, (GLuint sampler, GLenum pname, GLfloat param)) \
+399
SIGIL_GL_XMACRO(glSamplerParameterfv, void, (GLuint sampler, GLenum pname, const GLfloat* params)) \
+400
SIGIL_GL_XMACRO(glDeleteSamplers, void, (GLsizei n, const GLuint* samplers)) \
+401
SIGIL_GL_XMACRO(glBindBufferBase, void, (GLenum target, GLuint index, GLuint buffer)) \
+402
SIGIL_GL_XMACRO(glBindBufferRange, void, (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size)) \
+403
SIGIL_GL_XMACRO(glTexImage2DMultisample, void, (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations)) \
+404
SIGIL_GL_XMACRO(glTexImage3DMultisample, void, (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations)) \
+405
SIGIL_GL_XMACRO(glDispatchCompute, void, (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z)) \
+406
SIGIL_GL_XMACRO(glMemoryBarrier, void, (GLbitfield barriers)) \
+407
SIGIL_GL_XMACRO(glBindImageTexture, void, (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format)) \
+408
SIGIL_GL_XMACRO(glTexStorage2DMultisample, void, (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations)) \
+409
SIGIL_GL_XMACRO(glTexStorage2D, void, (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)) \
+410
SIGIL_GL_XMACRO(glTexStorage3DMultisample, void, (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations)) \
+411
SIGIL_GL_XMACRO(glTexStorage3D, void, (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)) \
+412
SIGIL_GL_XMACRO(glCompressedTexSubImage2D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data)) \
+413
SIGIL_GL_XMACRO(glCompressedTexSubImage3D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data)) \
+414
SIGIL_GL_XMACRO(glTextureView, void, (GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers)) \
+415
SIGIL_GL_XMACRO(glDrawElementsBaseVertex, void, (GLenum mode, GLsizei count, GLenum type, const void* indices, GLint basevertex)) \
+416
SIGIL_GL_XMACRO(glDrawElementsInstancedBaseVertex, void, (GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount, GLint basevertex)) \
+417
SIGIL_GL_XMACRO(glDrawElementsInstancedBaseVertexBaseInstance, void, (GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance)) \
+418
SIGIL_GL_XMACRO(glDrawArraysInstancedBaseInstance, void, (GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance))
+419
+420
#define SIGIL_GL_XMACRO(name, ret, args) typedef ret (GL_APIENTRY* PFN_ ## name) args;
+421
SIGIL_GL_FUNCS
+422
#undef SIGIL_GL_XMACRO
+423
+424
#define SIGIL_GL_XMACRO(name, ret, args) static PFN_ ## name name;
+425
SIGIL_GL_FUNCS
+426
#undef SIGIL_GL_XMACRO
+427
+428
typedef void *(*sigil_gl_proc_loader)(const char *name);
+429
+430
/* Fill every pointer through `load`. Returns the number left NULL: entry
+431
* points newer than the context (glTextureView on a 4.1 context, the
+432
* base-instance draws before 4.2) are expected to be missing and sokol_gfx
+433
* only calls them behind its feature checks; glGenBuffers or glGetIntegerv
+434
* missing means there is no usable context, and sigil_gl_ready() says so. */
+435
static int sigil_gl_load(sigil_gl_proc_loader load)
+436
{
+437
int missing = 0;
+438
#define SIGIL_GL_XMACRO(name, ret, args) \
+439
name = (PFN_ ## name)load(#name); if (!name) missing++;
+440
SIGIL_GL_FUNCS
+441
#undef SIGIL_GL_XMACRO
+442
return missing;
+443
}
+444
+445
static int sigil_gl_ready(void)
+446
{
+447
return glGetIntegerv != NULL && glClearBufferfv != NULL && glGenBuffers != NULL
+448
&& glCreateShader != NULL && glBindFramebuffer != NULL;
+449
}
+450
+451
#endif /* SIGIL_GL_NATIVE_LOADER_H */
src/c/graphics.cmodified
@@ -8,20 +8,18 @@
8
9
/* Sokol headers (implementation is in sokol-graphics.c).
10
*
−11
* On web (wasm32-wasi) there is no windowing system: sokol_app / sokol_glue are
−12
* replaced by the sigil-wasm-gles3 JS bridge (canvas + WebGL2 context +
−13
* swapchain). Those two headers are therefore excluded on the web build; every
−14
* sapp / sglue touch point is routed through the sig_gfx_ abstraction below,
−15
* whose native branch expands to the exact same calls as before. */
−16
#if !defined(__wasm__)
−17
#include "sokol_app.h"
−18
#endif
+11
* The window is a platform concern this file reaches only through the
+12
* sig_gfx_ abstraction below: natively sigil-desktop's C surface
+13
* (framebuffer size; the GL context is current from the init callback on),
+14
* on web (wasm32-wasi) the sigil-wasm-gles3 JS bridge (canvas + WebGL2
+15
* context + swapchain). Both build the sokol_gfx environment and swapchain
+16
* by hand; there is no sokol_glue. */
17
#include "sokol_gfx.h"
−20
#if !defined(__wasm__)
−21
#include "sokol_glue.h"
−22
#endif
18
#include "sokol_gp.h"
19
#include "sokol_log.h"
+20
#if !defined(__wasm__)
+21
#include "sigil-desktop.h"
+22
#endif
23
24
#include <stdio.h>
25
#include <stdlib.h>
@@ -31,12 +29,12 @@
29
#include <time.h>
30
#include <stdint.h>
31
−34
/* ---- platform abstraction: native (sokol_app/glue) vs web (GL bridge) -------
−35
* These four accessors are the ONLY sokol_app/sokol_glue touch points in this
−36
* file. Native expands to the exact sapp / sglue calls used before, so the
−37
* native build is behaviour-identical. Web supplies the default framebuffer
−38
* swapchain manually (lifted from the Milestone-1 wasm-sokol-sprite example) and
−39
* sources the canvas size from the sigil_wasm_gles3 app-shell import module. */
+32
/* ---- platform abstraction: native (sigil-desktop) vs web (GL bridge) --------
+33
* These four accessors are the ONLY window touch points in this file. Web
+34
* supplies the default framebuffer swapchain manually (lifted from the
+35
* Milestone-1 wasm-sokol-sprite example) and sources the canvas size from
+36
* the sigil_wasm_gles3 app-shell import module; native asks sigil-desktop
+37
* for the framebuffer size and reports the same formats sokol_app did. */
38
#if defined(__wasm__)
39
__attribute__((import_module("sigil_wasm_gles3"), import_name("canvas_width")))
40
extern int sigil_wasm_gles3_canvas_width(void);
@@ -64,10 +62,32 @@ static sg_swapchain sig_gfx_swapchain(void) {
62
return swap;
63
}
64
#else
−67
static inline int sig_gfx_width(void) { return sapp_width(); }
−68
static inline int sig_gfx_height(void) { return sapp_height(); }
−69
static inline sg_environment sig_gfx_environment(void) { return sglue_environment(); }
−70
static inline sg_swapchain sig_gfx_swapchain(void) { return sglue_swapchain(); }
+65
/* Native: sigil-desktop's framebuffer, and the values sokol_app's GL
+66
* backend used to report (RGBA8, a combined 24/8 depth-stencil buffer,
+67
* which is GLFW's default framebuffer, no MSAA, GL framebuffer 0). */
+68
static int sig_gfx_width(void) { int w = 1, h = 1; sigil_desktop_framebuffer_size(&w, &h); return w; }
+69
static int sig_gfx_height(void) { int w = 1, h = 1; sigil_desktop_framebuffer_size(&w, &h); return h; }
+70
+71
static sg_environment sig_gfx_environment(void) {
+72
sg_environment env = {0};
+73
env.defaults.color_format = SG_PIXELFORMAT_RGBA8;
+74
env.defaults.depth_format = SG_PIXELFORMAT_DEPTH_STENCIL;
+75
env.defaults.sample_count = 1;
+76
return env;
+77
}
+78
static sg_swapchain sig_gfx_swapchain(void) {
+79
sg_swapchain swap = {0};
+80
swap.width = sig_gfx_width();
+81
swap.height = sig_gfx_height();
+82
swap.sample_count = 1;
+83
swap.color_format = SG_PIXELFORMAT_RGBA8;
+84
swap.depth_format = SG_PIXELFORMAT_DEPTH_STENCIL;
+85
swap.gl.framebuffer = 0;
+86
return swap;
+87
}
+88
+89
/* sokol-graphics.c: fill sokol's GL entry points from the current context. */
+90
int sigil_graphics_load_gl(void);
91
#endif
92
93
#ifndef M_PI
@@ -263,6 +283,21 @@ static Value native_gfx_setup(SigilVM *vm, int argc, Value *args)
283
return SIGIL_NIL;
284
}
285
+286
#if !defined(__wasm__)
+287
/* Fill sokol's GL entry points from the window's context, which
+288
* sigil-desktop made current before the init callback ran. Without a
+289
* context (gfx-setup outside app-run) every pointer stays NULL and
+290
* sg_setup would crash on the first call, so refuse here instead. */
+291
{
+292
int missing = sigil_graphics_load_gl();
+293
if (missing) {
+294
sigil__vm_error(vm, SIGIL_ERR_RUNTIME,
+295
"gfx-setup: no OpenGL context; call it from the game thunk (inside run-game / app-run)");
+296
return SIGIL_UNDEFINED;
+297
}
+298
}
+299
#endif
+300
301
/* Initialize sokol_gfx. Install slog_func so validation failures
302
* print a useful diagnostic before sokol aborts. */
303
sg_desc desc = {
src/c/sokol-graphics.cmodified
@@ -1,19 +1,19 @@
1
/*
2
* sokol-graphics.c - Sokol implementation for sigil-graphics
3
*
−4
* Implements sokol_gfx and sokol_gp (and, on native, sokol_glue).
+4
* Implements sokol_gfx and sokol_gp (and, on native, sokol_log), with GL
+5
* entry points supplied by an external loader on both targets.
6
*
−6
* NATIVE (default): SOKOL_GLCORE. sokol_glue bridges sokol_app (implemented in
−7
* sigil-app) to sokol_gfx; sokol_app.h is included for declarations only, and
−8
* slog_func comes from sigil-app.
+7
* NATIVE (default): SOKOL_GLCORE + SOKOL_EXTERNAL_GL_LOADER. The window and
+8
* context are sigil-desktop's (GLFW); gl_native_loader.h fills sokol's GL
+9
* function pointers through sigil_desktop_gl_get_proc_address. No system GL
+10
* header, no libGL link.
11
*
−10
* WEB (wasm32-wasi, __wasm__): SOKOL_GLES3 + SOKOL_EXTERNAL_GL_LOADER (set via
−11
* the web build's -D flags). sokol's gl* calls resolve to WASM imports in the
−12
* "gl" module via gl_shim.h (shipped by sigil-wasm-gles3). There is no
−13
* sokol_app / sokol_glue on web — the canvas, WebGL2 context, and swapchain come
−14
* from the sigil-wasm-gles3 JS bridge (see graphics.c's sig_gfx_* abstraction),
−15
* so those headers are excluded and slog_func is provided here since sigil-app
−16
* is not linked on web.
+12
* WEB (wasm32-wasi, __wasm__): SOKOL_GLES3 + SOKOL_EXTERNAL_GL_LOADER. sokol's
+13
* gl* calls resolve to WASM imports in the "gl" module via gl_shim.h (shipped
+14
* by sigil-wasm-gles3). There is no window package on web: the canvas, WebGL2
+15
* context, and swapchain come from the sigil-wasm-gles3 JS bridge (see
+16
* graphics.c's sig_gfx_* abstraction), and slog_func is provided here.
17
*/
18
19
/* sgp's per-draw uniform buffer: 128 floats (512 B). Must equal
@@ -71,27 +71,41 @@ void slog_func(const char* tag, uint32_t log_level, uint32_t log_item_id,
71
72
#else
73
−74
/* Native: desktop GL core backend. Self-configured here (was previously set via
−75
* a -DSOKOL_GLCORE compiler flag; moved into the source so one build task serves
−76
* both native and web). #ifndef-guarded so a build/example still passing
−77
* -DSOKOL_GLCORE is conflict-free. Behaviour is identical: SOKOL_GLCORE ends up
−78
* defined either way. */
+74
/* Native: desktop GL core backend over sigil-desktop's window. GL comes in
+75
* through the generated loader (gl_native_loader.h: sokol's own list of
+76
* entry points, filled from sigil_desktop_gl_get_proc_address, which is
+77
* GLFW's glfwGetProcAddress), so this file needs no system GL header and
+78
* the package links no libGL; GLFW loads libGL/libEGL at run time. The
+79
* loader is the same shape as the web build's gl_shim.h, hence
+80
* SOKOL_EXTERNAL_GL_LOADER on both. */
81
#ifndef SOKOL_GLCORE
82
#define SOKOL_GLCORE
83
#endif
+84
#ifndef SOKOL_EXTERNAL_GL_LOADER
+85
#define SOKOL_EXTERNAL_GL_LOADER
+86
#endif
87
−83
/* Include sokol_app declarations WITHOUT implementation (implemented in sigil-app) */
−84
#include "sokol_app.h"
+88
#include "gl_native_loader.h"
+89
#include "sigil-desktop.h"
90
−86
/* Now define SOKOL_IMPL for the headers we implement */
+91
/* sokol_log's implementation lives here now (it was in sigil-app when the
+92
* window was sokol_app); graphics.c declares slog_func through sokol_log.h. */
93
#define SOKOL_IMPL
+94
#include "sokol_log.h"
95
−89
/* Order matters: gfx before glue, glue before gp */
+96
/* Order matters: gfx before gp. No sokol_glue: graphics.c builds the
+97
* environment and swapchain from sigil-desktop's framebuffer size. */
98
#include "sokol_gfx.h"
−91
#include "sokol_glue.h"
99
#include "sokol_gp.h"
−93
/* slog_func is implemented in sigil-app's archive (sigil-app's
−94
* sokol-app.c picks up SOKOL_LOG_IMPL via SOKOL_IMPL). graphics.c
−95
* just declares it via sokol_log.h. */
+100
+101
/* Called by graphics.c before sg_setup, with the window's context current.
+102
* Returns 0 when the core entry points are all present, else the count of
+103
* missing ones (and sokol cannot run). */
+104
int sigil_graphics_load_gl(void)
+105
{
+106
int missing = sigil_gl_load(sigil_desktop_gl_get_proc_address);
+107
if (!sigil_gl_ready()) return missing > 0 ? missing : 1;
+108
return 0;
+109
}
110
111
#endif
test/test-shader-limits/README.mdmodified
@@ -69,3 +69,20 @@ sabotage legs that showed each of those going red are in the task note
69
`tasks/sigil-graphics-shader-limits`. Frame timing under Xvfb (llvmpipe) and
70
SwiftShader is software rendering on both arms: it bounds the CPU-side cost of a
71
step, not what a phone's GPU will do.
+72
+73
## Wayland arm
+74
+75
`verify-wl.mjs` is the native arm for a Wayland compositor the caller owns
+76
(a headless sway); it captures the window through `swaymsg` and `grim`
+77
instead of `xdotool` and `import`, and pins the window to the child's pid.
+78
+79
```sh
+80
WAYLAND_DISPLAY=/run/user/$UID/<private>/wayland-1 SWAYSOCK=<its ipc socket> \
+81
guix shell -m ../../manifest.scm imagemagick grim jq -- \
+82
sh -c 'LD_LIBRARY_PATH=$GUIX_ENVIRONMENT/lib node verify-wl.mjs --native'
+83
```
+84
+85
With sigil-desktop 0.10 the binary's NEEDED list is libm and libc only, so
+86
`guix shell --pure -m <sigil-desktop>/guix/run-wayland.scm -- build/dev/bin/test-shader-limits`
+87
runs it with no LD_LIBRARY_PATH at all (the runtime libraries resolve
+88
through sigil-desktop's dlopen fallback).
test/test-shader-limits/dev-redirects.sglmodified
@@ -1,6 +1,11 @@
−1
;; Local sigil-graphics is the in-progress version under development.
+1
;; Local sigil-graphics is the in-progress version under development;
+2
;; sigil-desktop (URL still sigil-app until the Codeberg rename) is the
+3
;; sibling checkout.
4
(redirects
5
repos: (list
6
(for-repo
7
url: "codeberg:sigil/sigil-graphics"
−6
use: (from-path dir: "../.."))))
+8
use: (from-path dir: "../.."))
+9
(for-repo
+10
url: "codeberg:sigil/sigil-app"
+11
use: (from-path dir: "../../../sigil-desktop"))))
test/test-shader-limits/package.sglmodified
@@ -47,8 +47,8 @@
47
features: '(web wasm graphics)))
48
49
dependencies: (list
−50
;; Windowing, native only (sokol_app + X11 cannot build for wasm).
−51
(from-git url: "codeberg:sigil/sigil-app" version: "^0.9.0" configs: '(dev))
+50
;; Windowing, native only (GLFW cannot build for wasm).
+51
(from-git url: "codeberg:sigil/sigil-app" name: "sigil-desktop" version: "^0.10.0" configs: '(dev))
52
;; The package under test; dev-redirects.sgl points it at ../..
53
(from-git url: "codeberg:sigil/sigil-graphics" version: "^0.11.2")
54
;; Web only: the wasm runtime (loader + entry ABI) and the raw-WebGL2
test/test-shader-limits/src/test-shader-limits/shell-native.sglmodified
@@ -1,4 +1,4 @@
−1
;;; (test-shader-limits shell-native) - The sigil-app window.
+1
;;; (test-shader-limits shell-native) - The sigil-desktop window.
2
;;;
3
;;; test-shader-limits [--grid N] [--steps N] [--rule life|reaction] [--substeps N]
4
;;; [--bench] [--hold SECONDS]
@@ -12,7 +12,7 @@
12
(define-library (test-shader-limits shell-native)
13
(import (sigil core)
14
(sigil process)
−15
(sigil app)
+15
(sigil desktop)
16
(sigil graphics)
17
(test-shader-limits scene))
18
test/test-shader-limits/verify-wl.mjsadded
@@ -0,0 +1,446 @@
+1
// verify-wl.mjs - verify.mjs's native arm for a Wayland compositor: the same
+2
// scene, the same assertions, the window captured through the compositor
+3
// instead of an X server.
+4
//
+5
// node verify-wl.mjs --native [--bin ...] [--grid 64] [--steps 8] [--expect-steps N] [--shot PATH]
+6
//
+7
// Runs the binary with WAYLAND_DISPLAY pointing at a compositor the caller
+8
// owns (a headless sway: WLR_BACKENDS=headless sway -c <config>, see the
+9
// sigil-desktop notes), waits for "shader-limits: ready", finds the window
+10
// in `swaymsg -t get_tree` by name AND by the child's pid (a leftover window
+11
// from an earlier run must not be captured), and reads its rect with
+12
// `grim -g`. swaymsg, jq, grim, convert and identify must be on PATH; the
+13
// window must float without a border (a `for_window ... floating enable,
+14
// border none` rule) so the rect is the framebuffer. The assertions scale
+15
// with the capture, so an output at scale 2 (a 1280x960 capture of the
+16
// 640x480 window) passes the same checks.
+17
//
+18
// Everything below this header is verify.mjs; keep the two in step.
+19
+20
import http from "node:http";
+21
import fs from "node:fs";
+22
import path from "node:path";
+23
import { spawn, execFileSync } from "node:child_process";
+24
+25
const args = process.argv.slice(2);
+26
const flag = (name) => args.includes(name);
+27
const opt = (name, dflt) => { const i = args.indexOf(name); return i >= 0 ? args[i + 1] : dflt; };
+28
const VALUED = ["--bin", "--grid", "--steps", "--expect-steps", "--shot", "--port", "--cdp", "--reports", "--hold", "--rule", "--substeps"];
+29
const positional = args.filter((a, i) => !a.startsWith("--") && !(i > 0 && VALUED.includes(args[i - 1])));
+30
+31
const NATIVE = flag("--native");
+32
const WEB = flag("--web");
+33
const BENCH = flag("--bench");
+34
if (NATIVE === WEB) { console.log("usage: node verify.mjs --native | --web [options]"); process.exit(2); }
+35
const GRID = parseInt(opt("--grid", BENCH ? "512" : "64"), 10);
+36
const STEPS = parseInt(opt("--steps", "8"), 10);
+37
const EXPECT_STEPS = parseInt(opt("--expect-steps", String(STEPS)), 10);
+38
const SHOT = opt("--shot", `/tmp/test-shader-limits-${NATIVE ? "native" : "web"}.png`);
+39
const REPORTS = parseInt(opt("--reports", "3"), 10);
+40
const HOLD = parseInt(opt("--hold", "60"), 10);
+41
const RULE = opt("--rule", "life");
+42
const SUBSTEPS = parseInt(opt("--substeps", "1"), 10);
+43
const REACTION = RULE === "reaction";
+44
+45
// ---- the scene's geometry, mirrored from scene.sgl ---------------------------
+46
const VW = 640, VH = 480;
+47
const FIELD_X = 8, FIELD_Y = 8, FIELD_PX = 384;
+48
const PAL_X = 408, LEV_X = 440, STRIP = 24, STRIP_GAP = 28;
+49
const PIX_X = 408, PIX_Y = 260, PIX_SCALE = 16;
+50
const PALETTE = [[255, 0, 0], [0, 255, 0], [0, 0, 255], [255, 255, 0], [0, 255, 255], [255, 0, 255], [255, 128, 0], [128, 0, 255]];
+51
const LEVELS = [0, 64, 128, 255];
+52
const PATTERN_B = [
+53
[0, 255, 0], [255, 255, 0], [0, 255, 0], [255, 255, 0],
+54
[255, 255, 0], [255, 255, 255], [255, 255, 0], [0, 255, 0],
+55
[0, 255, 0], [255, 255, 0], [0, 0, 0], [255, 255, 0],
+56
[255, 255, 0], [0, 255, 0], [255, 255, 0], [0, 255, 0],
+57
];
+58
const PROBES = ["make-texture-size", "update-texture-size", "update-same-frame", "update-immutable",
+59
"shader-compile-error", "uniform-block-too-large", "uniform-too-many",
+60
"uniform-count", "uniform-scalar-for-array", "filter-name", "uniform-nested", "uniform-flat-vector"];
+61
+62
// The seed, as scene.sgl draws it, and a CPU Life on a torus.
+63
function seedGrid(n) {
+64
const g = new Uint8Array(n * n);
+65
const set = (x, y) => { g[((y + n) % n) * n + ((x + n) % n)] = 1; };
+66
const s = n - 3;
+67
set(s + 1, s); set(s + 2, s + 1); set(s, s + 2); set(s + 1, s + 2); set(s + 2, s + 2);
+68
set(9, 10); set(10, 10); set(11, 10);
+69
set(20, 20); set(21, 20); set(20, 21); set(21, 21);
+70
return g;
+71
}
+72
function lifeStep(g, n) {
+73
const out = new Uint8Array(n * n);
+74
for (let y = 0; y < n; y++) for (let x = 0; x < n; x++) {
+75
let c = 0;
+76
for (let dy = -1; dy <= 1; dy++) for (let dx = -1; dx <= 1; dx++) {
+77
if (dx || dy) c += g[((y + dy + n) % n) * n + ((x + dx + n) % n)];
+78
}
+79
const alive = g[y * n + x];
+80
out[y * n + x] = (c === 3 || (c === 2 && alive)) ? 1 : 0;
+81
}
+82
return out;
+83
}
+84
function expectedField(n, steps) { let g = seedGrid(n); for (let i = 0; i < steps; i++) g = lifeStep(g, n); return g; }
+85
+86
// ---- verdicts -------------------------------------------------------------------
+87
const results = [];
+88
const planned = (WEB ? ["imports"] : []).concat(["probes", "update", "ready", "field", "palette", "pixels", "gl-log"]).concat(WEB ? ["console"] : []);
+89
function pass(name, detail) { results.push([name, "PASS"]); console.log(`PASS ${name}${detail ? ": " + detail : ""}`); }
+90
function fail(name, detail) { results.push([name, "FAIL"]); console.log(`FAIL ${name}: ${detail}`); }
+91
function notRun() { const done = new Set(results.map((r) => r[0])); return planned.filter((p) => !done.has(p)); }
+92
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
+93
+94
// A captured frame: RGBA bytes, buffer size, and the virtual-to-buffer scale.
+95
// px(vx, vy) samples the buffer pixel under the centre of virtual pixel (vx, vy).
+96
function makeFrame(data, w, h) {
+97
const sx = w / VW, sy = h / VH;
+98
return {
+99
w, h, sx, sy,
+100
px(vx, vy) {
+101
const bx = Math.min(w - 1, Math.floor((vx + 0.5) * sx)), by = Math.min(h - 1, Math.floor((vy + 0.5) * sy));
+102
const i = (by * w + bx) * 4;
+103
return [data[i], data[i + 1], data[i + 2]];
+104
},
+105
};
+106
}
+107
const near = (a, b, tol) => Math.abs(a[0] - b[0]) <= tol && Math.abs(a[1] - b[1]) <= tol && Math.abs(a[2] - b[2]) <= tol;
+108
+109
function checkLines(lines) {
+110
// probes
+111
const seen = new Map();
+112
for (const l of lines) { const m = l.match(/^shader-limits: probe (\S+) (ok|FAIL)(.*)$/); if (m) seen.set(m[1], m[2] + m[3]); }
+113
const missing = PROBES.filter((p) => !seen.has(p));
+114
const failed = [...seen].filter(([, v]) => v.startsWith("FAIL")).map(([k, v]) => `${k}${v.slice(4)}`);
+115
if (!missing.length && !failed.length) pass("probes", `${PROBES.length} probes ok`);
+116
else fail("probes", `${missing.length ? "missing " + missing.join(",") + "; " : ""}${failed.length ? "failed: " + failed.join(" | ") : ""}`);
+117
// update
+118
const upd = lines.find((l) => /^shader-limits: update /.test(l));
+119
if (upd === "shader-limits: update ok") pass("update", "update-texture landed on frame 2");
+120
else fail("update", upd || "no update line");
+121
// ready
+122
const rdy = lines.map((l) => l.match(/^shader-limits: ready grid=(\d+) steps=(\d+)$/)).find(Boolean);
+123
if (rdy && parseInt(rdy[1], 10) === GRID && parseInt(rdy[2], 10) === EXPECT_STEPS) pass("ready", rdy[0]);
+124
else fail("ready", rdy ? `${rdy[0]} (expected grid=${GRID} steps=${EXPECT_STEPS})` : "no ready line");
+125
}
+126
+127
function checkFrame(frame) {
+128
if (REACTION) { checkReaction(frame); checkStripsAndPixels(frame); return; }
+129
// field
+130
const exp = expectedField(GRID, EXPECT_STEPS);
+131
const cell = FIELD_PX / GRID;
+132
let mismatches = 0, live = 0, seenLive = 0; const firstBad = [];
+133
for (let y = 0; y < GRID; y++) for (let x = 0; x < GRID; x++) {
+134
const c = frame.px(FIELD_X + x * cell + (cell - 1) / 2, FIELD_Y + y * cell + (cell - 1) / 2);
+135
const lit = c[0] > 128 ? 1 : 0;
+136
live += exp[y * GRID + x]; seenLive += lit;
+137
if (lit !== exp[y * GRID + x]) { mismatches++; if (firstBad.length < 6) firstBad.push(`(${x},${y}) got ${lit} want ${exp[y * GRID + x]}`); }
+138
}
+139
if (mismatches === 0 && live >= 12) pass("field", `${GRID}x${GRID} cells match a CPU Life after ${EXPECT_STEPS} steps; ${live} live cells (glider, blinker, block)`);
+140
else fail("field", `${mismatches} of ${GRID * GRID} cells differ (expected ${live} live, saw ${seenLive}); first: ${firstBad.join("; ")}`);
+141
checkStripsAndPixels(frame);
+142
}
+143
+144
function checkStripsAndPixels(frame) {
+145
// palette
+146
const bad = [];
+147
for (let i = 0; i < 8; i++) {
+148
const c = frame.px(PAL_X + STRIP / 2, 8 + i * STRIP_GAP + STRIP / 2);
+149
if (!near(c, PALETTE[i], 12)) bad.push(`palette[${i}] got ${c} want ${PALETTE[i]}`);
+150
}
+151
for (let i = 0; i < 4; i++) {
+152
const c = frame.px(LEV_X + STRIP / 2, 8 + i * STRIP_GAP + STRIP / 2);
+153
if (!near(c, [LEVELS[i], LEVELS[i], LEVELS[i]], 12)) bad.push(`levels[${i}] got ${c} want ${LEVELS[i]}`);
+154
}
+155
if (!bad.length) pass("palette", "8 vec4 palette entries and 4 float levels read back through the shader");
+156
else fail("palette", bad.join("; "));
+157
// pixels
+158
const badPx = [];
+159
for (let t = 0; t < 16; t++) {
+160
const tx = t % 4, ty = Math.floor(t / 4);
+161
const c = frame.px(PIX_X + tx * PIX_SCALE + PIX_SCALE / 2, PIX_Y + ty * PIX_SCALE + PIX_SCALE / 2);
+162
if (!near(c, PATTERN_B[t], 12)) badPx.push(`texel ${tx},${ty} got ${c} want ${PATTERN_B[t]}`);
+163
}
+164
if (!badPx.length) pass("pixels", "16 texels show the update-texture pattern");
+165
else fail("pixels", badPx.join("; "));
+166
}
+167
+168
// Gray-Scott has no closed form to compare against, so the reaction field is
+169
// judged by shape: v (the G channel) must have grown from three seed squares
+170
// (together 4.7% of the field) into a pattern covering between 6% and
+171
// 70% of the cells, while u (R) is still high somewhere (the field has not
+172
// saturated), and the pattern must not be one flat value.
+173
function checkReaction(frame) {
+174
const cell = FIELD_PX / GRID;
+175
let vHigh = 0, uHigh = 0; const vBins = new Set();
+176
for (let y = 0; y < GRID; y++) for (let x = 0; x < GRID; x++) {
+177
const c = frame.px(FIELD_X + x * cell + (cell - 1) / 2, FIELD_Y + y * cell + (cell - 1) / 2);
+178
if (c[1] > 64) vHigh++;
+179
if (c[0] > 192) uHigh++;
+180
vBins.add(c[1] >> 4);
+181
}
+182
const total = GRID * GRID, vf = vHigh / total, uf = uHigh / total;
+183
const detail = `v>0.25 on ${(vf * 100).toFixed(1)}% of cells, u>0.75 on ${(uf * 100).toFixed(1)}%, ${vBins.size} v levels`;
+184
// the three seed squares cover 3/64 = 4.7% of the field; growth past 6% is the pattern
+185
if (vf >= 0.06 && vf <= 0.7 && uf >= 0.2 && vBins.size >= 6) pass("field", `reaction pattern grew: ${detail}`);
+186
else fail("field", `no reaction pattern: ${detail}`);
+187
}
+188
+189
// sokol logs through slog_func: natively sigil-app's format `[sg][error][id:N] ...`
+190
// on stderr, on the web sigil-graphics' own `sokol[level=L] file:line [tag] msg`
+191
// on the console (level 0 panic, 1 error, 2 warning, 3 info; the web build
+192
// has no SOKOL_DEBUG (zig cc defines NDEBUG at -Oz, measured 2026-09-19 with
+193
// `zig cc -Oz -target wasm32-wasi -E` on an #ifdef NDEBUG probe) so the
+194
// message text is empty and the line number is
+195
// the pointer). A render target whose pass sokol refuses draws nothing and
+196
// says so only here, so any error-level line is a failure.
+197
// The shader-compile-error probe fails one GLSL compile on purpose, which
+198
// sokol reports as GL_SHADER_COMPILATION_FAILED (item id 7; sokol_gfx.h:10828
+199
// in the vendored header): exactly one such line is expected and exempt.
+200
const COMPILE_FAIL = (l) => /\[sg\]\[error\]\[id:7\]/.test(l) || /^sokol\[level=1\] \S+:10828 \[sg\]/.test(l);
+201
function checkGlLog(lines) {
+202
const all = lines.filter((l) => /\[(sg|sgp|sapp)\]\[(error|panic)\]/.test(l) || /^sokol\[level=[01]\]/.test(l));
+203
const expected = all.filter(COMPILE_FAIL);
+204
const bad = all.filter((l) => !COMPILE_FAIL(l)).concat(expected.slice(1));
+205
if (expected.length !== 1) bad.push(`expected exactly one deliberate compile failure line, saw ${expected.length}`);
+206
const warn = lines.filter((l) => /\[(sg|sgp)\]\[warning\]/.test(l) || /^sokol\[level=2\]/.test(l));
+207
if (!bad.length) pass("gl-log", `no sokol error lines beyond the one deliberate compile failure${warn.length ? "; " + warn.length + " warning(s): " + warn.slice(0, 3).join(" | ") : ""}`);
+208
else fail("gl-log", `${bad.length} sokol error line(s): ${bad.slice(0, 4).join(" | ")}`);
+209
}
+210
+211
function finish() {
+212
const failed = results.filter((r) => r[1] === "FAIL").length;
+213
const nr = notRun();
+214
console.log(`${failed ? "RED" : "GREEN"}: ${results.length - failed} pass, ${failed} fail${nr.length ? "; did not run: " + nr.join(" ") : ""}`);
+215
return failed || nr.length ? 1 : 0;
+216
}
+217
+218
// =============================================================================
+219
// NATIVE ARM
+220
// =============================================================================
+221
if (NATIVE) {
+222
const bin = path.resolve(opt("--bin", "build/dev/bin/test-shader-limits"));
+223
if (!fs.existsSync(bin)) { console.log(`SETUP-FAILED: ${bin} missing; build first`); process.exit(2); }
+224
if (!process.env.WAYLAND_DISPLAY) { console.log("SETUP-FAILED: WAYLAND_DISPLAY is not set; point it at a worker-owned headless sway"); process.exit(2); }
+225
for (const tool of ["swaymsg", "jq", "grim", "convert", "identify"]) {
+226
try { execFileSync("sh", ["-c", `command -v ${tool}`], { stdio: "ignore" }); }
+227
catch { console.log(`SETUP-FAILED: ${tool} is not on PATH (run inside guix shell -m ../../manifest.scm imagemagick xdotool)`); process.exit(2); }
+228
}
+229
const appArgs = ["--grid", String(GRID), "--steps", String(STEPS), "--hold", String(HOLD), "--rule", RULE, "--substeps", String(SUBSTEPS)].concat(BENCH ? ["--bench"] : []);
+230
const child = spawn(bin, appArgs, { stdio: ["ignore", "pipe", "pipe"], detached: true });
+231
const lines = [];
+232
let buf = "";
+233
child.stdout.on("data", (d) => { buf += d.toString(); let i; while ((i = buf.indexOf("\n")) >= 0) { lines.push(buf.slice(0, i)); buf = buf.slice(i + 1); } });
+234
const stderrLines = [];
+235
child.stderr.on("data", (d) => { for (const l of d.toString().split("\n")) if (l.trim()) stderrLines.push(l); });
+236
let exited = null;
+237
child.on("exit", (code, sig) => { exited = { code, sig }; });
+238
const stop = () => { try { process.kill(-child.pid, "SIGTERM"); } catch { /* gone */ } };
+239
process.on("exit", stop);
+240
+241
const waitLine = async (re, ms) => {
+242
const t0 = Date.now();
+243
while (Date.now() - t0 < ms) {
+244
const hit = lines.find((l) => re.test(l));
+245
if (hit) return hit;
+246
if (exited) return null;
+247
await sleep(100);
+248
}
+249
return null;
+250
};
+251
+252
if (BENCH) {
+253
const t0 = Date.now();
+254
while (Date.now() - t0 < HOLD * 1000 + 5000) {
+255
const reports = lines.filter((l) => /^shader-limits: frame-ms /.test(l));
+256
if (reports.length >= REPORTS || exited) break;
+257
await sleep(200);
+258
}
+259
console.log(`bench native grid=${GRID} (renderer: ${glRenderer()})`);
+260
for (const l of lines.filter((l) => /^shader-limits: (init|frame-ms) /.test(l))) console.log(" " + l);
+261
stop();
+262
process.exit(0);
+263
}
+264
+265
const ready = await waitLine(/^shader-limits: ready /, 30000);
+266
if (!ready) {
+267
console.log(`TIMED-OUT ready: no ready line in 30 s${exited ? ` (exited ${JSON.stringify(exited)})` : ""}; did not run: ${notRun().join(" ")}`);
+268
console.log("stdout so far:\n " + lines.join("\n ")); console.log("stderr so far:\n " + stderrLines.join("\n "));
+269
stop(); process.exit(2);
+270
}
+271
checkLines(lines);
+272
// The frame that shows the settled state was presented before the line
+273
// was printed, and the app keeps presenting it; one more frame's worth of
+274
// time makes sure the X server has it before the capture.
+275
await sleep(300);
+276
// WAYLAND ARM (scratch copy for the sigil-desktop-glfw spike): capture the
+277
// window through the compositor. swaymsg gives the window's rect on the
+278
// headless output; grim reads that region in output pixels.
+279
let rect = "";
+280
for (let i = 0; i < 50 && !rect; i++) {
+281
try {
+282
rect = execFileSync("sh", ["-c", `swaymsg -t get_tree | jq -r '.. | objects | select(.name? == "test-shader-limits" and .pid? == ${child.pid}) | "\\(.rect.x),\\(.rect.y) \\(.rect.width)x\\(.rect.height)"' | head -1`]).toString().trim();
+283
} catch { /* not yet */ }
+284
if (!rect) await sleep(100);
+285
}
+286
if (!rect) { console.log("SETUP-FAILED: no sway window named test-shader-limits; did not run: " + notRun().join(" ")); stop(); process.exit(2); }
+287
console.log(`note: sway window rect ${rect}`);
+288
execFileSync("grim", ["-g", rect, SHOT]);
+289
const [w, h] = execFileSync("identify", ["-format", "%w %h", SHOT]).toString().trim().split(" ").map(Number);
+290
const raw = execFileSync("convert", [SHOT, "-depth", "8", "rgba:-"], { maxBuffer: 64 * 1024 * 1024 });
+291
if (raw.length !== w * h * 4) { console.log(`SETUP-FAILED: raw dump is ${raw.length} bytes for ${w}x${h}`); stop(); process.exit(2); }
+292
console.log(`note: captured ${w}x${h} window to ${SHOT}`);
+293
checkFrame(makeFrame(raw, w, h));
+294
checkGlLog(stderrLines.concat(lines));
+295
stop();
+296
process.exit(finish());
+297
}
+298
+299
function glRenderer() {
+300
try { return execFileSync("sh", ["-c", "glxinfo -B 2>/dev/null | grep -i 'renderer string' | head -1"]).toString().trim() || "glxinfo unavailable"; }
+301
catch { return "glxinfo unavailable"; }
+302
}
+303
+304
// =============================================================================
+305
// WEB ARM
+306
// =============================================================================
+307
const ROOT = path.resolve(positional[0] || "build/web");
+308
const PORT = parseInt(opt("--port", "8097"), 10);
+309
const CDP = parseInt(opt("--cdp", "9237"), 10);
+310
const TYPES = { ".html": "text/html;charset=utf-8", ".js": "text/javascript;charset=utf-8", ".wasm": "application/wasm",
+311
".json": "application/json;charset=utf-8", ".css": "text/css;charset=utf-8", ".png": "image/png" };
+312
+313
// ---- imports, from the file on disk ------------------------------------------
+314
{
+315
const wasmPath = path.join(ROOT, "test-shader-limits.wasm");
+316
if (!fs.existsSync(wasmPath)) { console.log(`SETUP-FAILED imports: ${wasmPath} missing; build --config web first`); process.exit(2); }
+317
const mod = new WebAssembly.Module(fs.readFileSync(wasmPath));
+318
const byModule = {};
+319
for (const imp of WebAssembly.Module.imports(mod)) (byModule[imp.module] = byModule[imp.module] || []).push(imp.name);
+320
const modules = Object.keys(byModule).sort();
+321
const expected = ["gl", "sigil_wasm_gles3", "wasi_snapshot_preview1"];
+322
const listing = modules.map((m) => `${m}(${byModule[m].length})`).join(" ");
+323
if (JSON.stringify(modules) === JSON.stringify(expected)) pass("imports", listing);
+324
else fail("imports", `expected modules ${expected.join(",")} got ${listing}`);
+325
}
+326
+327
const server = http.createServer((req, res) => {
+328
const urlPath = decodeURIComponent((req.url || "/").split("?")[0]);
+329
const fp = path.join(ROOT, urlPath === "/" ? "/index.html" : urlPath);
+330
if (fp !== ROOT && !fp.startsWith(ROOT + path.sep)) { res.writeHead(403).end(); return; }
+331
fs.readFile(fp, (err, buf) => {
+332
if (err) { res.writeHead(404).end("not found: " + urlPath); return; }
+333
res.writeHead(200, { "Content-Type": TYPES[path.extname(fp)] || "application/octet-stream", "Cache-Control": "no-store" });
+334
res.end(buf);
+335
});
+336
});
+337
await new Promise((r) => server.listen(PORT, "127.0.0.1", r));
+338
+339
const udd = fs.mkdtempSync("/tmp/test-shader-limits-chrome-");
+340
const chrome = spawn("google-chrome", [
+341
"--headless=new", "--no-sandbox", "--disable-dev-shm-usage",
+342
"--use-gl=angle", "--use-angle=swiftshader", "--enable-unsafe-swiftshader",
+343
"--enable-webgl", "--ignore-gpu-blocklist",
+344
`--remote-debugging-port=${CDP}`, `--user-data-dir=${udd}`,
+345
"--window-size=800,600", "about:blank",
+346
], { stdio: "ignore", detached: true });
+347
function killChromeGroup(sig) { try { process.kill(-chrome.pid, sig); } catch { /* gone */ } }
+348
let exiting = false;
+349
function shutdown(code) {
+350
if (exiting) return; exiting = true;
+351
try { server.close(); } catch { /* not listening */ }
+352
killChromeGroup("SIGTERM");
+353
setTimeout(() => { killChromeGroup("SIGKILL"); try { fs.rmSync(udd, { recursive: true, force: true }); } catch { /* scratch */ } process.exit(code); }, 1500).unref();
+354
const done = () => { try { fs.rmSync(udd, { recursive: true, force: true }); } catch { /* scratch */ } process.exit(code); };
+355
if (chrome.exitCode !== null) done(); else chrome.once("exit", done);
+356
}
+357
process.on("exit", () => { killChromeGroup("SIGKILL"); try { fs.rmSync(udd, { recursive: true, force: true }); } catch { /* scratch */ } });
+358
process.on("SIGINT", () => shutdown(130));
+359
process.on("SIGTERM", () => shutdown(143));
+360
process.on("unhandledRejection", (err) => { console.log("EXCEPTION: " + (err && err.stack || err)); shutdown(2); });
+361
process.on("uncaughtException", (err) => { console.log("EXCEPTION: " + (err && err.stack || err)); shutdown(2); });
+362
setTimeout(() => { console.log(`TIMED-OUT whole run after 120 s; did not run: ${notRun().join(" ")}`); shutdown(2); }, 120000).unref();
+363
+364
let pageWs = null;
+365
for (let i = 0; i < 80 && !pageWs; i++) {
+366
try { const ts = await (await fetch(`http://127.0.0.1:${CDP}/json`)).json(); const p = ts.find((t) => t.type === "page"); if (p && p.webSocketDebuggerUrl) pageWs = p.webSocketDebuggerUrl; } catch { /* not up yet */ }
+367
await sleep(250);
+368
}
+369
if (!pageWs) { console.log("SETUP-FAILED: no chrome page target after 20 s; did not run: " + notRun().join(" ")); shutdown(2); }
+370
+371
const ws = new WebSocket(pageWs);
+372
let msgId = 0; const pending = new Map();
+373
const consoleLines = []; const consoleErrors = [];
+374
function send(method, params = {}) {
+375
return new Promise((res, rej) => { const id = ++msgId; pending.set(id, { res, rej }); ws.send(JSON.stringify({ id, method, params })); });
+376
}
+377
ws.addEventListener("message", (ev) => {
+378
const msg = JSON.parse(ev.data);
+379
if (msg.id && pending.has(msg.id)) { const { res, rej } = pending.get(msg.id); pending.delete(msg.id); msg.error ? rej(new Error(JSON.stringify(msg.error))) : res(msg.result); return; }
+380
if (msg.method === "Runtime.consoleAPICalled") {
+381
const text = (msg.params.args || []).map((a) => a.value ?? a.description ?? "").join(" ");
+382
consoleLines.push(text);
+383
if (msg.params.type === "error") consoleErrors.push("console.error: " + text);
+384
}
+385
if (msg.method === "Log.entryAdded" && msg.params.entry.level === "error") consoleErrors.push("log: " + msg.params.entry.text);
+386
if (msg.method === "Runtime.exceptionThrown") consoleErrors.push("exception: " + (msg.params.exceptionDetails?.exception?.description || msg.params.exceptionDetails?.text));
+387
});
+388
await new Promise((res, rej) => { ws.addEventListener("open", res); ws.addEventListener("error", rej); });
+389
await send("Page.enable"); await send("Runtime.enable"); await send("Log.enable");
+390
// A devicePixelRatio of 2 so the canvas buffer (1280x960) is not the virtual
+391
// size: the sampler's scale mapping is then exercised, not the identity.
+392
await send("Emulation.setDeviceMetricsOverride", { width: 800, height: 600, deviceScaleFactor: 2, mobile: false });
+393
+394
async function evalJS(expr) {
+395
const r = await send("Runtime.evaluate", { expression: expr, returnByValue: true, awaitPromise: true });
+396
if (r.exceptionDetails) throw new Error(JSON.stringify(r.exceptionDetails));
+397
return r.result.value;
+398
}
+399
async function waitLine(re, ms) {
+400
const t0 = Date.now();
+401
while (Date.now() - t0 < ms) { const hit = consoleLines.find((l) => re.test(l)); if (hit) return hit; await sleep(100); }
+402
return null;
+403
}
+404
+405
const query = `?grid=${GRID}&steps=${STEPS}&rule=${RULE}&substeps=${SUBSTEPS}${BENCH ? "&bench" : ""}`;
+406
await send("Page.navigate", { url: `http://127.0.0.1:${PORT}/index.html${query}` });
+407
+408
if (BENCH) {
+409
const t0 = Date.now();
+410
while (Date.now() - t0 < 90000) {
+411
if (consoleLines.filter((l) => /^shader-limits: frame-ms /.test(l)).length >= REPORTS) break;
+412
await sleep(200);
+413
}
+414
const renderer = await evalJS(`(() => { const c = document.createElement("canvas"); const gl = c.getContext("webgl2"); const d = gl && gl.getExtension("WEBGL_debug_renderer_info"); return d ? gl.getParameter(d.UNMASKED_RENDERER_WEBGL) : "unknown"; })()`);
+415
console.log(`bench web grid=${GRID} (renderer: ${renderer})`);
+416
for (const l of consoleLines.filter((l) => /^shader-limits: (init|frame-ms) /.test(l))) console.log(" " + l);
+417
shutdown(0);
+418
} else {
+419
const ready = await waitLine(/^shader-limits: ready /, 30000);
+420
if (!ready) {
+421
console.log(`TIMED-OUT ready: no ready line in 30 s; did not run: ${notRun().join(" ")}`);
+422
console.log("console so far:\n " + consoleLines.join("\n ") + "\nerrors:\n " + consoleErrors.join("\n "));
+423
shutdown(2);
+424
} else {
+425
checkLines(consoleLines);
+426
if (flag("--verbose")) console.log("console:\n " + consoleLines.join("\n "));
+427
// Read the canvas inside an animation frame: the app's tick registered
+428
// its next frame first, so a callback registered now runs after the draw
+429
// and before the (non-preserved) buffer is discarded.
+430
const px = await evalJS(`new Promise((resolve) => requestAnimationFrame(() => {
+431
const c = document.getElementById("stage");
+432
const off = document.createElement("canvas"); off.width = c.width; off.height = c.height;
+433
const g = off.getContext("2d"); g.drawImage(c, 0, 0);
+434
const d = g.getImageData(0, 0, c.width, c.height).data;
+435
resolve({ w: c.width, h: c.height, data: Array.from(d) });
+436
}))`);
+437
const shot = await send("Page.captureScreenshot", { format: "png" });
+438
fs.writeFileSync(SHOT, Buffer.from(shot.data, "base64"));
+439
console.log(`note: canvas buffer ${px.w}x${px.h}; page screenshot at ${SHOT}`);
+440
checkFrame(makeFrame(Uint8Array.from(px.data), px.w, px.h));
+441
checkGlLog(consoleLines);
+442
if (!consoleErrors.length) pass("console", "zero error entries, zero exceptions");
+443
else fail("console", consoleErrors.slice(0, 5).join(" | "));
+444
shutdown(finish());
+445
}
+446
}
vendor/sokol/sokol_app.hdeleted
@@ -1,14047 +0,0 @@
−1
#if defined(SOKOL_IMPL) && !defined(SOKOL_APP_IMPL)
−2
#define SOKOL_APP_IMPL
−3
#endif
−4
#ifndef SOKOL_APP_INCLUDED
−5
/*
−6
sokol_app.h -- cross-platform application wrapper
−7
−8
Project URL: https://github.com/floooh/sokol
−9
−10
Do this:
−11
#define SOKOL_IMPL or
−12
#define SOKOL_APP_IMPL
−13
before you include this file in *one* C or C++ file to create the
−14
implementation.
−15
−16
In the same place define one of the following to select the 3D-API
−17
which should be initialized by sokol_app.h (this must also match
−18
the backend selected for sokol_gfx.h if both are used in the same
−19
project):
−20
−21
#define SOKOL_GLCORE
−22
#define SOKOL_GLES3
−23
#define SOKOL_D3D11
−24
#define SOKOL_METAL
−25
#define SOKOL_WGPU
−26
#define SOKOL_NOAPI
−27
−28
Optionally provide the following defines with your own implementations:
−29
−30
SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
−31
SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false))
−32
SOKOL_WIN32_FORCE_MAIN - define this on Win32 to add a main() entry point
−33
SOKOL_WIN32_FORCE_WINMAIN - define this on Win32 to add a WinMain() entry point (enabled by default unless
−34
SOKOL_WIN32_FORCE_MAIN or SOKOL_NO_ENTRY is defined)
−35
SOKOL_NO_ENTRY - define this if sokol_app.h shouldn't "hijack" the main() function
−36
SOKOL_APP_API_DECL - public function declaration prefix (default: extern)
−37
SOKOL_API_DECL - same as SOKOL_APP_API_DECL
−38
SOKOL_API_IMPL - public function implementation prefix (default: -)
−39
−40
Optionally define the following to force debug checks and validations
−41
even in release mode:
−42
−43
SOKOL_DEBUG - by default this is defined if NDEBUG is not defined
−44
−45
If sokol_app.h is compiled as a DLL, define the following before
−46
including the declaration or implementation:
−47
−48
SOKOL_DLL
−49
−50
On Windows, SOKOL_DLL will define SOKOL_APP_API_DECL as __declspec(dllexport)
−51
or __declspec(dllimport) as needed.
−52
−53
if SOKOL_WIN32_FORCE_MAIN and SOKOL_WIN32_FORCE_WINMAIN are both defined,
−54
it is up to the developer to define the desired subsystem.
−55
−56
On Linux, SOKOL_GLCORE can use either GLX or EGL.
−57
GLX is default, set SOKOL_FORCE_EGL to override.
−58
−59
For example code, see https://github.com/floooh/sokol-samples/tree/master/sapp
−60
−61
Portions of the Windows and Linux GL initialization, event-, icon- etc... code
−62
have been taken from GLFW (http://www.glfw.org/).
−63
−64
iOS onscreen keyboard support 'inspired' by libgdx.
−65
−66
Link with the following system libraries:
−67
−68
- on macOS:
−69
- all backends: Foundation, Cocoa, QuartzCore
−70
- with SOKOL_METAL: Metal, MetalKit
−71
- with SOKOL_GLCORE: OpenGL
−72
- with SOKOL_WGPU: a WebGPU implementation library (tested with webgpu_dawn)
−73
- on iOS:
−74
- all backends: Foundation, UIKit
−75
- with SOKOL_METAL: Metal, MetalKit
−76
- with SOKOL_GLES3: OpenGLES, GLKit
−77
- on Linux:
−78
- all backends: X11, Xi, Xcursor, dl, pthread, m
−79
- with SOKOL_GLCORE: GL
−80
- with SOKOL_GLES3: GLESv2
−81
- with SOKOL_WGPU: a WebGPU implementation library (tested with webgpu_dawn)
−82
- with EGL: EGL
−83
- on Android: GLESv3, EGL, log, android
−84
- on Windows:
−85
- with MSVC or Clang: library dependencies are defined via `#pragma comment`
−86
- with SOKOL_WGPU: a WebGPU implementation library (tested with webgpu_dawn)
−87
- with MINGW/MSYS2 gcc:
−88
- compile with '-mwin32' so that _WIN32 is defined
−89
- link with the following libs: -lkernel32 -luser32 -lshell32
−90
- additionally with the GL backend: -lgdi32
−91
- additionally with the D3D11 backend: -ld3d11 -ldxgi
−92
−93
On Linux, you also need to use the -pthread compiler and linker option, otherwise weird
−94
things will happen, see here for details: https://github.com/floooh/sokol/issues/376
−95
−96
On macOS and iOS, the implementation must be compiled as Objective-C.
−97
−98
On Emscripten:
−99
- for WebGL2: add the linker option `-s USE_WEBGL2=1`
−100
- for WebGPU: compile and link with `--use-port=emdawnwebgpu`
−101
(for more exotic situations read: https://dawn.googlesource.com/dawn/+/refs/heads/main/src/emdawnwebgpu/pkg/README.md)
−102
−103
FEATURE OVERVIEW
−104
================
−105
sokol_app.h provides a minimalistic cross-platform API which
−106
implements the 'application-wrapper' parts of a 3D application:
−107
−108
- a common application entry function
−109
- creates a window and 3D-API context/device with a swapchain
−110
surface, depth-stencil-buffer surface and optionally MSAA surface
−111
- makes the rendered frame visible
−112
- provides keyboard-, mouse- and low-level touch-events
−113
- platforms: MacOS, iOS, HTML5, Win32, Linux/RaspberryPi, Android
−114
- 3D-APIs: Metal, D3D11, GL4.1, GL4.3, GLES3, WebGL2, WebGPU, NOAPI
−115
−116
FEATURE/PLATFORM MATRIX
−117
=======================
−118
| Windows | macOS | Linux | iOS | Android | HTML5
−119
--------------------+---------+-------+-------+-------+---------+--------
−120
gl 4.x | YES | YES | YES | --- | --- | ---
−121
gles3/webgl2 | --- | --- | YES(2)| YES | YES | YES
−122
metal | --- | YES | --- | YES | --- | ---
−123
d3d11 | YES | --- | --- | --- | --- | ---
−124
webgpu | YES(4) | YES(4)| YES(4)| NO | NO | YES
−125
noapi | YES | TODO | TODO | --- | TODO | ---
−126
KEY_DOWN | YES | YES | YES | SOME | TODO | YES
−127
KEY_UP | YES | YES | YES | SOME | TODO | YES
−128
CHAR | YES | YES | YES | YES | TODO | YES
−129
MOUSE_DOWN | YES | YES | YES | --- | --- | YES
−130
MOUSE_UP | YES | YES | YES | --- | --- | YES
−131
MOUSE_SCROLL | YES | YES | YES | --- | --- | YES
−132
MOUSE_MOVE | YES | YES | YES | --- | --- | YES
−133
MOUSE_ENTER | YES | YES | YES | --- | --- | YES
−134
MOUSE_LEAVE | YES | YES | YES | --- | --- | YES
−135
TOUCHES_BEGAN | --- | --- | --- | YES | YES | YES
−136
TOUCHES_MOVED | --- | --- | --- | YES | YES | YES
−137
TOUCHES_ENDED | --- | --- | --- | YES | YES | YES
−138
TOUCHES_CANCELLED | --- | --- | --- | YES | YES | YES
−139
RESIZED | YES | YES | YES | YES | YES | YES
−140
ICONIFIED | YES | YES | YES | --- | --- | ---
−141
RESTORED | YES | YES | YES | --- | --- | ---
−142
FOCUSED | YES | YES | YES | --- | --- | YES
−143
UNFOCUSED | YES | YES | YES | --- | --- | YES
−144
SUSPENDED | --- | --- | --- | YES | YES | TODO
−145
RESUMED | --- | --- | --- | YES | YES | TODO
−146
QUIT_REQUESTED | YES | YES | YES | --- | --- | YES
−147
IME | TODO | TODO? | TODO | ??? | TODO | ???
−148
key repeat flag | YES | YES | YES | --- | --- | YES
−149
windowed | YES | YES | YES | --- | --- | YES
−150
fullscreen | YES | YES | YES | YES | YES | YES(3)
−151
mouse hide | YES | YES | YES | --- | --- | YES
−152
mouse lock | YES | YES | YES | --- | --- | YES
−153
set cursor type | YES | YES | YES | --- | --- | YES
−154
screen keyboard | --- | --- | --- | YES | TODO | YES
−155
swap interval | YES | YES | YES | YES | TODO | YES
−156
high-dpi | YES | YES | TODO | YES | YES | YES
−157
clipboard | YES | YES | YES | --- | --- | YES
−158
MSAA | YES | YES | YES | YES | YES | YES
−159
drag'n'drop | YES | YES | YES | --- | --- | YES
−160
window icon | YES | YES(1)| YES | --- | --- | YES
−161
−162
(1) macOS has no regular window icons, instead the dock icon is changed
−163
(2) supported with EGL only (not GLX)
−164
(3) fullscreen in the browser not supported on iphones
−165
(4) WebGPU on native desktop platforms should be considered experimental
−166
and mainly useful for debugging and benchmarking
−167
−168
STEP BY STEP
−169
============
−170
--- Add a sokol_main() function to your code which returns a sapp_desc structure
−171
with initialization parameters and callback function pointers. This
−172
function is called very early, usually at the start of the
−173
platform's entry function (e.g. main or WinMain). You should do as
−174
little as possible here, since the rest of your code might be called
−175
from another thread (this depends on the platform):
−176
−177
sapp_desc sokol_main(int argc, char* argv[]) {
−178
return (sapp_desc) {
−179
.width = 640,
−180
.height = 480,
−181
.init_cb = my_init_func,
−182
.frame_cb = my_frame_func,
−183
.cleanup_cb = my_cleanup_func,
−184
.event_cb = my_event_func,
−185
...
−186
};
−187
}
−188
−189
To get any logging output in case of errors you need to provide a log
−190
callback. The easiest way is via sokol_log.h:
−191
−192
#include "sokol_log.h"
−193
−194
sapp_desc sokol_main(int argc, char* argv[]) {
−195
return (sapp_desc) {
−196
...
−197
.logger.func = slog_func,
−198
};
−199
}
−200
−201
There are many more setup parameters, but these are the most important.
−202
For a complete list search for the sapp_desc structure declaration
−203
below.
−204
−205
DO NOT call any sokol-app function from inside sokol_main(), since
−206
sokol-app will not be initialized at this point.
−207
−208
The .width and .height parameters are the preferred size of the 3D
−209
rendering canvas. The actual size may differ from this depending on
−210
platform and other circumstances. Also the canvas size may change at
−211
any time (for instance when the user resizes the application window,
−212
or rotates the mobile device). You can just keep .width and .height
−213
zero-initialized to open a default-sized window (what "default-size"
−214
exactly means is platform-specific, but usually it's a size that covers
−215
most of, but not all, of the display).
−216
−217
All provided function callbacks will be called from the same thread,
−218
but this may be different from the thread where sokol_main() was called.
−219
−220
.init_cb (void (*)(void))
−221
This function is called once after the application window,
−222
3D rendering context and swap chain have been created. The
−223
function takes no arguments and has no return value.
−224
.frame_cb (void (*)(void))
−225
This is the per-frame callback, which is usually called 60
−226
times per second. This is where your application would update
−227
most of its state and perform all rendering.
−228
.cleanup_cb (void (*)(void))
−229
The cleanup callback is called once right before the application
−230
quits.
−231
.event_cb (void (*)(const sapp_event* event))
−232
The event callback is mainly for input handling, but is also
−233
used to communicate other types of events to the application. Keep the
−234
event_cb struct member zero-initialized if your application doesn't require
−235
event handling.
−236
−237
As you can see, those 'standard callbacks' don't have a user_data
−238
argument, so any data that needs to be preserved between callbacks
−239
must live in global variables. If keeping state in global variables
−240
is not an option, there's an alternative set of callbacks with
−241
an additional user_data pointer argument:
−242
−243
.user_data (void*)
−244
The user-data argument for the callbacks below
−245
.init_userdata_cb (void (*)(void* user_data))
−246
.frame_userdata_cb (void (*)(void* user_data))
−247
.cleanup_userdata_cb (void (*)(void* user_data))
−248
.event_userdata_cb (void(*)(const sapp_event* event, void* user_data))
−249
−250
The function sapp_userdata() can be used to query the user_data
−251
pointer provided in the sapp_desc struct.
−252
−253
You can also call sapp_query_desc() to get a copy of the
−254
original sapp_desc structure.
−255
−256
NOTE that there's also an alternative compile mode where sokol_app.h
−257
doesn't "hijack" the main() function. Search below for SOKOL_NO_ENTRY.
−258
−259
--- Implement the initialization callback function (init_cb), this is called
−260
once after the rendering surface, 3D API and swap chain have been
−261
initialized by sokol_app. All sokol-app functions can be called
−262
from inside the initialization callback, the most useful functions
−263
at this point are:
−264
−265
int sapp_width(void)
−266
int sapp_height(void)
−267
Returns the current width and height of the default framebuffer in pixels,
−268
this may change from one frame to the next, and it may be different
−269
from the initial size provided in the sapp_desc struct.
−270
−271
float sapp_widthf(void)
−272
float sapp_heightf(void)
−273
These are alternatives to sapp_width() and sapp_height() which return
−274
the default framebuffer size as float values instead of integer. This
−275
may help to prevent casting back and forth between int and float
−276
in more strongly typed languages than C and C++.
−277
−278
double sapp_frame_duration(void)
−279
Returns the frame duration in seconds averaged over a number of
−280
frames to smooth out any jittering spikes.
−281
−282
int sapp_color_format(void)
−283
int sapp_depth_format(void)
−284
The color and depth-stencil pixelformats of the default framebuffer,
−285
as integer values which are compatible with sokol-gfx's
−286
sg_pixel_format enum (so that they can be plugged directly in places
−287
where sg_pixel_format is expected). Possible values are:
−288
−289
23 == SG_PIXELFORMAT_RGBA8
−290
28 == SG_PIXELFORMAT_BGRA8
−291
42 == SG_PIXELFORMAT_DEPTH
−292
43 == SG_PIXELFORMAT_DEPTH_STENCIL
−293
−294
int sapp_sample_count(void)
−295
Return the MSAA sample count of the default framebuffer.
−296
−297
const void* sapp_metal_get_device(void)
−298
const void* sapp_metal_get_current_drawable(void)
−299
const void* sapp_metal_get_depth_stencil_texture(void)
−300
const void* sapp_metal_get_msaa_color_texture(void)
−301
If the Metal backend has been selected, these functions return pointers
−302
to various Metal API objects required for rendering, otherwise
−303
they return a null pointer. These void pointers are actually
−304
Objective-C ids converted with a (ARC) __bridge cast so that
−305
the ids can be tunneled through C code. Also note that the returned
−306
pointers may change from one frame to the next, only the Metal device
−307
object is guaranteed to stay the same.
−308
−309
const void* sapp_macos_get_window(void)
−310
On macOS, get the NSWindow object pointer, otherwise a null pointer.
−311
Before being used as Objective-C object, the void* must be converted
−312
back with a (ARC) __bridge cast.
−313
−314
const void* sapp_ios_get_window(void)
−315
On iOS, get the UIWindow object pointer, otherwise a null pointer.
−316
Before being used as Objective-C object, the void* must be converted
−317
back with a (ARC) __bridge cast.
−318
−319
const void* sapp_d3d11_get_device(void)
−320
const void* sapp_d3d11_get_device_context(void)
−321
const void* sapp_d3d11_get_render_view(void)
−322
const void* sapp_d3d11_get_resolve_view(void);
−323
const void* sapp_d3d11_get_depth_stencil_view(void)
−324
Similar to the sapp_metal_* functions, the sapp_d3d11_* functions
−325
return pointers to D3D11 API objects required for rendering,
−326
only if the D3D11 backend has been selected. Otherwise they
−327
return a null pointer. Note that the returned pointers to the
−328
render-target-view and depth-stencil-view may change from one
−329
frame to the next!
−330
−331
const void* sapp_win32_get_hwnd(void)
−332
On Windows, get the window's HWND, otherwise a null pointer. The
−333
HWND has been cast to a void pointer in order to be tunneled
−334
through code which doesn't include Windows.h.
−335
−336
const void* sapp_x11_get_window(void)
−337
On Linux, get the X11 Window, otherwise a null pointer. The
−338
Window has been cast to a void pointer in order to be tunneled
−339
through code which doesn't include X11/Xlib.h.
−340
−341
const void* sapp_x11_get_display(void)
−342
On Linux, get the X11 Display, otherwise a null pointer. The
−343
Display has been cast to a void pointer in order to be tunneled
−344
through code which doesn't include X11/Xlib.h.
−345
−346
const void* sapp_wgpu_get_device(void)
−347
const void* sapp_wgpu_get_render_view(void)
−348
const void* sapp_wgpu_get_resolve_view(void)
−349
const void* sapp_wgpu_get_depth_stencil_view(void)
−350
These are the WebGPU-specific functions to get the WebGPU
−351
objects and values required for rendering. If sokol_app.h
−352
is not compiled with SOKOL_WGPU, these functions return null.
−353
−354
uint32_t sapp_gl_get_framebuffer(void)
−355
This returns the 'default framebuffer' of the GL context.
−356
Typically this will be zero.
−357
−358
int sapp_gl_get_major_version(void)
−359
int sapp_gl_get_minor_version(void)
−360
bool sapp_gl_is_gles(void)
−361
Returns the major and minor version of the GL context and
−362
whether the GL context is a GLES context
−363
−364
const void* sapp_android_get_native_activity(void);
−365
On Android, get the native activity ANativeActivity pointer, otherwise
−366
a null pointer.
−367
−368
--- Implement the frame-callback function, this function will be called
−369
on the same thread as the init callback, but might be on a different
−370
thread than the sokol_main() function. Note that the size of
−371
the rendering framebuffer might have changed since the frame callback
−372
was called last. Call the functions sapp_width() and sapp_height()
−373
each frame to get the current size.
−374
−375
--- Optionally implement the event-callback to handle input events.
−376
sokol-app provides the following type of input events:
−377
- a 'virtual key' was pressed down or released
−378
- a single text character was entered (provided as UTF-32 encoded
−379
UNICODE code point)
−380
- a mouse button was pressed down or released (left, right, middle)
−381
- mouse-wheel or 2D scrolling events
−382
- the mouse was moved
−383
- the mouse has entered or left the application window boundaries
−384
- low-level, portable multi-touch events (began, moved, ended, cancelled)
−385
- the application window was resized, iconified or restored
−386
- the application was suspended or restored (on mobile platforms)
−387
- the user or application code has asked to quit the application
−388
- a string was pasted to the system clipboard
−389
- one or more files have been dropped onto the application window
−390
−391
To explicitly 'consume' an event and prevent that the event is
−392
forwarded for further handling to the operating system, call
−393
sapp_consume_event() from inside the event handler (NOTE that
−394
this behaviour is currently only implemented for some HTML5
−395
events, support for other platforms and event types will
−396
be added as needed, please open a GitHub ticket and/or provide
−397
a PR if needed).
−398
−399
NOTE: Do *not* call any 3D API rendering functions in the event
−400
callback function, since the 3D API context may not be active when the
−401
event callback is called (it may work on some platforms and 3D APIs,
−402
but not others, and the exact behaviour may change between
−403
sokol-app versions).
−404
−405
--- Implement the cleanup-callback function, this is called once
−406
after the user quits the application (see the section
−407
"APPLICATION QUIT" for detailed information on quitting
−408
behaviour, and how to intercept a pending quit - for instance to show a
−409
"Really Quit?" dialog box). Note that the cleanup-callback isn't
−410
guaranteed to be called on the web and mobile platforms.
−411
−412
MOUSE CURSOR TYPE AND VISIBILITY
−413
================================
−414
You can show and hide the mouse cursor with
−415
−416
void sapp_show_mouse(bool show)
−417
−418
And to get the current shown status:
−419
−420
bool sapp_mouse_shown(void)
−421
−422
NOTE that hiding the mouse cursor is different and independent from
−423
the MOUSE/POINTER LOCK feature which will also hide the mouse pointer when
−424
active (MOUSE LOCK is described below).
−425
−426
To change the mouse cursor to one of several predefined types, call
−427
the function:
−428
−429
void sapp_set_mouse_cursor(sapp_mouse_cursor cursor)
−430
−431
Setting the default mouse cursor SAPP_MOUSECURSOR_DEFAULT will restore
−432
the standard look.
−433
−434
To get the currently active mouse cursor type, call:
−435
−436
sapp_mouse_cursor sapp_get_mouse_cursor(void)
−437
−438
MOUSE LOCK (AKA POINTER LOCK, AKA MOUSE CAPTURE)
−439
================================================
−440
In normal mouse mode, no mouse movement events are reported when the
−441
mouse leaves the windows client area or hits the screen border (whether
−442
it's one or the other depends on the platform), and the mouse move events
−443
(SAPP_EVENTTYPE_MOUSE_MOVE) contain absolute mouse positions in
−444
framebuffer pixels in the sapp_event items mouse_x and mouse_y, and
−445
relative movement in framebuffer pixels in the sapp_event items mouse_dx
−446
and mouse_dy.
−447
−448
To get continuous mouse movement (also when the mouse leaves the window
−449
client area or hits the screen border), activate mouse-lock mode
−450
by calling:
−451
−452
sapp_lock_mouse(true)
−453
−454
When mouse lock is activated, the mouse pointer is hidden, the
−455
reported absolute mouse position (sapp_event.mouse_x/y) appears
−456
frozen, and the relative mouse movement in sapp_event.mouse_dx/dy
−457
no longer has a direct relation to framebuffer pixels but instead
−458
uses "raw mouse input" (what "raw mouse input" exactly means also
−459
differs by platform).
−460
−461
To deactivate mouse lock and return to normal mouse mode, call
−462
−463
sapp_lock_mouse(false)
−464
−465
And finally, to check if mouse lock is currently active, call
−466
−467
if (sapp_mouse_locked()) { ... }
−468
−469
Note that mouse-lock state may not change immediately after sapp_lock_mouse(true/false)
−470
is called, instead on some platforms the actual state switch may be delayed
−471
to the end of the current frame or even to a later frame.
−472
−473
The mouse may also be unlocked automatically without calling sapp_lock_mouse(false),
−474
most notably when the application window becomes inactive.
−475
−476
On the web platform there are further restrictions to be aware of, caused
−477
by the limitations of the HTML5 Pointer Lock API:
−478
−479
- sapp_lock_mouse(true) can be called at any time, but it will
−480
only take effect in a 'short-lived input event handler of a specific
−481
type', meaning when one of the following events happens:
−482
- SAPP_EVENTTYPE_MOUSE_DOWN
−483
- SAPP_EVENTTYPE_MOUSE_UP
−484
- SAPP_EVENTTYPE_MOUSE_SCROLL
−485
- SAPP_EVENTTYPE_KEY_UP
−486
- SAPP_EVENTTYPE_KEY_DOWN
−487
- The mouse lock/unlock action on the web platform is asynchronous,
−488
this means that sapp_mouse_locked() won't immediately return
−489
the new status after calling sapp_lock_mouse(), instead the
−490
reported status will only change when the pointer lock has actually
−491
been activated or deactivated in the browser.
−492
- On the web, mouse lock can be deactivated by the user at any time
−493
by pressing the Esc key. When this happens, sokol_app.h behaves
−494
the same as if sapp_lock_mouse(false) is called.
−495
−496
For things like camera manipulation it's most straightforward to lock
−497
and unlock the mouse right from the sokol_app.h event handler, for
−498
instance the following code enters and leaves mouse lock when the
−499
left mouse button is pressed and released, and then uses the relative

Showing the first 500 of 14048 diff lines for this file. This diff is INCOMPLETE; read the file or clone the repository for the rest.

vendor/sokol/sokol_glue.hdeleted
@@ -1,206 +0,0 @@
−1
#if defined(SOKOL_IMPL) && !defined(SOKOL_GLUE_IMPL)
−2
#define SOKOL_GLUE_IMPL
−3
#endif
−4
#ifndef SOKOL_GLUE_INCLUDED
−5
/*
−6
sokol_glue.h -- glue helper functions for sokol headers
−7
−8
Project URL: https://github.com/floooh/sokol
−9
−10
Do this:
−11
#define SOKOL_IMPL or
−12
#define SOKOL_GLUE_IMPL
−13
before you include this file in *one* C or C++ file to create the
−14
implementation.
−15
−16
...optionally provide the following macros to override defaults:
−17
−18
SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
−19
SOKOL_GLUE_API_DECL - public function declaration prefix (default: extern)
−20
SOKOL_API_DECL - same as SOKOL_GLUE_API_DECL
−21
SOKOL_API_IMPL - public function implementation prefix (default: -)
−22
−23
If sokol_glue.h is compiled as a DLL, define the following before
−24
including the declaration or implementation:
−25
−26
SOKOL_DLL
−27
−28
On Windows, SOKOL_DLL will define SOKOL_GLUE_API_DECL as __declspec(dllexport)
−29
or __declspec(dllimport) as needed.
−30
−31
OVERVIEW
−32
========
−33
sokol_glue.h provides glue helper functions between sokol_gfx.h and sokol_app.h,
−34
so that sokol_gfx.h doesn't need to depend on sokol_app.h but can be
−35
used with different window system glue libraries.
−36
−37
PROVIDED FUNCTIONS
−38
==================
−39
−40
sg_environment sglue_environment(void)
−41
−42
Returns an sg_environment struct initialized by calling sokol_app.h
−43
functions. Use this in the sg_setup() call like this:
−44
−45
sg_setup(&(sg_desc){
−46
.environment = sglue_environment(),
−47
...
−48
});
−49
−50
sg_swapchain sglue_swapchain(void)
−51
−52
Returns an sg_swapchain struct initialized by calling sokol_app.h
−53
functions. Use this in sg_begin_pass() for a 'swapchain pass' like
−54
this:
−55
−56
sg_begin_pass(&(sg_pass){ .swapchain = sglue_swapchain(), ... });
−57
−58
LICENSE
−59
=======
−60
zlib/libpng license
−61
−62
Copyright (c) 2018 Andre Weissflog
−63
−64
This software is provided 'as-is', without any express or implied warranty.
−65
In no event will the authors be held liable for any damages arising from the
−66
use of this software.
−67
−68
Permission is granted to anyone to use this software for any purpose,
−69
including commercial applications, and to alter it and redistribute it
−70
freely, subject to the following restrictions:
−71
−72
1. The origin of this software must not be misrepresented; you must not
−73
claim that you wrote the original software. If you use this software in a
−74
product, an acknowledgment in the product documentation would be
−75
appreciated but is not required.
−76
−77
2. Altered source versions must be plainly marked as such, and must not
−78
be misrepresented as being the original software.
−79
−80
3. This notice may not be removed or altered from any source
−81
distribution.
−82
*/
−83
#define SOKOL_GLUE_INCLUDED
−84
−85
#if defined(SOKOL_API_DECL) && !defined(SOKOL_GLUE_API_DECL)
−86
#define SOKOL_GLUE_API_DECL SOKOL_API_DECL
−87
#endif
−88
#ifndef SOKOL_GLUE_API_DECL
−89
#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_GLUE_IMPL)
−90
#define SOKOL_GLUE_API_DECL __declspec(dllexport)
−91
#elif defined(_WIN32) && defined(SOKOL_DLL)
−92
#define SOKOL_GLUE_API_DECL __declspec(dllimport)
−93
#else
−94
#define SOKOL_GLUE_API_DECL extern
−95
#endif
−96
#endif
−97
−98
#ifndef SOKOL_GFX_INCLUDED
−99
#error "Please include sokol_gfx.h before sokol_glue.h"
−100
#endif
−101
−102
#ifdef __cplusplus
−103
extern "C" {
−104
#endif
−105
−106
SOKOL_GLUE_API_DECL sg_environment sglue_environment(void);
−107
SOKOL_GLUE_API_DECL sg_swapchain sglue_swapchain(void);
−108
−109
#ifdef __cplusplus
−110
} /* extern "C" */
−111
#endif
−112
#endif /* SOKOL_GLUE_INCLUDED */
−113
−114
/*-- IMPLEMENTATION ----------------------------------------------------------*/
−115
#ifdef SOKOL_GLUE_IMPL
−116
#define SOKOL_GLUE_IMPL_INCLUDED (1)
−117
#include <string.h> /* memset */
−118
−119
#ifndef SOKOL_APP_INCLUDED
−120
#error "Please include sokol_app.h before the sokol_glue.h implementation"
−121
#endif
−122
−123
#ifndef SOKOL_API_IMPL
−124
#define SOKOL_API_IMPL
−125
#endif
−126
−127
#ifndef _SOKOL_PRIVATE
−128
#if defined(__GNUC__) || defined(__clang__)
−129
#define _SOKOL_PRIVATE __attribute__((unused)) static
−130
#else
−131
#define _SOKOL_PRIVATE static
−132
#endif
−133
#endif
−134
−135
#ifndef SOKOL_ASSERT
−136
#include <assert.h>
−137
#define SOKOL_ASSERT(c) assert(c)
−138
#endif
−139
#ifndef SOKOL_UNREACHABLE
−140
#define SOKOL_UNREACHABLE SOKOL_ASSERT(false)
−141
#endif
−142
−143
_SOKOL_PRIVATE sg_pixel_format _sglue_to_sgpixelformat(sapp_pixel_format fmt) {
−144
switch (fmt) {
−145
case SAPP_PIXELFORMAT_NONE: return SG_PIXELFORMAT_NONE;
−146
case SAPP_PIXELFORMAT_RGBA8: return SG_PIXELFORMAT_RGBA8;
−147
case SAPP_PIXELFORMAT_SRGB8A8: return SG_PIXELFORMAT_SRGB8A8;
−148
case SAPP_PIXELFORMAT_BGRA8: return SG_PIXELFORMAT_BGRA8;
−149
case SAPP_PIXELFORMAT_DEPTH_STENCIL: return SG_PIXELFORMAT_DEPTH_STENCIL;
−150
case SAPP_PIXELFORMAT_DEPTH: return SG_PIXELFORMAT_DEPTH;
−151
case SAPP_PIXELFORMAT_SBGRA8: // FIXME!
−152
default:
−153
SOKOL_UNREACHABLE;
−154
return SG_PIXELFORMAT_NONE;
−155
}
−156
}
−157
−158
SOKOL_API_IMPL sg_environment sglue_environment(void) {
−159
sg_environment res;
−160
memset(&res, 0, sizeof(res));
−161
const sapp_environment env = sapp_get_environment();
−162
res.defaults.color_format = _sglue_to_sgpixelformat(env.defaults.color_format);
−163
res.defaults.depth_format = _sglue_to_sgpixelformat(env.defaults.depth_format);
−164
res.defaults.sample_count = env.defaults.sample_count;
−165
res.metal.device = env.metal.device;
−166
res.d3d11.device = env.d3d11.device;
−167
res.d3d11.device_context = env.d3d11.device_context;
−168
res.wgpu.device = env.wgpu.device;
−169
res.vulkan.physical_device = env.vulkan.physical_device;
−170
res.vulkan.device = env.vulkan.device;
−171
res.vulkan.queue = env.vulkan.queue;
−172
res.vulkan.queue_family_index = env.vulkan.queue_family_index;
−173
return res;
−174
}
−175
−176
SOKOL_API_IMPL sg_swapchain sglue_swapchain(void) {
−177
sg_swapchain res;
−178
memset(&res, 0, sizeof(res));
−179
const sapp_swapchain sc = sapp_get_swapchain();
−180
res.width = sc.width;
−181
res.height = sc.height;
−182
res.sample_count = sc.sample_count;
−183
res.color_format = _sglue_to_sgpixelformat(sc.color_format);
−184
res.depth_format = _sglue_to_sgpixelformat(sc.depth_format);
−185
res.metal.current_drawable = sc.metal.current_drawable;
−186
res.metal.depth_stencil_texture = sc.metal.depth_stencil_texture;
−187
res.metal.msaa_color_texture = sc.metal.msaa_color_texture;
−188
res.d3d11.render_view = sc.d3d11.render_view;
−189
res.d3d11.resolve_view = sc.d3d11.resolve_view;
−190
res.d3d11.depth_stencil_view = sc.d3d11.depth_stencil_view;
−191
res.wgpu.render_view = sc.wgpu.render_view;
−192
res.wgpu.resolve_view = sc.wgpu.resolve_view;
−193
res.wgpu.depth_stencil_view = sc.wgpu.depth_stencil_view;
−194
res.vulkan.render_image = sc.vulkan.render_image;
−195
res.vulkan.render_view = sc.vulkan.render_view;
−196
res.vulkan.resolve_image = sc.vulkan.resolve_image;
−197
res.vulkan.resolve_view = sc.vulkan.resolve_view;
−198
res.vulkan.depth_stencil_image = sc.vulkan.depth_stencil_image;
−199
res.vulkan.depth_stencil_view = sc.vulkan.depth_stencil_view;
−200
res.vulkan.render_finished_semaphore = sc.vulkan.render_finished_semaphore;
−201
res.vulkan.present_complete_semaphore = sc.vulkan.present_complete_semaphore;
−202
res.gl.framebuffer = sc.gl.framebuffer;
−203
return res;
−204
}
−205
−206
#endif /* SOKOL_GLUE_IMPL */