You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

mat_pixel_affine.cpp 80 kB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618
  1. // Tencent is pleased to support the open source community by making ncnn available.
  2. //
  3. // Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
  4. //
  5. // Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
  6. // in compliance with the License. You may obtain a copy of the License at
  7. //
  8. // https://opensource.org/licenses/BSD-3-Clause
  9. //
  10. // Unless required by applicable law or agreed to in writing, software distributed
  11. // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  12. // CONDITIONS OF ANY KIND, either express or implied. See the License for the
  13. // specific language governing permissions and limitations under the License.
  14. #include "mat.h"
  15. #if __ARM_NEON
  16. #include <arm_neon.h>
  17. #endif // __ARM_NEON
  18. #include <limits.h>
  19. #include "platform.h"
  20. namespace ncnn {
  21. #if NCNN_PIXEL_AFFINE
  22. void get_rotation_matrix(float angle, float scale, float dx, float dy, float* tm)
  23. {
  24. angle *= (float)(3.14159265358979323846 / 180);
  25. float alpha = cosf(angle) * scale;
  26. float beta = sinf(angle) * scale;
  27. tm[0] = alpha;
  28. tm[1] = beta;
  29. tm[2] = (1.f - alpha) * dx - beta * dy;
  30. tm[3] = -beta;
  31. tm[4] = alpha;
  32. tm[5] = beta * dx + (1.f - alpha) * dy;
  33. }
  34. void get_affine_transform(const float* points_from, const float* points_to, int num_point, float* tm)
  35. {
  36. float ma[4][4] = {{0.f}};
  37. float mb[4] = {0.f};
  38. float mm[4];
  39. for (int i = 0; i < num_point; i++)
  40. {
  41. ma[0][0] += points_from[0] * points_from[0] + points_from[1] * points_from[1];
  42. ma[0][2] += points_from[0];
  43. ma[0][3] += points_from[1];
  44. mb[0] += points_from[0] * points_to[0] + points_from[1] * points_to[1];
  45. mb[1] += points_from[0] * points_to[1] - points_from[1] * points_to[0];
  46. mb[2] += points_to[0];
  47. mb[3] += points_to[1];
  48. points_from += 2;
  49. points_to += 2;
  50. }
  51. ma[1][1] = ma[0][0];
  52. ma[2][1] = ma[1][2] = -ma[0][3];
  53. ma[3][1] = ma[1][3] = ma[2][0] = ma[0][2];
  54. ma[2][2] = ma[3][3] = (float)num_point;
  55. ma[3][0] = ma[0][3];
  56. // MM = inv(A) * B
  57. // matrix 4x4 invert by https://github.com/willnode/N-Matrix-Programmer
  58. // suppose the user provide valid points combination
  59. // I have not taken det == zero into account here :> --- nihui
  60. float mai[4][4];
  61. float det;
  62. // clang-format off
  63. // *INDENT-OFF*
  64. {
  65. float A2323 = ma[2][2] * ma[3][3] - ma[2][3] * ma[3][2];
  66. float A1323 = ma[2][1] * ma[3][3] - ma[2][3] * ma[3][1];
  67. float A1223 = ma[2][1] * ma[3][2] - ma[2][2] * ma[3][1];
  68. float A0323 = ma[2][0] * ma[3][3] - ma[2][3] * ma[3][0];
  69. float A0223 = ma[2][0] * ma[3][2] - ma[2][2] * ma[3][0];
  70. float A0123 = ma[2][0] * ma[3][1] - ma[2][1] * ma[3][0];
  71. float A2313 = ma[1][2] * ma[3][3] - ma[1][3] * ma[3][2];
  72. float A1313 = ma[1][1] * ma[3][3] - ma[1][3] * ma[3][1];
  73. float A1213 = ma[1][1] * ma[3][2] - ma[1][2] * ma[3][1];
  74. float A2312 = ma[1][2] * ma[2][3] - ma[1][3] * ma[2][2];
  75. float A1312 = ma[1][1] * ma[2][3] - ma[1][3] * ma[2][1];
  76. float A1212 = ma[1][1] * ma[2][2] - ma[1][2] * ma[2][1];
  77. float A0313 = ma[1][0] * ma[3][3] - ma[1][3] * ma[3][0];
  78. float A0213 = ma[1][0] * ma[3][2] - ma[1][2] * ma[3][0];
  79. float A0312 = ma[1][0] * ma[2][3] - ma[1][3] * ma[2][0];
  80. float A0212 = ma[1][0] * ma[2][2] - ma[1][2] * ma[2][0];
  81. float A0113 = ma[1][0] * ma[3][1] - ma[1][1] * ma[3][0];
  82. float A0112 = ma[1][0] * ma[2][1] - ma[1][1] * ma[2][0];
  83. det = ma[0][0] * (ma[1][1] * A2323 - ma[1][2] * A1323 + ma[1][3] * A1223)
  84. - ma[0][1] * (ma[1][0] * A2323 - ma[1][2] * A0323 + ma[1][3] * A0223)
  85. + ma[0][2] * (ma[1][0] * A1323 - ma[1][1] * A0323 + ma[1][3] * A0123)
  86. - ma[0][3] * (ma[1][0] * A1223 - ma[1][1] * A0223 + ma[1][2] * A0123);
  87. det = 1.f / det;
  88. mai[0][0] = (ma[1][1] * A2323 - ma[1][2] * A1323 + ma[1][3] * A1223);
  89. mai[0][1] = - (ma[0][1] * A2323 - ma[0][2] * A1323 + ma[0][3] * A1223);
  90. mai[0][2] = (ma[0][1] * A2313 - ma[0][2] * A1313 + ma[0][3] * A1213);
  91. mai[0][3] = - (ma[0][1] * A2312 - ma[0][2] * A1312 + ma[0][3] * A1212);
  92. mai[1][0] = - (ma[1][0] * A2323 - ma[1][2] * A0323 + ma[1][3] * A0223);
  93. mai[1][1] = (ma[0][0] * A2323 - ma[0][2] * A0323 + ma[0][3] * A0223);
  94. mai[1][2] = - (ma[0][0] * A2313 - ma[0][2] * A0313 + ma[0][3] * A0213);
  95. mai[1][3] = (ma[0][0] * A2312 - ma[0][2] * A0312 + ma[0][3] * A0212);
  96. mai[2][0] = (ma[1][0] * A1323 - ma[1][1] * A0323 + ma[1][3] * A0123);
  97. mai[2][1] = - (ma[0][0] * A1323 - ma[0][1] * A0323 + ma[0][3] * A0123);
  98. mai[2][2] = (ma[0][0] * A1313 - ma[0][1] * A0313 + ma[0][3] * A0113);
  99. mai[2][3] = - (ma[0][0] * A1312 - ma[0][1] * A0312 + ma[0][3] * A0112);
  100. mai[3][0] = - (ma[1][0] * A1223 - ma[1][1] * A0223 + ma[1][2] * A0123);
  101. mai[3][1] = (ma[0][0] * A1223 - ma[0][1] * A0223 + ma[0][2] * A0123);
  102. mai[3][2] = - (ma[0][0] * A1213 - ma[0][1] * A0213 + ma[0][2] * A0113);
  103. mai[3][3] = (ma[0][0] * A1212 - ma[0][1] * A0212 + ma[0][2] * A0112);
  104. }
  105. // *INDENT-ON*
  106. // clang-format on
  107. mm[0] = det * (mai[0][0] * mb[0] + mai[0][1] * mb[1] + mai[0][2] * mb[2] + mai[0][3] * mb[3]);
  108. mm[1] = det * (mai[1][0] * mb[0] + mai[1][1] * mb[1] + mai[1][2] * mb[2] + mai[1][3] * mb[3]);
  109. mm[2] = det * (mai[2][0] * mb[0] + mai[2][1] * mb[1] + mai[2][2] * mb[2] + mai[2][3] * mb[3]);
  110. mm[3] = det * (mai[3][0] * mb[0] + mai[3][1] * mb[1] + mai[3][2] * mb[2] + mai[3][3] * mb[3]);
  111. tm[0] = tm[4] = mm[0];
  112. tm[1] = -mm[1];
  113. tm[3] = mm[1];
  114. tm[2] = mm[2];
  115. tm[5] = mm[3];
  116. }
  117. void invert_affine_transform(const float* tm, float* tm_inv)
  118. {
  119. float D = tm[0] * tm[4] - tm[1] * tm[3];
  120. D = D != 0.f ? 1.f / D : 0.f;
  121. float A11 = tm[4] * D;
  122. float A22 = tm[0] * D;
  123. float A12 = -tm[1] * D;
  124. float A21 = -tm[3] * D;
  125. float b1 = -A11 * tm[2] - A12 * tm[5];
  126. float b2 = -A21 * tm[2] - A22 * tm[5];
  127. tm_inv[0] = A11;
  128. tm_inv[1] = A12;
  129. tm_inv[2] = b1;
  130. tm_inv[3] = A21;
  131. tm_inv[4] = A22;
  132. tm_inv[5] = b2;
  133. }
  134. void warpaffine_bilinear_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type, unsigned int v)
  135. {
  136. return warpaffine_bilinear_c1(src, srcw, srch, srcw, dst, w, h, w, tm, type, v);
  137. }
  138. void warpaffine_bilinear_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type, unsigned int v)
  139. {
  140. return warpaffine_bilinear_c2(src, srcw, srch, srcw * 2, dst, w, h, w * 2, tm, type, v);
  141. }
  142. void warpaffine_bilinear_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type, unsigned int v)
  143. {
  144. return warpaffine_bilinear_c3(src, srcw, srch, srcw * 3, dst, w, h, w * 3, tm, type, v);
  145. }
  146. void warpaffine_bilinear_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type, unsigned int v)
  147. {
  148. return warpaffine_bilinear_c4(src, srcw, srch, srcw * 4, dst, w, h, w * 4, tm, type, v);
  149. }
  150. void warpaffine_bilinear_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type, unsigned int v)
  151. {
  152. const unsigned char* border_color = (const unsigned char*)&v;
  153. const int wgap = stride - w;
  154. const unsigned char* src0 = src;
  155. unsigned char* dst0 = dst;
  156. #define SATURATE_CAST_SHORT(X) (short)::std::min(::std::max((int)(X), SHRT_MIN), SHRT_MAX)
  157. #define SATURATE_CAST_INT(X) (int)::std::min(::std::max((int)((X) + ((X) >= 0.f ? 0.5f : -0.5f)), INT_MIN), INT_MAX)
  158. std::vector<int> adelta(w);
  159. std::vector<int> bdelta(w);
  160. for (int x = 0; x < w; x++)
  161. {
  162. adelta[x] = SATURATE_CAST_INT(tm[0] * x * (1 << 10));
  163. bdelta[x] = SATURATE_CAST_INT(tm[3] * x * (1 << 10));
  164. }
  165. int y = 0;
  166. for (; y < h; y++)
  167. {
  168. int X0 = SATURATE_CAST_INT((tm[1] * y + tm[2]) * (1 << 10));
  169. int Y0 = SATURATE_CAST_INT((tm[4] * y + tm[5]) * (1 << 10));
  170. int x = 0;
  171. for (; x + 7 < w; x += 8)
  172. {
  173. int sxy_inout = 0;
  174. {
  175. int X_0 = X0 + adelta[x];
  176. int Y_0 = Y0 + bdelta[x];
  177. int X_7 = X0 + adelta[x + 7];
  178. int Y_7 = Y0 + bdelta[x + 7];
  179. short sx_0 = SATURATE_CAST_SHORT((X_0 >> 10));
  180. short sy_0 = SATURATE_CAST_SHORT((Y_0 >> 10));
  181. short sx_7 = SATURATE_CAST_SHORT((X_7 >> 10));
  182. short sy_7 = SATURATE_CAST_SHORT((Y_7 >> 10));
  183. if (((unsigned short)sx_0 < srcw - 1 && (unsigned short)sy_0 < srch - 1) && ((unsigned short)sx_7 < srcw - 1 && (unsigned short)sy_7 < srch - 1))
  184. {
  185. // all inside
  186. sxy_inout = 1;
  187. }
  188. else if ((sx_0 < -1 && sx_7 < -1) || (sx_0 >= srcw && sx_7 >= srcw) || (sy_0 < -1 && sy_7 < -1) || (sy_0 >= srch && sy_7 >= srch))
  189. {
  190. // all outside
  191. sxy_inout = 2;
  192. }
  193. }
  194. if (sxy_inout == 1)
  195. {
  196. // all inside
  197. #if __ARM_NEON
  198. int32x4_t _Xl = vaddq_s32(vdupq_n_s32(X0), vld1q_s32(adelta.data() + x));
  199. int32x4_t _Xh = vaddq_s32(vdupq_n_s32(X0), vld1q_s32(adelta.data() + x + 4));
  200. int32x4_t _Yl = vaddq_s32(vdupq_n_s32(Y0), vld1q_s32(bdelta.data() + x));
  201. int32x4_t _Yh = vaddq_s32(vdupq_n_s32(Y0), vld1q_s32(bdelta.data() + x + 4));
  202. int16x4_t _sxl = vqshrn_n_s32(_Xl, 10);
  203. int16x4_t _sxh = vqshrn_n_s32(_Xh, 10);
  204. int16x4_t _syl = vqshrn_n_s32(_Yl, 10);
  205. int16x4_t _syh = vqshrn_n_s32(_Yh, 10);
  206. uint32x4_t _v1024m1 = vdupq_n_u32((1 << 10) - 1);
  207. uint16x8_t _fx = vcombine_u16(vmovn_u32(vandq_u32(vreinterpretq_u32_s32(_Xl), _v1024m1)), vmovn_u32(vandq_u32(vreinterpretq_u32_s32(_Xh), _v1024m1)));
  208. uint16x8_t _fy = vcombine_u16(vmovn_u32(vandq_u32(vreinterpretq_u32_s32(_Yl), _v1024m1)), vmovn_u32(vandq_u32(vreinterpretq_u32_s32(_Yh), _v1024m1)));
  209. uint16x8_t _alpha0 = vsubq_u16(vdupq_n_u16(1 << 10), _fx);
  210. uint16x8_t _alpha1 = _fx;
  211. uint16x8_t _beta0 = vsubq_u16(vdupq_n_u16(1 << 10), _fy);
  212. uint16x8_t _beta1 = _fy;
  213. int16x4_t _srcstride = vdup_n_s16(srcstride);
  214. int32x4_t _a0l = vaddw_s16(vmull_s16(_srcstride, _syl), _sxl);
  215. int32x4_t _a0h = vaddw_s16(vmull_s16(_srcstride, _syh), _sxh);
  216. int32x4_t _b0l = vaddw_s16(_a0l, _srcstride);
  217. int32x4_t _b0h = vaddw_s16(_a0h, _srcstride);
  218. uint8x8x2_t _a0a1 = uint8x8x2_t();
  219. uint8x8x2_t _b0b1 = uint8x8x2_t();
  220. {
  221. _a0a1 = vld2_lane_u8(src0 + vgetq_lane_s32(_a0l, 0), _a0a1, 0);
  222. _b0b1 = vld2_lane_u8(src0 + vgetq_lane_s32(_b0l, 0), _b0b1, 0);
  223. _a0a1 = vld2_lane_u8(src0 + vgetq_lane_s32(_a0l, 1), _a0a1, 1);
  224. _b0b1 = vld2_lane_u8(src0 + vgetq_lane_s32(_b0l, 1), _b0b1, 1);
  225. _a0a1 = vld2_lane_u8(src0 + vgetq_lane_s32(_a0l, 2), _a0a1, 2);
  226. _b0b1 = vld2_lane_u8(src0 + vgetq_lane_s32(_b0l, 2), _b0b1, 2);
  227. _a0a1 = vld2_lane_u8(src0 + vgetq_lane_s32(_a0l, 3), _a0a1, 3);
  228. _b0b1 = vld2_lane_u8(src0 + vgetq_lane_s32(_b0l, 3), _b0b1, 3);
  229. _a0a1 = vld2_lane_u8(src0 + vgetq_lane_s32(_a0h, 0), _a0a1, 4);
  230. _b0b1 = vld2_lane_u8(src0 + vgetq_lane_s32(_b0h, 0), _b0b1, 4);
  231. _a0a1 = vld2_lane_u8(src0 + vgetq_lane_s32(_a0h, 1), _a0a1, 5);
  232. _b0b1 = vld2_lane_u8(src0 + vgetq_lane_s32(_b0h, 1), _b0b1, 5);
  233. _a0a1 = vld2_lane_u8(src0 + vgetq_lane_s32(_a0h, 2), _a0a1, 6);
  234. _b0b1 = vld2_lane_u8(src0 + vgetq_lane_s32(_b0h, 2), _b0b1, 6);
  235. _a0a1 = vld2_lane_u8(src0 + vgetq_lane_s32(_a0h, 3), _a0a1, 7);
  236. _b0b1 = vld2_lane_u8(src0 + vgetq_lane_s32(_b0h, 3), _b0b1, 7);
  237. }
  238. uint16x8_t _a0_0 = vmovl_u8(_a0a1.val[0]);
  239. uint16x8_t _a1_0 = vmovl_u8(_a0a1.val[1]);
  240. uint16x8_t _b0_0 = vmovl_u8(_b0b1.val[0]);
  241. uint16x8_t _b1_0 = vmovl_u8(_b0b1.val[1]);
  242. uint16x4_t _a00_0l = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_low_u16(_a0_0), vget_low_u16(_alpha0)), vget_low_u16(_a1_0), vget_low_u16(_alpha1)), 5);
  243. uint16x4_t _a00_0h = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_high_u16(_a0_0), vget_high_u16(_alpha0)), vget_high_u16(_a1_0), vget_high_u16(_alpha1)), 5);
  244. uint16x4_t _b00_0l = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_low_u16(_b0_0), vget_low_u16(_alpha0)), vget_low_u16(_b1_0), vget_low_u16(_alpha1)), 5);
  245. uint16x4_t _b00_0h = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_high_u16(_b0_0), vget_high_u16(_alpha0)), vget_high_u16(_b1_0), vget_high_u16(_alpha1)), 5);
  246. uint16x4_t _dst_0l = vqshrn_n_u32(vmlal_u16(vmull_u16(_a00_0l, vget_low_u16(_beta0)), _b00_0l, vget_low_u16(_beta1)), 15);
  247. uint16x4_t _dst_0h = vqshrn_n_u32(vmlal_u16(vmull_u16(_a00_0h, vget_high_u16(_beta0)), _b00_0h, vget_high_u16(_beta1)), 15);
  248. uint8x8_t _dst = vqmovn_u16(vcombine_u16(_dst_0l, _dst_0h));
  249. vst1_u8(dst0, _dst);
  250. dst0 += 8;
  251. #else
  252. for (int xi = 0; xi < 8; xi++)
  253. {
  254. int X = X0 + adelta[x + xi];
  255. int Y = Y0 + bdelta[x + xi];
  256. short sx = SATURATE_CAST_SHORT((X >> 10));
  257. short sy = SATURATE_CAST_SHORT((Y >> 10));
  258. short fx = X & ((1 << 10) - 1);
  259. short fy = Y & ((1 << 10) - 1);
  260. short alpha0 = (1 << 10) - fx;
  261. short alpha1 = fx;
  262. short beta0 = (1 << 10) - fy;
  263. short beta1 = fy;
  264. const unsigned char* a0 = src0 + srcstride * sy + sx;
  265. const unsigned char* a1 = src0 + srcstride * sy + sx + 1;
  266. const unsigned char* b0 = src0 + srcstride * (sy + 1) + sx;
  267. const unsigned char* b1 = src0 + srcstride * (sy + 1) + sx + 1;
  268. dst0[0] = (unsigned char)(((((unsigned short)((a0[0] * alpha0 + a1[0] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[0] * alpha0 + b1[0] * alpha1) >> 5) * beta1))) >> 15);
  269. dst0 += 1;
  270. }
  271. #endif // __ARM_NEON
  272. }
  273. else if (sxy_inout == 2)
  274. {
  275. // all outside
  276. if (type != -233)
  277. {
  278. #if __ARM_NEON
  279. uint8x8_t _border_color = vdup_n_u8(border_color[0]);
  280. vst1_u8(dst0, _border_color);
  281. #else
  282. for (int xi = 0; xi < 8; xi++)
  283. {
  284. dst0[xi] = border_color[0];
  285. }
  286. #endif // __ARM_NEON
  287. }
  288. else
  289. {
  290. // skip
  291. }
  292. dst0 += 8;
  293. }
  294. else // if (sxy_inout == 0)
  295. {
  296. for (int xi = 0; xi < 8; xi++)
  297. {
  298. int X = X0 + adelta[x + xi];
  299. int Y = Y0 + bdelta[x + xi];
  300. short sx = SATURATE_CAST_SHORT((X >> 10));
  301. short sy = SATURATE_CAST_SHORT((Y >> 10));
  302. if (type != -233 && (sx < -1 || sx >= srcw || sy < -1 || sy >= srch))
  303. {
  304. dst0[0] = border_color[0];
  305. }
  306. else if (type == -233 && ((unsigned short)sx >= srcw - 1 || (unsigned short)sy >= srch - 1))
  307. {
  308. // skip
  309. }
  310. else
  311. {
  312. short fx = X & ((1 << 10) - 1);
  313. short fy = Y & ((1 << 10) - 1);
  314. short alpha0 = (1 << 10) - fx;
  315. short alpha1 = fx;
  316. short beta0 = (1 << 10) - fy;
  317. short beta1 = fy;
  318. short sx1 = sx + 1;
  319. short sy1 = sy + 1;
  320. const unsigned char* a0 = src0 + srcstride * sy + sx;
  321. const unsigned char* a1 = src0 + srcstride * sy + sx + 1;
  322. const unsigned char* b0 = src0 + srcstride * (sy + 1) + sx;
  323. const unsigned char* b1 = src0 + srcstride * (sy + 1) + sx + 1;
  324. if ((unsigned short)sx >= srcw || (unsigned short)sy >= srch)
  325. {
  326. a0 = type != -233 ? border_color : dst0;
  327. }
  328. if ((unsigned short)sx1 >= srcw || (unsigned short)sy >= srch)
  329. {
  330. a1 = type != -233 ? border_color : dst0;
  331. }
  332. if ((unsigned short)sx >= srcw || (unsigned short)sy1 >= srch)
  333. {
  334. b0 = type != -233 ? border_color : dst0;
  335. }
  336. if ((unsigned short)sx1 >= srcw || (unsigned short)sy1 >= srch)
  337. {
  338. b1 = type != -233 ? border_color : dst0;
  339. }
  340. dst0[0] = (unsigned char)(((((unsigned short)((a0[0] * alpha0 + a1[0] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[0] * alpha0 + b1[0] * alpha1) >> 5) * beta1))) >> 15);
  341. }
  342. dst0 += 1;
  343. }
  344. }
  345. }
  346. for (; x < w; x++)
  347. {
  348. int X = X0 + adelta[x];
  349. int Y = Y0 + bdelta[x];
  350. short sx = SATURATE_CAST_SHORT((X >> 10));
  351. short sy = SATURATE_CAST_SHORT((Y >> 10));
  352. if (type != -233 && (sx < -1 || sx >= srcw || sy < -1 || sy >= srch))
  353. {
  354. dst0[0] = border_color[0];
  355. }
  356. else if (type == -233 && ((unsigned short)sx >= srcw - 1 || (unsigned short)sy >= srch - 1))
  357. {
  358. // skip
  359. }
  360. else
  361. {
  362. short fx = X & ((1 << 10) - 1);
  363. short fy = Y & ((1 << 10) - 1);
  364. short alpha0 = (1 << 10) - fx;
  365. short alpha1 = fx;
  366. short beta0 = (1 << 10) - fy;
  367. short beta1 = fy;
  368. short sx1 = sx + 1;
  369. short sy1 = sy + 1;
  370. const unsigned char* a0 = src0 + srcstride * sy + sx;
  371. const unsigned char* a1 = src0 + srcstride * sy + sx + 1;
  372. const unsigned char* b0 = src0 + srcstride * (sy + 1) + sx;
  373. const unsigned char* b1 = src0 + srcstride * (sy + 1) + sx + 1;
  374. if ((unsigned short)sx >= srcw || (unsigned short)sy >= srch)
  375. {
  376. a0 = type != -233 ? border_color : dst0;
  377. }
  378. if ((unsigned short)sx1 >= srcw || (unsigned short)sy >= srch)
  379. {
  380. a1 = type != -233 ? border_color : dst0;
  381. }
  382. if ((unsigned short)sx >= srcw || (unsigned short)sy1 >= srch)
  383. {
  384. b0 = type != -233 ? border_color : dst0;
  385. }
  386. if ((unsigned short)sx1 >= srcw || (unsigned short)sy1 >= srch)
  387. {
  388. b1 = type != -233 ? border_color : dst0;
  389. }
  390. dst0[0] = (unsigned char)(((((unsigned short)((a0[0] * alpha0 + a1[0] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[0] * alpha0 + b1[0] * alpha1) >> 5) * beta1))) >> 15);
  391. }
  392. dst0 += 1;
  393. }
  394. dst0 += wgap;
  395. }
  396. #undef SATURATE_CAST_SHORT
  397. #undef SATURATE_CAST_INT
  398. }
  399. void warpaffine_bilinear_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type, unsigned int v)
  400. {
  401. const unsigned char* border_color = (const unsigned char*)&v;
  402. const int wgap = stride - w * 2;
  403. const unsigned char* src0 = src;
  404. unsigned char* dst0 = dst;
  405. #define SATURATE_CAST_SHORT(X) (short)::std::min(::std::max((int)(X), SHRT_MIN), SHRT_MAX)
  406. #define SATURATE_CAST_INT(X) (int)::std::min(::std::max((int)((X) + ((X) >= 0.f ? 0.5f : -0.5f)), INT_MIN), INT_MAX)
  407. std::vector<int> adelta(w);
  408. std::vector<int> bdelta(w);
  409. for (int x = 0; x < w; x++)
  410. {
  411. adelta[x] = SATURATE_CAST_INT(tm[0] * x * (1 << 10));
  412. bdelta[x] = SATURATE_CAST_INT(tm[3] * x * (1 << 10));
  413. }
  414. int y = 0;
  415. for (; y < h; y++)
  416. {
  417. int X0 = SATURATE_CAST_INT((tm[1] * y + tm[2]) * (1 << 10));
  418. int Y0 = SATURATE_CAST_INT((tm[4] * y + tm[5]) * (1 << 10));
  419. int x = 0;
  420. for (; x + 7 < w; x += 8)
  421. {
  422. int sxy_inout = 0;
  423. {
  424. int X_0 = X0 + adelta[x];
  425. int Y_0 = Y0 + bdelta[x];
  426. int X_7 = X0 + adelta[x + 7];
  427. int Y_7 = Y0 + bdelta[x + 7];
  428. short sx_0 = SATURATE_CAST_SHORT((X_0 >> 10));
  429. short sy_0 = SATURATE_CAST_SHORT((Y_0 >> 10));
  430. short sx_7 = SATURATE_CAST_SHORT((X_7 >> 10));
  431. short sy_7 = SATURATE_CAST_SHORT((Y_7 >> 10));
  432. if (((unsigned short)sx_0 < srcw - 1 && (unsigned short)sy_0 < srch - 1) && ((unsigned short)sx_7 < srcw - 1 && (unsigned short)sy_7 < srch - 1))
  433. {
  434. // all inside
  435. sxy_inout = 1;
  436. }
  437. else if ((sx_0 < -1 && sx_7 < -1) || (sx_0 >= srcw && sx_7 >= srcw) || (sy_0 < -1 && sy_7 < -1) || (sy_0 >= srch && sy_7 >= srch))
  438. {
  439. // all outside
  440. sxy_inout = 2;
  441. }
  442. }
  443. if (sxy_inout == 1)
  444. {
  445. // all inside
  446. #if __ARM_NEON
  447. int32x4_t _Xl = vaddq_s32(vdupq_n_s32(X0), vld1q_s32(adelta.data() + x));
  448. int32x4_t _Xh = vaddq_s32(vdupq_n_s32(X0), vld1q_s32(adelta.data() + x + 4));
  449. int32x4_t _Yl = vaddq_s32(vdupq_n_s32(Y0), vld1q_s32(bdelta.data() + x));
  450. int32x4_t _Yh = vaddq_s32(vdupq_n_s32(Y0), vld1q_s32(bdelta.data() + x + 4));
  451. int16x4_t _sxl = vqshrn_n_s32(_Xl, 10);
  452. int16x4_t _sxh = vqshrn_n_s32(_Xh, 10);
  453. int16x4_t _syl = vqshrn_n_s32(_Yl, 10);
  454. int16x4_t _syh = vqshrn_n_s32(_Yh, 10);
  455. uint32x4_t _v1024m1 = vdupq_n_u32((1 << 10) - 1);
  456. uint16x8_t _fx = vcombine_u16(vmovn_u32(vandq_u32(vreinterpretq_u32_s32(_Xl), _v1024m1)), vmovn_u32(vandq_u32(vreinterpretq_u32_s32(_Xh), _v1024m1)));
  457. uint16x8_t _fy = vcombine_u16(vmovn_u32(vandq_u32(vreinterpretq_u32_s32(_Yl), _v1024m1)), vmovn_u32(vandq_u32(vreinterpretq_u32_s32(_Yh), _v1024m1)));
  458. uint16x8_t _alpha0 = vsubq_u16(vdupq_n_u16(1 << 10), _fx);
  459. uint16x8_t _alpha1 = _fx;
  460. uint16x8_t _beta0 = vsubq_u16(vdupq_n_u16(1 << 10), _fy);
  461. uint16x8_t _beta1 = _fy;
  462. int16x4_t _srcstride = vdup_n_s16(srcstride);
  463. int16x4_t _v2 = vdup_n_s16(2);
  464. int32x4_t _a0l = vmlal_s16(vmull_s16(_srcstride, _syl), _sxl, _v2);
  465. int32x4_t _a0h = vmlal_s16(vmull_s16(_srcstride, _syh), _sxh, _v2);
  466. int32x4_t _b0l = vaddw_s16(_a0l, _srcstride);
  467. int32x4_t _b0h = vaddw_s16(_a0h, _srcstride);
  468. uint8x8x4_t _a0a1 = uint8x8x4_t();
  469. uint8x8x4_t _b0b1 = uint8x8x4_t();
  470. {
  471. _a0a1 = vld4_lane_u8(src0 + vgetq_lane_s32(_a0l, 0), _a0a1, 0);
  472. _b0b1 = vld4_lane_u8(src0 + vgetq_lane_s32(_b0l, 0), _b0b1, 0);
  473. _a0a1 = vld4_lane_u8(src0 + vgetq_lane_s32(_a0l, 1), _a0a1, 1);
  474. _b0b1 = vld4_lane_u8(src0 + vgetq_lane_s32(_b0l, 1), _b0b1, 1);
  475. _a0a1 = vld4_lane_u8(src0 + vgetq_lane_s32(_a0l, 2), _a0a1, 2);
  476. _b0b1 = vld4_lane_u8(src0 + vgetq_lane_s32(_b0l, 2), _b0b1, 2);
  477. _a0a1 = vld4_lane_u8(src0 + vgetq_lane_s32(_a0l, 3), _a0a1, 3);
  478. _b0b1 = vld4_lane_u8(src0 + vgetq_lane_s32(_b0l, 3), _b0b1, 3);
  479. _a0a1 = vld4_lane_u8(src0 + vgetq_lane_s32(_a0h, 0), _a0a1, 4);
  480. _b0b1 = vld4_lane_u8(src0 + vgetq_lane_s32(_b0h, 0), _b0b1, 4);
  481. _a0a1 = vld4_lane_u8(src0 + vgetq_lane_s32(_a0h, 1), _a0a1, 5);
  482. _b0b1 = vld4_lane_u8(src0 + vgetq_lane_s32(_b0h, 1), _b0b1, 5);
  483. _a0a1 = vld4_lane_u8(src0 + vgetq_lane_s32(_a0h, 2), _a0a1, 6);
  484. _b0b1 = vld4_lane_u8(src0 + vgetq_lane_s32(_b0h, 2), _b0b1, 6);
  485. _a0a1 = vld4_lane_u8(src0 + vgetq_lane_s32(_a0h, 3), _a0a1, 7);
  486. _b0b1 = vld4_lane_u8(src0 + vgetq_lane_s32(_b0h, 3), _b0b1, 7);
  487. }
  488. uint16x8_t _a0_0 = vmovl_u8(_a0a1.val[0]);
  489. uint16x8_t _a0_1 = vmovl_u8(_a0a1.val[1]);
  490. uint16x8_t _a1_0 = vmovl_u8(_a0a1.val[2]);
  491. uint16x8_t _a1_1 = vmovl_u8(_a0a1.val[3]);
  492. uint16x8_t _b0_0 = vmovl_u8(_b0b1.val[0]);
  493. uint16x8_t _b0_1 = vmovl_u8(_b0b1.val[1]);
  494. uint16x8_t _b1_0 = vmovl_u8(_b0b1.val[2]);
  495. uint16x8_t _b1_1 = vmovl_u8(_b0b1.val[3]);
  496. uint16x4_t _a00_0l = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_low_u16(_a0_0), vget_low_u16(_alpha0)), vget_low_u16(_a1_0), vget_low_u16(_alpha1)), 5);
  497. uint16x4_t _a00_1l = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_low_u16(_a0_1), vget_low_u16(_alpha0)), vget_low_u16(_a1_1), vget_low_u16(_alpha1)), 5);
  498. uint16x4_t _a00_0h = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_high_u16(_a0_0), vget_high_u16(_alpha0)), vget_high_u16(_a1_0), vget_high_u16(_alpha1)), 5);
  499. uint16x4_t _a00_1h = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_high_u16(_a0_1), vget_high_u16(_alpha0)), vget_high_u16(_a1_1), vget_high_u16(_alpha1)), 5);
  500. uint16x4_t _b00_0l = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_low_u16(_b0_0), vget_low_u16(_alpha0)), vget_low_u16(_b1_0), vget_low_u16(_alpha1)), 5);
  501. uint16x4_t _b00_1l = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_low_u16(_b0_1), vget_low_u16(_alpha0)), vget_low_u16(_b1_1), vget_low_u16(_alpha1)), 5);
  502. uint16x4_t _b00_0h = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_high_u16(_b0_0), vget_high_u16(_alpha0)), vget_high_u16(_b1_0), vget_high_u16(_alpha1)), 5);
  503. uint16x4_t _b00_1h = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_high_u16(_b0_1), vget_high_u16(_alpha0)), vget_high_u16(_b1_1), vget_high_u16(_alpha1)), 5);
  504. uint16x4_t _dst_0l = vqshrn_n_u32(vmlal_u16(vmull_u16(_a00_0l, vget_low_u16(_beta0)), _b00_0l, vget_low_u16(_beta1)), 15);
  505. uint16x4_t _dst_1l = vqshrn_n_u32(vmlal_u16(vmull_u16(_a00_1l, vget_low_u16(_beta0)), _b00_1l, vget_low_u16(_beta1)), 15);
  506. uint16x4_t _dst_0h = vqshrn_n_u32(vmlal_u16(vmull_u16(_a00_0h, vget_high_u16(_beta0)), _b00_0h, vget_high_u16(_beta1)), 15);
  507. uint16x4_t _dst_1h = vqshrn_n_u32(vmlal_u16(vmull_u16(_a00_1h, vget_high_u16(_beta0)), _b00_1h, vget_high_u16(_beta1)), 15);
  508. uint8x8x2_t _dst;
  509. _dst.val[0] = vqmovn_u16(vcombine_u16(_dst_0l, _dst_0h));
  510. _dst.val[1] = vqmovn_u16(vcombine_u16(_dst_1l, _dst_1h));
  511. vst2_u8(dst0, _dst);
  512. dst0 += 2 * 8;
  513. #else
  514. for (int xi = 0; xi < 8; xi++)
  515. {
  516. int X = X0 + adelta[x + xi];
  517. int Y = Y0 + bdelta[x + xi];
  518. short sx = SATURATE_CAST_SHORT((X >> 10));
  519. short sy = SATURATE_CAST_SHORT((Y >> 10));
  520. short fx = X & ((1 << 10) - 1);
  521. short fy = Y & ((1 << 10) - 1);
  522. short alpha0 = (1 << 10) - fx;
  523. short alpha1 = fx;
  524. short beta0 = (1 << 10) - fy;
  525. short beta1 = fy;
  526. const unsigned char* a0 = src0 + srcstride * sy + sx * 2;
  527. const unsigned char* a1 = src0 + srcstride * sy + sx * 2 + 2;
  528. const unsigned char* b0 = src0 + srcstride * (sy + 1) + sx * 2;
  529. const unsigned char* b1 = src0 + srcstride * (sy + 1) + sx * 2 + 2;
  530. dst0[0] = (unsigned char)(((((unsigned short)((a0[0] * alpha0 + a1[0] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[0] * alpha0 + b1[0] * alpha1) >> 5) * beta1))) >> 15);
  531. dst0[1] = (unsigned char)(((((unsigned short)((a0[1] * alpha0 + a1[1] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[1] * alpha0 + b1[1] * alpha1) >> 5) * beta1))) >> 15);
  532. dst0 += 2;
  533. }
  534. #endif // __ARM_NEON
  535. }
  536. else if (sxy_inout == 2)
  537. {
  538. // all outside
  539. if (type != -233)
  540. {
  541. #if __ARM_NEON
  542. uint8x8x2_t _border_color;
  543. _border_color.val[0] = vdup_n_u8(border_color[0]);
  544. _border_color.val[1] = vdup_n_u8(border_color[1]);
  545. vst2_u8(dst0, _border_color);
  546. #else
  547. for (int xi = 0; xi < 8; xi++)
  548. {
  549. dst0[xi * 2] = border_color[0];
  550. dst0[xi * 2 + 1] = border_color[1];
  551. }
  552. #endif
  553. }
  554. else
  555. {
  556. // skip
  557. }
  558. dst0 += 16;
  559. }
  560. else // if (sxy_inout == 0)
  561. {
  562. for (int xi = 0; xi < 8; xi++)
  563. {
  564. int X = X0 + adelta[x + xi];
  565. int Y = Y0 + bdelta[x + xi];
  566. short sx = SATURATE_CAST_SHORT((X >> 10));
  567. short sy = SATURATE_CAST_SHORT((Y >> 10));
  568. if (type != -233 && (sx < -1 || sx >= srcw || sy < -1 || sy >= srch))
  569. {
  570. dst0[0] = border_color[0];
  571. dst0[1] = border_color[1];
  572. }
  573. else if (type == -233 && ((unsigned short)sx >= srcw - 1 || (unsigned short)sy >= srch - 1))
  574. {
  575. // skip
  576. }
  577. else
  578. {
  579. short fx = X & ((1 << 10) - 1);
  580. short fy = Y & ((1 << 10) - 1);
  581. short alpha0 = (1 << 10) - fx;
  582. short alpha1 = fx;
  583. short beta0 = (1 << 10) - fy;
  584. short beta1 = fy;
  585. short sx1 = sx + 1;
  586. short sy1 = sy + 1;
  587. const unsigned char* a0 = src0 + srcstride * sy + sx * 2;
  588. const unsigned char* a1 = src0 + srcstride * sy + sx * 2 + 2;
  589. const unsigned char* b0 = src0 + srcstride * (sy + 1) + sx * 2;
  590. const unsigned char* b1 = src0 + srcstride * (sy + 1) + sx * 2 + 2;
  591. if ((unsigned short)sx >= srcw || (unsigned short)sy >= srch)
  592. {
  593. a0 = type != -233 ? border_color : dst0;
  594. }
  595. if ((unsigned short)sx1 >= srcw || (unsigned short)sy >= srch)
  596. {
  597. a1 = type != -233 ? border_color : dst0;
  598. }
  599. if ((unsigned short)sx >= srcw || (unsigned short)sy1 >= srch)
  600. {
  601. b0 = type != -233 ? border_color : dst0;
  602. }
  603. if ((unsigned short)sx1 >= srcw || (unsigned short)sy1 >= srch)
  604. {
  605. b1 = type != -233 ? border_color : dst0;
  606. }
  607. dst0[0] = (unsigned char)(((((unsigned short)((a0[0] * alpha0 + a1[0] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[0] * alpha0 + b1[0] * alpha1) >> 5) * beta1))) >> 15);
  608. dst0[1] = (unsigned char)(((((unsigned short)((a0[1] * alpha0 + a1[1] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[1] * alpha0 + b1[1] * alpha1) >> 5) * beta1))) >> 15);
  609. }
  610. dst0 += 2;
  611. }
  612. }
  613. }
  614. for (; x < w; x++)
  615. {
  616. int X = X0 + adelta[x];
  617. int Y = Y0 + bdelta[x];
  618. short sx = SATURATE_CAST_SHORT((X >> 10));
  619. short sy = SATURATE_CAST_SHORT((Y >> 10));
  620. if (type != -233 && (sx < -1 || sx >= srcw || sy < -1 || sy >= srch))
  621. {
  622. dst0[0] = border_color[0];
  623. dst0[1] = border_color[1];
  624. }
  625. else if (type == -233 && ((unsigned short)sx >= srcw - 1 || (unsigned short)sy >= srch - 1))
  626. {
  627. // skip
  628. }
  629. else
  630. {
  631. short fx = X & ((1 << 10) - 1);
  632. short fy = Y & ((1 << 10) - 1);
  633. short alpha0 = (1 << 10) - fx;
  634. short alpha1 = fx;
  635. short beta0 = (1 << 10) - fy;
  636. short beta1 = fy;
  637. short sx1 = sx + 1;
  638. short sy1 = sy + 1;
  639. const unsigned char* a0 = src0 + srcstride * sy + sx * 2;
  640. const unsigned char* a1 = src0 + srcstride * sy + sx * 2 + 2;
  641. const unsigned char* b0 = src0 + srcstride * (sy + 1) + sx * 2;
  642. const unsigned char* b1 = src0 + srcstride * (sy + 1) + sx * 2 + 2;
  643. if ((unsigned short)sx >= srcw || (unsigned short)sy >= srch)
  644. {
  645. a0 = type != -233 ? border_color : dst0;
  646. }
  647. if ((unsigned short)sx1 >= srcw || (unsigned short)sy >= srch)
  648. {
  649. a1 = type != -233 ? border_color : dst0;
  650. }
  651. if ((unsigned short)sx >= srcw || (unsigned short)sy1 >= srch)
  652. {
  653. b0 = type != -233 ? border_color : dst0;
  654. }
  655. if ((unsigned short)sx1 >= srcw || (unsigned short)sy1 >= srch)
  656. {
  657. b1 = type != -233 ? border_color : dst0;
  658. }
  659. dst0[0] = (unsigned char)(((((unsigned short)((a0[0] * alpha0 + a1[0] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[0] * alpha0 + b1[0] * alpha1) >> 5) * beta1))) >> 15);
  660. dst0[1] = (unsigned char)(((((unsigned short)((a0[1] * alpha0 + a1[1] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[1] * alpha0 + b1[1] * alpha1) >> 5) * beta1))) >> 15);
  661. }
  662. dst0 += 2;
  663. }
  664. dst0 += wgap;
  665. }
  666. #undef SATURATE_CAST_SHORT
  667. #undef SATURATE_CAST_INT
  668. }
  669. void warpaffine_bilinear_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type, unsigned int v)
  670. {
  671. const unsigned char* border_color = (const unsigned char*)&v;
  672. const int wgap = stride - w * 3;
  673. const unsigned char* src0 = src;
  674. unsigned char* dst0 = dst;
  675. #define SATURATE_CAST_SHORT(X) (short)::std::min(::std::max((int)(X), SHRT_MIN), SHRT_MAX)
  676. #define SATURATE_CAST_INT(X) (int)::std::min(::std::max((int)((X) + ((X) >= 0.f ? 0.5f : -0.5f)), INT_MIN), INT_MAX)
  677. std::vector<int> adelta(w);
  678. std::vector<int> bdelta(w);
  679. for (int x = 0; x < w; x++)
  680. {
  681. adelta[x] = SATURATE_CAST_INT(tm[0] * x * (1 << 10));
  682. bdelta[x] = SATURATE_CAST_INT(tm[3] * x * (1 << 10));
  683. }
  684. int y = 0;
  685. for (; y < h; y++)
  686. {
  687. int X0 = SATURATE_CAST_INT((tm[1] * y + tm[2]) * (1 << 10));
  688. int Y0 = SATURATE_CAST_INT((tm[4] * y + tm[5]) * (1 << 10));
  689. int x = 0;
  690. for (; x + 7 < w; x += 8)
  691. {
  692. int sxy_inout = 0;
  693. {
  694. int X_0 = X0 + adelta[x];
  695. int Y_0 = Y0 + bdelta[x];
  696. int X_7 = X0 + adelta[x + 7];
  697. int Y_7 = Y0 + bdelta[x + 7];
  698. short sx_0 = SATURATE_CAST_SHORT((X_0 >> 10));
  699. short sy_0 = SATURATE_CAST_SHORT((Y_0 >> 10));
  700. short sx_7 = SATURATE_CAST_SHORT((X_7 >> 10));
  701. short sy_7 = SATURATE_CAST_SHORT((Y_7 >> 10));
  702. if (((unsigned short)sx_0 < srcw - 1 && (unsigned short)sy_0 < srch - 1) && ((unsigned short)sx_7 < srcw - 1 && (unsigned short)sy_7 < srch - 1))
  703. {
  704. // all inside
  705. sxy_inout = 1;
  706. }
  707. else if ((sx_0 < -1 && sx_7 < -1) || (sx_0 >= srcw && sx_7 >= srcw) || (sy_0 < -1 && sy_7 < -1) || (sy_0 >= srch && sy_7 >= srch))
  708. {
  709. // all outside
  710. sxy_inout = 2;
  711. }
  712. }
  713. if (sxy_inout == 1)
  714. {
  715. // all inside
  716. #if __ARM_NEON
  717. int32x4_t _Xl = vaddq_s32(vdupq_n_s32(X0), vld1q_s32(adelta.data() + x));
  718. int32x4_t _Xh = vaddq_s32(vdupq_n_s32(X0), vld1q_s32(adelta.data() + x + 4));
  719. int32x4_t _Yl = vaddq_s32(vdupq_n_s32(Y0), vld1q_s32(bdelta.data() + x));
  720. int32x4_t _Yh = vaddq_s32(vdupq_n_s32(Y0), vld1q_s32(bdelta.data() + x + 4));
  721. int16x4_t _sxl = vqshrn_n_s32(_Xl, 10);
  722. int16x4_t _sxh = vqshrn_n_s32(_Xh, 10);
  723. int16x4_t _syl = vqshrn_n_s32(_Yl, 10);
  724. int16x4_t _syh = vqshrn_n_s32(_Yh, 10);
  725. uint32x4_t _v1024m1 = vdupq_n_u32((1 << 10) - 1);
  726. uint16x8_t _fx = vcombine_u16(vmovn_u32(vandq_u32(vreinterpretq_u32_s32(_Xl), _v1024m1)), vmovn_u32(vandq_u32(vreinterpretq_u32_s32(_Xh), _v1024m1)));
  727. uint16x8_t _fy = vcombine_u16(vmovn_u32(vandq_u32(vreinterpretq_u32_s32(_Yl), _v1024m1)), vmovn_u32(vandq_u32(vreinterpretq_u32_s32(_Yh), _v1024m1)));
  728. uint16x8_t _alpha0 = vsubq_u16(vdupq_n_u16(1 << 10), _fx);
  729. uint16x8_t _alpha1 = _fx;
  730. uint16x8_t _beta0 = vsubq_u16(vdupq_n_u16(1 << 10), _fy);
  731. uint16x8_t _beta1 = _fy;
  732. int16x4_t _srcstride = vdup_n_s16(srcstride);
  733. int16x4_t _v3 = vdup_n_s16(3);
  734. int32x4_t _a0l = vmlal_s16(vmull_s16(_srcstride, _syl), _sxl, _v3);
  735. int32x4_t _a0h = vmlal_s16(vmull_s16(_srcstride, _syh), _sxh, _v3);
  736. int32x4_t _b0l = vaddw_s16(_a0l, _srcstride);
  737. int32x4_t _b0h = vaddw_s16(_a0h, _srcstride);
  738. int32x4_t _a1l = vaddw_s16(_a0l, _v3);
  739. int32x4_t _a1h = vaddw_s16(_a0h, _v3);
  740. int32x4_t _b1l = vaddw_s16(_b0l, _v3);
  741. int32x4_t _b1h = vaddw_s16(_b0h, _v3);
  742. uint8x8x3_t _a0 = uint8x8x3_t();
  743. uint8x8x3_t _a1 = uint8x8x3_t();
  744. uint8x8x3_t _b0 = uint8x8x3_t();
  745. uint8x8x3_t _b1 = uint8x8x3_t();
  746. {
  747. _a0 = vld3_lane_u8(src0 + vgetq_lane_s32(_a0l, 0), _a0, 0);
  748. _a1 = vld3_lane_u8(src0 + vgetq_lane_s32(_a1l, 0), _a1, 0);
  749. _b0 = vld3_lane_u8(src0 + vgetq_lane_s32(_b0l, 0), _b0, 0);
  750. _b1 = vld3_lane_u8(src0 + vgetq_lane_s32(_b1l, 0), _b1, 0);
  751. _a0 = vld3_lane_u8(src0 + vgetq_lane_s32(_a0l, 1), _a0, 1);
  752. _a1 = vld3_lane_u8(src0 + vgetq_lane_s32(_a1l, 1), _a1, 1);
  753. _b0 = vld3_lane_u8(src0 + vgetq_lane_s32(_b0l, 1), _b0, 1);
  754. _b1 = vld3_lane_u8(src0 + vgetq_lane_s32(_b1l, 1), _b1, 1);
  755. _a0 = vld3_lane_u8(src0 + vgetq_lane_s32(_a0l, 2), _a0, 2);
  756. _a1 = vld3_lane_u8(src0 + vgetq_lane_s32(_a1l, 2), _a1, 2);
  757. _b0 = vld3_lane_u8(src0 + vgetq_lane_s32(_b0l, 2), _b0, 2);
  758. _b1 = vld3_lane_u8(src0 + vgetq_lane_s32(_b1l, 2), _b1, 2);
  759. _a0 = vld3_lane_u8(src0 + vgetq_lane_s32(_a0l, 3), _a0, 3);
  760. _a1 = vld3_lane_u8(src0 + vgetq_lane_s32(_a1l, 3), _a1, 3);
  761. _b0 = vld3_lane_u8(src0 + vgetq_lane_s32(_b0l, 3), _b0, 3);
  762. _b1 = vld3_lane_u8(src0 + vgetq_lane_s32(_b1l, 3), _b1, 3);
  763. _a0 = vld3_lane_u8(src0 + vgetq_lane_s32(_a0h, 0), _a0, 4);
  764. _a1 = vld3_lane_u8(src0 + vgetq_lane_s32(_a1h, 0), _a1, 4);
  765. _b0 = vld3_lane_u8(src0 + vgetq_lane_s32(_b0h, 0), _b0, 4);
  766. _b1 = vld3_lane_u8(src0 + vgetq_lane_s32(_b1h, 0), _b1, 4);
  767. _a0 = vld3_lane_u8(src0 + vgetq_lane_s32(_a0h, 1), _a0, 5);
  768. _a1 = vld3_lane_u8(src0 + vgetq_lane_s32(_a1h, 1), _a1, 5);
  769. _b0 = vld3_lane_u8(src0 + vgetq_lane_s32(_b0h, 1), _b0, 5);
  770. _b1 = vld3_lane_u8(src0 + vgetq_lane_s32(_b1h, 1), _b1, 5);
  771. _a0 = vld3_lane_u8(src0 + vgetq_lane_s32(_a0h, 2), _a0, 6);
  772. _a1 = vld3_lane_u8(src0 + vgetq_lane_s32(_a1h, 2), _a1, 6);
  773. _b0 = vld3_lane_u8(src0 + vgetq_lane_s32(_b0h, 2), _b0, 6);
  774. _b1 = vld3_lane_u8(src0 + vgetq_lane_s32(_b1h, 2), _b1, 6);
  775. _a0 = vld3_lane_u8(src0 + vgetq_lane_s32(_a0h, 3), _a0, 7);
  776. _a1 = vld3_lane_u8(src0 + vgetq_lane_s32(_a1h, 3), _a1, 7);
  777. _b0 = vld3_lane_u8(src0 + vgetq_lane_s32(_b0h, 3), _b0, 7);
  778. _b1 = vld3_lane_u8(src0 + vgetq_lane_s32(_b1h, 3), _b1, 7);
  779. }
  780. uint16x8_t _a0_0 = vmovl_u8(_a0.val[0]);
  781. uint16x8_t _a0_1 = vmovl_u8(_a0.val[1]);
  782. uint16x8_t _a0_2 = vmovl_u8(_a0.val[2]);
  783. uint16x8_t _a1_0 = vmovl_u8(_a1.val[0]);
  784. uint16x8_t _a1_1 = vmovl_u8(_a1.val[1]);
  785. uint16x8_t _a1_2 = vmovl_u8(_a1.val[2]);
  786. uint16x8_t _b0_0 = vmovl_u8(_b0.val[0]);
  787. uint16x8_t _b0_1 = vmovl_u8(_b0.val[1]);
  788. uint16x8_t _b0_2 = vmovl_u8(_b0.val[2]);
  789. uint16x8_t _b1_0 = vmovl_u8(_b1.val[0]);
  790. uint16x8_t _b1_1 = vmovl_u8(_b1.val[1]);
  791. uint16x8_t _b1_2 = vmovl_u8(_b1.val[2]);
  792. uint16x4_t _a00_0l = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_low_u16(_a0_0), vget_low_u16(_alpha0)), vget_low_u16(_a1_0), vget_low_u16(_alpha1)), 5);
  793. uint16x4_t _a00_1l = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_low_u16(_a0_1), vget_low_u16(_alpha0)), vget_low_u16(_a1_1), vget_low_u16(_alpha1)), 5);
  794. uint16x4_t _a00_2l = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_low_u16(_a0_2), vget_low_u16(_alpha0)), vget_low_u16(_a1_2), vget_low_u16(_alpha1)), 5);
  795. uint16x4_t _a00_0h = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_high_u16(_a0_0), vget_high_u16(_alpha0)), vget_high_u16(_a1_0), vget_high_u16(_alpha1)), 5);
  796. uint16x4_t _a00_1h = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_high_u16(_a0_1), vget_high_u16(_alpha0)), vget_high_u16(_a1_1), vget_high_u16(_alpha1)), 5);
  797. uint16x4_t _a00_2h = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_high_u16(_a0_2), vget_high_u16(_alpha0)), vget_high_u16(_a1_2), vget_high_u16(_alpha1)), 5);
  798. uint16x4_t _b00_0l = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_low_u16(_b0_0), vget_low_u16(_alpha0)), vget_low_u16(_b1_0), vget_low_u16(_alpha1)), 5);
  799. uint16x4_t _b00_1l = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_low_u16(_b0_1), vget_low_u16(_alpha0)), vget_low_u16(_b1_1), vget_low_u16(_alpha1)), 5);
  800. uint16x4_t _b00_2l = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_low_u16(_b0_2), vget_low_u16(_alpha0)), vget_low_u16(_b1_2), vget_low_u16(_alpha1)), 5);
  801. uint16x4_t _b00_0h = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_high_u16(_b0_0), vget_high_u16(_alpha0)), vget_high_u16(_b1_0), vget_high_u16(_alpha1)), 5);
  802. uint16x4_t _b00_1h = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_high_u16(_b0_1), vget_high_u16(_alpha0)), vget_high_u16(_b1_1), vget_high_u16(_alpha1)), 5);
  803. uint16x4_t _b00_2h = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_high_u16(_b0_2), vget_high_u16(_alpha0)), vget_high_u16(_b1_2), vget_high_u16(_alpha1)), 5);
  804. uint16x4_t _dst_0l = vqshrn_n_u32(vmlal_u16(vmull_u16(_a00_0l, vget_low_u16(_beta0)), _b00_0l, vget_low_u16(_beta1)), 15);
  805. uint16x4_t _dst_1l = vqshrn_n_u32(vmlal_u16(vmull_u16(_a00_1l, vget_low_u16(_beta0)), _b00_1l, vget_low_u16(_beta1)), 15);
  806. uint16x4_t _dst_2l = vqshrn_n_u32(vmlal_u16(vmull_u16(_a00_2l, vget_low_u16(_beta0)), _b00_2l, vget_low_u16(_beta1)), 15);
  807. uint16x4_t _dst_0h = vqshrn_n_u32(vmlal_u16(vmull_u16(_a00_0h, vget_high_u16(_beta0)), _b00_0h, vget_high_u16(_beta1)), 15);
  808. uint16x4_t _dst_1h = vqshrn_n_u32(vmlal_u16(vmull_u16(_a00_1h, vget_high_u16(_beta0)), _b00_1h, vget_high_u16(_beta1)), 15);
  809. uint16x4_t _dst_2h = vqshrn_n_u32(vmlal_u16(vmull_u16(_a00_2h, vget_high_u16(_beta0)), _b00_2h, vget_high_u16(_beta1)), 15);
  810. uint8x8x3_t _dst;
  811. _dst.val[0] = vqmovn_u16(vcombine_u16(_dst_0l, _dst_0h));
  812. _dst.val[1] = vqmovn_u16(vcombine_u16(_dst_1l, _dst_1h));
  813. _dst.val[2] = vqmovn_u16(vcombine_u16(_dst_2l, _dst_2h));
  814. vst3_u8(dst0, _dst);
  815. dst0 += 3 * 8;
  816. #else
  817. for (int xi = 0; xi < 8; xi++)
  818. {
  819. int X = X0 + adelta[x + xi];
  820. int Y = Y0 + bdelta[x + xi];
  821. short sx = SATURATE_CAST_SHORT((X >> 10));
  822. short sy = SATURATE_CAST_SHORT((Y >> 10));
  823. short fx = X & ((1 << 10) - 1);
  824. short fy = Y & ((1 << 10) - 1);
  825. short alpha0 = (1 << 10) - fx;
  826. short alpha1 = fx;
  827. short beta0 = (1 << 10) - fy;
  828. short beta1 = fy;
  829. const unsigned char* a0 = src0 + srcstride * sy + sx * 3;
  830. const unsigned char* a1 = src0 + srcstride * sy + sx * 3 + 3;
  831. const unsigned char* b0 = src0 + srcstride * (sy + 1) + sx * 3;
  832. const unsigned char* b1 = src0 + srcstride * (sy + 1) + sx * 3 + 3;
  833. dst0[0] = (unsigned char)(((((unsigned short)((a0[0] * alpha0 + a1[0] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[0] * alpha0 + b1[0] * alpha1) >> 5) * beta1))) >> 15);
  834. dst0[1] = (unsigned char)(((((unsigned short)((a0[1] * alpha0 + a1[1] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[1] * alpha0 + b1[1] * alpha1) >> 5) * beta1))) >> 15);
  835. dst0[2] = (unsigned char)(((((unsigned short)((a0[2] * alpha0 + a1[2] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[2] * alpha0 + b1[2] * alpha1) >> 5) * beta1))) >> 15);
  836. dst0 += 3;
  837. }
  838. #endif // __ARM_NEON
  839. }
  840. else if (sxy_inout == 2)
  841. {
  842. // all outside
  843. if (type != -233)
  844. {
  845. #if __ARM_NEON
  846. uint8x8x3_t _border_color;
  847. _border_color.val[0] = vdup_n_u8(border_color[0]);
  848. _border_color.val[1] = vdup_n_u8(border_color[1]);
  849. _border_color.val[2] = vdup_n_u8(border_color[2]);
  850. vst3_u8(dst0, _border_color);
  851. #else
  852. for (int xi = 0; xi < 8; xi++)
  853. {
  854. dst0[xi * 3] = border_color[0];
  855. dst0[xi * 3 + 1] = border_color[1];
  856. dst0[xi * 3 + 2] = border_color[2];
  857. }
  858. #endif // __ARM_NEON
  859. }
  860. else
  861. {
  862. // skip
  863. }
  864. dst0 += 24;
  865. }
  866. else // if (sxy_inout == 0)
  867. {
  868. for (int xi = 0; xi < 8; xi++)
  869. {
  870. int X = X0 + adelta[x + xi];
  871. int Y = Y0 + bdelta[x + xi];
  872. short sx = SATURATE_CAST_SHORT((X >> 10));
  873. short sy = SATURATE_CAST_SHORT((Y >> 10));
  874. if (type != -233 && (sx < -1 || sx >= srcw || sy < -1 || sy >= srch))
  875. {
  876. dst0[0] = border_color[0];
  877. dst0[1] = border_color[1];
  878. dst0[2] = border_color[2];
  879. }
  880. else if (type == -233 && ((unsigned short)sx >= srcw - 1 || (unsigned short)sy >= srch - 1))
  881. {
  882. // skip
  883. }
  884. else
  885. {
  886. short fx = X & ((1 << 10) - 1);
  887. short fy = Y & ((1 << 10) - 1);
  888. short alpha0 = (1 << 10) - fx;
  889. short alpha1 = fx;
  890. short beta0 = (1 << 10) - fy;
  891. short beta1 = fy;
  892. short sx1 = sx + 1;
  893. short sy1 = sy + 1;
  894. const unsigned char* a0 = src0 + srcstride * sy + sx * 3;
  895. const unsigned char* a1 = src0 + srcstride * sy + sx * 3 + 3;
  896. const unsigned char* b0 = src0 + srcstride * (sy + 1) + sx * 3;
  897. const unsigned char* b1 = src0 + srcstride * (sy + 1) + sx * 3 + 3;
  898. if ((unsigned short)sx >= srcw || (unsigned short)sy >= srch)
  899. {
  900. a0 = type != -233 ? border_color : dst0;
  901. }
  902. if ((unsigned short)sx1 >= srcw || (unsigned short)sy >= srch)
  903. {
  904. a1 = type != -233 ? border_color : dst0;
  905. }
  906. if ((unsigned short)sx >= srcw || (unsigned short)sy1 >= srch)
  907. {
  908. b0 = type != -233 ? border_color : dst0;
  909. }
  910. if ((unsigned short)sx1 >= srcw || (unsigned short)sy1 >= srch)
  911. {
  912. b1 = type != -233 ? border_color : dst0;
  913. }
  914. dst0[0] = (unsigned char)(((((unsigned short)((a0[0] * alpha0 + a1[0] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[0] * alpha0 + b1[0] * alpha1) >> 5) * beta1))) >> 15);
  915. dst0[1] = (unsigned char)(((((unsigned short)((a0[1] * alpha0 + a1[1] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[1] * alpha0 + b1[1] * alpha1) >> 5) * beta1))) >> 15);
  916. dst0[2] = (unsigned char)(((((unsigned short)((a0[2] * alpha0 + a1[2] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[2] * alpha0 + b1[2] * alpha1) >> 5) * beta1))) >> 15);
  917. }
  918. dst0 += 3;
  919. }
  920. }
  921. }
  922. for (; x < w; x++)
  923. {
  924. int X = X0 + adelta[x];
  925. int Y = Y0 + bdelta[x];
  926. short sx = SATURATE_CAST_SHORT((X >> 10));
  927. short sy = SATURATE_CAST_SHORT((Y >> 10));
  928. if (type != -233 && (sx < -1 || sx >= srcw || sy < -1 || sy >= srch))
  929. {
  930. dst0[0] = border_color[0];
  931. dst0[1] = border_color[1];
  932. dst0[2] = border_color[2];
  933. }
  934. else if (type == -233 && ((unsigned short)sx >= srcw - 1 || (unsigned short)sy >= srch - 1))
  935. {
  936. // skip
  937. }
  938. else
  939. {
  940. short fx = X & ((1 << 10) - 1);
  941. short fy = Y & ((1 << 10) - 1);
  942. short alpha0 = (1 << 10) - fx;
  943. short alpha1 = fx;
  944. short beta0 = (1 << 10) - fy;
  945. short beta1 = fy;
  946. short sx1 = sx + 1;
  947. short sy1 = sy + 1;
  948. const unsigned char* a0 = src0 + srcstride * sy + sx * 3;
  949. const unsigned char* a1 = src0 + srcstride * sy + sx * 3 + 3;
  950. const unsigned char* b0 = src0 + srcstride * (sy + 1) + sx * 3;
  951. const unsigned char* b1 = src0 + srcstride * (sy + 1) + sx * 3 + 3;
  952. if ((unsigned short)sx >= srcw || (unsigned short)sy >= srch)
  953. {
  954. a0 = type != -233 ? border_color : dst0;
  955. }
  956. if ((unsigned short)sx1 >= srcw || (unsigned short)sy >= srch)
  957. {
  958. a1 = type != -233 ? border_color : dst0;
  959. }
  960. if ((unsigned short)sx >= srcw || (unsigned short)sy1 >= srch)
  961. {
  962. b0 = type != -233 ? border_color : dst0;
  963. }
  964. if ((unsigned short)sx1 >= srcw || (unsigned short)sy1 >= srch)
  965. {
  966. b1 = type != -233 ? border_color : dst0;
  967. }
  968. dst0[0] = (unsigned char)(((((unsigned short)((a0[0] * alpha0 + a1[0] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[0] * alpha0 + b1[0] * alpha1) >> 5) * beta1))) >> 15);
  969. dst0[1] = (unsigned char)(((((unsigned short)((a0[1] * alpha0 + a1[1] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[1] * alpha0 + b1[1] * alpha1) >> 5) * beta1))) >> 15);
  970. dst0[2] = (unsigned char)(((((unsigned short)((a0[2] * alpha0 + a1[2] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[2] * alpha0 + b1[2] * alpha1) >> 5) * beta1))) >> 15);
  971. }
  972. dst0 += 3;
  973. }
  974. dst0 += wgap;
  975. }
  976. #undef SATURATE_CAST_SHORT
  977. #undef SATURATE_CAST_INT
  978. }
  979. void warpaffine_bilinear_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride, const float* tm, int type, unsigned int v)
  980. {
  981. const unsigned char* border_color = (const unsigned char*)&v;
  982. const int wgap = stride - w * 4;
  983. const unsigned char* src0 = src;
  984. unsigned char* dst0 = dst;
  985. #define SATURATE_CAST_SHORT(X) (short)::std::min(::std::max((int)(X), SHRT_MIN), SHRT_MAX)
  986. #define SATURATE_CAST_INT(X) (int)::std::min(::std::max((int)((X) + ((X) >= 0.f ? 0.5f : -0.5f)), INT_MIN), INT_MAX)
  987. std::vector<int> adelta(w);
  988. std::vector<int> bdelta(w);
  989. for (int x = 0; x < w; x++)
  990. {
  991. adelta[x] = SATURATE_CAST_INT(tm[0] * x * (1 << 10));
  992. bdelta[x] = SATURATE_CAST_INT(tm[3] * x * (1 << 10));
  993. }
  994. int y = 0;
  995. for (; y < h; y++)
  996. {
  997. int X0 = SATURATE_CAST_INT((tm[1] * y + tm[2]) * (1 << 10));
  998. int Y0 = SATURATE_CAST_INT((tm[4] * y + tm[5]) * (1 << 10));
  999. int x = 0;
  1000. for (; x + 7 < w; x += 8)
  1001. {
  1002. int sxy_inout = 0;
  1003. {
  1004. int X_0 = X0 + adelta[x];
  1005. int Y_0 = Y0 + bdelta[x];
  1006. int X_7 = X0 + adelta[x + 7];
  1007. int Y_7 = Y0 + bdelta[x + 7];
  1008. short sx_0 = SATURATE_CAST_SHORT((X_0 >> 10));
  1009. short sy_0 = SATURATE_CAST_SHORT((Y_0 >> 10));
  1010. short sx_7 = SATURATE_CAST_SHORT((X_7 >> 10));
  1011. short sy_7 = SATURATE_CAST_SHORT((Y_7 >> 10));
  1012. if (((unsigned short)sx_0 < srcw - 1 && (unsigned short)sy_0 < srch - 1) && ((unsigned short)sx_7 < srcw - 1 && (unsigned short)sy_7 < srch - 1))
  1013. {
  1014. // all inside
  1015. sxy_inout = 1;
  1016. }
  1017. else if ((sx_0 < -1 && sx_7 < -1) || (sx_0 >= srcw && sx_7 >= srcw) || (sy_0 < -1 && sy_7 < -1) || (sy_0 >= srch && sy_7 >= srch))
  1018. {
  1019. // all outside
  1020. sxy_inout = 2;
  1021. }
  1022. }
  1023. if (sxy_inout == 1)
  1024. {
  1025. // all inside
  1026. #if __ARM_NEON
  1027. int32x4_t _Xl = vaddq_s32(vdupq_n_s32(X0), vld1q_s32(adelta.data() + x));
  1028. int32x4_t _Xh = vaddq_s32(vdupq_n_s32(X0), vld1q_s32(adelta.data() + x + 4));
  1029. int32x4_t _Yl = vaddq_s32(vdupq_n_s32(Y0), vld1q_s32(bdelta.data() + x));
  1030. int32x4_t _Yh = vaddq_s32(vdupq_n_s32(Y0), vld1q_s32(bdelta.data() + x + 4));
  1031. int16x4_t _sxl = vqshrn_n_s32(_Xl, 10);
  1032. int16x4_t _sxh = vqshrn_n_s32(_Xh, 10);
  1033. int16x4_t _syl = vqshrn_n_s32(_Yl, 10);
  1034. int16x4_t _syh = vqshrn_n_s32(_Yh, 10);
  1035. uint32x4_t _v1024m1 = vdupq_n_u32((1 << 10) - 1);
  1036. uint16x8_t _fx = vcombine_u16(vmovn_u32(vandq_u32(vreinterpretq_u32_s32(_Xl), _v1024m1)), vmovn_u32(vandq_u32(vreinterpretq_u32_s32(_Xh), _v1024m1)));
  1037. uint16x8_t _fy = vcombine_u16(vmovn_u32(vandq_u32(vreinterpretq_u32_s32(_Yl), _v1024m1)), vmovn_u32(vandq_u32(vreinterpretq_u32_s32(_Yh), _v1024m1)));
  1038. uint16x8_t _alpha0 = vsubq_u16(vdupq_n_u16(1 << 10), _fx);
  1039. uint16x8_t _alpha1 = _fx;
  1040. uint16x8_t _beta0 = vsubq_u16(vdupq_n_u16(1 << 10), _fy);
  1041. uint16x8_t _beta1 = _fy;
  1042. int16x4_t _srcstride = vdup_n_s16(srcstride);
  1043. int16x4_t _v4 = vdup_n_s16(4);
  1044. int32x4_t _a0l = vmlal_s16(vmull_s16(_srcstride, _syl), _sxl, _v4);
  1045. int32x4_t _a0h = vmlal_s16(vmull_s16(_srcstride, _syh), _sxh, _v4);
  1046. int32x4_t _b0l = vaddw_s16(_a0l, _srcstride);
  1047. int32x4_t _b0h = vaddw_s16(_a0h, _srcstride);
  1048. uint8x8x4_t _a0 = uint8x8x4_t();
  1049. uint8x8x4_t _a1 = uint8x8x4_t();
  1050. uint8x8x4_t _b0 = uint8x8x4_t();
  1051. uint8x8x4_t _b1 = uint8x8x4_t();
  1052. {
  1053. uint8x8_t _a0a1_0 = vld1_u8(src0 + vgetq_lane_s32(_a0l, 0));
  1054. uint8x8_t _a0a1_1 = vld1_u8(src0 + vgetq_lane_s32(_a0l, 1));
  1055. uint8x8_t _a0a1_2 = vld1_u8(src0 + vgetq_lane_s32(_a0l, 2));
  1056. uint8x8_t _a0a1_3 = vld1_u8(src0 + vgetq_lane_s32(_a0l, 3));
  1057. uint8x8_t _a0a1_4 = vld1_u8(src0 + vgetq_lane_s32(_a0h, 0));
  1058. uint8x8_t _a0a1_5 = vld1_u8(src0 + vgetq_lane_s32(_a0h, 1));
  1059. uint8x8_t _a0a1_6 = vld1_u8(src0 + vgetq_lane_s32(_a0h, 2));
  1060. uint8x8_t _a0a1_7 = vld1_u8(src0 + vgetq_lane_s32(_a0h, 3));
  1061. // transpose 8x8
  1062. uint8x8x2_t _a0a101t_r = vtrn_u8(_a0a1_0, _a0a1_1);
  1063. uint8x8x2_t _a0a123t_r = vtrn_u8(_a0a1_2, _a0a1_3);
  1064. uint8x8x2_t _a0a145t_r = vtrn_u8(_a0a1_4, _a0a1_5);
  1065. uint8x8x2_t _a0a167t_r = vtrn_u8(_a0a1_6, _a0a1_7);
  1066. uint16x4x2_t _a0a102tt_r = vtrn_u16(vreinterpret_u16_u8(_a0a101t_r.val[0]), vreinterpret_u16_u8(_a0a123t_r.val[0]));
  1067. uint16x4x2_t _a0a113tt_r = vtrn_u16(vreinterpret_u16_u8(_a0a101t_r.val[1]), vreinterpret_u16_u8(_a0a123t_r.val[1]));
  1068. uint16x4x2_t _a0a146tt_r = vtrn_u16(vreinterpret_u16_u8(_a0a145t_r.val[0]), vreinterpret_u16_u8(_a0a167t_r.val[0]));
  1069. uint16x4x2_t _a0a157tt_r = vtrn_u16(vreinterpret_u16_u8(_a0a145t_r.val[1]), vreinterpret_u16_u8(_a0a167t_r.val[1]));
  1070. uint32x2x2_t _a0a104ttt_r = vtrn_u32(vreinterpret_u32_u16(_a0a102tt_r.val[0]), vreinterpret_u32_u16(_a0a146tt_r.val[0]));
  1071. uint32x2x2_t _a0a115ttt_r = vtrn_u32(vreinterpret_u32_u16(_a0a113tt_r.val[0]), vreinterpret_u32_u16(_a0a157tt_r.val[0]));
  1072. uint32x2x2_t _a0a126ttt_r = vtrn_u32(vreinterpret_u32_u16(_a0a102tt_r.val[1]), vreinterpret_u32_u16(_a0a146tt_r.val[1]));
  1073. uint32x2x2_t _a0a137ttt_r = vtrn_u32(vreinterpret_u32_u16(_a0a113tt_r.val[1]), vreinterpret_u32_u16(_a0a157tt_r.val[1]));
  1074. _a0.val[0] = vreinterpret_u8_u32(_a0a104ttt_r.val[0]);
  1075. _a0.val[1] = vreinterpret_u8_u32(_a0a115ttt_r.val[0]);
  1076. _a0.val[2] = vreinterpret_u8_u32(_a0a126ttt_r.val[0]);
  1077. _a0.val[3] = vreinterpret_u8_u32(_a0a137ttt_r.val[0]);
  1078. _a1.val[0] = vreinterpret_u8_u32(_a0a104ttt_r.val[1]);
  1079. _a1.val[1] = vreinterpret_u8_u32(_a0a115ttt_r.val[1]);
  1080. _a1.val[2] = vreinterpret_u8_u32(_a0a126ttt_r.val[1]);
  1081. _a1.val[3] = vreinterpret_u8_u32(_a0a137ttt_r.val[1]);
  1082. uint8x8_t _b0b1_0 = vld1_u8(src0 + vgetq_lane_s32(_b0l, 0));
  1083. uint8x8_t _b0b1_1 = vld1_u8(src0 + vgetq_lane_s32(_b0l, 1));
  1084. uint8x8_t _b0b1_2 = vld1_u8(src0 + vgetq_lane_s32(_b0l, 2));
  1085. uint8x8_t _b0b1_3 = vld1_u8(src0 + vgetq_lane_s32(_b0l, 3));
  1086. uint8x8_t _b0b1_4 = vld1_u8(src0 + vgetq_lane_s32(_b0h, 0));
  1087. uint8x8_t _b0b1_5 = vld1_u8(src0 + vgetq_lane_s32(_b0h, 1));
  1088. uint8x8_t _b0b1_6 = vld1_u8(src0 + vgetq_lane_s32(_b0h, 2));
  1089. uint8x8_t _b0b1_7 = vld1_u8(src0 + vgetq_lane_s32(_b0h, 3));
  1090. // transpose 8x8
  1091. uint8x8x2_t _b0b101t_r = vtrn_u8(_b0b1_0, _b0b1_1);
  1092. uint8x8x2_t _b0b123t_r = vtrn_u8(_b0b1_2, _b0b1_3);
  1093. uint8x8x2_t _b0b145t_r = vtrn_u8(_b0b1_4, _b0b1_5);
  1094. uint8x8x2_t _b0b167t_r = vtrn_u8(_b0b1_6, _b0b1_7);
  1095. uint16x4x2_t _b0b102tt_r = vtrn_u16(vreinterpret_u16_u8(_b0b101t_r.val[0]), vreinterpret_u16_u8(_b0b123t_r.val[0]));
  1096. uint16x4x2_t _b0b113tt_r = vtrn_u16(vreinterpret_u16_u8(_b0b101t_r.val[1]), vreinterpret_u16_u8(_b0b123t_r.val[1]));
  1097. uint16x4x2_t _b0b146tt_r = vtrn_u16(vreinterpret_u16_u8(_b0b145t_r.val[0]), vreinterpret_u16_u8(_b0b167t_r.val[0]));
  1098. uint16x4x2_t _b0b157tt_r = vtrn_u16(vreinterpret_u16_u8(_b0b145t_r.val[1]), vreinterpret_u16_u8(_b0b167t_r.val[1]));
  1099. uint32x2x2_t _b0b104ttt_r = vtrn_u32(vreinterpret_u32_u16(_b0b102tt_r.val[0]), vreinterpret_u32_u16(_b0b146tt_r.val[0]));
  1100. uint32x2x2_t _b0b115ttt_r = vtrn_u32(vreinterpret_u32_u16(_b0b113tt_r.val[0]), vreinterpret_u32_u16(_b0b157tt_r.val[0]));
  1101. uint32x2x2_t _b0b126ttt_r = vtrn_u32(vreinterpret_u32_u16(_b0b102tt_r.val[1]), vreinterpret_u32_u16(_b0b146tt_r.val[1]));
  1102. uint32x2x2_t _b0b137ttt_r = vtrn_u32(vreinterpret_u32_u16(_b0b113tt_r.val[1]), vreinterpret_u32_u16(_b0b157tt_r.val[1]));
  1103. _b0.val[0] = vreinterpret_u8_u32(_b0b104ttt_r.val[0]);
  1104. _b0.val[1] = vreinterpret_u8_u32(_b0b115ttt_r.val[0]);
  1105. _b0.val[2] = vreinterpret_u8_u32(_b0b126ttt_r.val[0]);
  1106. _b0.val[3] = vreinterpret_u8_u32(_b0b137ttt_r.val[0]);
  1107. _b1.val[0] = vreinterpret_u8_u32(_b0b104ttt_r.val[1]);
  1108. _b1.val[1] = vreinterpret_u8_u32(_b0b115ttt_r.val[1]);
  1109. _b1.val[2] = vreinterpret_u8_u32(_b0b126ttt_r.val[1]);
  1110. _b1.val[3] = vreinterpret_u8_u32(_b0b137ttt_r.val[1]);
  1111. }
  1112. uint16x8_t _a0_0 = vmovl_u8(_a0.val[0]);
  1113. uint16x8_t _a0_1 = vmovl_u8(_a0.val[1]);
  1114. uint16x8_t _a0_2 = vmovl_u8(_a0.val[2]);
  1115. uint16x8_t _a0_3 = vmovl_u8(_a0.val[3]);
  1116. uint16x8_t _a1_0 = vmovl_u8(_a1.val[0]);
  1117. uint16x8_t _a1_1 = vmovl_u8(_a1.val[1]);
  1118. uint16x8_t _a1_2 = vmovl_u8(_a1.val[2]);
  1119. uint16x8_t _a1_3 = vmovl_u8(_a1.val[3]);
  1120. uint16x8_t _b0_0 = vmovl_u8(_b0.val[0]);
  1121. uint16x8_t _b0_1 = vmovl_u8(_b0.val[1]);
  1122. uint16x8_t _b0_2 = vmovl_u8(_b0.val[2]);
  1123. uint16x8_t _b0_3 = vmovl_u8(_b0.val[3]);
  1124. uint16x8_t _b1_0 = vmovl_u8(_b1.val[0]);
  1125. uint16x8_t _b1_1 = vmovl_u8(_b1.val[1]);
  1126. uint16x8_t _b1_2 = vmovl_u8(_b1.val[2]);
  1127. uint16x8_t _b1_3 = vmovl_u8(_b1.val[3]);
  1128. uint16x4_t _a00_0l = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_low_u16(_a0_0), vget_low_u16(_alpha0)), vget_low_u16(_a1_0), vget_low_u16(_alpha1)), 5);
  1129. uint16x4_t _a00_1l = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_low_u16(_a0_1), vget_low_u16(_alpha0)), vget_low_u16(_a1_1), vget_low_u16(_alpha1)), 5);
  1130. uint16x4_t _a00_2l = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_low_u16(_a0_2), vget_low_u16(_alpha0)), vget_low_u16(_a1_2), vget_low_u16(_alpha1)), 5);
  1131. uint16x4_t _a00_3l = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_low_u16(_a0_3), vget_low_u16(_alpha0)), vget_low_u16(_a1_3), vget_low_u16(_alpha1)), 5);
  1132. uint16x4_t _a00_0h = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_high_u16(_a0_0), vget_high_u16(_alpha0)), vget_high_u16(_a1_0), vget_high_u16(_alpha1)), 5);
  1133. uint16x4_t _a00_1h = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_high_u16(_a0_1), vget_high_u16(_alpha0)), vget_high_u16(_a1_1), vget_high_u16(_alpha1)), 5);
  1134. uint16x4_t _a00_2h = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_high_u16(_a0_2), vget_high_u16(_alpha0)), vget_high_u16(_a1_2), vget_high_u16(_alpha1)), 5);
  1135. uint16x4_t _a00_3h = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_high_u16(_a0_3), vget_high_u16(_alpha0)), vget_high_u16(_a1_3), vget_high_u16(_alpha1)), 5);
  1136. uint16x4_t _b00_0l = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_low_u16(_b0_0), vget_low_u16(_alpha0)), vget_low_u16(_b1_0), vget_low_u16(_alpha1)), 5);
  1137. uint16x4_t _b00_1l = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_low_u16(_b0_1), vget_low_u16(_alpha0)), vget_low_u16(_b1_1), vget_low_u16(_alpha1)), 5);
  1138. uint16x4_t _b00_2l = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_low_u16(_b0_2), vget_low_u16(_alpha0)), vget_low_u16(_b1_2), vget_low_u16(_alpha1)), 5);
  1139. uint16x4_t _b00_3l = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_low_u16(_b0_3), vget_low_u16(_alpha0)), vget_low_u16(_b1_3), vget_low_u16(_alpha1)), 5);
  1140. uint16x4_t _b00_0h = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_high_u16(_b0_0), vget_high_u16(_alpha0)), vget_high_u16(_b1_0), vget_high_u16(_alpha1)), 5);
  1141. uint16x4_t _b00_1h = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_high_u16(_b0_1), vget_high_u16(_alpha0)), vget_high_u16(_b1_1), vget_high_u16(_alpha1)), 5);
  1142. uint16x4_t _b00_2h = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_high_u16(_b0_2), vget_high_u16(_alpha0)), vget_high_u16(_b1_2), vget_high_u16(_alpha1)), 5);
  1143. uint16x4_t _b00_3h = vqshrn_n_u32(vmlal_u16(vmull_u16(vget_high_u16(_b0_3), vget_high_u16(_alpha0)), vget_high_u16(_b1_3), vget_high_u16(_alpha1)), 5);
  1144. uint16x4_t _dst_0l = vqshrn_n_u32(vmlal_u16(vmull_u16(_a00_0l, vget_low_u16(_beta0)), _b00_0l, vget_low_u16(_beta1)), 15);
  1145. uint16x4_t _dst_1l = vqshrn_n_u32(vmlal_u16(vmull_u16(_a00_1l, vget_low_u16(_beta0)), _b00_1l, vget_low_u16(_beta1)), 15);
  1146. uint16x4_t _dst_2l = vqshrn_n_u32(vmlal_u16(vmull_u16(_a00_2l, vget_low_u16(_beta0)), _b00_2l, vget_low_u16(_beta1)), 15);
  1147. uint16x4_t _dst_3l = vqshrn_n_u32(vmlal_u16(vmull_u16(_a00_3l, vget_low_u16(_beta0)), _b00_3l, vget_low_u16(_beta1)), 15);
  1148. uint16x4_t _dst_0h = vqshrn_n_u32(vmlal_u16(vmull_u16(_a00_0h, vget_high_u16(_beta0)), _b00_0h, vget_high_u16(_beta1)), 15);
  1149. uint16x4_t _dst_1h = vqshrn_n_u32(vmlal_u16(vmull_u16(_a00_1h, vget_high_u16(_beta0)), _b00_1h, vget_high_u16(_beta1)), 15);
  1150. uint16x4_t _dst_2h = vqshrn_n_u32(vmlal_u16(vmull_u16(_a00_2h, vget_high_u16(_beta0)), _b00_2h, vget_high_u16(_beta1)), 15);
  1151. uint16x4_t _dst_3h = vqshrn_n_u32(vmlal_u16(vmull_u16(_a00_3h, vget_high_u16(_beta0)), _b00_3h, vget_high_u16(_beta1)), 15);
  1152. uint8x8x4_t _dst;
  1153. _dst.val[0] = vqmovn_u16(vcombine_u16(_dst_0l, _dst_0h));
  1154. _dst.val[1] = vqmovn_u16(vcombine_u16(_dst_1l, _dst_1h));
  1155. _dst.val[2] = vqmovn_u16(vcombine_u16(_dst_2l, _dst_2h));
  1156. _dst.val[3] = vqmovn_u16(vcombine_u16(_dst_3l, _dst_3h));
  1157. vst4_u8(dst0, _dst);
  1158. dst0 += 4 * 8;
  1159. #else
  1160. for (int xi = 0; xi < 8; xi++)
  1161. {
  1162. int X = X0 + adelta[x + xi];
  1163. int Y = Y0 + bdelta[x + xi];
  1164. short sx = SATURATE_CAST_SHORT((X >> 10));
  1165. short sy = SATURATE_CAST_SHORT((Y >> 10));
  1166. short fx = X & ((1 << 10) - 1);
  1167. short fy = Y & ((1 << 10) - 1);
  1168. short alpha0 = (1 << 10) - fx;
  1169. short alpha1 = fx;
  1170. short beta0 = (1 << 10) - fy;
  1171. short beta1 = fy;
  1172. const unsigned char* a0 = src0 + srcstride * sy + sx * 4;
  1173. const unsigned char* a1 = src0 + srcstride * sy + sx * 4 + 4;
  1174. const unsigned char* b0 = src0 + srcstride * (sy + 1) + sx * 4;
  1175. const unsigned char* b1 = src0 + srcstride * (sy + 1) + sx * 4 + 4;
  1176. dst0[0] = (unsigned char)(((((unsigned short)((a0[0] * alpha0 + a1[0] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[0] * alpha0 + b1[0] * alpha1) >> 5) * beta1))) >> 15);
  1177. dst0[1] = (unsigned char)(((((unsigned short)((a0[1] * alpha0 + a1[1] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[1] * alpha0 + b1[1] * alpha1) >> 5) * beta1))) >> 15);
  1178. dst0[2] = (unsigned char)(((((unsigned short)((a0[2] * alpha0 + a1[2] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[2] * alpha0 + b1[2] * alpha1) >> 5) * beta1))) >> 15);
  1179. dst0[3] = (unsigned char)(((((unsigned short)((a0[3] * alpha0 + a1[3] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[3] * alpha0 + b1[3] * alpha1) >> 5) * beta1))) >> 15);
  1180. dst0 += 4;
  1181. }
  1182. #endif // __ARM_NEON
  1183. }
  1184. else if (sxy_inout == 2)
  1185. {
  1186. // all outside
  1187. if (type != -233)
  1188. {
  1189. #if __ARM_NEON
  1190. uint8x8x4_t _border_color;
  1191. _border_color.val[0] = vdup_n_u8(border_color[0]);
  1192. _border_color.val[1] = vdup_n_u8(border_color[1]);
  1193. _border_color.val[2] = vdup_n_u8(border_color[2]);
  1194. _border_color.val[3] = vdup_n_u8(border_color[3]);
  1195. vst4_u8(dst0, _border_color);
  1196. #else
  1197. for (int xi = 0; xi < 8; xi++)
  1198. {
  1199. dst0[xi * 4] = border_color[0];
  1200. dst0[xi * 4 + 1] = border_color[1];
  1201. dst0[xi * 4 + 2] = border_color[2];
  1202. dst0[xi * 4 + 3] = border_color[3];
  1203. }
  1204. #endif // __ARM_NEON
  1205. }
  1206. else
  1207. {
  1208. // skip
  1209. }
  1210. dst0 += 32;
  1211. }
  1212. else // if (sxy_inout == 0)
  1213. {
  1214. for (int xi = 0; xi < 8; xi++)
  1215. {
  1216. int X = X0 + adelta[x + xi];
  1217. int Y = Y0 + bdelta[x + xi];
  1218. short sx = SATURATE_CAST_SHORT((X >> 10));
  1219. short sy = SATURATE_CAST_SHORT((Y >> 10));
  1220. if (type != -233 && (sx < -1 || sx >= srcw || sy < -1 || sy >= srch))
  1221. {
  1222. dst0[0] = border_color[0];
  1223. dst0[1] = border_color[1];
  1224. dst0[2] = border_color[2];
  1225. dst0[3] = border_color[3];
  1226. }
  1227. else if (type == -233 && ((unsigned short)sx >= srcw - 1 || (unsigned short)sy >= srch - 1))
  1228. {
  1229. // skip
  1230. }
  1231. else
  1232. {
  1233. short fx = X & ((1 << 10) - 1);
  1234. short fy = Y & ((1 << 10) - 1);
  1235. short alpha0 = (1 << 10) - fx;
  1236. short alpha1 = fx;
  1237. short beta0 = (1 << 10) - fy;
  1238. short beta1 = fy;
  1239. short sx1 = sx + 1;
  1240. short sy1 = sy + 1;
  1241. const unsigned char* a0 = src0 + srcstride * sy + sx * 4;
  1242. const unsigned char* a1 = src0 + srcstride * sy + sx * 4 + 4;
  1243. const unsigned char* b0 = src0 + srcstride * (sy + 1) + sx * 4;
  1244. const unsigned char* b1 = src0 + srcstride * (sy + 1) + sx * 4 + 4;
  1245. if ((unsigned short)sx >= srcw || (unsigned short)sy >= srch)
  1246. {
  1247. a0 = type != -233 ? border_color : dst0;
  1248. }
  1249. if ((unsigned short)sx1 >= srcw || (unsigned short)sy >= srch)
  1250. {
  1251. a1 = type != -233 ? border_color : dst0;
  1252. }
  1253. if ((unsigned short)sx >= srcw || (unsigned short)sy1 >= srch)
  1254. {
  1255. b0 = type != -233 ? border_color : dst0;
  1256. }
  1257. if ((unsigned short)sx1 >= srcw || (unsigned short)sy1 >= srch)
  1258. {
  1259. b1 = type != -233 ? border_color : dst0;
  1260. }
  1261. dst0[0] = (unsigned char)(((((unsigned short)((a0[0] * alpha0 + a1[0] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[0] * alpha0 + b1[0] * alpha1) >> 5) * beta1))) >> 15);
  1262. dst0[1] = (unsigned char)(((((unsigned short)((a0[1] * alpha0 + a1[1] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[1] * alpha0 + b1[1] * alpha1) >> 5) * beta1))) >> 15);
  1263. dst0[2] = (unsigned char)(((((unsigned short)((a0[2] * alpha0 + a1[2] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[2] * alpha0 + b1[2] * alpha1) >> 5) * beta1))) >> 15);
  1264. dst0[3] = (unsigned char)(((((unsigned short)((a0[3] * alpha0 + a1[3] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[3] * alpha0 + b1[3] * alpha1) >> 5) * beta1))) >> 15);
  1265. }
  1266. dst0 += 4;
  1267. }
  1268. }
  1269. }
  1270. for (; x < w; x++)
  1271. {
  1272. int X = X0 + adelta[x];
  1273. int Y = Y0 + bdelta[x];
  1274. short sx = SATURATE_CAST_SHORT((X >> 10));
  1275. short sy = SATURATE_CAST_SHORT((Y >> 10));
  1276. if (type != -233 && (sx < -1 || sx >= srcw || sy < -1 || sy >= srch))
  1277. {
  1278. dst0[0] = border_color[0];
  1279. dst0[1] = border_color[1];
  1280. dst0[2] = border_color[2];
  1281. dst0[3] = border_color[3];
  1282. }
  1283. else if (type == -233 && ((unsigned short)sx >= srcw - 1 || (unsigned short)sy >= srch - 1))
  1284. {
  1285. // skip
  1286. }
  1287. else
  1288. {
  1289. short fx = X & ((1 << 10) - 1);
  1290. short fy = Y & ((1 << 10) - 1);
  1291. short alpha0 = (1 << 10) - fx;
  1292. short alpha1 = fx;
  1293. short beta0 = (1 << 10) - fy;
  1294. short beta1 = fy;
  1295. short sx1 = sx + 1;
  1296. short sy1 = sy + 1;
  1297. const unsigned char* a0 = src0 + srcstride * sy + sx * 4;
  1298. const unsigned char* a1 = src0 + srcstride * sy + sx * 4 + 4;
  1299. const unsigned char* b0 = src0 + srcstride * (sy + 1) + sx * 4;
  1300. const unsigned char* b1 = src0 + srcstride * (sy + 1) + sx * 4 + 4;
  1301. if ((unsigned short)sx >= srcw || (unsigned short)sy >= srch)
  1302. {
  1303. a0 = type != -233 ? border_color : dst0;
  1304. }
  1305. if ((unsigned short)sx1 >= srcw || (unsigned short)sy >= srch)
  1306. {
  1307. a1 = type != -233 ? border_color : dst0;
  1308. }
  1309. if ((unsigned short)sx >= srcw || (unsigned short)sy1 >= srch)
  1310. {
  1311. b0 = type != -233 ? border_color : dst0;
  1312. }
  1313. if ((unsigned short)sx1 >= srcw || (unsigned short)sy1 >= srch)
  1314. {
  1315. b1 = type != -233 ? border_color : dst0;
  1316. }
  1317. dst0[0] = (unsigned char)(((((unsigned short)((a0[0] * alpha0 + a1[0] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[0] * alpha0 + b1[0] * alpha1) >> 5) * beta1))) >> 15);
  1318. dst0[1] = (unsigned char)(((((unsigned short)((a0[1] * alpha0 + a1[1] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[1] * alpha0 + b1[1] * alpha1) >> 5) * beta1))) >> 15);
  1319. dst0[2] = (unsigned char)(((((unsigned short)((a0[2] * alpha0 + a1[2] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[2] * alpha0 + b1[2] * alpha1) >> 5) * beta1))) >> 15);
  1320. dst0[3] = (unsigned char)(((((unsigned short)((a0[3] * alpha0 + a1[3] * alpha1) >> 5) * beta0)) + (((unsigned short)((b0[3] * alpha0 + b1[3] * alpha1) >> 5) * beta1))) >> 15);
  1321. }
  1322. dst0 += 4;
  1323. }
  1324. dst0 += wgap;
  1325. }
  1326. #undef SATURATE_CAST_SHORT
  1327. #undef SATURATE_CAST_INT
  1328. }
  1329. void warpaffine_bilinear_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type, unsigned int v)
  1330. {
  1331. // assert srcw % 2 == 0
  1332. // assert srch % 2 == 0
  1333. // assert w % 2 == 0
  1334. // assert h % 2 == 0
  1335. const unsigned char* border_color = (const unsigned char*)&v;
  1336. unsigned int v_y;
  1337. unsigned int v_uv;
  1338. unsigned char* border_color_y = (unsigned char*)&v_y;
  1339. unsigned char* border_color_uv = (unsigned char*)&v_uv;
  1340. border_color_y[0] = border_color[0];
  1341. border_color_uv[0] = border_color[1];
  1342. border_color_uv[1] = border_color[2];
  1343. const unsigned char* srcY = src;
  1344. unsigned char* dstY = dst;
  1345. warpaffine_bilinear_c1(srcY, srcw, srch, dstY, w, h, tm, type, v_y);
  1346. const float tm_uv[6] = {
  1347. tm[0],
  1348. tm[1],
  1349. tm[2] / 2.0f,
  1350. tm[3],
  1351. tm[4],
  1352. tm[5] / 2.0f,
  1353. };
  1354. const unsigned char* srcUV = src + srcw * srch;
  1355. unsigned char* dstUV = dst + w * h;
  1356. warpaffine_bilinear_c2(srcUV, srcw / 2, srch / 2, dstUV, w / 2, h / 2, tm_uv, type, v_uv);
  1357. }
  1358. #endif // NCNN_PIXEL_AFFINE
  1359. } // namespace ncnn