convolver_mips_dspr2.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. // Copyright (c) 2013 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include <algorithm>
  5. #include "skia/ext/convolver.h"
  6. #include "skia/ext/convolver_mips_dspr2.h"
  7. #include "third_party/skia/include/core/SkTypes.h"
  8. namespace skia {
  9. // Convolves horizontally along a single row. The row data is given in
  10. // |src_data| and continues for the num_values() of the filter.
  11. void ConvolveHorizontally_mips_dspr2(const unsigned char* src_data,
  12. const ConvolutionFilter1D& filter,
  13. unsigned char* out_row,
  14. bool has_alpha) {
  15. #if SIMD_MIPS_DSPR2
  16. int row_to_filter = 0;
  17. int num_values = filter.num_values();
  18. if (has_alpha) {
  19. for (int out_x = 0; out_x < num_values; out_x++) {
  20. // Get the filter that determines the current output pixel.
  21. int filter_offset, filter_length;
  22. const ConvolutionFilter1D::Fixed* filter_values =
  23. filter.FilterForValue(out_x, &filter_offset, &filter_length);
  24. int filter_x = 0;
  25. __asm__ __volatile__ (
  26. ".set push \n"
  27. ".set noreorder \n"
  28. "beqz %[filter_len], 3f \n"
  29. " sll $t0, %[filter_offset], 2 \n"
  30. "addu %[rtf], %[src_data], $t0 \n"
  31. "mtlo $0, $ac0 \n"
  32. "mtlo $0, $ac1 \n"
  33. "mtlo $0, $ac2 \n"
  34. "mtlo $0, $ac3 \n"
  35. "srl $t7, %[filter_len], 2 \n"
  36. "beqz $t7, 2f \n"
  37. " li %[fx], 0 \n"
  38. "11: \n"
  39. "addu $t4, %[filter_val], %[fx] \n"
  40. "sll $t5, %[fx], 1 \n"
  41. "ulw $t6, 0($t4) \n" // t6 = |cur[1]|cur[0]|
  42. "ulw $t8, 4($t4) \n" // t8 = |cur[3]|cur[2]|
  43. "addu $t0, %[rtf], $t5 \n"
  44. "lw $t1, 0($t0) \n" // t1 = |a0|b0|g0|r0|
  45. "lw $t2, 4($t0) \n" // t2 = |a1|b1|g1|r1|
  46. "lw $t3, 8($t0) \n" // t3 = |a2|b2|g2|r2|
  47. "lw $t4, 12($t0) \n" // t4 = |a3|b3|g3|r3|
  48. "precrq.qb.ph $t0, $t2, $t1 \n" // t0 = |a1|g1|a0|g0|
  49. "precr.qb.ph $t5, $t2, $t1 \n" // t5 = |b1|r1|b0|r0|
  50. "preceu.ph.qbla $t1, $t0 \n" // t1 = |0|a1|0|a0|
  51. "preceu.ph.qbra $t2, $t0 \n" // t2 = |0|g1|0|g0|
  52. "preceu.ph.qbla $t0, $t5 \n" // t0 = |0|b1|0|b0|
  53. "preceu.ph.qbra $t5, $t5 \n" // t5 = |0|r1|0|r0|
  54. "dpa.w.ph $ac0, $t1, $t6 \n" // ac0+(cur*a1)+(cur*a0)
  55. "dpa.w.ph $ac1, $t0, $t6 \n" // ac1+(cur*b1)+(cur*b0)
  56. "dpa.w.ph $ac2, $t2, $t6 \n" // ac2+(cur*g1)+(cur*g0)
  57. "dpa.w.ph $ac3, $t5, $t6 \n" // ac3+(cur*r1)+(cur*r0)
  58. "precrq.qb.ph $t0, $t4, $t3 \n" // t0 = |a3|g3|a2|g2|
  59. "precr.qb.ph $t5, $t4, $t3 \n" // t5 = |b3|r3|b2|r2|
  60. "preceu.ph.qbla $t1, $t0 \n" // t1 = |0|a3|0|a2|
  61. "preceu.ph.qbra $t2, $t0 \n" // t2 = |0|g3|0|g2|
  62. "preceu.ph.qbla $t0, $t5 \n" // t0 = |0|b3|0|b2|
  63. "preceu.ph.qbra $t5, $t5 \n" // t5 = |0|r3|0|r2|
  64. "dpa.w.ph $ac0, $t1, $t8 \n" // ac0+(cur*a3)+(cur*a2)
  65. "dpa.w.ph $ac1, $t0, $t8 \n" // ac1+(cur*b3)+(cur*b2)
  66. "dpa.w.ph $ac2, $t2, $t8 \n" // ac2+(cur*g3)+(cur*g2)
  67. "dpa.w.ph $ac3, $t5, $t8 \n" // ac3+(cur*r3)+(cur*r2)
  68. "addiu $t7, $t7, -1 \n"
  69. "bgtz $t7, 11b \n"
  70. " addiu %[fx], %[fx], 8 \n"
  71. "2: \n"
  72. "andi $t7, %[filter_len], 0x3 \n" // residual
  73. "beqz $t7, 3f \n"
  74. " nop \n"
  75. "21: \n"
  76. "sll $t1, %[fx], 1 \n"
  77. "addu $t2, %[filter_val], %[fx] \n"
  78. "addu $t0, %[rtf], $t1 \n"
  79. "lh $t6, 0($t2) \n" // t6 = filter_val[fx]
  80. "lbu $t1, 0($t0) \n" // t1 = row[fx * 4 + 0]
  81. "lbu $t2, 1($t0) \n" // t2 = row[fx * 4 + 1]
  82. "lbu $t3, 2($t0) \n" // t3 = row[fx * 4 + 2]
  83. "lbu $t4, 3($t0) \n" // t4 = row[fx * 4 + 2]
  84. "maddu $ac3, $t6, $t1 \n"
  85. "maddu $ac2, $t6, $t2 \n"
  86. "maddu $ac1, $t6, $t3 \n"
  87. "maddu $ac0, $t6, $t4 \n"
  88. "addiu $t7, $t7, -1 \n"
  89. "bgtz $t7, 21b \n"
  90. " addiu %[fx], %[fx], 2 \n"
  91. "3: \n"
  92. "extrv.w $t0, $ac0, %[kShiftBits] \n" // a >> kShiftBits
  93. "extrv.w $t1, $ac1, %[kShiftBits] \n" // b >> kShiftBits
  94. "extrv.w $t2, $ac2, %[kShiftBits] \n" // g >> kShiftBits
  95. "extrv.w $t3, $ac3, %[kShiftBits] \n" // r >> kShiftBits
  96. "sll $t5, %[out_x], 2 \n"
  97. "repl.ph $t6, 128 \n" // t6 = | 128 | 128 |
  98. "addu $t5, %[out_row], $t5 \n"
  99. "append $t2, $t3, 16 \n"
  100. "append $t0, $t1, 16 \n"
  101. "subu.ph $t1, $t0, $t6 \n"
  102. "shll_s.ph $t1, $t1, 8 \n"
  103. "shra.ph $t1, $t1, 8 \n"
  104. "addu.ph $t1, $t1, $t6 \n"
  105. "subu.ph $t3, $t2, $t6 \n"
  106. "shll_s.ph $t3, $t3, 8 \n"
  107. "shra.ph $t3, $t3, 8 \n"
  108. "addu.ph $t3, $t3, $t6 \n"
  109. "precr.qb.ph $t0, $t1, $t3 \n"
  110. "usw $t0, 0($t5) \n"
  111. ".set pop \n"
  112. : [fx] "+r" (filter_x), [out_x] "+r" (out_x), [out_row] "+r" (out_row),
  113. [rtf] "+r" (row_to_filter)
  114. : [filter_val] "r" (filter_values), [filter_len] "r" (filter_length),
  115. [kShiftBits] "r" (ConvolutionFilter1D::kShiftBits),
  116. [filter_offset] "r" (filter_offset), [src_data] "r" (src_data)
  117. : "lo", "hi", "$ac1lo", "$ac1hi", "$ac2lo", "$ac2hi", "$ac3lo", "$ac3hi",
  118. "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8"
  119. );
  120. }
  121. } else {
  122. for (int out_x = 0; out_x < num_values; out_x++) {
  123. // Get the filter that determines the current output pixel.
  124. int filter_offset, filter_length;
  125. const ConvolutionFilter1D::Fixed* filter_values =
  126. filter.FilterForValue(out_x, &filter_offset, &filter_length);
  127. int filter_x = 0;
  128. __asm__ __volatile__ (
  129. ".set push \n"
  130. ".set noreorder \n"
  131. "beqz %[filter_len], 3f \n"
  132. " sll $t0, %[filter_offset], 2 \n"
  133. "addu %[rtf], %[src_data], $t0 \n"
  134. "mtlo $0, $ac1 \n"
  135. "mtlo $0, $ac2 \n"
  136. "mtlo $0, $ac3 \n"
  137. "srl $t7, %[filter_len], 2 \n"
  138. "beqz $t7, 2f \n"
  139. " li %[fx], 0 \n"
  140. "11: \n"
  141. "addu $t4, %[filter_val], %[fx] \n"
  142. "sll $t5, %[fx], 1 \n"
  143. "ulw $t6, 0($t4) \n" // t6 = |cur[1]|cur[0]|
  144. "ulw $t8, 4($t4) \n" // t8 = |cur[3]|cur[2]|
  145. "addu $t0, %[rtf], $t5 \n"
  146. "lw $t1, 0($t0) \n" // t1 = |a0|b0|g0|r0|
  147. "lw $t2, 4($t0) \n" // t2 = |a1|b1|g1|r1|
  148. "lw $t3, 8($t0) \n" // t3 = |a2|b2|g2|r2|
  149. "lw $t4, 12($t0) \n" // t4 = |a3|b3|g3|r3|
  150. "precrq.qb.ph $t0, $t2, $t1 \n" // t0 = |a1|g1|a0|g0|
  151. "precr.qb.ph $t5, $t2, $t1 \n" // t5 = |b1|r1|b0|r0|
  152. "preceu.ph.qbra $t2, $t0 \n" // t2 = |0|g1|0|g0|
  153. "preceu.ph.qbla $t0, $t5 \n" // t0 = |0|b1|0|b0|
  154. "preceu.ph.qbra $t5, $t5 \n" // t5 = |0|r1|0|r0|
  155. "dpa.w.ph $ac1, $t0, $t6 \n" // ac1+(cur*b1)+(cur*b0)
  156. "dpa.w.ph $ac2, $t2, $t6 \n" // ac2+(cur*g1)+(cur*g0)
  157. "dpa.w.ph $ac3, $t5, $t6 \n" // ac3+(cur*r1)+(cur*r0)
  158. "precrq.qb.ph $t0, $t4, $t3 \n" // t0 = |a3|g3|a2|g2|
  159. "precr.qb.ph $t5, $t4, $t3 \n" // t5 = |b3|r3|b2|r2|
  160. "preceu.ph.qbra $t2, $t0 \n" // t2 = |0|g3|0|g2|
  161. "preceu.ph.qbla $t0, $t5 \n" // t0 = |0|b3|0|b2|
  162. "preceu.ph.qbra $t5, $t5 \n" // t5 = |0|r3|0|r2|
  163. "dpa.w.ph $ac1, $t0, $t8 \n" // ac1+(cur*b3)+(cur*b2)
  164. "dpa.w.ph $ac2, $t2, $t8 \n" // ac2+(cur*g3)+(cur*g2)
  165. "dpa.w.ph $ac3, $t5, $t8 \n" // ac3+(cur*r3)+(cur*r2)
  166. "addiu $t7, $t7, -1 \n"
  167. "bgtz $t7, 11b \n"
  168. " addiu %[fx], %[fx], 8 \n"
  169. "2: \n"
  170. "andi $t7, %[filter_len], 0x3 \n" // residual
  171. "beqz $t7, 3f \n"
  172. " nop \n"
  173. "21: \n"
  174. "sll $t1, %[fx], 1 \n"
  175. "addu $t2, %[filter_val], %[fx] \n"
  176. "addu $t0, %[rtf], $t1 \n"
  177. "lh $t6, 0($t2) \n" // t6 = filter_val[fx]
  178. "lbu $t1, 0($t0) \n" // t1 = row[fx * 4 + 0]
  179. "lbu $t2, 1($t0) \n" // t2 = row[fx * 4 + 1]
  180. "lbu $t3, 2($t0) \n" // t3 = row[fx * 4 + 2]
  181. "maddu $ac3, $t6, $t1 \n"
  182. "maddu $ac2, $t6, $t2 \n"
  183. "maddu $ac1, $t6, $t3 \n"
  184. "addiu $t7, $t7, -1 \n"
  185. "bgtz $t7, 21b \n"
  186. " addiu %[fx], %[fx], 2 \n"
  187. "3: \n"
  188. "extrv.w $t1, $ac1, %[kShiftBits] \n" // b >> kShiftBits
  189. "extrv.w $t2, $ac2, %[kShiftBits] \n" // g >> kShiftBits
  190. "extrv.w $t3, $ac3, %[kShiftBits] \n" // r >> kShiftBits
  191. "repl.ph $t6, 128 \n" // t6 = | 128 | 128 |
  192. "sll $t8, %[out_x], 2 \n"
  193. "addu $t8, %[out_row], $t8 \n"
  194. "append $t2, $t3, 16 \n"
  195. "andi $t1, 0xFFFF \n"
  196. "subu.ph $t5, $t1, $t6 \n"
  197. "shll_s.ph $t5, $t5, 8 \n"
  198. "shra.ph $t5, $t5, 8 \n"
  199. "addu.ph $t5, $t5, $t6 \n"
  200. "subu.ph $t4, $t2, $t6 \n"
  201. "shll_s.ph $t4, $t4, 8 \n"
  202. "shra.ph $t4, $t4, 8 \n"
  203. "addu.ph $t4, $t4, $t6 \n"
  204. "precr.qb.ph $t0, $t5, $t4 \n"
  205. "usw $t0, 0($t8) \n"
  206. ".set pop \n"
  207. : [fx] "+r" (filter_x), [out_x] "+r" (out_x), [out_row] "+r" (out_row),
  208. [rtf] "+r" (row_to_filter)
  209. : [filter_val] "r" (filter_values), [filter_len] "r" (filter_length),
  210. [kShiftBits] "r" (ConvolutionFilter1D::kShiftBits),
  211. [filter_offset] "r" (filter_offset), [src_data] "r" (src_data)
  212. : "lo", "hi", "$ac1lo", "$ac1hi", "$ac2lo", "$ac2hi", "$ac3lo", "$ac3hi",
  213. "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8"
  214. );
  215. }
  216. }
  217. #endif
  218. }
  219. void ConvolveVertically_mips_dspr2(const ConvolutionFilter1D::Fixed* filter_val,
  220. int filter_length,
  221. unsigned char* const* source_data_rows,
  222. int pixel_width,
  223. unsigned char* out_row,
  224. bool has_alpha) {
  225. #if SIMD_MIPS_DSPR2
  226. // We go through each column in the output and do a vertical convolution,
  227. // generating one output pixel each time.
  228. int byte_offset;
  229. int cnt;
  230. int filter_y;
  231. if (has_alpha) {
  232. for (int out_x = 0; out_x < pixel_width; out_x++) {
  233. __asm__ __volatile__ (
  234. ".set push \n"
  235. ".set noreorder \n"
  236. "beqz %[filter_len], 3f \n"
  237. " sll %[offset], %[out_x], 2 \n"
  238. "mtlo $0, $ac0 \n"
  239. "mtlo $0, $ac1 \n"
  240. "mtlo $0, $ac2 \n"
  241. "mtlo $0, $ac3 \n"
  242. "srl %[cnt], %[filter_len], 2 \n"
  243. "beqz %[cnt], 2f \n"
  244. " li %[fy], 0 \n"
  245. "11: \n"
  246. "sll $t1, %[fy], 1 \n"
  247. "addu $t0, %[src_data_rows], $t1 \n"
  248. "lw $t1, 0($t0) \n"
  249. "lw $t2, 4($t0) \n"
  250. "lw $t3, 8($t0) \n"
  251. "lw $t4, 12($t0) \n"
  252. "addu $t1, $t1, %[offset] \n"
  253. "addu $t2, $t2, %[offset] \n"
  254. "addu $t3, $t3, %[offset] \n"
  255. "addu $t4, $t4, %[offset] \n"
  256. "lw $t1, 0($t1) \n" // t1 = |a0|b0|g0|r0|
  257. "lw $t2, 0($t2) \n" // t2 = |a1|b1|g1|r1|
  258. "lw $t3, 0($t3) \n" // t3 = |a0|b0|g0|r0|
  259. "lw $t4, 0($t4) \n" // t4 = |a1|b1|g1|r1|
  260. "precrq.qb.ph $t5, $t2, $t1 \n" // t5 = |a1|g1|a0|g0|
  261. "precr.qb.ph $t6, $t2, $t1 \n" // t6 = |b1|r1|b0|r0|
  262. "preceu.ph.qbla $t0, $t5 \n" // t0 = |0|a1|0|a0|
  263. "preceu.ph.qbra $t1, $t5 \n" // t1 = |0|g1|0|g0|
  264. "preceu.ph.qbla $t2, $t6 \n" // t2 = |0|b1|0|b0|
  265. "preceu.ph.qbra $t5, $t6 \n" // t5 = |0|r1|0|r0|
  266. "addu $t6, %[filter_val], %[fy] \n"
  267. "ulw $t7, 0($t6) \n" // t7 = |cur_1|cur_0|
  268. "ulw $t6, 4($t6) \n" // t6 = |cur_3|cur_2|
  269. "dpa.w.ph $ac0, $t5, $t7 \n" // (cur*r1)+(cur*r0)
  270. "dpa.w.ph $ac1, $t1, $t7 \n" // (cur*g1)+(cur*g0)
  271. "dpa.w.ph $ac2, $t2, $t7 \n" // (cur*b1)+(cur*b0)
  272. "dpa.w.ph $ac3, $t0, $t7 \n" // (cur*a1)+(cur*a0)
  273. "precrq.qb.ph $t5, $t4, $t3 \n" // t5 = |a3|g3|a2|g2|
  274. "precr.qb.ph $t7, $t4, $t3 \n" // t7 = |b3|r3|b2|r2|
  275. "preceu.ph.qbla $t0, $t5 \n" // t0 = |0|a3|0|a2|
  276. "preceu.ph.qbra $t1, $t5 \n" // t1 = |0|g3|0|g2|
  277. "preceu.ph.qbla $t2, $t7 \n" // t2 = |0|b3|0|b2|
  278. "preceu.ph.qbra $t5, $t7 \n" // t5 = |0|r3|0|r2|
  279. "dpa.w.ph $ac0, $t5, $t6 \n" // (cur*r3)+(cur*r2)
  280. "dpa.w.ph $ac1, $t1, $t6 \n" // (cur*g3)+(cur*g2)
  281. "dpa.w.ph $ac2, $t2, $t6 \n" // (cur*b3)+(cur*b2)
  282. "dpa.w.ph $ac3, $t0, $t6 \n" // (cur*a3)+(cur*a2)
  283. "addiu %[cnt], %[cnt], -1 \n"
  284. "bgtz %[cnt], 11b \n"
  285. " addiu %[fy], %[fy], 8 \n"
  286. "2: \n"
  287. "andi %[cnt], %[filter_len], 0x3 \n" // residual
  288. "beqz %[cnt], 3f \n"
  289. " nop \n"
  290. "21: \n"
  291. "addu $t0, %[filter_val], %[fy] \n"
  292. "lh $t4, 0($t0) \n" // t4=filter_val[fx]
  293. "sll $t1, %[fy], 1 \n"
  294. "addu $t0, %[src_data_rows], $t1 \n"
  295. "lw $t1, 0($t0) \n"
  296. "addu $t0, $t1, %[offset] \n"
  297. "lbu $t1, 0($t0) \n" // t1 = row[fx*4 + 0]
  298. "lbu $t2, 1($t0) \n" // t2 = row[fx*4 + 1]
  299. "lbu $t3, 2($t0) \n" // t3 = row[fx*4 + 2]
  300. "lbu $t0, 3($t0) \n" // t4 = row[fx*4 + 2]
  301. "maddu $ac0, $t4, $t1 \n"
  302. "maddu $ac1, $t4, $t2 \n"
  303. "maddu $ac2, $t4, $t3 \n"
  304. "maddu $ac3, $t4, $t0 \n"
  305. "addiu %[cnt], %[cnt], -1 \n"
  306. "bgtz %[cnt], 21b \n"
  307. " addiu %[fy], %[fy], 2 \n"
  308. "3: \n"
  309. "extrv.w $t3, $ac0, %[kShiftBits] \n" // a >> kShiftBits
  310. "extrv.w $t2, $ac1, %[kShiftBits] \n" // b >> kShiftBits
  311. "extrv.w $t1, $ac2, %[kShiftBits] \n" // g >> kShiftBits
  312. "extrv.w $t0, $ac3, %[kShiftBits] \n" // r >> kShiftBits
  313. "repl.ph $t4, 128 \n" // t4 = | 128 | 128 |
  314. "addu $t5, %[out_row], %[offset] \n"
  315. "append $t2, $t3, 16 \n" // t2 = |0|g|0|r|
  316. "append $t0, $t1, 16 \n" // t0 = |0|a|0|b|
  317. "subu.ph $t1, $t0, $t4 \n"
  318. "shll_s.ph $t1, $t1, 8 \n"
  319. "shra.ph $t1, $t1, 8 \n"
  320. "addu.ph $t1, $t1, $t4 \n" // Clamp(a)|Clamp(b)
  321. "subu.ph $t2, $t2, $t4 \n"
  322. "shll_s.ph $t2, $t2, 8 \n"
  323. "shra.ph $t2, $t2, 8 \n"
  324. "addu.ph $t2, $t2, $t4 \n" // Clamp(g)|Clamp(r)
  325. "andi $t3, $t1, 0xFF \n" // t3 = ClampTo8(b)
  326. "cmp.lt.ph $t3, $t2 \n" // cmp b, g, r
  327. "pick.ph $t0, $t2, $t3 \n"
  328. "andi $t3, $t0, 0xFF \n"
  329. "srl $t4, $t0, 16 \n"
  330. "cmp.lt.ph $t3, $t4 \n"
  331. "pick.ph $t0, $t4, $t3 \n" // t0 = max_color_ch
  332. "srl $t3, $t1, 16 \n" // t1 = ClampTo8(a)
  333. "cmp.lt.ph $t3, $t0 \n"
  334. "pick.ph $t0, $t0, $t3 \n"
  335. "ins $t1, $t0, 16, 8 \n"
  336. "precr.qb.ph $t0, $t1, $t2 \n" // t0 = |a|b|g|r|
  337. "usw $t0, 0($t5) \n"
  338. ".set pop \n"
  339. : [filter_val] "+r" (filter_val), [filter_len] "+r" (filter_length),
  340. [offset] "+r" (byte_offset), [fy] "+r" (filter_y), [cnt] "+r" (cnt),
  341. [out_x] "+r" (out_x), [pixel_width] "+r" (pixel_width)
  342. : [src_data_rows] "r" (source_data_rows), [out_row] "r" (out_row),
  343. [kShiftBits] "r" (ConvolutionFilter1D::kShiftBits)
  344. : "lo", "hi", "$ac1lo", "$ac1hi", "$ac2lo", "$ac2hi", "$ac3lo", "$ac3hi",
  345. "t0", "t1", "t2", "t3", "t4", "t5", "t6","t7", "memory"
  346. );
  347. }
  348. } else {
  349. for (int out_x = 0; out_x < pixel_width; out_x++) {
  350. __asm__ __volatile__ (
  351. ".set push \n"
  352. ".set noreorder \n"
  353. "beqz %[filter_len], 3f \n"
  354. " sll %[offset], %[out_x], 2 \n"
  355. "mtlo $0, $ac0 \n"
  356. "mtlo $0, $ac1 \n"
  357. "mtlo $0, $ac2 \n"
  358. "srl %[cnt], %[filter_len], 2 \n"
  359. "beqz %[cnt], 2f \n"
  360. " li %[fy], 0 \n"
  361. "11: \n"
  362. "sll $t1, %[fy], 1 \n"
  363. "addu $t0, %[src_data_rows], $t1 \n"
  364. "lw $t1, 0($t0) \n"
  365. "lw $t2, 4($t0) \n"
  366. "lw $t3, 8($t0) \n"
  367. "lw $t4, 12($t0) \n"
  368. "addu $t1, $t1, %[offset] \n"
  369. "addu $t2, $t2, %[offset] \n"
  370. "addu $t3, $t3, %[offset] \n"
  371. "addu $t4, $t4, %[offset] \n"
  372. "lw $t1, 0($t1) \n" // t1 = |a0|b0|g0|r0|
  373. "lw $t2, 0($t2) \n" // t2 = |a1|b1|g1|r1|
  374. "lw $t3, 0($t3) \n" // t3 = |a0|b0|g0|r0|
  375. "lw $t4, 0($t4) \n" // t4 = |a1|b1|g1|r1|
  376. "precrq.qb.ph $t5, $t2, $t1 \n" // t5 = |a1|g1|a0|g0|
  377. "precr.qb.ph $t6, $t2, $t1 \n" // t6 = |b1|r1|b0|r0|
  378. "preceu.ph.qbra $t1, $t5 \n" // t1 = |0|g1|0|g0|
  379. "preceu.ph.qbla $t2, $t6 \n" // t2 = |0|b1|0|b0|
  380. "preceu.ph.qbra $t5, $t6 \n" // t5 = |0|r1|0|r0|
  381. "addu $t6, %[filter_val], %[fy] \n"
  382. "ulw $t0, 0($t6) \n" // t0 = |cur_1|cur_0|
  383. "ulw $t6, 4($t6) \n" // t6 = |cur_1|cur_0|
  384. "dpa.w.ph $ac0, $t5, $t0 \n" // (cur*r1)+(cur*r0)
  385. "dpa.w.ph $ac1, $t1, $t0 \n" // (cur*g1)+(cur*g0)
  386. "dpa.w.ph $ac2, $t2, $t0 \n" // (cur*b1)+(cur*b0)
  387. "precrq.qb.ph $t5, $t4, $t3 \n" // t5 = |a3|g3|a2|g2|
  388. "precr.qb.ph $t0, $t4, $t3 \n" // t0 = |b3|r3|b2|r2|
  389. "preceu.ph.qbra $t1, $t5 \n" // t1 = |0|g3|0|g2|
  390. "preceu.ph.qbla $t2, $t0 \n" // t2 = |0|b3|0|b2|
  391. "preceu.ph.qbra $t5, $t0 \n" // t5 = |0|r3|0|r2|
  392. "dpa.w.ph $ac0, $t5, $t6 \n" // (cur*r1)+(cur*r0)
  393. "dpa.w.ph $ac1, $t1, $t6 \n" // (cur*g1)+(cur*g0)
  394. "dpa.w.ph $ac2, $t2, $t6 \n" // (cur*b1)+(cur*b0)
  395. "addiu %[cnt], %[cnt], -1 \n"
  396. "bgtz %[cnt], 11b \n"
  397. " addiu %[fy], %[fy], 8 \n"
  398. "2: \n"
  399. "andi %[cnt], %[filter_len], 0x3 \n" // residual
  400. "beqz %[cnt], 3f \n"
  401. " nop \n"
  402. "21: \n"
  403. "addu $t0, %[filter_val], %[fy] \n"
  404. "lh $t4, 0($t0) \n" // filter_val[fx]
  405. "sll $t1, %[fy], 1 \n"
  406. "addu $t0, %[src_data_rows], $t1 \n"
  407. "lw $t1, 0($t0) \n"
  408. "addu $t0, $t1, %[offset] \n"
  409. "lbu $t1, 0($t0) \n" // t1 = row[fx*4 + 0]
  410. "lbu $t2, 1($t0) \n" // t2 = row[fx*4 + 1]
  411. "lbu $t3, 2($t0) \n" // t3 = row[fx*4 + 2]
  412. "maddu $ac0, $t4, $t1 \n"
  413. "maddu $ac1, $t4, $t2 \n"
  414. "maddu $ac2, $t4, $t3 \n"
  415. "addiu %[cnt], %[cnt], -1 \n"
  416. "bgtz %[cnt], 21b \n"
  417. " addiu %[fy], %[fy], 2 \n"
  418. "3: \n"
  419. "extrv.w $t3, $ac0, %[kShiftBits] \n" // r >> kShiftBits
  420. "extrv.w $t2, $ac1, %[kShiftBits] \n" // g >> kShiftBits
  421. "extrv.w $t1, $ac2, %[kShiftBits] \n" // b >> kShiftBits
  422. "repl.ph $t6, 128 \n" // t6 = | 128 | 128 |
  423. "addu $t5, %[out_row], %[offset] \n"
  424. "append $t2, $t3, 16 \n" // t2 = |0|g|0|r|
  425. "andi $t1, $t1, 0xFFFF \n"
  426. "subu.ph $t1, $t1, $t6 \n"
  427. "shll_s.ph $t1, $t1, 8 \n"
  428. "shra.ph $t1, $t1, 8 \n"
  429. "addu.ph $t1, $t1, $t6 \n" // Clamp(a)|Clamp(b)
  430. "subu.ph $t2, $t2, $t6 \n"
  431. "shll_s.ph $t2, $t2, 8 \n"
  432. "shra.ph $t2, $t2, 8 \n"
  433. "addu.ph $t2, $t2, $t6 \n" // Clamp(g)|Clamp(r)
  434. "li $t0, 0xFF \n"
  435. "ins $t1, $t0, 16, 8 \n"
  436. "precr.qb.ph $t0, $t1, $t2 \n" // t0 = |a|b|g|r|
  437. "usw $t0, 0($t5) \n"
  438. ".set pop \n"
  439. : [filter_val] "+r" (filter_val), [filter_len] "+r" (filter_length),
  440. [offset] "+r" (byte_offset), [fy] "+r" (filter_y), [cnt] "+r" (cnt),
  441. [out_x] "+r" (out_x), [pixel_width] "+r" (pixel_width)
  442. : [src_data_rows] "r" (source_data_rows), [out_row] "r" (out_row),
  443. [kShiftBits] "r" (ConvolutionFilter1D::kShiftBits)
  444. : "lo", "hi", "$ac1lo", "$ac1hi", "$ac2lo", "$ac2hi", "$ac3lo", "$ac3hi",
  445. "t0", "t1", "t2", "t3", "t4", "t5", "t6", "memory"
  446. );
  447. }
  448. }
  449. #endif
  450. }
  451. } // namespace skia