| /* | 
 |  * Copyright (c) 2021, Alliance for Open Media. All rights reserved | 
 |  * | 
 |  * This source code is subject to the terms of the BSD 3-Clause Clear License | 
 |  * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear | 
 |  * License was not distributed with this source code in the LICENSE file, you | 
 |  * can obtain it at aomedia.org/license/software-license/bsd-3-c-c/.  If the | 
 |  * Alliance for Open Media Patent License 1.0 was not distributed with this | 
 |  * source code in the PATENTS file, you can obtain it at | 
 |  * aomedia.org/license/patent-license/. | 
 |  */ | 
 |  | 
 | #include <assert.h> | 
 |  | 
 | #include "config/aom_config.h" | 
 |  | 
 | #include "aom_scale/yv12config.h" | 
 | #include "aom_mem/aom_mem.h" | 
 | #include "aom_scale/aom_scale.h" | 
 |  | 
 | #if HAVE_DSPR2 | 
 | static void extend_plane(uint8_t *const src, int src_stride, int width, | 
 |                          int height, int extend_top, int extend_left, | 
 |                          int extend_bottom, int extend_right) { | 
 |   int i, j; | 
 |   uint8_t *left_src, *right_src; | 
 |   uint8_t *left_dst_start, *right_dst_start; | 
 |   uint8_t *left_dst, *right_dst; | 
 |   uint8_t *top_src, *bot_src; | 
 |   uint8_t *top_dst, *bot_dst; | 
 |   uint32_t left_pix; | 
 |   uint32_t right_pix; | 
 |   uint32_t linesize; | 
 |  | 
 |   /* copy the left and right most columns out */ | 
 |   left_src = src; | 
 |   right_src = src + width - 1; | 
 |   left_dst_start = src - extend_left; | 
 |   right_dst_start = src + width; | 
 |  | 
 |   for (i = height; i--;) { | 
 |     left_dst = left_dst_start; | 
 |     right_dst = right_dst_start; | 
 |  | 
 |     __asm__ __volatile__( | 
 |         "lb        %[left_pix],     0(%[left_src])      \n\t" | 
 |         "lb        %[right_pix],    0(%[right_src])     \n\t" | 
 |         "replv.qb  %[left_pix],     %[left_pix]         \n\t" | 
 |         "replv.qb  %[right_pix],    %[right_pix]        \n\t" | 
 |  | 
 |         : [left_pix] "=&r"(left_pix), [right_pix] "=&r"(right_pix) | 
 |         : [left_src] "r"(left_src), [right_src] "r"(right_src)); | 
 |  | 
 |     for (j = extend_left / 4; j--;) { | 
 |       __asm__ __volatile__( | 
 |           "sw     %[left_pix],    0(%[left_dst])     \n\t" | 
 |           "sw     %[right_pix],   0(%[right_dst])    \n\t" | 
 |  | 
 |           : | 
 |           : [left_dst] "r"(left_dst), [left_pix] "r"(left_pix), | 
 |             [right_dst] "r"(right_dst), [right_pix] "r"(right_pix)); | 
 |  | 
 |       left_dst += 4; | 
 |       right_dst += 4; | 
 |     } | 
 |  | 
 |     for (j = extend_left % 4; j--;) { | 
 |       __asm__ __volatile__( | 
 |           "sb     %[left_pix],    0(%[left_dst])     \n\t" | 
 |           "sb     %[right_pix],   0(%[right_dst])     \n\t" | 
 |  | 
 |           : | 
 |           : [left_dst] "r"(left_dst), [left_pix] "r"(left_pix), | 
 |             [right_dst] "r"(right_dst), [right_pix] "r"(right_pix)); | 
 |  | 
 |       left_dst += 1; | 
 |       right_dst += 1; | 
 |     } | 
 |  | 
 |     left_src += src_stride; | 
 |     right_src += src_stride; | 
 |     left_dst_start += src_stride; | 
 |     right_dst_start += src_stride; | 
 |   } | 
 |  | 
 |   /* Now copy the top and bottom lines into each line of the respective | 
 |    * borders | 
 |    */ | 
 |   top_src = src - extend_left; | 
 |   bot_src = src + src_stride * (height - 1) - extend_left; | 
 |   top_dst = src + src_stride * (-extend_top) - extend_left; | 
 |   bot_dst = src + src_stride * (height)-extend_left; | 
 |   linesize = extend_left + extend_right + width; | 
 |  | 
 |   for (i = 0; i < extend_top; i++) { | 
 |     memcpy(top_dst, top_src, linesize); | 
 |     top_dst += src_stride; | 
 |   } | 
 |  | 
 |   for (i = 0; i < extend_bottom; i++) { | 
 |     memcpy(bot_dst, bot_src, linesize); | 
 |     bot_dst += src_stride; | 
 |   } | 
 | } | 
 |  | 
 | static void extend_frame(YV12_BUFFER_CONFIG *const ybf, int ext_size) { | 
 |   const int c_w = ybf->uv_crop_width; | 
 |   const int c_h = ybf->uv_crop_height; | 
 |   const int ss_x = ybf->uv_width < ybf->y_width; | 
 |   const int ss_y = ybf->uv_height < ybf->y_height; | 
 |   const int c_et = ext_size >> ss_y; | 
 |   const int c_el = ext_size >> ss_x; | 
 |   const int c_eb = c_et + ybf->uv_height - ybf->uv_crop_height; | 
 |   const int c_er = c_el + ybf->uv_width - ybf->uv_crop_width; | 
 |  | 
 |   assert(ybf->y_height - ybf->y_crop_height < 16); | 
 |   assert(ybf->y_width - ybf->y_crop_width < 16); | 
 |   assert(ybf->y_height - ybf->y_crop_height >= 0); | 
 |   assert(ybf->y_width - ybf->y_crop_width >= 0); | 
 |  | 
 |   extend_plane(ybf->y_buffer, ybf->y_stride, ybf->y_crop_width, | 
 |                ybf->y_crop_height, ext_size, ext_size, | 
 |                ext_size + ybf->y_height - ybf->y_crop_height, | 
 |                ext_size + ybf->y_width - ybf->y_crop_width); | 
 |  | 
 |   extend_plane(ybf->u_buffer, ybf->uv_stride, c_w, c_h, c_et, c_el, c_eb, c_er); | 
 |  | 
 |   extend_plane(ybf->v_buffer, ybf->uv_stride, c_w, c_h, c_et, c_el, c_eb, c_er); | 
 | } | 
 |  | 
 | void aom_extend_frame_borders_dspr2(YV12_BUFFER_CONFIG *ybf, | 
 |                                     const int num_planes) { | 
 |   extend_frame(ybf, ybf->border, num_planes); | 
 | } | 
 |  | 
 | void aom_extend_frame_inner_borders_dspr2(YV12_BUFFER_CONFIG *ybf, | 
 |                                           const int num_planes) { | 
 |   const int inner_bw = (ybf->border > AOMINNERBORDERINPIXELS) | 
 |                            ? AOMINNERBORDERINPIXELS | 
 |                            : ybf->border; | 
 |   extend_frame(ybf, inner_bw, num_planes); | 
 | } | 
 | #endif |