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