1 #include <u.h> 2 #include <libc.h> 3 #include <draw.h> 4 #include <memdraw.h> 5 6 #define poolalloc(a, b) malloc(b) 7 #define poolfree(a, b) free(b) 8 9 void 10 memimagemove(void *from, void *to) 11 { 12 Memdata *md; 13 14 md = *(Memdata**)to; 15 if(md->base != from){ 16 print("compacted data not right: #%p\n", md->base); 17 abort(); 18 } 19 md->base = to; 20 21 /* if allocmemimage changes this must change too */ 22 md->bdata = (uchar*)&md->base[2]; 23 } 24 25 Memimage* 26 allocmemimaged(Rectangle r, ulong chan, Memdata *md, void *X) 27 { 28 int d; 29 ulong l; 30 Memimage *i; 31 32 if(Dx(r) <= 0 || Dy(r) <= 0){ 33 werrstr("bad rectangle %R", r); 34 return nil; 35 } 36 if((d = chantodepth(chan)) == 0) { 37 werrstr("bad channel descriptor %.8lux", chan); 38 return nil; 39 } 40 41 l = wordsperline(r, d); 42 43 i = mallocz(sizeof(Memimage), 1); 44 if(i == nil) 45 return nil; 46 47 i->X = X; 48 i->data = md; 49 i->zero = sizeof(ulong)*l*r.min.y; 50 51 if(r.min.x >= 0) 52 i->zero += (r.min.x*d)/8; 53 else 54 i->zero -= (-r.min.x*d+7)/8; 55 i->zero = -i->zero; 56 i->width = l; 57 i->r = r; 58 i->clipr = r; 59 i->flags = 0; 60 i->layer = nil; 61 i->cmap = memdefcmap; 62 if(memsetchan(i, chan) < 0){ 63 free(i); 64 return nil; 65 } 66 return i; 67 } 68 69 Memimage* 70 _allocmemimage(Rectangle r, ulong chan) 71 { 72 int d; 73 ulong l, nw; 74 Memdata *md; 75 Memimage *i; 76 77 if((d = chantodepth(chan)) == 0) { 78 werrstr("bad channel descriptor %.8lux", chan); 79 return nil; 80 } 81 82 l = wordsperline(r, d); 83 nw = l*Dy(r); 84 md = malloc(sizeof(Memdata)); 85 if(md == nil) 86 return nil; 87 88 md->ref = 1; 89 md->base = poolalloc(imagmem, (2+nw)*sizeof(ulong)); 90 if(md->base == nil){ 91 free(md); 92 return nil; 93 } 94 95 md->base[0] = (ulong)md; 96 md->base[1] = getcallerpc(&r); 97 98 /* if this changes, memimagemove must change too */ 99 md->bdata = (uchar*)&md->base[2]; 100 101 md->allocd = 1; 102 103 i = allocmemimaged(r, chan, md, nil); 104 if(i == nil){ 105 poolfree(imagmem, md->base); 106 free(md); 107 return nil; 108 } 109 md->imref = i; 110 return i; 111 } 112 113 void 114 _freememimage(Memimage *i) 115 { 116 if(i == nil) 117 return; 118 if(i->data->ref-- == 1 && i->data->allocd){ 119 if(i->data->base) 120 poolfree(imagmem, i->data->base); 121 free(i->data); 122 } 123 free(i); 124 } 125 126 /* 127 * Wordaddr is deprecated. 128 */ 129 ulong* 130 wordaddr(Memimage *i, Point p) 131 { 132 return (ulong*) ((ulong)byteaddr(i, p) & ~(sizeof(ulong)-1)); 133 } 134 135 uchar* 136 byteaddr(Memimage *i, Point p) 137 { 138 uchar *a; 139 140 a = i->data->bdata+i->zero+sizeof(ulong)*p.y*i->width; 141 142 if(i->depth < 8){ 143 /* 144 * We need to always round down, 145 * but C rounds toward zero. 146 */ 147 int np; 148 np = 8/i->depth; 149 if(p.x < 0) 150 return a+(p.x-np+1)/np; 151 else 152 return a+p.x/np; 153 } 154 else 155 return a+p.x*(i->depth/8); 156 } 157 158 int 159 memsetchan(Memimage *i, ulong chan) 160 { 161 int d; 162 int t, j, k; 163 ulong cc; 164 int bytes; 165 166 if((d = chantodepth(chan)) == 0) { 167 werrstr("bad channel descriptor"); 168 return -1; 169 } 170 171 i->depth = d; 172 i->chan = chan; 173 i->flags &= ~(Fgrey|Falpha|Fcmap|Fbytes); 174 bytes = 1; 175 for(cc=chan, j=0, k=0; cc; j+=NBITS(cc), cc>>=8, k++){ 176 t=TYPE(cc); 177 if(t < 0 || t >= NChan){ 178 werrstr("bad channel string"); 179 return -1; 180 } 181 if(t == CGrey) 182 i->flags |= Fgrey; 183 if(t == CAlpha) 184 i->flags |= Falpha; 185 if(t == CMap && i->cmap == nil){ 186 i->cmap = memdefcmap; 187 i->flags |= Fcmap; 188 } 189 190 i->shift[t] = j; 191 i->mask[t] = (1<<NBITS(cc))-1; 192 i->nbits[t] = NBITS(cc); 193 if(NBITS(cc) != 8) 194 bytes = 0; 195 } 196 i->nchan = k; 197 if(bytes) 198 i->flags |= Fbytes; 199 return 0; 200 } 201