@@ 46,6 46,8 @@ enum{
Edestotl, /* datakit destination out to lunch */
Enetotl, /* datakit controller out to lunch */
Erejected, /* datakit destination rejected call */
- Ebadblt, /* bad bitblt or bitctl request */
+ Ebadblt, /* bad bitblt or bitmap request */
+ Enobitmap, /* out of bitmap descriptors */
+ Enobitstore, /* out of bitmap storage */
Egreg, /* it's all greg's fault */
};
@@ 9,14 9,31 @@
#include "gnot.h"
-extern Bitmap screen;
+/*
+ * Some fields in Bitmaps are overloaded:
+ * ldepth = -1 means free.
+ * base is next pointer when free.
+ * Arena is a word containing N, followed by a pointer to its bitmap,
+ * followed by N blocks. The bitmap pointer is zero if block is free.
+ */
struct{
Ref;
int bltuse;
QLock blt; /* a group of bitblts in a single write is atomic */
+ Bitmap *map; /* arena */
+ Bitmap *free; /* free list */
+ ulong *words; /* storage */
+ ulong nwords; /* total in arena */
+ ulong *wfree; /* pointer to next free word */
+ int lastid; /* last allocated bitmap id */
}bit;
+#define FREE 0x80000000
+void bitcompact(void);
+void bitfree(Bitmap*);
+extern Bitmap screen;
+
enum{
Qdir,
Qbitblt,
@@ 31,6 48,22 @@ Dirtab bitdir[]={
void
bitreset(void)
{
+ int i;
+ Bitmap *bp;
+
+ bit.map = ialloc(conf.nbitmap * sizeof(Bitmap), 0);
+ for(i=0,bp=bit.map; i<conf.nbitmap; i++,bp++){
+ bp->ldepth = -1;
+ bp->base = (ulong*)(bp+1);
+ }
+ bp--;
+ bp->base = 0;
+ bit.map[0] = screen; /* bitmap 0 is screen */
+ bit.free = bit.map+1;
+ bit.lastid = -1;
+ bit.words = ialloc(conf.nbitbyte, 0);
+ bit.nwords = conf.nbitbyte/sizeof(ulong);
+ bit.wfree = bit.words;
}
void
@@ 74,15 107,12 @@ bitopen(Chan *c, int omode)
if(omode != OREAD)
error(0, Eperm);
}else{
- /*
- * Always open #b/bitblt first
- */
lock(&bit);
- if((c->qid==Qbitblt && bit.bltuse)
- || (c->qid!=Qbitblt && !bit.bltuse)){
+ if(bit.bltuse){
unlock(&bit);
error(0, Einuse);
}
+ bit.lastid = -1;
unlock(&bit);
incref(&bit);
}
@@ 113,25 143,60 @@ bitwstat(Chan *c, char *db)
void
bitclose(Chan *c)
{
+ int i;
+ Bitmap *bp;
+
if(c->qid != CHDIR){
- lock(&bit);
- if(--bit.ref == 0)
+ lock(&bit); /* FREE ALL THE BITMAPS: BUG */
+ if(--bit.ref == 0){
+ for(i=1,bp=&bit.map[1]; i<conf.nbitmap; i++,bp++)
+ if(bp->ldepth >= 0)
+ bitfree(bp);
bit.bltuse = 0;
+ }
unlock(&bit);
}
}
+#define GSHORT(p) (((p)[0]<<0) | ((p)[1]<<8))
+#define GLONG(p) ((GSHORT(p)<<0) | (GSHORT(p+2)<<16))
+
long
bitread(Chan *c, void *va, long n)
{
+ uchar *p;
+
if(c->qid & CHDIR)
return devdirread(c, va, n, bitdir, NBIT, devgen);
- error(0, Egreg);
+ if(c->qid != Qbitblt)
+ error(0, Egreg);
+ p = va;
+ qlock(&bit.blt);
+ if(waserror()){
+ qunlock(&bit.blt);
+ nexterror();
+ }
+ /*
+ * Fuss about and figure out what to say.
+ */
+ if(bit.lastid > 0){
+ if(n < 3)
+ error(0, Ebadblt);
+ p[0] = 'A';
+ p[1] = bit.lastid;
+ p[2] = bit.lastid>>8;
+ bit.lastid = -1;
+ n = 3;
+ goto done;
+ }
+ error(0, Ebadblt);
+
+ done:
+ qunlock(&bit.blt);
+ return n;
}
-#define SHORT(p) (((p)[0]<<0) | ((p)[1]<<8))
-#define LONG(p) ((SHORT(p)<<0) | (SHORT(p+2)<<16))
long
bitwrite(Chan *c, void *va, long n)
@@ 139,55 204,133 @@ bitwrite(Chan *c, void *va, long n)
uchar *p;
long m;
long v;
+ ulong l, nw, ws;
Point pt;
Rectangle rect;
- Bitmap *src, *dst;
+ Bitmap *bp, *src, *dst;
if(c->qid == CHDIR)
error(0, Eisdir);
+ if(c->qid != Qbitblt)
+ error(0, Egreg);
+
p = va;
m = n;
- switch(c->qid){
- case Qbitblt:
- qlock(&bit.blt);
- if(waserror()){
- qunlock(&bit.blt);
- nexterror();
- }
- while(m > 0)
- switch(*p){
- case 'b':
- if(m < 31)
- error(0, Ebadblt);
- v = SHORT(p+1);
- if(v != 0) /* BUG */
- error(0, Ebadblt);
- dst = &screen;
- pt.x = LONG(p+3);
- pt.y = LONG(p+7);
- v = SHORT(p+11);
- if(v != 0) /* BUG */
- error(0, Ebadblt);
- src = &screen;
- rect.min.x = LONG(p+13);
- rect.min.y = LONG(p+17);
- rect.max.x = LONG(p+21);
- rect.max.y = LONG(p+25);
- v = SHORT(p+29);
- bitblt(dst, pt, src, rect, v);
- m -= 31;
- p += 31;
- break;
- default:
+ qlock(&bit.blt);
+ if(waserror()){
+ qunlock(&bit.blt);
+ nexterror();
+ }
+ while(m > 0)
+ switch(*p){
+ case 'a':
+ /*
+ * allocate:
+ * 'a' 1
+ * ldepth 1
+ * Rectangle 16
+ * next read returns allocated bitmap id
+ */
+ if(m < 18)
+ error(0, Ebadblt);
+ v = *(p+1);
+ if(v != 0) /* BUG */
error(0, Ebadblt);
+ ws = 1<<(5-v); /* pixels per word */
+ if(bit.free == 0)
+ error(0, Enobitmap);
+ rect.min.x = GLONG(p+2);
+ rect.min.y = GLONG(p+6);
+ rect.max.x = GLONG(p+10);
+ rect.max.y = GLONG(p+14);
+ if(rect.min.x >= 0)
+ l = (rect.max.x+ws-1)/ws - rect.min.x/ws;
+ else{ /* make positive before divide */
+ long t;
+ t = (-rect.min.x)+ws-1;
+ t = (t/ws)*ws;
+ l = (t+rect.max.x+ws-1)/ws;
}
- qunlock(&bit.blt);
- break;
+ nw = l*Dy(rect);
+ if(bit.wfree+l+2 > bit.words+bit.nwords){
+ bitcompact();
+ if(bit.wfree+l+1 > bit.words+bit.nwords)
+ error(0, Enobitstore);
+ }
+ bp = bit.free;
+ bit.free = (Bitmap*)(bp->base);
+ *bit.wfree++ = nw;
+ *bit.wfree++ = (ulong)bp;
+ bp->base = bit.wfree;
+ memset(bp->base, 0, nw*sizeof(ulong));
+ bit.wfree += nw;
+ bp->zero = l*rect.min.y;
+ if(rect.min.x >= 0)
+ bp->zero += rect.min.x/ws;
+ else
+ bp->zero -= (-rect.min.x+ws-1)/ws;
+ bp->zero = -bp->zero;
+ bp->width = l;
+ bp->ldepth = v;
+ bp->rect = rect;
+ bp->cache = 0;
+ bit.lastid = bp-bit.map;
+ m -= 18;
+ p += 18;
+ break;
- default:
- error(0, Egreg);
- }
+ case 'b':
+ /*
+ * bitblt
+ * 'b' 1
+ * dst id 2
+ * dst Point 8
+ * src id 2
+ * src Rectangle 16
+ * code 2
+ */
+ if(m < 31)
+ error(0, Ebadblt);
+ v = GSHORT(p+1);
+ dst = &bit.map[v];
+ if(v<0 || v>=conf.nbitmap || dst->ldepth < 0)
+ error(0, Ebadblt);
+ pt.x = GLONG(p+3);
+ pt.y = GLONG(p+7);
+ v = GSHORT(p+11);
+ src = &bit.map[v];
+ if(v<0 || v>=conf.nbitmap || src->ldepth < 0)
+ error(0, Ebadblt);
+ rect.min.x = GLONG(p+13);
+ rect.min.y = GLONG(p+17);
+ rect.max.x = GLONG(p+21);
+ rect.max.y = GLONG(p+25);
+ v = GSHORT(p+29);
+ bitblt(dst, pt, src, rect, v);
+ m -= 31;
+ p += 31;
+ break;
+
+ case 'f':
+ /*
+ * free
+ * 'f' 1
+ * id 2
+ */
+ if(m < 3)
+ error(0, Ebadblt);
+ v = GSHORT(p+1);
+ dst = &bit.map[v];
+ if(v >= conf.nbitmap || dst->ldepth<0)
+ error(0, Ebadblt);
+ bitfree(dst);
+ m -= 3;
+ p += 3;
+ break;
+ }
+
+ qunlock(&bit.blt);
return n;
}
@@ 202,3 345,35 @@ biterrstr(Error *e, char *buf)
{
rooterrstr(e, buf);
}
+
+void
+bitfree(Bitmap *bp)
+{
+ bp->base[1] = 0;
+ bp->ldepth = -1;
+ bp->base = (ulong*)bit.free;
+ bit.free = bp;
+}
+
+void
+bitcompact(void)
+{
+ ulong *p1, *p2;
+
+print("bitcompact\n");
+ p1 = p2 = bit.words;
+ while(p2 < bit.wfree){
+ if(p2[1] == 0){
+ p2 += 2 + p2[0];
+ continue;
+ }
+ if(p1 != p2){
+ memcpy(p1, p2, (2+p2[0])*sizeof(ulong));
+ ((Bitmap*)p1[1])->base = p1+2;
+ }
+ p2 += 2 + p1[0];
+ p1 += 2 + p1[0];
+ }
+ bit.wfree = p1;
+print("bitcompact done\n");
+}