| // 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 <cassert> |
| |
| #include "src/dsp/dsp.h" |
| #include "src/utils/common.h" |
| #include "src/utils/constants.h" |
| |
| namespace libgav1 { |
| namespace dsp { |
| namespace { |
| |
| template <int bitdepth, typename Pixel> |
| void SuperRes_C(const void* /*coefficients*/, void* const source, |
| const ptrdiff_t stride, const int height, |
| const int downscaled_width, const int upscaled_width, |
| const int initial_subpixel_x, const int step, |
| void* const dest) { |
| assert(step <= 1 << kSuperResScaleBits); |
| auto* src = static_cast<Pixel*>(source) - DivideBy2(kSuperResFilterTaps); |
| auto* dst = static_cast<Pixel*>(dest); |
| int y = height; |
| do { |
| ExtendLine<Pixel>(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 += stride; |
| dst += 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<void>(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<void>(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 |