1/* 2 * Copyright (C) 2013-2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define ENTRY(f) .text; .align 4; .globl f; .type f,#function; f: .fnstart 18#define END(f) .fnend; .size f, .-f; 19 20#define BLEND_LIST(X) \ 21 X(0, CLEAR) \ 22 X(1, SRC) \ 23 X(2, DST) \ 24 X(3, SRC_OVER) \ 25 X(4, DST_OVER) \ 26 X(5, SRC_IN) \ 27 X(6, DST_IN) \ 28 X(7, SRC_OUT) \ 29 X(8, DST_OUT) \ 30 X(9, SRC_ATOP) \ 31 X(10, DST_ATOP) \ 32 X(11, XOR) \ 33 X(14, MULTIPLY) \ 34 X(21, DIFFERENCE) \ 35 X(34, ADD) \ 36 X(35, SUBTRACT) 37 38.eabi_attribute 25,1 @Tag_ABI_align8_preserved 39.arm 40 41/* For every blend operation supported, define a macro with just the arithmetic 42 * component. The rest can be handled later on. 43 * 44 * At entry q0-q3 contain the RGBA data from the destination buffer, and q8-q11 45 * contain the data from the source buffer. Both have already been split out 46 * into one colour component per register (if necessary). q3 and q11 contain 47 * the alpha components. 48 * 49 * At the same time as defining the assembly macro, define a corresponding 50 * preprocessor macro indicating any other requirements. 51 * zipped=0 -- The macro does not require the RGBA components to be 52 * separated. 53 * lddst=0 -- The macro does not require data from the destination buffer. 54 * ldsrc=0 -- The macro does not require data from the source buffer. 55 * nowrap=1 -- The macro requires no wrapper at all, and should simply be 56 * inserted without any surrounding load/store or loop code. 57 */ 58 59#define params_CLEAR zipped=0, lddst=0, ldsrc=0 60.macro blend_kernel_CLEAR 61 vmov.i8 q0, #0 62 vmov.i8 q1, #0 63 vmov.i8 q2, #0 64 vmov.i8 q3, #0 65.endm 66 67#define params_SRC zipped=0, lddst=0 68.macro blend_kernel_SRC 69 vmov q0, q8 70 vmov q1, q9 71 vmov q2, q10 72 vmov q3, q11 73.endm 74 75#define params_DST nowrap=1 76.macro blend_kernel_DST 77 /* nop */ 78.endm 79 80#define params_SRC_OVER zipped=1 81.macro blend_kernel_SRC_OVER 82 vmvn q7, q11 83 84 vmull.u8 q12, d15, d1 85 vmull.u8 q0, d14, d0 86 vmull.u8 q13, d15, d3 87 vmull.u8 q1, d14, d2 88 vmull.u8 q14, d15, d5 89 vmull.u8 q2, d14, d4 90 vmull.u8 q15, d15, d7 91 vmull.u8 q3, d14, d6 92 93 vrshrn.u16 d8, q0, #8 94 vrshrn.u16 d9, q12, #8 95 vrshrn.u16 d10, q1, #8 96 vrshrn.u16 d11, q13, #8 97 vrshrn.u16 d12, q2, #8 98 vrshrn.u16 d13, q14, #8 99 vrshrn.u16 d14, q3, #8 100 vrshrn.u16 d15, q15, #8 101 102 vaddw.u8 q0, d8 103 vaddw.u8 q12, d9 104 vaddw.u8 q1, d10 105 vaddw.u8 q13, d11 106 vaddw.u8 q2, d12 107 vaddw.u8 q14, d13 108 vaddw.u8 q3, d14 109 vaddw.u8 q15, d15 110 111 vrshrn.u16 d0, q0, #8 112 vrshrn.u16 d1, q12, #8 113 vrshrn.u16 d2, q1, #8 114 vrshrn.u16 d3, q13, #8 115 vrshrn.u16 d4, q2, #8 116 vrshrn.u16 d5, q14, #8 117 vrshrn.u16 d6, q3, #8 118 vrshrn.u16 d7, q15, #8 119 120 vqadd.u8 q0, q8 121 vqadd.u8 q1, q9 122 vqadd.u8 q2, q10 123 vqadd.u8 q3, q11 124.endm 125 126#define params_DST_OVER zipped=1 127.macro blend_kernel_DST_OVER 128 vmvn q7, q3 129 130 vmull.u8 q12, d15, d17 131 vmull.u8 q8, d14, d16 132 vmull.u8 q13, d15, d19 133 vmull.u8 q9, d14, d18 134 vmull.u8 q14, d15, d21 135 vmull.u8 q10, d14, d20 136 vmull.u8 q15, d15, d23 137 vmull.u8 q11, d14, d22 138 139 vrshrn.u16 d8, q0, #8 140 vrshrn.u16 d9, q12, #8 141 vrshrn.u16 d10, q1, #8 142 vrshrn.u16 d11, q13, #8 143 vrshrn.u16 d12, q2, #8 144 vrshrn.u16 d13, q14, #8 145 vrshrn.u16 d14, q3, #8 146 vrshrn.u16 d15, q15, #8 147 148 vaddw.u8 q8, d8 149 vaddw.u8 q12, d9 150 vaddw.u8 q9, d10 151 vaddw.u8 q13, d11 152 vaddw.u8 q10, d12 153 vaddw.u8 q14, d13 154 vaddw.u8 q11, d14 155 vaddw.u8 q15, d15 156 157 vrshrn.u16 d16, q8, #8 158 vrshrn.u16 d17, q12, #8 159 vrshrn.u16 d18, q9, #8 160 vrshrn.u16 d19, q13, #8 161 vrshrn.u16 d20, q10, #8 162 vrshrn.u16 d21, q14, #8 163 vrshrn.u16 d22, q11, #8 164 vrshrn.u16 d23, q15, #8 165 166 vqadd.u8 q0, q8 167 vqadd.u8 q1, q9 168 vqadd.u8 q2, q10 169 vqadd.u8 q3, q11 170.endm 171 172#define params_SRC_IN zipped=1 173.macro blend_kernel_SRC_IN 174 vmull.u8 q12, d7, d17 175 vmull.u8 q0, d6, d16 176 vmull.u8 q13, d7, d19 177 vmull.u8 q1, d6, d18 178 vmull.u8 q14, d7, d21 179 vmull.u8 q2, d6, d20 180 vmull.u8 q15, d7, d23 181 vmull.u8 q3, d6, d22 182 183 vrshrn.u16 d8, q0, #8 184 vrshrn.u16 d9, q12, #8 185 vrshrn.u16 d10, q1, #8 186 vrshrn.u16 d11, q13, #8 187 vrshrn.u16 d12, q2, #8 188 vrshrn.u16 d13, q14, #8 189 vrshrn.u16 d14, q3, #8 190 vrshrn.u16 d15, q15, #8 191 192 vaddw.u8 q0, d8 193 vaddw.u8 q12, d9 194 vaddw.u8 q1, d10 195 vaddw.u8 q13, d11 196 vaddw.u8 q2, d12 197 vaddw.u8 q14, d13 198 vaddw.u8 q3, d14 199 vaddw.u8 q15, d15 200 201 vrshrn.u16 d0, q0, #8 202 vrshrn.u16 d1, q12, #8 203 vrshrn.u16 d2, q1, #8 204 vrshrn.u16 d3, q13, #8 205 vrshrn.u16 d4, q2, #8 206 vrshrn.u16 d5, q14, #8 207 vrshrn.u16 d6, q3, #8 208 vrshrn.u16 d7, q15, #8 209.endm 210 211#define params_DST_IN zipped=1 212.macro blend_kernel_DST_IN 213 vmull.u8 q12, d1, d23 214 vmull.u8 q0, d0, d22 215 vmull.u8 q13, d3, d23 216 vmull.u8 q1, d2, d22 217 vmull.u8 q14, d5, d23 218 vmull.u8 q2, d4, d22 219 vmull.u8 q15, d7, d23 220 vmull.u8 q3, d6, d22 221 222 vrshrn.u16 d8, q0, #8 223 vrshrn.u16 d9, q12, #8 224 vrshrn.u16 d10, q1, #8 225 vrshrn.u16 d11, q13, #8 226 vrshrn.u16 d12, q2, #8 227 vrshrn.u16 d13, q14, #8 228 vrshrn.u16 d14, q3, #8 229 vrshrn.u16 d15, q15, #8 230 231 vaddw.u8 q0, d8 232 vaddw.u8 q12, d9 233 vaddw.u8 q1, d10 234 vaddw.u8 q13, d11 235 vaddw.u8 q2, d12 236 vaddw.u8 q14, d13 237 vaddw.u8 q3, d14 238 vaddw.u8 q15, d15 239 240 vrshrn.u16 d0, q0, #8 241 vrshrn.u16 d1, q12, #8 242 vrshrn.u16 d2, q1, #8 243 vrshrn.u16 d3, q13, #8 244 vrshrn.u16 d4, q2, #8 245 vrshrn.u16 d5, q14, #8 246 vrshrn.u16 d6, q3, #8 247 vrshrn.u16 d7, q15, #8 248.endm 249 250#define params_SRC_OUT zipped=1 251.macro blend_kernel_SRC_OUT 252 vmvn q3, q3 253 blend_kernel_SRC_IN 254.endm 255 256 257#define params_DST_OUT zipped=1 258.macro blend_kernel_DST_OUT 259 vmvn q11, q11 260 blend_kernel_DST_IN 261.endm 262 263#define params_SRC_ATOP zipped=1 264.macro blend_kernel_SRC_ATOP 265 vmvn q11, q11 266 267 vmull.u8 q12, d23, d1 268 vmull.u8 q0, d22, d0 269 vmull.u8 q13, d23, d3 270 vmull.u8 q1, d22, d2 271 vmull.u8 q14, d23, d5 272 vmull.u8 q2, d22, d4 273 274 vmull.u8 q4, d7, d17 275 vmull.u8 q8, d6, d16 276 vmull.u8 q5, d7, d19 277 vmull.u8 q9, d6, d18 278 vmull.u8 q6, d7, d21 279 vmull.u8 q10, d6, d20 280 281 vqadd.u16 q12, q4 282 vqadd.u16 q0, q8 283 vqadd.u16 q13, q5 284 vqadd.u16 q1, q9 285 vqadd.u16 q14, q6 286 vqadd.u16 q2, q10 287 288 vrshr.u16 q8, q0, #8 289 vrshr.u16 q4, q12, #8 290 vrshr.u16 q9, q1, #8 291 vrshr.u16 q5, q13, #8 292 vrshr.u16 q10, q2, #8 293 vrshr.u16 q6, q14, #8 294 295 vqadd.u16 q0, q8 296 vqadd.u16 q12, q4 297 vqadd.u16 q1, q9 298 vqadd.u16 q13, q5 299 vqadd.u16 q2, q10 300 vqadd.u16 q14, q6 301 302 vqrshrn.u16 d0, q0, #8 303 vqrshrn.u16 d1, q12, #8 304 vqrshrn.u16 d2, q1, #8 305 vqrshrn.u16 d3, q13, #8 306 vqrshrn.u16 d4, q2, #8 307 vqrshrn.u16 d5, q14, #8 308.endm 309 310#define params_DST_ATOP zipped=1 311.macro blend_kernel_DST_ATOP 312 vmvn q3, q3 313 314 vmull.u8 q12, d23, d1 315 vmull.u8 q0, d22, d0 316 vmull.u8 q13, d23, d3 317 vmull.u8 q1, d22, d2 318 vmull.u8 q14, d23, d5 319 vmull.u8 q2, d22, d4 320 321 vmull.u8 q4, d7, d17 322 vmull.u8 q8, d6, d16 323 vmull.u8 q5, d7, d19 324 vmull.u8 q9, d6, d18 325 vmull.u8 q6, d7, d21 326 vmull.u8 q10, d6, d20 327 328 vqadd.u16 q12, q4 329 vqadd.u16 q0, q8 330 vqadd.u16 q13, q5 331 vqadd.u16 q1, q9 332 vqadd.u16 q14, q6 333 vqadd.u16 q2, q10 334 335 vrshr.u16 q8, q0, #8 336 vrshr.u16 q4, q12, #8 337 vrshr.u16 q9, q1, #8 338 vrshr.u16 q5, q13, #8 339 vrshr.u16 q10, q2, #8 340 vrshr.u16 q6, q14, #8 341 342 vqadd.u16 q0, q8 343 vqadd.u16 q12, q4 344 vqadd.u16 q1, q9 345 vqadd.u16 q13, q5 346 vqadd.u16 q2, q10 347 vqadd.u16 q14, q6 348 349 vqrshrn.u16 d0, q0, #8 350 vqrshrn.u16 d1, q12, #8 351 vqrshrn.u16 d2, q1, #8 352 vqrshrn.u16 d3, q13, #8 353 vqrshrn.u16 d4, q2, #8 354 vqrshrn.u16 d5, q14, #8 355 356 vmvn q3, q3 357.endm 358 359#define params_MULTIPLY zipped=0 360.macro blend_kernel_MULTIPLY 361 vmull.u8 q12, d1, d17 362 vmull.u8 q0, d0, d16 363 vmull.u8 q13, d3, d19 364 vmull.u8 q1, d2, d18 365 vmull.u8 q14, d5, d21 366 vmull.u8 q2, d4, d20 367 vmull.u8 q15, d7, d23 368 vmull.u8 q3, d6, d22 369 370 vrshrn.u16 d8, q0, #8 371 vrshrn.u16 d9, q12, #8 372 vrshrn.u16 d10, q1, #8 373 vrshrn.u16 d11, q13, #8 374 vrshrn.u16 d12, q2, #8 375 vrshrn.u16 d13, q14, #8 376 vrshrn.u16 d14, q3, #8 377 vrshrn.u16 d15, q15, #8 378 379 vaddw.u8 q0, d8 380 vaddw.u8 q12, d9 381 vaddw.u8 q1, d10 382 vaddw.u8 q13, d11 383 vaddw.u8 q2, d12 384 vaddw.u8 q14, d13 385 vaddw.u8 q3, d14 386 vaddw.u8 q15, d15 387 388 vrshrn.u16 d0, q0, #8 389 vrshrn.u16 d1, q12, #8 390 vrshrn.u16 d2, q1, #8 391 vrshrn.u16 d3, q13, #8 392 vrshrn.u16 d4, q2, #8 393 vrshrn.u16 d5, q14, #8 394 vrshrn.u16 d6, q3, #8 395 vrshrn.u16 d7, q15, #8 396.endm 397 398#define params_ADD zipped=0 399.macro blend_kernel_ADD 400 vqadd.u8 q0, q0, q8 401 vqadd.u8 q1, q1, q9 402 vqadd.u8 q2, q2, q10 403 vqadd.u8 q3, q3, q11 404.endm 405 406#define params_SUBTRACT zipped=0 407.macro blend_kernel_SUBTRACT 408 vqsub.u8 q0, q0, q8 409 vqsub.u8 q1, q1, q9 410 vqsub.u8 q2, q2, q10 411 vqsub.u8 q3, q3, q11 412.endm 413 414#define params_DIFFERENCE zipped=0 415.macro blend_kernel_DIFFERENCE 416 vabd.u8 q0, q0, q8 417 vabd.u8 q1, q1, q9 418 vabd.u8 q2, q2, q10 419 vabd.u8 q3, q3, q11 420.endm 421 422#define params_XOR zipped=0 423.macro blend_kernel_XOR 424 veor q0, q0, q8 425 veor q1, q1, q9 426 veor q2, q2, q10 427 veor q3, q3, q11 428.endm 429 430 431/* Define the wrapper code which will load and store the data, iterate the 432 * correct number of times, and safely handle the remainder at the end of the 433 * loop. Various sections of assembly code are dropped or substituted for 434 * simpler operations if they're not needed. 435 */ 436.macro wrap_line kernel, nowrap=0, zipped=1, lddst=1, ldsrc=1, pld=1 437.if \nowrap 438 \kernel 439.else 440 vpush {d8-d15} 441 subs r2, #64 442 b 2f 443 .align 4 4441: 445 .if \lddst 446 .if \zipped 447 vld4.8 {d0,d2,d4,d6}, [r0]! 448 vld4.8 {d1,d3,d5,d7}, [r0]! 449 .else 450 vld1.8 {d0-d3}, [r0]! 451 vld1.8 {d4-d7}, [r0]! 452 .endif 453 sub r0, #64 454 .endif 455 .if \ldsrc 456 .if \zipped 457 vld4.8 {d16,d18,d20,d22}, [r1]! 458 vld4.8 {d17,d19,d21,d23}, [r1]! 459 .else 460 vld1.8 {d16-d19}, [r1]! 461 vld1.8 {d20-d23}, [r1]! 462 .endif 463 .endif 464 .if \pld 465 .if \lddst ; pld [r0, #192] ; .endif 466 .if \ldsrc ; pld [r1, #192] ; .endif 467 .endif 468 469 \kernel 470 471 subs r2, #64 472 .if \zipped 473 vst4.8 {d0,d2,d4,d6}, [r0]! 474 vst4.8 {d1,d3,d5,d7}, [r0]! 475 .else 476 vst1.8 {d0-d3}, [r0]! 477 vst1.8 {d4-d7}, [r0]! 478 .endif 479 4802: bge 1b 481 adds r2, #64 482 beq 2f 483 484 /* To handle the tail portion of the data (something less than 64 485 * bytes) load small power-of-two chunks into working registers. It 486 * doesn't matter where they end up in the register; the same process 487 * will store them back out using the same positions and the operations 488 * don't require data to interact with its neighbours. 489 */ 490 vmov.i8 q0, #0 491 vmov.i8 q1, #0 492 vmov.i8 q2, #0 493 vmov.i8 q3, #0 494 495 vmov.i8 q8, #0 496 vmov.i8 q9, #0 497 vmov.i8 q10, #0 498 vmov.i8 q11, #0 499 500 tst r2, #32 501 beq 1f 502 .if \lddst ; vld1.64 {d4-d7}, [r0]! ; .endif 503 .if \ldsrc ; vld1.64 {d20-d23}, [r1]! ; .endif 5041: tst r2, #16 505 beq 1f 506 .if \lddst ; vld1.64 {d2-d3}, [r0]! ; .endif 507 .if \ldsrc ; vld1.64 {d18-d19}, [r1]! ; .endif 5081: tst r2, #8 509 beq 1f 510 .if \lddst ; vld1.64 {d1}, [r0]! ; .endif 511 .if \ldsrc ; vld1.64 {d17}, [r1]! ; .endif 5121: tst r2, #4 513 beq 1f 514 .if \lddst ; vld1.32 {d0[1]}, [r0]! ; .endif 515 .if \ldsrc ; vld1.32 {d16[1]}, [r1]! ; .endif 5161: tst r2, #2 517 beq 1f 518 .if \lddst ; vld1.16 {d0[1]}, [r0]! ; .endif 519 .if \ldsrc ; vld1.16 {d16[1]}, [r1]! ; .endif 5201: tst r2, #1 521 beq 1f 522 .if \lddst ; vld1.8 {d0[1]}, [r0]! ; .endif 523 .if \ldsrc ; vld1.8 {d16[1]}, [r1]! ; .endif 5241: 525 .if \lddst ; sub r0, r2 ; .endif 526 527 .if \zipped 528 /* One small impediment in the process above is that some of the load 529 * operations can't perform byte-wise structure deinterleaving at the 530 * same time as loading only part of a register. So the data is loaded 531 * linearly and unpacked manually at this point. 532 */ 533 vuzp.8 q0, q1 534 vuzp.8 q2, q3 535 vuzp.8 q0, q2 536 vuzp.8 q1, q3 537 538 vuzp.8 q8, q9 539 vuzp.8 q10, q11 540 vuzp.8 q8, q10 541 vuzp.8 q9, q11 542 543 \kernel 544 545 vzip.8 q0, q2 546 vzip.8 q1, q3 547 vzip.8 q0, q1 548 vzip.8 q2, q3 549 .else 550 \kernel 551 .endif 552 553 tst r2, #32 554 beq 1f 555 vst1.64 {d4-d7}, [r0]! 5561: tst r2, #16 557 beq 1f 558 vst1.64 {d2-d3}, [r0]! 5591: tst r2, #8 560 beq 1f 561 vst1.64 {d1}, [r0]! 5621: tst r2, #4 563 beq 1f 564 vst1.32 {d0[1]}, [r0]! 5651: tst r2, #2 566 beq 1f 567 vst1.16 {d0[1]}, [r0]! 5681: tst r2, #1 569 beq 2f 570 vst1.8 {d0[1]}, [r0]! 5712: vpop {d8-d15} 572.endif 573 mov r0, #0 574 bx lr 575.endm 576 577 578/* produce list of blend_line_XX() functions; each function uses the wrap_line 579 * macro, passing it the name of the operation macro it wants along with 580 * optional parameters to remove unnecessary operations. 581 */ 582#define BLEND_X(d, n) ENTRY(blend_line_##n) ; wrap_line blend_kernel_##n, params_##n ; END(blend_line_##n) ; 583 BLEND_LIST(BLEND_X) 584#undef BLEND_X 585 586 587/* int rsdIntrinsicBlend_K( 588 * uchar4 *out, // r0 589 * uchar4 const *in, // r1 590 * int slot, // r2 591 * size_t xstart, // r3 592 * size_t xend); // [sp] 593 */ 594ENTRY(rsdIntrinsicBlend_K) 595 adr ip, blend_functions 596 cmp r2, #(blend_functions_end - blend_functions) >> 2 597 ldrlo ip, [ip, r2, LSL #2] 598 movhs ip, #0 599 ldr r2, [sp] 600 add r0, r3, LSL #2 601 add r1, r3, LSL #2 602 sub r2, r3 603 mov r2, r2, LSL #2 604 cmp ip, #0 605 addne ip, ip, pc 606 bxne ip 6071: mov r0, #-1 608 bx lr 609 610blend_functions: 611.set off,0 612#define BLEND_X(d, n) .rept d-off ; .word 0 ; .endr ; .word blend_line_##n-1b ; .set off, d+1 ; 613 BLEND_LIST(BLEND_X) 614#undef BLEND_X 615blend_functions_end: 616 617END(rsdIntrinsicBlend_K) 618