// Copyright 2021 The libgav1 Authors // // 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. #include "src/dsp/intrapred_filter.h" #include #include #include #include #include #include #include "src/dsp/constants.h" #include "src/dsp/dsp.h" #include "src/utils/common.h" #include "src/utils/constants.h" #include "src/utils/memory.h" namespace libgav1 { namespace dsp { namespace { //------------------------------------------------------------------------------ // FilterIntraPredictor_C // The recursive filter applies a different filter to the top 4 and 2 left // pixels to produce each pixel in a 4x2 sub-block. Each successive 4x2 uses the // prediction output of the blocks above and to the left, unless they are // adjacent to the |top_row| or |left_column|. The set of 8 filters is selected // according to |pred|. template void FilterIntraPredictor_C(void* LIBGAV1_RESTRICT const dest, ptrdiff_t stride, const void* LIBGAV1_RESTRICT const top_row, const void* LIBGAV1_RESTRICT const left_column, const FilterIntraPredictor pred, const int width, const int height) { const int kMaxPixel = (1 << bitdepth) - 1; const auto* const top = static_cast(top_row); const auto* const left = static_cast(left_column); assert(width <= 32 && height <= 32); Pixel buffer[3][33]; // cache 2 rows + top & left boundaries memcpy(buffer[0], &top[-1], (width + 1) * sizeof(top[0])); auto* dst = static_cast(dest); stride /= sizeof(Pixel); int row0 = 0, row2 = 2; int ystep = 1; int y = 0; do { buffer[1][0] = left[y]; buffer[row2][0] = left[y + 1]; int x = 1; do { const Pixel p0 = buffer[row0][x - 1]; // top-left const Pixel p1 = buffer[row0][x + 0]; // top 0 const Pixel p2 = buffer[row0][x + 1]; // top 1 const Pixel p3 = buffer[row0][x + 2]; // top 2 const Pixel p4 = buffer[row0][x + 3]; // top 3 const Pixel p5 = buffer[1][x - 1]; // left 0 const Pixel p6 = buffer[row2][x - 1]; // left 1 for (int i = 0; i < 8; ++i) { const int xoffset = i & 0x03; const int yoffset = (i >> 2) * ystep; const int value = kFilterIntraTaps[pred][i][0] * p0 + kFilterIntraTaps[pred][i][1] * p1 + kFilterIntraTaps[pred][i][2] * p2 + kFilterIntraTaps[pred][i][3] * p3 + kFilterIntraTaps[pred][i][4] * p4 + kFilterIntraTaps[pred][i][5] * p5 + kFilterIntraTaps[pred][i][6] * p6; // Section 7.11.2.3 specifies the right-hand side of the assignment as // Clip1( Round2Signed( pr, INTRA_FILTER_SCALE_BITS ) ). // Since Clip1() clips a negative value to 0, it is safe to replace // Round2Signed() with Round2(). buffer[1 + yoffset][x + xoffset] = static_cast( Clip3(RightShiftWithRounding(value, 4), 0, kMaxPixel)); } x += 4; } while (x < width); memcpy(dst, &buffer[1][1], width * sizeof(dst[0])); dst += stride; memcpy(dst, &buffer[row2][1], width * sizeof(dst[0])); dst += stride; // The final row becomes the top for the next pass. row0 ^= 2; row2 ^= 2; ystep = -ystep; y += 2; } while (y < height); } void Init8bpp() { Dsp* const dsp = dsp_internal::GetWritableDspTable(8); assert(dsp != nullptr); #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS dsp->filter_intra_predictor = FilterIntraPredictor_C<8, uint8_t>; #else // !LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS static_cast(dsp); #ifndef LIBGAV1_Dsp8bpp_FilterIntraPredictor dsp->filter_intra_predictor = FilterIntraPredictor_C<8, uint8_t>; #endif #endif // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS } #if LIBGAV1_MAX_BITDEPTH >= 10 void Init10bpp() { Dsp* const dsp = dsp_internal::GetWritableDspTable(10); assert(dsp != nullptr); #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS dsp->filter_intra_predictor = FilterIntraPredictor_C<10, uint16_t>; #else // !LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS static_cast(dsp); #ifndef LIBGAV1_Dsp10bpp_FilterIntraPredictor dsp->filter_intra_predictor = FilterIntraPredictor_C<10, uint16_t>; #endif #endif // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS } #endif // LIBGAV1_MAX_BITDEPTH >= 10 #if LIBGAV1_MAX_BITDEPTH == 12 void Init12bpp() { Dsp* const dsp = dsp_internal::GetWritableDspTable(12); assert(dsp != nullptr); #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS dsp->filter_intra_predictor = FilterIntraPredictor_C<12, uint16_t>; #else // !LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS static_cast(dsp); #ifndef LIBGAV1_Dsp12bpp_FilterIntraPredictor dsp->filter_intra_predictor = FilterIntraPredictor_C<12, uint16_t>; #endif #endif // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS } #endif // LIBGAV1_MAX_BITDEPTH == 12 } // namespace void IntraPredFilterInit_C() { Init8bpp(); #if LIBGAV1_MAX_BITDEPTH >= 10 Init10bpp(); #endif #if LIBGAV1_MAX_BITDEPTH == 12 Init12bpp(); #endif } } // namespace dsp } // namespace libgav1