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