// Copyright 2020 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/super_res.h" #include #include "src/dsp/dsp.h" #include "src/utils/common.h" #include "src/utils/constants.h" namespace libgav1 { namespace dsp { namespace { template void SuperRes_C(const void* /*coefficients*/, void* const source, const ptrdiff_t source_stride, const int height, const int downscaled_width, const int upscaled_width, const int initial_subpixel_x, const int step, void* const dest, ptrdiff_t dest_stride) { assert(step <= 1 << kSuperResScaleBits); auto* src = static_cast(source) - DivideBy2(kSuperResFilterTaps); auto* dst = static_cast(dest); int y = height; do { ExtendLine(src + DivideBy2(kSuperResFilterTaps), downscaled_width, kSuperResHorizontalBorder, kSuperResHorizontalBorder); // If (original) upscaled_width is <= 9, the downscaled_width may be // upscaled_width - 1 (i.e. 8, 9), and become the same (i.e. 4) when // subsampled via RightShiftWithRounding. This leads to an edge case where // |step| == 1 << 14. int subpixel_x = initial_subpixel_x; int x = 0; do { int sum = 0; const Pixel* const src_x = &src[subpixel_x >> kSuperResScaleBits]; const int src_x_subpixel = (subpixel_x & kSuperResScaleMask) >> kSuperResExtraBits; // The sign of each tap is: - + - + + - + - sum -= src_x[0] * kUpscaleFilterUnsigned[src_x_subpixel][0]; sum += src_x[1] * kUpscaleFilterUnsigned[src_x_subpixel][1]; sum -= src_x[2] * kUpscaleFilterUnsigned[src_x_subpixel][2]; sum += src_x[3] * kUpscaleFilterUnsigned[src_x_subpixel][3]; sum += src_x[4] * kUpscaleFilterUnsigned[src_x_subpixel][4]; sum -= src_x[5] * kUpscaleFilterUnsigned[src_x_subpixel][5]; sum += src_x[6] * kUpscaleFilterUnsigned[src_x_subpixel][6]; sum -= src_x[7] * kUpscaleFilterUnsigned[src_x_subpixel][7]; dst[x] = Clip3(RightShiftWithRounding(sum, kFilterBits), 0, (1 << bitdepth) - 1); subpixel_x += step; } while (++x < upscaled_width); src += source_stride; dst += dest_stride; } while (--y != 0); } void Init8bpp() { Dsp* dsp = dsp_internal::GetWritableDspTable(8); assert(dsp != nullptr); dsp->super_res_coefficients = nullptr; #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS dsp->super_res = SuperRes_C<8, uint8_t>; #else // !LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS static_cast(dsp); #ifndef LIBGAV1_Dsp8bpp_SuperRes dsp->super_res = SuperRes_C<8, uint8_t>; #endif #endif // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS } #if LIBGAV1_MAX_BITDEPTH >= 10 void Init10bpp() { Dsp* dsp = dsp_internal::GetWritableDspTable(10); assert(dsp != nullptr); dsp->super_res_coefficients = nullptr; #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS dsp->super_res = SuperRes_C<10, uint16_t>; #else // !LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS static_cast(dsp); #ifndef LIBGAV1_Dsp10bpp_SuperRes dsp->super_res = SuperRes_C<10, uint16_t>; #endif #endif // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS } #endif } // namespace void SuperResInit_C() { Init8bpp(); #if LIBGAV1_MAX_BITDEPTH >= 10 Init10bpp(); #endif } } // namespace dsp } // namespace libgav1