diff --git a/web/CMakeLists.txt b/web/CMakeLists.txt index ccff873d..25af77b0 100644 --- a/web/CMakeLists.txt +++ b/web/CMakeLists.txt @@ -11,6 +11,7 @@ option(TINYUSDZ_WASM64 "Use wasm64(memory64). Available only for Chrome and Fire option(TINYUSDZ_WASM_DEBUG "Enable WASM debug mode with source maps and assertions" OFF) option(TINYUSDZ_WASM_SIMD "Enable WebAssembly SIMD (128-bit, widely supported since 2021)" ON) option(TINYUSDZ_WASM_RELAXED_SIMD "Enable WebAssembly Relaxed SIMD (requires recent browsers)" OFF) +option(TINYUSDZ_WASM_COROUTINE "Enable C++20 coroutine-based async loading (allows browser repaint during loading)" OFF) if (TINYUSDZ_WASM64) set(BUILD_TARGET "tinyusdz_64") @@ -117,6 +118,12 @@ if (TINYUSDZ_WITH_EXR) target_compile_definitions(${BUILD_TARGET} PRIVATE TINYUSDZ_WITH_EXR=1) endif() +# C++20 coroutine support for async loading +if (TINYUSDZ_WASM_COROUTINE) + message(STATUS "TinyUSDZ WASM: C++20 coroutine async loading enabled") + target_compile_definitions(${BUILD_TARGET} PRIVATE TINYUSDZ_USE_COROUTINE=1) +endif() + # tinyusdz dir target_include_directories(${BUILD_TARGET} PRIVATE "${PROJECT_SOURCE_DIR}/../src/") @@ -203,6 +210,7 @@ endif() # Export HEAPU8 for zero-copy streaming transfer from JS to WASM string(APPEND TINYUSDZ_EMCC_LINK_FLAGS " -sEXPORTED_RUNTIME_METHODS=['HEAPU8']") + message(STATUS ${TINYUSDZ_EMCC_LINK_FLAGS}) set_target_properties(${BUILD_TARGET} PROPERTIES LINK_FLAGS "${TINYUSDZ_EMCC_LINK_FLAGS}") diff --git a/web/binding.cc b/web/binding.cc index d01de3d8..80c22996 100644 --- a/web/binding.cc +++ b/web/binding.cc @@ -116,6 +116,11 @@ EM_JS(void, reportTydraComplete, (int meshCount, int materialCount, int textureC // ============================================================================ // This allows the browser to repaint between processing phases. // Returns a Promise that resolves on the next animation frame. +// +// Enable with CMake option: -DTINYUSDZ_WASM_COROUTINE=ON (default) +// Disable with: -DTINYUSDZ_WASM_COROUTINE=OFF + +#if defined(TINYUSDZ_USE_COROUTINE) EM_JS(emscripten::EM_VAL, yieldToEventLoop_impl, (), { // Return a Promise that resolves on next animation frame @@ -156,6 +161,8 @@ EM_JS(void, reportAsyncPhaseStart, (const char* phase, float progress), { } }); +#endif // TINYUSDZ_USE_COROUTINE + namespace detail { std::array toArray(const tinyusdz::value::matrix3d &m) { @@ -1271,8 +1278,12 @@ class TinyUSDZLoaderNative { // This method uses C++20 coroutines to yield to the JavaScript event loop // between processing phases, allowing the browser to repaint during loading. // + // Enable with CMake option: -DTINYUSDZ_WASM_COROUTINE=ON (default) + // Disable with: -DTINYUSDZ_WASM_COROUTINE=OFF + // // Returns a Promise that resolves to a JS object: { success: bool, error?: string } // +#if defined(TINYUSDZ_USE_COROUTINE) emscripten::val loadFromBinaryAsync(std::string binary, std::string filename) { // IMPORTANT: Parameters are passed by VALUE (not by reference) to ensure // data remains valid across co_await suspension points. References would @@ -1339,6 +1350,7 @@ class TinyUSDZLoaderNative { result.set("textureCount", static_cast(render_scene_.textures.size())); co_return result; } +#endif // TINYUSDZ_USE_COROUTINE // u8 : Uint8Array object. bool loadTest(const std::string &filename, const emscripten::val &u8) { @@ -4493,7 +4505,9 @@ EMSCRIPTEN_BINDINGS(tinyusdz_module) { #endif .function("loadAsLayerFromBinary", &TinyUSDZLoaderNative::loadAsLayerFromBinary) .function("loadFromBinary", &TinyUSDZLoaderNative::loadFromBinary) +#if defined(TINYUSDZ_USE_COROUTINE) .function("loadFromBinaryAsync", &TinyUSDZLoaderNative::loadFromBinaryAsync) // C++20 coroutine async version +#endif .function("loadTest", &TinyUSDZLoaderNative::loadTest) .function("loadFromCachedAsset", &TinyUSDZLoaderNative::loadFromCachedAsset) .function("loadAsLayerFromCachedAsset", &TinyUSDZLoaderNative::loadAsLayerFromCachedAsset)