Files
vpinball-wasm/patches/vpinball/0002-threadpool-single-threaded-emscripten.patch
T
valknar 0a63835689
CI / Build wasm engine (push) Failing after 3m30s
CI / Publish to npm registry (push) Skipped
Scaffold vpinball-wasm: Emscripten port of Visual Pinball
Build scripts, CMake/source patches, npm packaging, and a Gitea CI
workflow to compile the real Visual Pinball engine (SDL3 + WebGL2 +
libwinevbs for real VBScript) to WebAssembly.

The patches are validated end-to-end: the patched engine boots in a
real browser, loads a real .vpx table, compiles its real GLSL shaders,
computes environment map radiance, initializes physics, and starts the
VBScript engine, before hanging on the one deliberately-deferred piece
of work (game loop rewrite around emscripten_set_main_loop), documented
in the README's roadmap.
2026-08-22 14:30:14 +02:00

48 lines
1.7 KiB
Diff

--- a/third-party/include/ThreadPool.h
+++ b/third-party/include/ThreadPool.h
@@ -110,9 +110,20 @@
: pool_size(threads)
, in_flight(0)
{
+#ifndef __EMSCRIPTEN__
const std::unique_lock<std::mutex> lock(this->queue_mutex);
for (std::size_t i = 0; i != threads; ++i)
start_worker(i, lock);
+#else
+ // vpinball-wasm: a single-threaded Emscripten build (no -pthread /
+ // SharedArrayBuffer for v1) cannot construct real std::thread workers -
+ // std::thread's constructor throws at runtime otherwise ("thread
+ // constructor failed"). Run zero real workers; enqueue() below executes
+ // tasks synchronously and inline instead, matching the porting plan's
+ // "run ThreadPool work serially" decision for one-off parallel work
+ // (parallel .vpx item deserialization at load, env-map baking, etc.).
+ (void)pool_size;
+#endif
}
// add new work item to the pool
@@ -139,6 +150,15 @@
std::future<return_type> res = task->get_future();
+#ifdef __EMSCRIPTEN__
+ // vpinball-wasm: no real worker threads exist (see the constructor) -
+ // run the task synchronously inline so callers still get a valid,
+ // already-ready future, exactly as if it had run on a worker.
+ (void)std::atomic_fetch_add_explicit(&in_flight, std::size_t(1), std::memory_order_relaxed);
+ (*task)();
+ (void)std::atomic_fetch_sub_explicit(&in_flight, std::size_t(1), std::memory_order_acq_rel);
+ return res;
+#else
std::unique_lock<std::mutex> lock(queue_mutex);
if (tasks.size () >= max_queue_size)
// wait for the queue to empty or be stopped
@@ -160,6 +180,7 @@
condition_consumers.notify_one();
return res;
+#endif
}