3 {% block descr %}Specialized blit functions and macros.{% endblock %}
8 #include "core/GP_Pixel.h"
9 #include "core/GP_GetPutPixel.h"
10 #include "core/GP_Context.h"
11 #include "core/GP_Blit.h"
12 #include "core/GP_Debug.h"
13 #include "core/GP_Convert.h"
14 #include "core/GP_Convert.gen.h"
15 #include "core/GP_Convert_Scale.gen.h"
16 #include "core/GP_MixPixels2.gen.h"
19 * TODO: this is used for same pixel but different offset, could still be optimized
21 static void blitXYXY_Naive_Raw(const GP_Context *src,
22 GP_Coord x0, GP_Coord y0, GP_Coord x1, GP_Coord y1,
23 GP_Context *dst, GP_Coord x2, GP_Coord y2)
27 for (y = y0; y <= y1; y++) {
28 for (x = x0; x <= x1; x++) {
29 GP_Pixel p = GP_GetPixel_Raw(src, x, y);
31 if (src->pixel_type != dst->pixel_type)
32 p = GP_ConvertContextPixel(p, src, dst);
34 GP_PutPixel_Raw(dst, x2 + (x - x0), y2 + (y - y0), p);
40 %% for ps in pixelsizes
42 * Blit for equal pixel types {{ ps.suffix }}
44 static void blitXYXY_Raw_{{ ps.suffix }}(const GP_Context *src,
45 GP_Coord x0, GP_Coord y0, GP_Coord x1, GP_Coord y1,
46 GP_Context *dst, GP_Coord x2, GP_Coord y2)
48 %% if not ps.needs_bit_endian()
49 /* memcpy() each horizontal line */
52 for (y = 0; y <= (y1 - y0); y++)
53 memcpy(GP_PIXEL_ADDR_{{ ps.suffix }}(dst, x2, y2 + y),
54 GP_PIXEL_ADDR_{{ ps.suffix }}(src, x0, y0 + y),
55 {{ int(ps.size/8) }} * (x1 - x0 + 1));
57 {# /* Rectangles may not be bit-aligned in the same way! */
58 /* Alignment (index) of first bits in the first byte */
59 //TODO: This is wrong for subcontexts where the offset
60 // needs to be summed with context->offset and moduled
61 int al1 = GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x0);
62 int al2 = GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x2);
63 /* Special case of the same alignment and width >=2 bytes */
64 if ((al1 == al2) && ((x1 - x0 + 1) * {{ ps.size }} >= 16)) {
65 /* Number of bits in the last partial byte */
66 int end_al = GP_PIXEL_ADDR_OFFSET_{{ ps.suffix }}(x1);
67 GP_ASSERT(({{ ps.size }} * (x1 - x0 + 1) - al1 - end_al) % 8 == 0);
68 int copy_size = ({{ ps.size }} * (x1 - x0 + 1) - al1 - end_al) / 8;
69 /* First and last byte incident to the line */
70 uint8_t *p1 = (uint8_t *) GP_PIXEL_ADDR_{{ ps.suffix }}(src, x1, y1);
71 uint8_t *p2 = (uint8_t *) GP_PIXEL_ADDR_{{ ps.suffix }}(dst, x2, y2);
72 uint8_t *end_p1 = (uint8_t *) GP_PIXEL_ADDR_{{ ps.suffix }}(src, x1, y0);
73 uint8_t *end_p2 = (uint8_t *) GP_PIXEL_ADDR_{{ ps.suffix }}(dst, x2, y2);
77 for (i = 0; i < (y1 - y0 + 1); i++) {
79 GP_SET_BITS(al1, 8-al1, *p2, GP_GET_BITS(al1, 8-al1, *p1));
80 memcpy(p2+(al1!=0), p1+(al1!=0), copy_size);
82 GP_SET_BITS(0, end_al, *end_p2, GP_GET_BITS(0, end_al, *end_p1));
83 p1 += src->bytes_per_row;
84 end_p1 += src->bytes_per_row;
85 p2 += dst->bytes_per_row;
86 end_p2 += dst->bytes_per_row;
88 } else /* Different bit-alignment, can't use memcpy() */
90 blitXYXY_Naive_Raw(src, x0, y0, x1, y1, dst, x2, y2);
97 * Generate Blits, I know this is n^2 variants but the gain is in speed is
98 * more than 50% and the size footprint for two for cycles is really small.
100 %% for src in pixeltypes
101 %% if not src.is_unknown() and not src.is_palette()
102 %% for dst in pixeltypes
103 %% if not dst.is_unknown() and not dst.is_palette()
104 %% if dst.name != src.name
106 * Blits {{ src.name }} to {{ dst.name }}
108 static void blitXYXY_Raw_{{ src.name }}_{{ dst.name }}(const GP_Context *src,
109 GP_Coord x0, GP_Coord y0, GP_Coord x1, GP_Coord y1,
110 GP_Context *dst, GP_Coord x2, GP_Coord y2)
112 GP_Coord x, y, dx, dy;
114 for (y = y0; y <= y1; y++) {
115 for (x = x0; x <= x1; x++) {
119 GP_Pixel p1, p2 = 0, p3 = 0;
121 p1 = GP_GetPixel_Raw_{{ src.pixelsize.suffix }}(src, x, y);
123 p2 = GP_GetPixel_Raw_{{ dst.pixelsize.suffix }}(dst, dx, dy);
124 p3 = GP_MixPixels_{{ src.name }}_{{ dst.name }}(p1, p2);
126 GP_Pixel_{{ src.name }}_TO_RGB888(p1, p2);
127 GP_Pixel_RGB888_TO_{{ dst.name }}(p2, p3);
129 GP_PutPixel_Raw_{{ dst.pixelsize.suffix }}(dst, dx, dy, p3);
140 void GP_BlitXYXY_Raw_Fast(const GP_Context *src,
141 GP_Coord x0, GP_Coord y0, GP_Coord x1, GP_Coord y1,
142 GP_Context *dst, GP_Coord x2, GP_Coord y2)
144 /* Same pixel type, could be (mostly) optimized to memcpy() */
145 if (src->pixel_type == dst->pixel_type) {
146 GP_FN_PER_BPP(blitXYXY_Raw, src->bpp, src->bit_endian,
147 src, x0, y0, x1, y1, dst, x2, y2);
151 /* Specialized functions */
152 switch (src->pixel_type) {
153 %% for src in pixeltypes
154 %% if not src.is_unknown() and not src.is_palette()
155 case GP_PIXEL_{{ src.name }}:
156 switch (dst->pixel_type) {
157 %% for dst in pixeltypes
158 %% if not dst.is_unknown() and not dst.is_palette()
159 %% if dst.name != src.name
160 case GP_PIXEL_{{ dst.name }}:
161 blitXYXY_Raw_{{ src.name }}_{{ dst.name }}(src, x0, y0, x1, y1, dst, x2, y2);
167 GP_ABORT("Invalid destination pixel %s",
168 GP_PixelTypeName(dst->pixel_type));
174 GP_ABORT("Invalid source pixel %s",
175 GP_PixelTypeName(src->pixel_type));
180 * And the same for non-raw variants.
182 %% for src in pixeltypes
183 %% if not src.is_unknown() and not src.is_palette()
184 %% for dst in pixeltypes
185 %% if not dst.is_unknown() and not dst.is_palette()
186 %% if dst.name != src.name
188 * Blits {{ src.name }} to {{ dst.name }}
190 static void blitXYXY_{{ src.name }}_{{ dst.name }}(const GP_Context *src,
191 GP_Coord x0, GP_Coord y0, GP_Coord x1, GP_Coord y1,
192 GP_Context *dst, GP_Coord x2, GP_Coord y2)
194 GP_Coord x, y, xt, yt;
196 for (y = y0; y <= y1; y++)
197 for (x = x0; x <= x1; x++) {
200 GP_TRANSFORM_POINT(src, xt, yt);
201 p1 = GP_GetPixel_Raw_{{ src.pixelsize.suffix }}(src, xt, yt);
202 GP_Pixel_{{ src.name }}_TO_RGB888(p1, p2);
203 GP_Pixel_RGB888_TO_{{ dst.name }}(p2, p1);
206 GP_TRANSFORM_POINT(dst, xt, yt);
207 GP_PutPixel_Raw_{{ dst.pixelsize.suffix }}(dst, xt, yt, p1);
218 * Same pixel type but with rotation.
220 %% for ps in pixelsizes
222 * Blits for same pixel type and bpp {{ ps.suffix }}
224 static void blitXYXY_{{ ps.suffix }}(const GP_Context *src,
225 GP_Coord x0, GP_Coord y0, GP_Coord x1, GP_Coord y1,
226 GP_Context *dst, GP_Coord x2, GP_Coord y2)
228 GP_Coord x, y, xt, yt;
230 for (y = y0; y <= y1; y++)
231 for (x = x0; x <= x1; x++) {
234 GP_TRANSFORM_POINT(src, xt, yt);
235 p = GP_GetPixel_Raw_{{ ps.suffix }}(src, xt, yt);
238 GP_TRANSFORM_POINT(dst, xt, yt);
239 GP_PutPixel_Raw_{{ ps.suffix }}(dst, xt, yt, p);
244 void GP_BlitXYXY_Fast(const GP_Context *src,
245 GP_Coord x0, GP_Coord y0, GP_Coord x1, GP_Coord y1,
246 GP_Context *dst, GP_Coord x2, GP_Coord y2)
248 /* Same pixel type */
249 if (src->pixel_type == dst->pixel_type) {
250 GP_FN_PER_BPP(blitXYXY, src->bpp, src->bit_endian,
251 src, x0, y0, x1, y1, dst, x2, y2);
255 /* Specialized functions */
256 switch (src->pixel_type) {
257 %% for src in pixeltypes
258 %% if not src.is_unknown() and not src.is_palette()
259 case GP_PIXEL_{{ src.name }}:
260 switch (dst->pixel_type) {
261 %% for dst in pixeltypes
262 %% if not dst.is_unknown() and not dst.is_palette()
263 %% if dst.name != src.name
264 case GP_PIXEL_{{ dst.name }}:
265 blitXYXY_{{ src.name }}_{{ dst.name }}(src, x0, y0, x1, y1, dst, x2, y2);
271 GP_ABORT("Invalid destination pixel %s",
272 GP_PixelTypeName(dst->pixel_type));
278 GP_ABORT("Invalid source pixel %s",
279 GP_PixelTypeName(src->pixel_type));