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