Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1313,3 +1313,117 @@ jobs:
if-no-files-found: error
name: "tic80-html-players"
path: build/players/*

# === HTML, WebGPU backend ===
# A job of its own so a WebGPU-only break cannot keep the GLES3 players off dev.
html-webgpu:
runs-on: ubuntu-latest

steps:
- uses: emscripten-core/setup-emsdk@v15

- uses: actions/checkout@v6
with:
submodules: recursive
fetch-depth: 0

- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6

- name: Install 32-bit build tools
run: sudo apt-get update && sudo apt-get install -y gcc-multilib

# The editorful build, as the site's players are: the loader keeps the name the site asks for.
- name: Build per-language WebGPU players
shell: bash
run: |
set -euo pipefail
langs=(lua ruby js moon yue fennel scheme squirrel wren wasm janet python miniscript forth gravity)
stage="$GITHUB_WORKSPACE/build/players-webgpu"
rm -rf "$stage"
for lang in "${langs[@]}"; do
flags=(-DBUILD_WITH_ALL=OFF)
for l in "${langs[@]}"; do
up=$(echo "$l" | tr '[:lower:]' '[:upper:]')
if [ "$l" = "$lang" ]; then flags+=("-DBUILD_WITH_$up=ON"); else flags+=("-DBUILD_WITH_$up=OFF"); fi
done
cd "$GITHUB_WORKSPACE/build"
emcmake cmake -G Ninja -DBUILD_TOUCH_INPUT=ON -DCMAKE_BUILD_TYPE=Release -DBUILD_EDITORS=ON -DBUILD_SOKOL_WGPU=ON "${flags[@]}" -DTIC80_TARGET="tic80$lang" ..
cmake --build . --parallel
for f in "bin/tic80$lang.js" "bin/tic80$lang.wasm"; do
[ -f "$f" ] || { echo "missing player: build/$f" >&2; exit 1; }
done
mkdir -p "$stage/$lang/webgpu"
cp "bin/tic80$lang.js" "$stage/$lang/webgpu/tic80.js"
cp "bin/tic80$lang.wasm" "$stage/$lang/webgpu/tic80$lang.wasm"
rm -f "bin/tic80$lang.js" "bin/tic80$lang.wasm"
done

# The target names the wasm its loader asks for; plain "tic80" would ask for the wrong one.
- name: Build universal WebGPU player
shell: bash
run: |
set -euo pipefail
stage="$GITHUB_WORKSPACE/build/players-webgpu/webgpu"
cd "$GITHUB_WORKSPACE/build"
emcmake cmake -G Ninja -DBUILD_TOUCH_INPUT=ON -DCMAKE_BUILD_TYPE=Release -DBUILD_WITH_ALL=ON -DBUILD_SOKOL_WGPU=ON -DTIC80_TARGET=tic80webgpu .. --fresh
cmake --build . --parallel
mkdir -p "$stage"
cp bin/tic80webgpu.js "$stage/tic80.js"
cp bin/tic80webgpu.wasm "$stage/tic80webgpu.wasm"
# the page an exported game gets, as the html job's "Build all" copies it
cp html/index.html "$stage/index.html"

# The backend is read from the loader: the wasm carries no such string.
- name: Check the builds are what they claim
shell: bash
run: |
set -euo pipefail
stage="$GITHUB_WORKSPACE/build/players-webgpu"
langs=(lua ruby js moon yue fennel scheme squirrel wren wasm janet python miniscript forth gravity)
files=()
for lang in "${langs[@]}"; do
js="$stage/$lang/webgpu/tic80.js"
wasm="$stage/$lang/webgpu/tic80$lang.wasm"
for f in "$js" "$wasm"; do
[ -f "$f" ] || { echo "missing player file: $f" >&2; exit 1; }
done
grep -qa "SPRITE EDITOR" "$wasm" ||
{ echo "player without editors: $wasm — BUILD_EDITORS=ON did not take" >&2; exit 1; }
grep -qa "Unable to initialize SDL Video" "$wasm" &&
{ echo "player on the SDL layer: $wasm — the sokol default did not take" >&2; exit 1; }
grep -qa "navigator.gpu" "$js" ||
{ echo "player without the WebGPU shim: $js — BUILD_SOKOL_WGPU=ON did not take" >&2; exit 1; }
grep -qa "tic80$lang.wasm" "$js" ||
{ echo "player asks for another wasm: $js does not name tic80$lang.wasm — TIC80_TARGET did not take" >&2; exit 1; }
files+=("$wasm")
done
for f in "$stage/webgpu/tic80.js" "$stage/webgpu/tic80webgpu.wasm" "$stage/webgpu/index.html"; do
[ -f "$f" ] || { echo "missing universal file: $f" >&2; exit 1; }
done
grep -qa "SPRITE EDITOR" "$stage/webgpu/tic80webgpu.wasm" ||
{ echo "the universal build carries no editors" >&2; exit 1; }
grep -qa "Unable to initialize SDL Video" "$stage/webgpu/tic80webgpu.wasm" &&
{ echo "the universal build is on the SDL layer — the sokol default did not take" >&2; exit 1; }
grep -qa "navigator.gpu" "$stage/webgpu/tic80.js" ||
{ echo "the universal build is not WebGPU" >&2; exit 1; }
grep -qa "tic80webgpu.wasm" "$stage/webgpu/tic80.js" ||
{ echo "the universal player asks for another wasm: it does not name tic80webgpu.wasm — TIC80_TARGET did not take" >&2; exit 1; }
# a language flag that did not take leaves two builds alike
for ((i = 0; i < ${#files[@]}; i++)); do
for ((j = i + 1; j < ${#files[@]}; j++)); do
if cmp -s "${files[i]}" "${files[j]}"; then
echo "duplicate player: $(basename "${files[i]}") == $(basename "${files[j]}") — a language flag did not take" >&2
exit 1
fi
done
done
echo "checked ${#files[@]} WebGPU players, all distinct, all with editors, all on the WebGPU shim"

- name: Deploy
uses: actions/upload-artifact@v6
with:
if-no-files-found: error
name: "tic80-html-webgpu"
path: build/players-webgpu/*
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,18 @@ endif()

option(BUILD_SDL "SDL Enabled" ${BUILD_SDL_DEFAULT})
option(BUILD_SOKOL "Sokol Enabled" ${BUILD_SOKOL_DEFAULT})
option(BUILD_SOKOL_WGPU "Sokol WebGPU backend (browser builds)" OFF)
if(BUILD_APPLE)
set(BUILD_SDL OFF)
set(BUILD_SOKOL OFF)
endif()
if(BUILD_SDL AND BUILD_SOKOL)
message(FATAL_ERROR "BUILD_SDL and BUILD_SOKOL are two system layers: enable exactly one")
endif()
# WebGPU is the Emscripten sokol backend; elsewhere it would be silently ignored.
if(BUILD_SOKOL_WGPU AND NOT (EMSCRIPTEN AND BUILD_SOKOL))
message(FATAL_ERROR "BUILD_SOKOL_WGPU is the Emscripten sokol backend: enable it with BUILD_SOKOL, for the browser")
endif()
option(BUILD_SDLGPU "SDL GPU Enabled" OFF)
option(BUILD_LIBRETRO "libretro Enabled" ${BUILD_LIBRETRO_DEFAULT})
option(BUILD_TOOLS "bin2txt prj2cart" OFF)
Expand Down Expand Up @@ -112,6 +117,7 @@ target_compile_definitions(runtime INTERFACE BUILD_DEPRECATED)
message("PREFER_SYSTEM_LIBRARIES: ${PREFER_SYSTEM_LIBRARIES}")
message("BUILD_STATIC: ${BUILD_STATIC}")
message("BUILD_SDLGPU: ${BUILD_SDLGPU}")
message("BUILD_SOKOL_WGPU: ${BUILD_SOKOL_WGPU}")
message("BUILD_TOUCH_INPUT: ${BUILD_TOUCH_INPUT}")
message("BUILD_WITH_ALL: ${BUILD_WITH_ALL}")

Expand Down
20 changes: 19 additions & 1 deletion cmake/sokol.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ if(BUILD_SOKOL)
target_compile_definitions(sokol PUBLIC SOKOL_METAL)
elseif(WIN32)
target_compile_definitions(sokol PUBLIC SOKOL_D3D11 UNICODE)
elseif(EMSCRIPTEN AND BUILD_SOKOL_WGPU)
# The browser's other backend: sokol_app owns the WebGPU device and swapchain.
target_compile_definitions(sokol PUBLIC SOKOL_WGPU)
elseif(EMSCRIPTEN)
target_compile_definitions(sokol PUBLIC SOKOL_GLES3)
elseif(USE_GLES2)
Expand Down Expand Up @@ -124,7 +127,22 @@ if(BUILD_SOKOL)
# The same runtime shape the SDL web target asks for — memory growth,
# fetch, the 4M stack a deep cart needs, the page's file hooks — with
# WebGL2 in place of SDL's GL.
set_target_properties(${TIC80_TARGET} PROPERTIES LINK_FLAGS "-s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s FETCH=1 -s STACK_SIZE=4194304 -s EXPORTED_FUNCTIONS=_main,_malloc,_free -s EXPORTED_RUNTIME_METHODS=UTF8ToString -s MIN_WEBGL_VERSION=2 -s MAX_WEBGL_VERSION=2 --pre-js ${CMAKE_SOURCE_DIR}/build/html/prejs.js -lidbfs.js")
set(TIC80_LINK_FLAGS "-s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s FETCH=1 -s STACK_SIZE=4194304 -s EXPORTED_FUNCTIONS=_main,_malloc,_free -s EXPORTED_RUNTIME_METHODS=UTF8ToString --pre-js ${CMAKE_SOURCE_DIR}/build/html/prejs.js -lidbfs.js")

if(BUILD_SOKOL_WGPU)

# WebGPU in place of WebGL2; the port carries the header, so it is on compile and link.
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --use-port=emdawnwebgpu")
# Named because the port's C++ drops them from the default set; unnamed they die in callMain.
set(TIC80_LINK_FLAGS "${TIC80_LINK_FLAGS} --use-port=emdawnwebgpu -sDEFAULT_TO_CXX -sEXPORTED_FUNCTIONS=_main,_malloc,_free,__emscripten_stack_alloc,_emscripten_stack_get_current,__emscripten_stack_restore")

else()

set(TIC80_LINK_FLAGS "${TIC80_LINK_FLAGS} -s MIN_WEBGL_VERSION=2 -s MAX_WEBGL_VERSION=2")

endif()

set_target_properties(${TIC80_TARGET} PROPERTIES LINK_FLAGS "${TIC80_LINK_FLAGS}")

endif()

Expand Down
Loading