upscale.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. /*
  2. * upscale.c 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. * (C) 2021 kub <derkub@gmail.com>
  28. */
  29. #include "upscale.h"
  30. /* X x Y -> X*5/4 x Y */
  31. void upscale_clut_nn_x_4_5(u8 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height)
  32. {
  33. int y;
  34. for (y = 0; y < height; y++) {
  35. h_upscale_nn_4_5(di, ds, si, ss, width, f_nop);
  36. }
  37. }
  38. void upscale_rgb_nn_x_4_5(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal)
  39. {
  40. int y;
  41. for (y = 0; y < height; y++) {
  42. h_upscale_nn_4_5(di, ds, si, ss, width, f_pal);
  43. }
  44. }
  45. void upscale_rgb_snn_x_4_5(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal)
  46. {
  47. int y;
  48. for (y = 0; y < height; y++) {
  49. h_upscale_snn_4_5(di, ds, si, ss, width, f_pal);
  50. }
  51. }
  52. void upscale_rgb_bl2_x_4_5(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal)
  53. {
  54. int y;
  55. for (y = 0; y < height; y++) {
  56. h_upscale_bl2_4_5(di, ds, si, ss, width, f_pal);
  57. }
  58. }
  59. void upscale_rgb_bl4_x_4_5(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal)
  60. {
  61. int y;
  62. for (y = 0; y < height; y++) {
  63. h_upscale_bl4_4_5(di, ds, si, ss, width, f_pal);
  64. }
  65. }
  66. /* X x Y -> X*5/4 x Y*17/16 */
  67. void upscale_clut_nn_x_4_5_y_16_17(u8 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height)
  68. {
  69. int swidth = width * 5/4;
  70. int y, j;
  71. for (y = 0; y < height; y += 16) {
  72. for (j = 0; j < 8; j++) {
  73. h_upscale_nn_4_5(di, ds, si, ss, width, f_nop);
  74. }
  75. di += ds;
  76. for (j = 0; j < 8; j++) {
  77. h_upscale_nn_4_5(di, ds, si, ss, width, f_nop);
  78. }
  79. di -= 9*ds;
  80. v_copy(&di[0], &di[-ds], swidth, f_nop);
  81. di += 9*ds;
  82. }
  83. }
  84. 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)
  85. {
  86. int swidth = width * 5/4;
  87. int y, j;
  88. for (y = 0; y < height; y += 16) {
  89. for (j = 0; j < 8; j++) {
  90. h_upscale_nn_4_5(di, ds, si, ss, width, f_pal);
  91. }
  92. di += ds;
  93. for (j = 0; j < 8; j++) {
  94. h_upscale_nn_4_5(di, ds, si, ss, width, f_pal);
  95. }
  96. di -= 9*ds;
  97. v_copy(&di[0], &di[-ds], swidth, f_nop);
  98. di += 9*ds;
  99. }
  100. }
  101. 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)
  102. {
  103. int swidth = width * 5/4;
  104. int y, j;
  105. for (y = 0; y < height; y += 16) {
  106. for (j = 0; j < 8; j++) {
  107. h_upscale_snn_4_5(di, ds, si, ss, width, f_pal);
  108. }
  109. di += ds;
  110. for (j = 0; j < 8; j++) {
  111. h_upscale_snn_4_5(di, ds, si, ss, width, f_pal);
  112. }
  113. /* mix lines 6-8 */
  114. di -= 9*ds;
  115. v_mix(&di[0], &di[-ds], &di[ds], swidth, p_05, f_nop);
  116. v_mix(&di[-ds], &di[-2*ds], &di[-ds], swidth, p_05, f_nop);
  117. v_mix(&di[ ds], &di[ ds], &di[ 2*ds], swidth, p_05, f_nop);
  118. di += 9*ds;
  119. }
  120. }
  121. 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)
  122. {
  123. int swidth = width * 5/4;
  124. int y, j;
  125. for (y = 0; y < height; y += 16) {
  126. for (j = 0; j < 4; j++) {
  127. h_upscale_bl2_4_5(di, ds, si, ss, width, f_pal);
  128. }
  129. di += ds;
  130. for (j = 0; j < 12; j++) {
  131. h_upscale_bl2_4_5(di, ds, si, ss, width, f_pal);
  132. }
  133. /* mix lines 3-10 */
  134. di -= 13*ds;
  135. v_mix(&di[0], &di[-ds], &di[ds], swidth, p_05, f_nop);
  136. for (j = 0; j < 7; j++) {
  137. di += ds;
  138. v_mix(&di[0], &di[0], &di[ds], swidth, p_05, f_nop);
  139. }
  140. di += 6*ds;
  141. }
  142. }
  143. 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)
  144. {
  145. int swidth = width * 5/4;
  146. int y, j;
  147. for (y = 0; y < height; y += 16) {
  148. for (j = 0; j < 2; j++) {
  149. h_upscale_bl4_4_5(di, ds, si, ss, width, f_pal);
  150. }
  151. di += ds;
  152. for (j = 0; j < 14; j++) {
  153. h_upscale_bl4_4_5(di, ds, si, ss, width, f_pal);
  154. }
  155. di -= 15*ds;
  156. /* mixing line 2: line 1 = -ds, line 2 = +ds */
  157. v_mix(&di[0], &di[-ds], &di[ds], swidth, p_025, f_nop);
  158. di += ds;
  159. /* mixing lines 3-5: line n-1 = 0, line n = +ds */
  160. for (j = 0; j < 3; j++) {
  161. v_mix(&di[0], &di[0], &di[ds], swidth, p_025, f_nop);
  162. di += ds;
  163. }
  164. /* mixing lines 6-9 */
  165. for (j = 0; j < 4; j++) {
  166. v_mix(&di[0], &di[0], &di[ds], swidth, p_05, f_nop);
  167. di += ds;
  168. }
  169. /* mixing lines 10-13 */
  170. for (j = 0; j < 4; j++) {
  171. v_mix(&di[0], &di[0], &di[ds], swidth, p_075, f_nop);
  172. di += ds;
  173. }
  174. /* lines 14-16, already in place */
  175. di += 3*ds;
  176. }
  177. }
  178. /* "classic" upscaler as found in several emulators. It's really more like a
  179. * x*4/3, y*16/15 upscaler, with an additional 5th row/17th line just inserted
  180. * from the source image. That gives nice n/4,n/16 alpha values plus better
  181. * symmetry in each block and avoids "borrowing" a row/line between blocks.
  182. */
  183. void upscale_rgb_bln_x_4_5_y_16_17(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal)
  184. {
  185. int swidth = width * 5/4;
  186. int y, j;
  187. for (y = 0; y < height; y += 16) {
  188. for (j = 0; j < 4; j++) {
  189. h_upscale_bln_4_5(di, ds, si, ss, width, f_pal);
  190. }
  191. di += ds;
  192. for (j = 0; j < 12; j++) {
  193. h_upscale_bln_4_5(di, ds, si, ss, width, f_pal);
  194. }
  195. di -= 13*ds;
  196. /* mixing line 4: line 3 = -ds, line 4 = +ds */
  197. v_mix(&di[0], &di[-ds], &di[ds], swidth, p_025, f_nop);
  198. di += ds;
  199. /* mixing lines 5-6: line n-1 = 0, line n = +ds */
  200. for (j = 0; j < 2; j++) {
  201. v_mix(&di[0], &di[0], &di[ds], swidth, p_025, f_nop);
  202. di += ds;
  203. }
  204. /* mixing line 7-9 */
  205. for (j = 0; j < 3; j++) {
  206. v_mix(&di[0], &di[0], &di[ds], swidth, p_05, f_nop);
  207. di += ds;
  208. }
  209. /* mixing lines 10-12 */
  210. for (j = 0; j < 3; j++) {
  211. v_mix(&di[0], &di[0], &di[ds], swidth, p_075, f_nop);
  212. di += ds;
  213. }
  214. /* lines 13-16, already in place */
  215. di += 4*ds;
  216. }
  217. }
  218. /* experimental 8 level bilinear for quality assessment */
  219. void upscale_rgb_bl8_x_4_5_y_16_17(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal)
  220. {
  221. int swidth = width * 5/4;
  222. int y, j;
  223. for (y = 0; y < 224; y += 16) {
  224. for (j = 0; j < 2; j++) {
  225. h_upscale_bl8_4_5(di, ds, si, ss, width, f_pal);
  226. }
  227. di += ds;
  228. for (j = 0; j < 14; j++) {
  229. h_upscale_bl8_4_5(di, ds, si, ss, width, f_pal);
  230. }
  231. di -= 15*ds;
  232. /* mixing line 2: line 2 = -ds, line 3 = +ds */
  233. v_mix(&di[0], &di[-ds], &di[ds], swidth, p_0125, f_nop);
  234. di += ds;
  235. /* mixing line 3: line 3 = 0, line 4 = +ds */
  236. v_mix(&di[0], &di[0], &di[ds], swidth, p_0125, f_nop);
  237. di += ds;
  238. /* mixing lines 4-5: line n-1 = 0, line n = +ds */
  239. for (j = 0; j < 2; j++) {
  240. v_mix(&di[0], &di[0], &di[ds], swidth, p_025, f_nop);
  241. di += ds;
  242. }
  243. /* mixing lines 6-7 */
  244. for (j = 0; j < 2; j++) {
  245. v_mix(&di[0], &di[0], &di[ds], 320, p_0375, f_nop);
  246. di += ds;
  247. }
  248. /* mixing lines 8-9 */
  249. for (j = 0; j < 2; j++) {
  250. v_mix(&di[0], &di[0], &di[ds], 320, p_05, f_nop);
  251. di += ds;
  252. }
  253. /* mixing lines 10-11 */
  254. for (j = 0; j < 2; j++) {
  255. v_mix(&di[0], &di[0], &di[ds], 320, p_0625, f_nop);
  256. di += ds;
  257. }
  258. /* mixing lines 12-13 */
  259. for (j = 0; j < 2; j++) {
  260. v_mix(&di[0], &di[0], &di[ds], 320, p_075, f_nop);
  261. di += ds;
  262. }
  263. /* mixing lines 14-15 */
  264. for (j = 0; j < 2; j++) {
  265. v_mix(&di[0], &di[0], &di[ds], 320, p_0875, f_nop);
  266. di += ds;
  267. }
  268. /* line 16, already in place */
  269. di += ds;
  270. }
  271. }
  272. /* X x Y -> X x Y*17/16 */
  273. void upscale_clut_nn_y_16_17(u8 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height)
  274. {
  275. int y, j;
  276. for (y = 0; y < height; y += 16) {
  277. for (j = 0; j < 8; j++) {
  278. h_copy(di, ds, si, ss, width, f_nop);
  279. }
  280. di += ds;
  281. for (j = 0; j < 8; j++) {
  282. h_copy(di, ds, si, ss, width, f_nop);
  283. }
  284. di -= 9*ds;
  285. v_copy(&di[0], &di[-ds], width, f_nop);
  286. di += 9*ds;
  287. }
  288. }
  289. void upscale_rgb_nn_y_16_17(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal)
  290. {
  291. int y, j;
  292. for (y = 0; y < height; y += 16) {
  293. for (j = 0; j < 8; j++) {
  294. h_copy(di, ds, si, ss, width, f_pal);
  295. }
  296. di += ds;
  297. for (j = 0; j < 8; j++) {
  298. h_copy(di, ds, si, ss, width, f_pal);
  299. }
  300. di -= 9*ds;
  301. v_copy(&di[0], &di[-ds], width, f_nop);
  302. di += 9*ds;
  303. }
  304. }
  305. void upscale_rgb_snn_y_16_17(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal)
  306. {
  307. int y, j;
  308. for (y = 0; y < height; y += 16) {
  309. for (j = 0; j < 8; j++) {
  310. h_copy(di, ds, si, ss, width, f_pal);
  311. }
  312. di += ds;
  313. for (j = 0; j < 8; j++) {
  314. h_copy(di, ds, si, ss, width, f_pal);
  315. }
  316. /* mix lines 6-8 */
  317. di -= 9*ds;
  318. v_mix(&di[0], &di[-ds], &di[ds], width, p_05, f_nop);
  319. v_mix(&di[-ds], &di[-2*ds], &di[-ds], width, p_05, f_nop);
  320. v_mix(&di[ ds], &di[ ds], &di[ 2*ds], width, p_05, f_nop);
  321. di += 9*ds;
  322. }
  323. }
  324. void upscale_rgb_bl2_y_16_17(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal)
  325. {
  326. int y, j;
  327. for (y = 0; y < height; y += 16) {
  328. for (j = 0; j < 4; j++) {
  329. h_copy(di, ds, si, ss, width, f_pal);
  330. }
  331. di += ds;
  332. for (j = 0; j < 12; j++) {
  333. h_copy(di, ds, si, ss, width, f_pal);
  334. }
  335. /* mix lines 3-10 */
  336. di -= 13*ds;
  337. v_mix(&di[0], &di[-ds], &di[ds], width, p_05, f_nop);
  338. for (j = 0; j < 7; j++) {
  339. di += ds;
  340. v_mix(&di[0], &di[0], &di[ds], width, p_05, f_nop);
  341. }
  342. di += 6*ds;
  343. }
  344. }
  345. void upscale_rgb_bl4_y_16_17(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal)
  346. {
  347. int y, j;
  348. for (y = 0; y < height; y += 16) {
  349. for (j = 0; j < 2; j++) {
  350. h_copy(di, ds, si, ss, width, f_pal);
  351. }
  352. di += ds;
  353. for (j = 0; j < 14; j++) {
  354. h_copy(di, ds, si, ss, width, f_pal);
  355. }
  356. di -= 15*ds;
  357. /* mixing line 2: line 1 = -ds, line 2 = +ds */
  358. v_mix(&di[0], &di[-ds], &di[ds], width, p_025, f_nop);
  359. di += ds;
  360. /* mixing lines 3-5: line n-1 = 0, line n = +ds */
  361. for (j = 0; j < 3; j++) {
  362. v_mix(&di[0], &di[0], &di[ds], width, p_025, f_nop);
  363. di += ds;
  364. }
  365. /* mixing lines 6-9 */
  366. for (j = 0; j < 4; j++) {
  367. v_mix(&di[0], &di[0], &di[ds], width, p_05, f_nop);
  368. di += ds;
  369. }
  370. /* mixing lines 10-13 */
  371. for (j = 0; j < 4; j++) {
  372. v_mix(&di[0], &di[0], &di[ds], width, p_075, f_nop);
  373. di += ds;
  374. }
  375. /* lines 14-16, already in place */
  376. di += 3*ds;
  377. }
  378. }
  379. /* X x Y -> X*2/1 x Y, e.g. for X 160->320 (GG) */
  380. void upscale_clut_nn_x_1_2(u8 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height)
  381. {
  382. int y;
  383. for (y = 0; y < height; y++) {
  384. h_upscale_nn_1_2(di, ds, si, ss, width, f_nop);
  385. }
  386. }
  387. void upscale_rgb_nn_x_1_2(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal)
  388. {
  389. int y;
  390. for (y = 0; y < height; y++) {
  391. h_upscale_nn_1_2(di, ds, si, ss, width, f_pal);
  392. }
  393. }
  394. void upscale_rgb_bl2_x_1_2(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal)
  395. {
  396. int y;
  397. for (y = 0; y < height; y++) {
  398. h_upscale_bl2_1_2(di, ds, si, ss, width, f_pal);
  399. }
  400. }
  401. /* X x Y -> X*2/1 x Y*5/3 (GG) */
  402. void upscale_clut_nn_x_1_2_y_3_5(u8 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height)
  403. {
  404. int swidth = width * 2;
  405. int y, j;
  406. for (y = 0; y < height; y += 3) {
  407. /* lines 0,2,4 */
  408. for (j = 0; j < 3; j++) {
  409. h_upscale_nn_1_2(di, ds, si, ss, width, f_nop);
  410. di += ds;
  411. }
  412. /* lines 1,3 */
  413. di -= 5*ds;
  414. for (j = 0; j < 2; j++) {
  415. v_copy(&di[0], &di[-ds], swidth, f_nop);
  416. di += 2*ds;
  417. }
  418. }
  419. }
  420. 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)
  421. {
  422. int swidth = width * 2;
  423. int y, j;
  424. for (y = 0; y < height; y += 3) {
  425. for (j = 0; j < 3; j++) {
  426. h_upscale_nn_1_2(di, ds, si, ss, width, f_pal);
  427. di += ds;
  428. }
  429. di -= 5*ds;
  430. for (j = 0; j < 2; j++) {
  431. v_copy(&di[0], &di[-ds], swidth, f_nop);
  432. di += 2*ds;
  433. }
  434. }
  435. }
  436. 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)
  437. {
  438. int swidth = width * 2;
  439. int y, j;
  440. for (y = 0; y < height; y += 3) {
  441. for (j = 0; j < 3; j++) {
  442. h_upscale_bl2_1_2(di, ds, si, ss, width, f_pal);
  443. di += ds;
  444. }
  445. di -= 5*ds;
  446. for (j = 0; j < 2; j++) {
  447. v_mix(&di[0], &di[-ds], &di[ds], swidth, p_05, f_nop);
  448. di += 2*ds;
  449. }
  450. }
  451. }
  452. 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)
  453. {
  454. int swidth = width * 2;
  455. int y, j, d;
  456. /* for 1st block backwards reference virtually duplicate source line 0 */
  457. for (y = 0, d = 2*ds; y < height; y += 3, d = -ds) {
  458. di += 2*ds;
  459. for (j = 0; j < 3; j++) {
  460. h_upscale_bl2_1_2(di, ds, si, ss, width, f_pal);
  461. }
  462. di -= 5*ds;
  463. v_mix(&di[0], &di[d ], &di[2*ds], swidth, p_05, f_nop); /*-1+0 */
  464. di += ds;
  465. v_mix(&di[0], &di[ds], &di[2*ds], swidth, p_075, f_nop);/* 0+1 */
  466. di += ds;
  467. v_mix(&di[0], &di[ 0], &di[ ds], swidth, p_025, f_nop);/* 0+1 */
  468. di += ds;
  469. v_mix(&di[0], &di[ 0], &di[ ds], swidth, p_05, f_nop); /* 1+2 */
  470. di += 2*ds;
  471. }
  472. }
  473. /* X x Y -> X x Y*5/3, e.g. for Y 144->240 (GG) */
  474. void upscale_clut_nn_y_3_5(u8 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height)
  475. {
  476. int y, j;
  477. for (y = 0; y < height; y += 3) {
  478. /* lines 0,2,4 */
  479. for (j = 0; j < 3; j++) {
  480. h_copy(di, ds, si, ss, width, f_nop);
  481. di += ds;
  482. }
  483. /* lines 1,3 */
  484. di -= 5*ds;
  485. for (j = 0; j < 2; j++) {
  486. v_copy(&di[0], &di[-ds], width, f_nop);
  487. di += 2*ds;
  488. }
  489. }
  490. }
  491. void upscale_rgb_nn_y_3_5(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal)
  492. {
  493. int y, j;
  494. for (y = 0; y < height; y += 3) {
  495. for (j = 0; j < 3; j++) {
  496. h_copy(di, ds, si, ss, width, f_pal);
  497. di += ds;
  498. }
  499. di -= 5*ds;
  500. for (j = 0; j < 2; j++) {
  501. v_copy(&di[0], &di[-ds], width, f_nop);
  502. di += 2*ds;
  503. }
  504. }
  505. }
  506. void upscale_rgb_bl2_y_3_5(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal)
  507. {
  508. int y, j;
  509. for (y = 0; y < height; y += 3) {
  510. for (j = 0; j < 3; j++) {
  511. h_copy(di, ds, si, ss, width, f_pal);
  512. di += ds;
  513. }
  514. di -= 5*ds;
  515. for (j = 0; j < 2; j++) {
  516. v_mix(&di[0], &di[-ds], &di[ds], width, p_05, f_nop);
  517. di += 2*ds;
  518. }
  519. }
  520. }
  521. void upscale_rgb_bl4_y_3_5(u16 *__restrict di, int ds, u8 *__restrict si, int ss, int width, int height, u16 *pal)
  522. {
  523. int y, j, d;
  524. /* for 1st block backwards reference virtually duplicate source line 0 */
  525. for (y = 0, d = 2*ds; y < height; y += 3, d = -ds) {
  526. di += 2*ds;
  527. for (j = 0; j < 3; j++) {
  528. h_copy(di, ds, si, ss, width, f_pal);
  529. }
  530. di -= 5*ds;
  531. v_mix(&di[0], &di[d ], &di[2*ds], width, p_05, f_nop); /*-1+0 */
  532. di += ds;
  533. v_mix(&di[0], &di[ds], &di[2*ds], width, p_075, f_nop);/* 0+1 */
  534. di += ds;
  535. v_mix(&di[0], &di[ 0], &di[ ds], width, p_025, f_nop);/* 0+1 */
  536. di += ds;
  537. v_mix(&di[0], &di[ 0], &di[ ds], width, p_05, f_nop); /* 1+2 */
  538. di += 2*ds;
  539. }
  540. }