Browse Source

gl3buf refactoring

- implemented missing scissor from draw triangles
- buffer a whole frame of uniforms
- moved paint to uniform conversion earlier
- simplified render loops and data structures
- renamed bunch of things
- combined shaders, use define to disable AA
shared-context
Mikko Mononen 11 years ago
parent
commit
b043187a51
1 changed files with 168 additions and 205 deletions
  1. +168
    -205
      src/nanovg_gl3buf.h

+ 168
- 205
src/nanovg_gl3buf.h View File

@@ -60,8 +60,8 @@ void nvgDeleteGL3(struct NVGcontext* ctx);
#include "nanovg.h"

enum GLNVGuniformLoc {
GLNVG_LOC_UBOVIEW,
GLNVG_LOC_UBOFRAG,
GLNVG_LOC_VIEW,
GLNVG_LOC_FRAG,
GLNVG_MAX_LOCS
};

@@ -73,8 +73,8 @@ enum GLNVGshaderType {
};

enum GLNVGuniformBindings {
GLNVG_UBO_VIEW_BINDING = 0,
GLNVG_UBO_FRAG_BINDING = 1,
GLNVG_VIEW_BINDING = 0,
GLNVG_FRAG_BINDING = 1,
};

struct GLNVGshader {
@@ -100,14 +100,12 @@ enum GLNVGcallType {

struct GLNVGcall {
int type;
int image;
int pathOffset;
int pathCount;
struct NVGpaint paint;
struct NVGscissor scissor;
float strokeWidth;
int triangleOffset;
int triangleCount;
int uboOffset;
int uniformOffset;
};

struct GLNVGpath {
@@ -117,7 +115,7 @@ struct GLNVGpath {
int strokeCount;
};

struct GLNVGuboFrag {
struct GLNVGfragUniforms {
float scissorMat[12]; // matrices are actually 3 vec4s
float paintMat[12];
float innerCol[4];
@@ -141,11 +139,12 @@ struct GLNVGcontext {
int textureId;
GLuint vertArr;
GLuint vertBuf;
GLuint uboViewBuf;
GLuint uboFragBuf;
int uboPosAlignment;
GLuint viewBuf;
GLuint fragBuf;
int fragSize;
int edgeAntiAlias;

// Per frame buffers
struct GLNVGcall* calls;
int ccalls;
int ncalls;
@@ -155,6 +154,9 @@ struct GLNVGcontext {
struct NVGvertex* verts;
int cverts;
int nverts;
unsigned char* uniforms;
int cuniforms;
int nuniforms;
};


@@ -237,18 +239,23 @@ static int glnvg__checkError(const char* str)
return 0;
}

static int glnvg__createShader(struct GLNVGshader* shader, const char* name, const char* vshader, const char* fshader)
static int glnvg__createShader(struct GLNVGshader* shader, const char* name, const char* header, const char* opts, const char* vshader, const char* fshader)
{
GLint status;
GLuint prog, vert, frag;
const char* str[3];
str[0] = header;
str[1] = opts != NULL ? opts : "";

memset(shader, 0, sizeof(*shader));

prog = glCreateProgram();
vert = glCreateShader(GL_VERTEX_SHADER);
frag = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vert, 1, &vshader, 0);
glShaderSource(frag, 1, &fshader, 0);
str[2] = vshader;
glShaderSource(vert, 3, str, 0);
str[2] = fshader;
glShaderSource(frag, 3, str, 0);

glCompileShader(vert);
glGetShaderiv(vert, GL_COMPILE_STATUS, &status);
@@ -296,22 +303,25 @@ static void glnvg__deleteShader(struct GLNVGshader* shader)

static void glnvg__getUniforms(struct GLNVGshader* shader)
{
shader->loc[GLNVG_LOC_UBOVIEW] = glGetUniformBlockIndex(shader->prog, "uboView");
shader->loc[GLNVG_LOC_UBOFRAG] = glGetUniformBlockIndex(shader->prog, "uboFrag");
shader->loc[GLNVG_LOC_VIEW] = glGetUniformBlockIndex(shader->prog, "view");
shader->loc[GLNVG_LOC_FRAG] = glGetUniformBlockIndex(shader->prog, "frag");
}

static int glnvg__renderCreate(void* uptr)
{
struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
int align = 1;

static const char* fillVertShader =
static const char* shaderHeader =
#ifdef NANOVG_GLES3
"#version 300 es\n"
"precision mediump float;\n"
"precision mediump float;\n";
#else
"#version 150 core\n"
"#version 150 core\n";
#endif
"layout(std140) uniform uboView {\n"

static const char* fillVertShader =
"layout(std140) uniform view {\n"
" vec2 viewSize;\n"
"};\n"
"in vec2 vertex;\n"
@@ -325,13 +335,7 @@ static int glnvg__renderCreate(void* uptr)
"}\n";

static const char* fillFragShaderEdgeAA =
#ifdef NANOVG_GLES3
"#version 300 es\n"
"precision mediump float;\n"
#else
"#version 150 core\n"
#endif
"layout(std140) uniform uboFrag {\n"
"layout(std140) uniform frag {\n"
" mat3 scissorMat;\n"
" mat3 paintMat;\n"
" vec4 innerCol;\n"
@@ -362,16 +366,21 @@ static int glnvg__renderCreate(void* uptr)
" sc = vec2(0.5,0.5) - sc * scissorScale;\n"
" return clamp(sc.x,0.0,1.0) * clamp(sc.y,0.0,1.0);\n"
"}\n"
"\n"
"#ifdef EDGE_AA\n"
"// Stroke - from [0..1] to clipped pyramid, where the slope is 1px.\n"
"float strokeMask() {\n"
" return min(1.0, (1.0-abs(ftcoord.x*2.0-1.0))*strokeMult) * ftcoord.y;\n"
"}\n"
"#endif\n"
"\n"
"void main(void) {\n"
" if (type == 0) { // Gradient\n"
" float scissor = scissorMask(fpos);\n"
"#ifdef EDGE_AA\n"
" float strokeAlpha = strokeMask();\n"
"#else\n"
" float strokeAlpha = 1.0f;\n"
"#endif\n"
" // Calculate gradient color using box gradient\n"
" vec2 pt = (paintMat * vec3(fpos,1.0)).xy;\n"
" float d = clamp((sdroundrect(pt, extent, radius) + feather*0.5) / feather, 0.0, 1.0);\n"
@@ -381,7 +390,11 @@ static int glnvg__renderCreate(void* uptr)
" outColor = color;\n"
" } else if (type == 1) { // Image\n"
" float scissor = scissorMask(fpos);\n"
"#ifdef EDGE_AA\n"
" float strokeAlpha = strokeMask();\n"
"#else\n"
" float strokeAlpha = 1.0f;\n"
"#endif\n"
" // Calculate color fron texture\n"
" vec2 pt = (paintMat * vec3(fpos,1.0)).xy / extent;\n"
" vec4 color = texture(tex, pt);\n"
@@ -392,75 +405,10 @@ static int glnvg__renderCreate(void* uptr)
" } else if (type == 2) { // Stencil fill\n"
" outColor = vec4(1,1,1,1);\n"
" } else if (type == 3) { // Textured tris\n"
" vec4 color = texture(tex, ftcoord);\n"
" color = texType == 0 ? color : vec4(1,1,1,color.x);\n"
" outColor = color * innerCol;\n"
" }\n"
"}\n";

static const char* fillFragShader =
#ifdef NANOVG_GLES3
"#version 300 es\n"
"precision mediump float;\n"
#else
"#version 150 core\n"
#endif
"layout(std140) uniform uboFrag {\n"
" mat3 scissorMat;\n"
" mat3 paintMat;\n"
" vec4 innerCol;\n"
" vec4 outerCol;\n"
" vec2 scissorExt;\n"
" vec2 scissorScale;\n"
" vec2 extent;\n"
" float radius;\n"
" float feather;\n"
" float strokeMult;\n"
" int texType;\n"
" int type;\n"
"};\n"
"uniform sampler2D tex;\n"
"in vec2 ftcoord;\n"
"in vec2 fpos;\n"
"out vec4 outColor;\n"
"\n"
"float sdroundrect(vec2 pt, vec2 ext, float rad) {\n"
" vec2 ext2 = ext - vec2(rad,rad);\n"
" vec2 d = abs(pt) - ext2;\n"
" return min(max(d.x,d.y),0.0) + length(max(d,0.0)) - rad;\n"
"}\n"
"\n"
"// Scissoring\n"
"float scissorMask(vec2 p) {\n"
" vec2 sc = (abs((scissorMat * vec3(p,1.0)).xy) - scissorExt);\n"
" sc = vec2(0.5,0.5) - sc * scissorScale;\n"
" return clamp(sc.x,0.0,1.0) * clamp(sc.y,0.0,1.0);\n"
"}\n"
"\n"
"void main(void) {\n"
" if (type == 0) { // Gradient\n"
" float scissor = scissorMask(fpos);\n"
" // Calculate gradient color using box gradient\n"
" vec2 pt = (paintMat * vec3(fpos,1.0)).xy;\n"
" float d = clamp((sdroundrect(pt, extent, radius) + feather*0.5) / feather, 0.0, 1.0);\n"
" vec4 color = mix(innerCol,outerCol,d);\n"
" // Combine alpha\n"
" color.w *= scissor;\n"
" outColor = color;\n"
" } else if (type == 1) { // Image\n"
" float scissor = scissorMask(fpos);\n"
" // Calculate color fron texture\n"
" vec2 pt = (paintMat * vec3(fpos,1.0)).xy / extent;\n"
" vec4 color = texture(tex, pt);\n"
" color = texType == 0 ? color : vec4(1,1,1,color.x);\n"
" // Combine alpha\n"
" color.w *= scissor;\n"
" outColor = color;\n"
" } else if (type == 2) { // Stencil fill\n"
" outColor = vec4(1,1,1,1);\n"
" } else if (type == 3) { // Textured tris\n"
" vec4 color = texture(tex, ftcoord);\n"
" color = texType == 0 ? color : vec4(1,1,1,color.x);\n"
" color.w *= scissor;\n"
" outColor = color * innerCol;\n"
" }\n"
"}\n";
@@ -468,10 +416,10 @@ static int glnvg__renderCreate(void* uptr)
glnvg__checkError("init");

if (gl->edgeAntiAlias) {
if (glnvg__createShader(&gl->shader, "shader", fillVertShader, fillFragShaderEdgeAA) == 0)
if (glnvg__createShader(&gl->shader, "shader", shaderHeader, "#define EDGE_AA 1\n", fillVertShader, fillFragShaderEdgeAA) == 0)
return 0;
} else {
if (glnvg__createShader(&gl->shader, "shader", fillVertShader, fillFragShader) == 0)
if (glnvg__createShader(&gl->shader, "shader", shaderHeader, NULL, fillVertShader, fillFragShaderEdgeAA) == 0)
return 0;
}

@@ -483,12 +431,12 @@ static int glnvg__renderCreate(void* uptr)
glGenBuffers(1, &gl->vertBuf);

// Create UBOs
glUniformBlockBinding(gl->shader.prog, gl->shader.loc[GLNVG_LOC_UBOVIEW], GLNVG_UBO_VIEW_BINDING);
glGenBuffers(1, &gl->uboViewBuf);
glUniformBlockBinding(gl->shader.prog, gl->shader.loc[GLNVG_LOC_UBOFRAG], GLNVG_UBO_FRAG_BINDING);
glGenBuffers(1, &gl->uboFragBuf);
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &gl->uboPosAlignment);
gl->uboPosAlignment = sizeof(struct GLNVGuboFrag) + gl->uboPosAlignment - sizeof(struct GLNVGuboFrag) % gl->uboPosAlignment;
glUniformBlockBinding(gl->shader.prog, gl->shader.loc[GLNVG_LOC_VIEW], GLNVG_VIEW_BINDING);
glGenBuffers(1, &gl->viewBuf);
glUniformBlockBinding(gl->shader.prog, gl->shader.loc[GLNVG_LOC_FRAG], GLNVG_FRAG_BINDING);
glGenBuffers(1, &gl->fragBuf);
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &align);
gl->fragSize = sizeof(struct GLNVGfragUniforms) + align - sizeof(struct GLNVGfragUniforms) % align;

glnvg__checkError("done");

@@ -613,60 +561,55 @@ static void glnvg__xformToMat3x4(float* m3, float* t)
m3[11] = 0.0f;
}

static int glnvg__setupPaintUBO(struct GLNVGcontext* gl, struct NVGpaint* paint, struct NVGscissor* scissor, float width, struct GLNVGuboFrag* uboBuff)
static int glnvg__convertPaint(struct GLNVGcontext* gl, struct GLNVGfragUniforms* frag, struct NVGpaint* paint, struct NVGscissor* scissor, float width)
{
struct GLNVGuboFrag ubo;
glnvg__toFloatColor(ubo.innerCol, paint->innerColor);
glnvg__toFloatColor(ubo.outerCol, paint->outerColor);
struct GLNVGtexture* tex = NULL;
float invxform[6];

glnvg__toFloatColor(frag->innerCol, paint->innerColor);
glnvg__toFloatColor(frag->outerCol, paint->outerColor);

glnvg__xformInverse(invxform, paint->xform);
glnvg__xformToMat3x4(ubo.paintMat, invxform);
glnvg__xformToMat3x4(frag->paintMat, invxform);

if (scissor->extent[0] < 0.5f || scissor->extent[1] < 0.5f) {
memset(ubo.scissorMat, 0, sizeof(ubo.scissorMat));
ubo.scissorExt[0] = 1.0f;
ubo.scissorExt[1] = 1.0f;
ubo.scissorScale[0] = 1.0f;
ubo.scissorScale[1] = 1.0f;
memset(frag->scissorMat, 0, sizeof(frag->scissorMat));
frag->scissorExt[0] = 1.0f;
frag->scissorExt[1] = 1.0f;
frag->scissorScale[0] = 1.0f;
frag->scissorScale[1] = 1.0f;
} else {
glnvg__xformInverse(invxform, scissor->xform);
glnvg__xformToMat3x4(ubo.scissorMat, invxform);
ubo.scissorExt[0] = scissor->extent[0];
ubo.scissorExt[1] = scissor->extent[1];
ubo.scissorScale[0] = sqrtf(scissor->xform[0]*scissor->xform[0] + scissor->xform[2]*scissor->xform[2]);
ubo.scissorScale[1] = sqrtf(scissor->xform[1]*scissor->xform[1] + scissor->xform[3]*scissor->xform[3]);
glnvg__xformToMat3x4(frag->scissorMat, invxform);
frag->scissorExt[0] = scissor->extent[0];
frag->scissorExt[1] = scissor->extent[1];
frag->scissorScale[0] = sqrtf(scissor->xform[0]*scissor->xform[0] + scissor->xform[2]*scissor->xform[2]);
frag->scissorScale[1] = sqrtf(scissor->xform[1]*scissor->xform[1] + scissor->xform[3]*scissor->xform[3]);
}
memcpy( ubo.extent, paint->extent, sizeof( ubo.extent ) );
ubo.strokeMult = width*0.5f + 0.5f;
memcpy(frag->extent, paint->extent, sizeof(frag->extent));
frag->strokeMult = width*0.5f + 0.5f;

if (paint->image != 0) {
tex = glnvg__findTexture(gl, paint->image);
if (tex == NULL) return 0;
ubo.type = NSVG_SHADER_FILLIMG;
ubo.texType = tex->type == NVG_TEXTURE_RGBA ? 0 : 1;
glnvg__checkError("tex paint loc");
frag->type = NSVG_SHADER_FILLIMG;
frag->texType = tex->type == NVG_TEXTURE_RGBA ? 0 : 1;
} else {
ubo.type = NSVG_SHADER_FILLGRAD;
ubo.radius = paint->radius;
ubo.feather = paint->feather;
glnvg__checkError("grad paint loc");
frag->type = NSVG_SHADER_FILLGRAD;
frag->radius = paint->radius;
frag->feather = paint->feather;
}
*uboBuff = ubo;
return 1;
}

static int glnvg__setupPaint(struct GLNVGcontext* gl, struct NVGpaint* paint, int uboOffset)
static void glnvg__setUniforms(struct GLNVGcontext* gl, int uniformOffset, int image)
{
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;
glBindTexture(GL_TEXTURE_2D, tex->tex);
glBindBufferRange(GL_UNIFORM_BUFFER, GLNVG_FRAG_BINDING, gl->fragBuf, uniformOffset, sizeof(struct GLNVGfragUniforms));
if (image != 0) {
struct GLNVGtexture* tex = glnvg__findTexture(gl, image);
glBindTexture(GL_TEXTURE_2D, tex != NULL ? tex->tex : 0);
glnvg__checkError("tex paint tex");
}
return 1;
}

static void glnvg__renderViewport(void* uptr, int width, int height)
@@ -679,7 +622,7 @@ static void glnvg__renderViewport(void* uptr, int width, int height)
static void glnvg__fill(struct GLNVGcontext* gl, struct GLNVGcall* call)
{
struct GLNVGpath* paths = &gl->paths[call->pathOffset];
int npaths = call->pathCount, i;
int i, npaths = call->pathCount;

// Draw shapes
glDisable(GL_BLEND);
@@ -689,8 +632,8 @@ static void glnvg__fill(struct GLNVGcontext* gl, struct GLNVGcall* call)
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");
glnvg__setUniforms(gl, call->uniformOffset, 0);
glnvg__checkError("fill simple");

glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP);
glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP);
@@ -703,7 +646,8 @@ static void glnvg__fill(struct GLNVGcontext* gl, struct GLNVGcall* call)
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glEnable(GL_BLEND);

glnvg__setupPaint(gl, &call->paint, call->uboOffset + gl->uboPosAlignment);
glnvg__setUniforms(gl, call->uniformOffset + gl->fragSize, call->image);
glnvg__checkError("fill fill");

if (gl->edgeAntiAlias) {
glStencilFunc(GL_EQUAL, 0x00, 0xff);
@@ -724,9 +668,10 @@ static void glnvg__fill(struct GLNVGcontext* gl, struct GLNVGcall* call)
static void glnvg__convexFill(struct GLNVGcontext* gl, struct GLNVGcall* call)
{
struct GLNVGpath* paths = &gl->paths[call->pathOffset];
int npaths = call->pathCount, i;
int i, npaths = call->pathCount;

glnvg__setupPaint(gl, &call->paint, call->uboOffset);
glnvg__setUniforms(gl, call->uniformOffset, call->image);
glnvg__checkError("convex fill");

for (i = 0; i < npaths; i++)
glDrawArrays(GL_TRIANGLE_FAN, paths[i].fillOffset, paths[i].fillCount);
@@ -742,7 +687,8 @@ 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, call->uboOffset);
glnvg__setUniforms(gl, call->uniformOffset, call->image);
glnvg__checkError("stroke fill");

// Draw Strokes
for (i = 0; i < npaths; i++)
@@ -751,57 +697,25 @@ static void glnvg__stroke(struct GLNVGcontext* gl, struct GLNVGcall* call)

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, call->uboOffset, sizeof(struct GLNVGuboFrag));
glnvg__setUniforms(gl, call->uniformOffset, call->image);
glnvg__checkError("triangles fill");

glnvg__checkError("tris solid img loc");
glDrawArrays(GL_TRIANGLES, call->triangleOffset, call->triangleCount);
}

static void glnvg__renderFlush(void* uptr)
{
struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
int i, offset;
char* buff;
int i;

if (gl->ncalls > 0) {

glUseProgram(gl->shader.prog);
glEnable(GL_CULL_FACE);

// upload ubo for frag shaders - maximum ubos is 2x num calls
glBindBuffer(GL_UNIFORM_BUFFER, gl->uboFragBuf);
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[offset];
call->uboOffset = offset;
if (call->type == GLNVG_FILL) {
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);
offset += gl->uboPosAlignment;
} else if (call->type == GLNVG_STROKE) {
glnvg__setupPaintUBO(gl, &call->paint, &call->scissor, call->strokeWidth, ubo);
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;
offset += gl->uboPosAlignment;
}
}
glUnmapBuffer(GL_UNIFORM_BUFFER);
// Upload ubo for frag shaders
glBindBuffer(GL_UNIFORM_BUFFER, gl->fragBuf);
glBufferData(GL_UNIFORM_BUFFER, gl->nuniforms * gl->fragSize, gl->uniforms, GL_STREAM_DRAW);

// Upload vertex data
glBindVertexArray(gl->vertArr);
@@ -813,12 +727,12 @@ static void glnvg__renderFlush(void* uptr)
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(struct NVGvertex), (const GLvoid*)(0 + 2*sizeof(float)));
// once per frame set ubo for view
glBindBuffer(GL_UNIFORM_BUFFER, gl->uboViewBuf);
glBindBuffer(GL_UNIFORM_BUFFER, gl->viewBuf);
glBufferData(GL_UNIFORM_BUFFER, sizeof(gl->view), 0, GL_STREAM_DRAW);
glBufferData(GL_UNIFORM_BUFFER, sizeof(gl->view), gl->view, GL_STREAM_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, GLNVG_UBO_VIEW_BINDING, gl->uboViewBuf);
glBindBufferBase(GL_UNIFORM_BUFFER, GLNVG_VIEW_BINDING, gl->viewBuf);

glBindBuffer(GL_UNIFORM_BUFFER, gl->uboFragBuf);
glBindBuffer(GL_UNIFORM_BUFFER, gl->fragBuf);

for (i = 0; i < gl->ncalls; i++) {
struct GLNVGcall* call = &gl->calls[i];
@@ -841,6 +755,7 @@ static void glnvg__renderFlush(void* uptr)
gl->nverts = 0;
gl->npaths = 0;
gl->ncalls = 0;
gl->nuniforms = 0;
}

static int glnvg__maxVertCount(const struct NVGpath* paths, int npaths)
@@ -891,6 +806,23 @@ static int glnvg__allocVerts(struct GLNVGcontext* gl, int n)
return ret;
}

static int glnvg__allocFragUniforms(struct GLNVGcontext* gl, int n)
{
int ret = 0, structSize = gl->fragSize;
if (gl->nuniforms+n > gl->cuniforms) {
gl->cuniforms = gl->cuniforms == 0 ? glnvg__maxi(n, 32) : gl->cuniforms * 2;
gl->uniforms = (unsigned char*)realloc(gl->uniforms, gl->cuniforms * structSize);
}
ret = gl->nuniforms * structSize;
gl->nuniforms += n;
return ret;
}

static struct GLNVGfragUniforms* nvg__fragUniformPtr(struct GLNVGcontext* gl, int i)
{
return (struct GLNVGfragUniforms*)&gl->uniforms[i];
}

static void glnvg__vset(struct NVGvertex* vtx, float x, float y, float u, float v)
{
vtx->x = x;
@@ -905,41 +837,41 @@ static void glnvg__renderFill(void* uptr, struct NVGpaint* paint, struct NVGscis
struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
struct GLNVGcall* call = glnvg__allocCall(gl);
struct NVGvertex* quad;
int i, maxverts, vertsoff;
struct GLNVGfragUniforms* frag;
int i, maxverts, offset;

call->type = GLNVG_FILL;
call->pathOffset = glnvg__allocPaths(gl, npaths);
call->pathCount = npaths;
call->paint = *paint;
call->scissor = *scissor;
call->image = paint->image;

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);
offset = glnvg__allocVerts(gl, maxverts + 6);

for (i = 0; i < npaths; i++) {
struct GLNVGpath* copy = &gl->paths[call->pathOffset + i];
const struct NVGpath* path = &paths[i];
memset(copy, 0, sizeof(struct GLNVGpath));
if (path->nfill) {
copy->fillOffset = vertsoff;
copy->fillOffset = offset;
copy->fillCount = path->nfill;
memcpy(&gl->verts[vertsoff], path->fill, sizeof(struct NVGvertex) * path->nfill);
vertsoff += path->nfill;
memcpy(&gl->verts[offset], path->fill, sizeof(struct NVGvertex) * path->nfill);
offset += path->nfill;
}
if (path->nstroke) {
copy->strokeOffset = vertsoff;
copy->strokeOffset = offset;
copy->strokeCount = path->nstroke;
memcpy(&gl->verts[vertsoff], path->stroke, sizeof(struct NVGvertex) * path->nstroke);
vertsoff += path->nstroke;
memcpy(&gl->verts[offset], path->stroke, sizeof(struct NVGvertex) * path->nstroke);
offset += path->nstroke;
}
}

// Quad
call->triangleOffset = vertsoff;
call->triangleOffset = offset;
call->triangleCount = 6;
quad = &gl->verts[call->triangleOffset];
glnvg__vset(&quad[0], bounds[0], bounds[3], 0.5f, 1.0f);
@@ -949,37 +881,53 @@ static void glnvg__renderFill(void* uptr, struct NVGpaint* paint, struct NVGscis
glnvg__vset(&quad[3], bounds[0], bounds[3], 0.5f, 1.0f);
glnvg__vset(&quad[4], bounds[2], bounds[1], 0.5f, 1.0f);
glnvg__vset(&quad[5], bounds[0], bounds[1], 0.5f, 1.0f);

// Setup uniforms for draw calls
if (call->type == GLNVG_FILL) {
call->uniformOffset = glnvg__allocFragUniforms(gl, 2);
// Simple shader for stencil
frag = nvg__fragUniformPtr(gl, call->uniformOffset);
frag->type = NSVG_SHADER_SIMPLE;
// Fill shader
glnvg__convertPaint(gl, nvg__fragUniformPtr(gl, call->uniformOffset + gl->fragSize), paint, scissor, 1.0001f);
} else {
call->uniformOffset = glnvg__allocFragUniforms(gl, 1);
// Fill shader
glnvg__convertPaint(gl, nvg__fragUniformPtr(gl, call->uniformOffset), paint, scissor, 1.0001f);
}
}

static void glnvg__renderStroke(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor,
float width, const struct NVGpath* paths, int npaths)
float strokeWidth, const struct NVGpath* paths, int npaths)
{
struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
struct GLNVGcall* call = glnvg__allocCall(gl);
int i, maxverts, vertsoff;
int i, maxverts, offset;

call->type = GLNVG_STROKE;
call->pathOffset = glnvg__allocPaths(gl, npaths);
call->pathCount = npaths;
call->paint = *paint;
call->scissor = *scissor;
call->strokeWidth = width;
call->image = paint->image;

// Allocate vertices for all the paths.
maxverts = glnvg__maxVertCount(paths, npaths);
vertsoff = glnvg__allocVerts(gl, maxverts + 6);
offset = glnvg__allocVerts(gl, maxverts + 6);

for (i = 0; i < npaths; i++) {
struct GLNVGpath* copy = &gl->paths[call->pathOffset + i];
const struct NVGpath* path = &paths[i];
memset(copy, 0, sizeof(struct GLNVGpath));
if (path->nstroke) {
copy->strokeOffset = vertsoff;
copy->strokeOffset = offset;
copy->strokeCount = path->nstroke;
memcpy(&gl->verts[vertsoff], path->stroke, sizeof(struct NVGvertex) * path->nstroke);
vertsoff += path->nstroke;
memcpy(&gl->verts[offset], path->stroke, sizeof(struct NVGvertex) * path->nstroke);
offset += path->nstroke;
}
}

// Fill shader
call->uniformOffset = glnvg__allocFragUniforms(gl, 1);
glnvg__convertPaint(gl, nvg__fragUniformPtr(gl, call->uniformOffset), paint, scissor, strokeWidth);
}

static void glnvg__renderTriangles(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor,
@@ -987,15 +935,21 @@ static void glnvg__renderTriangles(void* uptr, struct NVGpaint* paint, struct NV
{
struct GLNVGcontext* gl = (struct GLNVGcontext*)uptr;
struct GLNVGcall* call = glnvg__allocCall(gl);
struct GLNVGfragUniforms* frag;

call->type = GLNVG_TRIANGLES;
call->paint = *paint;
call->scissor = *scissor;
call->image = paint->image;

// Allocate vertices for all the paths.
call->triangleOffset = glnvg__allocVerts(gl, nverts);
call->triangleCount = nverts;
memcpy(&gl->verts[call->triangleOffset], verts, sizeof(struct NVGvertex) * nverts);

// Fill shader
call->uniformOffset = glnvg__allocFragUniforms(gl, 1);
frag = nvg__fragUniformPtr(gl, call->uniformOffset);
glnvg__convertPaint(gl, frag, paint, scissor, 1.0f);
frag->type = NSVG_SHADER_IMG;
}

static void glnvg__renderDelete(void* uptr)
@@ -1006,6 +960,15 @@ static void glnvg__renderDelete(void* uptr)

glnvg__deleteShader(&gl->shader);

if (gl->vertArr != 0)
glDeleteVertexArrays(1, &gl->vertArr);
if (gl->vertBuf != 0)
glDeleteBuffers(1, &gl->vertBuf);
if (gl->viewBuf != 0)
glDeleteBuffers(1, &gl->viewBuf);
if (gl->fragBuf != 0)
glDeleteBuffers(1, &gl->fragBuf);

for (i = 0; i < gl->ntextures; i++) {
if (gl->textures[i].tex != 0)
glDeleteTextures(1, &gl->textures[i].tex);


Loading…
Cancel
Save