shithub: libgraphics

Download patch

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
--