Skip to content

Commit

Permalink
Proxy webgpu calls back to the main thread. NFC (emscripten-core#20124)
Browse files Browse the repository at this point in the history
Until we have real multi-threaded webgpu support this is probable
the best we can do.

I tested these locally. I don't think we actually have WebGPU support
in our CI yet, but that is something else I'm working on.

Fixes: emscripten-core#19645
  • Loading branch information
sbc100 authored Sep 19, 2023
1 parent d67dc2a commit 992d1e9
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 14 deletions.
4 changes: 2 additions & 2 deletions src/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ addToLibrary({
assert(!implicit);
#endif
#if PTHREADS_DEBUG
dbg(`Pthread ${ptrToString(_pthread_self())} called exit(), posting exitOnMainThread.`);
dbg(`Pthread ${ptrToString(_pthread_self())} called exit(${status}), posting exitOnMainThread.`);
#endif
// When running in a pthread we propagate the exit back to the main thread
// where it can decide if the whole process should be shut down or not.
Expand All @@ -83,7 +83,7 @@ addToLibrary({
throw 'unwind';
}
#if PTHREADS_DEBUG
err(`main thread called exit: keepRuntimeAlive=${keepRuntimeAlive()} (counter=${runtimeKeepaliveCounter})`);
err(`main thread called exit(${status}): keepRuntimeAlive=${keepRuntimeAlive()} (counter=${runtimeKeepaliveCounter})`);
#endif // PTHREADS_DEBUG
#endif // PTHREADS

Expand Down
6 changes: 6 additions & 0 deletions src/library_html5_webgpu.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,10 @@ var LibraryHTML5WebGPU = {
{{{ html5_gpu.makeImportExport('render_bundle_encoder', 'RenderBundleEncoder') }}}
{{{ html5_gpu.makeImportExport('render_bundle', 'RenderBundle') }}}

for (const key of Object.keys(LibraryHTML5WebGPU)) {
if (typeof LibraryHTML5WebGPU[key] === 'function' && !(key + '__proxy' in LibraryHTML5WebGPU)) {
LibraryHTML5WebGPU[key + '__proxy'] = 'sync';
}
}

addToLibrary(LibraryHTML5WebGPU);
18 changes: 11 additions & 7 deletions src/library_webgpu.js
Original file line number Diff line number Diff line change
Expand Up @@ -2198,7 +2198,7 @@ var LibraryWebGPU = {
#endif

var bundles = Array.from(HEAP32.subarray(bundlesPtr >> 2, (bundlesPtr >> 2) + count),
function(id) { return WebGPU.mgrRenderBundle.get(id); });
(id) => WebGPU.mgrRenderBundle.get(id));
pass["executeBundles"](bundles);
},

Expand Down Expand Up @@ -2586,23 +2586,22 @@ var LibraryWebGPU = {
var device = WebGPU.mgrDevice.get(deviceId);
var context = WebGPU.mgrSurface.get(surfaceId);


#if ASSERTIONS
assert({{{ gpu.PresentMode.Fifo }}} ===
{{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUSwapChainDescriptor.presentMode) }}});
#endif

var canvasSize = [
{{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUSwapChainDescriptor.width) }}},
{{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUSwapChainDescriptor.height) }}}
{{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUSwapChainDescriptor.width) }}},
{{{ gpu.makeGetU32('descriptor', C_STRUCTS.WGPUSwapChainDescriptor.height) }}}
];

if (canvasSize[0] !== 0) {
context["canvas"]["width"] = canvasSize[0];
context["canvas"]["width"] = canvasSize[0];
}

if (canvasSize[1] !== 0) {
context["canvas"]["height"] = canvasSize[1];
context["canvas"]["height"] = canvasSize[1];
}

var configuration = {
Expand Down Expand Up @@ -2645,7 +2644,12 @@ for (var value in LibraryWebGPU.$WebGPU.FeatureName) {
}

for (const key of Object.keys(LibraryWebGPU)) {
LibraryWebGPU[key + '__i53abi'] = true;
if (typeof LibraryWebGPU[key] === 'function') {
LibraryWebGPU[key + '__i53abi'] = true;
if (!(key + '__proxy' in LibraryWebGPU)) {
LibraryWebGPU[key + '__proxy'] = 'sync';
}
}
}

autoAddDeps(LibraryWebGPU, '$WebGPU');
Expand Down
9 changes: 9 additions & 0 deletions test/test_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -4664,9 +4664,18 @@ def test_webgl_simple_enable_extensions(self):
def test_webgpu_basic_rendering(self, args):
self.btest_exit('webgpu_basic_rendering.cpp', args=['-sUSE_WEBGPU'] + args)

@requires_graphics_hardware
@requires_threads
def test_webgpu_basic_rendering_pthreads(self):
self.btest_exit('webgpu_basic_rendering.cpp', args=['-sUSE_WEBGPU', '-pthread', '-sPROXY_TO_PTHREAD'])

def test_webgpu_get_device(self):
self.btest_exit('webgpu_get_device.cpp', args=['-sUSE_WEBGPU', '-sASSERTIONS', '--closure=1'])

@requires_threads
def test_webgpu_get_device_pthreads(self):
self.btest_exit('webgpu_get_device.cpp', args=['-sUSE_WEBGPU', '-pthread', '-sPROXY_TO_PTHREAD'])

# Tests the feature that shell html page can preallocate the typed array and place it
# to Module.buffer before loading the script page.
# In this build mode, the -sINITIAL_MEMORY=xxx option will be ignored.
Expand Down
13 changes: 11 additions & 2 deletions test/webgpu_basic_rendering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,16 @@ void GetDevice(void (*callback)(wgpu::Device)) {
}
if (status == WGPURequestAdapterStatus_Unavailable) {
printf("WebGPU unavailable; exiting cleanly\n");
// exit(0) (rather than emscripten_force_exit(0)) ensures there is no dangling keepalive.
// exit(0) (rather than emscripten_force_exit(0)) ensures there is
// no dangling keepalive.
#if _REENTRANT
// FIXME: In multi-threaded builds this callback runs on the main
// which seems to be causing the runtime to stay alive here and
// results in the 99 being returned.
emscripten_force_exit(0);
#else
exit(0);
#endif
}
assert(status == WGPURequestAdapterStatus_Success);

Expand Down Expand Up @@ -410,6 +418,7 @@ int main() {
// emscripten_set_main_loop, and that should keep it alive until
// emscripten_cancel_main_loop.
//
// This code is returned when the runtime exits unless something else sets it, like exit(0).
// This code is returned when the runtime exits unless something else sets
// it, like exit(0).
return 99;
}
13 changes: 10 additions & 3 deletions test/webgpu_get_device.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
#include <emscripten.h>
#include <stdio.h>

#include <emscripten/em_asm.h>
#include <emscripten/html5_webgpu.h>

int main() {
__attribute__((constructor)) void init() {
EM_ASM({
Module['preinitializedWebGPUDevice'] = { this_is: 'a_dummy_object' };
});
emscripten_webgpu_get_device();
}

int main() {
WGPUDevice d = emscripten_webgpu_get_device();
printf("emscripten_webgpu_get_device: %p\n", d);
return 0;
}

0 comments on commit 992d1e9

Please sign in to comment.