upscale.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. /*
  2. * upscale.h image upscaling
  3. *
  4. * This file contains upscalers for picodrive.
  5. *
  6. * scaler types:
  7. * nn: nearest neighbour
  8. * snn: "smoothed" nearest neighbour (see below)
  9. * bln: n-level-bilinear with n quantized weights
  10. * quantization: 0: a<1/(2*n), 1/n: 1/(2*n)<=a<3/(2*n), etc
  11. * currently n=2, n=4 are implemented (there's n=8 mixing, but no filters)
  12. * [NB this has been brought to my attn, which is probably the same as bl2:
  13. * https://www.drdobbs.com/image-scaling-with-bresenham/184405045?pgno=1]
  14. *
  15. * "smoothed" nearest neighbour: uses the average of the source pixels if no
  16. * source pixel covers more than 65% of the result pixel. It definitely
  17. * looks better than nearest neighbour and is still quite fast. It creates
  18. * a sharper look than a bilinear filter, at the price of some visible jags
  19. * on diagonal edges.
  20. *
  21. * example scaling modes:
  22. * 256x_Y_ -> 320x_Y_, H32/mode 4, PAR 5:4, for PAL DAR 4:3 (NTSC 7% aspect err)
  23. * 256x224 -> 320x240, H32/mode 4, PAR 5:4, for NTSC DAR 4:3 (PAL 7% aspect err)
  24. * 320x224 -> 320x240, PAR 1:1, for NTSC, DAR 4:3 (PAL 7% etc etc...)
  25. * 160x144 -> 320x240: GG, PAR 6:5, scaling to 320x240 for DAR 4:3
  26. *
  27. *
  28. * (C) 2021 kub <derkub@gmail.com>
  29. *
  30. * This work is licensed under the terms of any of these licenses
  31. * (at your option):
  32. * - GNU GPL, version 2 or later.
  33. * - MAME license.
  34. * See COPYING file in the top-level directory.
  35. */
  36. #include <pico/pico_types.h>
  37. /* LSB of all colors in a pixel */
  38. #if defined(USE_BGR555)
  39. #define PXLSB 0x0421
  40. #else
  41. #define PXLSB 0x0821
  42. #endif
  43. /* RGB565 pixel mixing, see https://www.compuphase.com/graphic/scale3.htm and
  44. http://blargg.8bitalley.com/info/rgb_mixing.html */
  45. /* 2-level mixing */
  46. //#define p_05(d,p1,p2) d=(((p1)+(p2) + ( ((p1)^(p2))&PXLSB))>>1) // round up
  47. //#define p_05(d,p1,p2) d=(((p1)+(p2) - ( ((p1)^(p2))&PXLSB))>>1) // round down
  48. #define p_05(d,p1,p2) d=(((p1)&(p2)) + ((((p1)^(p2))&~PXLSB)>>1))
  49. /* 4-level mixing, 2 times slower */
  50. // 1/4*p1 + 3/4*p2 = 1/2*(1/2*(p1+p2) + p2)
  51. #define p_025(d,p1,p2) p_05(t, p1, p2); p_05( d, t, p2)
  52. #define p_075(d,p1,p2) p_025(d,p2,p1)
  53. /* 8-level mixing, 3 times slower */
  54. // 1/8*p1 + 7/8*p2 = 1/2*(1/2*(1/2*(p1+p2) + p2) + p2)
  55. #define p_0125(d,p1,p2) p_05(t, p1, p2); p_05( u, t, p2); p_05( d, u, p2)
  56. // 3/8*p1 + 5/8*p2 = 1/2*(1/2*(1/2*(p1+p2) + p2) + 1/2*(p1+p2))
  57. #define p_0375(d,p1,p2) p_05(t, p1, p2); p_05( u, t, p2); p_05( d, u, t)
  58. #define p_0625(d,p1,p2) p_0375(d,p2,p1)
  59. #define p_0875(d,p1,p2) p_0125(d,p2,p1)
  60. /* pixel transforms */
  61. #define f_pal(v) pal[v] // convert CLUT index -> RGB565
  62. #define f_nop(v) (v) // source already in dest format (CLUT/RGB)
  63. #define f_or(v) (v|pal) // CLUT, add palette selection
  64. /*
  65. scalers h:
  66. 256->320: - (4:5) (256x224/240 -> 320x224/240)
  67. 256->299: - (6:7) (256x224 -> 299x224, alt?)
  68. 160->320: - (1:2) 2x (160x144 -> 320x240, GG)
  69. 160->288: - (5:9) (160x144 -> 288x216, GG alt?)
  70. */
  71. /* scale 4:5 */
  72. #define h_upscale_nn_4_5(di,ds,si,ss,w,f) do { \
  73. int i; \
  74. for (i = w/4; i > 0; i--, si += 4, di += 5) { \
  75. di[0] = f(si[0]); \
  76. di[1] = f(si[1]); \
  77. di[2] = f(si[1]); \
  78. di[3] = f(si[2]); \
  79. di[4] = f(si[3]); \
  80. } \
  81. di += ds - w/4*5; \
  82. si += ss - w; \
  83. } while (0)
  84. // reverse version for overlapping buffers
  85. #define rh_upscale_nn_4_5(di,ds,si,ss,w,f) do { \
  86. int i; \
  87. di += w/4*5; \
  88. si += w; \
  89. for (i = w/4; i > 0; i--, si -= 4, di -= 5) { \
  90. di[-1] = f(si[-1]); \
  91. di[-2] = f(si[-2]); \
  92. di[-3] = f(si[-3]); \
  93. di[-4] = f(si[-3]); \
  94. di[-5] = f(si[-4]); \
  95. } \
  96. di += ds; \
  97. si += ss; \
  98. } while (0)
  99. #define h_upscale_snn_4_5(di,ds,si,ss,w,f) do { \
  100. int i; \
  101. for (i = w/4; i > 0; i--, si += 4, di += 5) { \
  102. di[0] = f(si[0]); \
  103. di[1] = f(si[1]); \
  104. p_05(di[2], f(si[1]),f(si[2])); \
  105. di[3] = f(si[2]); \
  106. di[4] = f(si[3]); \
  107. } \
  108. di += ds - w/4*5; \
  109. si += ss - w; \
  110. } while (0)
  111. #define h_upscale_bln_4_5(di,ds,si,ss,w,f) do { \
  112. int i; u16 t; \
  113. for (i = w/4; i > 0; i--, si += 4, di += 5) { \
  114. di[0] = f(si[0]); \
  115. p_025(di[1], f(si[0]),f(si[1])); \
  116. p_05 (di[2], f(si[1]),f(si[2])); \
  117. p_075(di[3], f(si[2]),f(si[3])); \
  118. di[4] = f(si[3]); \
  119. } \
  120. di += ds - w/4*5; \
  121. si += ss - w; \
  122. } while (0)
  123. #define h_upscale_bl2_4_5(di,ds,si,ss,w,f) do { \
  124. int i; \
  125. for (i = w/4; i > 0; i--, si += 4, di += 5) { \
  126. di[0] = f(si[0]); \
  127. p_05(di[1], f(si[0]),f(si[1])); \
  128. p_05(di[2], f(si[1]),f(si[2])); \
  129. di[3] = f(si[2]); \
  130. di[4] = f(si[3]); \
  131. } \
  132. di += ds - w/4*5; \
  133. si += ss - w; \
  134. } while (0)
  135. #define h_upscale_bl4_4_5(di,ds,si,ss,w,f) do { \
  136. int i; u16 t, p = f(si[0]); \
  137. for (i = w/4; i > 0; i--, si += 4, di += 5) { \
  138. p_025(di[0], p, f(si[0])); \
  139. p_05 (di[1], f(si[0]),f(si[1])); \
  140. p_05 (di[2], f(si[1]),f(si[2])); \
  141. p_075(di[3], f(si[2]),f(si[3])); \
  142. di[4] = p = f(si[3]); \
  143. } \
  144. di += ds - w/4*5; \
  145. si += ss - w; \
  146. } while (0)
  147. #define h_upscale_bl8_4_5(di,ds,si,ss,w,f) do { \
  148. int i; u16 t, u, p = f(si[0]); \
  149. for (i = w/4; i > 0; i--, si += 4, di += 5) { \
  150. p_025 (di[0], p, f(si[0])); \
  151. p_0375(di[1], f(si[0]),f(si[1])); \
  152. p_0625(di[2], f(si[1]),f(si[2])); \
  153. p_075 (di[3], f(si[2]),f(si[3])); \
  154. di[4] = p = f(si[3]); \
  155. } \
  156. di += ds - w/4*5; \
  157. si += ss - w; \
  158. } while (0)
  159. /* scale 6:7 */
  160. #define h_upscale_nn_6_7(di,ds,si,ss,w,f) do { \
  161. int i; \
  162. for (i = w/6; i > 0; i--, si += 6, di += 7) { \
  163. di[0] = f(si[0]); \
  164. di[1] = f(si[1]); \
  165. di[2] = f(si[2]); \
  166. di[3] = f(si[2]); \
  167. di[4] = f(si[3]); \
  168. di[5] = f(si[4]); \
  169. di[6] = f(si[5]); \
  170. } \
  171. di += ds - w/6*7; \
  172. si += ss - w; \
  173. } while (0)
  174. // reverse version for overlapping buffers
  175. #define rh_upscale_nn_6_7(di,ds,si,ss,w,f) do { \
  176. int i; \
  177. di += w/6*7; \
  178. si += w; \
  179. for (i = w/6; i > 0; i--, si -= 6, di -= 7) { \
  180. di[-1] = f(si[-1]); \
  181. di[-2] = f(si[-2]); \
  182. di[-3] = f(si[-3]); \
  183. di[-4] = f(si[-4]); \
  184. di[-5] = f(si[-4]); \
  185. di[-6] = f(si[-5]); \
  186. di[-7] = f(si[-6]); \
  187. } \
  188. di += ds; \
  189. si += ss; \
  190. } while (0)
  191. #define h_upscale_snn_6_7(di,ds,si,ss,w,f) do { \
  192. int i; \
  193. for (i = w/6; i > 0; i--, si += 6, di += 7) { \
  194. di[0] = f(si[0]); \
  195. di[1] = f(si[1]); \
  196. di[2] = f(si[2]); \
  197. p_05(di[3], f(si[2]),f(si[3])); \
  198. di[4] = f(si[3]); \
  199. di[5] = f(si[4]); \
  200. di[6] = f(si[5]); \
  201. } \
  202. di += ds - w/6*7; \
  203. si += ss - w; \
  204. } while (0)
  205. #define h_upscale_bl2_6_7(di,ds,si,ss,w,f) do { \
  206. int i; \
  207. for (i = w/6; i > 0; i--, si += 6, di += 7) { \
  208. di[0] = f(si[0]); \
  209. p_05(di[1], f(si[0]),f(si[1])); \
  210. p_05(di[2], f(si[1]),f(si[2])); \
  211. p_05(di[3], f(si[2]),f(si[3])); \
  212. p_05(di[4], f(si[3]),f(si[4])); \
  213. di[5] = f(si[4]); \
  214. di[6] = f(si[5]); \
  215. } \
  216. di += ds - w/6*7; \
  217. si += ss - w; \
  218. } while (0)
  219. #define h_upscale_bl4_6_7(di,ds,si,ss,w,f) do { \
  220. int i; u16 t p = f(si[0]); \
  221. for (i = w/6; i > 0; i--, si += 6, di += 7) { \
  222. p_025(di[0], p, f(si[0])); \
  223. p_025(di[1], f(si[0]),f(si[1])); \
  224. p_05 (di[2], f(si[1]),f(si[2])); \
  225. p_05 (di[3], f(si[2]),f(si[3])); \
  226. p_075(di[4], f(si[3]),f(si[4])); \
  227. p_075(di[5], f(si[4]),f(si[5])); \
  228. di[6] = p = f(si[5]); \
  229. } \
  230. di += ds - w/6*7; \
  231. si += ss - w; \
  232. } while (0)
  233. /* scale 5:9 */
  234. #define h_upscale_nn_5_9(di,ds,si,ss,w,f) do { \
  235. int i; \
  236. for (i = w/5; i > 0; i--, si += 5, di += 9) { \
  237. di[0] = f(si[0]); \
  238. di[1] = f(si[0]); \
  239. di[2] = f(si[1]); \
  240. di[3] = f(si[1]); \
  241. di[4] = f(si[2]); \
  242. di[5] = f(si[3]); \
  243. di[6] = f(si[3]); \
  244. di[7] = f(si[4]); \
  245. di[8] = f(si[4]); \
  246. } \
  247. di += ds - w/5*9; \
  248. si += ss - w; \
  249. } while (0)
  250. #define h_upscale_snn_5_9(di,ds,si,ss,w,f) do { \
  251. int i; \
  252. for (i = w/5; i > 0; i--, si += 5, di += 9) { \
  253. di[0] = f(si[0]); \
  254. di[1] = f(si[0]); \
  255. di[2] = f(si[1]); \
  256. p_05(di[3], f(si[1]),f(si[2])); \
  257. di[4] = f(si[2]); \
  258. p_05(di[5], f(si[2]),f(si[3])); \
  259. di[6] = f(si[3]); \
  260. di[7] = f(si[4]); \
  261. di[8] = f(si[4]); \
  262. } \
  263. di += ds - w/5*9; \
  264. si += ss - w; \
  265. } while (0)
  266. #define h_upscale_bl2_5_9(di,ds,si,ss,w,f) do { \
  267. int i; \
  268. for (i = w/5; i > 0; i--, si += 5, di += 9) { \
  269. di[0] = f(si[0]); \
  270. p_05(di[1], f(si[0]),f(si[1])); \
  271. di[2] = f(si[1]); \
  272. p_05(di[3], f(si[1]),f(si[2])); \
  273. di[4] = f(si[2]); \
  274. p_05(di[5], f(si[2]),f(si[3])); \
  275. di[6] = f(si[3]); \
  276. p_05(di[7], f(si[3]),f(si[4])); \
  277. di[8] = f(si[4]); \
  278. } \
  279. di += ds - w/5*9; \
  280. si += ss - w; \
  281. } while (0)
  282. #define h_upscale_bl4_5_9(di,ds,si,ss,w,f) do { \
  283. int i; u16 t, p = f(si[0]); \
  284. for (i = w/5; i > 0; i--, si += 5, di += 9) { \
  285. p_05 (di[0], p, f(si[0])); \
  286. di[1] = f(si[0]); \
  287. p_025(di[2], f(si[0]),f(si[1])); \
  288. p_075(di[3], f(si[1]),f(si[2])); \
  289. p_025(di[4], f(si[1]),f(si[2])); \
  290. p_075(di[5], f(si[2]),f(si[3])); \
  291. di[6] = f(si[3]); \
  292. p_05 (di[7], f(si[3]),f(si[4])); \
  293. di[8] = p = f(si[4]); \
  294. } \
  295. di += ds - w/5*9; \
  296. si += ss - w; \
  297. } while (0)
  298. /* scale 1:2 integer scale */
  299. #define h_upscale_nn_1_2(di,ds,si,ss,w,f) do { \
  300. int i; \
  301. for (i = w/2; i > 0; i--, si += 2, di += 4) { \
  302. di[0] = f(si[0]); \
  303. di[1] = f(si[0]); \
  304. di[2] = f(si[1]); \
  305. di[3] = f(si[1]); \
  306. } \
  307. di += ds - w*2; \
  308. si += ss - w; \
  309. } while (0)
  310. // reverse version for overlapping buffers
  311. #define rh_upscale_nn_1_2(di,ds,si,ss,w,f) do { \
  312. int i; \
  313. di += w*2; \
  314. si += w; \
  315. for (i = w/2; i > 0; i--, si -= 2, di -= 4) { \
  316. di[-1] = f(si[-1]); \
  317. di[-2] = f(si[-1]); \
  318. di[-3] = f(si[-2]); \
  319. di[-4] = f(si[-2]); \
  320. } \
  321. di += ds; \
  322. si += ss; \
  323. } while (0)
  324. #define h_upscale_bl2_1_2(di,ds,si,ss,w,f) do { \
  325. int i; uint p = f(si[0]); \
  326. for (i = w/2; i > 0; i--, si += 2, di += 4) { \
  327. p_05 (di[0], p, f(si[0])); \
  328. di[1] = f(si[0]); \
  329. p_05 (di[2], f(si[0]),f(si[1])); \
  330. di[3] = p = f(si[1]); \
  331. } \
  332. di += ds - w*2; \
  333. si += ss - w; \
  334. } while (0)
  335. /* scale 1:1, copy */
  336. #define h_copy(di,ds,si,ss,w,f) do { \
  337. int i; \
  338. for (i = w/4; i > 0; i--, si += 4, di += 4) { \
  339. di[0] = f(si[0]); \
  340. di[1] = f(si[1]); \
  341. di[2] = f(si[2]); \
  342. di[3] = f(si[3]); \
  343. } \
  344. di += ds - w; \
  345. si += ss - w; \
  346. } while (0)
  347. /*
  348. scalers v:
  349. 224->240: - (14:15) (256/320x224 -> 320x240)
  350. 224->238: - (16:17) (256/320x224 -> 320x238 alt?)
  351. 144->240: - (3:5) (160x144 -> 320x240, GG)
  352. 144->216: - (2:3) (160x144 -> 288x216, GG alt?)
  353. */
  354. #define v_mix(di,li,ri,w,p_mix,f) do { \
  355. u16 i, t, u; (void)t, (void)u; \
  356. for (i = 0; i < w; i += 4) { \
  357. p_mix((di)[i ], f((li)[i ]),f((ri)[i ])); \
  358. p_mix((di)[i+1], f((li)[i+1]),f((ri)[i+1])); \
  359. p_mix((di)[i+2], f((li)[i+2]),f((ri)[i+2])); \
  360. p_mix((di)[i+3], f((li)[i+3]),f((ri)[i+3])); \
  361. } \
  362. } while (0)
  363. #define v_copy(di,ri,w,f) do { \
  364. int i; \
  365. for (i = 0; i < w; i += 4) { \
  366. (di)[i ] = f((ri)[i ]); \
  367. (di)[i+1] = f((ri)[i+1]); \
  368. (di)[i+2] = f((ri)[i+2]); \
  369. (di)[i+3] = f((ri)[i+3]); \
  370. } \
  371. } while (0)
  372. /* scale 14:15 */
  373. #define v_upscale_nn_14_15(di,ds,w,l) do { \
  374. if (++l == 7) { \
  375. di += ds; \
  376. } else if (l >= 14) { \
  377. l = 0; \
  378. di -= 7*ds; \
  379. v_copy(&di[0], &di[-ds], w, f_nop); \
  380. di += 7*ds; \
  381. } \
  382. } while (0)
  383. #define v_upscale_snn_14_15(di,ds,w,l) do { \
  384. if (++l == 7) { \
  385. di += ds; \
  386. } else if (l >= 14) { \
  387. l = 0; \
  388. di -= 7*ds; \
  389. v_mix(&di[0], &di[-ds], &di[ds], w, p_05, f_nop); \
  390. v_mix(&di[-ds], &di[-2*ds], &di[-ds], w, p_05, f_nop); \
  391. v_mix(&di[ ds], &di[ ds], &di[ 2*ds], w, p_05, f_nop); \
  392. di += 7*ds; \
  393. } \
  394. } while (0)
  395. #define v_upscale_bl2_14_15(di,ds,w,l) do { \
  396. if (++l == 3) { \
  397. di += ds; \
  398. } else if (l >= 14) { \
  399. int j; \
  400. l = 0; \
  401. di -= 11*ds; \
  402. v_mix(&di[0], &di[-ds], &di[ds], w, p_05, f_nop); \
  403. for (j = 0; j < 7; j++) { \
  404. di += ds; \
  405. v_mix(&di[0], &di[0], &di[ds], w, p_05, f_nop); \
  406. } \
  407. di += 4*ds; \
  408. } \
  409. } while (0)
  410. #define v_upscale_bl4_14_15(di,ds,w,l) do { \
  411. if (++l == 1) { \
  412. di += ds; \
  413. } else if (l >= 14) { \
  414. int j; \
  415. l = 0; \
  416. di -= 13*ds; \
  417. v_mix(&di[0], &di[-ds], &di[ds], w, p_025, f_nop); \
  418. di += ds; \
  419. for (j = 0; j < 3; j++) { \
  420. v_mix(&di[0], &di[0], &di[ds], w, p_025, f_nop); \
  421. di += ds; \
  422. } \
  423. for (j = 0; j < 4; j++) { \
  424. v_mix(&di[0], &di[0], &di[ds], w, p_05, f_nop); \
  425. di += ds; \
  426. } \
  427. for (j = 0; j < 4; j++) { \
  428. v_mix(&di[0], &di[0], &di[ds], w, p_075, f_nop); \
  429. di += ds; \
  430. } \
  431. di += 1*ds; \
  432. } \
  433. } while (0)
  434. /* scale 16:17 */
  435. #define v_upscale_nn_16_17(di,ds,w,l) do { \
  436. if (++l == 8) { \
  437. di += ds; \
  438. } else if (l >= 16) { \
  439. l = 0; \
  440. di -= 8*ds; \
  441. v_copy(&di[0], &di[-ds], w, f_nop); \
  442. di += 8*ds; \
  443. } \
  444. } while (0)
  445. #define v_upscale_snn_16_17(di,ds,w,l) do { \
  446. if (++l == 8) { \
  447. di += ds; \
  448. } else if (l >= 16) { \
  449. l = 0; \
  450. di -= 8*ds; \
  451. v_mix(&di[0], &di[-ds], &di[ds], w, p_05, f_nop); \
  452. v_mix(&di[-ds], &di[-2*ds], &di[-ds], w, p_05, f_nop); \
  453. v_mix(&di[ ds], &di[ ds], &di[ 2*ds], w, p_05, f_nop); \
  454. di += 8*ds; \
  455. } \
  456. } while (0)
  457. #define v_upscale_bl2_16_17(di,ds,w,l) do { \
  458. if (++l == 4) { \
  459. di += ds; \
  460. } else if (l >= 16) { \
  461. int j; \
  462. l = 0; \
  463. di -= 12*ds; \
  464. v_mix(&di[0], &di[-ds], &di[ds], w, p_05, f_nop); \
  465. for (j = 0; j < 7; j++) { \
  466. di += ds; \
  467. v_mix(&di[0], &di[0], &di[ds], w, p_05, f_nop); \
  468. } \
  469. di += 5*ds; \
  470. } \
  471. } while (0)
  472. #define v_upscale_bl4_16_17(di,ds,w,l) do { \
  473. if (++l == 2) { \
  474. di += ds; \
  475. } else if (l >= 16) { \
  476. int j; \
  477. l = 0; \
  478. di -= 14*ds; \
  479. v_mix(&di[0], &di[-ds], &di[ds], w, p_025, f_nop); \
  480. di += ds; \
  481. for (j = 0; j < 3; j++) { \
  482. v_mix(&di[0], &di[0], &di[ds], w, p_025, f_nop); \
  483. di += ds; \
  484. } \
  485. for (j = 0; j < 4; j++) { \
  486. v_mix(&di[0], &di[0], &di[ds], w, p_05, f_nop); \
  487. di += ds; \
  488. } \
  489. for (j = 0; j < 4; j++) { \
  490. v_mix(&di[0], &di[0], &di[ds], w, p_075, f_nop); \
  491. di += ds; \
  492. } \
  493. di += 2*ds; \
  494. } \
  495. } while (0)
  496. /* scale 3:5 */
  497. #define v_upscale_nn_3_5(di,ds,w,l) do { \
  498. if (++l < 3) { \
  499. di += ds; \
  500. } else { \
  501. int j; \
  502. l = 0; \
  503. di -= 3*ds; \
  504. for (j = 0; j < 2; j++) { \
  505. v_copy(&di[0], &di[-ds], w, f_nop); \
  506. di += 2*ds; \
  507. } \
  508. di -= ds; \
  509. } \
  510. } while (0)
  511. #define v_upscale_snn_3_5(di,ds,w,l) do { \
  512. if (++l < 3) { \
  513. di += ds; \
  514. } else { \
  515. int j; \
  516. l = 0; \
  517. di -= 3*ds; \
  518. for (j = 0; j < 2; j++) { \
  519. v_mix(&di[0], &di[-ds], &di[ds], w, p_05, f_nop); \
  520. di += 2*ds; \
  521. } \
  522. di -= ds; \
  523. } \
  524. } while (0)
  525. /* scale 2:3 */
  526. #define v_upscale_nn_2_3(di,ds,w,l) do { \
  527. if (++l < 2) { \
  528. di += ds; \
  529. } else { \
  530. int j; \
  531. l = 0; \
  532. di -= 2*ds; \
  533. v_copy(&di[0], &di[-ds], w, f_nop); \
  534. di += 2*ds; \
  535. } \
  536. } while (0)
  537. #define v_upscale_snn_2_3(di,ds,w,l) do { \
  538. if (++l < 2) { \
  539. di += ds; \
  540. } else { \
  541. int j; \
  542. l = 0; \
  543. di -= 2*ds; \
  544. v_mix(&di[0], &di[-ds], &di[ds], w, p_05, f_nop); \
  545. di += 2*ds; \
  546. } \
  547. } while (0)
  548. /* X x Y -> X*5/4 x Y, for X 256->320 */
  549. void upscale_rgb_nn_x_4_5(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal);
  550. void upscale_rgb_snn_x_4_5(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal);
  551. void upscale_rgb_bl2_x_4_5(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal);
  552. void upscale_rgb_bl4_x_4_5(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal);
  553. /* X x Y -> X x Y*17/16, for Y 224->238 or 192->204 (SMS) */
  554. void upscale_rgb_nn_y_16_17(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal);
  555. void upscale_rgb_snn_y_16_17(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal);
  556. void upscale_rgb_bl2_y_16_17(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal);
  557. void upscale_rgb_bl4_y_16_17(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal);
  558. /* X x Y -> X*5/4 x Y*17/16 */
  559. void upscale_rgb_nn_x_4_5_y_16_17(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal);
  560. void upscale_rgb_snn_x_4_5_y_16_17(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal);
  561. void upscale_rgb_bl2_x_4_5_y_16_17(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal);
  562. void upscale_rgb_bl4_x_4_5_y_16_17(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal);
  563. /* X x Y -> X*2/1 x Y, e.g. for X 160->320 (GG) */
  564. void upscale_rgb_nn_x_1_2(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal);
  565. void upscale_rgb_bl2_x_1_2(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal);
  566. /* X x Y -> X x Y*5/3, e.g. for Y 144->240 (GG) */
  567. void upscale_rgb_nn_y_3_5(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal);
  568. void upscale_rgb_bl2_y_3_5(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal);
  569. void upscale_rgb_bl4_y_3_5(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal);
  570. /* X x Y -> X*2/1 x Y*5/3 (GG) */
  571. void upscale_rgb_nn_x_1_2_y_3_5(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal);
  572. void upscale_rgb_bl2_x_1_2_y_3_5(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal);
  573. void upscale_rgb_bl4_x_1_2_y_3_5(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal);