jehanne/sys/src/lib/memdraw/alloc.c

212 lines
3.8 KiB
C

/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <pool.h>
void
memimagemove(void *from, void *to)
{
Memdata *md;
md = *(Memdata**)to;
if(md->base != from){
jehanne_print("compacted data not right: #%p\n", md->base);
abort();
}
md->base = to;
/* if allocmemimage changes this must change too */
md->bdata = (uint8_t*)md->base+sizeof(Memdata*)+sizeof(uint32_t);
}
Memimage*
allocmemimaged(Rectangle r, uint32_t chan, Memdata *md)
{
int d;
uint32_t l;
Memimage *i;
if(Dx(r) <= 0 || Dy(r) <= 0){
jehanne_werrstr("bad rectangle %R", r);
return nil;
}
if((d = chantodepth(chan)) == 0) {
jehanne_werrstr("bad channel descriptor %.8lux", chan);
return nil;
}
l = wordsperline(r, d);
i = jehanne_mallocz(sizeof(Memimage), 1);
if(i == nil)
return nil;
i->data = md;
i->zero = sizeof(uint32_t)*l*r.min.y;
if(r.min.x >= 0)
i->zero += (r.min.x*d)/8;
else
i->zero -= (-r.min.x*d+7)/8;
i->zero = -i->zero;
i->width = l;
i->r = r;
i->clipr = r;
i->flags = 0;
i->layer = nil;
i->cmap = memdefcmap;
if(memsetchan(i, chan) < 0){
jehanne_free(i);
return nil;
}
return i;
}
Memimage*
allocmemimage(Rectangle r, uint32_t chan)
{
int d;
uint8_t *p;
uint32_t l, nw;
Memdata *md;
Memimage *i;
if((d = chantodepth(chan)) == 0) {
jehanne_werrstr("bad channel descriptor %.8lux", chan);
return nil;
}
l = wordsperline(r, d);
nw = l*Dy(r);
md = jehanne_malloc(sizeof(Memdata));
if(md == nil)
return nil;
md->ref = 1;
md->base = poolalloc(imagmem,
sizeof(Memdata*)+(1+nw)*sizeof(uint32_t));
if(md->base == nil){
jehanne_free(md);
return nil;
}
p = (uint8_t*)md->base;
*(Memdata**)p = md;
p += sizeof(Memdata*);
*(uint32_t*)p = jehanne_getcallerpc();
p += sizeof(uint32_t);
/* if this changes, memimagemove must change too */
md->bdata = p;
md->allocd = 1;
i = allocmemimaged(r, chan, md);
if(i == nil){
poolfree(imagmem, md->base);
jehanne_free(md);
return nil;
}
md->imref = i;
return i;
}
void
freememimage(Memimage *i)
{
if(i == nil)
return;
if(i->data->ref-- == 1 && i->data->allocd){
if(i->data->base)
poolfree(imagmem, i->data->base);
jehanne_free(i->data);
}
jehanne_free(i);
}
/*
* Wordaddr is deprecated.
*/
uint32_t*
wordaddr(Memimage *i, Point p)
{
return (uint32_t*) ((uintptr_t)byteaddr(i, p) & ~(sizeof(uint32_t)-1));
}
uint8_t*
byteaddr(Memimage *i, Point p)
{
uint8_t *a;
a = i->data->bdata+i->zero+sizeof(uint32_t)*p.y*i->width;
if(i->depth < 8){
/*
* We need to always round down,
* but C rounds toward zero.
*/
int np;
np = 8/i->depth;
if(p.x < 0)
return a+(p.x-np+1)/np;
else
return a+p.x/np;
}
else
return a+p.x*(i->depth/8);
}
int
memsetchan(Memimage *i, uint32_t chan)
{
int d;
int t, j, k;
uint32_t cc;
int bytes;
if((d = chantodepth(chan)) == 0) {
jehanne_werrstr("bad channel descriptor");
return -1;
}
i->depth = d;
i->chan = chan;
i->flags &= ~(Fgrey|Falpha|Fcmap|Fbytes);
bytes = 1;
for(cc=chan, j=0, k=0; cc; j+=NBITS(cc), cc>>=8, k++){
t=TYPE(cc);
if(t < 0 || t >= NChan){
jehanne_werrstr("bad channel string");
return -1;
}
if(t == CGrey)
i->flags |= Fgrey;
if(t == CAlpha)
i->flags |= Falpha;
if(t == CMap && i->cmap == nil){
i->cmap = memdefcmap;
i->flags |= Fcmap;
}
i->shift[t] = j;
i->mask[t] = (1<<NBITS(cc))-1;
i->nbits[t] = NBITS(cc);
if(NBITS(cc) != 8)
bytes = 0;
}
i->nchan = k;
if(bytes)
i->flags |= Fbytes;
return 0;
}