spiv: Fix image list counter
[gfxprim.git] / libs / core / GP_WritePixel.c
blobf53ad9f14a36718bce603092d7efdef889182632
1 /*****************************************************************************
2 * This file is part of gfxprim library. *
3 * *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
8 * *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
18 * *
19 * Copyright (C) 2009-2010 Jiri "BlueBear" Dluhos *
20 * <jiri.bluebear.dluhos@gmail.com> *
21 * *
22 * Copyright (C) 2009-2013 Cyril Hrubis <metan@ucw.cz> *
23 * *
24 *****************************************************************************/
26 #include <string.h>
28 #include "GP_Core.h"
29 #include "GP_WritePixel.h"
31 static const uint8_t bytes_1BPP[] = {0x00, 0xff};
33 void GP_WritePixels_1BPP_LE(void *start, uint8_t off,
34 size_t cnt, unsigned int val)
36 int len = cnt;
38 /* Write start of the line */
39 switch (off) {
40 case 0:
41 break;
42 case 1:
43 GP_SET_BITS1_ALIGNED(1, 1, start, val);
45 if (--len == 0)
46 return;
47 case 2:
48 GP_SET_BITS1_ALIGNED(2, 1, start, val);
50 if (--len == 0)
51 return;
52 case 3:
53 GP_SET_BITS1_ALIGNED(3, 1, start, val);
55 if (--len == 0)
56 return;
57 case 4:
58 GP_SET_BITS1_ALIGNED(4, 1, start, val);
60 if (--len == 0)
61 return;
62 case 5:
63 GP_SET_BITS1_ALIGNED(5, 1, start, val);
65 if (--len == 0)
66 return;
67 case 6:
68 GP_SET_BITS1_ALIGNED(6, 1, start, val);
70 if (--len == 0)
71 return;
72 case 7:
73 GP_SET_BITS1_ALIGNED(7, 1, start, val);
75 if (--len == 0)
76 return;
78 start++;
79 break;
82 /* Write as many bytes as possible */
83 memset(start, bytes_1BPP[val & 0x01], len/8);
85 start+=len/8;
87 /* And the rest */
88 switch (len%8) {
89 case 7:
90 GP_SET_BITS1_ALIGNED(6, 1, start, val);
91 case 6:
92 GP_SET_BITS1_ALIGNED(5, 1, start, val);
93 case 5:
94 GP_SET_BITS1_ALIGNED(4, 1, start, val);
95 case 4:
96 GP_SET_BITS1_ALIGNED(3, 1, start, val);
97 case 3:
98 GP_SET_BITS1_ALIGNED(2, 1, start, val);
99 case 2:
100 GP_SET_BITS1_ALIGNED(1, 1, start, val);
101 case 1:
102 GP_SET_BITS1_ALIGNED(0, 1, start, val);
103 break;
107 void GP_WritePixels_1BPP_BE(void *start, uint8_t off,
108 size_t cnt, unsigned int val)
110 int len = cnt;
112 /* Write start of the line */
113 switch (off) {
114 case 0:
115 break;
116 case 1:
117 GP_SET_BITS1_ALIGNED(6, 1, start, val);
119 if (--len == 0)
120 return;
121 case 2:
122 GP_SET_BITS1_ALIGNED(5, 1, start, val);
124 if (--len == 0)
125 return;
126 case 3:
127 GP_SET_BITS1_ALIGNED(4, 1, start, val);
129 if (--len == 0)
130 return;
131 case 4:
132 GP_SET_BITS1_ALIGNED(3, 1, start, val);
134 if (--len == 0)
135 return;
136 case 5:
137 GP_SET_BITS1_ALIGNED(2, 1, start, val);
139 if (--len == 0)
140 return;
141 case 6:
142 GP_SET_BITS1_ALIGNED(1, 1, start, val);
144 if (--len == 0)
145 return;
146 case 7:
147 GP_SET_BITS1_ALIGNED(0, 1, start, val);
149 if (--len == 0)
150 return;
152 start++;
153 break;
156 /* Write as many bytes as possible */
157 memset(start, bytes_1BPP[val & 0x01], len/8);
159 start+=len/8;
161 /* And the rest */
162 switch (len%8) {
163 case 7:
164 GP_SET_BITS1_ALIGNED(1, 1, start, val);
165 case 6:
166 GP_SET_BITS1_ALIGNED(2, 1, start, val);
167 case 5:
168 GP_SET_BITS1_ALIGNED(3, 1, start, val);
169 case 4:
170 GP_SET_BITS1_ALIGNED(4, 1, start, val);
171 case 3:
172 GP_SET_BITS1_ALIGNED(5, 1, start, val);
173 case 2:
174 GP_SET_BITS1_ALIGNED(6, 1, start, val);
175 case 1:
176 GP_SET_BITS1_ALIGNED(7, 1, start, val);
177 break;
181 static const uint8_t bytes_2BPP[] = {0x00, 0x55, 0xaa, 0xff};
183 void GP_WritePixels_2BPP_LE(void *start, uint8_t off,
184 size_t cnt, unsigned int val)
186 int len = cnt;
188 /* Write start of the line */
189 switch (off) {
190 case 0:
191 break;
192 case 2:
193 GP_SET_BITS1_ALIGNED(2, 2, start, val);
195 if (--len == 0)
196 return;
197 case 4:
198 GP_SET_BITS1_ALIGNED(4, 2, start, val);
200 if (--len == 0)
201 return;
202 case 6:
203 GP_SET_BITS1_ALIGNED(6, 2, start, val);
205 if (--len == 0)
206 return;
208 start++;
209 break;
212 /* Write as many bytes as possible */
213 memset(start, bytes_2BPP[val & 0x03], len/4);
215 start+=len/4;
217 /* And the rest */
218 switch (len%4) {
219 case 3:
220 GP_SET_BITS1_ALIGNED(4, 2, start, val);
221 case 2:
222 GP_SET_BITS1_ALIGNED(2, 2, start, val);
223 case 1:
224 GP_SET_BITS1_ALIGNED(0, 2, start, val);
225 break;
229 void GP_WritePixels_2BPP_BE(void *start, uint8_t off,
230 size_t cnt, unsigned int val)
232 int len = cnt;
234 /* Write start of the line */
235 switch (off) {
236 case 0:
237 break;
238 case 2:
239 GP_SET_BITS1_ALIGNED(6, 2, start, val);
241 if (--len == 0)
242 return;
243 case 4:
244 GP_SET_BITS1_ALIGNED(4, 2, start, val);
246 if (--len == 0)
247 return;
248 case 6:
249 GP_SET_BITS1_ALIGNED(2, 2, start, val);
251 if (--len == 0)
252 return;
254 start++;
255 break;
258 /* Write as many bytes as possible */
259 memset(start, bytes_2BPP[val & 0x03], len/4);
261 start+=len/4;
263 /* And the rest */
264 switch (len%4) {
265 case 3:
266 GP_SET_BITS1_ALIGNED(0, 2, start, val);
267 case 2:
268 GP_SET_BITS1_ALIGNED(2, 2, start, val);
269 case 1:
270 GP_SET_BITS1_ALIGNED(4, 2, start, val);
271 break;
275 static const uint8_t bytes_4BPP[] = {
276 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
277 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
280 void GP_WritePixels_4BPP_LE(void *start, uint8_t off,
281 size_t cnt, unsigned int val)
283 int len = cnt;
285 /* Write start of the line */
286 switch (off) {
287 case 0:
288 break;
289 case 4:
290 GP_SET_BITS1_ALIGNED(4, 4, start, val);
292 if (--len == 0)
293 return;
295 start++;
296 break;
299 /* Write as many bytes as possible */
300 memset(start, bytes_4BPP[val & 0x0f], len/2);
302 start+=len/2;
304 /* And the rest */
305 switch (len%2) {
306 case 1:
307 GP_SET_BITS1_ALIGNED(0, 4, start, val);
308 break;
312 void GP_WritePixels_4BPP_BE(void *start, uint8_t off,
313 size_t cnt, unsigned int val)
315 int len = cnt;
317 /* Write start of the line */
318 switch (off) {
319 case 0:
320 break;
321 case 4:
322 GP_SET_BITS1_ALIGNED(0, 4, start, val);
324 if (--len == 0)
325 return;
327 start++;
328 break;
331 /* Write as many bytes as possible */
332 memset(start, bytes_4BPP[val & 0x0f], len/2);
334 start+=len/2;
336 /* And the rest */
337 switch (len%2) {
338 case 1:
339 GP_SET_BITS1_ALIGNED(4, 4, start, val);
340 break;
344 void GP_WritePixels_8BPP(void *start, size_t count, unsigned int value)
346 memset(start, value, count);
349 void GP_WritePixels_16BPP(void *start, size_t count, unsigned int value)
351 uint16_t *p = (uint16_t *) start;
352 size_t i;
354 /* Write as much pixels as possible in 4-pixel blocks. */
355 for (i = count; i >= 4; p += 4, i -= 4) {
356 p[0] = value;
357 p[1] = value;
358 p[2] = value;
359 p[3] = value;
362 /* Write the rest. */
363 if (i > 0) {
364 p[0] = value;
365 if (i > 1) {
366 p[1] = value;
367 if (i > 2) {
368 p[2] = value;
374 void GP_WritePixels_24BPP(void *start, size_t count, unsigned int value)
376 uint8_t *bytep = (uint8_t *) start;
378 if (count == 0)
379 return;
381 /* How much bytes we are offset against the 32-bit boundary. */
382 int shift = ((uintptr_t) bytep) % 4;
385 * Pixels remaining to draw (one less than pixelcount because
386 * one incomplete pixel is drawn during the preparation phase.)
388 int i = count - 1;
391 * Handle each color component separately.
392 * (Probably they are R, G, B but who knows.)
394 uint8_t a = value & 0xff;
395 uint8_t b = (value >> 8) & 0xff;
396 uint8_t c = (value >> 16) & 0xff;
398 uint32_t *p;
399 uint32_t block[3];
402 * The line consists of three repeating 32-bit segments
403 * (except for the starting and ending segment:
404 * ABCA, BCAB, CABC.
406 #if __BIG_ENDIAN__
407 uint32_t abca = a << 24 | b << 16 | c << 8 | a;
408 uint32_t bcab = b << 24 | c << 16 | a << 8 | b;
409 uint32_t cabc = c << 24 | a << 16 | b << 8 | c;
410 #else
411 uint32_t abca = a << 24 | c << 16 | b << 8 | a;
412 uint32_t bcab = b << 24 | a << 16 | c << 8 | b;
413 uint32_t cabc = c << 24 | b << 16 | a << 8 | c;
414 #endif
417 * Handle the first few bytes (1 pixel or less) and prepare
418 * the repeating sequence.
420 switch (shift) {
421 default: /* shut up gcc */
422 case 0:
423 block[0] = abca;
424 block[1] = bcab;
425 block[2] = cabc;
426 p = (uint32_t *) bytep;
427 break;
428 case 3:
429 bytep[0] = a;
430 block[0] = bcab;
431 block[1] = cabc;
432 block[2] = abca;
433 p = (uint32_t *)(bytep + 1);
434 break;
435 case 2:
436 bytep[0] = a;
437 bytep[1] = b;
438 block[0] = cabc;
439 block[1] = abca;
440 block[2] = bcab;
441 p = (uint32_t *)(bytep + 2);
442 break;
443 case 1:
444 bytep[0] = a;
445 bytep[1] = b;
446 bytep[2] = c;
447 block[0] = abca;
448 block[1] = bcab;
449 block[2] = cabc;
450 p = (uint32_t *)(bytep + 3);
451 i--;
452 break;
456 * Write as much of the line as possible as
457 * triplets of 32-bit numbers; hopefully the compiler can
458 * put some wide write instructions in.
460 while (i >= 4) {
461 p[0] = block[0];
462 p[1] = block[1];
463 p[2] = block[2];
464 p += 3;
465 i -= 4;
468 /* Write the rest of the last pixel of the main part */
469 bytep = (uint8_t *) p;
470 switch (shift) {
471 case 0:
472 break;
473 case 1:
474 break;
475 case 2:
476 bytep[0] = c;
477 bytep++;
478 i--;
479 break;
480 case 3:
481 bytep[0] = b;
482 bytep[1] = c;
483 bytep += 2;
484 i--;
485 break;
488 while (i >= 0) {
489 bytep[0] = a;
490 bytep[1] = b;
491 bytep[2] = c;
492 bytep += 3;
493 i--;
497 void GP_WritePixels_32BPP(void *start, size_t count, unsigned int value)
500 * Inspired by GNU libc's wmemset() (by Ulrich Drepper, licensed under LGPL).
502 * Write the pixels in groups of four, allowing the compiler to use
503 * MMX/SSE/similar instructions if available. The last few pixels are
504 * copied normally one-by-one. (Speed gain is about 15% over a naive loop
505 * on AMD Phenom CPU.)
508 uint32_t *p = (uint32_t *) start;
509 size_t i = count;
510 while (i >= 4) {
511 p[0] = value;
512 p[1] = value;
513 p[2] = value;
514 p[3] = value;
515 p += 4;
516 i -= 4;
518 if (i > 0) {
519 p[0] = value;
520 if (i > 1) {
521 p[1] = value;
522 if (i > 2) {
523 p[2] = value;