From 85fb384a3d21be15887a82e1ed2300536de54c99 Mon Sep 17 00:00:00 2001 From: Mikko Mononen Date: Mon, 17 Feb 2014 18:20:00 +0200 Subject: [PATCH] UBO fixes - correct fix for ubo memroy allocation (use returned alignment instead of struct size) - separated convex fill to own command type - moved uboPos to call struct --- src/nanovg_gl3buf.h | 153 ++++++++++++++++++++++++-------------------- 1 file changed, 83 insertions(+), 70 deletions(-) diff --git a/src/nanovg_gl3buf.h b/src/nanovg_gl3buf.h index cc53a7f..815b57d 100644 --- a/src/nanovg_gl3buf.h +++ b/src/nanovg_gl3buf.h @@ -93,6 +93,7 @@ struct GLNVGtexture { enum GLNVGcallType { GLNVG_FILL, + GLNVG_CONVEXFILL, GLNVG_STROKE, GLNVG_TRIANGLES, }; @@ -106,6 +107,7 @@ struct GLNVGcall { float strokeWidth; int triangleOffset; int triangleCount; + int uboOffset; }; struct GLNVGpath { @@ -113,7 +115,6 @@ struct GLNVGpath { int fillCount; int strokeOffset; int strokeCount; - int convex; }; struct GLNVGuboFrag { @@ -656,10 +657,9 @@ static int glnvg__setupPaintUBO(struct GLNVGcontext* gl, struct NVGpaint* paint, return 1; } -static int glnvg__setupPaint(struct GLNVGcontext* gl, struct NVGpaint* paint, int* uboPos) +static int glnvg__setupPaint(struct GLNVGcontext* gl, struct NVGpaint* paint, int uboOffset) { - glBindBufferRange(GL_UNIFORM_BUFFER, GLNVG_UBO_FRAG_BINDING, gl->uboFragBuf, *uboPos, sizeof(struct GLNVGuboFrag)); - *uboPos += gl->uboPosAlignment; + glBindBufferRange(GL_UNIFORM_BUFFER, GLNVG_UBO_FRAG_BINDING, gl->uboFragBuf, uboOffset, sizeof(struct GLNVGuboFrag)); if (paint->image != 0) { struct GLNVGtexture* tex = glnvg__findTexture(gl, paint->image); if (tex == NULL) return 0; @@ -676,81 +676,87 @@ static void glnvg__renderViewport(void* uptr, int width, int height) gl->view[1] = (float)height; } -static void glnvg__fill(struct GLNVGcontext* gl, struct GLNVGcall* call, int* uboPos ) +static void glnvg__fill(struct GLNVGcontext* gl, struct GLNVGcall* call) { struct GLNVGpath* paths = &gl->paths[call->pathOffset]; int npaths = call->pathCount, i; - if (npaths == 1 && paths[0].convex) { - glnvg__setupPaint(gl, &call->paint, uboPos); - for (i = 0; i < npaths; i++) - glDrawArrays(GL_TRIANGLE_FAN, paths[i].fillOffset, paths[i].fillCount); - if (gl->edgeAntiAlias) { - // Draw fringes - for (i = 0; i < npaths; i++) - glDrawArrays(GL_TRIANGLE_STRIP, paths[i].strokeOffset, paths[i].strokeCount); - } - } else { + // Draw shapes + glDisable(GL_BLEND); + glEnable(GL_STENCIL_TEST); + glStencilMask(0xff); + glStencilFunc(GL_ALWAYS, 0, ~0L); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + + // set bindpoint for solid loc + glBindBufferRange(GL_UNIFORM_BUFFER, GLNVG_UBO_FRAG_BINDING, gl->uboFragBuf, call->uboOffset, sizeof(struct GLNVGuboFrag)); + glnvg__checkError("fill solid loc"); + + glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP); + glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP); + glDisable(GL_CULL_FACE); + for (i = 0; i < npaths; i++) + glDrawArrays(GL_TRIANGLE_FAN, paths[i].fillOffset, paths[i].fillCount); + glEnable(GL_CULL_FACE); + + // Draw aliased off-pixels + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glEnable(GL_BLEND); - // Draw shapes - glDisable(GL_BLEND); - glEnable(GL_STENCIL_TEST); - glStencilMask(0xff); - glStencilFunc(GL_ALWAYS, 0, ~0L); - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - - // set bindpoint for solid loc - glBindBufferRange(GL_UNIFORM_BUFFER, GLNVG_UBO_FRAG_BINDING, gl->uboFragBuf, *uboPos, sizeof(struct GLNVGuboFrag)); - *uboPos += gl->uboPosAlignment; - glnvg__checkError("fill solid loc"); - - glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP); - glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP); - glDisable(GL_CULL_FACE); + glnvg__setupPaint(gl, &call->paint, call->uboOffset + gl->uboPosAlignment); + + if (gl->edgeAntiAlias) { + glStencilFunc(GL_EQUAL, 0x00, 0xff); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + // Draw fringes for (i = 0; i < npaths; i++) - glDrawArrays(GL_TRIANGLE_FAN, paths[i].fillOffset, paths[i].fillCount); - glEnable(GL_CULL_FACE); + glDrawArrays(GL_TRIANGLE_STRIP, paths[i].strokeOffset, paths[i].strokeCount); + } - // Draw aliased off-pixels - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glEnable(GL_BLEND); + // Draw fill + glStencilFunc(GL_NOTEQUAL, 0x0, 0xff); + glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); + glDrawArrays(GL_TRIANGLES, call->triangleOffset, call->triangleCount); - glnvg__setupPaint(gl, &call->paint, uboPos); + glDisable(GL_STENCIL_TEST); +} - if (gl->edgeAntiAlias) { - glStencilFunc(GL_EQUAL, 0x00, 0xff); - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - // Draw fringes - for (i = 0; i < npaths; i++) - glDrawArrays(GL_TRIANGLE_STRIP, paths[i].strokeOffset, paths[i].strokeCount); - } +static void glnvg__convexFill(struct GLNVGcontext* gl, struct GLNVGcall* call) +{ + struct GLNVGpath* paths = &gl->paths[call->pathOffset]; + int npaths = call->pathCount, i; - // Draw fill - glStencilFunc(GL_NOTEQUAL, 0x0, 0xff); - glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); - glDrawArrays(GL_TRIANGLES, call->triangleOffset, call->triangleCount); + glnvg__setupPaint(gl, &call->paint, call->uboOffset); - glDisable(GL_STENCIL_TEST); + for (i = 0; i < npaths; i++) + glDrawArrays(GL_TRIANGLE_FAN, paths[i].fillOffset, paths[i].fillCount); + if (gl->edgeAntiAlias) { + // Draw fringes + for (i = 0; i < npaths; i++) + glDrawArrays(GL_TRIANGLE_STRIP, paths[i].strokeOffset, paths[i].strokeCount); } } -static void glnvg__stroke(struct GLNVGcontext* gl, struct GLNVGcall* call, int* uboPos) +static void glnvg__stroke(struct GLNVGcontext* gl, struct GLNVGcall* call) { struct GLNVGpath* paths = &gl->paths[call->pathOffset]; int npaths = call->pathCount, i; - glnvg__setupPaint(gl, &call->paint, uboPos); + + glnvg__setupPaint(gl, &call->paint, call->uboOffset); + // Draw Strokes for (i = 0; i < npaths; i++) glDrawArrays(GL_TRIANGLE_STRIP, paths[i].strokeOffset, paths[i].strokeCount); } -static void glnvg__triangles(struct GLNVGcontext* gl, struct GLNVGcall* call, int* uboPos) +static void glnvg__triangles(struct GLNVGcontext* gl, struct GLNVGcall* call) { struct GLNVGtexture* tex = glnvg__findTexture(gl, call->paint.image); if (tex != NULL) glBindTexture(GL_TEXTURE_2D, tex->tex); - glBindBufferRange(GL_UNIFORM_BUFFER, GLNVG_UBO_FRAG_BINDING, gl->uboFragBuf, *uboPos, sizeof(struct GLNVGuboFrag)); - *uboPos += gl->uboPosAlignment; + + glBindBufferRange(GL_UNIFORM_BUFFER, GLNVG_UBO_FRAG_BINDING, gl->uboFragBuf, call->uboOffset, sizeof(struct GLNVGuboFrag)); + glnvg__checkError("tris solid img loc"); glDrawArrays(GL_TRIANGLES, call->triangleOffset, call->triangleCount); } @@ -758,7 +764,8 @@ static void glnvg__triangles(struct GLNVGcontext* gl, struct GLNVGcall* call, in static void glnvg__renderFlush(void* uptr) { struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr; - int i, uboPos; + int i, offset; + char* buff; if (gl->ncalls > 0) { @@ -767,28 +774,31 @@ static void glnvg__renderFlush(void* uptr) // upload ubo for frag shaders - maximum ubos is 2x num calls glBindBuffer(GL_UNIFORM_BUFFER, gl->uboFragBuf); - glBufferData(GL_UNIFORM_BUFFER, 3 * gl->ncalls * sizeof(struct GLNVGuboFrag), 0, GL_STREAM_DRAW); - char* buff = (char*)glMapBuffer( GL_UNIFORM_BUFFER, GL_WRITE_ONLY ); + glBufferData(GL_UNIFORM_BUFFER, 2 * gl->ncalls * gl->uboPosAlignment, 0, GL_STREAM_DRAW); + buff = (char*)glMapBuffer(GL_UNIFORM_BUFFER, GL_WRITE_ONLY); + offset = 0; for (i = 0; i < gl->ncalls; i++) { struct GLNVGcall* call = &gl->calls[i]; - struct GLNVGuboFrag* ubo = (struct GLNVGuboFrag*)buff; + struct GLNVGuboFrag* ubo = (struct GLNVGuboFrag*)&buff[offset]; + call->uboOffset = offset; if (call->type == GLNVG_FILL) { - if (!(call->pathCount == 1 && gl->paths[call->pathOffset].convex)) { - ubo->type = NSVG_SHADER_SIMPLE; - buff += gl->uboPosAlignment; - ubo = (struct GLNVGuboFrag*)buff; - } + ubo->type = NSVG_SHADER_SIMPLE; + offset += gl->uboPosAlignment; + ubo = (struct GLNVGuboFrag*)&buff[offset]; + glnvg__setupPaintUBO(gl, &call->paint, &call->scissor, 1.0001f, ubo); + offset += gl->uboPosAlignment; + } else if (call->type == GLNVG_CONVEXFILL) { glnvg__setupPaintUBO(gl, &call->paint, &call->scissor, 1.0001f, ubo); - buff += gl->uboPosAlignment; + offset += gl->uboPosAlignment; } else if (call->type == GLNVG_STROKE) { glnvg__setupPaintUBO(gl, &call->paint, &call->scissor, call->strokeWidth, ubo); - buff += gl->uboPosAlignment; + offset += gl->uboPosAlignment; } else if (call->type == GLNVG_TRIANGLES) { struct GLNVGtexture* tex = glnvg__findTexture(gl, call->paint.image); glnvg__toFloatColor(ubo->innerCol, call->paint.innerColor); ubo->texType = tex->type == NVG_TEXTURE_RGBA ? 0 : 1; ubo->type = NSVG_SHADER_IMG; - buff += gl->uboPosAlignment; + offset += gl->uboPosAlignment; } } glUnmapBuffer(GL_UNIFORM_BUFFER); @@ -809,16 +819,17 @@ static void glnvg__renderFlush(void* uptr) glBindBufferBase(GL_UNIFORM_BUFFER, GLNVG_UBO_VIEW_BINDING, gl->uboViewBuf); glBindBuffer(GL_UNIFORM_BUFFER, gl->uboFragBuf); - uboPos = 0; for (i = 0; i < gl->ncalls; i++) { struct GLNVGcall* call = &gl->calls[i]; if (call->type == GLNVG_FILL) - glnvg__fill(gl, call, &uboPos); + glnvg__fill(gl, call); + else if (call->type == GLNVG_CONVEXFILL) + glnvg__convexFill(gl, call); else if (call->type == GLNVG_STROKE) - glnvg__stroke(gl, call, &uboPos); + glnvg__stroke(gl, call); else if (call->type == GLNVG_TRIANGLES) - glnvg__triangles(gl, call, &uboPos); + glnvg__triangles(gl, call); } glDisableVertexAttribArray(0); @@ -902,6 +913,9 @@ static void glnvg__renderFill(void* uptr, struct NVGpaint* paint, struct NVGscis call->paint = *paint; call->scissor = *scissor; + if (npaths == 1 && paths[0].convex) + call->type = GLNVG_CONVEXFILL; + // Allocate vertices for all the paths. maxverts = glnvg__maxVertCount(paths, npaths); vertsoff = glnvg__allocVerts(gl, maxverts + 6); @@ -910,7 +924,6 @@ static void glnvg__renderFill(void* uptr, struct NVGpaint* paint, struct NVGscis struct GLNVGpath* copy = &gl->paths[call->pathOffset + i]; const struct NVGpath* path = &paths[i]; memset(copy, 0, sizeof(struct GLNVGpath)); - copy->convex = path->convex; if (path->nfill) { copy->fillOffset = vertsoff; copy->fillCount = path->nfill;