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