Changeset 5633 for pjproject/trunk/third_party/yuv/source/scale_neon.cc
- Timestamp:
- Jul 28, 2017 2:51:44 AM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/third_party/yuv/source/scale_neon.cc
r5358 r5633 24 24 25 25 // Read 32x1 throw away even pixels, and write 16x1. 26 void ScaleRowDown2_NEON(const uint8* src_ptr, ptrdiff_t src_stride, 27 uint8* dst, int dst_width) { 28 asm volatile ( 29 "1: \n" 30 // load even pixels into q0, odd into q1 31 MEMACCESS(0) 32 "vld2.8 {q0, q1}, [%0]! \n" 33 "subs %2, %2, #16 \n" // 16 processed per loop 34 MEMACCESS(1) 35 "vst1.8 {q1}, [%1]! \n" // store odd pixels 36 "bgt 1b \n" 37 : "+r"(src_ptr), // %0 38 "+r"(dst), // %1 39 "+r"(dst_width) // %2 40 : 41 : "q0", "q1" // Clobber List 42 ); 26 void ScaleRowDown2_NEON(const uint8* src_ptr, 27 ptrdiff_t src_stride, 28 uint8* dst, 29 int dst_width) { 30 (void)src_stride; 31 asm volatile( 32 "1: \n" 33 // load even pixels into q0, odd into q1 34 "vld2.8 {q0, q1}, [%0]! \n" 35 "subs %2, %2, #16 \n" // 16 processed per loop 36 "vst1.8 {q1}, [%1]! \n" // store odd pixels 37 "bgt 1b \n" 38 : "+r"(src_ptr), // %0 39 "+r"(dst), // %1 40 "+r"(dst_width) // %2 41 : 42 : "q0", "q1" // Clobber List 43 ); 43 44 } 44 45 45 46 // Read 32x1 average down and write 16x1. 46 void ScaleRowDown2Linear_NEON(const uint8* src_ptr, ptrdiff_t src_stride, 47 uint8* dst, int dst_width) { 48 asm volatile ( 49 "1: \n" 50 MEMACCESS(0) 51 "vld1.8 {q0, q1}, [%0]! \n" // load pixels and post inc 52 "subs %2, %2, #16 \n" // 16 processed per loop 53 "vpaddl.u8 q0, q0 \n" // add adjacent 54 "vpaddl.u8 q1, q1 \n" 55 "vrshrn.u16 d0, q0, #1 \n" // downshift, round and pack 56 "vrshrn.u16 d1, q1, #1 \n" 57 MEMACCESS(1) 58 "vst1.8 {q0}, [%1]! \n" 59 "bgt 1b \n" 60 : "+r"(src_ptr), // %0 61 "+r"(dst), // %1 62 "+r"(dst_width) // %2 63 : 64 : "q0", "q1" // Clobber List 65 ); 47 void ScaleRowDown2Linear_NEON(const uint8* src_ptr, 48 ptrdiff_t src_stride, 49 uint8* dst, 50 int dst_width) { 51 (void)src_stride; 52 asm volatile( 53 "1: \n" 54 "vld1.8 {q0, q1}, [%0]! \n" // load pixels and post 55 // inc 56 "subs %2, %2, #16 \n" // 16 processed per loop 57 "vpaddl.u8 q0, q0 \n" // add adjacent 58 "vpaddl.u8 q1, q1 \n" 59 "vrshrn.u16 d0, q0, #1 \n" // downshift, round and 60 // pack 61 "vrshrn.u16 d1, q1, #1 \n" 62 "vst1.8 {q0}, [%1]! \n" 63 "bgt 1b \n" 64 : "+r"(src_ptr), // %0 65 "+r"(dst), // %1 66 "+r"(dst_width) // %2 67 : 68 : "q0", "q1" // Clobber List 69 ); 66 70 } 67 71 68 72 // Read 32x2 average down and write 16x1. 69 void ScaleRowDown2Box_NEON(const uint8* src_ptr, ptrdiff_t src_stride, 70 uint8* dst, int dst_width) { 71 asm volatile ( 72 // change the stride to row 2 pointer 73 "add %1, %0 \n" 74 "1: \n" 75 MEMACCESS(0) 76 "vld1.8 {q0, q1}, [%0]! \n" // load row 1 and post inc 77 MEMACCESS(1) 78 "vld1.8 {q2, q3}, [%1]! \n" // load row 2 and post inc 79 "subs %3, %3, #16 \n" // 16 processed per loop 80 "vpaddl.u8 q0, q0 \n" // row 1 add adjacent 81 "vpaddl.u8 q1, q1 \n" 82 "vpadal.u8 q0, q2 \n" // row 2 add adjacent + row1 83 "vpadal.u8 q1, q3 \n" 84 "vrshrn.u16 d0, q0, #2 \n" // downshift, round and pack 85 "vrshrn.u16 d1, q1, #2 \n" 86 MEMACCESS(2) 87 "vst1.8 {q0}, [%2]! \n" 88 "bgt 1b \n" 89 : "+r"(src_ptr), // %0 90 "+r"(src_stride), // %1 91 "+r"(dst), // %2 92 "+r"(dst_width) // %3 93 : 94 : "q0", "q1", "q2", "q3" // Clobber List 95 ); 96 } 97 98 void ScaleRowDown4_NEON(const uint8* src_ptr, ptrdiff_t src_stride, 99 uint8* dst_ptr, int dst_width) { 100 asm volatile ( 101 "1: \n" 102 MEMACCESS(0) 103 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // src line 0 104 "subs %2, %2, #8 \n" // 8 processed per loop 105 MEMACCESS(1) 106 "vst1.8 {d2}, [%1]! \n" 107 "bgt 1b \n" 108 : "+r"(src_ptr), // %0 109 "+r"(dst_ptr), // %1 110 "+r"(dst_width) // %2 111 : 112 : "q0", "q1", "memory", "cc" 113 ); 114 } 115 116 void ScaleRowDown4Box_NEON(const uint8* src_ptr, ptrdiff_t src_stride, 117 uint8* dst_ptr, int dst_width) { 73 void ScaleRowDown2Box_NEON(const uint8* src_ptr, 74 ptrdiff_t src_stride, 75 uint8* dst, 76 int dst_width) { 77 asm volatile( 78 // change the stride to row 2 pointer 79 "add %1, %0 \n" 80 "1: \n" 81 "vld1.8 {q0, q1}, [%0]! \n" // load row 1 and post inc 82 "vld1.8 {q2, q3}, [%1]! \n" // load row 2 and post inc 83 "subs %3, %3, #16 \n" // 16 processed per loop 84 "vpaddl.u8 q0, q0 \n" // row 1 add adjacent 85 "vpaddl.u8 q1, q1 \n" 86 "vpadal.u8 q0, q2 \n" // row 2 add adjacent + 87 // row1 88 "vpadal.u8 q1, q3 \n" 89 "vrshrn.u16 d0, q0, #2 \n" // downshift, round and 90 // pack 91 "vrshrn.u16 d1, q1, #2 \n" 92 "vst1.8 {q0}, [%2]! \n" 93 "bgt 1b \n" 94 : "+r"(src_ptr), // %0 95 "+r"(src_stride), // %1 96 "+r"(dst), // %2 97 "+r"(dst_width) // %3 98 : 99 : "q0", "q1", "q2", "q3" // Clobber List 100 ); 101 } 102 103 void ScaleRowDown4_NEON(const uint8* src_ptr, 104 ptrdiff_t src_stride, 105 uint8* dst_ptr, 106 int dst_width) { 107 (void)src_stride; 108 asm volatile( 109 "1: \n" 110 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // src line 0 111 "subs %2, %2, #8 \n" // 8 processed per loop 112 "vst1.8 {d2}, [%1]! \n" 113 "bgt 1b \n" 114 : "+r"(src_ptr), // %0 115 "+r"(dst_ptr), // %1 116 "+r"(dst_width) // %2 117 : 118 : "q0", "q1", "memory", "cc"); 119 } 120 121 void ScaleRowDown4Box_NEON(const uint8* src_ptr, 122 ptrdiff_t src_stride, 123 uint8* dst_ptr, 124 int dst_width) { 118 125 const uint8* src_ptr1 = src_ptr + src_stride; 119 126 const uint8* src_ptr2 = src_ptr + src_stride * 2; 120 127 const uint8* src_ptr3 = src_ptr + src_stride * 3; 121 asm volatile ( 122 "1: \n" 123 MEMACCESS(0) 124 "vld1.8 {q0}, [%0]! \n" // load up 16x4 125 MEMACCESS(3) 126 "vld1.8 {q1}, [%3]! \n" 127 MEMACCESS(4) 128 "vld1.8 {q2}, [%4]! \n" 129 MEMACCESS(5) 130 "vld1.8 {q3}, [%5]! \n" 131 "subs %2, %2, #4 \n" 132 "vpaddl.u8 q0, q0 \n" 133 "vpadal.u8 q0, q1 \n" 134 "vpadal.u8 q0, q2 \n" 135 "vpadal.u8 q0, q3 \n" 136 "vpaddl.u16 q0, q0 \n" 137 "vrshrn.u32 d0, q0, #4 \n" // divide by 16 w/rounding 138 "vmovn.u16 d0, q0 \n" 139 MEMACCESS(1) 140 "vst1.32 {d0[0]}, [%1]! \n" 141 "bgt 1b \n" 142 : "+r"(src_ptr), // %0 143 "+r"(dst_ptr), // %1 144 "+r"(dst_width), // %2 145 "+r"(src_ptr1), // %3 146 "+r"(src_ptr2), // %4 147 "+r"(src_ptr3) // %5 148 : 149 : "q0", "q1", "q2", "q3", "memory", "cc" 150 ); 128 asm volatile( 129 "1: \n" 130 "vld1.8 {q0}, [%0]! \n" // load up 16x4 131 "vld1.8 {q1}, [%3]! \n" 132 "vld1.8 {q2}, [%4]! \n" 133 "vld1.8 {q3}, [%5]! \n" 134 "subs %2, %2, #4 \n" 135 "vpaddl.u8 q0, q0 \n" 136 "vpadal.u8 q0, q1 \n" 137 "vpadal.u8 q0, q2 \n" 138 "vpadal.u8 q0, q3 \n" 139 "vpaddl.u16 q0, q0 \n" 140 "vrshrn.u32 d0, q0, #4 \n" // divide by 16 w/rounding 141 "vmovn.u16 d0, q0 \n" 142 "vst1.32 {d0[0]}, [%1]! \n" 143 "bgt 1b \n" 144 : "+r"(src_ptr), // %0 145 "+r"(dst_ptr), // %1 146 "+r"(dst_width), // %2 147 "+r"(src_ptr1), // %3 148 "+r"(src_ptr2), // %4 149 "+r"(src_ptr3) // %5 150 : 151 : "q0", "q1", "q2", "q3", "memory", "cc"); 151 152 } 152 153 … … 156 157 void ScaleRowDown34_NEON(const uint8* src_ptr, 157 158 ptrdiff_t src_stride, 158 uint8* dst_ptr, int dst_width) { 159 asm volatile ( 160 "1: \n" 161 MEMACCESS(0) 162 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // src line 0 163 "subs %2, %2, #24 \n" 164 "vmov d2, d3 \n" // order d0, d1, d2 165 MEMACCESS(1) 166 "vst3.8 {d0, d1, d2}, [%1]! \n" 167 "bgt 1b \n" 168 : "+r"(src_ptr), // %0 169 "+r"(dst_ptr), // %1 170 "+r"(dst_width) // %2 171 : 172 : "d0", "d1", "d2", "d3", "memory", "cc" 173 ); 159 uint8* dst_ptr, 160 int dst_width) { 161 (void)src_stride; 162 asm volatile( 163 "1: \n" 164 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // src line 0 165 "subs %2, %2, #24 \n" 166 "vmov d2, d3 \n" // order d0, d1, d2 167 "vst3.8 {d0, d1, d2}, [%1]! \n" 168 "bgt 1b \n" 169 : "+r"(src_ptr), // %0 170 "+r"(dst_ptr), // %1 171 "+r"(dst_width) // %2 172 : 173 : "d0", "d1", "d2", "d3", "memory", "cc"); 174 174 } 175 175 176 176 void ScaleRowDown34_0_Box_NEON(const uint8* src_ptr, 177 177 ptrdiff_t src_stride, 178 uint8* dst_ptr, int dst_width) { 179 asm volatile ( 180 "vmov.u8 d24, #3 \n" 181 "add %3, %0 \n" 182 "1: \n" 183 MEMACCESS(0) 184 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // src line 0 185 MEMACCESS(3) 186 "vld4.8 {d4, d5, d6, d7}, [%3]! \n" // src line 1 187 "subs %2, %2, #24 \n" 188 189 // filter src line 0 with src line 1 190 // expand chars to shorts to allow for room 191 // when adding lines together 192 "vmovl.u8 q8, d4 \n" 193 "vmovl.u8 q9, d5 \n" 194 "vmovl.u8 q10, d6 \n" 195 "vmovl.u8 q11, d7 \n" 196 197 // 3 * line_0 + line_1 198 "vmlal.u8 q8, d0, d24 \n" 199 "vmlal.u8 q9, d1, d24 \n" 200 "vmlal.u8 q10, d2, d24 \n" 201 "vmlal.u8 q11, d3, d24 \n" 202 203 // (3 * line_0 + line_1) >> 2 204 "vqrshrn.u16 d0, q8, #2 \n" 205 "vqrshrn.u16 d1, q9, #2 \n" 206 "vqrshrn.u16 d2, q10, #2 \n" 207 "vqrshrn.u16 d3, q11, #2 \n" 208 209 // a0 = (src[0] * 3 + s[1] * 1) >> 2 210 "vmovl.u8 q8, d1 \n" 211 "vmlal.u8 q8, d0, d24 \n" 212 "vqrshrn.u16 d0, q8, #2 \n" 213 214 // a1 = (src[1] * 1 + s[2] * 1) >> 1 215 "vrhadd.u8 d1, d1, d2 \n" 216 217 // a2 = (src[2] * 1 + s[3] * 3) >> 2 218 "vmovl.u8 q8, d2 \n" 219 "vmlal.u8 q8, d3, d24 \n" 220 "vqrshrn.u16 d2, q8, #2 \n" 221 222 MEMACCESS(1) 223 "vst3.8 {d0, d1, d2}, [%1]! \n" 224 225 "bgt 1b \n" 226 : "+r"(src_ptr), // %0 227 "+r"(dst_ptr), // %1 228 "+r"(dst_width), // %2 229 "+r"(src_stride) // %3 230 : 231 : "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11", "d24", "memory", "cc" 232 ); 178 uint8* dst_ptr, 179 int dst_width) { 180 asm volatile( 181 "vmov.u8 d24, #3 \n" 182 "add %3, %0 \n" 183 "1: \n" 184 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // src line 0 185 "vld4.8 {d4, d5, d6, d7}, [%3]! \n" // src line 1 186 "subs %2, %2, #24 \n" 187 188 // filter src line 0 with src line 1 189 // expand chars to shorts to allow for room 190 // when adding lines together 191 "vmovl.u8 q8, d4 \n" 192 "vmovl.u8 q9, d5 \n" 193 "vmovl.u8 q10, d6 \n" 194 "vmovl.u8 q11, d7 \n" 195 196 // 3 * line_0 + line_1 197 "vmlal.u8 q8, d0, d24 \n" 198 "vmlal.u8 q9, d1, d24 \n" 199 "vmlal.u8 q10, d2, d24 \n" 200 "vmlal.u8 q11, d3, d24 \n" 201 202 // (3 * line_0 + line_1) >> 2 203 "vqrshrn.u16 d0, q8, #2 \n" 204 "vqrshrn.u16 d1, q9, #2 \n" 205 "vqrshrn.u16 d2, q10, #2 \n" 206 "vqrshrn.u16 d3, q11, #2 \n" 207 208 // a0 = (src[0] * 3 + s[1] * 1) >> 2 209 "vmovl.u8 q8, d1 \n" 210 "vmlal.u8 q8, d0, d24 \n" 211 "vqrshrn.u16 d0, q8, #2 \n" 212 213 // a1 = (src[1] * 1 + s[2] * 1) >> 1 214 "vrhadd.u8 d1, d1, d2 \n" 215 216 // a2 = (src[2] * 1 + s[3] * 3) >> 2 217 "vmovl.u8 q8, d2 \n" 218 "vmlal.u8 q8, d3, d24 \n" 219 "vqrshrn.u16 d2, q8, #2 \n" 220 221 "vst3.8 {d0, d1, d2}, [%1]! \n" 222 223 "bgt 1b \n" 224 : "+r"(src_ptr), // %0 225 "+r"(dst_ptr), // %1 226 "+r"(dst_width), // %2 227 "+r"(src_stride) // %3 228 : 229 : "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11", "d24", "memory", 230 "cc"); 233 231 } 234 232 235 233 void ScaleRowDown34_1_Box_NEON(const uint8* src_ptr, 236 234 ptrdiff_t src_stride, 237 uint8* dst_ptr, int dst_width) { 238 asm volatile ( 239 "vmov.u8 d24, #3 \n" 240 "add %3, %0 \n" 241 "1: \n" 242 MEMACCESS(0) 243 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // src line 0 244 MEMACCESS(3) 245 "vld4.8 {d4, d5, d6, d7}, [%3]! \n" // src line 1 246 "subs %2, %2, #24 \n" 247 // average src line 0 with src line 1 248 "vrhadd.u8 q0, q0, q2 \n" 249 "vrhadd.u8 q1, q1, q3 \n" 250 251 // a0 = (src[0] * 3 + s[1] * 1) >> 2 252 "vmovl.u8 q3, d1 \n" 253 "vmlal.u8 q3, d0, d24 \n" 254 "vqrshrn.u16 d0, q3, #2 \n" 255 256 // a1 = (src[1] * 1 + s[2] * 1) >> 1 257 "vrhadd.u8 d1, d1, d2 \n" 258 259 // a2 = (src[2] * 1 + s[3] * 3) >> 2 260 "vmovl.u8 q3, d2 \n" 261 "vmlal.u8 q3, d3, d24 \n" 262 "vqrshrn.u16 d2, q3, #2 \n" 263 264 MEMACCESS(1) 265 "vst3.8 {d0, d1, d2}, [%1]! \n" 266 "bgt 1b \n" 267 : "+r"(src_ptr), // %0 268 "+r"(dst_ptr), // %1 269 "+r"(dst_width), // %2 270 "+r"(src_stride) // %3 271 : 272 : "r4", "q0", "q1", "q2", "q3", "d24", "memory", "cc" 273 ); 235 uint8* dst_ptr, 236 int dst_width) { 237 asm volatile( 238 "vmov.u8 d24, #3 \n" 239 "add %3, %0 \n" 240 "1: \n" 241 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // src line 0 242 "vld4.8 {d4, d5, d6, d7}, [%3]! \n" // src line 1 243 "subs %2, %2, #24 \n" 244 // average src line 0 with src line 1 245 "vrhadd.u8 q0, q0, q2 \n" 246 "vrhadd.u8 q1, q1, q3 \n" 247 248 // a0 = (src[0] * 3 + s[1] * 1) >> 2 249 "vmovl.u8 q3, d1 \n" 250 "vmlal.u8 q3, d0, d24 \n" 251 "vqrshrn.u16 d0, q3, #2 \n" 252 253 // a1 = (src[1] * 1 + s[2] * 1) >> 1 254 "vrhadd.u8 d1, d1, d2 \n" 255 256 // a2 = (src[2] * 1 + s[3] * 3) >> 2 257 "vmovl.u8 q3, d2 \n" 258 "vmlal.u8 q3, d3, d24 \n" 259 "vqrshrn.u16 d2, q3, #2 \n" 260 261 "vst3.8 {d0, d1, d2}, [%1]! \n" 262 "bgt 1b \n" 263 : "+r"(src_ptr), // %0 264 "+r"(dst_ptr), // %1 265 "+r"(dst_width), // %2 266 "+r"(src_stride) // %3 267 : 268 : "r4", "q0", "q1", "q2", "q3", "d24", "memory", "cc"); 274 269 } 275 270 276 271 #define HAS_SCALEROWDOWN38_NEON 277 static uvec8 kShuf38 = 278 { 0, 3, 6, 8, 11, 14, 16, 19, 22, 24, 27, 30, 0, 0, 0, 0 }; 279 static uvec8 kShuf38_2 = 280 { 0, 8, 16, 2, 10, 17, 4, 12, 18, 6, 14, 19, 0, 0, 0, 0 }; 281 static vec16 kMult38_Div6 = 282 { 65536 / 12, 65536 / 12, 65536 / 12, 65536 / 12, 283 65536 / 12, 65536 / 12, 65536 / 12, 65536 / 12 }; 284 static vec16 kMult38_Div9 = 285 { 65536 / 18, 65536 / 18, 65536 / 18, 65536 / 18, 286 65536 / 18, 65536 / 18, 65536 / 18, 65536 / 18 }; 272 static uvec8 kShuf38 = {0, 3, 6, 8, 11, 14, 16, 19, 22, 24, 27, 30, 0, 0, 0, 0}; 273 static uvec8 kShuf38_2 = {0, 8, 16, 2, 10, 17, 4, 12, 274 18, 6, 14, 19, 0, 0, 0, 0}; 275 static vec16 kMult38_Div6 = {65536 / 12, 65536 / 12, 65536 / 12, 65536 / 12, 276 65536 / 12, 65536 / 12, 65536 / 12, 65536 / 12}; 277 static vec16 kMult38_Div9 = {65536 / 18, 65536 / 18, 65536 / 18, 65536 / 18, 278 65536 / 18, 65536 / 18, 65536 / 18, 65536 / 18}; 287 279 288 280 // 32 -> 12 289 281 void ScaleRowDown38_NEON(const uint8* src_ptr, 290 282 ptrdiff_t src_stride, 291 uint8* dst_ptr, int dst_width) { 292 asm volatile ( 293 MEMACCESS(3) 294 "vld1.8 {q3}, [%3] \n" 295 "1: \n" 296 MEMACCESS(0) 297 "vld1.8 {d0, d1, d2, d3}, [%0]! \n" 298 "subs %2, %2, #12 \n" 299 "vtbl.u8 d4, {d0, d1, d2, d3}, d6 \n" 300 "vtbl.u8 d5, {d0, d1, d2, d3}, d7 \n" 301 MEMACCESS(1) 302 "vst1.8 {d4}, [%1]! \n" 303 MEMACCESS(1) 304 "vst1.32 {d5[0]}, [%1]! \n" 305 "bgt 1b \n" 306 : "+r"(src_ptr), // %0 307 "+r"(dst_ptr), // %1 308 "+r"(dst_width) // %2 309 : "r"(&kShuf38) // %3 310 : "d0", "d1", "d2", "d3", "d4", "d5", "memory", "cc" 311 ); 283 uint8* dst_ptr, 284 int dst_width) { 285 (void)src_stride; 286 asm volatile( 287 "vld1.8 {q3}, [%3] \n" 288 "1: \n" 289 "vld1.8 {d0, d1, d2, d3}, [%0]! \n" 290 "subs %2, %2, #12 \n" 291 "vtbl.u8 d4, {d0, d1, d2, d3}, d6 \n" 292 "vtbl.u8 d5, {d0, d1, d2, d3}, d7 \n" 293 "vst1.8 {d4}, [%1]! \n" 294 "vst1.32 {d5[0]}, [%1]! \n" 295 "bgt 1b \n" 296 : "+r"(src_ptr), // %0 297 "+r"(dst_ptr), // %1 298 "+r"(dst_width) // %2 299 : "r"(&kShuf38) // %3 300 : "d0", "d1", "d2", "d3", "d4", "d5", "memory", "cc"); 312 301 } 313 302 … … 315 304 void OMITFP ScaleRowDown38_3_Box_NEON(const uint8* src_ptr, 316 305 ptrdiff_t src_stride, 317 uint8* dst_ptr, int dst_width) { 306 uint8* dst_ptr, 307 int dst_width) { 318 308 const uint8* src_ptr1 = src_ptr + src_stride * 2; 319 309 320 asm volatile ( 321 MEMACCESS(5) 322 "vld1.16 {q13}, [%5] \n" 323 MEMACCESS(6) 324 "vld1.8 {q14}, [%6] \n" 325 MEMACCESS(7) 326 "vld1.8 {q15}, [%7] \n" 327 "add %3, %0 \n" 328 "1: \n" 329 330 // d0 = 00 40 01 41 02 42 03 43 331 // d1 = 10 50 11 51 12 52 13 53 332 // d2 = 20 60 21 61 22 62 23 63 333 // d3 = 30 70 31 71 32 72 33 73 334 MEMACCESS(0) 335 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" 336 MEMACCESS(3) 337 "vld4.8 {d4, d5, d6, d7}, [%3]! \n" 338 MEMACCESS(4) 339 "vld4.8 {d16, d17, d18, d19}, [%4]! \n" 340 "subs %2, %2, #12 \n" 341 342 // Shuffle the input data around to get align the data 343 // so adjacent data can be added. 0,1 - 2,3 - 4,5 - 6,7 344 // d0 = 00 10 01 11 02 12 03 13 345 // d1 = 40 50 41 51 42 52 43 53 346 "vtrn.u8 d0, d1 \n" 347 "vtrn.u8 d4, d5 \n" 348 "vtrn.u8 d16, d17 \n" 349 350 // d2 = 20 30 21 31 22 32 23 33 351 // d3 = 60 70 61 71 62 72 63 73 352 "vtrn.u8 d2, d3 \n" 353 "vtrn.u8 d6, d7 \n" 354 "vtrn.u8 d18, d19 \n" 355 356 // d0 = 00+10 01+11 02+12 03+13 357 // d2 = 40+50 41+51 42+52 43+53 358 "vpaddl.u8 q0, q0 \n" 359 "vpaddl.u8 q2, q2 \n" 360 "vpaddl.u8 q8, q8 \n" 361 362 // d3 = 60+70 61+71 62+72 63+73 363 "vpaddl.u8 d3, d3 \n" 364 "vpaddl.u8 d7, d7 \n" 365 "vpaddl.u8 d19, d19 \n" 366 367 // combine source lines 368 "vadd.u16 q0, q2 \n" 369 "vadd.u16 q0, q8 \n" 370 "vadd.u16 d4, d3, d7 \n" 371 "vadd.u16 d4, d19 \n" 372 373 // dst_ptr[3] = (s[6 + st * 0] + s[7 + st * 0] 374 // + s[6 + st * 1] + s[7 + st * 1] 375 // + s[6 + st * 2] + s[7 + st * 2]) / 6 376 "vqrdmulh.s16 q2, q2, q13 \n" 377 "vmovn.u16 d4, q2 \n" 378 379 // Shuffle 2,3 reg around so that 2 can be added to the 380 // 0,1 reg and 3 can be added to the 4,5 reg. This 381 // requires expanding from u8 to u16 as the 0,1 and 4,5 382 // registers are already expanded. Then do transposes 383 // to get aligned. 384 // q2 = xx 20 xx 30 xx 21 xx 31 xx 22 xx 32 xx 23 xx 33 385 "vmovl.u8 q1, d2 \n" 386 "vmovl.u8 q3, d6 \n" 387 "vmovl.u8 q9, d18 \n" 388 389 // combine source lines 390 "vadd.u16 q1, q3 \n" 391 "vadd.u16 q1, q9 \n" 392 393 // d4 = xx 20 xx 30 xx 22 xx 32 394 // d5 = xx 21 xx 31 xx 23 xx 33 395 "vtrn.u32 d2, d3 \n" 396 397 // d4 = xx 20 xx 21 xx 22 xx 23 398 // d5 = xx 30 xx 31 xx 32 xx 33 399 "vtrn.u16 d2, d3 \n" 400 401 // 0+1+2, 3+4+5 402 "vadd.u16 q0, q1 \n" 403 404 // Need to divide, but can't downshift as the the value 405 // isn't a power of 2. So multiply by 65536 / n 406 // and take the upper 16 bits. 407 "vqrdmulh.s16 q0, q0, q15 \n" 408 409 // Align for table lookup, vtbl requires registers to 410 // be adjacent 411 "vmov.u8 d2, d4 \n" 412 413 "vtbl.u8 d3, {d0, d1, d2}, d28 \n" 414 "vtbl.u8 d4, {d0, d1, d2}, d29 \n" 415 416 MEMACCESS(1) 417 "vst1.8 {d3}, [%1]! \n" 418 MEMACCESS(1) 419 "vst1.32 {d4[0]}, [%1]! \n" 420 "bgt 1b \n" 421 : "+r"(src_ptr), // %0 422 "+r"(dst_ptr), // %1 423 "+r"(dst_width), // %2 424 "+r"(src_stride), // %3 425 "+r"(src_ptr1) // %4 426 : "r"(&kMult38_Div6), // %5 427 "r"(&kShuf38_2), // %6 428 "r"(&kMult38_Div9) // %7 429 : "q0", "q1", "q2", "q3", "q8", "q9", "q13", "q14", "q15", "memory", "cc" 430 ); 310 asm volatile( 311 "vld1.16 {q13}, [%5] \n" 312 "vld1.8 {q14}, [%6] \n" 313 "vld1.8 {q15}, [%7] \n" 314 "add %3, %0 \n" 315 "1: \n" 316 317 // d0 = 00 40 01 41 02 42 03 43 318 // d1 = 10 50 11 51 12 52 13 53 319 // d2 = 20 60 21 61 22 62 23 63 320 // d3 = 30 70 31 71 32 72 33 73 321 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" 322 "vld4.8 {d4, d5, d6, d7}, [%3]! \n" 323 "vld4.8 {d16, d17, d18, d19}, [%4]! \n" 324 "subs %2, %2, #12 \n" 325 326 // Shuffle the input data around to get align the data 327 // so adjacent data can be added. 0,1 - 2,3 - 4,5 - 6,7 328 // d0 = 00 10 01 11 02 12 03 13 329 // d1 = 40 50 41 51 42 52 43 53 330 "vtrn.u8 d0, d1 \n" 331 "vtrn.u8 d4, d5 \n" 332 "vtrn.u8 d16, d17 \n" 333 334 // d2 = 20 30 21 31 22 32 23 33 335 // d3 = 60 70 61 71 62 72 63 73 336 "vtrn.u8 d2, d3 \n" 337 "vtrn.u8 d6, d7 \n" 338 "vtrn.u8 d18, d19 \n" 339 340 // d0 = 00+10 01+11 02+12 03+13 341 // d2 = 40+50 41+51 42+52 43+53 342 "vpaddl.u8 q0, q0 \n" 343 "vpaddl.u8 q2, q2 \n" 344 "vpaddl.u8 q8, q8 \n" 345 346 // d3 = 60+70 61+71 62+72 63+73 347 "vpaddl.u8 d3, d3 \n" 348 "vpaddl.u8 d7, d7 \n" 349 "vpaddl.u8 d19, d19 \n" 350 351 // combine source lines 352 "vadd.u16 q0, q2 \n" 353 "vadd.u16 q0, q8 \n" 354 "vadd.u16 d4, d3, d7 \n" 355 "vadd.u16 d4, d19 \n" 356 357 // dst_ptr[3] = (s[6 + st * 0] + s[7 + st * 0] 358 // + s[6 + st * 1] + s[7 + st * 1] 359 // + s[6 + st * 2] + s[7 + st * 2]) / 6 360 "vqrdmulh.s16 q2, q2, q13 \n" 361 "vmovn.u16 d4, q2 \n" 362 363 // Shuffle 2,3 reg around so that 2 can be added to the 364 // 0,1 reg and 3 can be added to the 4,5 reg. This 365 // requires expanding from u8 to u16 as the 0,1 and 4,5 366 // registers are already expanded. Then do transposes 367 // to get aligned. 368 // q2 = xx 20 xx 30 xx 21 xx 31 xx 22 xx 32 xx 23 xx 33 369 "vmovl.u8 q1, d2 \n" 370 "vmovl.u8 q3, d6 \n" 371 "vmovl.u8 q9, d18 \n" 372 373 // combine source lines 374 "vadd.u16 q1, q3 \n" 375 "vadd.u16 q1, q9 \n" 376 377 // d4 = xx 20 xx 30 xx 22 xx 32 378 // d5 = xx 21 xx 31 xx 23 xx 33 379 "vtrn.u32 d2, d3 \n" 380 381 // d4 = xx 20 xx 21 xx 22 xx 23 382 // d5 = xx 30 xx 31 xx 32 xx 33 383 "vtrn.u16 d2, d3 \n" 384 385 // 0+1+2, 3+4+5 386 "vadd.u16 q0, q1 \n" 387 388 // Need to divide, but can't downshift as the the value 389 // isn't a power of 2. So multiply by 65536 / n 390 // and take the upper 16 bits. 391 "vqrdmulh.s16 q0, q0, q15 \n" 392 393 // Align for table lookup, vtbl requires registers to 394 // be adjacent 395 "vmov.u8 d2, d4 \n" 396 397 "vtbl.u8 d3, {d0, d1, d2}, d28 \n" 398 "vtbl.u8 d4, {d0, d1, d2}, d29 \n" 399 400 "vst1.8 {d3}, [%1]! \n" 401 "vst1.32 {d4[0]}, [%1]! \n" 402 "bgt 1b \n" 403 : "+r"(src_ptr), // %0 404 "+r"(dst_ptr), // %1 405 "+r"(dst_width), // %2 406 "+r"(src_stride), // %3 407 "+r"(src_ptr1) // %4 408 : "r"(&kMult38_Div6), // %5 409 "r"(&kShuf38_2), // %6 410 "r"(&kMult38_Div9) // %7 411 : "q0", "q1", "q2", "q3", "q8", "q9", "q13", "q14", "q15", "memory", 412 "cc"); 431 413 } 432 414 … … 434 416 void ScaleRowDown38_2_Box_NEON(const uint8* src_ptr, 435 417 ptrdiff_t src_stride, 436 uint8* dst_ptr, int dst_width) { 437 asm volatile ( 438 MEMACCESS(4) 439 "vld1.16 {q13}, [%4] \n" 440 MEMACCESS(5) 441 "vld1.8 {q14}, [%5] \n" 442 "add %3, %0 \n" 443 "1: \n" 444 445 // d0 = 00 40 01 41 02 42 03 43 446 // d1 = 10 50 11 51 12 52 13 53 447 // d2 = 20 60 21 61 22 62 23 63 448 // d3 = 30 70 31 71 32 72 33 73 449 MEMACCESS(0) 450 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" 451 MEMACCESS(3) 452 "vld4.8 {d4, d5, d6, d7}, [%3]! \n" 453 "subs %2, %2, #12 \n" 454 455 // Shuffle the input data around to get align the data 456 // so adjacent data can be added. 0,1 - 2,3 - 4,5 - 6,7 457 // d0 = 00 10 01 11 02 12 03 13 458 // d1 = 40 50 41 51 42 52 43 53 459 "vtrn.u8 d0, d1 \n" 460 "vtrn.u8 d4, d5 \n" 461 462 // d2 = 20 30 21 31 22 32 23 33 463 // d3 = 60 70 61 71 62 72 63 73 464 "vtrn.u8 d2, d3 \n" 465 "vtrn.u8 d6, d7 \n" 466 467 // d0 = 00+10 01+11 02+12 03+13 468 // d2 = 40+50 41+51 42+52 43+53 469 "vpaddl.u8 q0, q0 \n" 470 "vpaddl.u8 q2, q2 \n" 471 472 // d3 = 60+70 61+71 62+72 63+73 473 "vpaddl.u8 d3, d3 \n" 474 "vpaddl.u8 d7, d7 \n" 475 476 // combine source lines 477 "vadd.u16 q0, q2 \n" 478 "vadd.u16 d4, d3, d7 \n" 479 480 // dst_ptr[3] = (s[6] + s[7] + s[6+st] + s[7+st]) / 4 481 "vqrshrn.u16 d4, q2, #2 \n" 482 483 // Shuffle 2,3 reg around so that 2 can be added to the 484 // 0,1 reg and 3 can be added to the 4,5 reg. This 485 // requires expanding from u8 to u16 as the 0,1 and 4,5 486 // registers are already expanded. Then do transposes 487 // to get aligned. 488 // q2 = xx 20 xx 30 xx 21 xx 31 xx 22 xx 32 xx 23 xx 33 489 "vmovl.u8 q1, d2 \n" 490 "vmovl.u8 q3, d6 \n" 491 492 // combine source lines 493 "vadd.u16 q1, q3 \n" 494 495 // d4 = xx 20 xx 30 xx 22 xx 32 496 // d5 = xx 21 xx 31 xx 23 xx 33 497 "vtrn.u32 d2, d3 \n" 498 499 // d4 = xx 20 xx 21 xx 22 xx 23 500 // d5 = xx 30 xx 31 xx 32 xx 33 501 "vtrn.u16 d2, d3 \n" 502 503 // 0+1+2, 3+4+5 504 "vadd.u16 q0, q1 \n" 505 506 // Need to divide, but can't downshift as the the value 507 // isn't a power of 2. So multiply by 65536 / n 508 // and take the upper 16 bits. 509 "vqrdmulh.s16 q0, q0, q13 \n" 510 511 // Align for table lookup, vtbl requires registers to 512 // be adjacent 513 "vmov.u8 d2, d4 \n" 514 515 "vtbl.u8 d3, {d0, d1, d2}, d28 \n" 516 "vtbl.u8 d4, {d0, d1, d2}, d29 \n" 517 518 MEMACCESS(1) 519 "vst1.8 {d3}, [%1]! \n" 520 MEMACCESS(1) 521 "vst1.32 {d4[0]}, [%1]! \n" 522 "bgt 1b \n" 523 : "+r"(src_ptr), // %0 524 "+r"(dst_ptr), // %1 525 "+r"(dst_width), // %2 526 "+r"(src_stride) // %3 527 : "r"(&kMult38_Div6), // %4 528 "r"(&kShuf38_2) // %5 529 : "q0", "q1", "q2", "q3", "q13", "q14", "memory", "cc" 530 ); 531 } 532 533 void ScaleAddRows_NEON(const uint8* src_ptr, ptrdiff_t src_stride, 534 uint16* dst_ptr, int src_width, int src_height) { 418 uint8* dst_ptr, 419 int dst_width) { 420 asm volatile( 421 "vld1.16 {q13}, [%4] \n" 422 "vld1.8 {q14}, [%5] \n" 423 "add %3, %0 \n" 424 "1: \n" 425 426 // d0 = 00 40 01 41 02 42 03 43 427 // d1 = 10 50 11 51 12 52 13 53 428 // d2 = 20 60 21 61 22 62 23 63 429 // d3 = 30 70 31 71 32 72 33 73 430 "vld4.8 {d0, d1, d2, d3}, [%0]! \n" 431 "vld4.8 {d4, d5, d6, d7}, [%3]! \n" 432 "subs %2, %2, #12 \n" 433 434 // Shuffle the input data around to get align the data 435 // so adjacent data can be added. 0,1 - 2,3 - 4,5 - 6,7 436 // d0 = 00 10 01 11 02 12 03 13 437 // d1 = 40 50 41 51 42 52 43 53 438 "vtrn.u8 d0, d1 \n" 439 "vtrn.u8 d4, d5 \n" 440 441 // d2 = 20 30 21 31 22 32 23 33 442 // d3 = 60 70 61 71 62 72 63 73 443 "vtrn.u8 d2, d3 \n" 444 "vtrn.u8 d6, d7 \n" 445 446 // d0 = 00+10 01+11 02+12 03+13 447 // d2 = 40+50 41+51 42+52 43+53 448 "vpaddl.u8 q0, q0 \n" 449 "vpaddl.u8 q2, q2 \n" 450 451 // d3 = 60+70 61+71 62+72 63+73 452 "vpaddl.u8 d3, d3 \n" 453 "vpaddl.u8 d7, d7 \n" 454 455 // combine source lines 456 "vadd.u16 q0, q2 \n" 457 "vadd.u16 d4, d3, d7 \n" 458 459 // dst_ptr[3] = (s[6] + s[7] + s[6+st] + s[7+st]) / 4 460 "vqrshrn.u16 d4, q2, #2 \n" 461 462 // Shuffle 2,3 reg around so that 2 can be added to the 463 // 0,1 reg and 3 can be added to the 4,5 reg. This 464 // requires expanding from u8 to u16 as the 0,1 and 4,5 465 // registers are already expanded. Then do transposes 466 // to get aligned. 467 // q2 = xx 20 xx 30 xx 21 xx 31 xx 22 xx 32 xx 23 xx 33 468 "vmovl.u8 q1, d2 \n" 469 "vmovl.u8 q3, d6 \n" 470 471 // combine source lines 472 "vadd.u16 q1, q3 \n" 473 474 // d4 = xx 20 xx 30 xx 22 xx 32 475 // d5 = xx 21 xx 31 xx 23 xx 33 476 "vtrn.u32 d2, d3 \n" 477 478 // d4 = xx 20 xx 21 xx 22 xx 23 479 // d5 = xx 30 xx 31 xx 32 xx 33 480 "vtrn.u16 d2, d3 \n" 481 482 // 0+1+2, 3+4+5 483 "vadd.u16 q0, q1 \n" 484 485 // Need to divide, but can't downshift as the the value 486 // isn't a power of 2. So multiply by 65536 / n 487 // and take the upper 16 bits. 488 "vqrdmulh.s16 q0, q0, q13 \n" 489 490 // Align for table lookup, vtbl requires registers to 491 // be adjacent 492 "vmov.u8 d2, d4 \n" 493 494 "vtbl.u8 d3, {d0, d1, d2}, d28 \n" 495 "vtbl.u8 d4, {d0, d1, d2}, d29 \n" 496 497 "vst1.8 {d3}, [%1]! \n" 498 "vst1.32 {d4[0]}, [%1]! \n" 499 "bgt 1b \n" 500 : "+r"(src_ptr), // %0 501 "+r"(dst_ptr), // %1 502 "+r"(dst_width), // %2 503 "+r"(src_stride) // %3 504 : "r"(&kMult38_Div6), // %4 505 "r"(&kShuf38_2) // %5 506 : "q0", "q1", "q2", "q3", "q13", "q14", "memory", "cc"); 507 } 508 509 void ScaleAddRows_NEON(const uint8* src_ptr, 510 ptrdiff_t src_stride, 511 uint16* dst_ptr, 512 int src_width, 513 int src_height) { 535 514 const uint8* src_tmp; 536 asm volatile ( 537 "1: \n" 538 "mov %0, %1 \n" 539 "mov r12, %5 \n" 540 "veor q2, q2, q2 \n" 541 "veor q3, q3, q3 \n" 542 "2: \n" 543 // load 16 pixels into q0 544 MEMACCESS(0) 545 "vld1.8 {q0}, [%0], %3 \n" 546 "vaddw.u8 q3, q3, d1 \n" 547 "vaddw.u8 q2, q2, d0 \n" 548 "subs r12, r12, #1 \n" 549 "bgt 2b \n" 550 MEMACCESS(2) 551 "vst1.16 {q2, q3}, [%2]! \n" // store pixels 552 "add %1, %1, #16 \n" 553 "subs %4, %4, #16 \n" // 16 processed per loop 554 "bgt 1b \n" 555 : "=&r"(src_tmp), // %0 556 "+r"(src_ptr), // %1 557 "+r"(dst_ptr), // %2 558 "+r"(src_stride), // %3 559 "+r"(src_width), // %4 560 "+r"(src_height) // %5 561 : 562 : "memory", "cc", "r12", "q0", "q1", "q2", "q3" // Clobber List 563 ); 564 } 565 515 asm volatile( 516 "1: \n" 517 "mov %0, %1 \n" 518 "mov r12, %5 \n" 519 "veor q2, q2, q2 \n" 520 "veor q3, q3, q3 \n" 521 "2: \n" 522 // load 16 pixels into q0 523 "vld1.8 {q0}, [%0], %3 \n" 524 "vaddw.u8 q3, q3, d1 \n" 525 "vaddw.u8 q2, q2, d0 \n" 526 "subs r12, r12, #1 \n" 527 "bgt 2b \n" 528 "vst1.16 {q2, q3}, [%2]! \n" // store pixels 529 "add %1, %1, #16 \n" 530 "subs %4, %4, #16 \n" // 16 processed per loop 531 "bgt 1b \n" 532 : "=&r"(src_tmp), // %0 533 "+r"(src_ptr), // %1 534 "+r"(dst_ptr), // %2 535 "+r"(src_stride), // %3 536 "+r"(src_width), // %4 537 "+r"(src_height) // %5 538 : 539 : "memory", "cc", "r12", "q0", "q1", "q2", "q3" // Clobber List 540 ); 541 } 542 543 // clang-format off 566 544 // TODO(Yang Zhang): Investigate less load instructions for 567 545 // the x/dx stepping … … 570 548 "add %6, %1, %5 \n" \ 571 549 "add %3, %3, %4 \n" \ 572 MEMACCESS(6) \573 550 "vld2.8 {d6["#n"], d7["#n"]}, [%6] \n" 574 575 void ScaleFilterCols_NEON(uint8* dst_ptr, const uint8* src_ptr, 576 int dst_width, int x, int dx) { 551 // clang-format on 552 553 // The NEON version mimics this formula (from row_common.cc): 554 // #define BLENDER(a, b, f) (uint8)((int)(a) + 555 // ((((int)((f)) * ((int)(b) - (int)(a))) + 0x8000) >> 16)) 556 557 void ScaleFilterCols_NEON(uint8* dst_ptr, 558 const uint8* src_ptr, 559 int dst_width, 560 int x, 561 int dx) { 577 562 int dx_offset[4] = {0, 1, 2, 3}; 578 563 int* tmp = dx_offset; … … 609 594 "vmul.s32 q11, q11, q13 \n" 610 595 "vmul.s32 q12, q12, q10 \n" 611 "v shrn.s32 d18, q11, #16\n"612 "v shrn.s32 d19, q12, #16\n"596 "vrshrn.s32 d18, q11, #16 \n" 597 "vrshrn.s32 d19, q12, #16 \n" 613 598 "vadd.s16 q8, q8, q9 \n" 614 599 "vmovn.s16 d6, q8 \n" 615 600 616 MEMACCESS(0)617 601 "vst1.8 {d6}, [%0]! \n" // store pixels 618 602 "vadd.s32 q1, q1, q0 \n" … … 637 621 // 16x2 -> 16x1 638 622 void ScaleFilterRows_NEON(uint8* dst_ptr, 639 const uint8* src_ptr, ptrdiff_t src_stride, 640 int dst_width, int source_y_fraction) { 641 asm volatile ( 642 "cmp %4, #0 \n" 643 "beq 100f \n" 644 "add %2, %1 \n" 645 "cmp %4, #64 \n" 646 "beq 75f \n" 647 "cmp %4, #128 \n" 648 "beq 50f \n" 649 "cmp %4, #192 \n" 650 "beq 25f \n" 651 652 "vdup.8 d5, %4 \n" 653 "rsb %4, #256 \n" 654 "vdup.8 d4, %4 \n" 655 // General purpose row blend. 656 "1: \n" 657 MEMACCESS(1) 658 "vld1.8 {q0}, [%1]! \n" 659 MEMACCESS(2) 660 "vld1.8 {q1}, [%2]! \n" 661 "subs %3, %3, #16 \n" 662 "vmull.u8 q13, d0, d4 \n" 663 "vmull.u8 q14, d1, d4 \n" 664 "vmlal.u8 q13, d2, d5 \n" 665 "vmlal.u8 q14, d3, d5 \n" 666 "vrshrn.u16 d0, q13, #8 \n" 667 "vrshrn.u16 d1, q14, #8 \n" 668 MEMACCESS(0) 669 "vst1.8 {q0}, [%0]! \n" 670 "bgt 1b \n" 671 "b 99f \n" 672 673 // Blend 25 / 75. 674 "25: \n" 675 MEMACCESS(1) 676 "vld1.8 {q0}, [%1]! \n" 677 MEMACCESS(2) 678 "vld1.8 {q1}, [%2]! \n" 679 "subs %3, %3, #16 \n" 680 "vrhadd.u8 q0, q1 \n" 681 "vrhadd.u8 q0, q1 \n" 682 MEMACCESS(0) 683 "vst1.8 {q0}, [%0]! \n" 684 "bgt 25b \n" 685 "b 99f \n" 686 687 // Blend 50 / 50. 688 "50: \n" 689 MEMACCESS(1) 690 "vld1.8 {q0}, [%1]! \n" 691 MEMACCESS(2) 692 "vld1.8 {q1}, [%2]! \n" 693 "subs %3, %3, #16 \n" 694 "vrhadd.u8 q0, q1 \n" 695 MEMACCESS(0) 696 "vst1.8 {q0}, [%0]! \n" 697 "bgt 50b \n" 698 "b 99f \n" 699 700 // Blend 75 / 25. 701 "75: \n" 702 MEMACCESS(1) 703 "vld1.8 {q1}, [%1]! \n" 704 MEMACCESS(2) 705 "vld1.8 {q0}, [%2]! \n" 706 "subs %3, %3, #16 \n" 707 "vrhadd.u8 q0, q1 \n" 708 "vrhadd.u8 q0, q1 \n" 709 MEMACCESS(0) 710 "vst1.8 {q0}, [%0]! \n" 711 "bgt 75b \n" 712 "b 99f \n" 713 714 // Blend 100 / 0 - Copy row unchanged. 715 "100: \n" 716 MEMACCESS(1) 717 "vld1.8 {q0}, [%1]! \n" 718 "subs %3, %3, #16 \n" 719 MEMACCESS(0) 720 "vst1.8 {q0}, [%0]! \n" 721 "bgt 100b \n" 722 723 "99: \n" 724 MEMACCESS(0) 725 "vst1.8 {d1[7]}, [%0] \n" 726 : "+r"(dst_ptr), // %0 727 "+r"(src_ptr), // %1 728 "+r"(src_stride), // %2 729 "+r"(dst_width), // %3 730 "+r"(source_y_fraction) // %4 731 : 732 : "q0", "q1", "d4", "d5", "q13", "q14", "memory", "cc" 733 ); 734 } 735 736 void ScaleARGBRowDown2_NEON(const uint8* src_ptr, ptrdiff_t src_stride, 737 uint8* dst, int dst_width) { 738 asm volatile ( 739 "1: \n" 740 // load even pixels into q0, odd into q1 741 MEMACCESS(0) 742 "vld2.32 {q0, q1}, [%0]! \n" 743 MEMACCESS(0) 744 "vld2.32 {q2, q3}, [%0]! \n" 745 "subs %2, %2, #8 \n" // 8 processed per loop 746 MEMACCESS(1) 747 "vst1.8 {q1}, [%1]! \n" // store odd pixels 748 MEMACCESS(1) 749 "vst1.8 {q3}, [%1]! \n" 750 "bgt 1b \n" 751 : "+r"(src_ptr), // %0 752 "+r"(dst), // %1 753 "+r"(dst_width) // %2 754 : 755 : "memory", "cc", "q0", "q1", "q2", "q3" // Clobber List 756 ); 757 } 758 759 void ScaleARGBRowDown2Linear_NEON(const uint8* src_argb, ptrdiff_t src_stride, 760 uint8* dst_argb, int dst_width) { 761 asm volatile ( 762 "1: \n" 763 MEMACCESS(0) 764 "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ARGB pixels. 765 MEMACCESS(0) 766 "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 ARGB pixels. 767 "subs %2, %2, #8 \n" // 8 processed per loop 768 "vpaddl.u8 q0, q0 \n" // B 16 bytes -> 8 shorts. 769 "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts. 770 "vpaddl.u8 q2, q2 \n" // R 16 bytes -> 8 shorts. 771 "vpaddl.u8 q3, q3 \n" // A 16 bytes -> 8 shorts. 772 "vrshrn.u16 d0, q0, #1 \n" // downshift, round and pack 773 "vrshrn.u16 d1, q1, #1 \n" 774 "vrshrn.u16 d2, q2, #1 \n" 775 "vrshrn.u16 d3, q3, #1 \n" 776 MEMACCESS(1) 777 "vst4.8 {d0, d1, d2, d3}, [%1]! \n" 778 "bgt 1b \n" 779 : "+r"(src_argb), // %0 780 "+r"(dst_argb), // %1 781 "+r"(dst_width) // %2 782 : 783 : "memory", "cc", "q0", "q1", "q2", "q3" // Clobber List 784 ); 785 } 786 787 void ScaleARGBRowDown2Box_NEON(const uint8* src_ptr, ptrdiff_t src_stride, 788 uint8* dst, int dst_width) { 789 asm volatile ( 790 // change the stride to row 2 pointer 791 "add %1, %1, %0 \n" 792 "1: \n" 793 MEMACCESS(0) 794 "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ARGB pixels. 795 MEMACCESS(0) 796 "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 ARGB pixels. 797 "subs %3, %3, #8 \n" // 8 processed per loop. 798 "vpaddl.u8 q0, q0 \n" // B 16 bytes -> 8 shorts. 799 "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts. 800 "vpaddl.u8 q2, q2 \n" // R 16 bytes -> 8 shorts. 801 "vpaddl.u8 q3, q3 \n" // A 16 bytes -> 8 shorts. 802 MEMACCESS(1) 803 "vld4.8 {d16, d18, d20, d22}, [%1]! \n" // load 8 more ARGB pixels. 804 MEMACCESS(1) 805 "vld4.8 {d17, d19, d21, d23}, [%1]! \n" // load last 8 ARGB pixels. 806 "vpadal.u8 q0, q8 \n" // B 16 bytes -> 8 shorts. 807 "vpadal.u8 q1, q9 \n" // G 16 bytes -> 8 shorts. 808 "vpadal.u8 q2, q10 \n" // R 16 bytes -> 8 shorts. 809 "vpadal.u8 q3, q11 \n" // A 16 bytes -> 8 shorts. 810 "vrshrn.u16 d0, q0, #2 \n" // downshift, round and pack 811 "vrshrn.u16 d1, q1, #2 \n" 812 "vrshrn.u16 d2, q2, #2 \n" 813 "vrshrn.u16 d3, q3, #2 \n" 814 MEMACCESS(2) 815 "vst4.8 {d0, d1, d2, d3}, [%2]! \n" 816 "bgt 1b \n" 817 : "+r"(src_ptr), // %0 818 "+r"(src_stride), // %1 819 "+r"(dst), // %2 820 "+r"(dst_width) // %3 821 : 822 : "memory", "cc", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11" 823 ); 623 const uint8* src_ptr, 624 ptrdiff_t src_stride, 625 int dst_width, 626 int source_y_fraction) { 627 asm volatile( 628 "cmp %4, #0 \n" 629 "beq 100f \n" 630 "add %2, %1 \n" 631 "cmp %4, #64 \n" 632 "beq 75f \n" 633 "cmp %4, #128 \n" 634 "beq 50f \n" 635 "cmp %4, #192 \n" 636 "beq 25f \n" 637 638 "vdup.8 d5, %4 \n" 639 "rsb %4, #256 \n" 640 "vdup.8 d4, %4 \n" 641 // General purpose row blend. 642 "1: \n" 643 "vld1.8 {q0}, [%1]! \n" 644 "vld1.8 {q1}, [%2]! \n" 645 "subs %3, %3, #16 \n" 646 "vmull.u8 q13, d0, d4 \n" 647 "vmull.u8 q14, d1, d4 \n" 648 "vmlal.u8 q13, d2, d5 \n" 649 "vmlal.u8 q14, d3, d5 \n" 650 "vrshrn.u16 d0, q13, #8 \n" 651 "vrshrn.u16 d1, q14, #8 \n" 652 "vst1.8 {q0}, [%0]! \n" 653 "bgt 1b \n" 654 "b 99f \n" 655 656 // Blend 25 / 75. 657 "25: \n" 658 "vld1.8 {q0}, [%1]! \n" 659 "vld1.8 {q1}, [%2]! \n" 660 "subs %3, %3, #16 \n" 661 "vrhadd.u8 q0, q1 \n" 662 "vrhadd.u8 q0, q1 \n" 663 "vst1.8 {q0}, [%0]! \n" 664 "bgt 25b \n" 665 "b 99f \n" 666 667 // Blend 50 / 50. 668 "50: \n" 669 "vld1.8 {q0}, [%1]! \n" 670 "vld1.8 {q1}, [%2]! \n" 671 "subs %3, %3, #16 \n" 672 "vrhadd.u8 q0, q1 \n" 673 "vst1.8 {q0}, [%0]! \n" 674 "bgt 50b \n" 675 "b 99f \n" 676 677 // Blend 75 / 25. 678 "75: \n" 679 "vld1.8 {q1}, [%1]! \n" 680 "vld1.8 {q0}, [%2]! \n" 681 "subs %3, %3, #16 \n" 682 "vrhadd.u8 q0, q1 \n" 683 "vrhadd.u8 q0, q1 \n" 684 "vst1.8 {q0}, [%0]! \n" 685 "bgt 75b \n" 686 "b 99f \n" 687 688 // Blend 100 / 0 - Copy row unchanged. 689 "100: \n" 690 "vld1.8 {q0}, [%1]! \n" 691 "subs %3, %3, #16 \n" 692 "vst1.8 {q0}, [%0]! \n" 693 "bgt 100b \n" 694 695 "99: \n" 696 "vst1.8 {d1[7]}, [%0] \n" 697 : "+r"(dst_ptr), // %0 698 "+r"(src_ptr), // %1 699 "+r"(src_stride), // %2 700 "+r"(dst_width), // %3 701 "+r"(source_y_fraction) // %4 702 : 703 : "q0", "q1", "d4", "d5", "q13", "q14", "memory", "cc"); 704 } 705 706 void ScaleARGBRowDown2_NEON(const uint8* src_ptr, 707 ptrdiff_t src_stride, 708 uint8* dst, 709 int dst_width) { 710 (void)src_stride; 711 asm volatile( 712 "1: \n" 713 // load even pixels into q0, odd into q1 714 "vld2.32 {q0, q1}, [%0]! \n" 715 "vld2.32 {q2, q3}, [%0]! \n" 716 "subs %2, %2, #8 \n" // 8 processed per loop 717 "vst1.8 {q1}, [%1]! \n" // store odd pixels 718 "vst1.8 {q3}, [%1]! \n" 719 "bgt 1b \n" 720 : "+r"(src_ptr), // %0 721 "+r"(dst), // %1 722 "+r"(dst_width) // %2 723 : 724 : "memory", "cc", "q0", "q1", "q2", "q3" // Clobber List 725 ); 726 } 727 728 void ScaleARGBRowDown2Linear_NEON(const uint8* src_argb, 729 ptrdiff_t src_stride, 730 uint8* dst_argb, 731 int dst_width) { 732 (void)src_stride; 733 asm volatile( 734 "1: \n" 735 "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ARGB pixels. 736 "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 ARGB 737 // pixels. 738 "subs %2, %2, #8 \n" // 8 processed per loop 739 "vpaddl.u8 q0, q0 \n" // B 16 bytes -> 8 shorts. 740 "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts. 741 "vpaddl.u8 q2, q2 \n" // R 16 bytes -> 8 shorts. 742 "vpaddl.u8 q3, q3 \n" // A 16 bytes -> 8 shorts. 743 "vrshrn.u16 d0, q0, #1 \n" // downshift, round and 744 // pack 745 "vrshrn.u16 d1, q1, #1 \n" 746 "vrshrn.u16 d2, q2, #1 \n" 747 "vrshrn.u16 d3, q3, #1 \n" 748 "vst4.8 {d0, d1, d2, d3}, [%1]! \n" 749 "bgt 1b \n" 750 : "+r"(src_argb), // %0 751 "+r"(dst_argb), // %1 752 "+r"(dst_width) // %2 753 : 754 : "memory", "cc", "q0", "q1", "q2", "q3" // Clobber List 755 ); 756 } 757 758 void ScaleARGBRowDown2Box_NEON(const uint8* src_ptr, 759 ptrdiff_t src_stride, 760 uint8* dst, 761 int dst_width) { 762 asm volatile( 763 // change the stride to row 2 pointer 764 "add %1, %1, %0 \n" 765 "1: \n" 766 "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ARGB pixels. 767 "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 ARGB 768 // pixels. 769 "subs %3, %3, #8 \n" // 8 processed per loop. 770 "vpaddl.u8 q0, q0 \n" // B 16 bytes -> 8 shorts. 771 "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts. 772 "vpaddl.u8 q2, q2 \n" // R 16 bytes -> 8 shorts. 773 "vpaddl.u8 q3, q3 \n" // A 16 bytes -> 8 shorts. 774 "vld4.8 {d16, d18, d20, d22}, [%1]! \n" // load 8 more ARGB 775 // pixels. 776 "vld4.8 {d17, d19, d21, d23}, [%1]! \n" // load last 8 ARGB 777 // pixels. 778 "vpadal.u8 q0, q8 \n" // B 16 bytes -> 8 shorts. 779 "vpadal.u8 q1, q9 \n" // G 16 bytes -> 8 shorts. 780 "vpadal.u8 q2, q10 \n" // R 16 bytes -> 8 shorts. 781 "vpadal.u8 q3, q11 \n" // A 16 bytes -> 8 shorts. 782 "vrshrn.u16 d0, q0, #2 \n" // downshift, round and 783 // pack 784 "vrshrn.u16 d1, q1, #2 \n" 785 "vrshrn.u16 d2, q2, #2 \n" 786 "vrshrn.u16 d3, q3, #2 \n" 787 "vst4.8 {d0, d1, d2, d3}, [%2]! \n" 788 "bgt 1b \n" 789 : "+r"(src_ptr), // %0 790 "+r"(src_stride), // %1 791 "+r"(dst), // %2 792 "+r"(dst_width) // %3 793 : 794 : "memory", "cc", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11"); 824 795 } 825 796 826 797 // Reads 4 pixels at a time. 827 798 // Alignment requirement: src_argb 4 byte aligned. 828 void ScaleARGBRowDownEven_NEON(const uint8* src_argb, ptrdiff_t src_stride, 829 int src_stepx, uint8* dst_argb, int dst_width) { 830 asm volatile ( 831 "mov r12, %3, lsl #2 \n" 832 "1: \n" 833 MEMACCESS(0) 834 "vld1.32 {d0[0]}, [%0], r12 \n" 835 MEMACCESS(0) 836 "vld1.32 {d0[1]}, [%0], r12 \n" 837 MEMACCESS(0) 838 "vld1.32 {d1[0]}, [%0], r12 \n" 839 MEMACCESS(0) 840 "vld1.32 {d1[1]}, [%0], r12 \n" 841 "subs %2, %2, #4 \n" // 4 pixels per loop. 842 MEMACCESS(1) 843 "vst1.8 {q0}, [%1]! \n" 844 "bgt 1b \n" 845 : "+r"(src_argb), // %0 846 "+r"(dst_argb), // %1 847 "+r"(dst_width) // %2 848 : "r"(src_stepx) // %3 849 : "memory", "cc", "r12", "q0" 850 ); 799 void ScaleARGBRowDownEven_NEON(const uint8* src_argb, 800 ptrdiff_t src_stride, 801 int src_stepx, 802 uint8* dst_argb, 803 int dst_width) { 804 (void)src_stride; 805 asm volatile( 806 "mov r12, %3, lsl #2 \n" 807 "1: \n" 808 "vld1.32 {d0[0]}, [%0], r12 \n" 809 "vld1.32 {d0[1]}, [%0], r12 \n" 810 "vld1.32 {d1[0]}, [%0], r12 \n" 811 "vld1.32 {d1[1]}, [%0], r12 \n" 812 "subs %2, %2, #4 \n" // 4 pixels per loop. 813 "vst1.8 {q0}, [%1]! \n" 814 "bgt 1b \n" 815 : "+r"(src_argb), // %0 816 "+r"(dst_argb), // %1 817 "+r"(dst_width) // %2 818 : "r"(src_stepx) // %3 819 : "memory", "cc", "r12", "q0"); 851 820 } 852 821 853 822 // Reads 4 pixels at a time. 854 823 // Alignment requirement: src_argb 4 byte aligned. 855 void ScaleARGBRowDownEvenBox_NEON(const uint8* src_argb, ptrdiff_t src_stride, 824 void ScaleARGBRowDownEvenBox_NEON(const uint8* src_argb, 825 ptrdiff_t src_stride, 856 826 int src_stepx, 857 uint8* dst_argb, int dst_width) { 858 asm volatile ( 859 "mov r12, %4, lsl #2 \n" 860 "add %1, %1, %0 \n" 861 "1: \n" 862 MEMACCESS(0) 863 "vld1.8 {d0}, [%0], r12 \n" // Read 4 2x2 blocks -> 2x1 864 MEMACCESS(1) 865 "vld1.8 {d1}, [%1], r12 \n" 866 MEMACCESS(0) 867 "vld1.8 {d2}, [%0], r12 \n" 868 MEMACCESS(1) 869 "vld1.8 {d3}, [%1], r12 \n" 870 MEMACCESS(0) 871 "vld1.8 {d4}, [%0], r12 \n" 872 MEMACCESS(1) 873 "vld1.8 {d5}, [%1], r12 \n" 874 MEMACCESS(0) 875 "vld1.8 {d6}, [%0], r12 \n" 876 MEMACCESS(1) 877 "vld1.8 {d7}, [%1], r12 \n" 878 "vaddl.u8 q0, d0, d1 \n" 879 "vaddl.u8 q1, d2, d3 \n" 880 "vaddl.u8 q2, d4, d5 \n" 881 "vaddl.u8 q3, d6, d7 \n" 882 "vswp.8 d1, d2 \n" // ab_cd -> ac_bd 883 "vswp.8 d5, d6 \n" // ef_gh -> eg_fh 884 "vadd.u16 q0, q0, q1 \n" // (a+b)_(c+d) 885 "vadd.u16 q2, q2, q3 \n" // (e+f)_(g+h) 886 "vrshrn.u16 d0, q0, #2 \n" // first 2 pixels. 887 "vrshrn.u16 d1, q2, #2 \n" // next 2 pixels. 888 "subs %3, %3, #4 \n" // 4 pixels per loop. 889 MEMACCESS(2) 890 "vst1.8 {q0}, [%2]! \n" 891 "bgt 1b \n" 892 : "+r"(src_argb), // %0 893 "+r"(src_stride), // %1 894 "+r"(dst_argb), // %2 895 "+r"(dst_width) // %3 896 : "r"(src_stepx) // %4 897 : "memory", "cc", "r12", "q0", "q1", "q2", "q3" 898 ); 899 } 900 827 uint8* dst_argb, 828 int dst_width) { 829 asm volatile( 830 "mov r12, %4, lsl #2 \n" 831 "add %1, %1, %0 \n" 832 "1: \n" 833 "vld1.8 {d0}, [%0], r12 \n" // Read 4 2x2 blocks -> 834 // 2x1 835 "vld1.8 {d1}, [%1], r12 \n" 836 "vld1.8 {d2}, [%0], r12 \n" 837 "vld1.8 {d3}, [%1], r12 \n" 838 "vld1.8 {d4}, [%0], r12 \n" 839 "vld1.8 {d5}, [%1], r12 \n" 840 "vld1.8 {d6}, [%0], r12 \n" 841 "vld1.8 {d7}, [%1], r12 \n" 842 "vaddl.u8 q0, d0, d1 \n" 843 "vaddl.u8 q1, d2, d3 \n" 844 "vaddl.u8 q2, d4, d5 \n" 845 "vaddl.u8 q3, d6, d7 \n" 846 "vswp.8 d1, d2 \n" // ab_cd -> ac_bd 847 "vswp.8 d5, d6 \n" // ef_gh -> eg_fh 848 "vadd.u16 q0, q0, q1 \n" // (a+b)_(c+d) 849 "vadd.u16 q2, q2, q3 \n" // (e+f)_(g+h) 850 "vrshrn.u16 d0, q0, #2 \n" // first 2 pixels. 851 "vrshrn.u16 d1, q2, #2 \n" // next 2 pixels. 852 "subs %3, %3, #4 \n" // 4 pixels per loop. 853 "vst1.8 {q0}, [%2]! \n" 854 "bgt 1b \n" 855 : "+r"(src_argb), // %0 856 "+r"(src_stride), // %1 857 "+r"(dst_argb), // %2 858 "+r"(dst_width) // %3 859 : "r"(src_stepx) // %4 860 : "memory", "cc", "r12", "q0", "q1", "q2", "q3"); 861 } 862 863 // clang-format off 901 864 // TODO(Yang Zhang): Investigate less load instructions for 902 865 // the x/dx stepping 903 #define LOAD1_DATA32_LANE(dn, n) \ 904 "lsr %5, %3, #16 \n" \ 905 "add %6, %1, %5, lsl #2 \n" \ 906 "add %3, %3, %4 \n" \ 907 MEMACCESS(6) \ 908 "vld1.32 {"#dn"["#n"]}, [%6] \n" 909 910 void ScaleARGBCols_NEON(uint8* dst_argb, const uint8* src_argb, 911 int dst_width, int x, int dx) { 866 #define LOAD1_DATA32_LANE(dn, n) \ 867 "lsr %5, %3, #16 \n" \ 868 "add %6, %1, %5, lsl #2 \n" \ 869 "add %3, %3, %4 \n" \ 870 "vld1.32 {" #dn "[" #n "]}, [%6] \n" 871 // clang-format on 872 873 void ScaleARGBCols_NEON(uint8* dst_argb, 874 const uint8* src_argb, 875 int dst_width, 876 int x, 877 int dx) { 912 878 int tmp; 913 879 const uint8* src_tmp = src_argb; 914 asm volatile ( 915 "1: \n" 916 LOAD1_DATA32_LANE(d0, 0) 917 LOAD1_DATA32_LANE(d0, 1) 918 LOAD1_DATA32_LANE(d1, 0) 919 LOAD1_DATA32_LANE(d1, 1) 920 LOAD1_DATA32_LANE(d2, 0) 921 LOAD1_DATA32_LANE(d2, 1) 922 LOAD1_DATA32_LANE(d3, 0) 923 LOAD1_DATA32_LANE(d3, 1) 924 925 MEMACCESS(0) 926 "vst1.32 {q0, q1}, [%0]! \n" // store pixels 927 "subs %2, %2, #8 \n" // 8 processed per loop 928 "bgt 1b \n" 929 : "+r"(dst_argb), // %0 930 "+r"(src_argb), // %1 931 "+r"(dst_width), // %2 932 "+r"(x), // %3 933 "+r"(dx), // %4 934 "=&r"(tmp), // %5 935 "+r"(src_tmp) // %6 936 : 937 : "memory", "cc", "q0", "q1" 938 ); 880 asm volatile( 881 "1: \n" LOAD1_DATA32_LANE( 882 d0, 0) LOAD1_DATA32_LANE(d0, 1) LOAD1_DATA32_LANE(d1, 0) 883 LOAD1_DATA32_LANE(d1, 1) LOAD1_DATA32_LANE(d2, 0) LOAD1_DATA32_LANE( 884 d2, 1) LOAD1_DATA32_LANE(d3, 0) LOAD1_DATA32_LANE(d3, 1) 885 886 "vst1.32 {q0, q1}, [%0]! \n" // store pixels 887 "subs %2, %2, #8 \n" // 8 processed per 888 // loop 889 "bgt 1b \n" 890 : "+r"(dst_argb), // %0 891 "+r"(src_argb), // %1 892 "+r"(dst_width), // %2 893 "+r"(x), // %3 894 "+r"(dx), // %4 895 "=&r"(tmp), // %5 896 "+r"(src_tmp) // %6 897 : 898 : "memory", "cc", "q0", "q1"); 939 899 } 940 900 941 901 #undef LOAD1_DATA32_LANE 942 902 903 // clang-format off 943 904 // TODO(Yang Zhang): Investigate less load instructions for 944 905 // the x/dx stepping 945 #define LOAD2_DATA32_LANE(dn1, dn2, n) \ 946 "lsr %5, %3, #16 \n" \ 947 "add %6, %1, %5, lsl #2 \n" \ 948 "add %3, %3, %4 \n" \ 949 MEMACCESS(6) \ 950 "vld2.32 {"#dn1"["#n"], "#dn2"["#n"]}, [%6] \n" 951 952 void ScaleARGBFilterCols_NEON(uint8* dst_argb, const uint8* src_argb, 953 int dst_width, int x, int dx) { 906 #define LOAD2_DATA32_LANE(dn1, dn2, n) \ 907 "lsr %5, %3, #16 \n" \ 908 "add %6, %1, %5, lsl #2 \n" \ 909 "add %3, %3, %4 \n" \ 910 "vld2.32 {" #dn1 "[" #n "], " #dn2 "[" #n "]}, [%6] \n" 911 // clang-format on 912 913 void ScaleARGBFilterCols_NEON(uint8* dst_argb, 914 const uint8* src_argb, 915 int dst_width, 916 int x, 917 int dx) { 954 918 int dx_offset[4] = {0, 1, 2, 3}; 955 919 int* tmp = dx_offset; … … 990 954 "vshrn.i16 d1, q12, #7 \n" 991 955 992 MEMACCESS(0)993 956 "vst1.32 {d0, d1}, [%0]! \n" // store pixels 994 957 "vadd.s32 q8, q8, q9 \n"
Note: See TracChangeset
for help on using the changeset viewer.