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