ref: 45a5d683af474c57b8c486d8cf44d424e0190f0d
parent: d464ab2c0efc986755f28403e69a75ef878a1230
author: rodri <rgl@antares-labs.eu>
date: Wed Feb 18 12:33:53 EST 2026
make the Vertexattrs hold a static amount of attributes unsurprisingly this simplifies the code a lot, with the drawback of reduced flexibility. avoiding so many recurring allocations is beneficial up to a point, because now the attributes are embedded in the vertices, which helps with locality, but requires copying more data. i think for now it's safe to say that if your shaders need an amount of attributes that outweigh these gains you are probably overdoing it.
--- a/TODO.md
+++ b/TODO.md
@@ -15,4 +15,3 @@
transparency rendering without the A-buffer.
- [ ] Implement decals
- [+] Implement Model deduplication/compaction routine
-- [ ] Turn the Vertexattrs into a dynamic hash table
--- a/clip.c
+++ b/clip.c
@@ -38,16 +38,6 @@
}
static void
-cleanpoly(Polygon *p)
-{- int i;
-
- for(i = 0; i < p->n; i++)
- _delvattrs(&p->v[i]);
- p->n = 0;
-}
-
-static void
fprintpoly(int fd, Polygon *p)
{int i;
@@ -112,38 +102,32 @@
if(sd1[j] >= 0){allin:
- addvert(Vout, _dupvertex(v1));
+ addvert(Vout, *v1);
}
}
- cleanpoly(Vin);
+ Vin->n = 0;
if(j < 6-1)
SWAP(Polygon*, &Vin, &Vout);
}
- if(Vout->n < 2)
- cleanpoly(Vout);
- else switch(p->type){- case PLine:
- cp[0] = *p;
- cp[0].v[0] = _dupvertex(&Vout->v[0]);
- cp[0].v[1] = eqpt3(Vout->v[0].p, Vout->v[1].p)? _dupvertex(&Vout->v[2]): _dupvertex(&Vout->v[1]);
- cleanpoly(Vout);
- np = 1;
- break;
- case PTriangle:
- /* triangulate */
- for(i = 0; i < Vout->n-2; i++, np++){- /*
- * when performing fan triangulation, indices 0 and 2
- * are referenced on every triangle, so duplicate them
- * to avoid complications during rasterization.
- */
- cp[np] = *p;
- cp[np].v[0] = i < Vout->n-2-1? _dupvertex(&Vout->v[0]): Vout->v[0];
- cp[np].v[1] = Vout->v[i+1];
- cp[np].v[2] = i < Vout->n-2-1? _dupvertex(&Vout->v[i+2]): Vout->v[i+2];
+ if(Vout->n > 1){+ switch(p->type){+ case PLine:
+ cp[0] = *p;
+ cp[0].v[0] = Vout->v[0];
+ cp[0].v[1] = eqpt3(Vout->v[0].p, Vout->v[1].p)? Vout->v[2]: Vout->v[1];
+ np = 1;
+ break;
+ case PTriangle:
+ /* triangulate */
+ for(i = 0; i < Vout->n-2; i++, np++){+ cp[np] = *p;
+ cp[np].v[0] = Vout->v[0];
+ cp[np].v[1] = Vout->v[i+1];
+ cp[np].v[2] = Vout->v[i+2];
+ }
+ break;
}
- break;
}
free(Vout->v);
free(Vin->v);
@@ -205,8 +189,6 @@
perc = len == 0? 0: hypot(Δp.x, Δp.y)/len;
_lerpvertex(&v[1], v0, v1, perc);
- _delvattrs(v0);
- _delvattrs(v1);
*v0 = v[0];
*v1 = v[1];
}
--- a/graphics.h
+++ b/graphics.h
@@ -51,6 +51,8 @@
VAPoint = 0,
VANumber,
+ MAXVATTRS = 10, /* change this if your shaders require it */
+
/* itemarray */
NaI = ~0ULL, /* not an index */
};
@@ -142,7 +144,7 @@
struct Vertexattrs
{- Vertexattr *attrs;
+ Vertexattr attrs[MAXVATTRS];
ulong nattrs;
};
--- a/internal.h
+++ b/internal.h
@@ -128,13 +128,11 @@
void _rmfbctl(Framebufctl*);
/* vertex */
-BVertex _dupvertex(BVertex*);
void _loadvertex(BVertex*, BVertex*);
void _lerpvertex(BVertex*, BVertex*, BVertex*, double);
void _berpvertex(BVertex*, BVertex*, BVertex*, BVertex*, Point3);
void _addvertex(BVertex*, BVertex*);
void _mulvertex(BVertex*, double);
-void _delvattrs(BVertex*);
void _fprintvattrs(int, Vertexattrs*);
void _addvattr(Vertexattrs*, char*, int, void*);
Vertexattr *_getvattr(Vertexattrs*, char*);
--- a/render.c
+++ b/render.c
@@ -458,10 +458,6 @@
// ∇z.f0 += ∇z.dy;
// ∇pcz.f0 += ∇pcz.dy;
}
-
-// _delvattrs(vp);
-// _delvattrs(&∇v.dx);
-// _delvattrs(&∇v.dy);
}
static void
@@ -523,11 +519,6 @@
fsp.scene = task.job->camera->scene;
task.fsp = &fsp;
(*rasterfn[task.p.type])(&task);
-
- _delvattrs(&v);
- if(task.p.type != PPoint)
- for(i = 0; i < task.p.type+1; i++)
- _delvattrs(&task.p.v[i]);
}
}
@@ -631,7 +622,6 @@
switch(p->type){case PPoint:
p->v[0].mtl = p->mtl;
- p->v[0].attrs = nil;
p->v[0].nattrs = 0;
vsp.v = &p->v[0];
@@ -651,16 +641,13 @@
if(ptinrect(bbox.min, wr[i])){rtask.clipr = &task.job->cliprects[i];
rtask.p = *p;
- rtask.p.v[0] = _dupvertex(&p->v[0]);
send(taskchans[i], &rtask);
break;
}
- _delvattrs(&p->v[0]);
break;
case PLine:
for(i = 0; i < 2; i++){p->v[i].mtl = p->mtl;
- p->v[i].attrs = nil;
p->v[i].nattrs = 0;
vsp.v = &p->v[i];
@@ -691,17 +678,12 @@
rtask.wr = wr[i];
rtask.clipr = &task.job->cliprects[i];
rtask.p = *p;
- rtask.p.v[0] = _dupvertex(&p->v[0]);
- rtask.p.v[1] = _dupvertex(&p->v[1]);
send(taskchans[i], &rtask);
}
- _delvattrs(&p->v[0]);
- _delvattrs(&p->v[1]);
break;
case PTriangle:
for(i = 0; i < 3; i++){p->v[i].mtl = p->mtl;
- p->v[i].attrs = nil;
p->v[i].nattrs = 0;
p->v[i].tangent = p->tangent;
@@ -723,7 +705,7 @@
/* culling */
if((vsp.camera->cullmode == CullFront && !isfacingback(p))
|| (vsp.camera->cullmode == CullBack && isfacingback(p)))
- goto skiptri;
+ continue;
p->v[0].p = ndc2viewport(vsp.fb, p->v[0].p);
p->v[1].p = ndc2viewport(vsp.fb, p->v[1].p);
@@ -740,15 +722,8 @@
rectclip(&rtask.wr, wr[i]);
rtask.clipr = &task.job->cliprects[i];
rtask.p = *p;
- rtask.p.v[0] = _dupvertex(&p->v[0]);
- rtask.p.v[1] = _dupvertex(&p->v[1]);
- rtask.p.v[2] = _dupvertex(&p->v[2]);
send(taskchans[i], &rtask);
}
-skiptri:
- _delvattrs(&p->v[0]);
- _delvattrs(&p->v[1]);
- _delvattrs(&p->v[2]);
}
break;
default: sysfatal("alien primitive detected");--- a/vertex.c
+++ b/vertex.c
@@ -19,8 +19,8 @@
v->attrs[i] = *va;
return;
}
- if(v->nattrs % 8 == 0)
- v->attrs = _erealloc(v->attrs, (v->nattrs + 8)*sizeof(*va));
+ if(v->nattrs == MAXVATTRS)
+ sysfatal("too many vertex attributes or uniforms");v->attrs[v->nattrs++] = *va;
}
@@ -33,18 +33,6 @@
addvattr(d, &s->attrs[i]);
}
-BVertex
-_dupvertex(BVertex *v)
-{- BVertex nv;
-
- nv = *v;
- nv.attrs = nil;
- nv.nattrs = 0;
- copyvattrs(&nv, v);
- return nv;
-}
-
void
_loadvertex(BVertex *d, BVertex *s)
{@@ -168,14 +156,6 @@
if(id != nil && strcmp(v->attrs[i].id, id) == 0)
return &v->attrs[i];
return nil;
-}
-
-void
-_delvattrs(BVertex *v)
-{- free(v->attrs);
- v->attrs= nil;
- v->nattrs = 0;
}
void
--
⑨