3 * Specialized blit functions and macros.
5 * Copyright (C) 2011 Tomas Gavenciak <gavento@ucw.cz>
6 * Copyright (C) 2011-2014 Cyril Hrubis <metan@ucw.cz>
11 #include "core/GP_Pixel.h"
12 #include "core/GP_GetPutPixel.h"
13 #include "core/GP_Pixmap.h"
14 #include "core/GP_Blit.h"
15 #include "core/GP_Debug.h"
16 #include "core/GP_Convert.h"
17 #include "core/GP_Convert.gen.h"
18 #include "core/GP_Convert_Scale.gen.h"
19 #include "core/GP_MixPixels2.gen.h"
22 * TODO: this is used for same pixel but different offset, could still be optimized
24 static void blitXYXY_Naive_Raw(const GP_Pixmap *src,
25 GP_Coord x0, GP_Coord y0, GP_Coord x1, GP_Coord y1,
26 GP_Pixmap *dst, GP_Coord x2, GP_Coord y2)
30 for (y = y0; y <= y1; y++) {
31 for (x = x0; x <= x1; x++) {
32 GP_Pixel p = GP_GetPixel_Raw(src, x, y);
34 if (src->pixel_type != dst->pixel_type)
35 p = GP_ConvertPixmapPixel(p, src, dst);
37 GP_PutPixel_Raw(dst, x2 + (x - x0), y2 + (y - y0), p);
43 @ for ps in pixelsizes:
45 * Blit for equal pixel types {{ ps.suffix }}
47 static void blitXYXY_Raw_{{ ps.suffix }}(const GP_Pixmap *src,
48 GP_Coord x0, GP_Coord y0, GP_Coord x1, GP_Coord y1,
49 GP_Pixmap *dst, GP_Coord x2, GP_Coord y2)
51 @ if not ps.needs_bit_endian():
52 /* memcpy() each horizontal line */
55 for (y = 0; y <= (y1 - y0); y++)
56 memcpy(GP_PIXEL_ADDR_{{ ps.suffix }}(dst, x2, y2 + y),
57 GP_PIXEL_ADDR_{{ ps.suffix }}(src, x0, y0 + y),
58 {{ int(ps.size/8) }} * (x1 - x0 + 1));
61 /* Rectangles may not be bit-aligned in the same way! */
62 /* Alignment (index) of first bits in the first byte */
63 //TODO: This is wrong for subpixmaps where the offset
64 // needs to be summed with pixmap->offset and moduled
65 int al1 = GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x0);
66 int al2 = GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x2);
67 /* Special case of the same alignment and width >=2 bytes */
68 if ((al1 == al2) && ((x1 - x0 + 1) * {{ ps.size }} >= 16)) {
69 /* Number of bits in the last partial byte */
70 int end_al = GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x1);
71 GP_ASSERT(({{ ps.size }} * (x1 - x0 + 1) - al1 - end_al) % 8 == 0);
72 int copy_size = ({{ ps.size }} * (x1 - x0 + 1) - al1 - end_al) / 8;
73 /* First and last byte incident to the line */
74 uint8_t *p1 = (uint8_t *) GP_PIXEL_ADDR_{{ ps.suffix }}(src, x1, y1);
75 uint8_t *p2 = (uint8_t *) GP_PIXEL_ADDR_{{ ps.suffix }}(dst, x2, y2);
76 uint8_t *end_p1 = (uint8_t *) GP_PIXEL_ADDR_{{ ps.suffix }}(src, x1, y0);
77 uint8_t *end_p2 = (uint8_t *) GP_PIXEL_ADDR_{{ ps.suffix }}(dst, x2, y2);
81 for (i = 0; i < (y1 - y0 + 1); i++) {
83 GP_SET_BITS(al1, 8-al1, *p2, GP_GET_BITS(al1, 8-al1, *p1));
84 memcpy(p2+(al1!=0), p1+(al1!=0), copy_size);
86 GP_SET_BITS(0, end_al, *end_p2, GP_GET_BITS(0, end_al, *end_p1));
87 p1 += src->bytes_per_row;
88 end_p1 += src->bytes_per_row;
89 p2 += dst->bytes_per_row;
90 end_p2 += dst->bytes_per_row;
92 } else /* Different bit-alignment, can't use memcpy() */
94 blitXYXY_Naive_Raw(src, x0, y0, x1, y1, dst, x2, y2);
100 * Generate Blits, I know this is n^2 variants but the gain is in speed is
101 * more than 50% and the size footprint for two for cycles is really small.
103 @ for src in pixeltypes:
104 @ if not src.is_unknown() and not src.is_palette():
105 @ for dst in pixeltypes:
106 @ if not dst.is_unknown() and not dst.is_palette():
107 @ if dst.name != src.name:
109 * Blits {{ src.name }} to {{ dst.name }}
111 static void blitXYXY_Raw_{{ src.name }}_{{ dst.name }}(const GP_Pixmap *src,
112 GP_Coord x0, GP_Coord y0, GP_Coord x1, GP_Coord y1,
113 GP_Pixmap *dst, GP_Coord x2, GP_Coord y2)
115 GP_Coord x, y, dx, dy;
117 for (y = y0; y <= y1; y++) {
118 for (x = x0; x <= x1; x++) {
122 GP_Pixel p1, p2 = 0, p3 = 0;
124 p1 = GP_GetPixel_Raw_{{ src.pixelsize.suffix }}(src, x, y);
126 p2 = GP_GetPixel_Raw_{{ dst.pixelsize.suffix }}(dst, dx, dy);
127 p3 = GP_MixPixels_{{ src.name }}_{{ dst.name }}(p1, p2);
129 GP_Pixel_{{ src.name }}_TO_RGB888(p1, p2);
130 GP_Pixel_RGB888_TO_{{ dst.name }}(p2, p3);
132 GP_PutPixel_Raw_{{ dst.pixelsize.suffix }}(dst, dx, dy, p3);
139 void GP_BlitXYXY_Raw_Fast(const GP_Pixmap *src,
140 GP_Coord x0, GP_Coord y0, GP_Coord x1, GP_Coord y1,
141 GP_Pixmap *dst, GP_Coord x2, GP_Coord y2)
143 /* Same pixel type, could be (mostly) optimized to memcpy() */
144 if (src->pixel_type == dst->pixel_type) {
145 GP_FN_PER_BPP(blitXYXY_Raw, src->bpp, src->bit_endian,
146 src, x0, y0, x1, y1, dst, x2, y2);
150 /* Specialized functions */
151 switch (src->pixel_type) {
152 @ for src in pixeltypes:
153 @ if not src.is_unknown() and not src.is_palette():
154 case GP_PIXEL_{{ src.name }}:
155 switch (dst->pixel_type) {
156 @ for dst in pixeltypes:
157 @ if not dst.is_unknown() and not dst.is_palette():
158 @ if dst.name != src.name:
159 case GP_PIXEL_{{ dst.name }}:
160 blitXYXY_Raw_{{ src.name }}_{{ dst.name }}(src, x0, y0, x1, y1, dst, x2, y2);
164 GP_ABORT("Invalid destination pixel %s",
165 GP_PixelTypeName(dst->pixel_type));
170 GP_ABORT("Invalid source pixel %s",
171 GP_PixelTypeName(src->pixel_type));
176 * And the same for non-raw variants.
178 @ for src in pixeltypes:
179 @ if not src.is_unknown() and not src.is_palette():
180 @ for dst in pixeltypes:
181 @ if not dst.is_unknown() and not dst.is_palette():
182 @ if dst.name != src.name:
184 * Blits {{ src.name }} to {{ dst.name }}
186 static void blitXYXY_{{ src.name }}_{{ dst.name }}(const GP_Pixmap *src,
187 GP_Coord x0, GP_Coord y0, GP_Coord x1, GP_Coord y1,
188 GP_Pixmap *dst, GP_Coord x2, GP_Coord y2)
190 GP_Coord x, y, xt, yt;
192 for (y = y0; y <= y1; y++)
193 for (x = x0; x <= x1; x++) {
196 GP_TRANSFORM_POINT(src, xt, yt);
197 p1 = GP_GetPixel_Raw_{{ src.pixelsize.suffix }}(src, xt, yt);
198 GP_Pixel_{{ src.name }}_TO_RGB888(p1, p2);
199 GP_Pixel_RGB888_TO_{{ dst.name }}(p2, p1);
202 GP_TRANSFORM_POINT(dst, xt, yt);
203 GP_PutPixel_Raw_{{ dst.pixelsize.suffix }}(dst, xt, yt, p1);
210 * Same pixel type but with rotation.
212 @ for ps in pixelsizes:
214 * Blits for same pixel type and bpp {{ ps.suffix }}
216 static void blitXYXY_{{ ps.suffix }}(const GP_Pixmap *src,
217 GP_Coord x0, GP_Coord y0, GP_Coord x1, GP_Coord y1,
218 GP_Pixmap *dst, GP_Coord x2, GP_Coord y2)
220 GP_Coord x, y, xt, yt;
222 for (y = y0; y <= y1; y++)
223 for (x = x0; x <= x1; x++) {
226 GP_TRANSFORM_POINT(src, xt, yt);
227 p = GP_GetPixel_Raw_{{ ps.suffix }}(src, xt, yt);
230 GP_TRANSFORM_POINT(dst, xt, yt);
231 GP_PutPixel_Raw_{{ ps.suffix }}(dst, xt, yt, p);
236 void GP_BlitXYXY_Fast(const GP_Pixmap *src,
237 GP_Coord x0, GP_Coord y0, GP_Coord x1, GP_Coord y1,
238 GP_Pixmap *dst, GP_Coord x2, GP_Coord y2)
240 GP_DEBUG(2, "Blitting %s -> %s",
241 GP_PixelTypeName(src->pixel_type),
242 GP_PixelTypeName(dst->pixel_type));
244 /* Same pixel type */
245 if (src->pixel_type == dst->pixel_type) {
246 GP_FN_PER_BPP(blitXYXY, src->bpp, src->bit_endian,
247 src, x0, y0, x1, y1, dst, x2, y2);
251 if (GP_PixmapRotationEqual(src, dst)) {
252 GP_BlitXYXY_Raw_Fast(src, x0, y0, x1, y1, dst, x2, y2);
256 /* Specialized functions */
257 switch (src->pixel_type) {
258 @ for src in pixeltypes:
259 @ if not src.is_unknown() and not src.is_palette():
260 case GP_PIXEL_{{ src.name }}:
261 switch (dst->pixel_type) {
262 @ for dst in pixeltypes:
263 @ if not dst.is_unknown() and not dst.is_palette():
264 @ if dst.name != src.name:
265 case GP_PIXEL_{{ dst.name }}:
266 blitXYXY_{{ src.name }}_{{ dst.name }}(src, x0, y0, x1, y1, dst, x2, y2);
270 GP_ABORT("Invalid destination pixel %s",
271 GP_PixelTypeName(dst->pixel_type));
276 GP_ABORT("Invalid source pixel %s",
277 GP_PixelTypeName(src->pixel_type));