1 /* ======================================================================== */
2 /*  Graphics Prescaler                                                      */
3 /*                                                                          */
4 /*  The graphics prescaler allows scaling up the 160x200 bitmap to some     */
5 /*  other size prior to final scaling to display resolution.  This is       */
6 /*  where we'd apply transforms such as Scale2X or a variant.               */
7 /* ======================================================================== */
8 
9 #include "config.h"
10 #include "periph/periph.h"
11 #include "gfx/gfx.h"
12 #include "gfx/gfx_prescale.h"
13 #include "scale/scale2x.h"
14 #include "scale/scale3x.h"
15 
16 typedef struct gfx_prescaler_typ_pvt_t
17 {
18     int     orig_x, orig_y;
19     uint8_t *intermediate;   // for scale4x only
20 } gfx_prescaler_typ_pvt_t;
21 
22 /* ======================================================================== */
23 /*  Prescalers                                                              */
24 /* ======================================================================== */
25 
26 /* ------------------------------------------------------------------------ */
27 /*  NULL prescaler                                                          */
28 /* ------------------------------------------------------------------------ */
gfx_prescaler_null_init(int orig_x,int orig_y,int * RESTRICT new_x,int * RESTRICT new_y,int * RESTRICT need_inter_vid,gfx_dirtyrect_spec * RESTRICT dr_spec)29 LOCAL void *gfx_prescaler_null_init(int orig_x, int orig_y,
30                                     int *RESTRICT new_x,
31                                     int *RESTRICT new_y,
32                                     int *RESTRICT need_inter_vid,
33                                     gfx_dirtyrect_spec *RESTRICT dr_spec)
34 {
35     *new_x          = orig_x;
36     *new_y          = orig_y;
37     *need_inter_vid = 0;
38 
39     dr_spec->active_first_x = 0;
40     dr_spec->active_first_y = 4;
41     dr_spec->active_last_x  = orig_x - 1;
42     dr_spec->active_last_y  = orig_y - 5;
43 
44     dr_spec->x_step         = 8;
45     dr_spec->y_step         = 16;
46 
47     dr_spec->pitch          = orig_x;
48 
49     dr_spec->bord_first_x   = 0;
50     dr_spec->bord_first_y   = 0;
51     dr_spec->bord_last_x    = orig_x - 1;
52     dr_spec->bord_last_y    = orig_y - 1;
53 
54     return NULL;
55 }
56 
gfx_prescaler_null(const uint8_t * RESTRICT src,uint8_t * RESTRICT dst,void * RESTRICT opaque)57 LOCAL void gfx_prescaler_null(const uint8_t *RESTRICT src,
58                                     uint8_t *RESTRICT dst,
59                                     void *RESTRICT opaque)
60 {
61     UNUSED(src);
62     UNUSED(dst);
63     UNUSED(opaque);
64     return;
65 }
66 
gfx_prescaler_null_dtor(void * u)67 LOCAL void gfx_prescaler_null_dtor(void *u)
68 {
69     UNUSED(u);
70     return;
71 }
72 
73 /* ------------------------------------------------------------------------ */
74 /*  SCALE2X                                                                 */
75 /* ------------------------------------------------------------------------ */
gfx_prescaler_scale2x_init(int orig_x,int orig_y,int * RESTRICT new_x,int * RESTRICT new_y,int * RESTRICT need_inter_vid,gfx_dirtyrect_spec * RESTRICT dr_spec)76 LOCAL void *gfx_prescaler_scale2x_init(int orig_x, int orig_y,
77                                        int *RESTRICT new_x,
78                                        int *RESTRICT new_y,
79                                        int *RESTRICT need_inter_vid,
80                                        gfx_dirtyrect_spec *RESTRICT dr_spec)
81 {
82     gfx_prescaler_typ_pvt_t *pvt = CALLOC(gfx_prescaler_typ_pvt_t, 1);
83 
84     if (!pvt)
85     {
86         fprintf(stderr, "Out of memory in gfx_prescale\n");
87         exit(1);
88     }
89 
90     pvt->orig_x = orig_x;
91     pvt->orig_y = orig_y;
92     pvt->intermediate = NULL;
93 
94     *new_x = orig_x * 2;
95     *new_y = orig_y * 2;
96     *need_inter_vid = 1;
97 
98     dr_spec->active_first_x = 0;
99     dr_spec->active_first_y = 8;
100     dr_spec->active_last_x  = 2*orig_x - 1;
101     dr_spec->active_last_y  = 2*orig_y - 9;
102 
103     dr_spec->x_step         = 16;
104     dr_spec->y_step         = 32;
105 
106     dr_spec->pitch          = 2*orig_x;
107 
108     dr_spec->bord_first_x   = 0;
109     dr_spec->bord_first_y   = 0;
110     dr_spec->bord_last_x    = 2*orig_x - 1;
111     dr_spec->bord_last_y    = 2*orig_y - 1;
112 
113     return pvt;
114 }
115 
116 /* Factored out and reused by scale4x */
perform_scale2x_8(int orig_x,int orig_y,const uint8_t * RESTRICT src,uint8_t * RESTRICT dst)117 LOCAL void perform_scale2x_8(int orig_x,
118                              int orig_y,
119                              const uint8_t *RESTRICT src,
120                                    uint8_t *RESTRICT dst)
121 {
122     int src_pitch = orig_x,
123         dst_pitch = orig_x * 2;
124     const uint8_t *src_prev = src;
125     const uint8_t *src_curr = src;
126     const uint8_t *src_next = src + src_pitch;
127     int y;
128 
129     scale2x_8_def((scale2x_uint8 *)dst, (scale2x_uint8 *)(dst + dst_pitch),
130                   (const scale2x_uint8 *)src_prev,
131                   (const scale2x_uint8 *)src_curr,
132                   (const scale2x_uint8 *)src_next, src_pitch);
133 
134     for (y = 2 ; y < orig_y; y++)
135     {
136         dst      += dst_pitch * 2;
137         src_prev  = src_curr;
138         src_curr  = src_next;
139         src_next += src_pitch;
140 
141         scale2x_8_def((scale2x_uint8 *)dst, (scale2x_uint8 *)(dst + dst_pitch),
142                       (const scale2x_uint8 *)src_prev,
143                       (const scale2x_uint8 *)src_curr,
144                       (const scale2x_uint8 *)src_next, src_pitch);
145     }
146 
147     dst     += dst_pitch * 2;
148     src_prev = src_curr;
149     src_curr = src_next;
150 
151     scale2x_8_def((scale2x_uint8 *)dst, (scale2x_uint8 *)(dst + dst_pitch),
152                   (const scale2x_uint8 *)src_prev,
153                   (const scale2x_uint8 *)src_curr,
154                   (const scale2x_uint8 *)src_next, src_pitch);
155 }
156 
gfx_prescaler_scale2x(const uint8_t * RESTRICT src,uint8_t * RESTRICT dst,void * RESTRICT opaque)157 LOCAL void  gfx_prescaler_scale2x(const uint8_t *RESTRICT src,
158                                         uint8_t *RESTRICT dst,
159                                            void *RESTRICT opaque)
160 {
161     gfx_prescaler_typ_pvt_t *pvt = (gfx_prescaler_typ_pvt_t *)opaque;
162     int orig_x = pvt->orig_x, orig_y = pvt->orig_y;
163 
164     perform_scale2x_8(orig_x, orig_y, src, dst);
165 
166     return;
167 }
168 
169 
170 /* ------------------------------------------------------------------------ */
171 /*  SCALE3X                                                                 */
172 /* ------------------------------------------------------------------------ */
gfx_prescaler_scale3x_init(int orig_x,int orig_y,int * RESTRICT new_x,int * RESTRICT new_y,int * RESTRICT need_inter_vid,gfx_dirtyrect_spec * RESTRICT dr_spec)173 LOCAL void *gfx_prescaler_scale3x_init(int orig_x, int orig_y,
174                                        int *RESTRICT new_x,
175                                        int *RESTRICT new_y,
176                                        int *RESTRICT need_inter_vid,
177                                        gfx_dirtyrect_spec *RESTRICT dr_spec)
178 {
179     gfx_prescaler_typ_pvt_t *pvt = CALLOC(gfx_prescaler_typ_pvt_t, 1);
180 
181     if (!pvt)
182     {
183         fprintf(stderr, "Out of memory in gfx_prescale\n");
184         exit(1);
185     }
186 
187     pvt->orig_x = orig_x;
188     pvt->orig_y = orig_y;
189     pvt->intermediate = NULL;
190 
191     *new_x = orig_x * 3;
192     *new_y = orig_y * 3;
193     *need_inter_vid = 1;
194 
195     dr_spec->active_first_x = 0;
196     dr_spec->active_first_y = 8;
197     dr_spec->active_last_x  = 3*orig_x - 1;
198     dr_spec->active_last_y  = 3*orig_y - 9;
199 
200     dr_spec->x_step         = 16;
201     dr_spec->y_step         = 32;
202 
203     dr_spec->pitch          = 3*orig_x;
204 
205     dr_spec->bord_first_x   = 0;
206     dr_spec->bord_first_y   = 0;
207     dr_spec->bord_last_x    = 3*orig_x - 1;
208     dr_spec->bord_last_y    = 3*orig_y - 1;
209 
210     return pvt;
211 }
212 
gfx_prescaler_scale3x(const uint8_t * RESTRICT src,uint8_t * RESTRICT dst,void * RESTRICT opaque)213 LOCAL void  gfx_prescaler_scale3x(const uint8_t *RESTRICT src,
214                                         uint8_t *RESTRICT dst,
215                                            void *RESTRICT opaque)
216 {
217     gfx_prescaler_typ_pvt_t *pvt = (gfx_prescaler_typ_pvt_t *)opaque;
218     int orig_x    = pvt->orig_x,
219         orig_y    = pvt->orig_y,
220         src_pitch = orig_x,
221         dst_pitch = orig_x * 3;
222     const uint8_t *src_prev = src;
223     const uint8_t *src_curr = src;
224     const uint8_t *src_next = src + src_pitch;
225     int y;
226 
227     scale3x_8_def((scale3x_uint8 *)(dst                ),
228                   (scale3x_uint8 *)(dst + dst_pitch * 2),
229                   (scale3x_uint8 *)(dst + dst_pitch * 3),
230                   (const scale3x_uint8 *)src_prev,
231                   (const scale3x_uint8 *)src_curr,
232                   (const scale3x_uint8 *)src_next, src_pitch);
233 
234     for (y = 3 ; y < orig_y; y++)
235     {
236         dst      += dst_pitch * 3;
237         src_prev  = src_curr;
238         src_curr  = src_next;
239         src_next += src_pitch;
240 
241         scale3x_8_def((scale3x_uint8 *)(dst                ),
242                       (scale3x_uint8 *)(dst + dst_pitch    ),
243                       (scale3x_uint8 *)(dst + dst_pitch * 2),
244                       (const scale3x_uint8 *)src_prev,
245                       (const scale3x_uint8 *)src_curr,
246                       (const scale3x_uint8 *)src_next, src_pitch);
247     }
248 
249     dst     += dst_pitch * 3;
250     src_prev = src_curr;
251     src_curr = src_next;
252 
253     scale3x_8_def((scale3x_uint8 *)(dst                ),
254                   (scale3x_uint8 *)(dst + dst_pitch * 2),
255                   (scale3x_uint8 *)(dst + dst_pitch * 3),
256                   (const scale3x_uint8 *)src_prev,
257                   (const scale3x_uint8 *)src_curr,
258                   (const scale3x_uint8 *)src_next, src_pitch);
259 
260     return;
261 }
262 
263 /* ------------------------------------------------------------------------ */
264 /*  SCALE4X                                                                 */
265 /* ------------------------------------------------------------------------ */
gfx_prescaler_scale4x_init(int orig_x,int orig_y,int * RESTRICT new_x,int * RESTRICT new_y,int * RESTRICT need_inter_vid,gfx_dirtyrect_spec * RESTRICT dr_spec)266 LOCAL void *gfx_prescaler_scale4x_init(int orig_x, int orig_y,
267                                        int *RESTRICT new_x,
268                                        int *RESTRICT new_y,
269                                        int *RESTRICT need_inter_vid,
270                                        gfx_dirtyrect_spec *RESTRICT dr_spec)
271 {
272     gfx_prescaler_typ_pvt_t *pvt = CALLOC(gfx_prescaler_typ_pvt_t, 1);
273     uint8_t *intermediate = CALLOC(uint8_t, orig_x * 2 * orig_y * 2);
274 
275     if (!pvt || !intermediate)
276     {
277         fprintf(stderr, "Out of memory in gfx_prescale\n");
278         exit(1);
279     }
280 
281     pvt->orig_x       = orig_x;
282     pvt->orig_y       = orig_y;
283     pvt->intermediate = intermediate;
284 
285     *new_x = orig_x * 4;
286     *new_y = orig_y * 4;
287     *need_inter_vid = 1;
288 
289     dr_spec->active_first_x = 0;
290     dr_spec->active_first_y = 8;
291     dr_spec->active_last_x  = 4*orig_x - 1;
292     dr_spec->active_last_y  = 4*orig_y - 9;
293 
294     dr_spec->x_step         = 16;
295     dr_spec->y_step         = 32;
296 
297     dr_spec->pitch          = 4*orig_x;
298 
299     dr_spec->bord_first_x   = 0;
300     dr_spec->bord_first_y   = 0;
301     dr_spec->bord_last_x    = 4*orig_x - 1;
302     dr_spec->bord_last_y    = 4*orig_y - 1;
303 
304     return pvt;
305 }
306 
gfx_prescaler_scale4x(const uint8_t * RESTRICT src,uint8_t * RESTRICT dst,void * RESTRICT opaque)307 LOCAL void gfx_prescaler_scale4x(const uint8_t *RESTRICT src,
308                                        uint8_t *RESTRICT dst,
309                                           void *RESTRICT opaque)
310 {
311     gfx_prescaler_typ_pvt_t *pvt = (gfx_prescaler_typ_pvt_t *)opaque;
312     int orig_x = pvt->orig_x, orig_y = pvt->orig_y;
313     uint8_t *mid = pvt->intermediate;
314 
315     perform_scale2x_8(orig_x,     orig_y,     src, mid);
316     perform_scale2x_8(orig_x * 2, orig_y * 2, mid, dst);
317 }
318 
319 /* ------------------------------------------------------------------------ */
320 /*  SCALEXX destructor                                                      */
321 /* ------------------------------------------------------------------------ */
322 
gfx_prescaler_scalexx_dtor(void * opaque)323 LOCAL void gfx_prescaler_scalexx_dtor(void *opaque)
324 {
325     gfx_prescaler_typ_pvt_t *pvt = (gfx_prescaler_typ_pvt_t *)opaque;
326 
327     if (pvt)
328     {
329         CONDFREE(pvt->intermediate);
330         free(pvt);
331     }
332 
333     return;
334 }
335 
336 /* ------------------------------------------------------------------------ */
337 /*  Rotate-180 Prescaler                                                    */
338 /* ------------------------------------------------------------------------ */
gfx_prescaler_rot180_init(int orig_x,int orig_y,int * RESTRICT new_x,int * RESTRICT new_y,int * RESTRICT need_inter_vid,gfx_dirtyrect_spec * RESTRICT dr_spec)339 LOCAL void *gfx_prescaler_rot180_init(int orig_x, int orig_y,
340                                       int *RESTRICT new_x,
341                                       int *RESTRICT new_y,
342                                       int *RESTRICT need_inter_vid,
343                                       gfx_dirtyrect_spec *RESTRICT dr_spec)
344 {
345     gfx_prescaler_typ_pvt_t *pvt = CALLOC(gfx_prescaler_typ_pvt_t, 1);
346 
347     if (!pvt)
348     {
349         fprintf(stderr, "Out of memory in gfx_prescale\n");
350         exit(1);
351     }
352 
353     pvt->orig_x = orig_x;
354     pvt->orig_y = orig_y;
355     pvt->intermediate = NULL;
356 
357     *new_x = orig_x;
358     *new_y = orig_y;
359     *need_inter_vid = 1;
360 
361     dr_spec->active_first_x = 0;
362     dr_spec->active_first_y = 4;
363     dr_spec->active_last_x  = orig_x - 1;
364     dr_spec->active_last_y  = orig_y - 5;
365 
366     dr_spec->x_step         = 8;
367     dr_spec->y_step         = 16;
368 
369     dr_spec->pitch          = orig_x;
370 
371     dr_spec->bord_first_x   = 0;
372     dr_spec->bord_first_y   = 0;
373     dr_spec->bord_last_x    = orig_x - 1;
374     dr_spec->bord_last_y    = orig_y - 1;
375 
376     return pvt;
377 }
378 
gfx_prescaler_rot180(const uint8_t * RESTRICT src,uint8_t * RESTRICT dst,void * RESTRICT opaque)379 LOCAL void gfx_prescaler_rot180(const uint8_t *RESTRICT src,
380                                       uint8_t *RESTRICT dst,
381                                          void *RESTRICT opaque)
382 {
383     gfx_prescaler_typ_pvt_t *pvt = (gfx_prescaler_typ_pvt_t *)opaque;
384     const uint8_t *RESTRICT ps = src;
385     uint8_t       *RESTRICT pd = dst + pvt->orig_x * pvt->orig_y - 1;
386     int i = pvt->orig_x * pvt->orig_y;
387 
388     while (i-- > 0)
389         *pd-- = *ps++;
390 
391     return;
392 }
393 
gfx_prescaler_rot180_dtor(void * u)394 LOCAL void gfx_prescaler_rot180_dtor(void *u)
395 {
396     UNUSED(u);
397     return;
398 }
399 
400 /* ======================================================================== */
401 /*  Prescaler Registry                                                      */
402 /* ======================================================================== */
403 gfx_prescaler_registry_t gfx_prescaler_registry[] =
404 {
405     {   "None",     gfx_prescaler_null,
406                     gfx_prescaler_null_init,
407                     gfx_prescaler_null_dtor
408     },
409 
410     {   "Scale2x",  gfx_prescaler_scale2x,
411                     gfx_prescaler_scale2x_init,
412                     gfx_prescaler_scalexx_dtor
413     },
414 
415     {   "Scale3x",  gfx_prescaler_scale3x,
416                     gfx_prescaler_scale3x_init,
417                     gfx_prescaler_scalexx_dtor
418     },
419 
420     {   "Scale4x",  gfx_prescaler_scale4x,
421                     gfx_prescaler_scale4x_init,
422                     gfx_prescaler_scalexx_dtor
423     },
424 
425     {   "Rot180",   gfx_prescaler_rot180,
426                     gfx_prescaler_rot180_init,
427                     gfx_prescaler_rot180_dtor
428     },
429 };
430 
431 
432 int gfx_prescaler_registry_size = sizeof(gfx_prescaler_registry) /
433                                   sizeof(gfx_prescaler_registry_t);
434 
435