xref: /plan9/sys/src/libmemdraw/alloc.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
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