xref: /plan9/sys/src/libmemdraw/alloc.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
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 		free(md);
99 		return nil;
100 	}
101 	md->imref = i;
102 	return i;
103 }
104 
105 void
106 freememimage(Memimage *i)
107 {
108 	if(i == nil)
109 		return;
110 	if(i->data->ref-- == 1 && i->data->allocd){
111 		if(i->data->base)
112 			poolfree(imagmem, i->data->base);
113 		free(i->data);
114 	}
115 	free(i);
116 }
117 
118 /*
119  * Wordaddr is deprecated.
120  */
121 ulong*
122 wordaddr(Memimage *i, Point p)
123 {
124 	return (ulong*) ((ulong)byteaddr(i, p) & ~(sizeof(ulong)-1));
125 }
126 
127 uchar*
128 byteaddr(Memimage *i, Point p)
129 {
130 	uchar *a;
131 
132 	a = i->data->bdata+i->zero+sizeof(ulong)*p.y*i->width;
133 
134 	if(i->depth < 8){
135 		/*
136 		 * We need to always round down,
137 		 * but C rounds toward zero.
138 		 */
139 		int np;
140 		np = 8/i->depth;
141 		if(p.x < 0)
142 			return a+(p.x-np+1)/np;
143 		else
144 			return a+p.x/np;
145 	}
146 	else
147 		return a+p.x*(i->depth/8);
148 }
149 
150 int
151 memsetchan(Memimage *i, ulong chan)
152 {
153 	int d;
154 	int t, j, k;
155 	ulong cc;
156 	int bytes;
157 
158 	if((d = chantodepth(chan)) == 0) {
159 		werrstr("bad channel descriptor");
160 		return -1;
161 	}
162 
163 	i->depth = d;
164 	i->chan = chan;
165 	i->flags &= ~(Fgrey|Falpha|Fcmap|Fbytes);
166 	bytes = 1;
167 	for(cc=chan, j=0, k=0; cc; j+=NBITS(cc), cc>>=8, k++){
168 		t=TYPE(cc);
169 		if(t < 0 || t >= NChan){
170 			werrstr("bad channel string");
171 			return -1;
172 		}
173 		if(t == CGrey)
174 			i->flags |= Fgrey;
175 		if(t == CAlpha)
176 			i->flags |= Falpha;
177 		if(t == CMap && i->cmap == nil){
178 			i->cmap = memdefcmap;
179 			i->flags |= Fcmap;
180 		}
181 
182 		i->shift[t] = j;
183 		i->mask[t] = (1<<NBITS(cc))-1;
184 		i->nbits[t] = NBITS(cc);
185 		if(NBITS(cc) != 8)
186 			bytes = 0;
187 	}
188 	i->nchan = k;
189 	if(bytes)
190 		i->flags |= Fbytes;
191 	return 0;
192 }
193