mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 05:33:36 +00:00
bindings/wasm: Support WebGPU
Updated WASM binding to bring WebGPU on the web player. binding will generate a WASM binary, which can render animation through both SW and WG raster engine. A raster engine will be chosen by parameter `engine`, when initializing.
This commit is contained in:
parent
32954f962d
commit
d704a2503a
5 changed files with 111 additions and 47 deletions
|
@ -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'
|
|
@ -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'
|
|
@ -23,6 +23,9 @@
|
|||
#include <thorvg.h>
|
||||
#include <emscripten/bind.h>
|
||||
#include "tvgPicture.h"
|
||||
#ifdef THORVG_WG_RASTER_SUPPORT
|
||||
#include <webgpu/webgpu.h>
|
||||
#endif
|
||||
|
||||
using namespace emscripten;
|
||||
using namespace std;
|
||||
|
@ -35,13 +38,60 @@ class __attribute__((visibility("default"))) TvgLottieAnimation
|
|||
public:
|
||||
~TvgLottieAnimation()
|
||||
{
|
||||
free(buffer);
|
||||
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();
|
||||
}
|
||||
|
||||
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(0, this->engine) != 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(0, this->engine) != 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<uint8_t>(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()
|
||||
|
@ -186,9 +237,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<SwCanvas*>(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<WgCanvas*>(canvas.get())->target(this->instance, this->surface, width, height);
|
||||
#endif
|
||||
}
|
||||
|
||||
float scale;
|
||||
float shiftX = 0.0f, shiftY = 0.0f;
|
||||
|
@ -311,38 +370,39 @@ public:
|
|||
// TODO: Advanced APIs wrt Interactivity & theme methods...
|
||||
|
||||
private:
|
||||
explicit TvgLottieAnimation()
|
||||
val output()
|
||||
{
|
||||
errorMsg = NoError;
|
||||
|
||||
if (Initializer::init(0) != Result::Success) {
|
||||
errorMsg = "init() fail";
|
||||
return;
|
||||
if (engine == tvg::CanvasEngine::Sw) {
|
||||
#ifdef THORVG_SW_RASTER_SUPPORT
|
||||
return val(typed_memory_view(width * height * 4, buffer));
|
||||
#endif
|
||||
}
|
||||
|
||||
canvas = SwCanvas::gen();
|
||||
if (!canvas) errorMsg = "Invalid canvas";
|
||||
|
||||
animation = Animation::gen();
|
||||
if (!animation) errorMsg = "Invalid animation";
|
||||
return val(typed_memory_view<uint8_t>(0, nullptr));
|
||||
}
|
||||
|
||||
private:
|
||||
string errorMsg;
|
||||
unique_ptr<SwCanvas> canvas = nullptr;
|
||||
CanvasEngine engine;
|
||||
unique_ptr<Canvas> canvas = nullptr;
|
||||
unique_ptr<Animation> 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>("TvgLottieAnimation")
|
||||
.constructor(&TvgLottieAnimation ::create)
|
||||
.constructor<string, string>()
|
||||
.function("error", &TvgLottieAnimation ::error, allow_raw_pointers())
|
||||
.function("size", &TvgLottieAnimation ::size)
|
||||
.function("duration", &TvgLottieAnimation ::duration)
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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.*
|
Loading…
Add table
Reference in a new issue