shithub: riscv

Download patch

ref: 763231588c971758d36c7c48cd073f2fa96f8f5a
parent: 844612fcb8257c8d8f20ef4da62edb65b2c08b76
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Tue Nov 18 11:07:34 EST 2014

games/snes: flush screen in parallel to audio (fixes buffer underruns on x200s)

the x200s is too slow on a single core to keep up without
audio buffer underruns, so the idea is to flush screen
in parallel to witing audio samples in a separate process.

with the proc, we also can keep updating the screen on resize
when paused.

--- a/sys/src/games/snes/snes.c
+++ b/sys/src/games/snes/snes.c
@@ -13,6 +13,7 @@
 
 int ppuclock, spcclock, dspclock, stimerclock, saveclock, msgclock, paused, perfclock, cpupause;
 Mousectl *mc;
+Channel *flushc;
 QLock pauselock;
 u32int keys;
 int savefd, scale, profile, mouse, loadreq, savereq;
@@ -185,6 +186,68 @@
 }
 
 void
+screenproc(void *)
+{
+	extern uchar pic[256*240*2*3];
+	Mouse m;
+	Point p;
+
+	enum { AMOUSE, ARESIZE, AFLUSH, AEND };
+	Alt a[AEND+1] = {
+		{ mc->c,	&m,	CHANRCV },
+		{ mc->resizec,	nil,	CHANRCV },
+		{ flushc,	nil,	CHANRCV },
+		{ nil,		nil,	CHANEND }
+	};
+
+	for(;;){
+		switch(alt(a)){
+		case AMOUSE:
+			if(mouse && ptinrect(m.xy, picr)){
+				p = subpt(m.xy, picr.min);
+				p.x /= scale;
+				p.y /= scale;
+				keys = keys & 0xff3f0000 | p.x | p.y << 8;
+				if((m.buttons & 1) != 0)
+					keys |= 1<<22;
+				if((m.buttons & 4) != 0)
+					keys |= 1<<23;
+				if((m.buttons & 2) != 0)
+					lastkeys = keys;
+			}
+			break;
+		case ARESIZE:
+			if(getwindow(display, Refnone) < 0)
+				sysfatal("resize failed: %r");
+			screeninit();
+			/* wet floor */
+		case AFLUSH:
+			if(scale == 1){
+				loadimage(tmp, tmp->r, pic, 256*239*2);
+				draw(screen, picr, tmp, nil, ZP);
+			} else {
+				Rectangle r;
+				uchar *s;
+				int w;
+
+				s = pic;
+				r = picr;
+				w = 256*2*scale;
+				while(r.min.y < picr.max.y){
+					loadimage(tmp, tmp->r, s, w);
+					s += w;
+					r.max.y = r.min.y+scale;
+					draw(screen, r, tmp, nil, ZP);
+					r.min.y = r.max.y;
+				}
+			}
+			flushimage(display, 1);
+			break;
+		}
+	}
+}
+
+void
 timing(void)
 {
 	static vlong old;
@@ -242,14 +305,16 @@
 		threadexitsall("usage");
 	}
 	loadrom(argv[0]);
-	if(initdraw(nil, nil, nil) < 0)
+	if(initdraw(nil, nil, argv0) < 0)
 		sysfatal("initdraw: %r");
+	flushc = chancreate(sizeof(ulong), 1);
 	mc = initmouse(nil, screen);
 	if(mc == nil)
 		sysfatal("initmouse: %r");
 	screeninit();
-	loadbat(argv[0]);
 	proccreate(keyproc, 0, 8192);
+	proccreate(screenproc, 0, 8192);
+	loadbat(argv[0]);
 	cpureset();
 	memreset();
 	spcreset();
@@ -314,48 +379,7 @@
 void
 flush(void)
 {
-	extern uchar pic[256*240*2*3];
-	Mouse m;
-	Point p;
-
-	if(nbrecvul(mc->resizec) > 0){
-		if(getwindow(display, Refnone) < 0)
-			sysfatal("resize failed: %r");
-		screeninit();
-	}
-	while(nbrecv(mc->c, &m) > 0)
-		if(mouse && ptinrect(m.xy, picr)){
-			p = subpt(m.xy, picr.min);
-			p.x /= scale;
-			p.y /= scale;
-			keys = keys & 0xff3f0000 | p.x | p.y << 8;
-			if((m.buttons & 1) != 0)
-				keys |= 1<<22;
-			if((m.buttons & 4) != 0)
-				keys |= 1<<23;
-			if((m.buttons & 2) != 0)
-				lastkeys = keys;
-		}
-	if(scale == 1){
-		loadimage(tmp, tmp->r, pic, 256*239*2);
-		draw(screen, picr, tmp, nil, ZP);
-	} else {
-		Rectangle r;
-		uchar *s;
-		int w;
-
-		s = pic;
-		r = picr;
-		w = 256*2*scale;
-		while(r.min.y < picr.max.y){
-			loadimage(tmp, tmp->r, s, w);
-			s += w;
-			r.max.y = r.min.y+scale;
-			draw(screen, r, tmp, nil, ZP);
-			r.min.y = r.max.y;
-		}
-	}
-	flushimage(display, 1);
+	sendul(flushc, 1);	/* flush screen */
 	audioout();
 }