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