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 <glib/gmem.h>
13 #include "nr-pixblock.h"
15 /// Size of buffer that needs no allocation (default 4).
16 #define NR_TINY_MAX sizeof (unsigned char *)
18 /**
19 * Pixbuf initialisation using homegrown memory handling ("pixelstore").
20 *
21 * Pixbuf sizes are differentiated into tiny, <4K, <16K, <64K, and more,
22 * with each type having its own method of memory handling. After allocating
23 * memory, the buffer is cleared if the clear flag is set. Intended to
24 * reduce memory fragmentation.
25 * \param pb Pointer to the pixbuf struct.
26 * \param mode Indicates grayscale/RGB/RGBA.
27 * \param clear True if buffer should be cleared.
28 * \pre x1>=x0 && y1>=y0 && pb!=NULL
29 */
30 void
31 nr_pixblock_setup_fast (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear)
32 {
33 int w, h, bpp;
34 size_t size;
36 w = x1 - x0;
37 h = y1 - y0;
38 bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
40 size = bpp * w * h;
42 if (size <= NR_TINY_MAX) {
43 pb->size = NR_PIXBLOCK_SIZE_TINY;
44 if (clear) memset (pb->data.p, 0x0, size);
45 } else if (size <= 4096) {
46 pb->size = NR_PIXBLOCK_SIZE_4K;
47 pb->data.px = nr_pixelstore_4K_new (clear, 0x0);
48 } else if (size <= 16384) {
49 pb->size = NR_PIXBLOCK_SIZE_16K;
50 pb->data.px = nr_pixelstore_16K_new (clear, 0x0);
51 } else if (size <= 65536) {
52 pb->size = NR_PIXBLOCK_SIZE_64K;
53 pb->data.px = nr_pixelstore_64K_new (clear, 0x0);
54 } else if (size <= 262144) {
55 pb->size = NR_PIXBLOCK_SIZE_256K;
56 pb->data.px = nr_pixelstore_256K_new (clear, 0x0);
57 } else if (size <= 1048576) {
58 pb->size = NR_PIXBLOCK_SIZE_1M;
59 pb->data.px = nr_pixelstore_1M_new (clear, 0x0);
60 } else {
61 pb->size = NR_PIXBLOCK_SIZE_BIG;
62 pb->data.px = NULL;
63 if (size > 100000000) { // Don't even try to allocate more than 100Mb (5000x5000 RGBA
64 // pixels). It'll just bog the system down even if successful. FIXME:
65 // Can anyone suggest something better than the magic number?
66 g_warning ("%lu bytes requested for pixel buffer, I won't try to allocate that.", (long unsigned) size);
67 return;
68 }
69 pb->data.px = g_try_new (unsigned char, size);
70 if (pb->data.px == NULL) { // memory allocation failed
71 g_warning ("Could not allocate %lu bytes for pixel buffer!", (long unsigned) size);
72 return;
73 }
74 if (clear) memset (pb->data.px, 0x0, size);
75 }
77 pb->mode = mode;
78 pb->empty = 1;
79 pb->visible_area.x0 = pb->area.x0 = x0;
80 pb->visible_area.y0 = pb->area.y0 = y0;
81 pb->visible_area.x1 = pb->area.x1 = x1;
82 pb->visible_area.y1 = pb->area.y1 = y1;
83 pb->rs = bpp * w;
84 }
86 /**
87 * Pixbuf initialisation using g_new.
88 *
89 * After allocating memory, the buffer is cleared if the clear flag is set.
90 * \param pb Pointer to the pixbuf struct.
91 * \param mode Indicates grayscale/RGB/RGBA.
92 * \param clear True if buffer should be cleared.
93 * \pre x1>=x0 && y1>=y0 && pb!=NULL
94 FIXME: currently unused except for nr_pixblock_new and pattern tiles, replace with _fast and delete?
95 */
96 void
97 nr_pixblock_setup (NRPixBlock *pb, NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear)
98 {
99 int w, h, bpp;
100 size_t size;
102 w = x1 - x0;
103 h = y1 - y0;
104 bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
106 size = bpp * w * h;
108 if (size <= NR_TINY_MAX) {
109 pb->size = NR_PIXBLOCK_SIZE_TINY;
110 if (clear) memset (pb->data.p, 0x0, size);
111 } else {
112 pb->size = NR_PIXBLOCK_SIZE_BIG;
113 pb->data.px = g_new (unsigned char, size);
114 if (clear) memset (pb->data.px, 0x0, size);
115 }
117 pb->mode = mode;
118 pb->empty = 1;
119 pb->visible_area.x0 = pb->area.x0 = x0;
120 pb->visible_area.y0 = pb->area.y0 = y0;
121 pb->visible_area.x1 = pb->area.x1 = x1;
122 pb->visible_area.y1 = pb->area.y1 = y1;
123 pb->rs = bpp * w;
124 }
126 /**
127 * Pixbuf initialisation with preset values.
128 *
129 * After copying all parameters into the NRPixBlock struct, the pixel buffer is cleared if the clear flag is set.
130 * \param pb Pointer to the pixbuf struct.
131 * \param mode Indicates grayscale/RGB/RGBA.
132 * \param clear True if buffer should be cleared.
133 * \pre x1>=x0 && y1>=y0 && pb!=NULL
134 */
135 void
136 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)
137 {
138 int w, bpp;
140 w = x1 - x0;
141 bpp = (mode == NR_PIXBLOCK_MODE_A8) ? 1 : (mode == NR_PIXBLOCK_MODE_R8G8B8) ? 3 : 4;
143 pb->size = NR_PIXBLOCK_SIZE_STATIC;
144 pb->mode = mode;
145 pb->empty = empty;
146 pb->visible_area.x0 = pb->area.x0 = x0;
147 pb->visible_area.y0 = pb->area.y0 = y0;
148 pb->visible_area.x1 = pb->area.x1 = x1;
149 pb->visible_area.y1 = pb->area.y1 = y1;
150 pb->data.px = px;
151 pb->rs = rs;
153 g_assert (pb->data.px != NULL);
154 if (clear) {
155 if (rs == bpp * w) {
156 /// \todo How do you recognise if
157 /// px was an uncleared tiny buffer?
158 if (pb->data.px)
159 memset (pb->data.px, 0x0, bpp * (y1 - y0) * w);
160 } else {
161 int y;
162 for (y = y0; y < y1; y++) {
163 memset (pb->data.px + (y - y0) * rs, 0x0, bpp * w);
164 }
165 }
166 }
167 }
169 /**
170 * Frees memory taken by pixel data in NRPixBlock.
171 * \param pb Pointer to pixblock.
172 * \pre pb and pb->data.px point to valid addresses.
173 *
174 * According to pb->size, one of the functions for freeing the pixelstore
175 * is called. May be called regardless of how pixbuf was set up.
176 */
177 void
178 nr_pixblock_release (NRPixBlock *pb)
179 {
180 switch (pb->size) {
181 case NR_PIXBLOCK_SIZE_TINY:
182 break;
183 case NR_PIXBLOCK_SIZE_4K:
184 nr_pixelstore_4K_free (pb->data.px);
185 break;
186 case NR_PIXBLOCK_SIZE_16K:
187 nr_pixelstore_16K_free (pb->data.px);
188 break;
189 case NR_PIXBLOCK_SIZE_64K:
190 nr_pixelstore_64K_free (pb->data.px);
191 break;
192 case NR_PIXBLOCK_SIZE_256K:
193 nr_pixelstore_256K_free (pb->data.px);
194 break;
195 case NR_PIXBLOCK_SIZE_1M:
196 nr_pixelstore_1M_free (pb->data.px);
197 break;
198 case NR_PIXBLOCK_SIZE_BIG:
199 g_free (pb->data.px);
200 break;
201 case NR_PIXBLOCK_SIZE_STATIC:
202 break;
203 default:
204 break;
205 }
206 }
208 /**
209 * Allocates NRPixBlock and sets it up.
210 *
211 * \return Pointer to fresh pixblock.
212 * Calls g_new() and nr_pixblock_setup().
213 FIXME: currently unused, delete?
214 */
215 NRPixBlock *
216 nr_pixblock_new (NR_PIXBLOCK_MODE mode, int x0, int y0, int x1, int y1, bool clear)
217 {
218 NRPixBlock *pb;
220 pb = g_new (NRPixBlock, 1);
222 nr_pixblock_setup (pb, mode, x0, y0, x1, y1, clear);
224 return pb;
225 }
227 /**
228 * Frees all memory taken by pixblock.
229 *
230 * \return NULL
231 */
232 NRPixBlock *
233 nr_pixblock_free (NRPixBlock *pb)
234 {
235 nr_pixblock_release (pb);
237 g_free (pb);
239 return NULL;
240 }
242 /* PixelStore operations */
244 #define NR_4K_BLOCK 32
245 static unsigned char **nr_4K_px = NULL;
246 static unsigned int nr_4K_len = 0;
247 static unsigned int nr_4K_size = 0;
249 unsigned char *
250 nr_pixelstore_4K_new (bool clear, unsigned char val)
251 {
252 unsigned char *px;
254 if (nr_4K_len != 0) {
255 nr_4K_len -= 1;
256 px = nr_4K_px[nr_4K_len];
257 } else {
258 px = g_new (unsigned char, 4096);
259 }
261 if (clear) memset (px, val, 4096);
263 return px;
264 }
266 void
267 nr_pixelstore_4K_free (unsigned char *px)
268 {
269 if (nr_4K_len == nr_4K_size) {
270 nr_4K_size += NR_4K_BLOCK;
271 nr_4K_px = g_renew (unsigned char *, nr_4K_px, nr_4K_size);
272 }
274 nr_4K_px[nr_4K_len] = px;
275 nr_4K_len += 1;
276 }
278 #define NR_16K_BLOCK 32
279 static unsigned char **nr_16K_px = NULL;
280 static unsigned int nr_16K_len = 0;
281 static unsigned int nr_16K_size = 0;
283 unsigned char *
284 nr_pixelstore_16K_new (bool clear, unsigned char val)
285 {
286 unsigned char *px;
288 if (nr_16K_len != 0) {
289 nr_16K_len -= 1;
290 px = nr_16K_px[nr_16K_len];
291 } else {
292 px = g_new (unsigned char, 16384);
293 }
295 if (clear) memset (px, val, 16384);
297 return px;
298 }
300 void
301 nr_pixelstore_16K_free (unsigned char *px)
302 {
303 if (nr_16K_len == nr_16K_size) {
304 nr_16K_size += NR_16K_BLOCK;
305 nr_16K_px = g_renew (unsigned char *, nr_16K_px, nr_16K_size);
306 }
308 nr_16K_px[nr_16K_len] = px;
309 nr_16K_len += 1;
310 }
312 #define NR_64K_BLOCK 32
313 static unsigned char **nr_64K_px = NULL;
314 static unsigned int nr_64K_len = 0;
315 static unsigned int nr_64K_size = 0;
317 unsigned char *
318 nr_pixelstore_64K_new (bool clear, unsigned char val)
319 {
320 unsigned char *px;
322 if (nr_64K_len != 0) {
323 nr_64K_len -= 1;
324 px = nr_64K_px[nr_64K_len];
325 } else {
326 px = g_new (unsigned char, 65536);
327 }
329 if (clear) memset (px, val, 65536);
331 return px;
332 }
334 void
335 nr_pixelstore_64K_free (unsigned char *px)
336 {
337 if (nr_64K_len == nr_64K_size) {
338 nr_64K_size += NR_64K_BLOCK;
339 nr_64K_px = g_renew (unsigned char *, nr_64K_px, nr_64K_size);
340 }
342 nr_64K_px[nr_64K_len] = px;
343 nr_64K_len += 1;
344 }
346 #define NR_256K_BLOCK 32
347 #define NR_256K 262144
348 static unsigned char **nr_256K_px = NULL;
349 static unsigned int nr_256K_len = 0;
350 static unsigned int nr_256K_size = 0;
352 unsigned char *
353 nr_pixelstore_256K_new (bool clear, unsigned char val)
354 {
355 unsigned char *px;
357 if (nr_256K_len != 0) {
358 nr_256K_len -= 1;
359 px = nr_256K_px[nr_256K_len];
360 } else {
361 px = g_new (unsigned char, NR_256K);
362 }
364 if (clear) memset (px, val, NR_256K);
366 return px;
367 }
369 void
370 nr_pixelstore_256K_free (unsigned char *px)
371 {
372 if (nr_256K_len == nr_256K_size) {
373 nr_256K_size += NR_256K_BLOCK;
374 nr_256K_px = g_renew (unsigned char *, nr_256K_px, nr_256K_size);
375 }
377 nr_256K_px[nr_256K_len] = px;
378 nr_256K_len += 1;
379 }
381 #define NR_1M_BLOCK 32
382 #define NR_1M 1048576
383 static unsigned char **nr_1M_px = NULL;
384 static unsigned int nr_1M_len = 0;
385 static unsigned int nr_1M_size = 0;
387 unsigned char *
388 nr_pixelstore_1M_new (bool clear, unsigned char val)
389 {
390 unsigned char *px;
392 if (nr_1M_len != 0) {
393 nr_1M_len -= 1;
394 px = nr_1M_px[nr_1M_len];
395 } else {
396 px = g_new (unsigned char, NR_1M);
397 }
399 if (clear) memset (px, val, NR_1M);
401 return px;
402 }
404 void
405 nr_pixelstore_1M_free (unsigned char *px)
406 {
407 if (nr_1M_len == nr_1M_size) {
408 nr_1M_size += NR_1M_BLOCK;
409 nr_1M_px = g_renew (unsigned char *, nr_1M_px, nr_1M_size);
410 }
412 nr_1M_px[nr_1M_len] = px;
413 nr_1M_len += 1;
414 }
416 /*
417 Local Variables:
418 mode:c++
419 c-file-style:"stroustrup"
420 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
421 indent-tabs-mode:nil
422 fill-column:99
423 End:
424 */
425 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :