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 * 2008, Jasper van de Gronde <th.v.d.gonde@hccnet.nl>
9 *
10 * This code is in the Public Domain
11 */
13 #include <cstring>
14 #include <string>
15 #include <string.h>
16 #include <glib/gmem.h>
17 #include "nr-pixblock.h"
19 /// Size of buffer that needs no allocation (default 4).
20 #define NR_TINY_MAX sizeof (unsigned char *)
22 /**
23 * Pixbuf initialisation using homegrown memory handling ("pixelstore").
24 *
25 * Pixbuf sizes are differentiated into tiny, <4K, <16K, <64K, and more,
26 * with each type having its own method of memory handling. After allocating
27 * memory, the buffer is cleared if the clear flag is set. Intended to
28 * reduce memory fragmentation.
29 * \param pb Pointer to the pixbuf struct.
30 * \param mode Indicates grayscale/RGB/RGBA.
31 * \param clear True if buffer should be cleared.
32 * \pre x1>=x0 && y1>=y0 && pb!=NULL
33 */
34 void
35 nr_pixblock_setup_fast (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear)
36 {
37 int w, h, bpp;
38 size_t size;
40 w = x1 - x0;
41 h = y1 - y0;
42 bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
44 size = bpp * w * h;
46 if (size <= NR_TINY_MAX) {
47 pb->size = NR_PIXBLOCK_SIZE_TINY;
48 if (clear) memset (pb->data.p, 0x0, size);
49 } else if (size <= 4096) {
50 pb->size = NR_PIXBLOCK_SIZE_4K;
51 pb->data.px = nr_pixelstore_4K_new (clear, 0x0);
52 } else if (size <= 16384) {
53 pb->size = NR_PIXBLOCK_SIZE_16K;
54 pb->data.px = nr_pixelstore_16K_new (clear, 0x0);
55 } else if (size <= 65536) {
56 pb->size = NR_PIXBLOCK_SIZE_64K;
57 pb->data.px = nr_pixelstore_64K_new (clear, 0x0);
58 } else if (size <= 262144) {
59 pb->size = NR_PIXBLOCK_SIZE_256K;
60 pb->data.px = nr_pixelstore_256K_new (clear, 0x0);
61 } else if (size <= 1048576) {
62 pb->size = NR_PIXBLOCK_SIZE_1M;
63 pb->data.px = nr_pixelstore_1M_new (clear, 0x0);
64 } else {
65 pb->size = NR_PIXBLOCK_SIZE_BIG;
66 pb->data.px = NULL;
67 if (size > 100000000) { // Don't even try to allocate more than 100Mb (5000x5000 RGBA
68 // pixels). It'll just bog the system down even if successful. FIXME:
69 // Can anyone suggest something better than the magic number?
70 g_warning ("%lu bytes requested for pixel buffer, I won't try to allocate that.", (long unsigned) size);
71 return;
72 }
73 pb->data.px = g_try_new (unsigned char, size);
74 if (pb->data.px == NULL) { // memory allocation failed
75 g_warning ("Could not allocate %lu bytes for pixel buffer!", (long unsigned) size);
76 return;
77 }
78 if (clear) memset (pb->data.px, 0x0, size);
79 }
81 pb->mode = mode;
82 pb->empty = 1;
83 pb->visible_area.x0 = pb->area.x0 = x0;
84 pb->visible_area.y0 = pb->area.y0 = y0;
85 pb->visible_area.x1 = pb->area.x1 = x1;
86 pb->visible_area.y1 = pb->area.y1 = y1;
87 pb->rs = bpp * w;
88 }
90 /**
91 * Pixbuf initialisation using g_new.
92 *
93 * After allocating memory, the buffer is cleared if the clear flag is set.
94 * \param pb Pointer to the pixbuf struct.
95 * \param mode Indicates grayscale/RGB/RGBA.
96 * \param clear True if buffer should be cleared.
97 * \pre x1>=x0 && y1>=y0 && pb!=NULL
98 FIXME: currently unused except for nr_pixblock_new and pattern tiles, replace with _fast and delete?
99 */
100 void
101 nr_pixblock_setup (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear)
102 {
103 int w, h, bpp;
104 size_t size;
106 w = x1 - x0;
107 h = y1 - y0;
108 bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
110 size = bpp * w * h;
112 if (size <= NR_TINY_MAX) {
113 pb->size = NR_PIXBLOCK_SIZE_TINY;
114 if (clear) memset (pb->data.p, 0x0, size);
115 } else {
116 pb->size = NR_PIXBLOCK_SIZE_BIG;
117 pb->data.px = g_new (unsigned char, size);
118 if (clear) memset (pb->data.px, 0x0, size);
119 }
121 pb->mode = mode;
122 pb->empty = 1;
123 pb->visible_area.x0 = pb->area.x0 = x0;
124 pb->visible_area.y0 = pb->area.y0 = y0;
125 pb->visible_area.x1 = pb->area.x1 = x1;
126 pb->visible_area.y1 = pb->area.y1 = y1;
127 pb->rs = bpp * w;
128 }
130 /**
131 * Pixbuf initialisation with preset values.
132 *
133 * After copying all parameters into the NRPixBlock struct, the pixel buffer is cleared if the clear flag is set.
134 * \param pb Pointer to the pixbuf struct.
135 * \param mode Indicates grayscale/RGB/RGBA.
136 * \param clear True if buffer should be cleared.
137 * \pre x1>=x0 && y1>=y0 && pb!=NULL
138 */
139 void
140 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)
141 {
142 int w, bpp;
144 w = x1 - x0;
145 bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
147 pb->size = NR_PIXBLOCK_SIZE_STATIC;
148 pb->mode = mode;
149 pb->empty = empty;
150 pb->visible_area.x0 = pb->area.x0 = x0;
151 pb->visible_area.y0 = pb->area.y0 = y0;
152 pb->visible_area.x1 = pb->area.x1 = x1;
153 pb->visible_area.y1 = pb->area.y1 = y1;
154 pb->data.px = px;
155 pb->rs = rs;
157 g_assert (pb->data.px != NULL);
158 if (clear) {
159 if (rs == bpp * w) {
160 /// \todo How do you recognise if
161 /// px was an uncleared tiny buffer?
162 if (pb->data.px)
163 memset (pb->data.px, 0x0, bpp * (y1 - y0) * w);
164 } else {
165 int y;
166 for (y = y0; y < y1; y++) {
167 memset (pb->data.px + (y - y0) * rs, 0x0, bpp * w);
168 }
169 }
170 }
171 }
173 /**
174 * Frees memory taken by pixel data in NRPixBlock.
175 * \param pb Pointer to pixblock.
176 * \pre pb and pb->data.px point to valid addresses.
177 *
178 * According to pb->size, one of the functions for freeing the pixelstore
179 * is called. May be called regardless of how pixbuf was set up.
180 */
181 void
182 nr_pixblock_release (NRPixBlock *pb)
183 {
184 switch (pb->size) {
185 case NR_PIXBLOCK_SIZE_TINY:
186 break;
187 case NR_PIXBLOCK_SIZE_4K:
188 nr_pixelstore_4K_free (pb->data.px);
189 break;
190 case NR_PIXBLOCK_SIZE_16K:
191 nr_pixelstore_16K_free (pb->data.px);
192 break;
193 case NR_PIXBLOCK_SIZE_64K:
194 nr_pixelstore_64K_free (pb->data.px);
195 break;
196 case NR_PIXBLOCK_SIZE_256K:
197 nr_pixelstore_256K_free (pb->data.px);
198 break;
199 case NR_PIXBLOCK_SIZE_1M:
200 nr_pixelstore_1M_free (pb->data.px);
201 break;
202 case NR_PIXBLOCK_SIZE_BIG:
203 g_free (pb->data.px);
204 break;
205 case NR_PIXBLOCK_SIZE_STATIC:
206 break;
207 default:
208 break;
209 }
210 }
212 /**
213 * Allocates NRPixBlock and sets it up.
214 *
215 * \return Pointer to fresh pixblock.
216 * Calls g_new() and nr_pixblock_setup().
217 FIXME: currently unused, delete? JG: Should be used more often! (To simplify memory management.)
218 */
219 NRPixBlock *
220 nr_pixblock_new (NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear)
221 {
222 NRPixBlock *pb;
224 pb = g_new (NRPixBlock, 1);
225 if (!pb) return 0;
227 nr_pixblock_setup (pb, mode, x0, y0, x1, y1, clear);
228 if (pb->size!=NR_PIXBLOCK_SIZE_TINY && !pb->data.px) {
229 g_free(pb);
230 return 0;
231 }
233 return pb;
234 }
236 /**
237 * Allocates NRPixBlock and sets it up.
238 *
239 * \return Pointer to fresh pixblock.
240 * Calls g_new() and nr_pixblock_setup().
241 */
242 NRPixBlock *
243 nr_pixblock_new_fast (NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear)
244 {
245 NRPixBlock *pb;
247 pb = g_new (NRPixBlock, 1);
248 if (!pb) return 0;
250 nr_pixblock_setup_fast (pb, mode, x0, y0, x1, y1, clear);
251 if (pb->size!=NR_PIXBLOCK_SIZE_TINY && !pb->data.px) {
252 g_free(pb);
253 return 0;
254 }
256 return pb;
257 }
259 /**
260 * Frees all memory taken by pixblock.
261 *
262 * \return NULL
263 */
264 NRPixBlock *
265 nr_pixblock_free (NRPixBlock *pb)
266 {
267 nr_pixblock_release (pb);
269 g_free (pb);
271 return NULL;
272 }
274 /* PixelStore operations */
276 #define NR_4K_BLOCK 32
277 static unsigned char **nr_4K_px = NULL;
278 static unsigned int nr_4K_len = 0;
279 static unsigned int nr_4K_size = 0;
281 unsigned char *
282 nr_pixelstore_4K_new (bool clear, unsigned char val)
283 {
284 unsigned char *px;
286 if (nr_4K_len != 0) {
287 nr_4K_len -= 1;
288 px = nr_4K_px[nr_4K_len];
289 } else {
290 px = g_new (unsigned char, 4096);
291 }
293 if (clear) memset (px, val, 4096);
295 return px;
296 }
298 void
299 nr_pixelstore_4K_free (unsigned char *px)
300 {
301 if (nr_4K_len == nr_4K_size) {
302 nr_4K_size += NR_4K_BLOCK;
303 nr_4K_px = g_renew (unsigned char *, nr_4K_px, nr_4K_size);
304 }
306 nr_4K_px[nr_4K_len] = px;
307 nr_4K_len += 1;
308 }
310 #define NR_16K_BLOCK 32
311 static unsigned char **nr_16K_px = NULL;
312 static unsigned int nr_16K_len = 0;
313 static unsigned int nr_16K_size = 0;
315 unsigned char *
316 nr_pixelstore_16K_new (bool clear, unsigned char val)
317 {
318 unsigned char *px;
320 if (nr_16K_len != 0) {
321 nr_16K_len -= 1;
322 px = nr_16K_px[nr_16K_len];
323 } else {
324 px = g_new (unsigned char, 16384);
325 }
327 if (clear) memset (px, val, 16384);
329 return px;
330 }
332 void
333 nr_pixelstore_16K_free (unsigned char *px)
334 {
335 if (nr_16K_len == nr_16K_size) {
336 nr_16K_size += NR_16K_BLOCK;
337 nr_16K_px = g_renew (unsigned char *, nr_16K_px, nr_16K_size);
338 }
340 nr_16K_px[nr_16K_len] = px;
341 nr_16K_len += 1;
342 }
344 #define NR_64K_BLOCK 32
345 static unsigned char **nr_64K_px = NULL;
346 static unsigned int nr_64K_len = 0;
347 static unsigned int nr_64K_size = 0;
349 unsigned char *
350 nr_pixelstore_64K_new (bool clear, unsigned char val)
351 {
352 unsigned char *px;
354 if (nr_64K_len != 0) {
355 nr_64K_len -= 1;
356 px = nr_64K_px[nr_64K_len];
357 } else {
358 px = g_new (unsigned char, 65536);
359 }
361 if (clear) memset (px, val, 65536);
363 return px;
364 }
366 void
367 nr_pixelstore_64K_free (unsigned char *px)
368 {
369 if (nr_64K_len == nr_64K_size) {
370 nr_64K_size += NR_64K_BLOCK;
371 nr_64K_px = g_renew (unsigned char *, nr_64K_px, nr_64K_size);
372 }
374 nr_64K_px[nr_64K_len] = px;
375 nr_64K_len += 1;
376 }
378 #define NR_256K_BLOCK 32
379 #define NR_256K 262144
380 static unsigned char **nr_256K_px = NULL;
381 static unsigned int nr_256K_len = 0;
382 static unsigned int nr_256K_size = 0;
384 unsigned char *
385 nr_pixelstore_256K_new (bool clear, unsigned char val)
386 {
387 unsigned char *px;
389 if (nr_256K_len != 0) {
390 nr_256K_len -= 1;
391 px = nr_256K_px[nr_256K_len];
392 } else {
393 px = g_new (unsigned char, NR_256K);
394 }
396 if (clear) memset (px, val, NR_256K);
398 return px;
399 }
401 void
402 nr_pixelstore_256K_free (unsigned char *px)
403 {
404 if (nr_256K_len == nr_256K_size) {
405 nr_256K_size += NR_256K_BLOCK;
406 nr_256K_px = g_renew (unsigned char *, nr_256K_px, nr_256K_size);
407 }
409 nr_256K_px[nr_256K_len] = px;
410 nr_256K_len += 1;
411 }
413 #define NR_1M_BLOCK 32
414 #define NR_1M 1048576
415 static unsigned char **nr_1M_px = NULL;
416 static unsigned int nr_1M_len = 0;
417 static unsigned int nr_1M_size = 0;
419 unsigned char *
420 nr_pixelstore_1M_new (bool clear, unsigned char val)
421 {
422 unsigned char *px;
424 if (nr_1M_len != 0) {
425 nr_1M_len -= 1;
426 px = nr_1M_px[nr_1M_len];
427 } else {
428 px = g_new (unsigned char, NR_1M);
429 }
431 if (clear) memset (px, val, NR_1M);
433 return px;
434 }
436 void
437 nr_pixelstore_1M_free (unsigned char *px)
438 {
439 if (nr_1M_len == nr_1M_size) {
440 nr_1M_size += NR_1M_BLOCK;
441 nr_1M_px = g_renew (unsigned char *, nr_1M_px, nr_1M_size);
442 }
444 nr_1M_px[nr_1M_len] = px;
445 nr_1M_len += 1;
446 }
448 /*
449 Local Variables:
450 mode:c++
451 c-file-style:"stroustrup"
452 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
453 indent-tabs-mode:nil
454 fill-column:99
455 End:
456 */
457 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :