nanovg icon indicating copy to clipboard operation
nanovg copied to clipboard

Add infrastructure to compile with emscripten

Open rconde01 opened this issue 8 years ago • 12 comments

If you did this, nanovg could be used as the basis of a web based dashboard...or lots of web based stuff I suppose.

rconde01 avatar Aug 05 '17 12:08 rconde01

The NanoVG API is based on the HTML5 Canvas API.

https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D

Using the canvas directly would be faster than rasterizing in JavaScript and drawing that onto a canvas.

indianakernick avatar Sep 10 '17 22:09 indianakernick

I've compiled nanovg with emscripten. It's pretty trivial, here is my makefile:

EXPORTED_FUNCTIONS=EXPORTED_FUNCTIONS="['_nvgBeginFrame','_nvgCancelFrame','_nvgEndFrame','_nvgGlobalCompositeOperation','_nvgGlobalCompositeBlendFunc','_nvgGlobalCompositeBlendFuncSeparate','_nvgRGB','_nvgRGBf','_nvgRGBA','_nvgRGBAf','_nvgLerpRGBA','_nvgTransRGBA','_nvgTransRGBAf','_nvgHSL','_nvgHSLA','_nvgSave','_nvgRestore','_nvgReset','_nvgShapeAntiAlias','_nvgStrokeColor','_nvgStrokePaint','_nvgFillColor','_nvgFillPaint','_nvgMiterLimit','_nvgStrokeWidth','_nvgLineCap','_nvgLineJoin','_nvgGlobalAlpha','_nvgResetTransform','_nvgTransform','_nvgTranslate','_nvgRotate','_nvgSkewX','_nvgSkewY','_nvgScale','_nvgCurrentTransform','_nvgTransformIdentity','_nvgTransformTranslate','_nvgTransformScale','_nvgTransformRotate','_nvgTransformSkewX','_nvgTransformSkewY','_nvgTransformMultiply','_nvgTransformPremultiply','_nvgTransformInverse','_nvgTransformPoint','_nvgDegToRad','_nvgRadToDeg','_nvgImageSize','_nvgDeleteImage','_nvgLinearGradient','_nvgBoxGradient','_nvgRadialGradient','_nvgImagePattern','_nvgScissor','_nvgIntersectScissor','_nvgResetScissor','_nvgBeginPath','_nvgMoveTo','_nvgLineTo','_nvgBezierTo','_nvgQuadTo','_nvgArcTo','_nvgClosePath','_nvgPathWinding','_nvgArc','_nvgRect','_nvgRoundedRect','_nvgRoundedRectVarying','_nvgEllipse','_nvgCircle','_nvgFill','_nvgStroke','_nvgCreateGLES2','_nvgDeleteGLES2','_nvglCreateImageFromHandleGLES2','_nvglImageHandleGLES2']"
# add these symbols for font support:
# ,'_nvgCreateFont','_nvgCreateFontMem','_nvgFindFont','_nvgAddFallbackFontId','_nvgAddFallbackFont','_nvgFontSize','_nvgFontBlur','_nvgTextLetterSpacing','_nvgTextLineHeight','_nvgTextAlign','_nvgFontFaceId','_nvgFontFace','_nvgText','_nvgTextBox','_nvgTextBounds','_nvgTextBoxBounds','_nvgTextGlyphPositions','_nvgTextMetrics','_nvgTextBreakLines'
EMCC_OPTIONS=-s GL_UNSAFE_OPTS=1 -s NO_EXIT_RUNTIME=1 -s $(EXPORTED_FUNCTIONS) # -s GL_PREINITIALIZED_CONTEXT=1
EMCC_INCLUDE=-I ../src

all: nanovg.js

nanovg.js: ../src/nanovg.c ../src/nanovg.h ../src/nanovg_gl.h ../src/nanovg_gl_utils.h nanovg-emscripten.c
	(cd ../src && \
	emcc -o ../emscripten/nanovg.js nanovg.c ../emscripten/nanovg-emscripten.c -Oz $(EMCC_INCLUDE) $(EMCC_OPTIONS))

debug: ../src/nanovg.c ../src/nanovg.h ../src/nanovg_gl.h ../src/nanovg_gl_utils.h nanovg-emscripten.c
	(cd ../src && \
	emcc -o ../emscripten/nanovg.js nanovg.c ../emscripten/nanovg-emscripten.c $(EMCC_INCLUDE) $(EMCC_OPTIONS))

clean:
	rm -f nanovg.js nanovg.js.*

nanovg-emscripten.c:

#include <GLES2/gl2.h>
#include "nanovg.h"
#define NANOVG_GLES2_IMPLEMENTATION
#include "nanovg_gl.h"
#include "nanovg_gl_utils.h"

The only problem is that you can't handle structures from JavaScript. What I did was to add a few functions to nanovg-emscripten.c to bridge these functions (like setting colors and image patterns).

anlumo avatar Oct 05 '17 22:10 anlumo

I was curious to experiment with this. Here is a fork that should compile with emscripten

https://github.com/olilarkin/nanovg/tree/emscripten

you can try it here: https://olilarkin.github.io/nanovg/

it is slow! didn't try and optimise anything

olilarkin avatar Apr 22 '18 15:04 olilarkin

Very nice! However, the wasm code was blocked by my adblocker for some reason…

Anyways, I only get 35fps on my GeForce 1080, there's definitely room for improvement there. I think the most important first step would be to reduce the number of gl calls to the bare minimum.

anlumo avatar Apr 22 '18 16:04 anlumo

i get 60FPS in firefox and 25 FPS in chrome!

olilarkin avatar May 08 '18 16:05 olilarkin

I've added a JavaScript bindings project and ported the demo.

https://github.com/flyover/nanovg-js

flyover avatar Aug 22 '18 12:08 flyover

silly me had NVG_DEBUG enabled which was causing slow performance in chrome, but not elsewhere. New version: https://olilarkin.github.io/nanovg/

olilarkin avatar Aug 25 '18 10:08 olilarkin

Can anyone think why Nano VG via WebGL would cause the warning "[.WebGL-0x7f8bff05b400]RENDER WARNING: there is no texture bound to the unit 0" ?

olilarkin avatar Nov 08 '18 14:11 olilarkin

@olilarkin nanovg uses one shader for all fill types and there's if statement choosing which fill type to use. In case of solid fill, there's no texture bound to unit 0. It is be fine by all means, but that webgl implementation might see texture sampler in the shader and whine about it.

memononen avatar Nov 08 '18 18:11 memononen

I'm seeing the same thing. The problem with it (besides log spam) is that after 100 of these, WebGL in Chrome stops logging altogether, and I'm missing any messages that happen after that, even if they're important.

anlumo avatar Nov 08 '18 19:11 anlumo

The Metal port faced the same issue (in legacy Metal versions) and it was resolved by passing an empty texture. Maybe it works for the GL backend, too.

https://github.com/ollix/MetalNanoVG/blob/92351749f97b0ce984c1e54c39a6fb6c2a0e9ed4/src/nanovg_mtl.m#L520-L521

olliwang avatar Nov 08 '18 20:11 olliwang

thanks @olliwang I followed roughly what you did in MetalNanoVG and fixed the issue here https://github.com/memononen/nanovg/pull/566

olilarkin avatar Mar 02 '20 21:03 olilarkin