1 #define __NR_PIXBLOCK_C__
3 /** \file
4 * \brief Allocation/Setup of NRPixBlock objects. Pixel store functions.
5 *
6 * Authors:
7 * (C) 1999-2002 Lauris Kaplinski <lauris@kaplinski.com>
8 *
9 * This code is in the Public Domain
10 */
12 #include "nr-pixblock.h"
14 /// Size of buffer that needs no allocation (default 4).
15 #define NR_TINY_MAX sizeof (unsigned char *)
17 /**
18 * Pixbuf initialisation using homegrown memory handling ("pixelstore").
19 *
20 * Pixbuf sizes are differentiated into tiny, <4K, <16K, <64K, and more,
21 * with each type having its own method of memory handling. After allocating
22 * memory, the buffer is cleared if the clear flag is set. Intended to
23 * reduce memory fragmentation.
24 * \param pb Pointer to the pixbuf struct.
25 * \param mode Indicates grayscale/RGB/RGBA.
26 * \param clear True if buffer should be cleared.
27 * \pre x1>=x0 && y1>=y0 && pb!=NULL
28 */
29 void
30 nr_pixblock_setup_fast (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear)
31 {
32 int w, h, bpp;
33 size_t size;
35 w = x1 - x0;
36 h = y1 - y0;
37 bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
39 size = bpp * w * h;
41 if (size <= NR_TINY_MAX) {
42 pb->size = NR_PIXBLOCK_SIZE_TINY;
43 if (clear) memset (pb->data.p, 0x0, size);
44 } else if (size <= 4096) {
45 pb->size = NR_PIXBLOCK_SIZE_4K;
46 pb->data.px = nr_pixelstore_4K_new (clear, 0x0);
47 } else if (size <= 16384) {
48 pb->size = NR_PIXBLOCK_SIZE_16K;
49 pb->data.px = nr_pixelstore_16K_new (clear, 0x0);
50 } else if (size <= 65536) {
51 pb->size = NR_PIXBLOCK_SIZE_64K;
52 pb->data.px = nr_pixelstore_64K_new (clear, 0x0);
53 } else if (size <= 262144) {
54 pb->size = NR_PIXBLOCK_SIZE_256K;
55 pb->data.px = nr_pixelstore_256K_new (clear, 0x0);
56 } else if (size <= 1048576) {
57 pb->size = NR_PIXBLOCK_SIZE_1M;
58 pb->data.px = nr_pixelstore_1M_new (clear, 0x0);
59 } else {
60 pb->size = NR_PIXBLOCK_SIZE_BIG;
61 pb->data.px = nr_new (unsigned char, size);
62 if (clear) memset (pb->data.px, 0x0, size);
63 }
65 pb->mode = mode;
66 pb->empty = 1;
67 pb->area.x0 = x0;
68 pb->area.y0 = y0;
69 pb->area.x1 = x1;
70 pb->area.y1 = y1;
71 pb->rs = bpp * w;
72 }
74 /**
75 * Pixbuf initialisation using nr_new.
76 *
77 * After allocating memory, the buffer is cleared if the clear flag is set.
78 * \param pb Pointer to the pixbuf struct.
79 * \param mode Indicates grayscale/RGB/RGBA.
80 * \param clear True if buffer should be cleared.
81 * \pre x1>=x0 && y1>=y0 && pb!=NULL
82 */
83 void
84 nr_pixblock_setup (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear)
85 {
86 int w, h, bpp;
87 size_t size;
89 w = x1 - x0;
90 h = y1 - y0;
91 bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
93 size = bpp * w * h;
95 if (size <= NR_TINY_MAX) {
96 pb->size = NR_PIXBLOCK_SIZE_TINY;
97 if (clear) memset (pb->data.p, 0x0, size);
98 } else {
99 pb->size = NR_PIXBLOCK_SIZE_BIG;
100 pb->data.px = nr_new (unsigned char, size);
101 if (clear) memset (pb->data.px, 0x0, size);
102 }
104 pb->mode = mode;
105 pb->empty = 1;
106 pb->area.x0 = x0;
107 pb->area.y0 = y0;
108 pb->area.x1 = x1;
109 pb->area.y1 = y1;
110 pb->rs = bpp * w;
111 }
113 /**
114 * Pixbuf initialisation with preset values.
115 *
116 * After copying all parameters into the NRPixBlock struct, the pixel buffer is cleared if the clear flag is set.
117 * \param pb Pointer to the pixbuf struct.
118 * \param mode Indicates grayscale/RGB/RGBA.
119 * \param clear True if buffer should be cleared.
120 * \pre x1>=x0 && y1>=y0 && pb!=NULL
121 */
122 void
123 nr_pixblock_setup_extern (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, unsigned char *px, int rs, bool empty, bool clear)
124 {
125 int w, bpp;
127 w = x1 - x0;
128 bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
130 pb->size = NR_PIXBLOCK_SIZE_STATIC;
131 pb->mode = mode;
132 pb->empty = empty;
133 pb->area.x0 = x0;
134 pb->area.y0 = y0;
135 pb->area.x1 = x1;
136 pb->area.y1 = y1;
137 pb->data.px = px;
138 pb->rs = rs;
140 g_assert (pb->data.px != NULL);
141 if (clear) {
142 if (rs == bpp * w) {
143 /// \todo How do you recognise if
144 /// px was an uncleared tiny buffer?
145 if (pb->data.px)
146 memset (pb->data.px, 0x0, bpp * (y1 - y0) * w);
147 } else {
148 int y;
149 for (y = y0; y < y1; y++) {
150 memset (pb->data.px + (y - y0) * rs, 0x0, bpp * w);
151 }
152 }
153 }
154 }
156 /**
157 * Frees memory taken by pixel data in NRPixBlock.
158 * \param pb Pointer to pixblock.
159 * \pre pb and pb->data.px point to valid addresses.
160 *
161 * According to pb->size, one of the functions for freeing the pixelstore
162 * is called. May be called regardless of how pixbuf was set up.
163 */
164 void
165 nr_pixblock_release (NRPixBlock *pb)
166 {
167 switch (pb->size) {
168 case NR_PIXBLOCK_SIZE_TINY:
169 break;
170 case NR_PIXBLOCK_SIZE_4K:
171 nr_pixelstore_4K_free (pb->data.px);
172 break;
173 case NR_PIXBLOCK_SIZE_16K:
174 nr_pixelstore_16K_free (pb->data.px);
175 break;
176 case NR_PIXBLOCK_SIZE_64K:
177 nr_pixelstore_64K_free (pb->data.px);
178 break;
179 case NR_PIXBLOCK_SIZE_256K:
180 nr_pixelstore_256K_free (pb->data.px);
181 break;
182 case NR_PIXBLOCK_SIZE_1M:
183 nr_pixelstore_1M_free (pb->data.px);
184 break;
185 case NR_PIXBLOCK_SIZE_BIG:
186 nr_free (pb->data.px);
187 break;
188 case NR_PIXBLOCK_SIZE_STATIC:
189 break;
190 default:
191 break;
192 }
193 }
195 /**
196 * Allocates NRPixBlock and sets it up.
197 *
198 * \return Pointer to fresh pixblock.
199 * Calls nr_new() and nr_pixblock_setup().
200 */
201 NRPixBlock *
202 nr_pixblock_new (NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear)
203 {
204 NRPixBlock *pb;
206 pb = nr_new (NRPixBlock, 1);
208 nr_pixblock_setup (pb, mode, x0, y0, x1, y1, clear);
210 return pb;
211 }
213 /**
214 * Frees all memory taken by pixblock.
215 *
216 * \return NULL
217 */
218 NRPixBlock *
219 nr_pixblock_free (NRPixBlock *pb)
220 {
221 nr_pixblock_release (pb);
223 nr_free (pb);
225 return NULL;
226 }
228 /* PixelStore operations */
230 #define NR_4K_BLOCK 32
231 static unsigned char **nr_4K_px = NULL;
232 static unsigned int nr_4K_len = 0;
233 static unsigned int nr_4K_size = 0;
235 unsigned char *
236 nr_pixelstore_4K_new (bool clear, unsigned char val)
237 {
238 unsigned char *px;
240 if (nr_4K_len != 0) {
241 nr_4K_len -= 1;
242 px = nr_4K_px[nr_4K_len];
243 } else {
244 px = nr_new (unsigned char, 4096);
245 }
247 if (clear) memset (px, val, 4096);
249 return px;
250 }
252 void
253 nr_pixelstore_4K_free (unsigned char *px)
254 {
255 if (nr_4K_len == nr_4K_size) {
256 nr_4K_size += NR_4K_BLOCK;
257 nr_4K_px = nr_renew (nr_4K_px, unsigned char *, nr_4K_size);
258 }
260 nr_4K_px[nr_4K_len] = px;
261 nr_4K_len += 1;
262 }
264 #define NR_16K_BLOCK 32
265 static unsigned char **nr_16K_px = NULL;
266 static unsigned int nr_16K_len = 0;
267 static unsigned int nr_16K_size = 0;
269 unsigned char *
270 nr_pixelstore_16K_new (bool clear, unsigned char val)
271 {
272 unsigned char *px;
274 if (nr_16K_len != 0) {
275 nr_16K_len -= 1;
276 px = nr_16K_px[nr_16K_len];
277 } else {
278 px = nr_new (unsigned char, 16384);
279 }
281 if (clear) memset (px, val, 16384);
283 return px;
284 }
286 void
287 nr_pixelstore_16K_free (unsigned char *px)
288 {
289 if (nr_16K_len == nr_16K_size) {
290 nr_16K_size += NR_16K_BLOCK;
291 nr_16K_px = nr_renew (nr_16K_px, unsigned char *, nr_16K_size);
292 }
294 nr_16K_px[nr_16K_len] = px;
295 nr_16K_len += 1;
296 }
298 #define NR_64K_BLOCK 32
299 static unsigned char **nr_64K_px = NULL;
300 static unsigned int nr_64K_len = 0;
301 static unsigned int nr_64K_size = 0;
303 unsigned char *
304 nr_pixelstore_64K_new (bool clear, unsigned char val)
305 {
306 unsigned char *px;
308 if (nr_64K_len != 0) {
309 nr_64K_len -= 1;
310 px = nr_64K_px[nr_64K_len];
311 } else {
312 px = nr_new (unsigned char, 65536);
313 }
315 if (clear) memset (px, val, 65536);
317 return px;
318 }
320 void
321 nr_pixelstore_64K_free (unsigned char *px)
322 {
323 if (nr_64K_len == nr_64K_size) {
324 nr_64K_size += NR_64K_BLOCK;
325 nr_64K_px = nr_renew (nr_64K_px, unsigned char *, nr_64K_size);
326 }
328 nr_64K_px[nr_64K_len] = px;
329 nr_64K_len += 1;
330 }
332 #define NR_256K_BLOCK 32
333 #define NR_256K 262144
334 static unsigned char **nr_256K_px = NULL;
335 static unsigned int nr_256K_len = 0;
336 static unsigned int nr_256K_size = 0;
338 unsigned char *
339 nr_pixelstore_256K_new (bool clear, unsigned char val)
340 {
341 unsigned char *px;
343 if (nr_256K_len != 0) {
344 nr_256K_len -= 1;
345 px = nr_256K_px[nr_256K_len];
346 } else {
347 px = nr_new (unsigned char, NR_256K);
348 }
350 if (clear) memset (px, val, NR_256K);
352 return px;
353 }
355 void
356 nr_pixelstore_256K_free (unsigned char *px)
357 {
358 if (nr_256K_len == nr_256K_size) {
359 nr_256K_size += NR_256K_BLOCK;
360 nr_256K_px = nr_renew (nr_256K_px, unsigned char *, nr_256K_size);
361 }
363 nr_256K_px[nr_256K_len] = px;
364 nr_256K_len += 1;
365 }
367 #define NR_1M_BLOCK 32
368 #define NR_1M 1048576
369 static unsigned char **nr_1M_px = NULL;
370 static unsigned int nr_1M_len = 0;
371 static unsigned int nr_1M_size = 0;
373 unsigned char *
374 nr_pixelstore_1M_new (bool clear, unsigned char val)
375 {
376 unsigned char *px;
378 if (nr_1M_len != 0) {
379 nr_1M_len -= 1;
380 px = nr_1M_px[nr_1M_len];
381 } else {
382 px = nr_new (unsigned char, NR_1M);
383 }
385 if (clear) memset (px, val, NR_1M);
387 return px;
388 }
390 void
391 nr_pixelstore_1M_free (unsigned char *px)
392 {
393 if (nr_1M_len == nr_1M_size) {
394 nr_1M_size += NR_1M_BLOCK;
395 nr_1M_px = nr_renew (nr_1M_px, unsigned char *, nr_1M_size);
396 }
398 nr_1M_px[nr_1M_len] = px;
399 nr_1M_len += 1;
400 }
402 /*
403 Local Variables:
404 mode:c++
405 c-file-style:"stroustrup"
406 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
407 indent-tabs-mode:nil
408 fill-column:99
409 End:
410 */
411 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :