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