Browse Source

More error checking on allocations

- changed remainder of allocations to follow same 1.5x patters
- do not leak memory when realloc() fails
- added error handling in case allocations fail
shared-context
Mikko Mononen 11 years ago
parent
commit
7f55decf8f
2 changed files with 80 additions and 23 deletions
  1. +19
    -14
      src/nanovg.c
  2. +61
    -9
      src/nanovg_gl.h

+ 19
- 14
src/nanovg.c View File

@@ -857,11 +857,11 @@ static void nvg__appendCommands(struct NVGcontext* ctx, float* vals, int nvals)
int i;

if (ctx->ncommands+nvals > ctx->ccommands) {
if (ctx->ccommands == 0) ctx->ccommands = 8;
while (ctx->ccommands < ctx->ncommands+nvals)
ctx->ccommands *= 2;
ctx->commands = (float*)realloc(ctx->commands, ctx->ccommands*sizeof(float));
if (ctx->commands == NULL) return;
float* commands;
ctx->ccommands = ctx->ncommands+nvals + ctx->ccommands/2;
commands = (float*)realloc(ctx->commands, ctx->ccommands*sizeof(float));
if (commands == NULL) return;
ctx->commands = commands;
}

// transform commands
@@ -922,9 +922,11 @@ static void nvg__addPath(struct NVGcontext* ctx)
{
struct NVGpath* path;
if (ctx->cache->npaths+1 > ctx->cache->cpaths) {
struct NVGpath* paths;
ctx->cache->cpaths = ctx->cache->npaths+1 + ctx->cache->cpaths/2;
ctx->cache->paths = (struct NVGpath*)realloc(ctx->cache->paths, sizeof(struct NVGpath)*ctx->cache->cpaths);
if (ctx->cache->paths == NULL) return;
paths = (struct NVGpath*)realloc(ctx->cache->paths, sizeof(struct NVGpath)*ctx->cache->cpaths);
if (paths == NULL) return;
ctx->cache->paths = paths;
}
path = &ctx->cache->paths[ctx->cache->npaths];
memset(path, 0, sizeof(*path));
@@ -956,9 +958,11 @@ static void nvg__addPoint(struct NVGcontext* ctx, float x, float y, int flags)
}

if (ctx->cache->npoints+1 > ctx->cache->cpoints) {
struct NVGpoint* points;
ctx->cache->cpoints = ctx->cache->npoints+1 + ctx->cache->cpoints/2;
ctx->cache->points = (struct NVGpoint*)realloc(ctx->cache->points, sizeof(struct NVGpoint)*ctx->cache->cpoints);
if (ctx->cache->points == NULL) return;
points = (struct NVGpoint*)realloc(ctx->cache->points, sizeof(struct NVGpoint)*ctx->cache->cpoints);
if (points == NULL) return;
ctx->cache->points = points;
}

pt = &ctx->cache->points[ctx->cache->npoints];
@@ -995,12 +999,13 @@ static float nvg__getAverageScale(float *t)
static struct NVGvertex* nvg__allocTempVerts(struct NVGcontext* ctx, int nverts)
{
if (nverts > ctx->cache->cverts) {
if (ctx->cache->cverts == 0) ctx->cache->cverts = 8;
while (ctx->cache->cverts < nverts)
ctx->cache->cverts *= 2;
ctx->cache->verts = (struct NVGvertex*)realloc(ctx->cache->verts, sizeof(struct NVGvertex)*ctx->cache->cverts);
if (ctx->cache->verts == NULL) return NULL;
struct NVGvertex* verts;
ctx->cache->cverts = (nverts + 0xff) & ~0xff; // Round up to prevent allocations when things change just slightly.
verts = (struct NVGvertex*)realloc(ctx->cache->verts, sizeof(struct NVGvertex)*ctx->cache->cverts);
if (verts == NULL) return NULL;
ctx->cache->verts = verts;
}

return ctx->cache->verts;
}



+ 61
- 9
src/nanovg_gl.h View File

@@ -128,6 +128,7 @@ struct GLNVGtexture {
};

enum GLNVGcallType {
GLNVG_NONE = 0,
GLNVG_FILL,
GLNVG_CONVEXFILL,
GLNVG_STROKE,
@@ -199,6 +200,7 @@ struct GLNVGcontext {
int nuniforms;
};

static int glnvg__maxi(int a, int b) { return a > b ? a : b; }

static struct GLNVGtexture* glnvg__allocTexture(struct GLNVGcontext* gl)
{
@@ -213,9 +215,11 @@ static struct GLNVGtexture* glnvg__allocTexture(struct GLNVGcontext* gl)
}
if (tex == NULL) {
if (gl->ntextures+1 > gl->ctextures) {
gl->ctextures = (gl->ctextures == 0) ? 2 : gl->ctextures*2;
gl->textures = (struct GLNVGtexture*)realloc(gl->textures, sizeof(struct GLNVGtexture)*gl->ctextures);
if (gl->textures == NULL) return NULL;
struct GLNVGtexture* textures;
gl->ctextures = glnvg__maxi(gl->ntextures+1, 4) + gl->ctextures/2; // 1.5x Overallocate
textures = (struct GLNVGtexture*)realloc(gl->textures, sizeof(struct GLNVGtexture)*gl->ctextures);
if (textures == NULL) return NULL;
gl->textures = textures;
}
tex = &gl->textures[gl->ntextures++];
}
@@ -577,6 +581,7 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, const
struct GLNVGtexture* tex = glnvg__allocTexture(gl);

if (tex == NULL) return 0;

glGenTextures(1, &tex->tex);
tex->width = w;
tex->height = h;
@@ -978,14 +983,15 @@ static int glnvg__maxVertCount(const struct NVGpath* paths, int npaths)
return count;
}

static int glnvg__maxi(int a, int b) { return a > b ? a : b; }

static struct GLNVGcall* glnvg__allocCall(struct GLNVGcontext* gl)
{
struct GLNVGcall* ret = NULL;
if (gl->ncalls+1 > gl->ccalls) {
struct GLNVGcall* calls;
gl->ccalls = glnvg__maxi(gl->ncalls+1, 128) + gl->ccalls; // 1.5x Overallocate
gl->calls = (struct GLNVGcall*)realloc(gl->calls, sizeof(struct GLNVGcall) * gl->ccalls);
calls = (struct GLNVGcall*)realloc(gl->calls, sizeof(struct GLNVGcall) * gl->ccalls);
if (calls == NULL) return NULL;
gl->calls = calls;
}
ret = &gl->calls[gl->ncalls++];
memset(ret, 0, sizeof(struct GLNVGcall));
@@ -996,8 +1002,11 @@ static int glnvg__allocPaths(struct GLNVGcontext* gl, int n)
{
int ret = 0;
if (gl->npaths+n > gl->cpaths) {
struct GLNVGpath* paths;
gl->cpaths = glnvg__maxi(gl->npaths + n, 128) + gl->cpaths; // 1.5x Overallocate
gl->paths = (struct GLNVGpath*)realloc(gl->paths, sizeof(struct GLNVGpath) * gl->cpaths);
paths = (struct GLNVGpath*)realloc(gl->paths, sizeof(struct GLNVGpath) * gl->cpaths);
if (paths == NULL) return -1;
gl->paths = paths;
}
ret = gl->npaths;
gl->npaths += n;
@@ -1008,8 +1017,11 @@ static int glnvg__allocVerts(struct GLNVGcontext* gl, int n)
{
int ret = 0;
if (gl->nverts+n > gl->cverts) {
struct NVGvertex* verts;
gl->cverts = glnvg__maxi(gl->nverts + n, 4096) + gl->cverts/2; // 1.5x Overallocate
gl->verts = (struct NVGvertex*)realloc(gl->verts, sizeof(struct NVGvertex) * gl->cverts);
verts = (struct NVGvertex*)realloc(gl->verts, sizeof(struct NVGvertex) * gl->cverts);
if (verts == NULL) return -1;
gl->verts = verts;
}
ret = gl->nverts;
gl->nverts += n;
@@ -1020,8 +1032,11 @@ static int glnvg__allocFragUniforms(struct GLNVGcontext* gl, int n)
{
int ret = 0, structSize = gl->fragSize;
if (gl->nuniforms+n > gl->cuniforms) {
unsigned char* uniforms;
gl->cuniforms = glnvg__maxi(gl->nuniforms+n, 128) + gl->cuniforms/2; // 1.5x Overallocate
gl->uniforms = (unsigned char*)realloc(gl->uniforms, gl->cuniforms * structSize);
uniforms = (unsigned char*)realloc(gl->uniforms, gl->cuniforms * structSize);
if (uniforms == NULL) return -1;
gl->uniforms = uniforms;
}
ret = gl->nuniforms * structSize;
gl->nuniforms += n;
@@ -1050,8 +1065,11 @@ static void glnvg__renderFill(void* uptr, struct NVGpaint* paint, struct NVGscis
struct GLNVGfragUniforms* frag;
int i, maxverts, offset;

if (call == NULL) return;

call->type = GLNVG_FILL;
call->pathOffset = glnvg__allocPaths(gl, npaths);
if (call->pathOffset == -1) goto error;
call->pathCount = npaths;
call->image = paint->image;

@@ -1061,6 +1079,7 @@ static void glnvg__renderFill(void* uptr, struct NVGpaint* paint, struct NVGscis
// Allocate vertices for all the paths.
maxverts = glnvg__maxVertCount(paths, npaths) + 6;
offset = glnvg__allocVerts(gl, maxverts);
if (offset == -1) goto error;

for (i = 0; i < npaths; i++) {
struct GLNVGpath* copy = &gl->paths[call->pathOffset + i];
@@ -1095,6 +1114,7 @@ static void glnvg__renderFill(void* uptr, struct NVGpaint* paint, struct NVGscis
// Setup uniforms for draw calls
if (call->type == GLNVG_FILL) {
call->uniformOffset = glnvg__allocFragUniforms(gl, 2);
if (call->uniformOffset == -1) goto error;
// Simple shader for stencil
frag = nvg__fragUniformPtr(gl, call->uniformOffset);
memset(frag, 0, sizeof(*frag));
@@ -1103,9 +1123,17 @@ static void glnvg__renderFill(void* uptr, struct NVGpaint* paint, struct NVGscis
glnvg__convertPaint(gl, nvg__fragUniformPtr(gl, call->uniformOffset + gl->fragSize), paint, scissor, fringe, fringe);
} else {
call->uniformOffset = glnvg__allocFragUniforms(gl, 1);
if (call->uniformOffset == -1) goto error;
// Fill shader
glnvg__convertPaint(gl, nvg__fragUniformPtr(gl, call->uniformOffset), paint, scissor, fringe, fringe);
}

return;

error:
// We get here if call alloc was ok, but something else is not.
// Roll back the last call to prevent drawing it.
if (gl->ncalls > 0) gl->ncalls--;
}

static void glnvg__renderStroke(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor, float fringe,
@@ -1115,14 +1143,18 @@ static void glnvg__renderStroke(void* uptr, struct NVGpaint* paint, struct NVGsc
struct GLNVGcall* call = glnvg__allocCall(gl);
int i, maxverts, offset;

if (call == NULL) return;

call->type = GLNVG_STROKE;
call->pathOffset = glnvg__allocPaths(gl, npaths);
if (call->pathOffset == -1) goto error;
call->pathCount = npaths;
call->image = paint->image;

// Allocate vertices for all the paths.
maxverts = glnvg__maxVertCount(paths, npaths);
offset = glnvg__allocVerts(gl, maxverts);
if (offset == -1) goto error;

for (i = 0; i < npaths; i++) {
struct GLNVGpath* copy = &gl->paths[call->pathOffset + i];
@@ -1138,7 +1170,15 @@ static void glnvg__renderStroke(void* uptr, struct NVGpaint* paint, struct NVGsc

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

return;

error:
// We get here if call alloc was ok, but something else is not.
// Roll back the last call to prevent drawing it.
if (gl->ncalls > 0) gl->ncalls--;
}

static void glnvg__renderTriangles(void* uptr, struct NVGpaint* paint, struct NVGscissor* scissor,
@@ -1148,19 +1188,31 @@ static void glnvg__renderTriangles(void* uptr, struct NVGpaint* paint, struct NV
struct GLNVGcall* call = glnvg__allocCall(gl);
struct GLNVGfragUniforms* frag;

if (call == NULL) return;

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

// Allocate vertices for all the paths.
call->triangleOffset = glnvg__allocVerts(gl, nverts);
if (call->triangleOffset == -1) goto error;
call->triangleCount = nverts;

memcpy(&gl->verts[call->triangleOffset], verts, sizeof(struct NVGvertex) * nverts);

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

return;

error:
// We get here if call alloc was ok, but something else is not.
// Roll back the last call to prevent drawing it.
if (gl->ncalls > 0) gl->ncalls--;
}

static void glnvg__renderDelete(void* uptr)


Loading…
Cancel
Save