diff --git a/cross/wasm_x86_i686.txt b/cross/wasm32_sw.txt similarity index 68% rename from cross/wasm_x86_i686.txt rename to cross/wasm32_sw.txt index 80f9e3ca..bd2dfafd 100644 --- a/cross/wasm_x86_i686.txt +++ b/cross/wasm32_sw.txt @@ -12,11 +12,10 @@ exe_suffix = 'js' [built-in options] cpp_args = ['-Wshift-negative-value', '-flto', '-Os', '-fno-exceptions'] -cpp_link_args = ['-Wshift-negative-value', '-flto', '-Os', '-fno-exceptions', '--bind', '-sWASM=1', '-sALLOW_MEMORY_GROWTH=1', '-sEXPORT_ES6=1', '-sFORCE_FILESYSTEM=1', '-sMODULARIZE=1', '-sEXPORTED_RUNTIME_METHODS=FS', '-sSINGLE_FILE=1'] -#cpp_link_args = ['-Wshift-negative-value', '-flto', '-Os', '-fno-exceptions', '--bind', '-sWASM=1', '-sALLOW_MEMORY_GROWTH=1', '-sFORCE_FILESYSTEM=1', '-g'] //enable g flag for wasm debugging +cpp_link_args = ['-Wshift-negative-value', '-flto', '-Os', '-fno-exceptions', '--bind', '-sWASM=1', '-sALLOW_MEMORY_GROWTH=1', '-sEXPORT_ES6=1', '-sFORCE_FILESYSTEM=1', '-sMODULARIZE=1', '-sEXPORTED_RUNTIME_METHODS=FS'] [host_machine] system = 'emscripten' -cpu_family = 'x86' -cpu = 'i686' +cpu_family = 'wasm32' +cpu = 'wasm32' endian = 'little' diff --git a/cross/wasm_webgpu.txt b/cross/wasm32_wg.txt similarity index 63% rename from cross/wasm_webgpu.txt rename to cross/wasm32_wg.txt index 42b59585..3d31c532 100644 --- a/cross/wasm_webgpu.txt +++ b/cross/wasm32_wg.txt @@ -12,7 +12,7 @@ exe_suffix = 'js' [built-in options] cpp_args = ['-Wshift-negative-value', '-flto', '-Os', '-fno-exceptions'] -cpp_link_args = ['-lembind', '-sMODULARIZE=1', '-sUSE_WEBGPU=1', '-sASYNCIFY=1', '-sFORCE_FILESYSTEM=1', '-sALLOW_MEMORY_GROWTH=1', '-sEXPORT_ES6=1', '-sSINGLE_FILE=1'] +cpp_link_args = ['-Wshift-negative-value', '-flto', '-Os', '-fno-exceptions', '--bind', '-sWASM=1', '-sALLOW_MEMORY_GROWTH=1', '-sEXPORT_ES6=1', '-sFORCE_FILESYSTEM=1', '-sMODULARIZE=1', '-sEXPORTED_RUNTIME_METHODS=FS', '-sUSE_WEBGPU=1', '-sASYNCIFY=1'] [host_machine] system = 'emscripten' diff --git a/src/bindings/wasm/tvgWasmLottieAnimation.cpp b/src/bindings/wasm/tvgWasmLottieAnimation.cpp index 8942993b..b674f2fb 100644 --- a/src/bindings/wasm/tvgWasmLottieAnimation.cpp +++ b/src/bindings/wasm/tvgWasmLottieAnimation.cpp @@ -23,6 +23,9 @@ #include #include #include "tvgPicture.h" +#ifdef THORVG_WG_RASTER_SUPPORT + #include +#endif using namespace emscripten; using namespace std; @@ -35,13 +38,60 @@ class __attribute__((visibility("default"))) TvgLottieAnimation public: ~TvgLottieAnimation() { - free(buffer); - Initializer::term(CanvasEngine::Sw); + if (engine == tvg::CanvasEngine::Sw) { + #ifdef THORVG_SW_RASTER_SUPPORT + free(buffer); + #endif + } else if (engine == tvg::CanvasEngine::Wg) { + #ifdef THORVG_WG_RASTER_SUPPORT + wgpuSurfaceRelease(surface); + wgpuInstanceRelease(instance); + #endif + } + + Initializer::term(engine); } - static TvgLottieAnimation* create() + explicit TvgLottieAnimation(string engine = "sw", string selector = "") { - return new TvgLottieAnimation; + errorMsg = NoError; + + if (engine == "sw") { + #ifdef THORVG_SW_RASTER_SUPPORT + this->engine = tvg::CanvasEngine::Sw; + if (Initializer::init(this->engine, 0) != Result::Success) { + errorMsg = "init() fail"; + return; + } + canvas = SwCanvas::gen(); + #endif + } else if (engine == "wg") { + #ifdef THORVG_WG_RASTER_SUPPORT + this->engine = tvg::CanvasEngine::Wg; + if (Initializer::init(this->engine, 0) != Result::Success) { + errorMsg = "init() fail"; + return; + } + + //Init WebGPU + instance = wgpuCreateInstance(nullptr); + + WGPUSurfaceDescriptorFromCanvasHTMLSelector canvasDesc{}; + canvasDesc.chain.next = nullptr; + canvasDesc.chain.sType = WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector; + canvasDesc.selector = selector.c_str(); + + WGPUSurfaceDescriptor surfaceDesc{}; + surfaceDesc.nextInChain = &canvasDesc.chain; + surface = wgpuInstanceCreateSurface(instance, &surfaceDesc); + + canvas = WgCanvas::gen(); + #endif + } + if (!canvas) errorMsg = "Invalid canvas"; + + animation = Animation::gen(); + if (!animation) errorMsg = "Invalid animation"; } string error() @@ -85,8 +135,7 @@ public: return false; } - //back up for saving - this->data = data; + this->data = data; //back up for saving canvas->clear(true); @@ -126,7 +175,9 @@ public: if (!canvas || !animation) return val(typed_memory_view(0, nullptr)); - if (!updated) return val(typed_memory_view(width * height * 4, buffer)); + if (!updated) { + return output(); + } if (canvas->draw() != Result::Success) { errorMsg = "draw() fail"; @@ -137,7 +188,7 @@ public: updated = false; - return val(typed_memory_view(width * height * 4, buffer)); + return output(); } bool update() @@ -184,9 +235,17 @@ public: this->width = width; this->height = height; - free(buffer); - buffer = (uint8_t*)malloc(width * height * sizeof(uint32_t)); - canvas->target((uint32_t *)buffer, width, width, height, SwCanvas::ABGR8888S); + if (engine == tvg::CanvasEngine::Sw) { + #ifdef THORVG_SW_RASTER_SUPPORT + free(buffer); + buffer = (uint8_t*)malloc(width * height * sizeof(uint32_t)); + static_cast(canvas.get())->target((uint32_t *)buffer, width, width, height, SwCanvas::ABGR8888S); + #endif + } else if (engine == tvg::CanvasEngine::Wg) { + #ifdef THORVG_WG_RASTER_SUPPORT + static_cast(canvas.get())->target(this->instance, this->surface, width, height); + #endif + } float scale; float shiftX = 0.0f, shiftY = 0.0f; @@ -309,38 +368,39 @@ public: // TODO: Advanced APIs wrt Interactivity & theme methods... private: - explicit TvgLottieAnimation() + val output() { - errorMsg = NoError; - - if (Initializer::init(CanvasEngine::Sw, 0) != Result::Success) { - errorMsg = "init() fail"; - return; - } - - canvas = SwCanvas::gen(); - if (!canvas) errorMsg = "Invalid canvas"; - - animation = Animation::gen(); - if (!animation) errorMsg = "Invalid animation"; + if (engine == tvg::CanvasEngine::Sw) { + #ifdef THORVG_SW_RASTER_SUPPORT + return val(typed_memory_view(width * height * 4, buffer)); + #endif + } + return val(typed_memory_view(0, nullptr)); } private: string errorMsg; - unique_ptr canvas = nullptr; + CanvasEngine engine; + unique_ptr canvas = nullptr; unique_ptr animation = nullptr; string data; - uint8_t* buffer = nullptr; uint32_t width = 0; uint32_t height = 0; float psize[2]; //picture size bool updated = false; + #ifdef THORVG_SW_RASTER_SUPPORT + uint8_t* buffer = nullptr; + #endif + #ifdef THORVG_WG_RASTER_SUPPORT + WGPUInstance instance{}; + WGPUSurface surface{}; + #endif }; EMSCRIPTEN_BINDINGS(thorvg_bindings) { class_("TvgLottieAnimation") - .constructor(&TvgLottieAnimation ::create) + .constructor() .function("error", &TvgLottieAnimation ::error, allow_raw_pointers()) .function("size", &TvgLottieAnimation ::size) .function("duration", &TvgLottieAnimation ::duration) diff --git a/wasm_build.sh b/wasm_build.sh index 5714dc31..cbd3b8ba 100755 --- a/wasm_build.sh +++ b/wasm_build.sh @@ -2,10 +2,26 @@ #https://github.com/thorvg/thorvg/wiki/ThorVG-Viewer-Development-Guide -if [ ! -d "./build_wasm" ]; then - sed "s|EMSDK:|$1|g" ./cross/wasm_x86_i686.txt > /tmp/.wasm_cross.txt - meson -Db_lto=true -Ddefault_library=static -Dstatic=true -Dloaders="all" -Dsavers="all" -Dthreads=false -Dbindings="wasm_beta" --cross-file /tmp/.wasm_cross.txt build_wasm +BACKEND="$1" +EMSDK="$2" + +if [ -z "$2" ]; then + BACKEND="all" + EMSDK="$1" fi -ninja -C build_wasm/ -ls -lrt build_wasm/src/bindings/wasm/thorvg-wasm.* +if [ ! -d "./build_wasm32_$BACKEND" ]; then + if [[ "$BACKEND" == "wg" ]]; then + sed "s|EMSDK:|$EMSDK|g" ./cross/wasm32_wg.txt > /tmp/.wasm_cross.txt + meson -Db_lto=true -Ddefault_library=static -Dstatic=true -Dloaders="all" -Dsavers="all" -Dthreads=false -Dbindings="wasm_beta" -Dengines="wg_beta" --cross-file /tmp/.wasm_cross.txt build_wasm32_wg + elif [[ "$BACKEND" == "sw" ]]; then + sed "s|EMSDK:|$EMSDK|g" ./cross/wasm32_sw.txt > /tmp/.wasm_cross.txt + meson -Db_lto=true -Ddefault_library=static -Dstatic=true -Dloaders="all" -Dsavers="all" -Dthreads=false -Dbindings="wasm_beta" --cross-file /tmp/.wasm_cross.txt build_wasm32_sw + else + sed "s|EMSDK:|$EMSDK|g" ./cross/wasm32_wg.txt > /tmp/.wasm_cross.txt + meson -Db_lto=true -Ddefault_library=static -Dstatic=true -Dloaders="all" -Dsavers="all" -Dthreads=false -Dbindings="wasm_beta" -Dengines="wg_beta, sw" --cross-file /tmp/.wasm_cross.txt build_wasm32_all + fi +fi + +ninja -C build_wasm32_$BACKEND/ +ls -lrt build_wasm32_$BACKEND/src/bindings/wasm/*.{js,wasm} diff --git a/wasm_webgpu_build.sh b/wasm_webgpu_build.sh deleted file mode 100755 index 1113cdba..00000000 --- a/wasm_webgpu_build.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -#https://github.com/thorvg/thorvg/wiki/WebGPU-Raster-Engine-Development - -if [ ! -d "./build_wasm" ]; then - sed "s|EMSDK:|$1|g" ./cross/wasm_webgpu.txt > /tmp/.wasm_cross.txt - meson -Db_lto=true -Ddefault_library=static -Dstatic=true -Dloaders="all" -Dsavers="all" -Dthreads=false -Dbindings="wasm_beta" -Dengines="wg_beta" --cross-file /tmp/.wasm_cross.txt build_wasm -fi - -ninja -C build_wasm/ -ls -lrt build_wasm/src/bindings/wasm/thorvg-wasm.*