Files
EVEngine/scripts/serve_webgpu.py
T
西风逍遥游 63445728e1 feat(webgpu): online playground with live script hot-reload
Adds a self-contained browser playground (editor + canvas + console + REPL)
around the Emscripten WebGPU build, plus the engine fixes required to render:
- JS<->Squirrel bridge (apply/eval/read/pause) and Emscripten 6 exports
- soft hot-reload via load.nut handle_change with __pg state preservation
- fix Uint16 index buffer byte sizes in SetIndexBuffer calls
- fix dangling GbufferSlot/SceneColorSlot gpuHandle pointers (std::move bug)
- fallback shadow depth texture when no shadow map is configured
- fix WGSL syntax (mod/ivec2) and default shadow sampler maxAnisotropy
- serve_webgpu.py COOP/COEP server and playground docs/demos/assets
2026-08-21 20:35:20 +08:00

76 lines
2.5 KiB
Python

#!/usr/bin/env python3
"""Serve the EVEngine WebGPU build directory with cross-origin isolation.
The Emscripten build runs the engine on pthreads and needs SharedArrayBuffer,
so the page MUST be served with COOP/COEP headers -- opening eve.html via
file:// will not work. This server adds those headers plus no-store caching so
rebuilt eve.js / eve.wasm / eve.data are always picked up.
Usage (from the repo root):
python scripts/serve_webgpu.py # serves build/webgpu-web/src/engine :8090
python scripts/serve_webgpu.py <engine-dir> [port]
"""
import argparse
import http.server
import os
import sys
from pathlib import Path
class PlaygroundHandler(http.server.SimpleHTTPRequestHandler):
def end_headers(self):
# Required for Emscripten pthreads / SharedArrayBuffer.
self.send_header("Cross-Origin-Opener-Policy", "same-origin")
self.send_header("Cross-Origin-Embedder-Policy", "require-corp")
# The engine files are regenerated on every build; never cache them.
self.send_header("Cache-Control", "no-store")
super().end_headers()
def log_message(self, fmt, *args):
sys.stderr.write("[serve] %s\n" % (fmt % args))
def main():
default_dir = (
Path(__file__).resolve().parent.parent
/ "build" / "webgpu-web" / "src" / "engine"
)
parser = argparse.ArgumentParser(
description="Serve the EVEngine WebGPU build (COOP/COEP)."
)
parser.add_argument(
"engine_dir",
nargs="?",
type=Path,
default=default_dir,
help="Directory containing eve.html (default: %(default)s)",
)
parser.add_argument("port", nargs="?", type=int, default=8090,
help="Port (default: 8090)")
args = parser.parse_args()
engine_dir = args.engine_dir.resolve()
if not (engine_dir / "eve.html").is_file():
print("error: %s does not contain eve.html" % engine_dir)
print(
"Build first:\n"
" emcmake cmake -B build/webgpu-web -G Ninja -DCMAKE_BUILD_TYPE=Release\n"
" cmake --build build/webgpu-web"
)
return 1
os.chdir(engine_dir)
httpd = http.server.ThreadingHTTPServer(("127.0.0.1", args.port), PlaygroundHandler)
print("Serving %s" % engine_dir)
print("Open http://127.0.0.1:%d/eve.html in Chrome/Edge 113+ (WebGPU enabled)." % args.port)
try:
httpd.serve_forever()
except KeyboardInterrupt:
pass
return 0
if __name__ == "__main__":
sys.exit(main())