Open MikhailGorobets opened 4 months ago
As with any callback-based API you just need to yield to the event loop while you wait for the results.
There are several ways to do that. See https://emscripten.org/docs/porting/emscripten-runtime-environment.html#browser-main-loop. The simplest way is probably use emscripten_set_main_loop
.
Having said that ASYNCIFY
(along with its modern/experimental counterpart -sJSPI
) is the only way to achieve this in blocking manner (i.e. without returning from your entry point).
ASYNCIFY
is really just last resort for folks that cannot easily break up their main loop
@sbc100
Yes, we can move the initialization to emscripten_set_main_loop,
but this won’t solve the problem with asyncMap for readback and the recently added asynchronous operations for creating shaders and pipelines
Can you explain, perhaps with an example? I'm pretty sure WebGPU does not depend on use of ASYNCIFY. I imagine when you use an asynchronous operator to create your shader you simply get a callback when its done and continue from there?
How can we rewrite this code without ASYNCIFY?
https://github.com/DiligentGraphics/DiligentCore/blob/2e9a5fbcc2539275f73cb8834e8c90939ccd683e/Graphics/GraphicsEngineWebGPU/src/BufferWebGPUImpl.cpp#L236
Currently RenderDeviceWebGPUImpl::PollEvents
function calls emscripten_sleep
inside
Without ASYNCIFY (or JSPI) you would need to rewrite your BufferWebGPUImpl::Map
function to itself be async (i.e. either take callback functions or return some kind of future/promise object).
@sbc100 Well, we can’t redesign the API of the front-end renderer since it assumes the function is synchronous. Does using JSPI increase link time? (Enabling ASYNCIFY increases link time by an order of magnitude). From what I understand, JSPI is an experimental feature and requires special flags in the browser to activate. Is it worth investing time to implement this feature, considering it might take years before JSPI is available to end users?
@sbc100 Well, we can’t redesign the API of the front-end renderer since it assumes the function is synchronous.
Right, sadly this is exactly the kind of situation where something like ASYNCIFY is needed.
Does using JSPI increase link time? (Enabling ASYNCIFY increases link time by an order of magnitude). From what I understand, JSPI is an experimental feature and requires special flags in the browser to activate. Is it worth investing time to implement this feature, considering it might take years before JSPI is available to end users?
JSPI works a lot like ASYNCIFY but does not have the link time costs of the runtime overheads. You are correct that it could be a while (not years I hope) before its enabled by default in browsers. You could consider using JSPI for local/debug biulds that you want to be fast and ASYNCIFY for your release builds I suppose?
Yes, we can probably consider this possibility. How are async-await operations handled in Rust? I looked at the source code of Bevy, and they simply use await
on asynchronous WebGPU functions there
The Bevy (sorry I don't know what that is) is using await
then presumably that means that are exposing an async API externally to their users (something its sounds like you don't want to do/change)? (not sure if async/await in rust works like this, e.g. how it does in JS).
I don’t know Rust either, but judging by the cod, they pass the async function to block_on (which executes async functions). This way, the end user has a synchronous API
https://github.com/juj/wasm_webgpu/blob/cb2f20154aba141c3e80d485a59d4eb7f41f8946/samples/buffer_map_sync/buffer_map_sync.c#L19-L31 shows a demo of doing synchronous buffer mapping from C code with Emscripten and WebGPU by using the upcoming JSPI API. (i.e. using -sJSPI
link flag in Emscripten)
https://github.com/juj/wasm_webgpu/blob/cb2f20154aba141c3e80d485a59d4eb7f41f8946/samples/clear_screen/clear_screen_sync.c#L27-L58 takes this a bit further, and implements a custom for(;;)
render loop using JSPI.
Is there a way to interact with the current version of WebGPU without using the
ASYNCIFY
flag? Functions likewgpuInstanceRequestAdapter
,wgpuAdapterRequestDevice
, andwgpuBufferMapAsync
require callingemscripten_sleep
(which in turn requires usingASYNCIFY
). EnabledASYNCIFY
significantly increases the program size (in my case from 10MB to 18MB). Besides this, the linking time becomes several minutes in Release mode, and when building in Debug mode, I get a runtime error https://github.com/emscripten-core/emscripten/issues/19346