Home | History | Annotate | Download | only in dsp
      1 // Copyright 2014 Google Inc. All Rights Reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style license
      4 // that can be found in the COPYING file in the root of the source
      5 // tree. An additional intellectual property rights grant can be found
      6 // in the file PATENTS. All contributing project authors may
      7 // be found in the AUTHORS file in the root of the source tree.
      8 // -----------------------------------------------------------------------------
      9 //
     10 // Image transforms and color space conversion methods for lossless decoder.
     11 //
     12 // Author(s):  Djordje Pesut    (djordje.pesut (at) imgtec.com)
     13 //             Jovan Zelincevic (jovan.zelincevic (at) imgtec.com)
     14 
     15 #include "src/dsp/dsp.h"
     16 
     17 #if defined(WEBP_USE_MIPS_DSP_R2)
     18 
     19 #include "src/dsp/lossless.h"
     20 #include "src/dsp/lossless_common.h"
     21 
     22 #define MAP_COLOR_FUNCS(FUNC_NAME, TYPE, GET_INDEX, GET_VALUE)                 \
     23 static void FUNC_NAME(const TYPE* src,                                         \
     24                       const uint32_t* const color_map,                         \
     25                       TYPE* dst, int y_start, int y_end,                       \
     26                       int width) {                                             \
     27   int y;                                                                       \
     28   for (y = y_start; y < y_end; ++y) {                                          \
     29     int x;                                                                     \
     30     for (x = 0; x < (width >> 2); ++x) {                                       \
     31       int tmp1, tmp2, tmp3, tmp4;                                              \
     32       __asm__ volatile (                                                       \
     33       ".ifc        " #TYPE ",  uint8_t                  \n\t"                  \
     34         "lbu       %[tmp1],  0(%[src])                  \n\t"                  \
     35         "lbu       %[tmp2],  1(%[src])                  \n\t"                  \
     36         "lbu       %[tmp3],  2(%[src])                  \n\t"                  \
     37         "lbu       %[tmp4],  3(%[src])                  \n\t"                  \
     38         "addiu     %[src],   %[src],      4             \n\t"                  \
     39       ".endif                                           \n\t"                  \
     40       ".ifc        " #TYPE ",  uint32_t                 \n\t"                  \
     41         "lw        %[tmp1],  0(%[src])                  \n\t"                  \
     42         "lw        %[tmp2],  4(%[src])                  \n\t"                  \
     43         "lw        %[tmp3],  8(%[src])                  \n\t"                  \
     44         "lw        %[tmp4],  12(%[src])                 \n\t"                  \
     45         "ext       %[tmp1],  %[tmp1],     8,        8   \n\t"                  \
     46         "ext       %[tmp2],  %[tmp2],     8,        8   \n\t"                  \
     47         "ext       %[tmp3],  %[tmp3],     8,        8   \n\t"                  \
     48         "ext       %[tmp4],  %[tmp4],     8,        8   \n\t"                  \
     49         "addiu     %[src],   %[src],      16            \n\t"                  \
     50       ".endif                                           \n\t"                  \
     51         "sll       %[tmp1],  %[tmp1],     2             \n\t"                  \
     52         "sll       %[tmp2],  %[tmp2],     2             \n\t"                  \
     53         "sll       %[tmp3],  %[tmp3],     2             \n\t"                  \
     54         "sll       %[tmp4],  %[tmp4],     2             \n\t"                  \
     55         "lwx       %[tmp1],  %[tmp1](%[color_map])      \n\t"                  \
     56         "lwx       %[tmp2],  %[tmp2](%[color_map])      \n\t"                  \
     57         "lwx       %[tmp3],  %[tmp3](%[color_map])      \n\t"                  \
     58         "lwx       %[tmp4],  %[tmp4](%[color_map])      \n\t"                  \
     59       ".ifc        " #TYPE ",  uint8_t                  \n\t"                  \
     60         "ext       %[tmp1],  %[tmp1],     8,        8   \n\t"                  \
     61         "ext       %[tmp2],  %[tmp2],     8,        8   \n\t"                  \
     62         "ext       %[tmp3],  %[tmp3],     8,        8   \n\t"                  \
     63         "ext       %[tmp4],  %[tmp4],     8,        8   \n\t"                  \
     64         "sb        %[tmp1],  0(%[dst])                  \n\t"                  \
     65         "sb        %[tmp2],  1(%[dst])                  \n\t"                  \
     66         "sb        %[tmp3],  2(%[dst])                  \n\t"                  \
     67         "sb        %[tmp4],  3(%[dst])                  \n\t"                  \
     68         "addiu     %[dst],   %[dst],      4             \n\t"                  \
     69       ".endif                                           \n\t"                  \
     70       ".ifc        " #TYPE ",  uint32_t                 \n\t"                  \
     71         "sw        %[tmp1],  0(%[dst])                  \n\t"                  \
     72         "sw        %[tmp2],  4(%[dst])                  \n\t"                  \
     73         "sw        %[tmp3],  8(%[dst])                  \n\t"                  \
     74         "sw        %[tmp4],  12(%[dst])                 \n\t"                  \
     75         "addiu     %[dst],   %[dst],      16            \n\t"                  \
     76       ".endif                                           \n\t"                  \
     77         : [tmp1]"=&r"(tmp1), [tmp2]"=&r"(tmp2), [tmp3]"=&r"(tmp3),             \
     78           [tmp4]"=&r"(tmp4), [src]"+&r"(src), [dst]"+r"(dst)                   \
     79         : [color_map]"r"(color_map)                                            \
     80         : "memory"                                                             \
     81       );                                                                       \
     82     }                                                                          \
     83     for (x = 0; x < (width & 3); ++x) {                                        \
     84       *dst++ = GET_VALUE(color_map[GET_INDEX(*src++)]);                        \
     85     }                                                                          \
     86   }                                                                            \
     87 }
     88 
     89 MAP_COLOR_FUNCS(MapARGB_MIPSdspR2, uint32_t, VP8GetARGBIndex, VP8GetARGBValue)
     90 MAP_COLOR_FUNCS(MapAlpha_MIPSdspR2, uint8_t, VP8GetAlphaIndex, VP8GetAlphaValue)
     91 
     92 #undef MAP_COLOR_FUNCS
     93 
     94 static WEBP_INLINE uint32_t ClampedAddSubtractFull(uint32_t c0, uint32_t c1,
     95                                                    uint32_t c2) {
     96   int temp0, temp1, temp2, temp3, temp4, temp5;
     97   __asm__ volatile (
     98     "preceu.ph.qbr   %[temp1],   %[c0]                 \n\t"
     99     "preceu.ph.qbl   %[temp2],   %[c0]                 \n\t"
    100     "preceu.ph.qbr   %[temp3],   %[c1]                 \n\t"
    101     "preceu.ph.qbl   %[temp4],   %[c1]                 \n\t"
    102     "preceu.ph.qbr   %[temp5],   %[c2]                 \n\t"
    103     "preceu.ph.qbl   %[temp0],   %[c2]                 \n\t"
    104     "subq.ph         %[temp3],   %[temp3],   %[temp5]  \n\t"
    105     "subq.ph         %[temp4],   %[temp4],   %[temp0]  \n\t"
    106     "addq.ph         %[temp1],   %[temp1],   %[temp3]  \n\t"
    107     "addq.ph         %[temp2],   %[temp2],   %[temp4]  \n\t"
    108     "shll_s.ph       %[temp1],   %[temp1],   7         \n\t"
    109     "shll_s.ph       %[temp2],   %[temp2],   7         \n\t"
    110     "precrqu_s.qb.ph %[temp2],   %[temp2],   %[temp1]  \n\t"
    111     : [temp0]"=r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
    112       [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5)
    113     : [c0]"r"(c0), [c1]"r"(c1), [c2]"r"(c2)
    114     : "memory"
    115   );
    116   return temp2;
    117 }
    118 
    119 static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1,
    120                                                    uint32_t c2) {
    121   int temp0, temp1, temp2, temp3, temp4, temp5;
    122   __asm__ volatile (
    123     "adduh.qb         %[temp5],   %[c0],      %[c1]       \n\t"
    124     "preceu.ph.qbr    %[temp3],   %[c2]                   \n\t"
    125     "preceu.ph.qbr    %[temp1],   %[temp5]                \n\t"
    126     "preceu.ph.qbl    %[temp2],   %[temp5]                \n\t"
    127     "preceu.ph.qbl    %[temp4],   %[c2]                   \n\t"
    128     "subq.ph          %[temp3],   %[temp1],   %[temp3]    \n\t"
    129     "subq.ph          %[temp4],   %[temp2],   %[temp4]    \n\t"
    130     "shrl.ph          %[temp5],   %[temp3],   15          \n\t"
    131     "shrl.ph          %[temp0],   %[temp4],   15          \n\t"
    132     "addq.ph          %[temp3],   %[temp3],   %[temp5]    \n\t"
    133     "addq.ph          %[temp4],   %[temp0],   %[temp4]    \n\t"
    134     "shra.ph          %[temp3],   %[temp3],   1           \n\t"
    135     "shra.ph          %[temp4],   %[temp4],   1           \n\t"
    136     "addq.ph          %[temp1],   %[temp1],   %[temp3]    \n\t"
    137     "addq.ph          %[temp2],   %[temp2],   %[temp4]    \n\t"
    138     "shll_s.ph        %[temp1],   %[temp1],   7           \n\t"
    139     "shll_s.ph        %[temp2],   %[temp2],   7           \n\t"
    140     "precrqu_s.qb.ph  %[temp1],   %[temp2],   %[temp1]    \n\t"
    141     : [temp0]"=r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
    142       [temp3]"=&r"(temp3), [temp4]"=r"(temp4), [temp5]"=&r"(temp5)
    143     : [c0]"r"(c0), [c1]"r"(c1), [c2]"r"(c2)
    144     : "memory"
    145   );
    146   return temp1;
    147 }
    148 
    149 static WEBP_INLINE uint32_t Select(uint32_t a, uint32_t b, uint32_t c) {
    150   int temp0, temp1, temp2, temp3, temp4, temp5;
    151   __asm__ volatile (
    152     "cmpgdu.lt.qb %[temp1], %[c],     %[b]             \n\t"
    153     "pick.qb      %[temp1], %[b],     %[c]             \n\t"
    154     "pick.qb      %[temp2], %[c],     %[b]             \n\t"
    155     "cmpgdu.lt.qb %[temp4], %[c],     %[a]             \n\t"
    156     "pick.qb      %[temp4], %[a],     %[c]             \n\t"
    157     "pick.qb      %[temp5], %[c],     %[a]             \n\t"
    158     "subu.qb      %[temp3], %[temp1], %[temp2]         \n\t"
    159     "subu.qb      %[temp0], %[temp4], %[temp5]         \n\t"
    160     "raddu.w.qb   %[temp3], %[temp3]                   \n\t"
    161     "raddu.w.qb   %[temp0], %[temp0]                   \n\t"
    162     "subu         %[temp3], %[temp3], %[temp0]         \n\t"
    163     "slti         %[temp0], %[temp3], 0x1              \n\t"
    164     "movz         %[a],     %[b],     %[temp0]         \n\t"
    165     : [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
    166       [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [temp0]"=&r"(temp0),
    167       [a]"+&r"(a)
    168     : [b]"r"(b), [c]"r"(c)
    169   );
    170   return a;
    171 }
    172 
    173 static WEBP_INLINE uint32_t Average2(uint32_t a0, uint32_t a1) {
    174   __asm__ volatile (
    175     "adduh.qb    %[a0], %[a0], %[a1]       \n\t"
    176     : [a0]"+r"(a0)
    177     : [a1]"r"(a1)
    178   );
    179   return a0;
    180 }
    181 
    182 static WEBP_INLINE uint32_t Average3(uint32_t a0, uint32_t a1, uint32_t a2) {
    183   return Average2(Average2(a0, a2), a1);
    184 }
    185 
    186 static WEBP_INLINE uint32_t Average4(uint32_t a0, uint32_t a1,
    187                                      uint32_t a2, uint32_t a3) {
    188   return Average2(Average2(a0, a1), Average2(a2, a3));
    189 }
    190 
    191 static uint32_t Predictor5_MIPSdspR2(uint32_t left, const uint32_t* const top) {
    192   return Average3(left, top[0], top[1]);
    193 }
    194 
    195 static uint32_t Predictor6_MIPSdspR2(uint32_t left, const uint32_t* const top) {
    196   return Average2(left, top[-1]);
    197 }
    198 
    199 static uint32_t Predictor7_MIPSdspR2(uint32_t left, const uint32_t* const top) {
    200   return Average2(left, top[0]);
    201 }
    202 
    203 static uint32_t Predictor8_MIPSdspR2(uint32_t left, const uint32_t* const top) {
    204   (void)left;
    205   return Average2(top[-1], top[0]);
    206 }
    207 
    208 static uint32_t Predictor9_MIPSdspR2(uint32_t left, const uint32_t* const top) {
    209   (void)left;
    210   return Average2(top[0], top[1]);
    211 }
    212 
    213 static uint32_t Predictor10_MIPSdspR2(uint32_t left,
    214                                       const uint32_t* const top) {
    215   return Average4(left, top[-1], top[0], top[1]);
    216 }
    217 
    218 static uint32_t Predictor11_MIPSdspR2(uint32_t left,
    219                                       const uint32_t* const top) {
    220   return Select(top[0], left, top[-1]);
    221 }
    222 
    223 static uint32_t Predictor12_MIPSdspR2(uint32_t left,
    224                                       const uint32_t* const top) {
    225   return ClampedAddSubtractFull(left, top[0], top[-1]);
    226 }
    227 
    228 static uint32_t Predictor13_MIPSdspR2(uint32_t left,
    229                                       const uint32_t* const top) {
    230   return ClampedAddSubtractHalf(left, top[0], top[-1]);
    231 }
    232 
    233 // Add green to blue and red channels (i.e. perform the inverse transform of
    234 // 'subtract green').
    235 static void AddGreenToBlueAndRed_MIPSdspR2(const uint32_t* src, int num_pixels,
    236                                            uint32_t* dst) {
    237   uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
    238   const uint32_t* const p_loop1_end = src + (num_pixels & ~3);
    239   const uint32_t* const p_loop2_end = src + num_pixels;
    240   __asm__ volatile (
    241     ".set       push                                          \n\t"
    242     ".set       noreorder                                     \n\t"
    243     "beq        %[src],          %[p_loop1_end],     3f       \n\t"
    244     " nop                                                     \n\t"
    245   "0:                                                         \n\t"
    246     "lw         %[temp0],        0(%[src])                    \n\t"
    247     "lw         %[temp1],        4(%[src])                    \n\t"
    248     "lw         %[temp2],        8(%[src])                    \n\t"
    249     "lw         %[temp3],        12(%[src])                   \n\t"
    250     "ext        %[temp4],        %[temp0],           8,    8  \n\t"
    251     "ext        %[temp5],        %[temp1],           8,    8  \n\t"
    252     "ext        %[temp6],        %[temp2],           8,    8  \n\t"
    253     "ext        %[temp7],        %[temp3],           8,    8  \n\t"
    254     "addiu      %[src],          %[src],             16       \n\t"
    255     "addiu      %[dst],          %[dst],             16       \n\t"
    256     "replv.ph   %[temp4],        %[temp4]                     \n\t"
    257     "replv.ph   %[temp5],        %[temp5]                     \n\t"
    258     "replv.ph   %[temp6],        %[temp6]                     \n\t"
    259     "replv.ph   %[temp7],        %[temp7]                     \n\t"
    260     "addu.qb    %[temp0],        %[temp0],           %[temp4] \n\t"
    261     "addu.qb    %[temp1],        %[temp1],           %[temp5] \n\t"
    262     "addu.qb    %[temp2],        %[temp2],           %[temp6] \n\t"
    263     "addu.qb    %[temp3],        %[temp3],           %[temp7] \n\t"
    264     "sw         %[temp0],        -16(%[dst])                  \n\t"
    265     "sw         %[temp1],        -12(%[dst])                  \n\t"
    266     "sw         %[temp2],        -8(%[dst])                   \n\t"
    267     "bne        %[src],          %[p_loop1_end],     0b       \n\t"
    268     " sw        %[temp3],        -4(%[dst])                   \n\t"
    269   "3:                                                         \n\t"
    270     "beq        %[src],          %[p_loop2_end],     2f       \n\t"
    271     " nop                                                     \n\t"
    272   "1:                                                         \n\t"
    273     "lw         %[temp0],        0(%[src])                    \n\t"
    274     "addiu      %[src],          %[src],             4        \n\t"
    275     "addiu      %[dst],          %[dst],             4        \n\t"
    276     "ext        %[temp4],        %[temp0],           8,    8  \n\t"
    277     "replv.ph   %[temp4],        %[temp4]                     \n\t"
    278     "addu.qb    %[temp0],        %[temp0],           %[temp4] \n\t"
    279     "bne        %[src],          %[p_loop2_end],     1b       \n\t"
    280     " sw        %[temp0],        -4(%[dst])                   \n\t"
    281   "2:                                                         \n\t"
    282     ".set       pop                                           \n\t"
    283     : [dst]"+&r"(dst), [src]"+&r"(src), [temp0]"=&r"(temp0),
    284       [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
    285       [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [temp6]"=&r"(temp6),
    286       [temp7]"=&r"(temp7)
    287     : [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end)
    288     : "memory"
    289   );
    290 }
    291 
    292 static void TransformColorInverse_MIPSdspR2(const VP8LMultipliers* const m,
    293                                             const uint32_t* src, int num_pixels,
    294                                             uint32_t* dst) {
    295   int temp0, temp1, temp2, temp3, temp4, temp5;
    296   uint32_t argb, argb1, new_red;
    297   const uint32_t G_to_R = m->green_to_red_;
    298   const uint32_t G_to_B = m->green_to_blue_;
    299   const uint32_t R_to_B = m->red_to_blue_;
    300   const uint32_t* const p_loop_end = src + (num_pixels & ~1);
    301   __asm__ volatile (
    302     ".set            push                                    \n\t"
    303     ".set            noreorder                               \n\t"
    304     "beq             %[src],       %[p_loop_end],  1f        \n\t"
    305     " nop                                                    \n\t"
    306     "replv.ph        %[temp0],     %[G_to_R]                 \n\t"
    307     "replv.ph        %[temp1],     %[G_to_B]                 \n\t"
    308     "replv.ph        %[temp2],     %[R_to_B]                 \n\t"
    309     "shll.ph         %[temp0],     %[temp0],       8         \n\t"
    310     "shll.ph         %[temp1],     %[temp1],       8         \n\t"
    311     "shll.ph         %[temp2],     %[temp2],       8         \n\t"
    312     "shra.ph         %[temp0],     %[temp0],       8         \n\t"
    313     "shra.ph         %[temp1],     %[temp1],       8         \n\t"
    314     "shra.ph         %[temp2],     %[temp2],       8         \n\t"
    315   "0:                                                        \n\t"
    316     "lw              %[argb],      0(%[src])                 \n\t"
    317     "lw              %[argb1],     4(%[src])                 \n\t"
    318     "sw              %[argb],      0(%[dst])                 \n\t"
    319     "sw              %[argb1],     4(%[dst])                 \n\t"
    320     "addiu           %[src],       %[src],         8         \n\t"
    321     "addiu           %[dst],       %[dst],         8         \n\t"
    322     "precrq.qb.ph    %[temp3],     %[argb],        %[argb1]  \n\t"
    323     "preceu.ph.qbra  %[temp3],     %[temp3]                  \n\t"
    324     "shll.ph         %[temp3],     %[temp3],       8         \n\t"
    325     "shra.ph         %[temp3],     %[temp3],       8         \n\t"
    326     "mul.ph          %[temp5],     %[temp3],       %[temp0]  \n\t"
    327     "mul.ph          %[temp3],     %[temp3],       %[temp1]  \n\t"
    328     "precrq.ph.w     %[new_red],   %[argb],        %[argb1]  \n\t"
    329     "ins             %[argb1],     %[argb],        16,   16  \n\t"
    330     "shra.ph         %[temp5],     %[temp5],       5         \n\t"
    331     "shra.ph         %[temp3],     %[temp3],       5         \n\t"
    332     "addu.ph         %[new_red],   %[new_red],     %[temp5]  \n\t"
    333     "addu.ph         %[argb1],     %[argb1],       %[temp3]  \n\t"
    334     "preceu.ph.qbra  %[temp5],     %[new_red]                \n\t"
    335     "shll.ph         %[temp4],     %[temp5],       8         \n\t"
    336     "shra.ph         %[temp4],     %[temp4],       8         \n\t"
    337     "mul.ph          %[temp4],     %[temp4],       %[temp2]  \n\t"
    338     "sb              %[temp5],     -2(%[dst])                \n\t"
    339     "sra             %[temp5],     %[temp5],       16        \n\t"
    340     "shra.ph         %[temp4],     %[temp4],       5         \n\t"
    341     "addu.ph         %[argb1],     %[argb1],       %[temp4]  \n\t"
    342     "preceu.ph.qbra  %[temp3],     %[argb1]                  \n\t"
    343     "sb              %[temp5],     -6(%[dst])                \n\t"
    344     "sb              %[temp3],     -4(%[dst])                \n\t"
    345     "sra             %[temp3],     %[temp3],       16        \n\t"
    346     "bne             %[src],       %[p_loop_end],  0b        \n\t"
    347     " sb             %[temp3],     -8(%[dst])                \n\t"
    348   "1:                                                        \n\t"
    349     ".set            pop                                     \n\t"
    350     : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
    351       [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
    352       [new_red]"=&r"(new_red), [argb]"=&r"(argb),
    353       [argb1]"=&r"(argb1), [dst]"+&r"(dst), [src]"+&r"(src)
    354     : [G_to_R]"r"(G_to_R), [R_to_B]"r"(R_to_B),
    355       [G_to_B]"r"(G_to_B), [p_loop_end]"r"(p_loop_end)
    356     : "memory", "hi", "lo"
    357   );
    358 
    359   // Fall-back to C-version for left-overs.
    360   if (num_pixels & 1) VP8LTransformColorInverse_C(m, src, 1, dst);
    361 }
    362 
    363 static void ConvertBGRAToRGB_MIPSdspR2(const uint32_t* src,
    364                                        int num_pixels, uint8_t* dst) {
    365   int temp0, temp1, temp2, temp3;
    366   const uint32_t* const p_loop1_end = src + (num_pixels & ~3);
    367   const uint32_t* const p_loop2_end = src + num_pixels;
    368   __asm__ volatile (
    369     ".set       push                                       \n\t"
    370     ".set       noreorder                                  \n\t"
    371     "beq        %[src],      %[p_loop1_end],    3f         \n\t"
    372     " nop                                                  \n\t"
    373   "0:                                                      \n\t"
    374     "lw         %[temp3],    12(%[src])                    \n\t"
    375     "lw         %[temp2],    8(%[src])                     \n\t"
    376     "lw         %[temp1],    4(%[src])                     \n\t"
    377     "lw         %[temp0],    0(%[src])                     \n\t"
    378     "ins        %[temp3],    %[temp2],          24,   8    \n\t"
    379     "sll        %[temp2],    %[temp2],          8          \n\t"
    380     "rotr       %[temp3],    %[temp3],          16         \n\t"
    381     "ins        %[temp2],    %[temp1],          0,    16   \n\t"
    382     "sll        %[temp1],    %[temp1],          8          \n\t"
    383     "wsbh       %[temp3],    %[temp3]                      \n\t"
    384     "balign     %[temp0],    %[temp1],          1          \n\t"
    385     "wsbh       %[temp2],    %[temp2]                      \n\t"
    386     "wsbh       %[temp0],    %[temp0]                      \n\t"
    387     "usw        %[temp3],    8(%[dst])                     \n\t"
    388     "rotr       %[temp0],    %[temp0],          16         \n\t"
    389     "usw        %[temp2],    4(%[dst])                     \n\t"
    390     "addiu      %[src],      %[src],            16         \n\t"
    391     "usw        %[temp0],    0(%[dst])                     \n\t"
    392     "bne        %[src],      %[p_loop1_end],    0b         \n\t"
    393     " addiu     %[dst],      %[dst],            12         \n\t"
    394   "3:                                                      \n\t"
    395     "beq        %[src],      %[p_loop2_end],    2f         \n\t"
    396     " nop                                                  \n\t"
    397   "1:                                                      \n\t"
    398     "lw         %[temp0],    0(%[src])                     \n\t"
    399     "addiu      %[src],      %[src],            4          \n\t"
    400     "wsbh       %[temp1],    %[temp0]                      \n\t"
    401     "addiu      %[dst],      %[dst],            3          \n\t"
    402     "ush        %[temp1],    -2(%[dst])                    \n\t"
    403     "sra        %[temp0],    %[temp0],          16         \n\t"
    404     "bne        %[src],      %[p_loop2_end],    1b         \n\t"
    405     " sb        %[temp0],    -3(%[dst])                    \n\t"
    406   "2:                                                      \n\t"
    407     ".set       pop                                        \n\t"
    408     : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
    409       [temp3]"=&r"(temp3), [dst]"+&r"(dst), [src]"+&r"(src)
    410     : [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end)
    411     : "memory"
    412   );
    413 }
    414 
    415 static void ConvertBGRAToRGBA_MIPSdspR2(const uint32_t* src,
    416                                         int num_pixels, uint8_t* dst) {
    417   int temp0, temp1, temp2, temp3;
    418   const uint32_t* const p_loop1_end = src + (num_pixels & ~3);
    419   const uint32_t* const p_loop2_end = src + num_pixels;
    420   __asm__ volatile (
    421     ".set       push                                       \n\t"
    422     ".set       noreorder                                  \n\t"
    423     "beq        %[src],      %[p_loop1_end],    3f         \n\t"
    424     " nop                                                  \n\t"
    425   "0:                                                      \n\t"
    426     "lw         %[temp0],    0(%[src])                     \n\t"
    427     "lw         %[temp1],    4(%[src])                     \n\t"
    428     "lw         %[temp2],    8(%[src])                     \n\t"
    429     "lw         %[temp3],    12(%[src])                    \n\t"
    430     "wsbh       %[temp0],    %[temp0]                      \n\t"
    431     "wsbh       %[temp1],    %[temp1]                      \n\t"
    432     "wsbh       %[temp2],    %[temp2]                      \n\t"
    433     "wsbh       %[temp3],    %[temp3]                      \n\t"
    434     "addiu      %[src],      %[src],            16         \n\t"
    435     "balign     %[temp0],    %[temp0],          1          \n\t"
    436     "balign     %[temp1],    %[temp1],          1          \n\t"
    437     "balign     %[temp2],    %[temp2],          1          \n\t"
    438     "balign     %[temp3],    %[temp3],          1          \n\t"
    439     "usw        %[temp0],    0(%[dst])                     \n\t"
    440     "usw        %[temp1],    4(%[dst])                     \n\t"
    441     "usw        %[temp2],    8(%[dst])                     \n\t"
    442     "usw        %[temp3],    12(%[dst])                    \n\t"
    443     "bne        %[src],      %[p_loop1_end],    0b         \n\t"
    444     " addiu     %[dst],      %[dst],            16         \n\t"
    445   "3:                                                      \n\t"
    446     "beq        %[src],      %[p_loop2_end],    2f         \n\t"
    447     " nop                                                  \n\t"
    448   "1:                                                      \n\t"
    449     "lw         %[temp0],    0(%[src])                     \n\t"
    450     "wsbh       %[temp0],    %[temp0]                      \n\t"
    451     "addiu      %[src],      %[src],            4          \n\t"
    452     "balign     %[temp0],    %[temp0],          1          \n\t"
    453     "usw        %[temp0],    0(%[dst])                     \n\t"
    454     "bne        %[src],      %[p_loop2_end],    1b         \n\t"
    455     " addiu     %[dst],      %[dst],            4          \n\t"
    456   "2:                                                      \n\t"
    457     ".set       pop                                        \n\t"
    458     : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
    459       [temp3]"=&r"(temp3), [dst]"+&r"(dst), [src]"+&r"(src)
    460     : [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end)
    461     : "memory"
    462   );
    463 }
    464 
    465 static void ConvertBGRAToRGBA4444_MIPSdspR2(const uint32_t* src,
    466                                             int num_pixels, uint8_t* dst) {
    467   int temp0, temp1, temp2, temp3, temp4, temp5;
    468   const uint32_t* const p_loop1_end = src + (num_pixels & ~3);
    469   const uint32_t* const p_loop2_end = src + num_pixels;
    470   __asm__ volatile (
    471     ".set           push                                       \n\t"
    472     ".set           noreorder                                  \n\t"
    473     "beq            %[src],      %[p_loop1_end],    3f         \n\t"
    474     " nop                                                      \n\t"
    475   "0:                                                          \n\t"
    476     "lw             %[temp0],    0(%[src])                     \n\t"
    477     "lw             %[temp1],    4(%[src])                     \n\t"
    478     "lw             %[temp2],    8(%[src])                     \n\t"
    479     "lw             %[temp3],    12(%[src])                    \n\t"
    480     "ext            %[temp4],    %[temp0],          28,   4    \n\t"
    481     "ext            %[temp5],    %[temp0],          12,   4    \n\t"
    482     "ins            %[temp0],    %[temp4],          0,    4    \n\t"
    483     "ext            %[temp4],    %[temp1],          28,   4    \n\t"
    484     "ins            %[temp0],    %[temp5],          16,   4    \n\t"
    485     "ext            %[temp5],    %[temp1],          12,   4    \n\t"
    486     "ins            %[temp1],    %[temp4],          0,    4    \n\t"
    487     "ext            %[temp4],    %[temp2],          28,   4    \n\t"
    488     "ins            %[temp1],    %[temp5],          16,   4    \n\t"
    489     "ext            %[temp5],    %[temp2],          12,   4    \n\t"
    490     "ins            %[temp2],    %[temp4],          0,    4    \n\t"
    491     "ext            %[temp4],    %[temp3],          28,   4    \n\t"
    492     "ins            %[temp2],    %[temp5],          16,   4    \n\t"
    493     "ext            %[temp5],    %[temp3],          12,   4    \n\t"
    494     "ins            %[temp3],    %[temp4],          0,    4    \n\t"
    495     "precr.qb.ph    %[temp1],    %[temp1],          %[temp0]   \n\t"
    496     "ins            %[temp3],    %[temp5],          16,   4    \n\t"
    497     "addiu          %[src],      %[src],            16         \n\t"
    498     "precr.qb.ph    %[temp3],    %[temp3],          %[temp2]   \n\t"
    499 #if (WEBP_SWAP_16BIT_CSP == 1)
    500     "usw            %[temp1],    0(%[dst])                     \n\t"
    501     "usw            %[temp3],    4(%[dst])                     \n\t"
    502 #else
    503     "wsbh           %[temp1],    %[temp1]                      \n\t"
    504     "wsbh           %[temp3],    %[temp3]                      \n\t"
    505     "usw            %[temp1],    0(%[dst])                     \n\t"
    506     "usw            %[temp3],    4(%[dst])                     \n\t"
    507 #endif
    508     "bne            %[src],      %[p_loop1_end],    0b         \n\t"
    509     " addiu         %[dst],      %[dst],            8          \n\t"
    510   "3:                                                          \n\t"
    511     "beq            %[src],      %[p_loop2_end],    2f         \n\t"
    512     " nop                                                      \n\t"
    513   "1:                                                          \n\t"
    514     "lw             %[temp0],    0(%[src])                     \n\t"
    515     "ext            %[temp4],    %[temp0],          28,   4    \n\t"
    516     "ext            %[temp5],    %[temp0],          12,   4    \n\t"
    517     "ins            %[temp0],    %[temp4],          0,    4    \n\t"
    518     "ins            %[temp0],    %[temp5],          16,   4    \n\t"
    519     "addiu          %[src],      %[src],            4          \n\t"
    520     "precr.qb.ph    %[temp0],    %[temp0],          %[temp0]   \n\t"
    521 #if (WEBP_SWAP_16BIT_CSP == 1)
    522     "ush            %[temp0],    0(%[dst])                     \n\t"
    523 #else
    524     "wsbh           %[temp0],    %[temp0]                      \n\t"
    525     "ush            %[temp0],    0(%[dst])                     \n\t"
    526 #endif
    527     "bne            %[src],      %[p_loop2_end],    1b         \n\t"
    528     " addiu         %[dst],      %[dst],            2          \n\t"
    529   "2:                                                          \n\t"
    530     ".set           pop                                        \n\t"
    531     : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
    532       [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
    533       [dst]"+&r"(dst), [src]"+&r"(src)
    534     : [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end)
    535     : "memory"
    536   );
    537 }
    538 
    539 static void ConvertBGRAToRGB565_MIPSdspR2(const uint32_t* src,
    540                                           int num_pixels, uint8_t* dst) {
    541   int temp0, temp1, temp2, temp3, temp4, temp5;
    542   const uint32_t* const p_loop1_end = src + (num_pixels & ~3);
    543   const uint32_t* const p_loop2_end = src + num_pixels;
    544   __asm__ volatile (
    545     ".set           push                                       \n\t"
    546     ".set           noreorder                                  \n\t"
    547     "beq            %[src],      %[p_loop1_end],    3f         \n\t"
    548     " nop                                                      \n\t"
    549   "0:                                                          \n\t"
    550     "lw             %[temp0],    0(%[src])                     \n\t"
    551     "lw             %[temp1],    4(%[src])                     \n\t"
    552     "lw             %[temp2],    8(%[src])                     \n\t"
    553     "lw             %[temp3],    12(%[src])                    \n\t"
    554     "ext            %[temp4],    %[temp0],          8,    16   \n\t"
    555     "ext            %[temp5],    %[temp0],          5,    11   \n\t"
    556     "ext            %[temp0],    %[temp0],          3,    5    \n\t"
    557     "ins            %[temp4],    %[temp5],          0,    11   \n\t"
    558     "ext            %[temp5],    %[temp1],          5,    11   \n\t"
    559     "ins            %[temp4],    %[temp0],          0,    5    \n\t"
    560     "ext            %[temp0],    %[temp1],          8,    16   \n\t"
    561     "ext            %[temp1],    %[temp1],          3,    5    \n\t"
    562     "ins            %[temp0],    %[temp5],          0,    11   \n\t"
    563     "ext            %[temp5],    %[temp2],          5,    11   \n\t"
    564     "ins            %[temp0],    %[temp1],          0,    5    \n\t"
    565     "ext            %[temp1],    %[temp2],          8,    16   \n\t"
    566     "ext            %[temp2],    %[temp2],          3,    5    \n\t"
    567     "ins            %[temp1],    %[temp5],          0,    11   \n\t"
    568     "ext            %[temp5],    %[temp3],          5,    11   \n\t"
    569     "ins            %[temp1],    %[temp2],          0,    5    \n\t"
    570     "ext            %[temp2],    %[temp3],          8,    16   \n\t"
    571     "ext            %[temp3],    %[temp3],          3,    5    \n\t"
    572     "ins            %[temp2],    %[temp5],          0,    11   \n\t"
    573     "append         %[temp0],    %[temp4],          16         \n\t"
    574     "ins            %[temp2],    %[temp3],          0,    5    \n\t"
    575     "addiu          %[src],      %[src],            16         \n\t"
    576     "append         %[temp2],    %[temp1],          16         \n\t"
    577 #if (WEBP_SWAP_16BIT_CSP == 1)
    578     "usw            %[temp0],    0(%[dst])                     \n\t"
    579     "usw            %[temp2],    4(%[dst])                     \n\t"
    580 #else
    581     "wsbh           %[temp0],    %[temp0]                      \n\t"
    582     "wsbh           %[temp2],    %[temp2]                      \n\t"
    583     "usw            %[temp0],    0(%[dst])                     \n\t"
    584     "usw            %[temp2],    4(%[dst])                     \n\t"
    585 #endif
    586     "bne            %[src],      %[p_loop1_end],    0b         \n\t"
    587     " addiu         %[dst],      %[dst],            8          \n\t"
    588   "3:                                                          \n\t"
    589     "beq            %[src],      %[p_loop2_end],    2f         \n\t"
    590     " nop                                                      \n\t"
    591   "1:                                                          \n\t"
    592     "lw             %[temp0],    0(%[src])                     \n\t"
    593     "ext            %[temp4],    %[temp0],          8,    16   \n\t"
    594     "ext            %[temp5],    %[temp0],          5,    11   \n\t"
    595     "ext            %[temp0],    %[temp0],          3,    5    \n\t"
    596     "ins            %[temp4],    %[temp5],          0,    11   \n\t"
    597     "addiu          %[src],      %[src],            4          \n\t"
    598     "ins            %[temp4],    %[temp0],          0,    5    \n\t"
    599 #if (WEBP_SWAP_16BIT_CSP == 1)
    600     "ush            %[temp4],    0(%[dst])                     \n\t"
    601 #else
    602     "wsbh           %[temp4],    %[temp4]                      \n\t"
    603     "ush            %[temp4],    0(%[dst])                     \n\t"
    604 #endif
    605     "bne            %[src],      %[p_loop2_end],    1b         \n\t"
    606     " addiu         %[dst],      %[dst],            2          \n\t"
    607   "2:                                                          \n\t"
    608     ".set           pop                                        \n\t"
    609     : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
    610       [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
    611       [dst]"+&r"(dst), [src]"+&r"(src)
    612     : [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end)
    613     : "memory"
    614   );
    615 }
    616 
    617 static void ConvertBGRAToBGR_MIPSdspR2(const uint32_t* src,
    618                                        int num_pixels, uint8_t* dst) {
    619   int temp0, temp1, temp2, temp3;
    620   const uint32_t* const p_loop1_end = src + (num_pixels & ~3);
    621   const uint32_t* const p_loop2_end = src + num_pixels;
    622   __asm__ volatile (
    623     ".set       push                                         \n\t"
    624     ".set       noreorder                                    \n\t"
    625     "beq        %[src],      %[p_loop1_end],    3f           \n\t"
    626     " nop                                                    \n\t"
    627   "0:                                                        \n\t"
    628     "lw         %[temp0],    0(%[src])                       \n\t"
    629     "lw         %[temp1],    4(%[src])                       \n\t"
    630     "lw         %[temp2],    8(%[src])                       \n\t"
    631     "lw         %[temp3],    12(%[src])                      \n\t"
    632     "ins        %[temp0],    %[temp1],          24,    8     \n\t"
    633     "sra        %[temp1],    %[temp1],          8            \n\t"
    634     "ins        %[temp1],    %[temp2],          16,    16    \n\t"
    635     "sll        %[temp2],    %[temp2],          8            \n\t"
    636     "balign     %[temp3],    %[temp2],          1            \n\t"
    637     "addiu      %[src],      %[src],            16           \n\t"
    638     "usw        %[temp0],    0(%[dst])                       \n\t"
    639     "usw        %[temp1],    4(%[dst])                       \n\t"
    640     "usw        %[temp3],    8(%[dst])                       \n\t"
    641     "bne        %[src],      %[p_loop1_end],    0b           \n\t"
    642     " addiu     %[dst],      %[dst],            12           \n\t"
    643   "3:                                                        \n\t"
    644     "beq        %[src],      %[p_loop2_end],    2f           \n\t"
    645     " nop                                                    \n\t"
    646   "1:                                                        \n\t"
    647     "lw         %[temp0],    0(%[src])                       \n\t"
    648     "addiu      %[src],      %[src],            4            \n\t"
    649     "addiu      %[dst],      %[dst],            3            \n\t"
    650     "ush        %[temp0],    -3(%[dst])                      \n\t"
    651     "sra        %[temp0],    %[temp0],          16           \n\t"
    652     "bne        %[src],      %[p_loop2_end],    1b           \n\t"
    653     " sb        %[temp0],    -1(%[dst])                      \n\t"
    654   "2:                                                        \n\t"
    655     ".set       pop                                          \n\t"
    656     : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
    657       [temp3]"=&r"(temp3), [dst]"+&r"(dst), [src]"+&r"(src)
    658     : [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end)
    659     : "memory"
    660   );
    661 }
    662 
    663 //------------------------------------------------------------------------------
    664 // Entry point
    665 
    666 extern void VP8LDspInitMIPSdspR2(void);
    667 
    668 WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitMIPSdspR2(void) {
    669   VP8LMapColor32b = MapARGB_MIPSdspR2;
    670   VP8LMapColor8b = MapAlpha_MIPSdspR2;
    671 
    672   VP8LPredictors[5] = Predictor5_MIPSdspR2;
    673   VP8LPredictors[6] = Predictor6_MIPSdspR2;
    674   VP8LPredictors[7] = Predictor7_MIPSdspR2;
    675   VP8LPredictors[8] = Predictor8_MIPSdspR2;
    676   VP8LPredictors[9] = Predictor9_MIPSdspR2;
    677   VP8LPredictors[10] = Predictor10_MIPSdspR2;
    678   VP8LPredictors[11] = Predictor11_MIPSdspR2;
    679   VP8LPredictors[12] = Predictor12_MIPSdspR2;
    680   VP8LPredictors[13] = Predictor13_MIPSdspR2;
    681 
    682   VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed_MIPSdspR2;
    683   VP8LTransformColorInverse = TransformColorInverse_MIPSdspR2;
    684 
    685   VP8LConvertBGRAToRGB = ConvertBGRAToRGB_MIPSdspR2;
    686   VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA_MIPSdspR2;
    687   VP8LConvertBGRAToRGBA4444 = ConvertBGRAToRGBA4444_MIPSdspR2;
    688   VP8LConvertBGRAToRGB565 = ConvertBGRAToRGB565_MIPSdspR2;
    689   VP8LConvertBGRAToBGR = ConvertBGRAToBGR_MIPSdspR2;
    690 }
    691 
    692 #else  // !WEBP_USE_MIPS_DSP_R2
    693 
    694 WEBP_DSP_INIT_STUB(VP8LDspInitMIPSdspR2)
    695 
    696 #endif  // WEBP_USE_MIPS_DSP_R2
    697