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.
This commit is contained in:
parent
844612fcb8
commit
763231588c
1 changed files with 68 additions and 44 deletions
|
@ -13,6 +13,7 @@ int nprg, nsram, hirom, battery;
|
||||||
|
|
||||||
int ppuclock, spcclock, dspclock, stimerclock, saveclock, msgclock, paused, perfclock, cpupause;
|
int ppuclock, spcclock, dspclock, stimerclock, saveclock, msgclock, paused, perfclock, cpupause;
|
||||||
Mousectl *mc;
|
Mousectl *mc;
|
||||||
|
Channel *flushc;
|
||||||
QLock pauselock;
|
QLock pauselock;
|
||||||
u32int keys;
|
u32int keys;
|
||||||
int savefd, scale, profile, mouse, loadreq, savereq;
|
int savefd, scale, profile, mouse, loadreq, savereq;
|
||||||
|
@ -184,6 +185,68 @@ screeninit(void)
|
||||||
draw(screen, screen->r, bg, nil, ZP);
|
draw(screen, screen->r, bg, nil, ZP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
void
|
||||||
timing(void)
|
timing(void)
|
||||||
{
|
{
|
||||||
|
@ -242,14 +305,16 @@ usage:
|
||||||
threadexitsall("usage");
|
threadexitsall("usage");
|
||||||
}
|
}
|
||||||
loadrom(argv[0]);
|
loadrom(argv[0]);
|
||||||
if(initdraw(nil, nil, nil) < 0)
|
if(initdraw(nil, nil, argv0) < 0)
|
||||||
sysfatal("initdraw: %r");
|
sysfatal("initdraw: %r");
|
||||||
|
flushc = chancreate(sizeof(ulong), 1);
|
||||||
mc = initmouse(nil, screen);
|
mc = initmouse(nil, screen);
|
||||||
if(mc == nil)
|
if(mc == nil)
|
||||||
sysfatal("initmouse: %r");
|
sysfatal("initmouse: %r");
|
||||||
screeninit();
|
screeninit();
|
||||||
loadbat(argv[0]);
|
|
||||||
proccreate(keyproc, 0, 8192);
|
proccreate(keyproc, 0, 8192);
|
||||||
|
proccreate(screenproc, 0, 8192);
|
||||||
|
loadbat(argv[0]);
|
||||||
cpureset();
|
cpureset();
|
||||||
memreset();
|
memreset();
|
||||||
spcreset();
|
spcreset();
|
||||||
|
@ -314,48 +379,7 @@ usage:
|
||||||
void
|
void
|
||||||
flush(void)
|
flush(void)
|
||||||
{
|
{
|
||||||
extern uchar pic[256*240*2*3];
|
sendul(flushc, 1); /* flush screen */
|
||||||
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);
|
|
||||||
audioout();
|
audioout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue