/* libs/pixelflinger/t32cb16blend.S
**
** Copyright 2010, 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.
*/

#ifdef DEBUG
#define DBG
#else
#define DBG #
#endif

/*
 * blend one of 2 16bpp RGB pixels held in dreg selected by shift
 * with the 32bpp ABGR pixel held in src and store the result in fb
 *
 * Assumes that the dreg data is little endian and that
 * the the second pixel (shift==16) will be merged into
 * the fb result
 *
 * Uses $t0,$t6,$t7,$t8
 */

#if __mips==32 && __mips_isa_rev>=2
    .macro pixel dreg src fb shift
    /*
     * sA = s >> 24
     * f = 0x100 - (sA + (sA>>7))
     */
DBG .set    noat
DBG rdhwr   $at,$2
DBG .set    at

    srl  $t7,\src,24
    srl  $t6,$t7,7
    addu $t7,$t6
    li   $t6,0x100
    subu $t7,$t6,$t7

    /* red */
    ext  $t8,\dreg,\shift+6+5,5         # dst[\shift:15..11]
    mul  $t6,$t8,$t7
    ext  $t0,\dreg,\shift+5,6           # start green extraction dst[\shift:10..5]
    ext  $t8,\src,3,5               # src[7..3]
    srl  $t6,8
    addu $t8,$t6
.if \shift!=0
    sll  $t8,\shift+11
    or   \fb,$t8
.else
    sll  \fb,$t8,11
.endif

    /* green */
    mul  $t8,$t0,$t7
    ext  $t0,\dreg,\shift,5         # start blue extraction dst[\shift:4..0]
    ext  $t6,\src,2+8,6             # src[15..10]
    srl  $t8,8
    addu $t8,$t6

    /* blue */
    mul  $t0,$t0,$t7
    sll  $t8, $t8, \shift+5
    or   \fb, \fb, $t8
    ext  $t6,\src,(3+8+8),5
    srl  $t8,$t0,8
    addu $t8,$t6
    sll  $t8, $t8, \shift
    or   \fb, \fb, $t8

DBG .set    noat
DBG rdhwr $t8,$2
DBG subu  $t8,$at
DBG sltu  $at,$t8,$v0
DBG movn  $v0,$t8,$at
DBG sgtu  $at,$t8,$v1
DBG movn  $v1,$t8,$at
DBG .set    at
    .endm

#else

    .macro pixel dreg src fb shift
    /*
     * sA = s >> 24
     * f = 0x100 - (sA + (sA>>7))
     */
DBG .set    push
DBG .set    noat
DBG .set    mips32r2
DBG rdhwr   $at,$2
DBG .set    pop

    srl  $t7,\src,24
    srl  $t6,$t7,7
    addu $t7,$t6
    li   $t6,0x100
    subu $t7,$t6,$t7

    /*
     * red
     * dR = (d >> (6 + 5)) & 0x1f;
     * dR = (f*dR)>>8
     * sR = (s >> (   3)) & 0x1f;
     * sR += dR
     * fb |= sR << 11
     */
    srl  $t8,\dreg,\shift+6+5
.if \shift==0
    and  $t8,0x1f
.endif
    mul  $t8,$t8,$t7
    srl  $t6,\src,3
    and  $t6,0x1f
    srl  $t8,8
    addu $t8,$t6
.if \shift!=0
    sll  $t8,\shift+11
    or   \fb,$t8
.else
    sll  \fb,$t8,11
.endif

        /*
     * green
     * dG = (d >> 5) & 0x3f
     * dG = (f*dG) >> 8
     * sG = (s >> ( 8+2))&0x3F;
     */
    srl  $t8,\dreg,\shift+5
    and  $t8,0x3f
    mul  $t8,$t8,$t7
    srl  $t6,\src,8+2
    and  $t6,0x3f
    srl  $t8,8
    addu $t8,$t6
    sll  $t8,\shift + 5
    or   \fb,$t8

    /* blue */
.if \shift!=0
    srl  $t8,\dreg,\shift
    and  $t8,0x1f
.else
    and  $t8,\dreg,0x1f
.endif
    mul  $t8,$t8,$t7
    srl  $t6,\src,(8+8+3)
    and  $t6,0x1f
    srl  $t8,8
    addu $t8,$t6
.if \shift!=0
    sll  $t8,\shift
.endif
    or   \fb,$t8
DBG .set    push
DBG .set    noat
DBG .set    mips32r2
DBG rdhwr   $t8,$2
DBG subu    $t8,$at
DBG sltu    $at,$t8,$v0
DBG movn    $v0,$t8,$at
DBG sgtu    $at,$t8,$v1
DBG movn    $v1,$t8,$at
DBG .set    pop
    .endm
#endif

    .text
    .align

    .global scanline_t32cb16blend_mips
    .ent    scanline_t32cb16blend_mips
scanline_t32cb16blend_mips:
DBG li    $v0,0xffffffff
DBG li    $v1,0
    /* Align the destination if necessary */
    and   $t0,$a0,3
    beqz  $t0,aligned

    /* as long as there is at least one pixel */
    beqz  $a2,done

    lw    $t4,($a1)
    addu  $a0,2
    addu  $a1,4
    beqz  $t4,1f
    lhu   $t3,-2($a0)
    pixel $t3,$t4,$t1,0
    sh    $t1,-2($a0)
1:  subu  $a2,1

aligned:
    /* Check to see if its worth unrolling the loop */
    subu  $a2,4
    bltz  $a2,tail

    /* Process 4 pixels at a time */
fourpixels:
    /* 1st pair of pixels */
    lw    $t4,0($a1)
    lw    $t5,4($a1)
    addu  $a0,8
    addu  $a1,16

    /* both are zero, skip this pair */
    or    $t3,$t4,$t5
    beqz  $t3,1f

    /* load the destination */
    lw    $t3,-8($a0)

    pixel $t3,$t4,$t1,0
    andi  $t1, 0xFFFF
    pixel $t3,$t5,$t1,16
    sw    $t1,-8($a0)

1:
    /* 2nd pair of pixels */
    lw    $t4,-8($a1)
    lw    $t5,-4($a1)

    /* both are zero, skip this pair */
    or    $t3,$t4,$t5
    beqz  $t3,1f

    /* load the destination */
    lw    $t3,-4($a0)

    pixel $t3,$t4,$t1,0
    andi  $t1, 0xFFFF
    pixel $t3,$t5,$t1,16
    sw    $t1,-4($a0)

1:  subu  $a2,4
    bgtz  $a2,fourpixels

tail:
    /* the pixel count underran, restore it now */
    addu  $a2,4

    /* handle the last 0..3 pixels */
    beqz  $a2,done
onepixel:
    lw    $t4,($a1)
    addu  $a0,2
    addu  $a1,4
    beqz  $t4,1f
    lhu   $t3,-2($a0)
    pixel $t3,$t4,$t1,0
    sh    $t1,-2($a0)
1:  subu  $a2,1
    bnez  $a2,onepixel
done:
DBG .set    push
DBG .set    mips32r2
DBG rdhwr   $a0,$3
DBG mul     $v0,$a0
DBG mul     $v1,$a0
DBG .set    pop
    j     $ra
    .end    scanline_t32cb16blend_mips