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_resize.cpp 41 kB

7 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248
  1. // Tencent is pleased to support the open source community by making ncnn available.
  2. //
  3. // Copyright (C) 2018 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. #include <algorithm>
  16. #include <limits.h>
  17. #include <math.h>
  18. #if __ARM_NEON
  19. #include <arm_neon.h>
  20. #endif // __ARM_NEON
  21. #include "platform.h"
  22. namespace ncnn {
  23. #if NCNN_PIXEL
  24. void resize_bilinear_c1(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h)
  25. {
  26. return resize_bilinear_c1(src, srcw, srch, srcw, dst, w, h, w);
  27. }
  28. void resize_bilinear_c2(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h)
  29. {
  30. return resize_bilinear_c2(src, srcw, srch, srcw * 2, dst, w, h, w * 2);
  31. }
  32. void resize_bilinear_c3(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h)
  33. {
  34. return resize_bilinear_c3(src, srcw, srch, srcw * 3, dst, w, h, w * 3);
  35. }
  36. void resize_bilinear_c4(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h)
  37. {
  38. return resize_bilinear_c4(src, srcw, srch, srcw * 4, dst, w, h, w * 4);
  39. }
  40. void resize_bilinear_c1(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride)
  41. {
  42. const int INTER_RESIZE_COEF_BITS = 11;
  43. const int INTER_RESIZE_COEF_SCALE = 1 << INTER_RESIZE_COEF_BITS;
  44. // const int ONE=INTER_RESIZE_COEF_SCALE;
  45. double scale_x = (double)srcw / w;
  46. double scale_y = (double)srch / h;
  47. int* buf = new int[w + h + w + h];
  48. int* xofs = buf; //new int[w];
  49. int* yofs = buf + w; //new int[h];
  50. short* ialpha = (short*)(buf + w + h); //new short[w * 2];
  51. short* ibeta = (short*)(buf + w + h + w); //new short[h * 2];
  52. float fx;
  53. float fy;
  54. int sx;
  55. int sy;
  56. #define SATURATE_CAST_SHORT(X) (short)::std::min(::std::max((int)(X + (X >= 0.f ? 0.5f : -0.5f)), SHRT_MIN), SHRT_MAX);
  57. for (int dx = 0; dx < w; dx++)
  58. {
  59. fx = (float)((dx + 0.5) * scale_x - 0.5);
  60. sx = static_cast<int>(floor(fx));
  61. fx -= sx;
  62. if (sx < 0)
  63. {
  64. sx = 0;
  65. fx = 0.f;
  66. }
  67. if (sx >= srcw - 1)
  68. {
  69. sx = srcw - 2;
  70. fx = 1.f;
  71. }
  72. xofs[dx] = sx;
  73. float a0 = (1.f - fx) * INTER_RESIZE_COEF_SCALE;
  74. float a1 = fx * INTER_RESIZE_COEF_SCALE;
  75. ialpha[dx * 2] = SATURATE_CAST_SHORT(a0);
  76. ialpha[dx * 2 + 1] = SATURATE_CAST_SHORT(a1);
  77. }
  78. for (int dy = 0; dy < h; dy++)
  79. {
  80. fy = (float)((dy + 0.5) * scale_y - 0.5);
  81. sy = static_cast<int>(floor(fy));
  82. fy -= sy;
  83. if (sy < 0)
  84. {
  85. sy = 0;
  86. fy = 0.f;
  87. }
  88. if (sy >= srch - 1)
  89. {
  90. sy = srch - 2;
  91. fy = 1.f;
  92. }
  93. yofs[dy] = sy;
  94. float b0 = (1.f - fy) * INTER_RESIZE_COEF_SCALE;
  95. float b1 = fy * INTER_RESIZE_COEF_SCALE;
  96. ibeta[dy * 2] = SATURATE_CAST_SHORT(b0);
  97. ibeta[dy * 2 + 1] = SATURATE_CAST_SHORT(b1);
  98. }
  99. #undef SATURATE_CAST_SHORT
  100. // loop body
  101. Mat rowsbuf0(w, (size_t)2u);
  102. Mat rowsbuf1(w, (size_t)2u);
  103. short* rows0 = (short*)rowsbuf0.data;
  104. short* rows1 = (short*)rowsbuf1.data;
  105. int prev_sy1 = -2;
  106. for (int dy = 0; dy < h; dy++)
  107. {
  108. int sy = yofs[dy];
  109. if (sy == prev_sy1)
  110. {
  111. // reuse all rows
  112. }
  113. else if (sy == prev_sy1 + 1)
  114. {
  115. // hresize one row
  116. short* rows0_old = rows0;
  117. rows0 = rows1;
  118. rows1 = rows0_old;
  119. const unsigned char* S1 = src + srcstride * (sy + 1);
  120. const short* ialphap = ialpha;
  121. short* rows1p = rows1;
  122. for (int dx = 0; dx < w; dx++)
  123. {
  124. int sx = xofs[dx];
  125. short a0 = ialphap[0];
  126. short a1 = ialphap[1];
  127. const unsigned char* S1p = S1 + sx;
  128. rows1p[dx] = (S1p[0] * a0 + S1p[1] * a1) >> 4;
  129. ialphap += 2;
  130. }
  131. }
  132. else
  133. {
  134. // hresize two rows
  135. const unsigned char* S0 = src + srcstride * (sy);
  136. const unsigned char* S1 = src + srcstride * (sy + 1);
  137. const short* ialphap = ialpha;
  138. short* rows0p = rows0;
  139. short* rows1p = rows1;
  140. for (int dx = 0; dx < w; dx++)
  141. {
  142. int sx = xofs[dx];
  143. short a0 = ialphap[0];
  144. short a1 = ialphap[1];
  145. const unsigned char* S0p = S0 + sx;
  146. const unsigned char* S1p = S1 + sx;
  147. rows0p[dx] = (S0p[0] * a0 + S0p[1] * a1) >> 4;
  148. rows1p[dx] = (S1p[0] * a0 + S1p[1] * a1) >> 4;
  149. ialphap += 2;
  150. }
  151. }
  152. prev_sy1 = sy;
  153. // vresize
  154. short b0 = ibeta[0];
  155. short b1 = ibeta[1];
  156. short* rows0p = rows0;
  157. short* rows1p = rows1;
  158. unsigned char* Dp = dst + stride * (dy);
  159. #if __ARM_NEON
  160. int nn = w >> 3;
  161. #else
  162. int nn = 0;
  163. #endif
  164. int remain = w - (nn << 3);
  165. #if __ARM_NEON
  166. #if __aarch64__
  167. int16x4_t _b0 = vdup_n_s16(b0);
  168. int16x4_t _b1 = vdup_n_s16(b1);
  169. int32x4_t _v2 = vdupq_n_s32(2);
  170. for (; nn > 0; nn--)
  171. {
  172. int16x4_t _rows0p_sr4 = vld1_s16(rows0p);
  173. int16x4_t _rows1p_sr4 = vld1_s16(rows1p);
  174. int16x4_t _rows0p_1_sr4 = vld1_s16(rows0p + 4);
  175. int16x4_t _rows1p_1_sr4 = vld1_s16(rows1p + 4);
  176. int32x4_t _rows0p_sr4_mb0 = vmull_s16(_rows0p_sr4, _b0);
  177. int32x4_t _rows1p_sr4_mb1 = vmull_s16(_rows1p_sr4, _b1);
  178. int32x4_t _rows0p_1_sr4_mb0 = vmull_s16(_rows0p_1_sr4, _b0);
  179. int32x4_t _rows1p_1_sr4_mb1 = vmull_s16(_rows1p_1_sr4, _b1);
  180. int32x4_t _acc = _v2;
  181. _acc = vsraq_n_s32(_acc, _rows0p_sr4_mb0, 16);
  182. _acc = vsraq_n_s32(_acc, _rows1p_sr4_mb1, 16);
  183. int32x4_t _acc_1 = _v2;
  184. _acc_1 = vsraq_n_s32(_acc_1, _rows0p_1_sr4_mb0, 16);
  185. _acc_1 = vsraq_n_s32(_acc_1, _rows1p_1_sr4_mb1, 16);
  186. int16x4_t _acc16 = vshrn_n_s32(_acc, 2);
  187. int16x4_t _acc16_1 = vshrn_n_s32(_acc_1, 2);
  188. uint8x8_t _D = vqmovun_s16(vcombine_s16(_acc16, _acc16_1));
  189. vst1_u8(Dp, _D);
  190. Dp += 8;
  191. rows0p += 8;
  192. rows1p += 8;
  193. }
  194. #else
  195. if (nn > 0)
  196. {
  197. asm volatile(
  198. "vdup.s16 d16, %8 \n"
  199. "mov r4, #2 \n"
  200. "vdup.s16 d17, %9 \n"
  201. "vdup.s32 q12, r4 \n"
  202. "pld [%0, #128] \n"
  203. "vld1.s16 {d2-d3}, [%0 :128]!\n"
  204. "pld [%1, #128] \n"
  205. "vld1.s16 {d6-d7}, [%1 :128]!\n"
  206. "0: \n"
  207. "vmull.s16 q0, d2, d16 \n"
  208. "vmull.s16 q1, d3, d16 \n"
  209. "vorr.s32 q10, q12, q12 \n"
  210. "vorr.s32 q11, q12, q12 \n"
  211. "vmull.s16 q2, d6, d17 \n"
  212. "vmull.s16 q3, d7, d17 \n"
  213. "vsra.s32 q10, q0, #16 \n"
  214. "vsra.s32 q11, q1, #16 \n"
  215. "pld [%0, #128] \n"
  216. "vld1.s16 {d2-d3}, [%0 :128]!\n"
  217. "vsra.s32 q10, q2, #16 \n"
  218. "vsra.s32 q11, q3, #16 \n"
  219. "pld [%1, #128] \n"
  220. "vld1.s16 {d6-d7}, [%1 :128]!\n"
  221. "vshrn.s32 d20, q10, #2 \n"
  222. "vshrn.s32 d21, q11, #2 \n"
  223. "vqmovun.s16 d20, q10 \n"
  224. "vst1.8 {d20}, [%2]! \n"
  225. "subs %3, #1 \n"
  226. "bne 0b \n"
  227. "sub %0, #16 \n"
  228. "sub %1, #16 \n"
  229. : "=r"(rows0p), // %0
  230. "=r"(rows1p), // %1
  231. "=r"(Dp), // %2
  232. "=r"(nn) // %3
  233. : "0"(rows0p),
  234. "1"(rows1p),
  235. "2"(Dp),
  236. "3"(nn),
  237. "r"(b0), // %8
  238. "r"(b1) // %9
  239. : "cc", "memory", "r4", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11", "q12");
  240. }
  241. #endif // __aarch64__
  242. #endif // __ARM_NEON
  243. for (; remain; --remain)
  244. {
  245. // D[x] = (rows0[x]*b0 + rows1[x]*b1) >> INTER_RESIZE_COEF_BITS;
  246. *Dp++ = (unsigned char)(((short)((b0 * (short)(*rows0p++)) >> 16) + (short)((b1 * (short)(*rows1p++)) >> 16) + 2) >> 2);
  247. }
  248. ibeta += 2;
  249. }
  250. delete[] buf;
  251. }
  252. void resize_bilinear_c2(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride)
  253. {
  254. const int INTER_RESIZE_COEF_BITS = 11;
  255. const int INTER_RESIZE_COEF_SCALE = 1 << INTER_RESIZE_COEF_BITS;
  256. // const int ONE=INTER_RESIZE_COEF_SCALE;
  257. double scale_x = (double)srcw / w;
  258. double scale_y = (double)srch / h;
  259. int* buf = new int[w + h + w + h];
  260. int* xofs = buf; //new int[w];
  261. int* yofs = buf + w; //new int[h];
  262. short* ialpha = (short*)(buf + w + h); //new short[w * 2];
  263. short* ibeta = (short*)(buf + w + h + w); //new short[h * 2];
  264. float fx;
  265. float fy;
  266. int sx;
  267. int sy;
  268. #define SATURATE_CAST_SHORT(X) (short)::std::min(::std::max((int)(X + (X >= 0.f ? 0.5f : -0.5f)), SHRT_MIN), SHRT_MAX);
  269. for (int dx = 0; dx < w; dx++)
  270. {
  271. fx = (float)((dx + 0.5) * scale_x - 0.5);
  272. sx = static_cast<int>(floor(fx));
  273. fx -= sx;
  274. if (sx < 0)
  275. {
  276. sx = 0;
  277. fx = 0.f;
  278. }
  279. if (sx >= srcw - 1)
  280. {
  281. sx = srcw - 2;
  282. fx = 1.f;
  283. }
  284. xofs[dx] = sx * 2;
  285. float a0 = (1.f - fx) * INTER_RESIZE_COEF_SCALE;
  286. float a1 = fx * INTER_RESIZE_COEF_SCALE;
  287. ialpha[dx * 2] = SATURATE_CAST_SHORT(a0);
  288. ialpha[dx * 2 + 1] = SATURATE_CAST_SHORT(a1);
  289. }
  290. for (int dy = 0; dy < h; dy++)
  291. {
  292. fy = (float)((dy + 0.5) * scale_y - 0.5);
  293. sy = static_cast<int>(floor(fy));
  294. fy -= sy;
  295. if (sy < 0)
  296. {
  297. sy = 0;
  298. fy = 0.f;
  299. }
  300. if (sy >= srch - 1)
  301. {
  302. sy = srch - 2;
  303. fy = 1.f;
  304. }
  305. yofs[dy] = sy;
  306. float b0 = (1.f - fy) * INTER_RESIZE_COEF_SCALE;
  307. float b1 = fy * INTER_RESIZE_COEF_SCALE;
  308. ibeta[dy * 2] = SATURATE_CAST_SHORT(b0);
  309. ibeta[dy * 2 + 1] = SATURATE_CAST_SHORT(b1);
  310. }
  311. #undef SATURATE_CAST_SHORT
  312. // loop body
  313. Mat rowsbuf0(w * 2 + 2, (size_t)2u);
  314. Mat rowsbuf1(w * 2 + 2, (size_t)2u);
  315. short* rows0 = (short*)rowsbuf0.data;
  316. short* rows1 = (short*)rowsbuf1.data;
  317. int prev_sy1 = -2;
  318. for (int dy = 0; dy < h; dy++)
  319. {
  320. int sy = yofs[dy];
  321. if (sy == prev_sy1)
  322. {
  323. // reuse all rows
  324. }
  325. else if (sy == prev_sy1 + 1)
  326. {
  327. // hresize one row
  328. short* rows0_old = rows0;
  329. rows0 = rows1;
  330. rows1 = rows0_old;
  331. const unsigned char* S1 = src + srcstride * (sy + 1);
  332. const short* ialphap = ialpha;
  333. short* rows1p = rows1;
  334. for (int dx = 0; dx < w; dx++)
  335. {
  336. int sx = xofs[dx];
  337. const unsigned char* S1p = S1 + sx;
  338. #if __ARM_NEON
  339. int16x4_t _a0a1XX = vld1_s16(ialphap);
  340. int16x4_t _a0a0a1a1 = vzip_s16(_a0a1XX, _a0a1XX).val[0];
  341. uint8x8_t _S1 = uint8x8_t();
  342. _S1 = vld1_lane_u8(S1p, _S1, 0);
  343. _S1 = vld1_lane_u8(S1p + 1, _S1, 1);
  344. _S1 = vld1_lane_u8(S1p + 2, _S1, 2);
  345. _S1 = vld1_lane_u8(S1p + 3, _S1, 3);
  346. int16x8_t _S116 = vreinterpretq_s16_u16(vmovl_u8(_S1));
  347. int16x4_t _S1lowhigh = vget_low_s16(_S116);
  348. int32x4_t _S1ma0a1 = vmull_s16(_S1lowhigh, _a0a0a1a1);
  349. int32x2_t _rows1low = vadd_s32(vget_low_s32(_S1ma0a1), vget_high_s32(_S1ma0a1));
  350. int32x4_t _rows1 = vcombine_s32(_rows1low, vget_high_s32(_S1ma0a1));
  351. int16x4_t _rows1_sr4 = vshrn_n_s32(_rows1, 4);
  352. vst1_s16(rows1p, _rows1_sr4);
  353. #else
  354. short a0 = ialphap[0];
  355. short a1 = ialphap[1];
  356. rows1p[0] = (S1p[0] * a0 + S1p[2] * a1) >> 4;
  357. rows1p[1] = (S1p[1] * a0 + S1p[3] * a1) >> 4;
  358. #endif // __ARM_NEON
  359. ialphap += 2;
  360. rows1p += 2;
  361. }
  362. }
  363. else
  364. {
  365. // hresize two rows
  366. const unsigned char* S0 = src + srcstride * (sy);
  367. const unsigned char* S1 = src + srcstride * (sy + 1);
  368. const short* ialphap = ialpha;
  369. short* rows0p = rows0;
  370. short* rows1p = rows1;
  371. for (int dx = 0; dx < w; dx++)
  372. {
  373. int sx = xofs[dx];
  374. short a0 = ialphap[0];
  375. short a1 = ialphap[1];
  376. const unsigned char* S0p = S0 + sx;
  377. const unsigned char* S1p = S1 + sx;
  378. #if __ARM_NEON
  379. int16x4_t _a0 = vdup_n_s16(a0);
  380. int16x4_t _a1 = vdup_n_s16(a1);
  381. uint8x8_t _S0 = uint8x8_t();
  382. uint8x8_t _S1 = uint8x8_t();
  383. _S0 = vld1_lane_u8(S0p, _S0, 0);
  384. _S0 = vld1_lane_u8(S0p + 1, _S0, 1);
  385. _S0 = vld1_lane_u8(S0p + 2, _S0, 2);
  386. _S0 = vld1_lane_u8(S0p + 3, _S0, 3);
  387. _S1 = vld1_lane_u8(S1p, _S1, 0);
  388. _S1 = vld1_lane_u8(S1p + 1, _S1, 1);
  389. _S1 = vld1_lane_u8(S1p + 2, _S1, 2);
  390. _S1 = vld1_lane_u8(S1p + 3, _S1, 3);
  391. int16x8_t _S016 = vreinterpretq_s16_u16(vmovl_u8(_S0));
  392. int16x8_t _S116 = vreinterpretq_s16_u16(vmovl_u8(_S1));
  393. int16x4_t _S0lowhigh = vget_low_s16(_S016);
  394. int16x4_t _S1lowhigh = vget_low_s16(_S116);
  395. int32x2x2_t _S0S1low_S0S1high = vtrn_s32(vreinterpret_s32_s16(_S0lowhigh), vreinterpret_s32_s16(_S1lowhigh));
  396. int32x4_t _rows01 = vmull_s16(vreinterpret_s16_s32(_S0S1low_S0S1high.val[0]), _a0);
  397. _rows01 = vmlal_s16(_rows01, vreinterpret_s16_s32(_S0S1low_S0S1high.val[1]), _a1);
  398. int16x4_t _rows01_sr4 = vshrn_n_s32(_rows01, 4);
  399. int16x4_t _rows1_sr4 = vext_s16(_rows01_sr4, _rows01_sr4, 2);
  400. vst1_s16(rows0p, _rows01_sr4);
  401. vst1_s16(rows1p, _rows1_sr4);
  402. #else
  403. rows0p[0] = (S0p[0] * a0 + S0p[2] * a1) >> 4;
  404. rows0p[1] = (S0p[1] * a0 + S0p[3] * a1) >> 4;
  405. rows1p[0] = (S1p[0] * a0 + S1p[2] * a1) >> 4;
  406. rows1p[1] = (S1p[1] * a0 + S1p[3] * a1) >> 4;
  407. #endif // __ARM_NEON
  408. ialphap += 2;
  409. rows0p += 2;
  410. rows1p += 2;
  411. }
  412. }
  413. prev_sy1 = sy;
  414. // vresize
  415. short b0 = ibeta[0];
  416. short b1 = ibeta[1];
  417. short* rows0p = rows0;
  418. short* rows1p = rows1;
  419. unsigned char* Dp = dst + stride * (dy);
  420. #if __ARM_NEON
  421. int nn = (w * 2) >> 3;
  422. #else
  423. int nn = 0;
  424. #endif
  425. int remain = (w * 2) - (nn << 3);
  426. #if __ARM_NEON
  427. #if __aarch64__
  428. int16x4_t _b0 = vdup_n_s16(b0);
  429. int16x4_t _b1 = vdup_n_s16(b1);
  430. int32x4_t _v2 = vdupq_n_s32(2);
  431. for (; nn > 0; nn--)
  432. {
  433. int16x4_t _rows0p_sr4 = vld1_s16(rows0p);
  434. int16x4_t _rows1p_sr4 = vld1_s16(rows1p);
  435. int16x4_t _rows0p_1_sr4 = vld1_s16(rows0p + 4);
  436. int16x4_t _rows1p_1_sr4 = vld1_s16(rows1p + 4);
  437. int32x4_t _rows0p_sr4_mb0 = vmull_s16(_rows0p_sr4, _b0);
  438. int32x4_t _rows1p_sr4_mb1 = vmull_s16(_rows1p_sr4, _b1);
  439. int32x4_t _rows0p_1_sr4_mb0 = vmull_s16(_rows0p_1_sr4, _b0);
  440. int32x4_t _rows1p_1_sr4_mb1 = vmull_s16(_rows1p_1_sr4, _b1);
  441. int32x4_t _acc = _v2;
  442. _acc = vsraq_n_s32(_acc, _rows0p_sr4_mb0, 16);
  443. _acc = vsraq_n_s32(_acc, _rows1p_sr4_mb1, 16);
  444. int32x4_t _acc_1 = _v2;
  445. _acc_1 = vsraq_n_s32(_acc_1, _rows0p_1_sr4_mb0, 16);
  446. _acc_1 = vsraq_n_s32(_acc_1, _rows1p_1_sr4_mb1, 16);
  447. int16x4_t _acc16 = vshrn_n_s32(_acc, 2);
  448. int16x4_t _acc16_1 = vshrn_n_s32(_acc_1, 2);
  449. uint8x8_t _D = vqmovun_s16(vcombine_s16(_acc16, _acc16_1));
  450. vst1_u8(Dp, _D);
  451. Dp += 8;
  452. rows0p += 8;
  453. rows1p += 8;
  454. }
  455. #else
  456. if (nn > 0)
  457. {
  458. asm volatile(
  459. "vdup.s16 d16, %8 \n"
  460. "mov r4, #2 \n"
  461. "vdup.s16 d17, %9 \n"
  462. "vdup.s32 q12, r4 \n"
  463. "pld [%0, #128] \n"
  464. "vld1.s16 {d2-d3}, [%0 :128]!\n"
  465. "pld [%1, #128] \n"
  466. "vld1.s16 {d6-d7}, [%1 :128]!\n"
  467. "0: \n"
  468. "vmull.s16 q0, d2, d16 \n"
  469. "vmull.s16 q1, d3, d16 \n"
  470. "vorr.s32 q10, q12, q12 \n"
  471. "vorr.s32 q11, q12, q12 \n"
  472. "vmull.s16 q2, d6, d17 \n"
  473. "vmull.s16 q3, d7, d17 \n"
  474. "vsra.s32 q10, q0, #16 \n"
  475. "vsra.s32 q11, q1, #16 \n"
  476. "pld [%0, #128] \n"
  477. "vld1.s16 {d2-d3}, [%0 :128]!\n"
  478. "vsra.s32 q10, q2, #16 \n"
  479. "vsra.s32 q11, q3, #16 \n"
  480. "pld [%1, #128] \n"
  481. "vld1.s16 {d6-d7}, [%1 :128]!\n"
  482. "vshrn.s32 d20, q10, #2 \n"
  483. "vshrn.s32 d21, q11, #2 \n"
  484. "vqmovun.s16 d20, q10 \n"
  485. "vst1.8 {d20}, [%2]! \n"
  486. "subs %3, #1 \n"
  487. "bne 0b \n"
  488. "sub %0, #16 \n"
  489. "sub %1, #16 \n"
  490. : "=r"(rows0p), // %0
  491. "=r"(rows1p), // %1
  492. "=r"(Dp), // %2
  493. "=r"(nn) // %3
  494. : "0"(rows0p),
  495. "1"(rows1p),
  496. "2"(Dp),
  497. "3"(nn),
  498. "r"(b0), // %8
  499. "r"(b1) // %9
  500. : "cc", "memory", "r4", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11", "q12");
  501. }
  502. #endif // __aarch64__
  503. #endif // __ARM_NEON
  504. for (; remain; --remain)
  505. {
  506. // D[x] = (rows0[x]*b0 + rows1[x]*b1) >> INTER_RESIZE_COEF_BITS;
  507. *Dp++ = (unsigned char)(((short)((b0 * (short)(*rows0p++)) >> 16) + (short)((b1 * (short)(*rows1p++)) >> 16) + 2) >> 2);
  508. }
  509. ibeta += 2;
  510. }
  511. delete[] buf;
  512. }
  513. void resize_bilinear_c3(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride)
  514. {
  515. const int INTER_RESIZE_COEF_BITS = 11;
  516. const int INTER_RESIZE_COEF_SCALE = 1 << INTER_RESIZE_COEF_BITS;
  517. // const int ONE=INTER_RESIZE_COEF_SCALE;
  518. double scale_x = (double)srcw / w;
  519. double scale_y = (double)srch / h;
  520. int* buf = new int[w + h + w + h];
  521. int* xofs = buf; //new int[w];
  522. int* yofs = buf + w; //new int[h];
  523. short* ialpha = (short*)(buf + w + h); //new short[w * 2];
  524. short* ibeta = (short*)(buf + w + h + w); //new short[h * 2];
  525. float fx;
  526. float fy;
  527. int sx;
  528. int sy;
  529. #define SATURATE_CAST_SHORT(X) (short)::std::min(::std::max((int)(X + (X >= 0.f ? 0.5f : -0.5f)), SHRT_MIN), SHRT_MAX);
  530. for (int dx = 0; dx < w; dx++)
  531. {
  532. fx = (float)((dx + 0.5) * scale_x - 0.5);
  533. sx = static_cast<int>(floor(fx));
  534. fx -= sx;
  535. if (sx < 0)
  536. {
  537. sx = 0;
  538. fx = 0.f;
  539. }
  540. if (sx >= srcw - 1)
  541. {
  542. sx = srcw - 2;
  543. fx = 1.f;
  544. }
  545. xofs[dx] = sx * 3;
  546. float a0 = (1.f - fx) * INTER_RESIZE_COEF_SCALE;
  547. float a1 = fx * INTER_RESIZE_COEF_SCALE;
  548. ialpha[dx * 2] = SATURATE_CAST_SHORT(a0);
  549. ialpha[dx * 2 + 1] = SATURATE_CAST_SHORT(a1);
  550. }
  551. for (int dy = 0; dy < h; dy++)
  552. {
  553. fy = (float)((dy + 0.5) * scale_y - 0.5);
  554. sy = static_cast<int>(floor(fy));
  555. fy -= sy;
  556. if (sy < 0)
  557. {
  558. sy = 0;
  559. fy = 0.f;
  560. }
  561. if (sy >= srch - 1)
  562. {
  563. sy = srch - 2;
  564. fy = 1.f;
  565. }
  566. yofs[dy] = sy;
  567. float b0 = (1.f - fy) * INTER_RESIZE_COEF_SCALE;
  568. float b1 = fy * INTER_RESIZE_COEF_SCALE;
  569. ibeta[dy * 2] = SATURATE_CAST_SHORT(b0);
  570. ibeta[dy * 2 + 1] = SATURATE_CAST_SHORT(b1);
  571. }
  572. #undef SATURATE_CAST_SHORT
  573. // loop body
  574. Mat rowsbuf0(w * 3 + 1, (size_t)2u);
  575. Mat rowsbuf1(w * 3 + 1, (size_t)2u);
  576. short* rows0 = (short*)rowsbuf0.data;
  577. short* rows1 = (short*)rowsbuf1.data;
  578. int prev_sy1 = -2;
  579. for (int dy = 0; dy < h; dy++)
  580. {
  581. int sy = yofs[dy];
  582. if (sy == prev_sy1)
  583. {
  584. // reuse all rows
  585. }
  586. else if (sy == prev_sy1 + 1)
  587. {
  588. // hresize one row
  589. short* rows0_old = rows0;
  590. rows0 = rows1;
  591. rows1 = rows0_old;
  592. const unsigned char* S1 = src + srcstride * (sy + 1);
  593. const short* ialphap = ialpha;
  594. short* rows1p = rows1;
  595. for (int dx = 0; dx < w; dx++)
  596. {
  597. int sx = xofs[dx];
  598. short a0 = ialphap[0];
  599. short a1 = ialphap[1];
  600. const unsigned char* S1p = S1 + sx;
  601. #if __ARM_NEON
  602. int16x4_t _a0 = vdup_n_s16(a0);
  603. int16x4_t _a1 = vdup_n_s16(a1);
  604. uint8x8_t _S1 = uint8x8_t();
  605. _S1 = vld1_lane_u8(S1p, _S1, 0);
  606. _S1 = vld1_lane_u8(S1p + 1, _S1, 1);
  607. _S1 = vld1_lane_u8(S1p + 2, _S1, 2);
  608. _S1 = vld1_lane_u8(S1p + 3, _S1, 3);
  609. _S1 = vld1_lane_u8(S1p + 4, _S1, 4);
  610. _S1 = vld1_lane_u8(S1p + 5, _S1, 5);
  611. int16x8_t _S116 = vreinterpretq_s16_u16(vmovl_u8(_S1));
  612. int16x4_t _S1low = vget_low_s16(_S116);
  613. int16x4_t _S1high = vext_s16(_S1low, vget_high_s16(_S116), 3);
  614. int32x4_t _rows1 = vmull_s16(_S1low, _a0);
  615. _rows1 = vmlal_s16(_rows1, _S1high, _a1);
  616. int16x4_t _rows1_sr4 = vshrn_n_s32(_rows1, 4);
  617. vst1_s16(rows1p, _rows1_sr4);
  618. #else
  619. rows1p[0] = (S1p[0] * a0 + S1p[3] * a1) >> 4;
  620. rows1p[1] = (S1p[1] * a0 + S1p[4] * a1) >> 4;
  621. rows1p[2] = (S1p[2] * a0 + S1p[5] * a1) >> 4;
  622. #endif // __ARM_NEON
  623. ialphap += 2;
  624. rows1p += 3;
  625. }
  626. }
  627. else
  628. {
  629. // hresize two rows
  630. const unsigned char* S0 = src + srcstride * (sy);
  631. const unsigned char* S1 = src + srcstride * (sy + 1);
  632. const short* ialphap = ialpha;
  633. short* rows0p = rows0;
  634. short* rows1p = rows1;
  635. for (int dx = 0; dx < w; dx++)
  636. {
  637. int sx = xofs[dx];
  638. short a0 = ialphap[0];
  639. short a1 = ialphap[1];
  640. const unsigned char* S0p = S0 + sx;
  641. const unsigned char* S1p = S1 + sx;
  642. #if __ARM_NEON
  643. int16x4_t _a0 = vdup_n_s16(a0);
  644. int16x4_t _a1 = vdup_n_s16(a1);
  645. uint8x8_t _S0 = uint8x8_t();
  646. uint8x8_t _S1 = uint8x8_t();
  647. _S0 = vld1_lane_u8(S0p, _S0, 0);
  648. _S0 = vld1_lane_u8(S0p + 1, _S0, 1);
  649. _S0 = vld1_lane_u8(S0p + 2, _S0, 2);
  650. _S0 = vld1_lane_u8(S0p + 3, _S0, 3);
  651. _S0 = vld1_lane_u8(S0p + 4, _S0, 4);
  652. _S0 = vld1_lane_u8(S0p + 5, _S0, 5);
  653. _S1 = vld1_lane_u8(S1p, _S1, 0);
  654. _S1 = vld1_lane_u8(S1p + 1, _S1, 1);
  655. _S1 = vld1_lane_u8(S1p + 2, _S1, 2);
  656. _S1 = vld1_lane_u8(S1p + 3, _S1, 3);
  657. _S1 = vld1_lane_u8(S1p + 4, _S1, 4);
  658. _S1 = vld1_lane_u8(S1p + 5, _S1, 5);
  659. int16x8_t _S016 = vreinterpretq_s16_u16(vmovl_u8(_S0));
  660. int16x8_t _S116 = vreinterpretq_s16_u16(vmovl_u8(_S1));
  661. int16x4_t _S0low = vget_low_s16(_S016);
  662. int16x4_t _S1low = vget_low_s16(_S116);
  663. int16x4_t _S0high = vext_s16(_S0low, vget_high_s16(_S016), 3);
  664. int16x4_t _S1high = vext_s16(_S1low, vget_high_s16(_S116), 3);
  665. int32x4_t _rows0 = vmull_s16(_S0low, _a0);
  666. int32x4_t _rows1 = vmull_s16(_S1low, _a0);
  667. _rows0 = vmlal_s16(_rows0, _S0high, _a1);
  668. _rows1 = vmlal_s16(_rows1, _S1high, _a1);
  669. int16x4_t _rows0_sr4 = vshrn_n_s32(_rows0, 4);
  670. int16x4_t _rows1_sr4 = vshrn_n_s32(_rows1, 4);
  671. vst1_s16(rows0p, _rows0_sr4);
  672. vst1_s16(rows1p, _rows1_sr4);
  673. #else
  674. rows0p[0] = (S0p[0] * a0 + S0p[3] * a1) >> 4;
  675. rows0p[1] = (S0p[1] * a0 + S0p[4] * a1) >> 4;
  676. rows0p[2] = (S0p[2] * a0 + S0p[5] * a1) >> 4;
  677. rows1p[0] = (S1p[0] * a0 + S1p[3] * a1) >> 4;
  678. rows1p[1] = (S1p[1] * a0 + S1p[4] * a1) >> 4;
  679. rows1p[2] = (S1p[2] * a0 + S1p[5] * a1) >> 4;
  680. #endif // __ARM_NEON
  681. ialphap += 2;
  682. rows0p += 3;
  683. rows1p += 3;
  684. }
  685. }
  686. prev_sy1 = sy;
  687. // vresize
  688. short b0 = ibeta[0];
  689. short b1 = ibeta[1];
  690. short* rows0p = rows0;
  691. short* rows1p = rows1;
  692. unsigned char* Dp = dst + stride * (dy);
  693. #if __ARM_NEON
  694. int nn = (w * 3) >> 3;
  695. #else
  696. int nn = 0;
  697. #endif
  698. int remain = (w * 3) - (nn << 3);
  699. #if __ARM_NEON
  700. #if __aarch64__
  701. int16x4_t _b0 = vdup_n_s16(b0);
  702. int16x4_t _b1 = vdup_n_s16(b1);
  703. int32x4_t _v2 = vdupq_n_s32(2);
  704. for (; nn > 0; nn--)
  705. {
  706. int16x4_t _rows0p_sr4 = vld1_s16(rows0p);
  707. int16x4_t _rows1p_sr4 = vld1_s16(rows1p);
  708. int16x4_t _rows0p_1_sr4 = vld1_s16(rows0p + 4);
  709. int16x4_t _rows1p_1_sr4 = vld1_s16(rows1p + 4);
  710. int32x4_t _rows0p_sr4_mb0 = vmull_s16(_rows0p_sr4, _b0);
  711. int32x4_t _rows1p_sr4_mb1 = vmull_s16(_rows1p_sr4, _b1);
  712. int32x4_t _rows0p_1_sr4_mb0 = vmull_s16(_rows0p_1_sr4, _b0);
  713. int32x4_t _rows1p_1_sr4_mb1 = vmull_s16(_rows1p_1_sr4, _b1);
  714. int32x4_t _acc = _v2;
  715. _acc = vsraq_n_s32(_acc, _rows0p_sr4_mb0, 16);
  716. _acc = vsraq_n_s32(_acc, _rows1p_sr4_mb1, 16);
  717. int32x4_t _acc_1 = _v2;
  718. _acc_1 = vsraq_n_s32(_acc_1, _rows0p_1_sr4_mb0, 16);
  719. _acc_1 = vsraq_n_s32(_acc_1, _rows1p_1_sr4_mb1, 16);
  720. int16x4_t _acc16 = vshrn_n_s32(_acc, 2);
  721. int16x4_t _acc16_1 = vshrn_n_s32(_acc_1, 2);
  722. uint8x8_t _D = vqmovun_s16(vcombine_s16(_acc16, _acc16_1));
  723. vst1_u8(Dp, _D);
  724. Dp += 8;
  725. rows0p += 8;
  726. rows1p += 8;
  727. }
  728. #else
  729. if (nn > 0)
  730. {
  731. asm volatile(
  732. "vdup.s16 d16, %8 \n"
  733. "mov r4, #2 \n"
  734. "vdup.s16 d17, %9 \n"
  735. "vdup.s32 q12, r4 \n"
  736. "pld [%0, #128] \n"
  737. "vld1.s16 {d2-d3}, [%0 :128]!\n"
  738. "pld [%1, #128] \n"
  739. "vld1.s16 {d6-d7}, [%1 :128]!\n"
  740. "0: \n"
  741. "vmull.s16 q0, d2, d16 \n"
  742. "vmull.s16 q1, d3, d16 \n"
  743. "vorr.s32 q10, q12, q12 \n"
  744. "vorr.s32 q11, q12, q12 \n"
  745. "vmull.s16 q2, d6, d17 \n"
  746. "vmull.s16 q3, d7, d17 \n"
  747. "vsra.s32 q10, q0, #16 \n"
  748. "vsra.s32 q11, q1, #16 \n"
  749. "pld [%0, #128] \n"
  750. "vld1.s16 {d2-d3}, [%0 :128]!\n"
  751. "vsra.s32 q10, q2, #16 \n"
  752. "vsra.s32 q11, q3, #16 \n"
  753. "pld [%1, #128] \n"
  754. "vld1.s16 {d6-d7}, [%1 :128]!\n"
  755. "vshrn.s32 d20, q10, #2 \n"
  756. "vshrn.s32 d21, q11, #2 \n"
  757. "vqmovun.s16 d20, q10 \n"
  758. "vst1.8 {d20}, [%2]! \n"
  759. "subs %3, #1 \n"
  760. "bne 0b \n"
  761. "sub %0, #16 \n"
  762. "sub %1, #16 \n"
  763. : "=r"(rows0p), // %0
  764. "=r"(rows1p), // %1
  765. "=r"(Dp), // %2
  766. "=r"(nn) // %3
  767. : "0"(rows0p),
  768. "1"(rows1p),
  769. "2"(Dp),
  770. "3"(nn),
  771. "r"(b0), // %8
  772. "r"(b1) // %9
  773. : "cc", "memory", "r4", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11", "q12");
  774. }
  775. #endif // __aarch64__
  776. #endif // __ARM_NEON
  777. for (; remain; --remain)
  778. {
  779. // D[x] = (rows0[x]*b0 + rows1[x]*b1) >> INTER_RESIZE_COEF_BITS;
  780. *Dp++ = (unsigned char)(((short)((b0 * (short)(*rows0p++)) >> 16) + (short)((b1 * (short)(*rows1p++)) >> 16) + 2) >> 2);
  781. }
  782. ibeta += 2;
  783. }
  784. delete[] buf;
  785. }
  786. void resize_bilinear_c4(const unsigned char* src, int srcw, int srch, int srcstride, unsigned char* dst, int w, int h, int stride)
  787. {
  788. const int INTER_RESIZE_COEF_BITS = 11;
  789. const int INTER_RESIZE_COEF_SCALE = 1 << INTER_RESIZE_COEF_BITS;
  790. // const int ONE=INTER_RESIZE_COEF_SCALE;
  791. double scale_x = (double)srcw / w;
  792. double scale_y = (double)srch / h;
  793. int* buf = new int[w + h + w + h];
  794. int* xofs = buf; //new int[w];
  795. int* yofs = buf + w; //new int[h];
  796. short* ialpha = (short*)(buf + w + h); //new short[w * 2];
  797. short* ibeta = (short*)(buf + w + h + w); //new short[h * 2];
  798. float fx;
  799. float fy;
  800. int sx;
  801. int sy;
  802. #define SATURATE_CAST_SHORT(X) (short)::std::min(::std::max((int)(X + (X >= 0.f ? 0.5f : -0.5f)), SHRT_MIN), SHRT_MAX);
  803. for (int dx = 0; dx < w; dx++)
  804. {
  805. fx = (float)((dx + 0.5) * scale_x - 0.5);
  806. sx = static_cast<int>(floor(fx));
  807. fx -= sx;
  808. if (sx < 0)
  809. {
  810. sx = 0;
  811. fx = 0.f;
  812. }
  813. if (sx >= srcw - 1)
  814. {
  815. sx = srcw - 2;
  816. fx = 1.f;
  817. }
  818. xofs[dx] = sx * 4;
  819. float a0 = (1.f - fx) * INTER_RESIZE_COEF_SCALE;
  820. float a1 = fx * INTER_RESIZE_COEF_SCALE;
  821. ialpha[dx * 2] = SATURATE_CAST_SHORT(a0);
  822. ialpha[dx * 2 + 1] = SATURATE_CAST_SHORT(a1);
  823. }
  824. for (int dy = 0; dy < h; dy++)
  825. {
  826. fy = (float)((dy + 0.5) * scale_y - 0.5);
  827. sy = static_cast<int>(floor(fy));
  828. fy -= sy;
  829. if (sy < 0)
  830. {
  831. sy = 0;
  832. fy = 0.f;
  833. }
  834. if (sy >= srch - 1)
  835. {
  836. sy = srch - 2;
  837. fy = 1.f;
  838. }
  839. yofs[dy] = sy;
  840. float b0 = (1.f - fy) * INTER_RESIZE_COEF_SCALE;
  841. float b1 = fy * INTER_RESIZE_COEF_SCALE;
  842. ibeta[dy * 2] = SATURATE_CAST_SHORT(b0);
  843. ibeta[dy * 2 + 1] = SATURATE_CAST_SHORT(b1);
  844. }
  845. #undef SATURATE_CAST_SHORT
  846. // loop body
  847. Mat rowsbuf0(w * 4, (size_t)2u);
  848. Mat rowsbuf1(w * 4, (size_t)2u);
  849. short* rows0 = (short*)rowsbuf0.data;
  850. short* rows1 = (short*)rowsbuf1.data;
  851. int prev_sy1 = -2;
  852. for (int dy = 0; dy < h; dy++)
  853. {
  854. int sy = yofs[dy];
  855. if (sy == prev_sy1)
  856. {
  857. // reuse all rows
  858. }
  859. else if (sy == prev_sy1 + 4)
  860. {
  861. // hresize one row
  862. short* rows0_old = rows0;
  863. rows0 = rows1;
  864. rows1 = rows0_old;
  865. const unsigned char* S1 = src + srcstride * (sy + 1);
  866. const short* ialphap = ialpha;
  867. short* rows1p = rows1;
  868. for (int dx = 0; dx < w; dx++)
  869. {
  870. int sx = xofs[dx];
  871. short a0 = ialphap[0];
  872. short a1 = ialphap[1];
  873. const unsigned char* S1p = S1 + sx;
  874. #if __ARM_NEON
  875. int16x4_t _a0 = vdup_n_s16(a0);
  876. int16x4_t _a1 = vdup_n_s16(a1);
  877. uint8x8_t _S1 = vld1_u8(S1p);
  878. int16x8_t _S116 = vreinterpretq_s16_u16(vmovl_u8(_S1));
  879. int16x4_t _S1low = vget_low_s16(_S116);
  880. int16x4_t _S1high = vget_high_s16(_S116);
  881. int32x4_t _rows1 = vmull_s16(_S1low, _a0);
  882. _rows1 = vmlal_s16(_rows1, _S1high, _a1);
  883. int16x4_t _rows1_sr4 = vshrn_n_s32(_rows1, 4);
  884. vst1_s16(rows1p, _rows1_sr4);
  885. #else
  886. rows1p[0] = (S1p[0] * a0 + S1p[4] * a1) >> 4;
  887. rows1p[1] = (S1p[1] * a0 + S1p[5] * a1) >> 4;
  888. rows1p[2] = (S1p[2] * a0 + S1p[6] * a1) >> 4;
  889. rows1p[3] = (S1p[3] * a0 + S1p[7] * a1) >> 4;
  890. #endif // __ARM_NEON
  891. ialphap += 2;
  892. rows1p += 4;
  893. }
  894. }
  895. else
  896. {
  897. // hresize two rows
  898. const unsigned char* S0 = src + srcstride * (sy);
  899. const unsigned char* S1 = src + srcstride * (sy + 1);
  900. const short* ialphap = ialpha;
  901. short* rows0p = rows0;
  902. short* rows1p = rows1;
  903. for (int dx = 0; dx < w; dx++)
  904. {
  905. int sx = xofs[dx];
  906. short a0 = ialphap[0];
  907. short a1 = ialphap[1];
  908. const unsigned char* S0p = S0 + sx;
  909. const unsigned char* S1p = S1 + sx;
  910. #if __ARM_NEON
  911. int16x4_t _a0 = vdup_n_s16(a0);
  912. int16x4_t _a1 = vdup_n_s16(a1);
  913. uint8x8_t _S0 = vld1_u8(S0p);
  914. uint8x8_t _S1 = vld1_u8(S1p);
  915. int16x8_t _S016 = vreinterpretq_s16_u16(vmovl_u8(_S0));
  916. int16x8_t _S116 = vreinterpretq_s16_u16(vmovl_u8(_S1));
  917. int16x4_t _S0low = vget_low_s16(_S016);
  918. int16x4_t _S1low = vget_low_s16(_S116);
  919. int16x4_t _S0high = vget_high_s16(_S016);
  920. int16x4_t _S1high = vget_high_s16(_S116);
  921. int32x4_t _rows0 = vmull_s16(_S0low, _a0);
  922. int32x4_t _rows1 = vmull_s16(_S1low, _a0);
  923. _rows0 = vmlal_s16(_rows0, _S0high, _a1);
  924. _rows1 = vmlal_s16(_rows1, _S1high, _a1);
  925. int16x4_t _rows0_sr4 = vshrn_n_s32(_rows0, 4);
  926. int16x4_t _rows1_sr4 = vshrn_n_s32(_rows1, 4);
  927. vst1_s16(rows0p, _rows0_sr4);
  928. vst1_s16(rows1p, _rows1_sr4);
  929. #else
  930. rows0p[0] = (S0p[0] * a0 + S0p[4] * a1) >> 4;
  931. rows0p[1] = (S0p[1] * a0 + S0p[5] * a1) >> 4;
  932. rows0p[2] = (S0p[2] * a0 + S0p[6] * a1) >> 4;
  933. rows0p[3] = (S0p[3] * a0 + S0p[7] * a1) >> 4;
  934. rows1p[0] = (S1p[0] * a0 + S1p[4] * a1) >> 4;
  935. rows1p[1] = (S1p[1] * a0 + S1p[5] * a1) >> 4;
  936. rows1p[2] = (S1p[2] * a0 + S1p[6] * a1) >> 4;
  937. rows1p[3] = (S1p[3] * a0 + S1p[7] * a1) >> 4;
  938. #endif // __ARM_NEON
  939. ialphap += 2;
  940. rows0p += 4;
  941. rows1p += 4;
  942. }
  943. }
  944. prev_sy1 = sy;
  945. // vresize
  946. short b0 = ibeta[0];
  947. short b1 = ibeta[1];
  948. short* rows0p = rows0;
  949. short* rows1p = rows1;
  950. unsigned char* Dp = dst + stride * (dy);
  951. #if __ARM_NEON
  952. int nn = (w * 4) >> 3;
  953. #else
  954. int nn = 0;
  955. #endif
  956. int remain = (w * 4) - (nn << 3);
  957. #if __ARM_NEON
  958. #if __aarch64__
  959. int16x4_t _b0 = vdup_n_s16(b0);
  960. int16x4_t _b1 = vdup_n_s16(b1);
  961. int32x4_t _v2 = vdupq_n_s32(2);
  962. for (; nn > 0; nn--)
  963. {
  964. int16x4_t _rows0p_sr4 = vld1_s16(rows0p);
  965. int16x4_t _rows1p_sr4 = vld1_s16(rows1p);
  966. int16x4_t _rows0p_1_sr4 = vld1_s16(rows0p + 4);
  967. int16x4_t _rows1p_1_sr4 = vld1_s16(rows1p + 4);
  968. int32x4_t _rows0p_sr4_mb0 = vmull_s16(_rows0p_sr4, _b0);
  969. int32x4_t _rows1p_sr4_mb1 = vmull_s16(_rows1p_sr4, _b1);
  970. int32x4_t _rows0p_1_sr4_mb0 = vmull_s16(_rows0p_1_sr4, _b0);
  971. int32x4_t _rows1p_1_sr4_mb1 = vmull_s16(_rows1p_1_sr4, _b1);
  972. int32x4_t _acc = _v2;
  973. _acc = vsraq_n_s32(_acc, _rows0p_sr4_mb0, 16);
  974. _acc = vsraq_n_s32(_acc, _rows1p_sr4_mb1, 16);
  975. int32x4_t _acc_1 = _v2;
  976. _acc_1 = vsraq_n_s32(_acc_1, _rows0p_1_sr4_mb0, 16);
  977. _acc_1 = vsraq_n_s32(_acc_1, _rows1p_1_sr4_mb1, 16);
  978. int16x4_t _acc16 = vshrn_n_s32(_acc, 2);
  979. int16x4_t _acc16_1 = vshrn_n_s32(_acc_1, 2);
  980. uint8x8_t _D = vqmovun_s16(vcombine_s16(_acc16, _acc16_1));
  981. vst1_u8(Dp, _D);
  982. Dp += 8;
  983. rows0p += 8;
  984. rows1p += 8;
  985. }
  986. #else
  987. if (nn > 0)
  988. {
  989. asm volatile(
  990. "vdup.s16 d16, %8 \n"
  991. "mov r4, #2 \n"
  992. "vdup.s16 d17, %9 \n"
  993. "vdup.s32 q12, r4 \n"
  994. "pld [%0, #128] \n"
  995. "vld1.s16 {d2-d3}, [%0 :128]!\n"
  996. "pld [%1, #128] \n"
  997. "vld1.s16 {d6-d7}, [%1 :128]!\n"
  998. "0: \n"
  999. "vmull.s16 q0, d2, d16 \n"
  1000. "vmull.s16 q1, d3, d16 \n"
  1001. "vorr.s32 q10, q12, q12 \n"
  1002. "vorr.s32 q11, q12, q12 \n"
  1003. "vmull.s16 q2, d6, d17 \n"
  1004. "vmull.s16 q3, d7, d17 \n"
  1005. "vsra.s32 q10, q0, #16 \n"
  1006. "vsra.s32 q11, q1, #16 \n"
  1007. "pld [%0, #128] \n"
  1008. "vld1.s16 {d2-d3}, [%0 :128]!\n"
  1009. "vsra.s32 q10, q2, #16 \n"
  1010. "vsra.s32 q11, q3, #16 \n"
  1011. "pld [%1, #128] \n"
  1012. "vld1.s16 {d6-d7}, [%1 :128]!\n"
  1013. "vshrn.s32 d20, q10, #2 \n"
  1014. "vshrn.s32 d21, q11, #2 \n"
  1015. "vqmovun.s16 d20, q10 \n"
  1016. "vst1.8 {d20}, [%2]! \n"
  1017. "subs %3, #1 \n"
  1018. "bne 0b \n"
  1019. "sub %0, #16 \n"
  1020. "sub %1, #16 \n"
  1021. : "=r"(rows0p), // %0
  1022. "=r"(rows1p), // %1
  1023. "=r"(Dp), // %2
  1024. "=r"(nn) // %3
  1025. : "0"(rows0p),
  1026. "1"(rows1p),
  1027. "2"(Dp),
  1028. "3"(nn),
  1029. "r"(b0), // %8
  1030. "r"(b1) // %9
  1031. : "cc", "memory", "r4", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11", "q12");
  1032. }
  1033. #endif // __aarch64__
  1034. #endif // __ARM_NEON
  1035. for (; remain; --remain)
  1036. {
  1037. // D[x] = (rows0[x]*b0 + rows1[x]*b1) >> INTER_RESIZE_COEF_BITS;
  1038. *Dp++ = (unsigned char)(((short)((b0 * (short)(*rows0p++)) >> 16) + (short)((b1 * (short)(*rows1p++)) >> 16) + 2) >> 2);
  1039. }
  1040. ibeta += 2;
  1041. }
  1042. delete[] buf;
  1043. }
  1044. void resize_bilinear_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h)
  1045. {
  1046. // assert srcw % 2 == 0
  1047. // assert srch % 2 == 0
  1048. // assert w % 2 == 0
  1049. // assert h % 2 == 0
  1050. const unsigned char* srcY = src;
  1051. unsigned char* dstY = dst;
  1052. resize_bilinear_c1(srcY, srcw, srch, dstY, w, h);
  1053. const unsigned char* srcUV = src + srcw * srch;
  1054. unsigned char* dstUV = dst + w * h;
  1055. resize_bilinear_c2(srcUV, srcw / 2, srch / 2, dstUV, w / 2, h / 2);
  1056. }
  1057. #endif // NCNN_PIXEL
  1058. } // namespace ncnn