gl_engine: support cross compile GL backend into WASM

Support cross compile the GL backend code into WASM.
The code needs WebGL 2.0 API so, the compile flags contains `MAX_WEBGL_VERSION` and `FULL_ES3`
Also add binding code to initialize the WebGL context and GLCanvas.
This commit is contained in:
RuiwenTang 2024-11-08 15:31:33 +08:00 committed by Hermet Park
parent 0f409a654a
commit af5e0e3ef9
5 changed files with 85 additions and 2 deletions

21
cross/wasm32_gl.txt Normal file
View file

@ -0,0 +1,21 @@
[binaries]
cpp = 'EMSDK:upstream/emscripten/em++.py'
ar = 'EMSDK:upstream/emscripten/emar.py'
strip = '-strip'
[properties]
root = 'EMSDK:upstream/emscripten/system'
shared_lib_suffix = 'js'
static_lib_suffix = 'js'
shared_module_suffix = 'js'
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', '-sMAX_WEBGL_VERSION=2', '-sFULL_ES3']
[host_machine]
system = 'emscripten'
cpu_family = 'wasm32'
cpu = 'wasm32'
endian = 'little'

View file

@ -27,6 +27,9 @@
#ifdef THORVG_WG_RASTER_SUPPORT #ifdef THORVG_WG_RASTER_SUPPORT
#include <webgpu/webgpu.h> #include <webgpu/webgpu.h>
#endif #endif
#ifdef THORVG_GL_RASTER_SUPPORT
#include <emscripten/html5_webgl.h>
#endif
using namespace emscripten; using namespace emscripten;
using namespace std; using namespace std;
@ -155,6 +158,54 @@ struct TvgWgEngine : TvgEngineMethod
} }
}; };
struct TvgGLEngine : TvgEngineMethod
{
uintptr_t context = 0;
~TvgGLEngine() override
{
#ifdef THORVG_GL_RASTER_SUPPORT
if (context) {
Initializer::term(tvg::CanvasEngine::Gl);
emscripten_webgl_destroy_context(context);
context = 0;
}
#endif
}
Canvas* init(string& selector) override
{
#ifdef THORVG_GL_RASTER_SUPPORT
EmscriptenWebGLContextAttributes attrs{};
attrs.alpha = true;
attrs.depth = false;
attrs.stencil = false;
attrs.premultipliedAlpha = true;
attrs.failIfMajorPerformanceCaveat = false;
attrs.majorVersion = 2;
attrs.minorVersion = 0;
attrs.enableExtensionsByDefault = true;
context = emscripten_webgl_create_context(selector.c_str(), &attrs);
if (context == 0) return nullptr;
emscripten_webgl_make_context_current(context);
#endif
if (Initializer::init(0, tvg::CanvasEngine::Gl) != Result::Success) return nullptr;
return GlCanvas::gen();
}
void resize(Canvas* canvas, int w, int h) override
{
#ifdef THORVG_GL_RASTER_SUPPORT
emscripten_webgl_make_context_current(context);
static_cast<GlCanvas*>(canvas)->target(0, w, h);
#endif
}
};
class __attribute__((visibility("default"))) TvgLottieAnimation class __attribute__((visibility("default"))) TvgLottieAnimation
{ {
@ -171,6 +222,7 @@ public:
errorMsg = NoError; errorMsg = NoError;
if (engine == "sw") this->engine = new TvgSwEngine; if (engine == "sw") this->engine = new TvgSwEngine;
else if (engine == "gl") this->engine = new TvgGLEngine;
else if (engine == "wg") this->engine = new TvgWgEngine; else if (engine == "wg") this->engine = new TvgWgEngine;
if (!this->engine) { if (!this->engine) {

View file

@ -26,6 +26,9 @@ source_file = [
if host_machine.system() == 'darwin' if host_machine.system() == 'darwin'
gl_dep = declare_dependency(link_args: ['-framework', 'OpenGL']) gl_dep = declare_dependency(link_args: ['-framework', 'OpenGL'])
compiler_flags += ['-Wno-deprecated'] #for deprecated opengl compiler_flags += ['-Wno-deprecated'] #for deprecated opengl
elif cc.get_id() == 'emscripten'
target_opengles = true
gl_dep = dependency('GLESv3', required: false)
else else
#find a opengl library with fallbacks #find a opengl library with fallbacks
gl_dep = dependency('GL', required: false) gl_dep = dependency('GL', required: false)

View file

@ -42,8 +42,11 @@
#include "tvgCommon.h" #include "tvgCommon.h"
#include "tvgRender.h" #include "tvgRender.h"
#ifdef __EMSCRIPTEN__
#define GL_CHECK(x) \ // query GL Error on WebGL is very slow, so disable it on WebGL
#define GL_CHECK(x) x
#else
#define GL_CHECK(x) \
x; \ x; \
do { \ do { \
GLenum glError = glGetError(); \ GLenum glError = glGetError(); \
@ -52,6 +55,7 @@
assert(0); \ assert(0); \
} \ } \
} while(0) } while(0)
#endif
enum class GlStencilMode { enum class GlStencilMode {
None, None,

View file

@ -17,6 +17,9 @@ if [ ! -d "./build_wasm" ]; then
elif [[ "$BACKEND" == "sw" ]]; then elif [[ "$BACKEND" == "sw" ]]; then
sed "s|EMSDK:|$EMSDK|g" ./cross/wasm32_sw.txt > /tmp/.wasm_cross.txt 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_wasm 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
elif [[ "$BACKEND" == "gl" ]]; then
sed "s|EMSDK:|$EMSDK|g" ./cross/wasm32_gl.txt > /tmp/.wasm_cross.txt
meson -Db_lto=true -Ddefault_library=static -Dstatic=true -Dloaders="all" -Dsavers="all" -Dthreads=false -Dbindings="wasm_beta" -Dengines="gl" --cross-file /tmp/.wasm_cross.txt build_wasm
else else
sed "s|EMSDK:|$EMSDK|g" ./cross/wasm32_wg.txt > /tmp/.wasm_cross.txt 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, sw" --cross-file /tmp/.wasm_cross.txt build_wasm meson -Db_lto=true -Ddefault_library=static -Dstatic=true -Dloaders="all" -Dsavers="all" -Dthreads=false -Dbindings="wasm_beta" -Dengines="wg, sw" --cross-file /tmp/.wasm_cross.txt build_wasm