shithub: 3dee

Download patch

ref: cbfa17d446effcfc1e7d17aed624af8f098370f1
parent: 22edbd9f543509ab129ba03af92baed79139e07f
author: rodri <rgl@antares-labs.eu>
date: Thu May 23 17:26:19 EDT 2024

get rid of rendering latency by decoupling it from i/o.

i was using a single alternator to mux both i/o and drawing
in a single proc, and avoid locking. the problem is that it
causes a fight to break up every time there's any input
(steady 100Hz) or a lot of drawing requests from the
renderer (up to 60Hz.)

i added a drawproc to handle exclusively drawing requests,
 and a drawing lock for UI widgets that kidnap the display.

--- a/med.c
+++ b/med.c
@@ -76,6 +76,7 @@
 Model *model;
 Shadertab *shader;
 QLock scenelk;
+QLock drawlk;
 Mouse om;
 Quaternion orient = {1,0,0,0};
 
@@ -466,11 +467,11 @@
 }
 
 void
-drawproc(void *)
+renderproc(void *)
 {
 	uvlong t0, Δt;
 
-	threadsetname("drawproc");
+	threadsetname("renderproc");
 
 	t0 = nsec();
 	for(;;){
@@ -492,6 +493,18 @@
 }
 
 void
+drawproc(void *)
+{
+	threadsetname("drawproc");
+
+	for(;;)
+		if(recv(drawc, nil) && canqlock(&drawlk)){
+			redraw();
+			qunlock(&drawlk);
+		}
+}
+
+void
 lmb(void)
 {
 	if((om.buttons^mctl->buttons) == 0)
@@ -516,6 +529,7 @@
 	};
 	static Menu menu = { .item = items };
 
+	qlock(&drawlk);
 	switch(menuhit(2, mctl, &menu, _screen)){
 	case TSNEAREST:
 		tsampler = neartexsampler;
@@ -526,6 +540,7 @@
 	case QUIT:
 		threadexitsall(nil);
 	}
+	qunlock(&drawlk);
 	nbsend(drawc, nil);
 }
 
@@ -532,29 +547,43 @@
 static char *
 genrmbmenuitem(int idx)
 {
+	static char *items[] = {
+		"",
+		"add cube",
+		nil
+	};
 	if(idx < nelem(shadertab))
 		return shadertab[idx].name;
-	else if(idx == nelem(shadertab))
-		return "";
-	else if(idx == nelem(shadertab)+1)
-		return "add cube";
-	return nil;
+	idx -= nelem(shadertab);
+	return items[idx];
 }
 
 void
 rmb(void)
 {
+	enum {
+		SP,
+		ADDCUBE,
+	};
 	static Menu menu = { .gen = genrmbmenuitem };
 	int idx;
 
+	qlock(&drawlk);
 	idx = menuhit(3, mctl, &menu, _screen);
 	if(idx < 0)
-		return;
+		goto nohit;
 	if(idx < nelem(shadertab)){
 		shader = &shadertab[idx];
 		memset(&cam.stats, 0, sizeof(cam.stats));
-	}else if(idx == nelem(shadertab)+1)
+	}
+	idx -= nelem(shadertab);
+	switch(idx){
+	case ADDCUBE:
 		addcube();
+		break;
+	}
+nohit:
+	qunlock(&drawlk);
 	nbsend(drawc, nil);
 }
 
@@ -763,15 +792,15 @@
 
 	proccreate(kbdproc, nil, mainstacksize);
 	proccreate(keyproc, keyc, mainstacksize);
+	proccreate(renderproc, nil, mainstacksize);
 	proccreate(drawproc, nil, mainstacksize);
 
 	for(;;){
-		enum {MOUSE, RESIZE, KEY, DRAW};
+		enum {MOUSE, RESIZE, KEY};
 		Alt a[] = {
 			{mctl->c, &mctl->Mouse, CHANRCV},
 			{mctl->resizec, nil, CHANRCV},
 			{keyc, nil, CHANRCV},
-			{drawc, nil, CHANRCV},
 			{nil, nil, CHANEND}
 		};
 		switch(alt(a)){
@@ -778,7 +807,6 @@
 		case MOUSE: mouse(); break;
 		case RESIZE: resize(); break;
 		case KEY: handlekeys(); break;
-		case DRAW: redraw(); break;
 		}
 	}
 }
--- a/solar.c
+++ b/solar.c
@@ -136,6 +136,7 @@
 Tm date;
 char datestr[16];
 Scene *scene;
+QLock drawlk;
 
 Camera camera;
 Camcfg cameracfg = {
@@ -408,11 +409,11 @@
 }
 
 void
-drawproc(void *)
+renderproc(void *)
 {
 	uvlong t0, Δt;
 
-	threadsetname("drawproc");
+	threadsetname("renderproc");
 
 	t0 = nsec();
 	for(;;){
@@ -431,6 +432,18 @@
 	}
 }
 
+void
+drawproc(void *)
+{
+	threadsetname("drawproc");
+
+	for(;;)
+		if(recv(drawc, nil) && canqlock(&drawlk)){
+			redraw();
+			qunlock(&drawlk);
+		}
+}
+
 static char *
 genplanetmenu(int idx)
 {
@@ -446,11 +459,13 @@
 	Planet *p;
 	int idx;
 
+	qlock(&drawlk);
 	idx = menuhit(1, mctl, &menu, _screen);
-	if(idx < 0)
-		return;
-	p = &planets[idx];
-	placecamera(&camera, camera.p, p->body->p, cameracfg.up);
+	if(idx >= 0){
+		p = &planets[idx];
+		placecamera(&camera, camera.p, p->body->p, cameracfg.up);
+	}
+	qunlock(&drawlk);
 	nbsend(drawc, nil);
 }
 
@@ -460,10 +475,11 @@
 	static Menu menu = { .gen = genplanetmenu };
 	int idx;
 
+	qlock(&drawlk);
 	idx = menuhit(1, mctl, &menu, _screen);
-	if(idx < 0)
-		return;
-	gotoplanet(&planets[idx]);
+	if(idx >= 0)
+		gotoplanet(&planets[idx]);
+	qunlock(&drawlk);
 	nbsend(drawc, nil);
 }
 
@@ -477,13 +493,17 @@
 		return;
 
 	memmove(buf, datestr, sizeof buf);
+	qlock(&drawlk);
 	if(enter("new date", buf, sizeof buf, mctl, kctl, nil) <= 0)
-		return;
+		goto nodate;
 	if(tmparse(&t, datefmt, buf, nil, nil) == nil)
-		return;
+		goto nodate;
 	date = t;
 	snprint(datestr, sizeof datestr, "%τ", tmfmt(&date, datefmt));
 	updateplanets();
+nodate:
+	qunlock(&drawlk);
+	nbsend(drawc, nil);
 }
 
 Cmdbut cmds[] = {
@@ -554,16 +574,17 @@
 	if((om.buttons ^ mctl->buttons) == 0)
 		return;
 
+	qlock(&drawlk);
 	switch(menuhit(2, mctl, &menu, _screen)){
 	case CHGSPEED:
 		snprint(buf, sizeof buf, "%g", speed);
-		if(enter("speed (km)", buf, sizeof buf, mctl, kctl, nil) <= 0)
-			return;
-		speed = fabs(strtod(buf, nil));
+		if(enter("speed (km)", buf, sizeof buf, mctl, kctl, nil) > 0)
+			speed = fabs(strtod(buf, nil));
 		break;
 	case QUIT:
 		threadexitsall(nil);
 	}
+	qunlock(&drawlk);
 	nbsend(drawc, nil);
 }
 
@@ -808,15 +829,15 @@
 
 	proccreate(kbdproc, nil, mainstacksize);
 	proccreate(keyproc, keyc, mainstacksize);
+	proccreate(renderproc, nil, mainstacksize);
 	proccreate(drawproc, nil, mainstacksize);
 
 	for(;;){
-		enum {MOUSE, RESIZE, KEY, DRAW};
+		enum {MOUSE, RESIZE, KEY};
 		Alt a[] = {
 			{mctl->c, &mctl->Mouse, CHANRCV},
 			{mctl->resizec, nil, CHANRCV},
 			{keyc, nil, CHANRCV},
-			{drawc, nil, CHANRCV},
 			{nil, nil, CHANEND}
 		};
 		switch(alt(a)){
@@ -823,7 +844,6 @@
 		case MOUSE: mouse(); break;
 		case RESIZE: resize(); break;
 		case KEY: handlekeys(); break;
-		case DRAW: redraw(); break;
 		}
 	}
 }
--- a/vis.c
+++ b/vis.c
@@ -50,6 +50,7 @@
 Model *model;
 Entity *subject;
 Scene *scene;
+QLock drawlk;
 Mouse om;
 Quaternion orient = {1,0,0,0};
 
@@ -481,12 +482,12 @@
 }
 
 void
-drawproc(void *)
+renderproc(void *)
 {
 	uvlong t0, Δt;
 	int fd;
 
-	threadsetname("drawproc");
+	threadsetname("renderproc");
 
 	fd = -1;
 	if(inception){
@@ -522,6 +523,18 @@
 }
 
 void
+drawproc(void *)
+{
+	threadsetname("drawproc");
+
+	for(;;)
+		if(recv(drawc, nil) && canqlock(&drawlk)){
+			redraw();
+			qunlock(&drawlk);
+		}
+}
+
+void
 lmb(void)
 {
 	if((om.buttons^mctl->buttons) == 0)
@@ -546,14 +559,15 @@
 	char buf[256], *f[3];
 	int nf;
 
+	qlock(&drawlk);
 	switch(menuhit(2, mctl, &menu, _screen)){
 	case MOVELIGHT:
 		snprint(buf, sizeof buf, "%g %g %g", light.p.x, light.p.y, light.p.z);
 		if(enter("light pos", buf, sizeof buf, mctl, kctl, nil) <= 0)
-			return;
+			break;
 		nf = tokenize(buf, f, 3);
 		if(nf != 3)
-			return;
+			break;
 		light.p.x = strtod(f[0], nil);
 		light.p.y = strtod(f[1], nil);
 		light.p.z = strtod(f[2], nil);
@@ -565,6 +579,7 @@
 		tsampler = bilitexsampler;
 		break;
 	}
+	qunlock(&drawlk);
 	nbsend(drawc, nil);
 }
 
@@ -582,12 +597,14 @@
 	static Menu menu = { .gen = genrmbmenuitem };
 	int idx;
 
+	qlock(&drawlk);
 	idx = menuhit(3, mctl, &menu, _screen);
-	if(idx < 0)
-		return;
-	shader = &shadertab[idx];
-	for(idx = 0; idx < nelem(cams); idx++)
-		memset(&cams[idx].stats, 0, sizeof(cams[idx].stats));
+	if(idx >= 0){
+		shader = &shadertab[idx];
+		for(idx = 0; idx < nelem(cams); idx++)
+			memset(&cams[idx].stats, 0, sizeof(cams[idx].stats));
+	}
+	qunlock(&drawlk);
 	nbsend(drawc, nil);
 }
 
@@ -843,15 +860,15 @@
 
 	proccreate(kbdproc, nil, mainstacksize);
 	proccreate(keyproc, keyc, mainstacksize);
+	proccreate(renderproc, nil, mainstacksize);
 	proccreate(drawproc, nil, mainstacksize);
 
 	for(;;){
-		enum {MOUSE, RESIZE, KEY, DRAW};
+		enum {MOUSE, RESIZE, KEY};
 		Alt a[] = {
 			{mctl->c, &mctl->Mouse, CHANRCV},
 			{mctl->resizec, nil, CHANRCV},
 			{keyc, nil, CHANRCV},
-			{drawc, nil, CHANRCV},
 			{nil, nil, CHANEND}
 		};
 		switch(alt(a)){
@@ -858,7 +875,6 @@
 		case MOUSE: mouse(); break;
 		case RESIZE: resize(); break;
 		case KEY: handlekeys(); break;
-		case DRAW: redraw(); break;
 		}
 	}
 }