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]
|
[built-in options]
|
||||||
cpp_args = ['-Wshift-negative-value', '-flto', '-Os', '-fno-exceptions']
|
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', '-sEXPORT_ES6=1', '-sFORCE_FILESYSTEM=1', '-sMODULARIZE=1', '-sEXPORTED_RUNTIME_METHODS=FS']
|
||||||
#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
|
|
||||||
|
|
||||||
[host_machine]
|
[host_machine]
|
||||||
system = 'emscripten'
|
system = 'emscripten'
|
||||||
cpu_family = 'x86'
|
cpu_family = 'wasm32'
|
||||||
cpu = 'i686'
|
cpu = 'wasm32'
|
||||||
endian = 'little'
|
endian = 'little'
|
|
@ -12,7 +12,7 @@ exe_suffix = 'js'
|
||||||
|
|
||||||
[built-in options]
|
[built-in options]
|
||||||
cpp_args = ['-Wshift-negative-value', '-flto', '-Os', '-fno-exceptions']
|
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]
|
[host_machine]
|
||||||
system = 'emscripten'
|
system = 'emscripten'
|
|
@ -23,6 +23,9 @@
|
||||||
#include <thorvg.h>
|
#include <thorvg.h>
|
||||||
#include <emscripten/bind.h>
|
#include <emscripten/bind.h>
|
||||||
#include "tvgPicture.h"
|
#include "tvgPicture.h"
|
||||||
|
#ifdef THORVG_WG_RASTER_SUPPORT
|
||||||
|
#include <webgpu/webgpu.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace emscripten;
|
using namespace emscripten;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -35,13 +38,60 @@ class __attribute__((visibility("default"))) TvgLottieAnimation
|
||||||
public:
|
public:
|
||||||
~TvgLottieAnimation()
|
~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();
|
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()
|
string error()
|
||||||
|
@ -85,8 +135,7 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//back up for saving
|
this->data = data; //back up for saving
|
||||||
this->data = data;
|
|
||||||
|
|
||||||
canvas->clear(true);
|
canvas->clear(true);
|
||||||
|
|
||||||
|
@ -126,7 +175,9 @@ public:
|
||||||
|
|
||||||
if (!canvas || !animation) return val(typed_memory_view<uint8_t>(0, nullptr));
|
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) {
|
if (canvas->draw() != Result::Success) {
|
||||||
errorMsg = "draw() fail";
|
errorMsg = "draw() fail";
|
||||||
|
@ -137,7 +188,7 @@ public:
|
||||||
|
|
||||||
updated = false;
|
updated = false;
|
||||||
|
|
||||||
return val(typed_memory_view(width * height * 4, buffer));
|
return output();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool update()
|
bool update()
|
||||||
|
@ -186,9 +237,17 @@ public:
|
||||||
this->width = width;
|
this->width = width;
|
||||||
this->height = height;
|
this->height = height;
|
||||||
|
|
||||||
free(buffer);
|
if (engine == tvg::CanvasEngine::Sw) {
|
||||||
buffer = (uint8_t*)malloc(width * height * sizeof(uint32_t));
|
#ifdef THORVG_SW_RASTER_SUPPORT
|
||||||
canvas->target((uint32_t *)buffer, width, width, height, SwCanvas::ABGR8888S);
|
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 scale;
|
||||||
float shiftX = 0.0f, shiftY = 0.0f;
|
float shiftX = 0.0f, shiftY = 0.0f;
|
||||||
|
@ -311,38 +370,39 @@ public:
|
||||||
// TODO: Advanced APIs wrt Interactivity & theme methods...
|
// TODO: Advanced APIs wrt Interactivity & theme methods...
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit TvgLottieAnimation()
|
val output()
|
||||||
{
|
{
|
||||||
errorMsg = NoError;
|
if (engine == tvg::CanvasEngine::Sw) {
|
||||||
|
#ifdef THORVG_SW_RASTER_SUPPORT
|
||||||
if (Initializer::init(0) != Result::Success) {
|
return val(typed_memory_view(width * height * 4, buffer));
|
||||||
errorMsg = "init() fail";
|
#endif
|
||||||
return;
|
}
|
||||||
}
|
return val(typed_memory_view<uint8_t>(0, nullptr));
|
||||||
|
|
||||||
canvas = SwCanvas::gen();
|
|
||||||
if (!canvas) errorMsg = "Invalid canvas";
|
|
||||||
|
|
||||||
animation = Animation::gen();
|
|
||||||
if (!animation) errorMsg = "Invalid animation";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
string errorMsg;
|
string errorMsg;
|
||||||
unique_ptr<SwCanvas> canvas = nullptr;
|
CanvasEngine engine;
|
||||||
|
unique_ptr<Canvas> canvas = nullptr;
|
||||||
unique_ptr<Animation> animation = nullptr;
|
unique_ptr<Animation> animation = nullptr;
|
||||||
string data;
|
string data;
|
||||||
uint8_t* buffer = nullptr;
|
|
||||||
uint32_t width = 0;
|
uint32_t width = 0;
|
||||||
uint32_t height = 0;
|
uint32_t height = 0;
|
||||||
float psize[2]; //picture size
|
float psize[2]; //picture size
|
||||||
bool updated = false;
|
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)
|
EMSCRIPTEN_BINDINGS(thorvg_bindings)
|
||||||
{
|
{
|
||||||
class_<TvgLottieAnimation>("TvgLottieAnimation")
|
class_<TvgLottieAnimation>("TvgLottieAnimation")
|
||||||
.constructor(&TvgLottieAnimation ::create)
|
.constructor<string, string>()
|
||||||
.function("error", &TvgLottieAnimation ::error, allow_raw_pointers())
|
.function("error", &TvgLottieAnimation ::error, allow_raw_pointers())
|
||||||
.function("size", &TvgLottieAnimation ::size)
|
.function("size", &TvgLottieAnimation ::size)
|
||||||
.function("duration", &TvgLottieAnimation ::duration)
|
.function("duration", &TvgLottieAnimation ::duration)
|
||||||
|
|
|
@ -2,10 +2,26 @@
|
||||||
|
|
||||||
#https://github.com/thorvg/thorvg/wiki/ThorVG-Viewer-Development-Guide
|
#https://github.com/thorvg/thorvg/wiki/ThorVG-Viewer-Development-Guide
|
||||||
|
|
||||||
if [ ! -d "./build_wasm" ]; then
|
BACKEND="$1"
|
||||||
sed "s|EMSDK:|$1|g" ./cross/wasm_x86_i686.txt > /tmp/.wasm_cross.txt
|
EMSDK="$2"
|
||||||
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
|
|
||||||
|
if [ -z "$2" ]; then
|
||||||
|
BACKEND="all"
|
||||||
|
EMSDK="$1"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ninja -C build_wasm/
|
if [ ! -d "./build_wasm32_$BACKEND" ]; then
|
||||||
ls -lrt build_wasm/src/bindings/wasm/thorvg-wasm.*
|
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