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.
48 lines
1.7 KiB
Diff
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
|
|
}
|
|
|
|
|