reduce software cursor flickering

the software cursor starts flickering and reacts bumby if a process
spends most of its time with drawlock acquired because the timer interrupt
thats supposed to redraw the cursor fails to acquire the lock at the time
the timer fires.

instead of trying to draw the cursor on the screen from a timer interrupt
30 times per second, devmouse now creates a process calling cursoron() and
cursoroff() when the cursor needs to be redrawn. this allows the swcursor
to schedule a redraw while holding the drawlock in swcursoravoid() and
cursoron()/cursoroff() are now able to wait for a qlock (drawlock) because
they get called from process context.

the overall responsiveness is also improved with this change as the cursor
redraw rate isnt limited to 30 times a second anymore.
This commit is contained in:
cinap_lenrek 2013-04-14 16:28:54 +02:00
parent 58e500f4a7
commit 3045d63969
17 changed files with 303 additions and 614 deletions

View file

@ -64,7 +64,6 @@ extern void setpower(int, int);
extern void setr13(int, u32int*); extern void setr13(int, u32int*);
extern int splfhi(void); extern int splfhi(void);
extern int splflo(void); extern int splflo(void);
extern void swcursorinit(void);
extern int tas(void *); extern int tas(void *);
extern void touser(uintptr); extern void touser(uintptr);
extern void trapinit(void); extern void trapinit(void);

View file

@ -249,8 +249,6 @@ main(void)
clockinit(); clockinit();
printinit(); printinit();
timersinit(); timersinit();
if(conf.monitor)
swcursorinit();
cpuidprint(); cpuidprint();
archreset(); archreset();

View file

@ -14,7 +14,7 @@ dev
cap cap
fs fs
ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum inferno ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum inferno
draw screen draw screen swcursor
mouse mouse mouse mouse
uart uart

View file

@ -14,7 +14,7 @@ dev
cap cap
fs fs
ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum inferno ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum inferno
draw screen draw screen swcursor
mouse mouse mouse mouse
uart uart

View file

@ -69,203 +69,32 @@ static void myscreenputs(char *s, int n);
static void screenputc(char *buf); static void screenputc(char *buf);
static void screenwin(void); static void screenwin(void);
/* void
* Software cursor. cursoron(void)
*/
static int swvisible; /* is the cursor visible? */
static int swenabled; /* is the cursor supposed to be on the screen? */
static Memimage *swback; /* screen under cursor */
static Memimage *swimg; /* cursor image */
static Memimage *swmask; /* cursor mask */
static Memimage *swimg1;
static Memimage *swmask1;
static Point swoffset;
static Rectangle swrect; /* screen rectangle in swback */
static Point swpt; /* desired cursor location */
static Point swvispt; /* actual cursor location */
static int swvers; /* incremented each time cursor image changes */
static int swvisvers; /* the version on the screen */
/*
* called with drawlock locked for us, most of the time.
* kernel prints at inopportune times might mean we don't
* hold the lock, but memimagedraw is now reentrant so
* that should be okay: worst case we get cursor droppings.
*/
static void
swcursorhide(void)
{ {
if(swvisible == 0) qlock(&drawlock);
return;
if(swback == nil)
return;
swvisible = 0;
memimagedraw(gscreen, swrect, swback, ZP, memopaque, ZP, S);
flushmemscreen(swrect);
}
static void
swcursoravoid(Rectangle r)
{
if(swvisible && rectXrect(r, swrect))
swcursorhide();
}
static void
swcursordraw(void)
{
int dounlock;
if(swvisible)
return;
if(swenabled == 0)
return;
if(swback == nil || swimg1 == nil || swmask1 == nil)
return;
dounlock = canqlock(&drawlock);
swvispt = swpt;
swvisvers = swvers;
swrect = rectaddpt(Rect(0,0,16,16), swvispt);
memimagedraw(swback, swback->r, gscreen, swpt, memopaque, ZP, S);
memimagedraw(gscreen, swrect, swimg1, ZP, swmask1, ZP, SoverD);
flushmemscreen(swrect);
swvisible = 1;
if(dounlock)
qunlock(&drawlock);
}
int
cursoron(int dolock)
{
int retry;
if (dolock)
lock(&cursor); lock(&cursor);
if (canqlock(&drawlock)) {
retry = 0;
swcursorhide(); swcursorhide();
swcursordraw(); swcursordraw(mousexy());
qunlock(&drawlock);
} else
retry = 1;
if (dolock)
unlock(&cursor); unlock(&cursor);
return retry; qunlock(&drawlock);
} }
void void
cursoroff(int dolock) cursoroff(void)
{ {
if (dolock) qlock(&drawlock);
lock(&cursor); lock(&cursor);
swcursorhide(); swcursorhide();
if (dolock)
unlock(&cursor); unlock(&cursor);
} qunlock(&drawlock);
static void
swload(Cursor *curs)
{
uchar *ip, *mp;
int i, j, set, clr;
if(!swimg || !swmask || !swimg1 || !swmask1)
return;
/*
* Build cursor image and mask.
* Image is just the usual cursor image
* but mask is a transparent alpha mask.
*
* The 16x16x8 memimages do not have
* padding at the end of their scan lines.
*/
ip = byteaddr(swimg, ZP);
mp = byteaddr(swmask, ZP);
for(i=0; i<32; i++){
set = curs->set[i];
clr = curs->clr[i];
for(j=0x80; j; j>>=1){
*ip++ = set&j ? 0x00 : 0xFF;
*mp++ = (clr|set)&j ? 0xFF : 0x00;
}
}
swoffset = curs->offset;
swvers++;
memimagedraw(swimg1, swimg1->r, swimg, ZP, memopaque, ZP, S);
memimagedraw(swmask1, swmask1->r, swmask, ZP, memopaque, ZP, S);
} }
/* called from devmouse */ /* called from devmouse */
void void
setcursor(Cursor* curs) setcursor(Cursor* curs)
{ {
cursoroff(0); swcursorload(curs);
swload(curs);
cursoron(0);
}
static int
swmove(Point p)
{
swpt = addpt(p, swoffset);
return 0;
}
static void
swcursorclock(void)
{
int x;
if(!swenabled)
return;
swmove(mousexy());
if(swvisible && eqpt(swpt, swvispt) && swvers==swvisvers)
return;
x = splhi();
if(swenabled)
if(!swvisible || !eqpt(swpt, swvispt) || swvers!=swvisvers)
if(canqlock(&drawlock)){
swcursorhide();
swcursordraw();
qunlock(&drawlock);
}
splx(x);
}
void
swcursorinit(void)
{
static int init;
if(!init){
init = 1;
addclock0link(swcursorclock, 10);
swenabled = 1;
}
if(swback){
freememimage(swback);
freememimage(swmask);
freememimage(swmask1);
freememimage(swimg);
freememimage(swimg1);
}
swback = allocmemimage(Rect(0,0,32,32), gscreen->chan);
swmask = allocmemimage(Rect(0,0,16,16), GREY8);
swmask1 = allocmemimage(Rect(0,0,16,16), GREY1);
swimg = allocmemimage(Rect(0,0,16,16), GREY8);
swimg1 = allocmemimage(Rect(0,0,16,16), GREY1);
if(swback==nil || swmask==nil || swmask1==nil || swimg==nil || swimg1 == nil){
print("software cursor: allocmemimage fails\n");
return;
}
memfillcolor(swmask, DOpaque);
memfillcolor(swmask1, DOpaque);
memfillcolor(swimg, DBlack);
memfillcolor(swimg1, DBlack);
} }
int int
@ -348,6 +177,7 @@ screeninit(void)
memdefont = getmemdefont(); memdefont = getmemdefont();
screenwin(); screenwin();
screenputs = myscreenputs; screenputs = myscreenputs;
swcursorinit();
} }
void void

View file

@ -21,16 +21,24 @@ extern Cursor arrow;
/* mouse.c */ /* mouse.c */
extern void mousectl(Cmdbuf*); extern void mousectl(Cmdbuf*);
extern void mouseresize(void); extern void mouseresize(void);
extern void mouseredraw(void);
/* screen.c */ /* screen.c */
extern void blankscreen(int); extern void blankscreen(int);
extern void flushmemscreen(Rectangle); extern void flushmemscreen(Rectangle);
extern uchar* attachscreen(Rectangle*, ulong*, int*, int*, int*); extern uchar* attachscreen(Rectangle*, ulong*, int*, int*, int*);
extern int cursoron(int); extern void cursoron(void);
extern void cursoroff(int); extern void cursoroff(void);
extern void setcursor(Cursor*); extern void setcursor(Cursor*);
/* devdraw.c */ /* devdraw.c */
extern QLock drawlock; extern QLock drawlock;
#define ishwimage(i) 1 /* for ../port/devdraw.c */ #define ishwimage(i) 1 /* for ../port/devdraw.c */
/* swcursor.c */
void swcursorhide(void);
void swcursoravoid(Rectangle);
void swcursordraw(Point);
void swcursorload(Cursor *);
void swcursorinit(void);

View file

@ -24,7 +24,7 @@ dev
ether netif ether netif
ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum inferno ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum inferno
draw screen draw screen swcursor
dss dss
mouse mouse

View file

@ -346,174 +346,33 @@ screenpower(int on)
blankscreen(on == 0); blankscreen(on == 0);
} }
/*
* called with drawlock locked for us, most of the time.
* kernel prints at inopportune times might mean we don't
* hold the lock, but memimagedraw is now reentrant so
* that should be okay: worst case we get cursor droppings.
*/
void void
swcursorhide(void) cursoron(void)
{ {
if(swvisible == 0) qlock(&drawlock);
return; lock(&cursor);
if(swback == nil)
return;
swvisible = 0;
memimagedraw(gscreen, swrect, swback, ZP, memopaque, ZP, S);
flushmemscreen(swrect);
}
void
swcursoravoid(Rectangle r)
{
if(swvisible && rectXrect(r, swrect))
swcursorhide(); swcursorhide();
swcursordraw(mousexy());
unlock(&cursor);
qunlock(&drawlock);
} }
void void
swcursordraw(void) cursoroff(void)
{ {
if(swvisible) qlock(&drawlock);
return; lock(&cursor);
if(swenabled == 0)
return;
if(swback == nil || swimg1 == nil || swmask1 == nil)
return;
// assert(!canqlock(&drawlock)); // assertion fails on omap
swvispt = swpt;
swvisvers = swvers;
swrect = rectaddpt(Rect(0,0,16,16), swvispt);
memimagedraw(swback, swback->r, gscreen, swpt, memopaque, ZP, S);
memimagedraw(gscreen, swrect, swimg1, ZP, swmask1, ZP, SoverD);
flushmemscreen(swrect);
swvisible = 1;
}
int
cursoron(int dolock)
{
if (dolock)
lock(&oscreen);
cursoroff(0);
swcursordraw();
if (dolock)
unlock(&oscreen);
return 0;
}
void
cursoroff(int dolock)
{
if (dolock)
lock(&oscreen);
swcursorhide(); swcursorhide();
if (dolock) unlock(&cursor);
unlock(&oscreen); qunlock(&drawlock);
}
void
swload(Cursor *curs)
{
uchar *ip, *mp;
int i, j, set, clr;
if(!swimg || !swmask || !swimg1 || !swmask1)
return;
/*
* Build cursor image and mask.
* Image is just the usual cursor image
* but mask is a transparent alpha mask.
*
* The 16x16x8 memimages do not have
* padding at the end of their scan lines.
*/
ip = byteaddr(swimg, ZP);
mp = byteaddr(swmask, ZP);
for(i=0; i<32; i++){
set = curs->set[i];
clr = curs->clr[i];
for(j=0x80; j; j>>=1){
*ip++ = set&j ? 0x00 : 0xFF;
*mp++ = (clr|set)&j ? 0xFF : 0x00;
}
}
swoffset = curs->offset;
swvers++;
memimagedraw(swimg1, swimg1->r, swimg, ZP, memopaque, ZP, S);
memimagedraw(swmask1, swmask1->r, swmask, ZP, memopaque, ZP, S);
} }
/* called from devmouse */ /* called from devmouse */
void void
setcursor(Cursor* curs) setcursor(Cursor* curs)
{ {
cursoroff(1);
oscreen.Cursor = *curs; oscreen.Cursor = *curs;
swload(curs); swcursorload(curs);
cursoron(1);
}
int
swmove(Point p)
{
swpt = addpt(p, swoffset);
return 0;
}
void
swcursorclock(void)
{
int x;
if(!swenabled)
return;
swmove(mousexy());
if(swvisible && eqpt(swpt, swvispt) && swvers==swvisvers)
return;
x = splhi();
if(swenabled)
if(!swvisible || !eqpt(swpt, swvispt) || swvers!=swvisvers)
if(canqlock(&drawlock)){
swcursorhide();
swcursordraw();
qunlock(&drawlock);
}
splx(x);
}
void
swcursorinit(void)
{
static int init;
if(!init){
init = 1;
addclock0link(swcursorclock, 10);
}
if(swback){
freememimage(swback);
freememimage(swmask);
freememimage(swmask1);
freememimage(swimg);
freememimage(swimg1);
}
swback = allocmemimage(Rect(0,0,32,32), gscreen->chan);
swmask = allocmemimage(Rect(0,0,16,16), GREY8);
swmask1 = allocmemimage(Rect(0,0,16,16), GREY1);
swimg = allocmemimage(Rect(0,0,16,16), GREY8);
swimg1 = allocmemimage(Rect(0,0,16,16), GREY1);
if(swback==nil || swmask==nil || swmask1==nil || swimg==nil || swimg1 == nil){
print("software cursor: allocmemimage fails\n");
return;
}
memfillcolor(swmask, DOpaque);
memfillcolor(swmask1, DOpaque);
memfillcolor(swimg, DBlack);
memfillcolor(swimg1, DBlack);
} }
/* called from main and possibly later from devdss to change resolution */ /* called from main and possibly later from devdss to change resolution */

View file

@ -20,12 +20,13 @@ extern Point mousexy(void);
extern void mouseaccelerate(int); extern void mouseaccelerate(int);
extern void mouseresize(void); extern void mouseresize(void);
extern void mouseredraw(void);
/* screen.c */ /* screen.c */
extern uchar* attachscreen(Rectangle*, ulong*, int*, int*, int*); extern uchar* attachscreen(Rectangle*, ulong*, int*, int*, int*);
extern void flushmemscreen(Rectangle); extern void flushmemscreen(Rectangle);
extern int cursoron(int); extern void cursoron(void);
extern void cursoroff(int); extern void cursoroff(void);
extern void setcursor(Cursor*); extern void setcursor(Cursor*);
extern int screensize(int, int, int, ulong); extern int screensize(int, int, int, ulong);
extern int screenaperture(int, int); extern int screenaperture(int, int);
@ -49,6 +50,13 @@ extern QLock drawlock;
#define ishwimage(i) 0 /* for ../port/devdraw.c */ #define ishwimage(i) 0 /* for ../port/devdraw.c */
/* swcursor.c */
void swcursorhide(void);
void swcursoravoid(Rectangle);
void swcursordraw(Point);
void swcursorload(Cursor *);
void swcursorinit(void);
/* for communication between devdss.c and screen.c */ /* for communication between devdss.c and screen.c */
enum { enum {
@ -93,7 +101,6 @@ struct Settings {
}; };
struct OScreen { struct OScreen {
Lock;
Cursor; Cursor;
Settings *settings; Settings *settings;
int open; int open;

View file

@ -349,7 +349,7 @@ vgactl(Cmdbuf *cb)
if(chantodepth(chan) != z) if(chantodepth(chan) != z)
error("depth, channel do not match"); error("depth, channel do not match");
cursoroff(1); cursoroff();
deletescreenimage(); deletescreenimage();
if(screensize(x, y, z, chan)) if(screensize(x, y, z, chan))
error(Egreg); error(Egreg);
@ -397,7 +397,7 @@ vgactl(Cmdbuf *cb)
y = scr->gscreen->r.max.y; y = scr->gscreen->r.max.y;
z = scr->gscreen->depth; z = scr->gscreen->depth;
chan = scr->gscreen->chan; chan = scr->gscreen->chan;
cursoroff(1); cursoroff();
deletescreenimage(); deletescreenimage();
if(screensize(x, y, z, chan)) if(screensize(x, y, z, chan))
error(Egreg); error(Egreg);
@ -411,7 +411,7 @@ vgactl(Cmdbuf *cb)
hwaccel = !scr->softscreen && (scr->scroll || scr->fill); hwaccel = !scr->softscreen && (scr->scroll || scr->fill);
vgascreenwin(scr); vgascreenwin(scr);
resetscreenimage(); resetscreenimage();
cursoron(1); cursoron();
return; return;
case CMlinear: case CMlinear:

View file

@ -23,7 +23,7 @@ dev
ether netif ether netif
ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum386 inferno ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum386 inferno
draw screen vga vgax draw screen vga vgax swcursor
mouse mouse mouse mouse
kbd kbd
vga vga

View file

@ -21,7 +21,7 @@ dev
ether netif ether netif
ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum386 inferno ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium ptclbsum386 inferno
draw screen vga vgax draw screen vga vgax swcursor
mouse mouse mouse mouse
kbd kbd
vga vga

View file

@ -37,8 +37,6 @@ Cursor arrow = {
}, },
}; };
int didswcursorinit;
int int
screensize(int x, int y, int, ulong chan) screensize(int x, int y, int, ulong chan)
{ {
@ -101,7 +99,6 @@ screensize(int x, int y, int, ulong chan)
poperror(); poperror();
drawcmap(); drawcmap();
if(didswcursorinit)
swcursorinit(); swcursorinit();
qunlock(&drawlock); qunlock(&drawlock);
@ -327,27 +324,63 @@ setcolor(ulong p, ulong r, ulong g, ulong b)
return setpalette(p, r, g, b); return setpalette(p, r, g, b);
} }
int void
cursoron(int dolock) swenable(VGAscr*)
{ {
VGAscr *scr; swcursorload(&arrow);
int v;
scr = &vgascreen[0];
if(scr->cur == nil || scr->cur->move == nil)
return 0;
if(dolock)
lock(&cursor);
v = scr->cur->move(scr, mousexy());
if(dolock)
unlock(&cursor);
return v;
} }
void void
cursoroff(int) swdisable(VGAscr*)
{
}
void
swload(VGAscr*, Cursor *curs)
{
swcursorload(curs);
}
int
swmove(VGAscr*, Point p)
{
swcursorhide();
swcursordraw(p);
return 0;
}
VGAcur swcursor =
{
"soft",
swenable,
swdisable,
swload,
swmove,
};
void
cursoron(void)
{
VGAscr *scr;
VGAcur *cur;
scr = &vgascreen[0];
cur = scr->cur;
if(cur == nil || cur->move == nil)
return;
if(cur == &swcursor)
qlock(&drawlock);
lock(&cursor);
cur->move(scr, mousexy());
unlock(&cursor);
if(cur == &swcursor)
qunlock(&drawlock);
}
void
cursoroff(void)
{ {
} }
@ -532,196 +565,3 @@ vgalinearaddr(VGAscr *scr, ulong paddr, int size)
poperror(); poperror();
} }
} }
/*
* Software cursor.
*/
int swvisible; /* is the cursor visible? */
int swenabled; /* is the cursor supposed to be on the screen? */
Memimage* swback; /* screen under cursor */
Memimage* swimg; /* cursor image */
Memimage* swmask; /* cursor mask */
Memimage* swimg1;
Memimage* swmask1;
Point swoffset;
Rectangle swrect; /* screen rectangle in swback */
Point swpt; /* desired cursor location */
Point swvispt; /* actual cursor location */
int swvers; /* incremented each time cursor image changes */
int swvisvers; /* the version on the screen */
/*
* called with drawlock locked for us, most of the time.
* kernel prints at inopportune times might mean we don't
* hold the lock, but memimagedraw is now reentrant so
* that should be okay: worst case we get cursor droppings.
*/
void
swcursorhide(void)
{
if(swvisible == 0)
return;
if(swback == nil)
return;
swvisible = 0;
memimagedraw(gscreen, swrect, swback, ZP, memopaque, ZP, S);
flushmemscreen(swrect);
}
void
swcursoravoid(Rectangle r)
{
if(swvisible && rectXrect(r, swrect))
swcursorhide();
}
void
swcursordraw(void)
{
if(swvisible)
return;
if(swenabled == 0)
return;
if(swback == nil || swimg1 == nil || swmask1 == nil)
return;
assert(!canqlock(&drawlock));
swvispt = swpt;
swvisvers = swvers;
swrect = rectaddpt(Rect(0,0,16,16), swvispt);
memimagedraw(swback, swback->r, gscreen, swpt, memopaque, ZP, S);
memimagedraw(gscreen, swrect, swimg1, ZP, swmask1, ZP, SoverD);
flushmemscreen(swrect);
swvisible = 1;
}
void
swload(VGAscr*, Cursor *curs)
{
uchar *ip, *mp;
int i, j, set, clr;
if(!swimg || !swmask || !swimg1 || !swmask1)
return;
/*
* Build cursor image and mask.
* Image is just the usual cursor image
* but mask is a transparent alpha mask.
*
* The 16x16x8 memimages do not have
* padding at the end of their scan lines.
*/
ip = byteaddr(swimg, ZP);
mp = byteaddr(swmask, ZP);
for(i=0; i<32; i++){
set = curs->set[i];
clr = curs->clr[i];
for(j=0x80; j; j>>=1){
*ip++ = set&j ? 0x00 : 0xFF;
*mp++ = (clr|set)&j ? 0xFF : 0x00;
}
}
swoffset = curs->offset;
swvers++;
memimagedraw(swimg1, swimg1->r, swimg, ZP, memopaque, ZP, S);
memimagedraw(swmask1, swmask1->r, swmask, ZP, memopaque, ZP, S);
}
int
swmove(VGAscr*, Point p)
{
swpt = addpt(p, swoffset);
return 0;
}
void
swcursorclock(void)
{
int x;
if(!swenabled)
return;
if(swvisible && eqpt(swpt, swvispt) && swvers==swvisvers)
return;
x = splhi();
if(swenabled)
if(!swvisible || !eqpt(swpt, swvispt) || swvers!=swvisvers)
if(canqlock(&drawlock)){
swcursorhide();
swcursordraw();
qunlock(&drawlock);
}
splx(x);
}
void
swcursorinit(void)
{
static int init;
VGAscr *scr;
didswcursorinit = 1;
if(!init){
init = 1;
addclock0link(swcursorclock, 10);
}
scr = &vgascreen[0];
if(scr->gscreen==nil)
return;
if(swback){
freememimage(swback);
freememimage(swmask);
freememimage(swmask1);
freememimage(swimg);
freememimage(swimg1);
}
swback = allocmemimage(Rect(0,0,32,32), gscreen->chan);
swmask = allocmemimage(Rect(0,0,16,16), GREY8);
swmask1 = allocmemimage(Rect(0,0,16,16), GREY1);
swimg = allocmemimage(Rect(0,0,16,16), GREY8);
swimg1 = allocmemimage(Rect(0,0,16,16), GREY1);
if(swback==nil || swmask==nil || swmask1==nil || swimg==nil || swimg1 == nil)
print("software cursor: allocmemimage fails");
memfillcolor(swback, DTransparent);
memfillcolor(swmask, DOpaque);
memfillcolor(swmask1, DOpaque);
memfillcolor(swimg, DBlack);
memfillcolor(swimg1, DBlack);
}
/*
* Need to lock drawlock for ourselves.
*/
void
swenable(VGAscr *scr)
{
swenabled = 1;
if(canqlock(&drawlock)){
swload(scr, &arrow);
swcursordraw();
qunlock(&drawlock);
}
}
void
swdisable(VGAscr*)
{
swenabled = 0;
if(canqlock(&drawlock)){
swcursorhide();
qunlock(&drawlock);
}
}
VGAcur swcursor =
{
"soft",
swenable,
swdisable,
swload,
swmove,
};

View file

@ -132,6 +132,7 @@ enum {
/* mouse.c */ /* mouse.c */
extern void mousectl(Cmdbuf*); extern void mousectl(Cmdbuf*);
extern void mouseresize(void); extern void mouseresize(void);
extern void mouseredraw(void);
/* screen.c */ /* screen.c */
extern int hwaccel; /* use hw acceleration; default on */ extern int hwaccel; /* use hw acceleration; default on */
@ -140,8 +141,8 @@ extern int panning; /* use virtual screen panning; default off */
extern void addvgaseg(char*, ulong, ulong); extern void addvgaseg(char*, ulong, ulong);
extern uchar* attachscreen(Rectangle*, ulong*, int*, int*, int*); extern uchar* attachscreen(Rectangle*, ulong*, int*, int*, int*);
extern void flushmemscreen(Rectangle); extern void flushmemscreen(Rectangle);
extern int cursoron(int); extern void cursoron(void);
extern void cursoroff(int); extern void cursoroff(void);
extern void setcursor(Cursor*); extern void setcursor(Cursor*);
extern int screensize(int, int, int, ulong); extern int screensize(int, int, int, ulong);
extern int screenaperture(int, int); extern int screenaperture(int, int);
@ -176,3 +177,10 @@ extern void vgablank(VGAscr*, int);
extern Lock vgascreenlock; extern Lock vgascreenlock;
#define ishwimage(i) (vgascreen[0].gscreendata && (i)->data->bdata == vgascreen[0].gscreendata->bdata) #define ishwimage(i) (vgascreen[0].gscreendata && (i)->data->bdata == vgascreen[0].gscreendata->bdata)
/* swcursor.c */
void swcursorhide(void);
void swcursoravoid(Rectangle);
void swcursordraw(Point);
void swcursorload(Cursor *);
void swcursorinit(void);

View file

@ -33,16 +33,13 @@ struct Mouseinfo
{ {
Lock; Lock;
Mousestate; Mousestate;
int dx;
int dy;
int track; /* dx & dy updated */
int redraw; /* update cursor on screen */ int redraw; /* update cursor on screen */
Rendez redrawr; /* wait for cursor screen updates */
ulong lastcounter; /* value when /dev/mouse read */ ulong lastcounter; /* value when /dev/mouse read */
ulong lastresize; ulong lastresize;
ulong resize; ulong resize;
Rendez r; Rendez r;
Ref; Ref;
QLock;
int open; int open;
int acceleration; int acceleration;
int maxacc; int maxacc;
@ -77,8 +74,7 @@ Cursor curs;
void Cursortocursor(Cursor*); void Cursortocursor(Cursor*);
int mousechanged(void*); int mousechanged(void*);
void mouseredraw(void);
static void mouseclock(void);
enum{ enum{
Qdir, Qdir,
@ -114,8 +110,6 @@ mousereset(void)
curs = arrow; curs = arrow;
Cursortocursor(&arrow); Cursortocursor(&arrow);
/* redraw cursor about 30 times per second */
addclock0link(mouseclock, 33);
} }
static int static int
@ -129,6 +123,8 @@ mousedevgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp)
return rc; return rc;
} }
static void mouseproc(void*);
static void static void
mouseinit(void) mouseinit(void)
{ {
@ -137,8 +133,10 @@ mouseinit(void)
curs = arrow; curs = arrow;
Cursortocursor(&arrow); Cursortocursor(&arrow);
cursoron(1); cursoron();
mousetime = seconds(); mousetime = seconds();
kproc("mouse", mouseproc, 0);
} }
static Chan* static Chan*
@ -222,13 +220,15 @@ mouseclose(Chan *c)
unlock(&mouse); unlock(&mouse);
return; return;
} }
if(--mouse.ref == 0){ if(--mouse.ref != 0){
cursoroff(1); unlock(&mouse);
curs = arrow; return;
Cursortocursor(&arrow);
cursoron(1);
} }
unlock(&mouse); unlock(&mouse);
cursoroff();
curs = arrow;
Cursortocursor(&arrow);
cursoron();
} }
} }
@ -373,7 +373,7 @@ mousewrite(Chan *c, void *va, long n, vlong)
error(Eisdir); error(Eisdir);
case Qcursor: case Qcursor:
cursoroff(1); cursoroff();
if(n < 2*4+2*2*16){ if(n < 2*4+2*2*16){
curs = arrow; curs = arrow;
Cursortocursor(&arrow); Cursortocursor(&arrow);
@ -385,11 +385,7 @@ mousewrite(Chan *c, void *va, long n, vlong)
memmove(curs.set, p+40, 2*16); memmove(curs.set, p+40, 2*16);
Cursortocursor(&curs); Cursortocursor(&curs);
} }
qlock(&mouse); cursoron();
mouse.redraw = 1;
mouseclock();
qunlock(&mouse);
cursoron(1);
return n; return n;
case Qmousectl: case Qmousectl:
@ -466,14 +462,10 @@ mousewrite(Chan *c, void *va, long n, vlong)
if(p == 0) if(p == 0)
error(Eshort); error(Eshort);
pt.y = strtoul(p, 0, 0); pt.y = strtoul(p, 0, 0);
qlock(&mouse); if(gscreen != nil && ptinrect(pt, gscreen->r)){
if(ptinrect(pt, gscreen->r)){
mouse.xy = pt; mouse.xy = pt;
mouse.redraw = 1; mousetrack(0, 0, mouse.buttons, TK2MS(MACHP(0)->ticks));
mouse.track = 1;
mouseclock();
} }
qunlock(&mouse);
return n; return n;
} }
@ -505,32 +497,40 @@ Dev mousedevtab = {
void void
Cursortocursor(Cursor *c) Cursortocursor(Cursor *c)
{ {
qlock(&drawlock);
lock(&cursor); lock(&cursor);
memmove(&cursor.Cursor, c, sizeof(Cursor)); memmove(&cursor.Cursor, c, sizeof(Cursor));
setcursor(c); setcursor(c);
unlock(&cursor); unlock(&cursor);
qunlock(&drawlock);
} }
static int
shouldredraw(void*)
{
return mouse.redraw != 0;
}
/* /*
* called by the clock routine to redraw the cursor * process that redraws the cursor
*/ */
static void static void
mouseclock(void) mouseproc(void*)
{ {
if(mouse.track){ while(waserror())
mousetrack(mouse.dx, mouse.dy, mouse.buttons, TK2MS(MACHP(0)->ticks)); ;
mouse.track = 0; for(;;){
mouse.dx = 0; if(mouse.redraw){
mouse.dy = 0;
}
if(mouse.redraw && canlock(&cursor)){
mouse.redraw = 0; mouse.redraw = 0;
cursoroff(0); cursoroff();
mouse.redraw = cursoron(0); cursoron();
unlock(&cursor); drawactive(1);
} } else {
drawactive(0); drawactive(0);
}
tsleep(&mouse.redrawr, shouldredraw, 0, 20*1000);
}
} }
static int static int
@ -595,7 +595,6 @@ absmousetrack(int x, int y, int b, int msec)
lastb = mouse.buttons; lastb = mouse.buttons;
mouse.xy = Pt(x, y); mouse.xy = Pt(x, y);
mouse.buttons = b; mouse.buttons = b;
mouse.redraw = 1;
mouse.counter++; mouse.counter++;
mouse.msec = msec; mouse.msec = msec;
@ -611,7 +610,8 @@ absmousetrack(int x, int y, int b, int msec)
mouse.qfull = 1; mouse.qfull = 1;
} }
wakeup(&mouse.r); wakeup(&mouse.r);
drawactive(1);
mouseredraw();
} }
/* /*
@ -782,3 +782,9 @@ mouseresize(void)
wakeup(&mouse.r); wakeup(&mouse.r);
} }
void
mouseredraw(void)
{
mouse.redraw = 1;
wakeup(&mouse.redrawr);
}

View file

@ -81,6 +81,7 @@ devuart.$O: ../port/netif.h
devmouse.$O: screen.h /sys/include/memdraw.h devmouse.$O: screen.h /sys/include/memdraw.h
devdraw.$O: screen.h /sys/include/memdraw.h devdraw.$O: screen.h /sys/include/memdraw.h
screen.$O: screen.h /sys/include/memdraw.h screen.$O: screen.h /sys/include/memdraw.h
swcursor.$O: screen.h /sys/include/memdraw.h
thwack.$O: ../port/thwack.h thwack.$O: ../port/thwack.h
unthwack.$O: ../port/thwack.h unthwack.$O: ../port/thwack.h
devsdp.$O: ../port/thwack.h devsdp.$O: ../port/thwack.h

133
sys/src/9/port/swcursor.c Normal file
View file

@ -0,0 +1,133 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
#define Image IMAGE
#include <draw.h>
#include <memdraw.h>
#include <cursor.h>
#include "screen.h"
extern Memimage* gscreen;
/*
* Software cursor.
*/
static Memimage* swback; /* screen under cursor */
static Memimage* swimg; /* cursor image */
static Memimage* swmask; /* cursor mask */
static Memimage* swimg1;
static Memimage* swmask1;
static Point swoffset;
static Rectangle swrect; /* screen rectangle in swback */
static Point swvispt; /* actual cursor location */
static int swvisible; /* is the cursor visible? */
/*
* called with drawlock locked for us, most of the time.
* kernel prints at inopportune times might mean we don't
* hold the lock, but memimagedraw is now reentrant so
* that should be okay: worst case we get cursor droppings.
*/
void
swcursorhide(void)
{
if(swvisible == 0)
return;
if(swback == nil || gscreen == nil)
return;
swvisible = 0;
memimagedraw(gscreen, swrect, swback, ZP, memopaque, ZP, S);
flushmemscreen(swrect);
}
void
swcursoravoid(Rectangle r)
{
if(swvisible && rectXrect(r, swrect)){
swcursorhide();
mouseredraw(); /* schedule cursor redraw after we release drawlock */
}
}
void
swcursordraw(Point p)
{
if(swvisible)
return;
if(swback == nil || swimg1 == nil || swmask1 == nil || gscreen == nil)
return;
assert(!canqlock(&drawlock));
swvispt = addpt(swoffset, p);
swrect = rectaddpt(Rect(0,0,16,16), swvispt);
memimagedraw(swback, swback->r, gscreen, swvispt, memopaque, ZP, S);
memimagedraw(gscreen, swrect, swimg1, ZP, swmask1, ZP, SoverD);
flushmemscreen(swrect);
swvisible = 1;
}
void
swcursorload(Cursor *curs)
{
uchar *ip, *mp;
int i, j, set, clr;
if(swimg == nil || swmask == nil || swimg1 == nil || swmask1 == nil)
return;
/*
* Build cursor image and mask.
* Image is just the usual cursor image
* but mask is a transparent alpha mask.
*
* The 16x16x8 memimages do not have
* padding at the end of their scan lines.
*/
ip = byteaddr(swimg, ZP);
mp = byteaddr(swmask, ZP);
for(i=0; i<32; i++){
set = curs->set[i];
clr = curs->clr[i];
for(j=0x80; j; j>>=1){
*ip++ = set&j ? 0x00 : 0xFF;
*mp++ = (clr|set)&j ? 0xFF : 0x00;
}
}
swoffset = curs->offset;
memimagedraw(swimg1, swimg1->r, swimg, ZP, memopaque, ZP, S);
memimagedraw(swmask1, swmask1->r, swmask, ZP, memopaque, ZP, S);
mouseredraw();
}
void
swcursorinit(void)
{
if(gscreen == nil)
return;
if(swback){
freememimage(swback);
freememimage(swmask);
freememimage(swmask1);
freememimage(swimg);
freememimage(swimg1);
}
swback = allocmemimage(Rect(0,0,32,32), gscreen->chan);
swmask = allocmemimage(Rect(0,0,16,16), GREY8);
swmask1 = allocmemimage(Rect(0,0,16,16), GREY1);
swimg = allocmemimage(Rect(0,0,16,16), GREY8);
swimg1 = allocmemimage(Rect(0,0,16,16), GREY1);
if(swback == nil || swmask == nil || swmask1 == nil || swimg == nil || swimg1 == nil){
print("software cursor: allocmemimage fails\n");
return;
}
memfillcolor(swback, DTransparent);
memfillcolor(swmask, DOpaque);
memfillcolor(swmask1, DOpaque);
memfillcolor(swimg, DBlack);
memfillcolor(swimg1, DBlack);
}