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 79 kB

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