diff --git a/src/nanovg.c b/src/nanovg.c index 5fdbd66..bb0f038 100644 --- a/src/nanovg.c +++ b/src/nanovg.c @@ -112,6 +112,14 @@ struct NVGpathCache { }; typedef struct NVGpathCache NVGpathCache; +struct NVGfontContext { // Fontstash context plus font images; shared between shared NanoVG contexts. + int refCount; + struct FONScontext* fs; + int fontImages[NVG_MAX_FONTIMAGES]; + int fontImageIdx; +}; +typedef struct NVGfontContext NVGfontContext; + struct NVGcontext { NVGparams params; float* commands; @@ -125,9 +133,7 @@ struct NVGcontext { float distTol; float fringeWidth; float devicePxRatio; - struct FONScontext* fs; - int fontImages[NVG_MAX_FONTIMAGES]; - int fontImageIdx; + NVGfontContext* fontContext; int drawCallCount; int fillTriCount; int strokeTriCount; @@ -286,7 +292,7 @@ static NVGstate* nvg__getState(NVGcontext* ctx) return &ctx->states[ctx->nstates-1]; } -NVGcontext* nvgCreateInternal(NVGparams* params) +NVGcontext* nvgCreateInternal(NVGparams* params, NVGcontext* other) // Share the fonts and images of 'other' if it's non-NULL. { FONSparams fontParams; NVGcontext* ctx = (NVGcontext*)malloc(sizeof(NVGcontext)); @@ -295,8 +301,16 @@ NVGcontext* nvgCreateInternal(NVGparams* params) memset(ctx, 0, sizeof(NVGcontext)); ctx->params = *params; - for (i = 0; i < NVG_MAX_FONTIMAGES; i++) - ctx->fontImages[i] = 0; + if (other) { + ctx->fontContext = other->fontContext; + ctx->fontContext->refCount++; + } else { + ctx->fontContext = (NVGfontContext*)malloc(sizeof(NVGfontContext)); + if (ctx->fontContext == NULL) goto error; + for (i = 0; i < NVG_MAX_FONTIMAGES; i++) + ctx->fontContext->fontImages[i] = 0; + ctx->fontContext->refCount = 1; + } ctx->commands = (float*)malloc(sizeof(float)*NVG_INIT_COMMANDS_SIZE); if (!ctx->commands) goto error; @@ -311,25 +325,27 @@ NVGcontext* nvgCreateInternal(NVGparams* params) nvg__setDevicePixelRatio(ctx, 1.0f); - if (ctx->params.renderCreate(ctx->params.userPtr) == 0) goto error; + if (ctx->params.renderCreate(ctx->params.userPtr, other ? other->params.userPtr : NULL) == 0) goto error; // Init font rendering - memset(&fontParams, 0, sizeof(fontParams)); - fontParams.width = NVG_INIT_FONTIMAGE_SIZE; - fontParams.height = NVG_INIT_FONTIMAGE_SIZE; - fontParams.flags = FONS_ZERO_TOPLEFT; - fontParams.renderCreate = NULL; - fontParams.renderUpdate = NULL; - fontParams.renderDraw = NULL; - fontParams.renderDelete = NULL; - fontParams.userPtr = NULL; - ctx->fs = fonsCreateInternal(&fontParams); - if (ctx->fs == NULL) goto error; - - // Create font texture - ctx->fontImages[0] = ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_ALPHA, fontParams.width, fontParams.height, 0, NULL); - if (ctx->fontImages[0] == 0) goto error; - ctx->fontImageIdx = 0; + if (!other) { + memset(&fontParams, 0, sizeof(fontParams)); + fontParams.width = NVG_INIT_FONTIMAGE_SIZE; + fontParams.height = NVG_INIT_FONTIMAGE_SIZE; + fontParams.flags = FONS_ZERO_TOPLEFT; + fontParams.renderCreate = NULL; + fontParams.renderUpdate = NULL; + fontParams.renderDraw = NULL; + fontParams.renderDelete = NULL; + fontParams.userPtr = NULL; + ctx->fontContext->fs = fonsCreateInternal(&fontParams); + if (ctx->fontContext->fs == NULL) goto error; + + // Create font texture + ctx->fontContext->fontImages[0] = ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_ALPHA, fontParams.width, fontParams.height, 0, NULL); + if (ctx->fontContext->fontImages[0] == 0) goto error; + ctx->fontContext->fontImageIdx = 0; + } return ctx; @@ -350,14 +366,18 @@ void nvgDeleteInternal(NVGcontext* ctx) if (ctx->commands != NULL) free(ctx->commands); if (ctx->cache != NULL) nvg__deletePathCache(ctx->cache); - if (ctx->fs) - fonsDeleteInternal(ctx->fs); + if (ctx->fontContext != NULL && --ctx->fontContext->refCount == 0) { + if (ctx->fontContext->fs) + fonsDeleteInternal(ctx->fontContext->fs); - for (i = 0; i < NVG_MAX_FONTIMAGES; i++) { - if (ctx->fontImages[i] != 0) { - nvgDeleteImage(ctx, ctx->fontImages[i]); - ctx->fontImages[i] = 0; + for (i = 0; i < NVG_MAX_FONTIMAGES; i++) { + if (ctx->fontContext->fontImages[i] != 0) { + nvgDeleteImage(ctx, ctx->fontContext->fontImages[i]); + ctx->fontContext->fontImages[i] = 0; + } } + + free(ctx->fontContext); } if (ctx->params.renderDelete != NULL) @@ -394,30 +414,30 @@ void nvgCancelFrame(NVGcontext* ctx) void nvgEndFrame(NVGcontext* ctx) { ctx->params.renderFlush(ctx->params.userPtr); - if (ctx->fontImageIdx != 0) { - int fontImage = ctx->fontImages[ctx->fontImageIdx]; + if (ctx->fontContext->fontImageIdx != 0) { + int fontImage = ctx->fontContext->fontImages[ctx->fontContext->fontImageIdx]; int i, j, iw, ih; // delete images that smaller than current one if (fontImage == 0) return; nvgImageSize(ctx, fontImage, &iw, &ih); - for (i = j = 0; i < ctx->fontImageIdx; i++) { - if (ctx->fontImages[i] != 0) { + for (i = j = 0; i < ctx->fontContext->fontImageIdx; i++) { + if (ctx->fontContext->fontImages[i] != 0) { int nw, nh; - nvgImageSize(ctx, ctx->fontImages[i], &nw, &nh); + nvgImageSize(ctx, ctx->fontContext->fontImages[i], &nw, &nh); if (nw < iw || nh < ih) - nvgDeleteImage(ctx, ctx->fontImages[i]); + nvgDeleteImage(ctx, ctx->fontContext->fontImages[i]); else - ctx->fontImages[j++] = ctx->fontImages[i]; + ctx->fontContext->fontImages[j++] = ctx->fontContext->fontImages[i]; } } // make current font image to first - ctx->fontImages[j++] = ctx->fontImages[0]; - ctx->fontImages[0] = fontImage; - ctx->fontImageIdx = 0; + ctx->fontContext->fontImages[j++] = ctx->fontContext->fontImages[0]; + ctx->fontContext->fontImages[0] = fontImage; + ctx->fontContext->fontImageIdx = 0; // clear all images after j for (i = j; i < NVG_MAX_FONTIMAGES; i++) - ctx->fontImages[i] = 0; + ctx->fontContext->fontImages[i] = 0; } } @@ -2309,35 +2329,35 @@ void nvgStroke(NVGcontext* ctx) // Add fonts int nvgCreateFont(NVGcontext* ctx, const char* name, const char* filename) { - return fonsAddFont(ctx->fs, name, filename, 0); + return fonsAddFont(ctx->fontContext->fs, name, filename, 0); } int nvgCreateFontAtIndex(NVGcontext* ctx, const char* name, const char* filename, const int fontIndex) { - return fonsAddFont(ctx->fs, name, filename, fontIndex); + return fonsAddFont(ctx->fontContext->fs, name, filename, fontIndex); } int nvgCreateFontMem(NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData) { - return fonsAddFontMem(ctx->fs, name, data, ndata, freeData, 0); + return fonsAddFontMem(ctx->fontContext->fs, name, data, ndata, freeData, 0); } int nvgCreateFontMemAtIndex(NVGcontext* ctx, const char* name, unsigned char* data, int ndata, int freeData, const int fontIndex) { - return fonsAddFontMem(ctx->fs, name, data, ndata, freeData, fontIndex); + return fonsAddFontMem(ctx->fontContext->fs, name, data, ndata, freeData, fontIndex); } int nvgFindFont(NVGcontext* ctx, const char* name) { if (name == NULL) return -1; - return fonsGetFontByName(ctx->fs, name); + return fonsGetFontByName(ctx->fontContext->fs, name); } int nvgAddFallbackFontId(NVGcontext* ctx, int baseFont, int fallbackFont) { if(baseFont == -1 || fallbackFont == -1) return 0; - return fonsAddFallbackFont(ctx->fs, baseFont, fallbackFont); + return fonsAddFallbackFont(ctx->fontContext->fs, baseFont, fallbackFont); } int nvgAddFallbackFont(NVGcontext* ctx, const char* baseFont, const char* fallbackFont) @@ -2347,7 +2367,7 @@ int nvgAddFallbackFont(NVGcontext* ctx, const char* baseFont, const char* fallba void nvgResetFallbackFontsId(NVGcontext* ctx, int baseFont) { - fonsResetFallbackFont(ctx->fs, baseFont); + fonsResetFallbackFont(ctx->fontContext->fs, baseFont); } void nvgResetFallbackFonts(NVGcontext* ctx, const char* baseFont) @@ -2395,7 +2415,7 @@ void nvgFontFaceId(NVGcontext* ctx, int font) void nvgFontFace(NVGcontext* ctx, const char* font) { NVGstate* state = nvg__getState(ctx); - state->fontId = fonsGetFontByName(ctx->fs, font); + state->fontId = fonsGetFontByName(ctx->fontContext->fs, font); } static float nvg__quantize(float a, float d) @@ -2412,12 +2432,12 @@ static void nvg__flushTextTexture(NVGcontext* ctx) { int dirty[4]; - if (fonsValidateTexture(ctx->fs, dirty)) { - int fontImage = ctx->fontImages[ctx->fontImageIdx]; + if (fonsValidateTexture(ctx->fontContext->fs, dirty)) { + int fontImage = ctx->fontContext->fontImages[ctx->fontContext->fontImageIdx]; // Update texture if (fontImage != 0) { int iw, ih; - const unsigned char* data = fonsGetTextureData(ctx->fs, &iw, &ih); + const unsigned char* data = fonsGetTextureData(ctx->fontContext->fs, &iw, &ih); int x = dirty[0]; int y = dirty[1]; int w = dirty[2] - dirty[0]; @@ -2431,23 +2451,23 @@ static int nvg__allocTextAtlas(NVGcontext* ctx) { int iw, ih; nvg__flushTextTexture(ctx); - if (ctx->fontImageIdx >= NVG_MAX_FONTIMAGES-1) + if (ctx->fontContext->fontImageIdx >= NVG_MAX_FONTIMAGES-1) return 0; // if next fontImage already have a texture - if (ctx->fontImages[ctx->fontImageIdx+1] != 0) - nvgImageSize(ctx, ctx->fontImages[ctx->fontImageIdx+1], &iw, &ih); + if (ctx->fontContext->fontImages[ctx->fontContext->fontImageIdx+1] != 0) + nvgImageSize(ctx, ctx->fontContext->fontImages[ctx->fontContext->fontImageIdx+1], &iw, &ih); else { // calculate the new font image size and create it. - nvgImageSize(ctx, ctx->fontImages[ctx->fontImageIdx], &iw, &ih); + nvgImageSize(ctx, ctx->fontContext->fontImages[ctx->fontContext->fontImageIdx], &iw, &ih); if (iw > ih) ih *= 2; else iw *= 2; if (iw > NVG_MAX_FONTIMAGE_SIZE || ih > NVG_MAX_FONTIMAGE_SIZE) iw = ih = NVG_MAX_FONTIMAGE_SIZE; - ctx->fontImages[ctx->fontImageIdx+1] = ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_ALPHA, iw, ih, 0, NULL); + ctx->fontContext->fontImages[ctx->fontContext->fontImageIdx+1] = ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_ALPHA, iw, ih, 0, NULL); } - ++ctx->fontImageIdx; - fonsResetAtlas(ctx->fs, iw, ih); + ++ctx->fontContext->fontImageIdx; + fonsResetAtlas(ctx->fontContext->fs, iw, ih); return 1; } @@ -2458,7 +2478,7 @@ static void nvg__renderText(NVGcontext* ctx, NVGvertex* verts, int nverts) NVGpaint paint = state->fill; // Render triangles. - paint.image = ctx->fontImages[ctx->fontImageIdx]; + paint.image = ctx->fontContext->fontImages[ctx->fontContext->fontImageIdx]; // Apply global tint for (i = 0; i < 4; i++) { @@ -2495,19 +2515,19 @@ float nvgText(NVGcontext* ctx, float x, float y, const char* string, const char* if (state->fontId == FONS_INVALID) return x; - fonsSetSize(ctx->fs, state->fontSize*scale); - fonsSetSpacing(ctx->fs, state->letterSpacing*scale); - fonsSetBlur(ctx->fs, state->fontBlur*scale); - fonsSetAlign(ctx->fs, state->textAlign); - fonsSetFont(ctx->fs, state->fontId); + fonsSetSize(ctx->fontContext->fs, state->fontSize*scale); + fonsSetSpacing(ctx->fontContext->fs, state->letterSpacing*scale); + fonsSetBlur(ctx->fontContext->fs, state->fontBlur*scale); + fonsSetAlign(ctx->fontContext->fs, state->textAlign); + fonsSetFont(ctx->fontContext->fs, state->fontId); cverts = nvg__maxi(2, (int)(end - string)) * 6; // conservative estimate. verts = nvg__allocTempVerts(ctx, cverts); if (verts == NULL) return x; - fonsTextIterInit(ctx->fs, &iter, x*scale, y*scale, string, end, FONS_GLYPH_BITMAP_REQUIRED); + fonsTextIterInit(ctx->fontContext->fs, &iter, x*scale, y*scale, string, end, FONS_GLYPH_BITMAP_REQUIRED); prevIter = iter; - while (fonsTextIterNext(ctx->fs, &iter, &q)) { + while (fonsTextIterNext(ctx->fontContext->fs, &iter, &q)) { float c[4*2]; if (iter.prevGlyphIndex == -1) { // can not retrieve glyph? if (nverts != 0) { @@ -2517,7 +2537,7 @@ float nvgText(NVGcontext* ctx, float x, float y, const char* string, const char* if (!nvg__allocTextAtlas(ctx)) break; // no memory :( iter = prevIter; - fonsTextIterNext(ctx->fs, &iter, &q); // try again + fonsTextIterNext(ctx->fontContext->fs, &iter, &q); // try again if (iter.prevGlyphIndex == -1) // still can not find glyph? break; } @@ -2602,18 +2622,18 @@ int nvgTextGlyphPositions(NVGcontext* ctx, float x, float y, const char* string, if (string == end) return 0; - fonsSetSize(ctx->fs, state->fontSize*scale); - fonsSetSpacing(ctx->fs, state->letterSpacing*scale); - fonsSetBlur(ctx->fs, state->fontBlur*scale); - fonsSetAlign(ctx->fs, state->textAlign); - fonsSetFont(ctx->fs, state->fontId); + fonsSetSize(ctx->fontContext->fs, state->fontSize*scale); + fonsSetSpacing(ctx->fontContext->fs, state->letterSpacing*scale); + fonsSetBlur(ctx->fontContext->fs, state->fontBlur*scale); + fonsSetAlign(ctx->fontContext->fs, state->textAlign); + fonsSetFont(ctx->fontContext->fs, state->fontId); - fonsTextIterInit(ctx->fs, &iter, x*scale, y*scale, string, end, FONS_GLYPH_BITMAP_OPTIONAL); + fonsTextIterInit(ctx->fontContext->fs, &iter, x*scale, y*scale, string, end, FONS_GLYPH_BITMAP_OPTIONAL); prevIter = iter; - while (fonsTextIterNext(ctx->fs, &iter, &q)) { + while (fonsTextIterNext(ctx->fontContext->fs, &iter, &q)) { if (iter.prevGlyphIndex < 0 && nvg__allocTextAtlas(ctx)) { // can not retrieve glyph? iter = prevIter; - fonsTextIterNext(ctx->fs, &iter, &q); // try again + fonsTextIterNext(ctx->fontContext->fs, &iter, &q); // try again } prevIter = iter; positions[npos].str = iter.str; @@ -2666,20 +2686,20 @@ int nvgTextBreakLines(NVGcontext* ctx, const char* string, const char* end, floa if (string == end) return 0; - fonsSetSize(ctx->fs, state->fontSize*scale); - fonsSetSpacing(ctx->fs, state->letterSpacing*scale); - fonsSetBlur(ctx->fs, state->fontBlur*scale); - fonsSetAlign(ctx->fs, state->textAlign); - fonsSetFont(ctx->fs, state->fontId); + fonsSetSize(ctx->fontContext->fs, state->fontSize*scale); + fonsSetSpacing(ctx->fontContext->fs, state->letterSpacing*scale); + fonsSetBlur(ctx->fontContext->fs, state->fontBlur*scale); + fonsSetAlign(ctx->fontContext->fs, state->textAlign); + fonsSetFont(ctx->fontContext->fs, state->fontId); breakRowWidth *= scale; - fonsTextIterInit(ctx->fs, &iter, 0, 0, string, end, FONS_GLYPH_BITMAP_OPTIONAL); + fonsTextIterInit(ctx->fontContext->fs, &iter, 0, 0, string, end, FONS_GLYPH_BITMAP_OPTIONAL); prevIter = iter; - while (fonsTextIterNext(ctx->fs, &iter, &q)) { + while (fonsTextIterNext(ctx->fontContext->fs, &iter, &q)) { if (iter.prevGlyphIndex < 0 && nvg__allocTextAtlas(ctx)) { // can not retrieve glyph? iter = prevIter; - fonsTextIterNext(ctx->fs, &iter, &q); // try again + fonsTextIterNext(ctx->fontContext->fs, &iter, &q); // try again } prevIter = iter; switch (iter.codepoint) { @@ -2850,16 +2870,16 @@ float nvgTextBounds(NVGcontext* ctx, float x, float y, const char* string, const if (state->fontId == FONS_INVALID) return 0; - fonsSetSize(ctx->fs, state->fontSize*scale); - fonsSetSpacing(ctx->fs, state->letterSpacing*scale); - fonsSetBlur(ctx->fs, state->fontBlur*scale); - fonsSetAlign(ctx->fs, state->textAlign); - fonsSetFont(ctx->fs, state->fontId); + fonsSetSize(ctx->fontContext->fs, state->fontSize*scale); + fonsSetSpacing(ctx->fontContext->fs, state->letterSpacing*scale); + fonsSetBlur(ctx->fontContext->fs, state->fontBlur*scale); + fonsSetAlign(ctx->fontContext->fs, state->textAlign); + fonsSetFont(ctx->fontContext->fs, state->fontId); - width = fonsTextBounds(ctx->fs, x*scale, y*scale, string, end, bounds); + width = fonsTextBounds(ctx->fontContext->fs, x*scale, y*scale, string, end, bounds); if (bounds != NULL) { // Use line bounds for height. - fonsLineBounds(ctx->fs, y*scale, &bounds[1], &bounds[3]); + fonsLineBounds(ctx->fontContext->fs, y*scale, &bounds[1], &bounds[3]); bounds[0] *= invscale; bounds[1] *= invscale; bounds[2] *= invscale; @@ -2894,12 +2914,12 @@ void nvgTextBoxBounds(NVGcontext* ctx, float x, float y, float breakRowWidth, co minx = maxx = x; miny = maxy = y; - fonsSetSize(ctx->fs, state->fontSize*scale); - fonsSetSpacing(ctx->fs, state->letterSpacing*scale); - fonsSetBlur(ctx->fs, state->fontBlur*scale); - fonsSetAlign(ctx->fs, state->textAlign); - fonsSetFont(ctx->fs, state->fontId); - fonsLineBounds(ctx->fs, 0, &rminy, &rmaxy); + fonsSetSize(ctx->fontContext->fs, state->fontSize*scale); + fonsSetSpacing(ctx->fontContext->fs, state->letterSpacing*scale); + fonsSetBlur(ctx->fontContext->fs, state->fontBlur*scale); + fonsSetAlign(ctx->fontContext->fs, state->textAlign); + fonsSetFont(ctx->fontContext->fs, state->fontId); + fonsLineBounds(ctx->fontContext->fs, 0, &rminy, &rmaxy); rminy *= invscale; rmaxy *= invscale; @@ -2945,13 +2965,13 @@ void nvgTextMetrics(NVGcontext* ctx, float* ascender, float* descender, float* l if (state->fontId == FONS_INVALID) return; - fonsSetSize(ctx->fs, state->fontSize*scale); - fonsSetSpacing(ctx->fs, state->letterSpacing*scale); - fonsSetBlur(ctx->fs, state->fontBlur*scale); - fonsSetAlign(ctx->fs, state->textAlign); - fonsSetFont(ctx->fs, state->fontId); + fonsSetSize(ctx->fontContext->fs, state->fontSize*scale); + fonsSetSpacing(ctx->fontContext->fs, state->letterSpacing*scale); + fonsSetBlur(ctx->fontContext->fs, state->fontBlur*scale); + fonsSetAlign(ctx->fontContext->fs, state->textAlign); + fonsSetFont(ctx->fontContext->fs, state->fontId); - fonsVertMetrics(ctx->fs, ascender, descender, lineh); + fonsVertMetrics(ctx->fontContext->fs, ascender, descender, lineh); if (ascender != NULL) *ascender *= invscale; if (descender != NULL) diff --git a/src/nanovg.h b/src/nanovg.h index b1c4e30..8e50926 100644 --- a/src/nanovg.h +++ b/src/nanovg.h @@ -662,7 +662,7 @@ typedef struct NVGpath NVGpath; struct NVGparams { void* userPtr; int edgeAntiAlias; - int (*renderCreate)(void* uptr); + int (*renderCreate)(void* uptr, void* otherUptr); int (*renderCreateTexture)(void* uptr, int type, int w, int h, int imageFlags, const unsigned char* data); int (*renderDeleteTexture)(void* uptr, int image); int (*renderUpdateTexture)(void* uptr, int image, int x, int y, int w, int h, const unsigned char* data); @@ -678,7 +678,7 @@ struct NVGparams { typedef struct NVGparams NVGparams; // Constructor and destructor, called by the render back-end. -NVGcontext* nvgCreateInternal(NVGparams* params); +NVGcontext* nvgCreateInternal(NVGparams* params, NVGcontext* other); void nvgDeleteInternal(NVGcontext* ctx); NVGparams* nvgInternalParams(NVGcontext* ctx); diff --git a/src/nanovg_gl.h b/src/nanovg_gl.h index 798b236..5aef5eb 100644 --- a/src/nanovg_gl.h +++ b/src/nanovg_gl.h @@ -57,6 +57,7 @@ enum NVGcreateFlags { #if defined NANOVG_GL2 NVGcontext* nvgCreateGL2(int flags); +NVGcontext* nvgCreateSharedGL2(NVGcontext* other, int flags); void nvgDeleteGL2(NVGcontext* ctx); int nvglCreateImageFromHandleGL2(NVGcontext* ctx, GLuint textureId, int w, int h, int flags); @@ -67,6 +68,7 @@ GLuint nvglImageHandleGL2(NVGcontext* ctx, int image); #if defined NANOVG_GL3 NVGcontext* nvgCreateGL3(int flags); +NVGcontext* nvgCreateSharedGL3(NVGcontext* other, int flags); void nvgDeleteGL3(NVGcontext* ctx); int nvglCreateImageFromHandleGL3(NVGcontext* ctx, GLuint textureId, int w, int h, int flags); @@ -77,6 +79,7 @@ GLuint nvglImageHandleGL3(NVGcontext* ctx, int image); #if defined NANOVG_GLES2 NVGcontext* nvgCreateGLES2(int flags); +NVGcontext* nvgCreateSharedGLES2(NVGcontext* other, int flags); void nvgDeleteGLES2(NVGcontext* ctx); int nvglCreateImageFromHandleGLES2(NVGcontext* ctx, GLuint textureId, int w, int h, int flags); @@ -87,6 +90,7 @@ GLuint nvglImageHandleGLES2(NVGcontext* ctx, int image); #if defined NANOVG_GLES3 NVGcontext* nvgCreateGLES3(int flags); +NVGcontext* nvgCreateSharedGLES3(NVGcontext* other, int flags); void nvgDeleteGLES3(NVGcontext* ctx); int nvglCreateImageFromHandleGLES3(NVGcontext* ctx, GLuint textureId, int w, int h, int flags); @@ -228,13 +232,19 @@ struct GLNVGfragUniforms { }; typedef struct GLNVGfragUniforms GLNVGfragUniforms; -struct GLNVGcontext { - GLNVGshader shader; +struct GLNVGtextureContext { // Textures; shared between shared NanoVG contexts. + int refCount; GLNVGtexture* textures; - float view[2]; int ntextures; int ctextures; int textureId; +}; +typedef struct GLNVGtextureContext GLNVGtextureContext; + +struct GLNVGcontext { + GLNVGshader shader; + GLNVGtextureContext* textureContext; + float view[2]; GLuint vertBuf; #if defined NANOVG_GL3 GLuint vertArr; @@ -350,26 +360,26 @@ static GLNVGtexture* glnvg__allocTexture(GLNVGcontext* gl) GLNVGtexture* tex = NULL; int i; - for (i = 0; i < gl->ntextures; i++) { - if (gl->textures[i].id == 0) { - tex = &gl->textures[i]; + for (i = 0; i < gl->textureContext->ntextures; i++) { + if (gl->textureContext->textures[i].id == 0) { + tex = &gl->textureContext->textures[i]; break; } } if (tex == NULL) { - if (gl->ntextures+1 > gl->ctextures) { + if (gl->textureContext->ntextures+1 > gl->textureContext->ctextures) { GLNVGtexture* textures; - int ctextures = glnvg__maxi(gl->ntextures+1, 4) + gl->ctextures/2; // 1.5x Overallocate - textures = (GLNVGtexture*)realloc(gl->textures, sizeof(GLNVGtexture)*ctextures); + int ctextures = glnvg__maxi(gl->textureContext->ntextures+1, 4) + gl->textureContext->ctextures/2; // 1.5x Overallocate + textures = (GLNVGtexture*)realloc(gl->textureContext->textures, sizeof(GLNVGtexture)*ctextures); if (textures == NULL) return NULL; - gl->textures = textures; - gl->ctextures = ctextures; + gl->textureContext->textures = textures; + gl->textureContext->ctextures = ctextures; } - tex = &gl->textures[gl->ntextures++]; + tex = &gl->textureContext->textures[gl->textureContext->ntextures++]; } memset(tex, 0, sizeof(*tex)); - tex->id = ++gl->textureId; + tex->id = ++gl->textureContext->textureId; return tex; } @@ -377,20 +387,20 @@ static GLNVGtexture* glnvg__allocTexture(GLNVGcontext* gl) static GLNVGtexture* glnvg__findTexture(GLNVGcontext* gl, int id) { int i; - for (i = 0; i < gl->ntextures; i++) - if (gl->textures[i].id == id) - return &gl->textures[i]; + for (i = 0; i < gl->textureContext->ntextures; i++) + if (gl->textureContext->textures[i].id == id) + return &gl->textureContext->textures[i]; return NULL; } static int glnvg__deleteTexture(GLNVGcontext* gl, int id) { int i; - for (i = 0; i < gl->ntextures; i++) { - if (gl->textures[i].id == id) { - if (gl->textures[i].tex != 0 && (gl->textures[i].flags & NVG_IMAGE_NODELETE) == 0) - glDeleteTextures(1, &gl->textures[i].tex); - memset(&gl->textures[i], 0, sizeof(gl->textures[i])); + for (i = 0; i < gl->textureContext->ntextures; i++) { + if (gl->textureContext->textures[i].id == id) { + if (gl->textureContext->textures[i].tex != 0 && (gl->textureContext->textures[i].flags & NVG_IMAGE_NODELETE) == 0) + glDeleteTextures(1, &gl->textureContext->textures[i].tex); + memset(&gl->textureContext->textures[i], 0, sizeof(gl->textureContext->textures[i])); return 1; } } @@ -504,9 +514,20 @@ static void glnvg__getUniforms(GLNVGshader* shader) static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int imageFlags, const unsigned char* data); -static int glnvg__renderCreate(void* uptr) +static int glnvg__renderCreate(void* uptr, void* otherUptr) // Share the textures of GLNVGcontext 'otherUptr' if it's non-NULL. { GLNVGcontext* gl = (GLNVGcontext*)uptr; + + if (otherUptr) { + GLNVGcontext* other = (GLNVGcontext*)otherUptr; + gl->textureContext = other->textureContext; + gl->textureContext->refCount++; + } else { + gl->textureContext = (GLNVGtextureContext*)malloc(sizeof(GLNVGtextureContext)); + memset(gl->textureContext, 0, sizeof(GLNVGtextureContext)); + gl->textureContext->refCount = 1; + } + int align = 4; // TODO: mediump float may not be enough for GLES2 in iOS. @@ -1545,11 +1566,14 @@ static void glnvg__renderDelete(void* uptr) if (gl->vertBuf != 0) glDeleteBuffers(1, &gl->vertBuf); - for (i = 0; i < gl->ntextures; i++) { - if (gl->textures[i].tex != 0 && (gl->textures[i].flags & NVG_IMAGE_NODELETE) == 0) - glDeleteTextures(1, &gl->textures[i].tex); + if (gl->textureContext != NULL && --gl->textureContext->refCount == 0) { + for (i = 0; i < gl->textureContext->ntextures; i++) { + if (gl->textureContext->textures[i].tex != 0 && (gl->textureContext->textures[i].flags & NVG_IMAGE_NODELETE) == 0) + glDeleteTextures(1, &gl->textureContext->textures[i].tex); + } + free(gl->textureContext->textures); + free(gl->textureContext); } - free(gl->textures); free(gl->paths); free(gl->verts); @@ -1569,6 +1593,28 @@ NVGcontext* nvgCreateGLES2(int flags) #elif defined NANOVG_GLES3 NVGcontext* nvgCreateGLES3(int flags) #endif +{ +#if defined NANOVG_GL2 + return nvgCreateSharedGL2(NULL, flags); +#elif defined NANOVG_GL3 + return nvgCreateSharedGL3(NULL, flags); +#elif defined NANOVG_GLES2 + return nvgCreateSharedGLES2(NULL, flags); +#elif defined NANOVG_GLES3 + return nvgCreateSharedGLES3(NULL, flags); +#endif +} + +// Share the fonts and textures of 'other' if it's non-NULL. +#if defined NANOVG_GL2 +NVGcontext* nvgCreateSharedGL2(NVGcontext* other, int flags) +#elif defined NANOVG_GL3 +NVGcontext* nvgCreateSharedGL3(NVGcontext* other, int flags) +#elif defined NANOVG_GLES2 +NVGcontext* nvgCreateSharedGLES2(NVGcontext* other, int flags) +#elif defined NANOVG_GLES3 +NVGcontext* nvgCreateSharedGLES3(NVGcontext* other, int flags) +#endif { NVGparams params; NVGcontext* ctx = NULL; @@ -1594,7 +1640,7 @@ NVGcontext* nvgCreateGLES3(int flags) gl->flags = flags; - ctx = nvgCreateInternal(¶ms); + ctx = nvgCreateInternal(¶ms, other); if (ctx == NULL) goto error; return ctx;