/* libs/pixelflinger/t32cb16blend.S
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License"); 
** you may not use this file except in compliance with the License. 
** You may obtain a copy of the License at 
**
**     http://www.apache.org/licenses/LICENSE-2.0 
**
** Unless required by applicable law or agreed to in writing, software 
** distributed under the License is distributed on an "AS IS" BASIS, 
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
** See the License for the specific language governing permissions and 
** limitations under the License.
*/


	.text
	.syntax unified
	.balign 4
	
	.global scanline_t32cb16blend_arm


/*
 * .macro pixel
 *
 * \DREG is a 32-bit register containing *two* original destination RGB565 
 *       pixels, with the even one in the low-16 bits, and the odd one in the
 *       high 16 bits.
 *
 * \SRC is a 32-bit 0xAABBGGRR pixel value, with pre-multiplied colors.
 *
 * \FB is a target register that will contain the blended pixel values.
 *
 * \ODD is either 0 or 1 and indicates if we're blending the lower or 
 *      upper 16-bit pixels in DREG into FB
 *
 *
 * clobbered: r6, r7, lr
 *
 */

.macro pixel,   DREG, SRC, FB, ODD

    // SRC = 0xAABBGGRR
    mov     r7, \SRC, lsr #24           // sA
    add     r7, r7, r7, lsr #7          // sA + (sA >> 7)
    rsb     r7, r7, #0x100              // sA = 0x100 - (sA+(sA>>7))

1:

.if \ODD

    // red
    mov     lr, \DREG, lsr #(16 + 11)
    smulbb  lr, r7, lr
    mov     r6, \SRC, lsr #3
    and     r6, r6, #0x1F
    add     lr, r6, lr, lsr #8
    cmp     lr, #0x1F
    orrhs   \FB, \FB, #(0x1F<<(16 + 11))
    orrlo   \FB, \FB, lr, lsl #(16 + 11)

        // green
        and     r6, \DREG, #(0x3F<<(16 + 5))
        smulbt  r6, r7, r6
        mov     lr, \SRC, lsr #(8+2)
        and     lr, lr, #0x3F
        add     r6, lr, r6, lsr #(5+8)
        cmp     r6, #0x3F
        orrhs   \FB, \FB, #(0x3F<<(16 + 5))
        orrlo   \FB, \FB, r6, lsl #(16 + 5)

            // blue
            and     lr, \DREG, #(0x1F << 16)
            smulbt  lr, r7, lr
            mov     r6, \SRC, lsr #(8+8+3)
            and     r6, r6, #0x1F
            add     lr, r6, lr, lsr #8
            cmp     lr, #0x1F
            orrhs   \FB, \FB, #(0x1F << 16)
            orrlo   \FB, \FB, lr, lsl #16

.else

    // red
    mov     lr, \DREG, lsr #11
    and     lr, lr, #0x1F
    smulbb  lr, r7, lr
    mov     r6, \SRC, lsr #3
    and     r6, r6, #0x1F
    add     lr, r6, lr, lsr #8
    cmp     lr, #0x1F
    movhs   \FB, #(0x1F<<11)
    movlo   \FB, lr, lsl #11


        // green
        and     r6, \DREG, #(0x3F<<5)
        smulbb  r6, r7, r6
        mov     lr, \SRC, lsr #(8+2)
        and     lr, lr, #0x3F
        add     r6, lr, r6, lsr #(5+8)
        cmp     r6, #0x3F
        orrhs   \FB, \FB, #(0x3F<<5)
        orrlo   \FB, \FB, r6, lsl #5

            // blue
            and     lr, \DREG, #0x1F
            smulbb  lr, r7, lr
            mov     r6, \SRC, lsr #(8+8+3)
            and     r6, r6, #0x1F
            add     lr, r6, lr, lsr #8
            cmp     lr, #0x1F
            orrhs   \FB, \FB, #0x1F
            orrlo   \FB, \FB, lr

.endif

    .endm
    

// r0:  dst ptr
// r1:  src ptr
// r2:  count
// r3:  d
// r4:  s0
// r5:  s1
// r6:  pixel
// r7:  pixel
// r8:  free
// r9:  free
// r10: free
// r11: free
// r12: scratch
// r14: pixel

scanline_t32cb16blend_arm:
    stmfd	sp!, {r4-r7, lr}

    pld     [r0]
    pld     [r1]

    // align DST to 32 bits
    tst     r0, #0x3
    beq     aligned
    subs    r2, r2, #1
    ldmfdlo sp!, {r4-r7, lr}        // return
    bxlo    lr

last:
    ldr     r4, [r1], #4
    ldrh    r3, [r0]
    pixel   r3, r4, r12, 0
    strh    r12, [r0], #2

aligned:
    subs    r2, r2, #2
    blo     9f

    // The main loop is unrolled twice and processes 4 pixels
8:  ldmia   r1!, {r4, r5}
    // stream the source
    pld     [r1, #32]
    add     r0, r0, #4
    // it's all zero, skip this pixel
    orrs    r3, r4, r5
    beq     7f
    
    // load the destination
    ldr     r3, [r0, #-4]
    // stream the destination
    pld     [r0, #32]
    pixel   r3, r4, r12, 0
    pixel   r3, r5, r12, 1
    // effectively, we're getting write-combining by virtue of the
    // cpu's write-back cache.
    str     r12, [r0, #-4]

    // 2nd iterration of the loop, don't stream anything
    subs    r2, r2, #2
    movlt   r4, r5
    blt     9f
    ldmia   r1!, {r4, r5}
    add     r0, r0, #4
    orrs    r3, r4, r5
    beq     7f
    ldr     r3, [r0, #-4]
    pixel   r3, r4, r12, 0
    pixel   r3, r5, r12, 16
    str     r12, [r0, #-4]

    
7:  subs    r2, r2, #2
    bhs     8b
    mov     r4, r5

9:  adds    r2, r2, #1
    ldmfdlo sp!, {r4-r7, lr}        // return
    bxlo    lr
    b       last