binding/wasm: code refactoring

removed a bunch of #ifdefs and consolidated
implementations across engines.
This commit is contained in:
Hermet Park 2025-03-28 22:58:01 +09:00 committed by Hermet Park
parent 1928f46e6a
commit fa332dbc84

View file

@ -25,12 +25,6 @@
#include <emscripten/bind.h> #include <emscripten/bind.h>
#include "tvgPicture.h" #include "tvgPicture.h"
#include "tvgWasmDefaultFont.h" #include "tvgWasmDefaultFont.h"
#ifdef THORVG_WG_RASTER_SUPPORT
#include <emscripten/html5_webgpu.h>
#endif
#ifdef THORVG_GL_RASTER_SUPPORT
#include <emscripten/html5_webgl.h>
#endif
using namespace emscripten; using namespace emscripten;
using namespace std; using namespace std;
@ -38,75 +32,6 @@ using namespace tvg;
static const char* NoError = "None"; static const char* NoError = "None";
#ifdef THORVG_WG_RASTER_SUPPORT
static WGPUInstance instance{};
static WGPUAdapter adapter{};
static WGPUDevice device{};
static bool adapterRequested = false;
static bool deviceRequested = false;
static bool initializationFailed = false;
#endif
// 0: success, 1: fail, 2: wait for async request
int init()
{
#ifdef THORVG_WG_RASTER_SUPPORT
if (initializationFailed) return 1;
//Init WebGPU
if (!instance) instance = wgpuCreateInstance(nullptr);
// request adapter
if (!adapter) {
if (adapterRequested) return 2;
const WGPURequestAdapterOptions requestAdapterOptions { .nextInChain = nullptr, .powerPreference = WGPUPowerPreference_HighPerformance, .forceFallbackAdapter = false };
auto onAdapterRequestEnded = [](WGPURequestAdapterStatus status, WGPUAdapter adapter, char const* message, void* pUserData) {
if (status != WGPURequestAdapterStatus_Success) {
initializationFailed = true;
return;
}
*((WGPUAdapter*)pUserData) = adapter;
};
wgpuInstanceRequestAdapter(instance, &requestAdapterOptions, onAdapterRequestEnded, &adapter);
adapterRequested = true;
return 2;
}
// request device
if (deviceRequested) return device == nullptr ? 2 : 0;
WGPUFeatureName featureNames[32]{};
size_t featuresCount = wgpuAdapterEnumerateFeatures(adapter, featureNames);
if (!device) {
const WGPUDeviceDescriptor deviceDesc { .nextInChain = nullptr, .label = "The device", .requiredFeatureCount = featuresCount, .requiredFeatures = featureNames };
auto onDeviceRequestEnded = [](WGPURequestDeviceStatus status, WGPUDevice device, char const* message, void* pUserData) {
if (status != WGPURequestDeviceStatus_Success) {
initializationFailed = true;
return;
}
*((WGPUDevice*)pUserData) = device;
};
wgpuAdapterRequestDevice(adapter, &deviceDesc, onDeviceRequestEnded, &device);
deviceRequested = true;
return 2;
}
#endif
return 0;
}
void term()
{
#ifdef THORVG_WG_RASTER_SUPPORT
wgpuDeviceRelease(device);
wgpuAdapterRelease(adapter);
wgpuInstanceRelease(instance);
#endif
}
struct TvgEngineMethod struct TvgEngineMethod
{ {
virtual ~TvgEngineMethod() {} virtual ~TvgEngineMethod() {}
@ -154,24 +79,30 @@ struct TvgSwEngine : TvgEngineMethod
}; };
#ifdef THORVG_WG_RASTER_SUPPORT
#include <emscripten/html5_webgpu.h>
static WGPUInstance instance{};
static WGPUAdapter adapter{};
static WGPUDevice device{};
static bool adapterRequested = false;
static bool deviceRequested = false;
static bool initializationFailed = false;
struct TvgWgEngine : TvgEngineMethod struct TvgWgEngine : TvgEngineMethod
{ {
#ifdef THORVG_WG_RASTER_SUPPORT
WGPUSurface surface{}; WGPUSurface surface{};
#endif
~TvgWgEngine() ~TvgWgEngine()
{ {
#ifdef THORVG_WG_RASTER_SUPPORT
wgpuSurfaceRelease(surface); wgpuSurfaceRelease(surface);
Initializer::term(tvg::CanvasEngine::Wg); Initializer::term(tvg::CanvasEngine::Wg);
retrieveFont(); retrieveFont();
#endif
} }
Canvas* init(string& selector) override Canvas* init(string& selector) override
{ {
#ifdef THORVG_WG_RASTER_SUPPORT
WGPUSurfaceDescriptorFromCanvasHTMLSelector canvasDesc{}; WGPUSurfaceDescriptorFromCanvasHTMLSelector canvasDesc{};
canvasDesc.chain.next = nullptr; canvasDesc.chain.next = nullptr;
canvasDesc.chain.sType = WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector; canvasDesc.chain.sType = WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector;
@ -184,37 +115,91 @@ struct TvgWgEngine : TvgEngineMethod
Initializer::init(0, tvg::CanvasEngine::Wg); Initializer::init(0, tvg::CanvasEngine::Wg);
loadFont(); loadFont();
return WgCanvas::gen(); return WgCanvas::gen();
#else
return nullptr;
#endif
} }
void resize(Canvas* canvas, int w, int h) override void resize(Canvas* canvas, int w, int h) override
{ {
#ifdef THORVG_WG_RASTER_SUPPORT
if (canvas) static_cast<WgCanvas*>(canvas)->target(device, instance, surface, w, h, ColorSpace::ABGR8888S); if (canvas) static_cast<WgCanvas*>(canvas)->target(device, instance, surface, w, h, ColorSpace::ABGR8888S);
#endif
} }
static int init()
{
if (initializationFailed) return 1;
//Init WebGPU
if (!instance) instance = wgpuCreateInstance(nullptr);
// request adapter
if (!adapter) {
if (adapterRequested) return 2;
const WGPURequestAdapterOptions requestAdapterOptions { .nextInChain = nullptr, .powerPreference = WGPUPowerPreference_HighPerformance, .forceFallbackAdapter = false };
auto onAdapterRequestEnded = [](WGPURequestAdapterStatus status, WGPUAdapter adapter, char const* message, void* pUserData) {
if (status != WGPURequestAdapterStatus_Success) {
initializationFailed = true;
return;
}
*((WGPUAdapter*)pUserData) = adapter;
}; };
wgpuInstanceRequestAdapter(instance, &requestAdapterOptions, onAdapterRequestEnded, &adapter);
adapterRequested = true;
return 2;
}
// request device
if (deviceRequested) return device == nullptr ? 2 : 0;
WGPUFeatureName featureNames[32]{};
size_t featuresCount = wgpuAdapterEnumerateFeatures(adapter, featureNames);
if (!device) {
const WGPUDeviceDescriptor deviceDesc { .nextInChain = nullptr, .label = "The device", .requiredFeatureCount = featuresCount, .requiredFeatures = featureNames };
auto onDeviceRequestEnded = [](WGPURequestDeviceStatus status, WGPUDevice device, char const* message, void* pUserData) {
if (status != WGPURequestDeviceStatus_Success) {
initializationFailed = true;
return;
}
*((WGPUDevice*)pUserData) = device;
};
wgpuAdapterRequestDevice(adapter, &deviceDesc, onDeviceRequestEnded, &device);
deviceRequested = true;
return 2;
}
return 0;
}
static void term()
{
wgpuDeviceRelease(device);
wgpuAdapterRelease(adapter);
wgpuInstanceRelease(instance);
}
};
#endif
#ifdef THORVG_GL_RASTER_SUPPORT
#include <emscripten/html5_webgl.h>
struct TvgGLEngine : TvgEngineMethod struct TvgGLEngine : TvgEngineMethod
{ {
intptr_t context = 0; intptr_t context = 0;
~TvgGLEngine() override
~TvgGLEngine()
{ {
#ifdef THORVG_GL_RASTER_SUPPORT
if (context) { if (context) {
Initializer::term(tvg::CanvasEngine::Gl); Initializer::term(tvg::CanvasEngine::Gl);
emscripten_webgl_destroy_context(context); emscripten_webgl_destroy_context(context);
context = 0; context = 0;
} }
retrieveFont(); retrieveFont();
#endif
} }
Canvas* init(string& selector) override Canvas* init(string& selector) override
{ {
#ifdef THORVG_GL_RASTER_SUPPORT
EmscriptenWebGLContextAttributes attrs{}; EmscriptenWebGLContextAttributes attrs{};
attrs.alpha = true; attrs.alpha = true;
attrs.depth = false; attrs.depth = false;
@ -234,9 +219,6 @@ struct TvgGLEngine : TvgEngineMethod
loadFont(); loadFont();
return GlCanvas::gen(); return GlCanvas::gen();
#else
return nullptr;
#endif
} }
void resize(Canvas* canvas, int w, int h) override void resize(Canvas* canvas, int w, int h) override
@ -244,6 +226,7 @@ struct TvgGLEngine : TvgEngineMethod
if (canvas) static_cast<GlCanvas*>(canvas)->target((void*)context, 0, w, h, ColorSpace::ABGR8888S); if (canvas) static_cast<GlCanvas*>(canvas)->target((void*)context, 0, w, h, ColorSpace::ABGR8888S);
} }
}; };
#endif
class __attribute__((visibility("default"))) TvgLottieAnimation class __attribute__((visibility("default"))) TvgLottieAnimation
@ -261,8 +244,12 @@ public:
errorMsg = NoError; errorMsg = NoError;
if (engine == "sw") this->engine = new TvgSwEngine; if (engine == "sw") this->engine = new TvgSwEngine;
#ifdef THORVG_GL_RASTER_SUPPORT
else if (engine == "gl") this->engine = new TvgGLEngine; else if (engine == "gl") this->engine = new TvgGLEngine;
#endif
#ifdef THORVG_WG_RASTER_SUPPORT
else if (engine == "wg") this->engine = new TvgWgEngine; else if (engine == "wg") this->engine = new TvgWgEngine;
#endif
if (!this->engine) { if (!this->engine) {
errorMsg = "Invalid engine"; errorMsg = "Invalid engine";
@ -285,7 +272,6 @@ public:
return errorMsg; return errorMsg;
} }
// Getter methods
val size() val size()
{ {
return val(typed_memory_view(2, psize)); return val(typed_memory_view(2, psize));
@ -309,7 +295,6 @@ public:
return animation->curFrame(); return animation->curFrame();
} }
// Render methods
bool load(string data, string mimetype, int width, int height, string rpath = "") bool load(string data, string mimetype, int width, int height, string rpath = "")
{ {
errorMsg = NoError; errorMsg = NoError;
@ -435,11 +420,9 @@ public:
updated = true; updated = true;
} }
// Saver methods
bool save(string data, string mimetype) bool save(string data, string mimetype)
{ {
if (mimetype == "gif") return save2Gif(data); if (mimetype == "gif") return save2Gif(data);
errorMsg = "Invalid mimetype"; errorMsg = "Invalid mimetype";
return false; return false;
} }
@ -491,7 +474,7 @@ public:
bg->fill(255, 255, 255, 255); bg->fill(255, 255, 255, 255);
bg->appendRect(0, 0, GIF_SIZE, GIF_SIZE); bg->appendRect(0, 0, GIF_SIZE, GIF_SIZE);
if (saver->background(std::move(bg)) != Result::Success) { if (saver->background(bg) != Result::Success) {
errorMsg = "background() fail"; errorMsg = "background() fail";
return false; return false;
} }
@ -519,6 +502,25 @@ private:
bool updated = false; bool updated = false;
}; };
// 0: success, 1: fail, 2: wait for async request
int init()
{
#ifdef THORVG_WG_RASTER_SUPPORT
TvgWgEngine::init();
#endif
return 0;
}
void term()
{
#ifdef THORVG_WG_RASTER_SUPPORT
TvgWgEngine::term();
#endif
}
EMSCRIPTEN_BINDINGS(thorvg_bindings) EMSCRIPTEN_BINDINGS(thorvg_bindings)
{ {
emscripten::function("init", &init); emscripten::function("init", &init);