/* * Copyright (c) 2010 The WebM project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /**************************************************************************** * * Module Title : gen_scalers.c * * Description : Generic image scaling functions. * ***************************************************************************/ /**************************************************************************** * Header Files ****************************************************************************/ #include "vpx_scale/vpxscale.h" /**************************************************************************** * Imports ****************************************************************************/ /**************************************************************************** * * ROUTINE : horizontal_line_4_5_scale_c4 * * INPUTS : const unsigned char *source : Pointer to source data. * unsigned int source_width : Stride of source. * unsigned char *dest : Pointer to destination data. * unsigned int dest_width : Stride of destination (NOT USED). * * OUTPUTS : None. * * RETURNS : void * * FUNCTION : Copies horizontal line of pixels from source to * destination scaling up by 4 to 5. * * SPECIAL NOTES : None. * ****************************************************************************/ static void horizontal_line_4_5_scale_c64 ( const unsigned char *source, unsigned int source_width, unsigned char *dest, unsigned int dest_width ) { unsigned i; unsigned int ba, cb, dc, ed; unsigned char *restrict des = dest; unsigned int *restrict src = (unsigned int *)source; unsigned int const_51_205, const_102_154, const_205_51, const_154_102; unsigned int src_current, src_next; (void) dest_width; // Constants that are to be used for the filtering. For // best speed we are going to want to right shift by 16. // In the generic version they were shift by 8, so put // an extra 8 in now so that 16 will come out later. const_51_205 = 0x3300CD00; //_pack2 (51 << 8, 205 << 8); const_205_51 = 0xCD003300; //_pack2 (205 << 8, 51 << 8); const_102_154 = 0x66009A00; //_pack2 (102 << 8, 154 << 8); const_154_102 = 0x9A006600; //_pack2 (154 << 8, 102 << 8); // 5 points are needed to filter to give 5 output points. // A load can pull up 4 at a time, and one needs to be // "borrowed" from the next set of data. So instead of // loading those 5 points each time, "steal" a point from // the next set and only load up 4 each time through. src_current = _mem4(src); for (i = 0; i < source_width - 4; i += 4) { src_next = _mem4(src++); // Reorder the data so that it is ready for the // dot product. ba = _unpklu4(src_current); cb = _unpkhu4(_rotl(src_current, 8)); dc = _unpkhu4(src_current); ed = _unpkhu4(_shrmb(src_next, src_current)); // Use the dot product with round and shift. des [0] = src_current & 0xff; des [1] = _dotprsu2(ba, const_205_51); des [2] = _dotprsu2(cb, const_154_102); des [3] = _dotprsu2(dc, const_102_154); des [4] = _dotprsu2(ed, const_51_205); des += 5; // reuse loaded vales next time around. src_current = src_next; } // vp8_filter the last set of points. Normally a point from the next set // would be used, but there is no next set, so just fill. ba = _unpklu4(src_current); cb = _unpkhu4(_rotl(src_current, 8)); dc = _unpkhu4(src_current); des [0] = src_current & 0xff; des [1] = _dotprsu2(ba, const_205_51); des [2] = _dotprsu2(cb, const_154_102); des [3] = _dotprsu2(dc, const_102_154); des [4] = src_current & 0xff; } /**************************************************************************** * * ROUTINE : vertical_band_4_5_scale_c64 * * INPUTS : unsigned char *dest : Pointer to destination data. * unsigned int dest_pitch : Stride of destination data. * unsigned int dest_width : Width of destination data. * * OUTPUTS : None. * * RETURNS : void * * FUNCTION : Scales vertical band of pixels by scale 4 to 5. The * height of the band scaled is 4-pixels. * * SPECIAL NOTES : The routine uses the first line of the band below * the current band. * ****************************************************************************/ static void vertical_band_4_5_scale_c64(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) { unsigned int i; unsigned int a, b, c, d, e; unsigned int ba, cb, dc, ed; unsigned char *restrict src = dest; unsigned char *restrict des = dest; unsigned int const_51_205, const_102_154, const_205_51, const_154_102; const_51_205 = 0x3300CD00; //_pack2 (51 << 8, 205 << 8); const_205_51 = 0xCD003300; //_pack2 (205 << 8, 51 << 8); const_102_154 = 0x66009A00; //_pack2 (102 << 8, 154 << 8); const_154_102 = 0x9A006600; //_pack2 (154 << 8, 102 << 8); // Force a loop unroll here so that there is not such a // dependancy. a = src [0]; b = src [dest_pitch]; c = src [dest_pitch*2]; d = src [dest_pitch*3]; e = src [dest_pitch*5]; src ++; for (i = 0; i < dest_width; i++) { ba = _pack2(b, a); cb = _pack2(c, b); dc = _pack2(d, c); ed = _pack2(e, d); a = src [0]; b = src [dest_pitch]; c = src [dest_pitch*2]; d = src [dest_pitch*3]; e = src [dest_pitch*5]; src ++; des [dest_pitch] = _dotprsu2(ba, const_205_51); des [dest_pitch*2] = _dotprsu2(cb, const_154_102); des [dest_pitch*3] = _dotprsu2(dc, const_102_154); des [dest_pitch*4] = _dotprsu2(ed, const_51_205); des ++; } } /**************************************************************************** * * ROUTINE : last_vertical_band_4_5_scale_c64 * * INPUTS : unsigned char *dest : Pointer to destination data. * unsigned int dest_pitch : Stride of destination data. * unsigned int dest_width : Width of destination data. * * OUTPUTS : None. * * RETURNS : void * * FUNCTION : Scales last vertical band of pixels by scale 4 to 5. The * height of the band scaled is 4-pixels. * * SPECIAL NOTES : The routine does not have available the first line of * the band below the current band, since this is the * last band. * ****************************************************************************/ static void last_vertical_band_4_5_scale_c64(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) { unsigned int i; unsigned int a, b, c, d; unsigned int ba, cb, dc; unsigned char *restrict src = dest; unsigned char *restrict des = dest; unsigned int const_102_154, const_205_51, const_154_102; const_205_51 = 0xCD003300; //_pack2 (205 << 8, 51 << 8); const_102_154 = 0x66009A00; //_pack2 (102 << 8, 154 << 8); const_154_102 = 0x9A006600; //_pack2 (154 << 8, 102 << 8); a = src [0]; b = src [dest_pitch]; c = src [dest_pitch*2]; d = src [dest_pitch*3]; src ++; for (i = 0; i < dest_width; ++i) { ba = _pack2(b, a); cb = _pack2(c, b); dc = _pack2(d, c); a = src [0]; b = src [dest_pitch]; c = src [dest_pitch*2]; d = src [dest_pitch*3]; src ++; des [dest_pitch] = _dotprsu2(ba, const_205_51); des [dest_pitch*2] = _dotprsu2(cb, const_154_102); des [dest_pitch*3] = _dotprsu2(dc, const_102_154); des [dest_pitch*4] = (unsigned char) d; des++; } } /**************************************************************************** * * ROUTINE : horizontal_line_3_5_scale_c64 * * INPUTS : const unsigned char *source : Pointer to source data. * unsigned int source_width : Stride of source. * unsigned char *dest : Pointer to destination data. * unsigned int dest_width : Stride of destination (NOT USED). * * OUTPUTS : None. * * RETURNS : void * * FUNCTION : Copies horizontal line of pixels from source to * destination scaling up by 3 to 5. * * SPECIAL NOTES : None. * * ****************************************************************************/ static void horizontal_line_3_5_scale_c64 ( const unsigned char *source, unsigned int source_width, unsigned char *dest, unsigned int dest_width ) { unsigned int i; unsigned int ba, cb, dc; unsigned int src_current; unsigned char *restrict des = dest; unsigned char *restrict src = (unsigned char *)source; unsigned int const_51_205, const_102_154, const_205_51, const_154_102; (void) dest_width; const_51_205 = 0x3300CD00; //_pack2 (51 << 8, 205 << 8); const_205_51 = 0xCD003300; //_pack2 (205 << 8, 51 << 8); const_102_154 = 0x66009A00; //_pack2 (102 << 8, 154 << 8); const_154_102 = 0x9A006600; //_pack2 (154 << 8, 102 << 8); for (i = 0; i < source_width - 3; i += 3) { src_current = _mem4(src); // Reorder the data so that it is ready for the // dot product. ba = _unpklu4(src_current); cb = _unpkhu4(_rotl(src_current, 8)); dc = _unpkhu4(src_current); des [0] = src_current & 0xff; des [1] = _dotprsu2(ba, const_154_102); des [2] = _dotprsu2(cb, const_51_205); des [3] = _dotprsu2(cb, const_205_51); des [4] = _dotprsu2(dc, const_102_154); src += 3; des += 5; } src_current = _mem4(src); ba = _unpklu4(src_current); cb = _unpkhu4(_rotl(src_current, 8)); dc = _unpkhu4(src_current); des [0] = src_current & 0xff; des [1] = _dotprsu2(ba, const_154_102); des [2] = _dotprsu2(cb, const_51_205); des [3] = _dotprsu2(cb, const_205_51); des [4] = dc & 0xff; } /**************************************************************************** * * ROUTINE : vertical_band_3_5_scale_c64 * * INPUTS : unsigned char *dest : Pointer to destination data. * unsigned int dest_pitch : Stride of destination data. * unsigned int dest_width : Width of destination data. * * OUTPUTS : None. * * RETURNS : void * * FUNCTION : Scales vertical band of pixels by scale 3 to 5. The * height of the band scaled is 3-pixels. * * SPECIAL NOTES : The routine uses the first line of the band below * the current band. * ****************************************************************************/ static void vertical_band_3_5_scale_c64(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) { unsigned int i; unsigned int a, b, c, d; unsigned int ba, cb, dc; unsigned char *restrict src = dest; unsigned char *restrict des = dest; unsigned int const_51_205, const_102_154, const_205_51, const_154_102; const_51_205 = 0x3300CD00; //_pack2 (51 << 8, 205 << 8); const_205_51 = 0xCD003300; //_pack2 (205 << 8, 51 << 8); const_102_154 = 0x66009A00; //_pack2 (102 << 8, 154 << 8); const_154_102 = 0x9A006600; //_pack2 (154 << 8, 102 << 8); a = src [0]; b = src [dest_pitch]; c = src [dest_pitch*2]; d = src [dest_pitch*5]; src ++; for (i = 0; i < dest_width; i++) { ba = _pack2(b, a); cb = _pack2(c, b); dc = _pack2(d, c); a = src [0]; b = src [dest_pitch]; c = src [dest_pitch*2]; d = src [dest_pitch*5]; src ++; des [dest_pitch] = _dotprsu2(ba, const_154_102); des [dest_pitch*2] = _dotprsu2(cb, const_51_205); des [dest_pitch*3] = _dotprsu2(cb, const_205_51); des [dest_pitch*4] = _dotprsu2(dc, const_102_154); des++; } } /**************************************************************************** * * ROUTINE : last_vertical_band_3_5_scale_c64 * * INPUTS : unsigned char *dest : Pointer to destination data. * unsigned int dest_pitch : Stride of destination data. * unsigned int dest_width : Width of destination data. * * OUTPUTS : None. * * RETURNS : void * * FUNCTION : Scales last vertical band of pixels by scale 3 to 5. The * height of the band scaled is 3-pixels. * * SPECIAL NOTES : The routine does not have available the first line of * the band below the current band, since this is the * last band. * ****************************************************************************/ static void last_vertical_band_3_5_scale_c64(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) { unsigned int i; unsigned int a, b, c; unsigned int ba, cb; unsigned char *restrict src = dest; unsigned char *restrict des = dest; unsigned int const_51_205, const_205_51, const_154_102; const_51_205 = 0x3300CD00; //_pack2 (51 << 8, 205 << 8); const_205_51 = 0xCD003300; //_pack2 (205 << 8, 51 << 8); const_154_102 = 0x9A006600; //_pack2 (154 << 8, 102 << 8); a = src [0]; b = src [dest_pitch]; c = src [dest_pitch*2]; src ++; for (i = 0; i < dest_width; ++i) { ba = _pack2(b, a); cb = _pack2(c, b); a = src [0]; b = src [dest_pitch]; c = src [dest_pitch*2]; src ++; des [dest_pitch] = _dotprsu2(ba, const_154_102); des [dest_pitch*2] = _dotprsu2(cb, const_51_205); des [dest_pitch*3] = _dotprsu2(cb, const_205_51); des [dest_pitch*4] = (unsigned char)(c) ; des++; } } /**************************************************************************** * * ROUTINE : horizontal_line_1_2_scale_c64 * * INPUTS : const unsigned char *source : Pointer to source data. * unsigned int source_width : Stride of source. * unsigned char *dest : Pointer to destination data. * unsigned int dest_width : Stride of destination (NOT USED). * * OUTPUTS : None. * * RETURNS : void * * FUNCTION : Copies horizontal line of pixels from source to * destination scaling up by 1 to 2. * * SPECIAL NOTES : source width must be a multiple of 4. * ****************************************************************************/ void horizontal_line_1_2_scale_c64 ( const unsigned char *source, unsigned int source_width, unsigned char *dest, unsigned int dest_width ) { unsigned int i; unsigned char *restrict des = dest; unsigned char *restrict src = (unsigned char *)source; unsigned int src7_4i, src4_1i, src3_0i; unsigned int a4_0i, ahi, alo; double src7_0d, src3_0d; const unsigned int k01 = 0x01010101; for (i = 0; i < source_width / 4; i += 1) { // Load up the data from src. Here a wide load is // used to get 8 bytes at once, only 5 will be used // for the actual computation. src7_0d = _memd8(src); src3_0i = _lo(src7_0d); src7_4i = _hi(src7_0d); // Need to average between points. Shift byte 5 into // the lower word. This will result in bytes 5-1 // averaged with 4-0. src4_1i = _shrmb(src7_4i, src3_0i); a4_0i = _avgu4(src4_1i, src3_0i); // Expand the data out. Could do an unpack, however // all but the multiply units are getting pretty hard // here the multiply unit can take some of the computations. src3_0d = _mpyu4(src3_0i, k01); // The averages need to be unpacked so that they are in 16 // bit form and will be able to be interleaved with the // original data ahi = _unpkhu4(a4_0i); alo = _unpklu4(a4_0i); ahi = _swap4(ahi); alo = _swap4(alo); // Mix the average result in with the orginal data. ahi = _hi(src3_0d) | ahi; alo = _lo(src3_0d) | alo; _memd8(des) = _itod(ahi, alo); des += 8; src += 4; } } /**************************************************************************** * * ROUTINE : vertical_band_1_2_scale_c64 * * INPUTS : unsigned char *dest : Pointer to destination data. * unsigned int dest_pitch : Stride of destination data. * unsigned int dest_width : Width of destination data. * * OUTPUTS : None. * * RETURNS : void * * FUNCTION : Scales vertical band of pixels by scale 1 to 2. The * height of the band scaled is 1-pixel. * * SPECIAL NOTES : The routine uses the first line of the band below * the current band. * Destination width must be a multiple of 4. Because the * intput must be, therefore the output must be. * ****************************************************************************/ static void vertical_band_1_2_scale_c64(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) { unsigned int i; unsigned int a, b; unsigned int *restrict line_a = (unsigned int *)dest; unsigned int *restrict line_b = (unsigned int *)(dest + (dest_pitch * 2)); unsigned int *restrict des = (unsigned int *)(dest + dest_pitch); for (i = 0; i < dest_width / 4; i++) { a = _mem4(line_a++); b = _mem4(line_b++); _mem4(des++) = _avgu4(a, b); } } /**************************************************************************** * * ROUTINE : last_vertical_band_1_2_scale_c64 * * INPUTS : unsigned char *dest : Pointer to destination data. * unsigned int dest_pitch : Stride of destination data. * unsigned int dest_width : Width of destination data. * * OUTPUTS : None. * * RETURNS : void * * FUNCTION : Scales last vertical band of pixels by scale 1 to 2. The * height of the band scaled is 1-pixel. * * SPECIAL NOTES : The routine does not have available the first line of * the band below the current band, since this is the * last band. Again, width must be a multiple of 4. * ****************************************************************************/ static void last_vertical_band_1_2_scale_c64(unsigned char *dest, unsigned int dest_pitch, unsigned int dest_width) { unsigned int i; unsigned int *restrict src = (unsigned int *)dest; unsigned int *restrict des = (unsigned int *)(dest + dest_pitch); for (i = 0; i < dest_width / 4; ++i) { _mem4(des++) = _mem4(src++); } } void register_generic_scalers(void) { vp8_horizontal_line_1_2_scale = horizontal_line_1_2_scale_c64; vp8_vertical_band_1_2_scale = vertical_band_1_2_scale_c64; vp8_last_vertical_band_1_2_scale = last_vertical_band_1_2_scale_c64; vp8_horizontal_line_3_5_scale = horizontal_line_3_5_scale_c64; vp8_vertical_band_3_5_scale = vertical_band_3_5_scale_c64; vp8_last_vertical_band_3_5_scale = last_vertical_band_3_5_scale_c64; vp8_horizontal_line_4_5_scale = horizontal_line_4_5_scale_c64; vp8_vertical_band_4_5_scale = vertical_band_4_5_scale_c64; vp8_last_vertical_band_4_5_scale = last_vertical_band_4_5_scale_c64; }