shithub: tinyrend

Download patch

ref: 1a839bc268588144d9b39c45a665545c1aaa2ef3
parent: 82771754da18277f2e34efff4d5beca9a11d5c75
author: rodri <rgl@antares-labs.eu>
date: Fri Nov 10 10:29:27 EST 2023

parallelize shader execution.

--- a/main.c
+++ b/main.c
@@ -9,12 +9,31 @@
 #include <geometry.h>
 
 typedef Point Triangle[3];
+typedef struct Sparams Sparams;
+typedef struct SUparams SUparams;
 
+/* shader params */
+struct Sparams
+{
+	Memimage *frag;
+	Point p;
+};
 
+/* shader unit params */
+struct SUparams
+{
+	Memimage *dst;
+	Rectangle r;
+	int id;
+	Channel *donec;
+	Memimage *(*shader)(Sparams*);
+};
+
+
 Memimage *fb;
 Memimage *red, *green, *blue;
-Memimage *frag;
 Channel *drawc;
+int nprocs;
 
 void resized(void);
 uvlong nanosec(void);
@@ -204,19 +223,60 @@
 }
 
 void
-shade(Memimage *dst, Rectangle r, Memimage *(*shader)(Point))
+shaderunit(void *arg)
 {
+	SUparams *params;
+	Sparams sp;
 	Point p;
 	Memimage *c;
 
-	for(p.y = r.min.y; p.y < r.max.y; p.y++)
-		for(p.x = r.min.x; p.x < r.max.x; p.x++)
-			if((c = shader(p)) != nil)
-				pixel(dst, p, c);
+	params = arg;
+	sp.frag = rgb(DBlack);
+
+	for(p.y = params->r.min.y; p.y < params->r.max.y; p.y++)
+		for(p.x = params->r.min.x; p.x < params->r.max.x; p.x++){
+			sp.p = p;
+			if((c = params->shader(&sp)) != nil)
+				pixel(params->dst, p, c);
+		}
+
+	freememimage(sp.frag);
+	sendp(params->donec, nil);
+	free(params);
+	threadexits(nil);
 }
 
+void
+shade(Memimage *dst, Memimage *(*shader)(Sparams*))
+{
+	int i;
+	Point dim;
+	SUparams *params;
+	Channel *donec;
+
+	/* shitty approach until i find a better algo */
+	dim.x = Dx(dst->r)/nprocs;
+
+	donec = chancreate(sizeof(void*), 0);
+
+	for(i = 0; i < nprocs; i++){
+		params = emalloc(sizeof *params);
+		params->dst = dst;
+		params->r = Rect(i*dim.x,0,min((i+1)*dim.x, dst->r.max.x),dst->r.max.y);
+		params->id = i;
+		params->donec = donec;
+		params->shader = shader;
+		proccreate(shaderunit, params, mainstacksize);
+		fprint(2, "spawned su %d for %R\n", params->id, params->r);
+	}
+
+	while(i--)
+		recvp(donec);
+	chanfree(donec);
+}
+
 Memimage *
-triangleshader(Point p)
+triangleshader(Sparams *sp)
 {
 	Triangle2 t;
 	Rectangle bbox;
@@ -231,10 +291,10 @@
 		min(min(t.p0.x, t.p1.x), t.p2.x), min(min(t.p0.y, t.p1.y), t.p2.y),
 		max(max(t.p0.x, t.p1.x), t.p2.x), max(max(t.p0.y, t.p1.y), t.p2.y)
 	);
-	if(!ptinrect(p, bbox))
+	if(!ptinrect(sp->p, bbox))
 		return nil;
 
-	bc = barycoords(t, Pt2(p.x,p.y,1));
+	bc = barycoords(t, Pt2(sp->p.x,sp->p.y,1));
 	if(bc.x < 0 || bc.y < 0 || bc.z < 0)
 		return nil;
 
@@ -242,18 +302,18 @@
 	cbuf[1] = 0xFF*bc.z;
 	cbuf[2] = 0xFF*bc.y;
 	cbuf[3] = 0xFF*bc.x;
-	memfillcolor(frag, *(ulong*)cbuf);
-	return frag;
+	memfillcolor(sp->frag, *(ulong*)cbuf);
+	return sp->frag;
 }
 
 Memimage *
-circleshader(Point p)
+circleshader(Sparams *sp)
 {
 	Point2 uv;
 	double r;
 	uchar cbuf[4];
 
-	uv = Pt2(p.x,p.y,1);
+	uv = Pt2(sp->p.x,sp->p.y,1);
 	uv.x /= Dx(fb->r);
 	uv.y /= Dy(fb->r);
 	r = 0.3;
@@ -266,8 +326,8 @@
 	cbuf[2] = 0xFF*uv.y;
 	cbuf[3] = 0xFF*uv.x;
 
-	memfillcolor(frag, *(ulong*)cbuf);
-	return frag;
+	memfillcolor(sp->frag, *(ulong*)cbuf);
+	return sp->frag;
 }
 
 void
@@ -312,7 +372,7 @@
 void
 usage(void)
 {
-	fprint(2, "usage: %s\n", argv0);
+	fprint(2, "usage: %s [-n nprocs]\n", argv0);
 	exits("usage");
 }
 
@@ -326,11 +386,17 @@
 
 	GEOMfmtinstall();
 	ARGBEGIN{
+	case 'n':
+		nprocs = strtoul(EARGF(usage()), nil, 10);
+		break;
 	default: usage();
 	}ARGEND;
-	if(argc > 0)
+	if(argc != 0)
 		usage();
 
+	if(nprocs < 1)
+		nprocs = strtoul(getenv("NPROC"), nil, 10);
+
 	if(newwindow(nil) < 0)
 		sysfatal("newwindow: %r");
 	if(initdraw(nil, nil, nil) < 0)
@@ -349,7 +415,7 @@
 	frag = rgb(DBlack);
 
 	t0 = nanosec();
-	shade(fb, fb->r, circleshader);
+	shade(fb, circleshader);
 	t1 = nanosec();
 	fprint(2, "shader took %lludns\n", t1-t0);
 
@@ -365,7 +431,7 @@
 	triangle(fb, Pt(400,230), Pt(450,180), Pt(150, 320), red);
 
 	t0 = nanosec();
-	shade(fb, fb->r, triangleshader);
+	shade(fb, triangleshader);
 	t1 = nanosec();
 	fprint(2, "shader took %lludns\n", t1-t0);