diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2015-06-09 09:17:55 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2015-06-09 09:17:55 +0200 |
commit | 90b4fe9cf65bb24b55472ce2e32a7dbc3c5e7f97 (patch) | |
tree | a7c02e9355ee981d4d68796402501ec8dcc45e54 /sys/src/9/zynq/screen.c | |
parent | cda46731d8166e5b113a8acdf90479a03bb6a3a8 (diff) |
zynq: add /dev/fbctl to attach framebuffer to devdraw
Diffstat (limited to 'sys/src/9/zynq/screen.c')
-rw-r--r-- | sys/src/9/zynq/screen.c | 231 |
1 files changed, 192 insertions, 39 deletions
diff --git a/sys/src/9/zynq/screen.c b/sys/src/9/zynq/screen.c index e4a6ab948..0b1affce2 100644 --- a/sys/src/9/zynq/screen.c +++ b/sys/src/9/zynq/screen.c @@ -13,22 +13,15 @@ #include "screen.h" Memimage *gscreen; -static Memdata xgdata; -static Memimage xgscreen = -{ - { 0, 0, 800, 600 }, /* r */ - { 0, 0, 800, 600 }, /* clipr */ - 24, /* depth */ - 3, /* nchan */ - BGR24, /* chan */ - nil, /* cmap */ - &xgdata, /* data */ - 0, /* zero */ - 0, /* width in words of a single scan line */ - 0, /* layer */ - 0, /* flags */ -}; +static struct { + Rendez; + + Rectangle rect; + Proc *proc; + + uintptr addr; +} fbscreen; void cursoron(void) @@ -46,46 +39,32 @@ setcursor(Cursor*) } void -flushmemscreen(Rectangle) +flushmemscreen(Rectangle r) { -} - -void -drawflushreal(void) -{ - uchar *fb, *fbe; - - fb = xgdata.bdata; - fbe = fb + Dx(xgscreen.r) * Dy(xgscreen.r) * 3; - cleandse(fb, fbe); - clean2pa(PADDR(fb), PADDR(fbe)); + combinerect(&fbscreen.rect, r); + wakeup(&fbscreen); } void screeninit(void) { - uchar *fb; - - fb = xspanalloc(Dx(xgscreen.r) * Dy(xgscreen.r) * 3, 64, 0); - print("%p\n", PADDR(fb)); - memsetchan(&xgscreen, BGR24); conf.monitor = 1; - xgdata.bdata = fb; - xgdata.ref = 1; - gscreen = &xgscreen; - gscreen->width = wordsperline(gscreen->r, gscreen->depth); - - memimageinit(); } uchar* attachscreen(Rectangle *r, ulong *chan, int* d, int *width, int *softscreen) { + if(gscreen == nil) + return nil; + *r = gscreen->r; *d = gscreen->depth; *chan = gscreen->chan; *width = gscreen->width; - *softscreen = 0; + + /* make devdraw use gscreen->data */ + *softscreen = 0xa110c; + gscreen->data->ref++; return gscreen->data->bdata; } @@ -110,3 +89,177 @@ void mousectl(Cmdbuf *) { } + +static int +isflush(void *) +{ + return !badrect(fbscreen.rect); +} + +static void +flushproc(void *arg) +{ + int sno, n, w; + uchar *sp, *dp, *top; + Rectangle r; + + for(sno = 0; sno < NSEG; sno++) + if(up->seg[sno] == nil && sno != ESEG) + break; + if(sno == NSEG) + panic("flushproc"); + + up->seg[sno] = arg; + + cclose(up->dot); + up->dot = up->slash; + incref(up->dot); + + fbscreen.proc = up; + if(waserror()){ + print("flushproc: %s\n", up->errstr); + fbscreen.addr = 0; + fbscreen.proc = nil; + return; + } + + for(;;){ + sleep(&fbscreen, isflush, nil); + + eqlock(&drawlock); + r = fbscreen.rect; + fbscreen.rect = ZR; + if(badrect(r) || gscreen == nil || rectclip(&r, gscreen->r) == 0){ + qunlock(&drawlock); + continue; + } + w = sizeof(ulong)*gscreen->width; + n = bytesperline(r, gscreen->depth); + sp = byteaddr(gscreen, r.min); + dp = (uchar*)fbscreen.addr + (sp - &gscreen->data->bdata[gscreen->zero]); + top = (uchar*)up->seg[sno]->top; + if(dp+(Dy(r)-1)*w+n > top) + r.max.y = (top-(uchar*)fbscreen.addr)/w; + qunlock(&drawlock); + + while(r.min.y < r.max.y) { + memmove(dp, sp, n); + sp += w; + dp += w; + r.min.y++; + } + } +} + +enum { + CMaddr, + CMsize, + CMinit, +}; + +static Cmdtab fbctlmsg[] = { + CMaddr, "addr", 2, + CMsize, "size", 3, + CMinit, "init", 1, +}; + +long +fbctlwrite(Chan*, void *a, long n, vlong) +{ + Cmdbuf *cb; + Cmdtab *ct; + ulong x, y, z, chan; + Segment *s; + uintptr addr; + char *p; + + cb = parsecmd(a, n); + if(waserror()){ + free(cb); + nexterror(); + } + ct = lookupcmd(cb, fbctlmsg, nelem(fbctlmsg)); + switch(ct->index){ + case CMaddr: + addr = strtoul(cb->f[1], 0, 0); + + eqlock(&up->seglock); + if((s = seg(up, addr, 0)) == nil || (s->type&SG_RONLY) != 0){ + qunlock(&up->seglock); + error(Ebadarg); + } + incref(s); + qunlock(&up->seglock); + + if(fbscreen.proc != nil){ + postnote(fbscreen.proc, 0, "die", NUser); + while(fbscreen.proc != nil) + sched(); + } + fbscreen.addr = addr; + kproc("fbflush", flushproc, s); + break; + + case CMsize: + x = strtoul(cb->f[1], &p, 0); + if(x == 0 || x > 10240) + error(Ebadarg); + if(*p) + p++; + y = strtoul(p, &p, 0); + if(y == 0 || y > 10240) + error(Ebadarg); + if(*p) + p++; + z = strtoul(p, &p, 0); + + if((chan = strtochan(cb->f[2])) == 0) + error("bad channel"); + if(chantodepth(chan) != z) + error("depth, channel do not match"); + + cursoroff(); + deletescreenimage(); + eqlock(&drawlock); + if(memimageinit() < 0){ + qunlock(&drawlock); + error("memimageinit failed"); + } + if(gscreen != nil){ + freememimage(gscreen); + gscreen = nil; + } + gscreen = allocmemimage(Rect(0,0,x,y), chan); + qunlock(&drawlock); + /* wet floor */ + + case CMinit: + if(gscreen == nil) + error("no framebuffer"); + resetscreenimage(); + cursoron(); + break; + } + free(cb); + poperror(); + return n; +} + +long +fbctlread(Chan*, void *a, long n, vlong offset) +{ + char buf[256], chan[32], *p, *e; + + p = buf; + e = p + sizeof(buf); + qlock(&drawlock); + if(gscreen != nil){ + p = seprint(p, e, "size %dx%dx%d %s\n", + Dx(gscreen->r), Dy(gscreen->r), gscreen->depth, + chantostr(chan, gscreen->chan)); + } + qunlock(&drawlock); + seprint(p, e, "addr %#p\n", fbscreen.addr); + return readstr(offset, a, n, buf); +} + |