SDL_stretch.c 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #include "../SDL_internal.h"
  19. /* This a stretch blit implementation based on ideas given to me by
  20. Tomasz Cejner - thanks! :)
  21. April 27, 2000 - Sam Lantinga
  22. */
  23. #include "SDL_video.h"
  24. #include "SDL_blit.h"
  25. #include "SDL_render.h"
  26. /* This isn't ready for general consumption yet - it should be folded
  27. into the general blitting mechanism.
  28. */
  29. #if ((defined(_MSC_VER) && defined(_M_IX86)) || \
  30. (defined(__WATCOMC__) && defined(__386__)) || \
  31. (defined(__GNUC__) && defined(__i386__))) && SDL_ASSEMBLY_ROUTINES
  32. /* There's a bug with gcc 4.4.1 and -O2 where srcp doesn't get the correct
  33. * value after the first scanline. */
  34. /* This bug seems fixed, at least with gcc >= 4.6 */
  35. # define USE_ASM_STRETCH
  36. # if defined(__GNUC__)
  37. # if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6))
  38. # undef USE_ASM_STRETCH
  39. # endif
  40. # endif
  41. #endif
  42. #ifdef USE_ASM_STRETCH
  43. #ifdef HAVE_MPROTECT
  44. #include <sys/types.h>
  45. #include <sys/mman.h>
  46. #endif
  47. #ifdef __GNUC__
  48. #define PAGE_ALIGNED __attribute__((__aligned__(4096)))
  49. #else
  50. #define PAGE_ALIGNED
  51. #endif
  52. #if defined(_M_IX86) || defined(__i386__) || defined(__386__)
  53. #define PREFIX16 0x66
  54. #define STORE_BYTE 0xAA
  55. #define STORE_WORD 0xAB
  56. #define LOAD_BYTE 0xAC
  57. #define LOAD_WORD 0xAD
  58. #define RETURN 0xC3
  59. #else
  60. #error Need assembly opcodes for this architecture
  61. #endif
  62. static unsigned char copy_row[4096] PAGE_ALIGNED;
  63. static int
  64. generate_rowbytes(int src_w, int dst_w, int bpp)
  65. {
  66. static struct
  67. {
  68. int bpp;
  69. int src_w;
  70. int dst_w;
  71. int status;
  72. } last;
  73. int i;
  74. int pos, inc;
  75. unsigned char *eip, *fence;
  76. unsigned char load, store;
  77. /* See if we need to regenerate the copy buffer */
  78. if ((src_w == last.src_w) && (dst_w == last.dst_w) && (bpp == last.bpp)) {
  79. return (last.status);
  80. }
  81. last.bpp = bpp;
  82. last.src_w = src_w;
  83. last.dst_w = dst_w;
  84. last.status = -1;
  85. switch (bpp) {
  86. case 1:
  87. load = LOAD_BYTE;
  88. store = STORE_BYTE;
  89. break;
  90. case 2:
  91. case 4:
  92. load = LOAD_WORD;
  93. store = STORE_WORD;
  94. break;
  95. default:
  96. return SDL_SetError("ASM stretch of %d bytes isn't supported", bpp);
  97. }
  98. #ifdef HAVE_MPROTECT
  99. /* Make the code writeable */
  100. if (mprotect(copy_row, sizeof(copy_row), PROT_READ | PROT_WRITE) < 0) {
  101. return SDL_SetError("Couldn't make copy buffer writeable");
  102. }
  103. #endif
  104. pos = 0x10000;
  105. inc = (src_w << 16) / dst_w;
  106. eip = copy_row;
  107. fence = copy_row + sizeof(copy_row)-2;
  108. for (i = 0; i < dst_w; ++i) {
  109. while (pos >= 0x10000L) {
  110. if (eip == fence) {
  111. return -1;
  112. }
  113. if (bpp == 2) {
  114. *eip++ = PREFIX16;
  115. }
  116. *eip++ = load;
  117. pos -= 0x10000L;
  118. }
  119. if (eip == fence) {
  120. return -1;
  121. }
  122. if (bpp == 2) {
  123. *eip++ = PREFIX16;
  124. }
  125. *eip++ = store;
  126. pos += inc;
  127. }
  128. *eip++ = RETURN;
  129. #ifdef HAVE_MPROTECT
  130. /* Make the code executable but not writeable */
  131. if (mprotect(copy_row, sizeof(copy_row), PROT_READ | PROT_EXEC) < 0) {
  132. return SDL_SetError("Couldn't make copy buffer executable");
  133. }
  134. #endif
  135. last.status = 0;
  136. return (0);
  137. }
  138. #endif /* USE_ASM_STRETCH */
  139. #define DEFINE_COPY_ROW(name, type) \
  140. static void name(type *src, int src_w, type *dst, int dst_w) \
  141. { \
  142. int i; \
  143. int pos, inc; \
  144. type pixel = 0; \
  145. \
  146. pos = 0x10000; \
  147. inc = (src_w << 16) / dst_w; \
  148. for ( i=dst_w; i>0; --i ) { \
  149. while ( pos >= 0x10000L ) { \
  150. pixel = *src++; \
  151. pos -= 0x10000L; \
  152. } \
  153. *dst++ = pixel; \
  154. pos += inc; \
  155. } \
  156. }
  157. /* *INDENT-OFF* */
  158. DEFINE_COPY_ROW(copy_row1, Uint8)
  159. DEFINE_COPY_ROW(copy_row2, Uint16)
  160. DEFINE_COPY_ROW(copy_row4, Uint32)
  161. /* *INDENT-ON* */
  162. /* The ASM code doesn't handle 24-bpp stretch blits */
  163. static void
  164. copy_row3(Uint8 * src, int src_w, Uint8 * dst, int dst_w)
  165. {
  166. int i;
  167. int pos, inc;
  168. Uint8 pixel[3] = { 0, 0, 0 };
  169. pos = 0x10000;
  170. inc = (src_w << 16) / dst_w;
  171. for (i = dst_w; i > 0; --i) {
  172. while (pos >= 0x10000L) {
  173. pixel[0] = *src++;
  174. pixel[1] = *src++;
  175. pixel[2] = *src++;
  176. pos -= 0x10000L;
  177. }
  178. *dst++ = pixel[0];
  179. *dst++ = pixel[1];
  180. *dst++ = pixel[2];
  181. pos += inc;
  182. }
  183. }
  184. static int SDL_LowerSoftStretchNearest(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect);
  185. static int SDL_LowerSoftStretchLinear(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect);
  186. static int SDL_UpperSoftStretch(SDL_Surface * src, const SDL_Rect * srcrect, SDL_Surface * dst, const SDL_Rect * dstrect, SDL_ScaleMode scaleMode);
  187. /* Perform a stretch blit between two surfaces of the same format.
  188. NOTE: This function is not safe to call from multiple threads!
  189. */
  190. int
  191. SDL_SoftStretch(SDL_Surface *src, const SDL_Rect *srcrect,
  192. SDL_Surface *dst, const SDL_Rect *dstrect)
  193. {
  194. return SDL_UpperSoftStretch(src, srcrect, dst, dstrect, SDL_ScaleModeNearest);
  195. }
  196. int
  197. SDL_SoftStretchLinear(SDL_Surface *src, const SDL_Rect *srcrect,
  198. SDL_Surface *dst, const SDL_Rect *dstrect)
  199. {
  200. return SDL_UpperSoftStretch(src, srcrect, dst, dstrect, SDL_ScaleModeLinear);
  201. }
  202. static int
  203. SDL_UpperSoftStretch(SDL_Surface * src, const SDL_Rect * srcrect,
  204. SDL_Surface * dst, const SDL_Rect * dstrect, SDL_ScaleMode scaleMode)
  205. {
  206. int ret;
  207. int src_locked;
  208. int dst_locked;
  209. SDL_Rect full_src;
  210. SDL_Rect full_dst;
  211. if (src->format->format != dst->format->format) {
  212. return SDL_SetError("Only works with same format surfaces");
  213. }
  214. if (scaleMode != SDL_ScaleModeNearest) {
  215. if (src->format->BytesPerPixel != 4 || src->format->format == SDL_PIXELFORMAT_ARGB2101010) {
  216. return SDL_SetError("Wrong format");
  217. }
  218. }
  219. /* Verify the blit rectangles */
  220. if (srcrect) {
  221. if ((srcrect->x < 0) || (srcrect->y < 0) ||
  222. ((srcrect->x + srcrect->w) > src->w) ||
  223. ((srcrect->y + srcrect->h) > src->h)) {
  224. return SDL_SetError("Invalid source blit rectangle");
  225. }
  226. } else {
  227. full_src.x = 0;
  228. full_src.y = 0;
  229. full_src.w = src->w;
  230. full_src.h = src->h;
  231. srcrect = &full_src;
  232. }
  233. if (dstrect) {
  234. if ((dstrect->x < 0) || (dstrect->y < 0) ||
  235. ((dstrect->x + dstrect->w) > dst->w) ||
  236. ((dstrect->y + dstrect->h) > dst->h)) {
  237. return SDL_SetError("Invalid destination blit rectangle");
  238. }
  239. } else {
  240. full_dst.x = 0;
  241. full_dst.y = 0;
  242. full_dst.w = dst->w;
  243. full_dst.h = dst->h;
  244. dstrect = &full_dst;
  245. }
  246. if (dstrect->w <= 0 || dstrect->h <= 0) {
  247. return 0;
  248. }
  249. /* Lock the destination if it's in hardware */
  250. dst_locked = 0;
  251. if (SDL_MUSTLOCK(dst)) {
  252. if (SDL_LockSurface(dst) < 0) {
  253. return SDL_SetError("Unable to lock destination surface");
  254. }
  255. dst_locked = 1;
  256. }
  257. /* Lock the source if it's in hardware */
  258. src_locked = 0;
  259. if (SDL_MUSTLOCK(src)) {
  260. if (SDL_LockSurface(src) < 0) {
  261. if (dst_locked) {
  262. SDL_UnlockSurface(dst);
  263. }
  264. return SDL_SetError("Unable to lock source surface");
  265. }
  266. src_locked = 1;
  267. }
  268. if (scaleMode == SDL_ScaleModeNearest) {
  269. ret = SDL_LowerSoftStretchNearest(src, srcrect, dst, dstrect);
  270. } else {
  271. ret = SDL_LowerSoftStretchLinear(src, srcrect, dst, dstrect);
  272. }
  273. /* We need to unlock the surfaces if they're locked */
  274. if (dst_locked) {
  275. SDL_UnlockSurface(dst);
  276. }
  277. if (src_locked) {
  278. SDL_UnlockSurface(src);
  279. }
  280. return ret;
  281. }
  282. int
  283. SDL_LowerSoftStretchNearest(SDL_Surface *src, const SDL_Rect *srcrect,
  284. SDL_Surface *dst, const SDL_Rect *dstrect)
  285. {
  286. int pos, inc;
  287. int dst_maxrow;
  288. int src_row, dst_row;
  289. Uint8 *srcp = NULL;
  290. Uint8 *dstp;
  291. #ifdef USE_ASM_STRETCH
  292. SDL_bool use_asm = SDL_TRUE;
  293. #ifdef __GNUC__
  294. int u1, u2;
  295. #endif
  296. #endif /* USE_ASM_STRETCH */
  297. const int bpp = dst->format->BytesPerPixel;
  298. /* Set up the data... */
  299. pos = 0x10000;
  300. inc = (srcrect->h << 16) / dstrect->h;
  301. src_row = srcrect->y;
  302. dst_row = dstrect->y;
  303. #ifdef USE_ASM_STRETCH
  304. /* Write the opcodes for this stretch */
  305. if ((bpp == 3) || (generate_rowbytes(srcrect->w, dstrect->w, bpp) < 0)) {
  306. use_asm = SDL_FALSE;
  307. }
  308. #endif
  309. /* Perform the stretch blit */
  310. for (dst_maxrow = dst_row + dstrect->h; dst_row < dst_maxrow; ++dst_row) {
  311. dstp = (Uint8 *) dst->pixels + (dst_row * dst->pitch)
  312. + (dstrect->x * bpp);
  313. while (pos >= 0x10000L) {
  314. srcp = (Uint8 *) src->pixels + (src_row * src->pitch)
  315. + (srcrect->x * bpp);
  316. ++src_row;
  317. pos -= 0x10000L;
  318. }
  319. #ifdef USE_ASM_STRETCH
  320. if (use_asm) {
  321. #ifdef __GNUC__
  322. __asm__ __volatile__("call *%4":"=&D"(u1), "=&S"(u2)
  323. :"0"(dstp), "1"(srcp), "r"(copy_row)
  324. :"memory");
  325. #elif defined(_MSC_VER) || defined(__WATCOMC__)
  326. /* *INDENT-OFF* */
  327. {
  328. void *code = copy_row;
  329. __asm {
  330. push edi
  331. push esi
  332. mov edi, dstp
  333. mov esi, srcp
  334. call dword ptr code
  335. pop esi
  336. pop edi
  337. }
  338. }
  339. /* *INDENT-ON* */
  340. #else
  341. #error Need inline assembly for this compiler
  342. #endif
  343. } else
  344. #endif
  345. switch (bpp) {
  346. case 1:
  347. copy_row1(srcp, srcrect->w, dstp, dstrect->w);
  348. break;
  349. case 2:
  350. copy_row2((Uint16 *) srcp, srcrect->w,
  351. (Uint16 *) dstp, dstrect->w);
  352. break;
  353. case 3:
  354. copy_row3(srcp, srcrect->w, dstp, dstrect->w);
  355. break;
  356. case 4:
  357. copy_row4((Uint32 *) srcp, srcrect->w,
  358. (Uint32 *) dstp, dstrect->w);
  359. break;
  360. }
  361. pos += inc;
  362. }
  363. return 0;
  364. }
  365. /* bilinear interpolation precision must be < 8
  366. Because with SSE: add-multiply: _mm_madd_epi16 works with signed int
  367. so pixels 0xb1...... are negatives and false the result
  368. same in NEON probably */
  369. #define PRECISION 7
  370. #define FIXED_POINT(i) ((uint32_t)(i) << 16)
  371. #define SRC_INDEX(fp) ((uint32_t)(fp) >> 16)
  372. #define INTEGER(fp) ((uint32_t)(fp) >> PRECISION)
  373. #define FRAC(fp) ((uint32_t)(fp >> (16 - PRECISION)) & ((1<<PRECISION) - 1))
  374. #define FRAC_ZERO 0
  375. #define FRAC_ONE (1 << PRECISION)
  376. #define FP_ONE FIXED_POINT(1)
  377. #define BILINEAR___START \
  378. int i; \
  379. int fp_sum_h, fp_step_h, left_pad_h, right_pad_h; \
  380. int fp_sum_w, fp_step_w, left_pad_w, right_pad_w; \
  381. int fp_sum_w_init, left_pad_w_init, right_pad_w_init, dst_gap, middle_init; \
  382. get_scaler_datas(src_h, dst_h, &fp_sum_h, &fp_step_h, &left_pad_h, &right_pad_h); \
  383. get_scaler_datas(src_w, dst_w, &fp_sum_w, &fp_step_w, &left_pad_w, &right_pad_w); \
  384. fp_sum_w_init = fp_sum_w + left_pad_w * fp_step_w; \
  385. left_pad_w_init = left_pad_w; \
  386. right_pad_w_init = right_pad_w; \
  387. dst_gap = dst_pitch - 4 * dst_w; \
  388. middle_init = dst_w - left_pad_w - right_pad_w; \
  389. #define BILINEAR___HEIGHT \
  390. int index_h, frac_h0, frac_h1, middle; \
  391. const Uint32 *src_h0, *src_h1; \
  392. int no_padding, incr_h0, incr_h1; \
  393. \
  394. no_padding = !(i < left_pad_h || i > dst_h - 1 - right_pad_h); \
  395. index_h = SRC_INDEX(fp_sum_h); \
  396. frac_h0 = FRAC(fp_sum_h); \
  397. \
  398. index_h = no_padding ? index_h : (i < left_pad_h ? 0 : src_h - 1); \
  399. frac_h0 = no_padding ? frac_h0 : 0; \
  400. incr_h1 = no_padding ? src_pitch : 0; \
  401. incr_h0 = index_h * src_pitch; \
  402. \
  403. src_h0 = (const Uint32 *)((const Uint8 *)src + incr_h0); \
  404. src_h1 = (const Uint32 *)((const Uint8 *)src_h0 + incr_h1); \
  405. \
  406. fp_sum_h += fp_step_h; \
  407. \
  408. frac_h1 = FRAC_ONE - frac_h0; \
  409. fp_sum_w = fp_sum_w_init; \
  410. right_pad_w = right_pad_w_init; \
  411. left_pad_w = left_pad_w_init; \
  412. middle = middle_init; \
  413. #if defined(__clang__)
  414. // Remove inlining of this function
  415. // Compiler crash with clang 9.0.8 / android-ndk-r21d
  416. // Compiler crash with clang 11.0.3 / Xcode
  417. // OK with clang 11.0.5 / android-ndk-22
  418. // OK with clang 12.0.0 / Xcode
  419. __attribute__((noinline))
  420. #endif
  421. static void
  422. get_scaler_datas(int src_nb, int dst_nb, int *fp_start, int *fp_step, int *left_pad, int *right_pad)
  423. {
  424. int step = FIXED_POINT(src_nb) / (dst_nb); /* source step in fixed point */
  425. int x0 = FP_ONE / 2; /* dst first pixel center at 0.5 in fixed point */
  426. int fp_sum;
  427. int i;
  428. #if 0
  429. /* scale to source coordinates */
  430. x0 *= src_nb;
  431. x0 /= dst_nb; /* x0 == step / 2 */
  432. #else
  433. /* Use this code for perfect match with pixman */
  434. Sint64 tmp[2];
  435. tmp[0] = (Sint64)step * (x0 >> 16);
  436. tmp[1] = (Sint64)step * (x0 & 0xFFFF);
  437. x0 = (int) (tmp[0] + ((tmp[1] + 0x8000) >> 16)); /* x0 == (step + 1) / 2 */
  438. #endif
  439. /* -= 0.5, get back the pixel origin, in source coordinates */
  440. x0 -= FP_ONE / 2;
  441. *fp_start = x0;
  442. *fp_step = step;
  443. *left_pad = 0;
  444. *right_pad = 0;
  445. fp_sum = x0;
  446. for (i = 0; i < dst_nb; i++) {
  447. if (fp_sum < 0) {
  448. *left_pad += 1;
  449. } else {
  450. int index = SRC_INDEX(fp_sum);
  451. if (index > src_nb - 2) {
  452. *right_pad += 1;
  453. }
  454. }
  455. fp_sum += step;
  456. }
  457. // SDL_Log("%d -> %d x0=%d step=%d left_pad=%d right_pad=%d", src_nb, dst_nb, *fp_start, *fp_step, *left_pad, *right_pad);
  458. }
  459. typedef struct color_t {
  460. Uint8 a;
  461. Uint8 b;
  462. Uint8 c;
  463. Uint8 d;
  464. } color_t;
  465. #if 0
  466. static void
  467. printf_64(const char *str, void *var)
  468. {
  469. uint8_t *val = (uint8_t*) var;
  470. printf(" * %s: %02x %02x %02x %02x _ %02x %02x %02x %02x\n",
  471. str, val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7]);
  472. }
  473. #endif
  474. /* Interpolated == x0 + frac * (x1 - x0) == x0 * (1 - frac) + x1 * frac */
  475. static SDL_INLINE void
  476. INTERPOL(const Uint32 *src_x0, const Uint32 *src_x1, int frac0, int frac1, Uint32 *dst)
  477. {
  478. const color_t *c0 = (const color_t *)src_x0;
  479. const color_t *c1 = (const color_t *)src_x1;
  480. color_t *cx = (color_t *)dst;
  481. #if 0
  482. cx->a = c0->a + INTEGER(frac0 * (c1->a - c0->a));
  483. cx->b = c0->b + INTEGER(frac0 * (c1->b - c0->b));
  484. cx->c = c0->c + INTEGER(frac0 * (c1->c - c0->c));
  485. cx->d = c0->d + INTEGER(frac0 * (c1->d - c0->d));
  486. #else
  487. cx->a = INTEGER(frac1 * c0->a + frac0 * c1->a);
  488. cx->b = INTEGER(frac1 * c0->b + frac0 * c1->b);
  489. cx->c = INTEGER(frac1 * c0->c + frac0 * c1->c);
  490. cx->d = INTEGER(frac1 * c0->d + frac0 * c1->d);
  491. #endif
  492. }
  493. static SDL_INLINE void
  494. INTERPOL_BILINEAR(const Uint32 *s0, const Uint32 *s1, int frac_w0, int frac_h0, int frac_h1, Uint32 *dst)
  495. {
  496. Uint32 tmp[2];
  497. unsigned int frac_w1 = FRAC_ONE - frac_w0;
  498. /* Vertical first, store to 'tmp' */
  499. INTERPOL(s0, s1, frac_h0, frac_h1, tmp);
  500. INTERPOL(s0 + 1, s1 + 1, frac_h0, frac_h1, tmp + 1);
  501. /* Horizontal, store to 'dst' */
  502. INTERPOL(tmp, tmp + 1, frac_w0, frac_w1, dst);
  503. }
  504. static int
  505. scale_mat(const Uint32 *src, int src_w, int src_h, int src_pitch,
  506. Uint32 *dst, int dst_w, int dst_h, int dst_pitch)
  507. {
  508. BILINEAR___START
  509. for (i = 0; i < dst_h; i++) {
  510. BILINEAR___HEIGHT
  511. while (left_pad_w--) {
  512. INTERPOL_BILINEAR(src_h0, src_h1, FRAC_ZERO, frac_h0, frac_h1, dst);
  513. dst += 1;
  514. }
  515. while (middle--) {
  516. const Uint32 *s_00_01;
  517. const Uint32 *s_10_11;
  518. int index_w = 4 * SRC_INDEX(fp_sum_w);
  519. int frac_w = FRAC(fp_sum_w);
  520. fp_sum_w += fp_step_w;
  521. /*
  522. x00 ... x0_ ..... x01
  523. . . .
  524. . x .
  525. . . .
  526. . . .
  527. x10 ... x1_ ..... x11
  528. */
  529. s_00_01 = (const Uint32 *)((const Uint8 *)src_h0 + index_w);
  530. s_10_11 = (const Uint32 *)((const Uint8 *)src_h1 + index_w);
  531. INTERPOL_BILINEAR(s_00_01, s_10_11, frac_w, frac_h0, frac_h1, dst);
  532. dst += 1;
  533. }
  534. while (right_pad_w--) {
  535. int index_w = 4 * (src_w - 2);
  536. const Uint32 *s_00_01 = (const Uint32 *)((const Uint8 *)src_h0 + index_w);
  537. const Uint32 *s_10_11 = (const Uint32 *)((const Uint8 *)src_h1 + index_w);
  538. INTERPOL_BILINEAR(s_00_01, s_10_11, FRAC_ONE, frac_h0, frac_h1, dst);
  539. dst += 1;
  540. }
  541. dst = (Uint32 *)((Uint8 *)dst + dst_gap);
  542. }
  543. return 0;
  544. }
  545. #if defined(__SSE2__)
  546. # define HAVE_SSE2_INTRINSICS 1
  547. #endif
  548. #if defined(__ARM_NEON)
  549. # define HAVE_NEON_INTRINSICS 1
  550. # define CAST_uint8x8_t (uint8x8_t)
  551. # define CAST_uint32x2_t (uint32x2_t)
  552. #endif
  553. #if defined(__WINRT__) || defined(_MSC_VER)
  554. # if defined(HAVE_NEON_INTRINSICS)
  555. # undef CAST_uint8x8_t
  556. # undef CAST_uint32x2_t
  557. # define CAST_uint8x8_t
  558. # define CAST_uint32x2_t
  559. # endif
  560. #endif
  561. #if defined(HAVE_SSE2_INTRINSICS)
  562. #if 0
  563. static void
  564. printf_128(const char *str, __m128i var)
  565. {
  566. uint16_t *val = (uint16_t*) &var;
  567. printf(" * %s: %04x %04x %04x %04x _ %04x %04x %04x %04x\n",
  568. str, val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7]);
  569. }
  570. #endif
  571. static SDL_INLINE int
  572. hasSSE2()
  573. {
  574. static int val = -1;
  575. if (val != -1) {
  576. return val;
  577. }
  578. val = SDL_HasSSE2();
  579. return val;
  580. }
  581. static SDL_INLINE void
  582. INTERPOL_BILINEAR_SSE(const Uint32 *s0, const Uint32 *s1, int frac_w, __m128i v_frac_h0, __m128i v_frac_h1, Uint32 *dst, __m128i zero)
  583. {
  584. __m128i x_00_01, x_10_11; /* Pixels in 4*uint8 in row */
  585. __m128i v_frac_w0, k0, l0, d0, e0;
  586. int f, f2;
  587. f = frac_w;
  588. f2 = FRAC_ONE - frac_w;
  589. v_frac_w0 = _mm_set_epi16(f, f2, f, f2, f, f2, f, f2);
  590. x_00_01 = _mm_loadl_epi64((const __m128i *)s0); /* Load x00 and x01 */
  591. x_10_11 = _mm_loadl_epi64((const __m128i *)s1);
  592. /* Interpolated == x0 + frac * (x1 - x0) == x0 * (1 - frac) + x1 * frac */
  593. /* Interpolation vertical */
  594. k0 = _mm_mullo_epi16(_mm_unpacklo_epi8(x_00_01, zero), v_frac_h1);
  595. l0 = _mm_mullo_epi16(_mm_unpacklo_epi8(x_10_11, zero), v_frac_h0);
  596. k0 = _mm_add_epi16(k0, l0);
  597. /* For perfect match, clear the factionnal part eventually. */
  598. /*
  599. k0 = _mm_srli_epi16(k0, PRECISION);
  600. k0 = _mm_slli_epi16(k0, PRECISION);
  601. */
  602. /* Interpolation horizontal */
  603. l0 = _mm_unpacklo_epi64(/* unused */ l0, k0);
  604. k0 = _mm_madd_epi16(_mm_unpackhi_epi16(l0, k0), v_frac_w0);
  605. /* Store 1 pixel */
  606. d0 = _mm_srli_epi32(k0, PRECISION * 2);
  607. e0 = _mm_packs_epi32(d0, d0);
  608. e0 = _mm_packus_epi16(e0, e0);
  609. *dst = _mm_cvtsi128_si32(e0);
  610. }
  611. static int
  612. scale_mat_SSE(const Uint32 *src, int src_w, int src_h, int src_pitch, Uint32 *dst, int dst_w, int dst_h, int dst_pitch)
  613. {
  614. BILINEAR___START
  615. for (i = 0; i < dst_h; i++) {
  616. int nb_block2;
  617. __m128i v_frac_h0;
  618. __m128i v_frac_h1;
  619. __m128i zero;
  620. BILINEAR___HEIGHT
  621. nb_block2 = middle / 2;
  622. v_frac_h0 = _mm_set_epi16(frac_h0, frac_h0, frac_h0, frac_h0, frac_h0, frac_h0, frac_h0, frac_h0);
  623. v_frac_h1 = _mm_set_epi16(frac_h1, frac_h1, frac_h1, frac_h1, frac_h1, frac_h1, frac_h1, frac_h1);
  624. zero = _mm_setzero_si128();
  625. while (left_pad_w--) {
  626. INTERPOL_BILINEAR_SSE(src_h0, src_h1, FRAC_ZERO, v_frac_h0, v_frac_h1, dst, zero);
  627. dst += 1;
  628. }
  629. while (nb_block2--) {
  630. int index_w_0, frac_w_0;
  631. int index_w_1, frac_w_1;
  632. const Uint32 *s_00_01, *s_02_03, *s_10_11, *s_12_13;
  633. __m128i x_00_01, x_10_11, x_02_03, x_12_13;/* Pixels in 4*uint8 in row */
  634. __m128i v_frac_w0, k0, l0, d0, e0;
  635. __m128i v_frac_w1, k1, l1, d1, e1;
  636. int f, f2;
  637. index_w_0 = 4 * SRC_INDEX(fp_sum_w);
  638. frac_w_0 = FRAC(fp_sum_w);
  639. fp_sum_w += fp_step_w;
  640. index_w_1 = 4 * SRC_INDEX(fp_sum_w);
  641. frac_w_1 = FRAC(fp_sum_w);
  642. fp_sum_w += fp_step_w;
  643. /*
  644. x00............ x01 x02...........x03
  645. . . . . . .
  646. j0 f0 j1 j2 f1 j3
  647. . . . . . .
  648. . . . . . .
  649. . . . . . .
  650. x10............ x11 x12...........x13
  651. */
  652. s_00_01 = (const Uint32 *)((const Uint8 *)src_h0 + index_w_0);
  653. s_02_03 = (const Uint32 *)((const Uint8 *)src_h0 + index_w_1);
  654. s_10_11 = (const Uint32 *)((const Uint8 *)src_h1 + index_w_0);
  655. s_12_13 = (const Uint32 *)((const Uint8 *)src_h1 + index_w_1);
  656. f = frac_w_0;
  657. f2 = FRAC_ONE - frac_w_0;
  658. v_frac_w0 = _mm_set_epi16(f, f2, f, f2, f, f2, f, f2);
  659. f = frac_w_1;
  660. f2 = FRAC_ONE - frac_w_1;
  661. v_frac_w1 = _mm_set_epi16(f, f2, f, f2, f, f2, f, f2);
  662. x_00_01 = _mm_loadl_epi64((const __m128i *)s_00_01); /* Load x00 and x01 */
  663. x_02_03 = _mm_loadl_epi64((const __m128i *)s_02_03);
  664. x_10_11 = _mm_loadl_epi64((const __m128i *)s_10_11);
  665. x_12_13 = _mm_loadl_epi64((const __m128i *)s_12_13);
  666. /* Interpolation vertical */
  667. k0 = _mm_mullo_epi16(_mm_unpacklo_epi8(x_00_01, zero), v_frac_h1);
  668. l0 = _mm_mullo_epi16(_mm_unpacklo_epi8(x_10_11, zero), v_frac_h0);
  669. k0 = _mm_add_epi16(k0, l0);
  670. k1 = _mm_mullo_epi16(_mm_unpacklo_epi8(x_02_03, zero), v_frac_h1);
  671. l1 = _mm_mullo_epi16(_mm_unpacklo_epi8(x_12_13, zero), v_frac_h0);
  672. k1 = _mm_add_epi16(k1, l1);
  673. /* Interpolation horizontal */
  674. l0 = _mm_unpacklo_epi64(/* unused */ l0, k0);
  675. k0 = _mm_madd_epi16(_mm_unpackhi_epi16(l0, k0), v_frac_w0);
  676. l1 = _mm_unpacklo_epi64(/* unused */ l1, k1);
  677. k1 = _mm_madd_epi16(_mm_unpackhi_epi16(l1, k1), v_frac_w1);
  678. /* Store 1 pixel */
  679. d0 = _mm_srli_epi32(k0, PRECISION * 2);
  680. e0 = _mm_packs_epi32(d0, d0);
  681. e0 = _mm_packus_epi16(e0, e0);
  682. *dst++ = _mm_cvtsi128_si32(e0);
  683. /* Store 1 pixel */
  684. d1 = _mm_srli_epi32(k1, PRECISION * 2);
  685. e1 = _mm_packs_epi32(d1, d1);
  686. e1 = _mm_packus_epi16(e1, e1);
  687. *dst++ = _mm_cvtsi128_si32(e1);
  688. }
  689. /* Last point */
  690. if (middle & 0x1) {
  691. const Uint32 *s_00_01;
  692. const Uint32 *s_10_11;
  693. int index_w = 4 * SRC_INDEX(fp_sum_w);
  694. int frac_w = FRAC(fp_sum_w);
  695. fp_sum_w += fp_step_w;
  696. s_00_01 = (const Uint32 *)((const Uint8 *)src_h0 + index_w);
  697. s_10_11 = (const Uint32 *)((const Uint8 *)src_h1 + index_w);
  698. INTERPOL_BILINEAR_SSE(s_00_01, s_10_11, frac_w, v_frac_h0, v_frac_h1, dst, zero);
  699. dst += 1;
  700. }
  701. while (right_pad_w--) {
  702. int index_w = 4 * (src_w - 2);
  703. const Uint32 *s_00_01 = (const Uint32 *)((const Uint8 *)src_h0 + index_w);
  704. const Uint32 *s_10_11 = (const Uint32 *)((const Uint8 *)src_h1 + index_w);
  705. INTERPOL_BILINEAR_SSE(s_00_01, s_10_11, FRAC_ONE, v_frac_h0, v_frac_h1, dst, zero);
  706. dst += 1;
  707. }
  708. dst = (Uint32 *)((Uint8 *)dst + dst_gap);
  709. }
  710. return 0;
  711. }
  712. #endif
  713. #if defined(HAVE_NEON_INTRINSICS)
  714. static SDL_INLINE int
  715. hasNEON()
  716. {
  717. static int val = -1;
  718. if (val != -1) {
  719. return val;
  720. }
  721. val = SDL_HasNEON();
  722. return val;
  723. }
  724. static SDL_INLINE void
  725. INTERPOL_BILINEAR_NEON(const Uint32 *s0, const Uint32 *s1, int frac_w, uint8x8_t v_frac_h0, uint8x8_t v_frac_h1, Uint32 *dst)
  726. {
  727. uint8x8_t x_00_01, x_10_11; /* Pixels in 4*uint8 in row */
  728. uint16x8_t k0;
  729. uint32x4_t l0;
  730. uint16x8_t d0;
  731. uint8x8_t e0;
  732. x_00_01 = CAST_uint8x8_t vld1_u32(s0); /* Load 2 pixels */
  733. x_10_11 = CAST_uint8x8_t vld1_u32(s1);
  734. /* Interpolated == x0 + frac * (x1 - x0) == x0 * (1 - frac) + x1 * frac */
  735. k0 = vmull_u8(x_00_01, v_frac_h1); /* k0 := x0 * (1 - frac) */
  736. k0 = vmlal_u8(k0, x_10_11, v_frac_h0); /* k0 += x1 * frac */
  737. /* k0 now contains 2 interpolated pixels { j0, j1 } */
  738. l0 = vshll_n_u16(vget_low_u16(k0), PRECISION);
  739. l0 = vmlsl_n_u16(l0, vget_low_u16(k0), frac_w);
  740. l0 = vmlal_n_u16(l0, vget_high_u16(k0), frac_w);
  741. /* Shift and narrow */
  742. d0 = vcombine_u16(
  743. /* uint16x4_t */ vshrn_n_u32(l0, 2 * PRECISION),
  744. /* uint16x4_t */ vshrn_n_u32(l0, 2 * PRECISION)
  745. );
  746. /* Narrow again */
  747. e0 = vmovn_u16(d0);
  748. /* Store 1 pixel */
  749. *dst = vget_lane_u32(CAST_uint32x2_t e0, 0);
  750. }
  751. static int
  752. scale_mat_NEON(const Uint32 *src, int src_w, int src_h, int src_pitch, Uint32 *dst, int dst_w, int dst_h, int dst_pitch)
  753. {
  754. BILINEAR___START
  755. for (i = 0; i < dst_h; i++) {
  756. int nb_block4;
  757. uint8x8_t v_frac_h0, v_frac_h1;
  758. BILINEAR___HEIGHT
  759. nb_block4 = middle / 4;
  760. v_frac_h0 = vmov_n_u8(frac_h0);
  761. v_frac_h1 = vmov_n_u8(frac_h1);
  762. while (left_pad_w--) {
  763. INTERPOL_BILINEAR_NEON(src_h0, src_h1, FRAC_ZERO, v_frac_h0, v_frac_h1, dst);
  764. dst += 1;
  765. }
  766. while (nb_block4--) {
  767. int index_w_0, frac_w_0;
  768. int index_w_1, frac_w_1;
  769. int index_w_2, frac_w_2;
  770. int index_w_3, frac_w_3;
  771. const Uint32 *s_00_01, *s_02_03, *s_04_05, *s_06_07;
  772. const Uint32 *s_10_11, *s_12_13, *s_14_15, *s_16_17;
  773. uint8x8_t x_00_01, x_10_11, x_02_03, x_12_13;/* Pixels in 4*uint8 in row */
  774. uint8x8_t x_04_05, x_14_15, x_06_07, x_16_17;
  775. uint16x8_t k0, k1, k2, k3;
  776. uint32x4_t l0, l1, l2, l3;
  777. uint16x8_t d0, d1;
  778. uint8x8_t e0, e1;
  779. uint32x4_t f0;
  780. index_w_0 = 4 * SRC_INDEX(fp_sum_w);
  781. frac_w_0 = FRAC(fp_sum_w);
  782. fp_sum_w += fp_step_w;
  783. index_w_1 = 4 * SRC_INDEX(fp_sum_w);
  784. frac_w_1 = FRAC(fp_sum_w);
  785. fp_sum_w += fp_step_w;
  786. index_w_2 = 4 * SRC_INDEX(fp_sum_w);
  787. frac_w_2 = FRAC(fp_sum_w);
  788. fp_sum_w += fp_step_w;
  789. index_w_3 = 4 * SRC_INDEX(fp_sum_w);
  790. frac_w_3 = FRAC(fp_sum_w);
  791. fp_sum_w += fp_step_w;
  792. s_00_01 = (const Uint32 *)((const Uint8 *)src_h0 + index_w_0);
  793. s_02_03 = (const Uint32 *)((const Uint8 *)src_h0 + index_w_1);
  794. s_04_05 = (const Uint32 *)((const Uint8 *)src_h0 + index_w_2);
  795. s_06_07 = (const Uint32 *)((const Uint8 *)src_h0 + index_w_3);
  796. s_10_11 = (const Uint32 *)((const Uint8 *)src_h1 + index_w_0);
  797. s_12_13 = (const Uint32 *)((const Uint8 *)src_h1 + index_w_1);
  798. s_14_15 = (const Uint32 *)((const Uint8 *)src_h1 + index_w_2);
  799. s_16_17 = (const Uint32 *)((const Uint8 *)src_h1 + index_w_3);
  800. /* Interpolation vertical */
  801. x_00_01 = CAST_uint8x8_t vld1_u32(s_00_01); /* Load 2 pixels */
  802. x_02_03 = CAST_uint8x8_t vld1_u32(s_02_03);
  803. x_04_05 = CAST_uint8x8_t vld1_u32(s_04_05);
  804. x_06_07 = CAST_uint8x8_t vld1_u32(s_06_07);
  805. x_10_11 = CAST_uint8x8_t vld1_u32(s_10_11);
  806. x_12_13 = CAST_uint8x8_t vld1_u32(s_12_13);
  807. x_14_15 = CAST_uint8x8_t vld1_u32(s_14_15);
  808. x_16_17 = CAST_uint8x8_t vld1_u32(s_16_17);
  809. /* Interpolated == x0 + frac * (x1 - x0) == x0 * (1 - frac) + x1 * frac */
  810. k0 = vmull_u8(x_00_01, v_frac_h1); /* k0 := x0 * (1 - frac) */
  811. k0 = vmlal_u8(k0, x_10_11, v_frac_h0); /* k0 += x1 * frac */
  812. k1 = vmull_u8(x_02_03, v_frac_h1);
  813. k1 = vmlal_u8(k1, x_12_13, v_frac_h0);
  814. k2 = vmull_u8(x_04_05, v_frac_h1);
  815. k2 = vmlal_u8(k2, x_14_15, v_frac_h0);
  816. k3 = vmull_u8(x_06_07, v_frac_h1);
  817. k3 = vmlal_u8(k3, x_16_17, v_frac_h0);
  818. /* k0 now contains 2 interpolated pixels { j0, j1 } */
  819. /* k1 now contains 2 interpolated pixels { j2, j3 } */
  820. /* k2 now contains 2 interpolated pixels { j4, j5 } */
  821. /* k3 now contains 2 interpolated pixels { j6, j7 } */
  822. l0 = vshll_n_u16(vget_low_u16(k0), PRECISION);
  823. l0 = vmlsl_n_u16(l0, vget_low_u16(k0), frac_w_0);
  824. l0 = vmlal_n_u16(l0, vget_high_u16(k0), frac_w_0);
  825. l1 = vshll_n_u16(vget_low_u16(k1), PRECISION);
  826. l1 = vmlsl_n_u16(l1, vget_low_u16(k1), frac_w_1);
  827. l1 = vmlal_n_u16(l1, vget_high_u16(k1), frac_w_1);
  828. l2 = vshll_n_u16(vget_low_u16(k2), PRECISION);
  829. l2 = vmlsl_n_u16(l2, vget_low_u16(k2), frac_w_2);
  830. l2 = vmlal_n_u16(l2, vget_high_u16(k2), frac_w_2);
  831. l3 = vshll_n_u16(vget_low_u16(k3), PRECISION);
  832. l3 = vmlsl_n_u16(l3, vget_low_u16(k3), frac_w_3);
  833. l3 = vmlal_n_u16(l3, vget_high_u16(k3), frac_w_3);
  834. /* shift and narrow */
  835. d0 = vcombine_u16(
  836. /* uint16x4_t */ vshrn_n_u32(l0, 2 * PRECISION),
  837. /* uint16x4_t */ vshrn_n_u32(l1, 2 * PRECISION)
  838. );
  839. /* narrow again */
  840. e0 = vmovn_u16(d0);
  841. /* Shift and narrow */
  842. d1 = vcombine_u16(
  843. /* uint16x4_t */ vshrn_n_u32(l2, 2 * PRECISION),
  844. /* uint16x4_t */ vshrn_n_u32(l3, 2 * PRECISION)
  845. );
  846. /* Narrow again */
  847. e1 = vmovn_u16(d1);
  848. f0 = vcombine_u32(CAST_uint32x2_t e0, CAST_uint32x2_t e1);
  849. /* Store 4 pixels */
  850. vst1q_u32(dst, f0);
  851. dst += 4;
  852. }
  853. if (middle & 0x2) {
  854. int index_w_0, frac_w_0;
  855. int index_w_1, frac_w_1;
  856. const Uint32 *s_00_01, *s_02_03;
  857. const Uint32 *s_10_11, *s_12_13;
  858. uint8x8_t x_00_01, x_10_11, x_02_03, x_12_13;/* Pixels in 4*uint8 in row */
  859. uint16x8_t k0, k1;
  860. uint32x4_t l0, l1;
  861. uint16x8_t d0;
  862. uint8x8_t e0;
  863. index_w_0 = 4 * SRC_INDEX(fp_sum_w);
  864. frac_w_0 = FRAC(fp_sum_w);
  865. fp_sum_w += fp_step_w;
  866. index_w_1 = 4 * SRC_INDEX(fp_sum_w);
  867. frac_w_1 = FRAC(fp_sum_w);
  868. fp_sum_w += fp_step_w;
  869. /*
  870. x00............ x01 x02...........x03
  871. . . . . . .
  872. j0 dest0 j1 j2 dest1 j3
  873. . . . . . .
  874. . . . . . .
  875. . . . . . .
  876. x10............ x11 x12...........x13
  877. */
  878. s_00_01 = (const Uint32 *)((const Uint8 *)src_h0 + index_w_0);
  879. s_02_03 = (const Uint32 *)((const Uint8 *)src_h0 + index_w_1);
  880. s_10_11 = (const Uint32 *)((const Uint8 *)src_h1 + index_w_0);
  881. s_12_13 = (const Uint32 *)((const Uint8 *)src_h1 + index_w_1);
  882. /* Interpolation vertical */
  883. x_00_01 = CAST_uint8x8_t vld1_u32(s_00_01);/* Load 2 pixels */
  884. x_02_03 = CAST_uint8x8_t vld1_u32(s_02_03);
  885. x_10_11 = CAST_uint8x8_t vld1_u32(s_10_11);
  886. x_12_13 = CAST_uint8x8_t vld1_u32(s_12_13);
  887. /* Interpolated == x0 + frac * (x1 - x0) == x0 * (1 - frac) + x1 * frac */
  888. k0 = vmull_u8(x_00_01, v_frac_h1); /* k0 := x0 * (1 - frac) */
  889. k0 = vmlal_u8(k0, x_10_11, v_frac_h0); /* k0 += x1 * frac */
  890. k1 = vmull_u8(x_02_03, v_frac_h1);
  891. k1 = vmlal_u8(k1, x_12_13, v_frac_h0);
  892. /* k0 now contains 2 interpolated pixels { j0, j1 } */
  893. /* k1 now contains 2 interpolated pixels { j2, j3 } */
  894. l0 = vshll_n_u16(vget_low_u16(k0), PRECISION);
  895. l0 = vmlsl_n_u16(l0, vget_low_u16(k0), frac_w_0);
  896. l0 = vmlal_n_u16(l0, vget_high_u16(k0), frac_w_0);
  897. l1 = vshll_n_u16(vget_low_u16(k1), PRECISION);
  898. l1 = vmlsl_n_u16(l1, vget_low_u16(k1), frac_w_1);
  899. l1 = vmlal_n_u16(l1, vget_high_u16(k1), frac_w_1);
  900. /* Shift and narrow */
  901. d0 = vcombine_u16(
  902. /* uint16x4_t */ vshrn_n_u32(l0, 2 * PRECISION),
  903. /* uint16x4_t */ vshrn_n_u32(l1, 2 * PRECISION)
  904. );
  905. /* Narrow again */
  906. e0 = vmovn_u16(d0);
  907. /* Store 2 pixels */
  908. vst1_u32(dst, CAST_uint32x2_t e0);
  909. dst += 2;
  910. }
  911. /* Last point */
  912. if (middle & 0x1) {
  913. int index_w = 4 * SRC_INDEX(fp_sum_w);
  914. int frac_w = FRAC(fp_sum_w);
  915. const Uint32 *s_00_01 = (const Uint32 *)((const Uint8 *)src_h0 + index_w);
  916. const Uint32 *s_10_11 = (const Uint32 *)((const Uint8 *)src_h1 + index_w);
  917. INTERPOL_BILINEAR_NEON(s_00_01, s_10_11, frac_w, v_frac_h0, v_frac_h1, dst);
  918. dst += 1;
  919. }
  920. while (right_pad_w--) {
  921. int index_w = 4 * (src_w - 2);
  922. const Uint32 *s_00_01 = (const Uint32 *)((const Uint8 *)src_h0 + index_w);
  923. const Uint32 *s_10_11 = (const Uint32 *)((const Uint8 *)src_h1 + index_w);
  924. INTERPOL_BILINEAR_NEON(s_00_01, s_10_11, FRAC_ONE, v_frac_h0, v_frac_h1, dst);
  925. dst += 1;
  926. }
  927. dst = (Uint32 *)((Uint8 *)dst + dst_gap);
  928. }
  929. return 0;
  930. }
  931. #endif
  932. int
  933. SDL_LowerSoftStretchLinear(SDL_Surface *s, const SDL_Rect *srcrect,
  934. SDL_Surface *d, const SDL_Rect *dstrect)
  935. {
  936. int ret = -1;
  937. int src_w = srcrect->w;
  938. int src_h = srcrect->h;
  939. int dst_w = dstrect->w;
  940. int dst_h = dstrect->h;
  941. int src_pitch = s->pitch;
  942. int dst_pitch = d->pitch;
  943. Uint32 *src = (Uint32 *) ((Uint8 *)s->pixels + srcrect->x * 4 + srcrect->y * src_pitch);
  944. Uint32 *dst = (Uint32 *) ((Uint8 *)d->pixels + dstrect->x * 4 + dstrect->y * dst_pitch);
  945. #if defined(HAVE_NEON_INTRINSICS)
  946. if (ret == -1 && hasNEON()) {
  947. ret = scale_mat_NEON(src, src_w, src_h, src_pitch, dst, dst_w, dst_h, dst_pitch);
  948. }
  949. #endif
  950. #if defined(HAVE_SSE2_INTRINSICS)
  951. if (ret == -1 && hasSSE2()) {
  952. ret = scale_mat_SSE(src, src_w, src_h, src_pitch, dst, dst_w, dst_h, dst_pitch);
  953. }
  954. #endif
  955. if (ret == -1) {
  956. scale_mat(src, src_w, src_h, src_pitch, dst, dst_w, dst_h, dst_pitch);
  957. }
  958. return ret;
  959. }
  960. /* vi: set ts=4 sw=4 expandtab: */