| // Copyright 2019 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/mask_blend.h" |
| |
| #include <cassert> |
| #include <cstddef> |
| #include <cstdint> |
| |
| #include "src/dsp/dsp.h" |
| #include "src/utils/common.h" |
| |
| namespace libgav1 { |
| namespace dsp { |
| namespace { |
| |
| template <int subsampling_x, int subsampling_y> |
| uint8_t GetMaskValue(const uint8_t* mask, const uint8_t* mask_next_row, int x) { |
| if ((subsampling_x | subsampling_y) == 0) { |
| return mask[x]; |
| } |
| if (subsampling_x == 1 && subsampling_y == 0) { |
| return static_cast<uint8_t>(RightShiftWithRounding( |
| mask[MultiplyBy2(x)] + mask[MultiplyBy2(x) + 1], 1)); |
| } |
| assert(subsampling_x == 1 && subsampling_y == 1); |
| return static_cast<uint8_t>(RightShiftWithRounding( |
| mask[MultiplyBy2(x)] + mask[MultiplyBy2(x) + 1] + |
| mask_next_row[MultiplyBy2(x)] + mask_next_row[MultiplyBy2(x) + 1], |
| 2)); |
| } |
| |
| template <int bitdepth, typename Pixel, bool is_inter_intra, int subsampling_x, |
| int subsampling_y> |
| void MaskBlend_C(const void* prediction_0, const void* prediction_1, |
| const ptrdiff_t prediction_stride_1, const uint8_t* mask, |
| const ptrdiff_t mask_stride, const int width, const int height, |
| void* dest, const ptrdiff_t dest_stride) { |
| static_assert(!(bitdepth == 8 && is_inter_intra), ""); |
| assert(mask != nullptr); |
| using PredType = |
| typename std::conditional<bitdepth == 8, int16_t, uint16_t>::type; |
| const auto* pred_0 = static_cast<const PredType*>(prediction_0); |
| const auto* pred_1 = static_cast<const PredType*>(prediction_1); |
| auto* dst = static_cast<Pixel*>(dest); |
| const ptrdiff_t dst_stride = dest_stride / sizeof(Pixel); |
| constexpr int step_y = subsampling_y ? 2 : 1; |
| const uint8_t* mask_next_row = mask + mask_stride; |
| // 7.11.3.2 Rounding variables derivation process |
| // 2 * FILTER_BITS(7) - (InterRound0(3|5) + InterRound1(7)) |
| constexpr int inter_post_round_bits = (bitdepth == 12) ? 2 : 4; |
| for (int y = 0; y < height; ++y) { |
| for (int x = 0; x < width; ++x) { |
| const uint8_t mask_value = |
| GetMaskValue<subsampling_x, subsampling_y>(mask, mask_next_row, x); |
| if (is_inter_intra) { |
| dst[x] = static_cast<Pixel>(RightShiftWithRounding( |
| mask_value * pred_1[x] + (64 - mask_value) * pred_0[x], 6)); |
| } else { |
| assert(prediction_stride_1 == width); |
| int res = (mask_value * pred_0[x] + (64 - mask_value) * pred_1[x]) >> 6; |
| res -= (bitdepth == 8) ? 0 : kCompoundOffset; |
| dst[x] = static_cast<Pixel>( |
| Clip3(RightShiftWithRounding(res, inter_post_round_bits), 0, |
| (1 << bitdepth) - 1)); |
| } |
| } |
| dst += dst_stride; |
| mask += mask_stride * step_y; |
| mask_next_row += mask_stride * step_y; |
| pred_0 += width; |
| pred_1 += prediction_stride_1; |
| } |
| } |
| |
| template <int subsampling_x, int subsampling_y> |
| void InterIntraMaskBlend8bpp_C(const uint8_t* prediction_0, |
| uint8_t* prediction_1, |
| const ptrdiff_t prediction_stride_1, |
| const uint8_t* mask, const ptrdiff_t mask_stride, |
| const int width, const int height) { |
| assert(mask != nullptr); |
| constexpr int step_y = subsampling_y ? 2 : 1; |
| const uint8_t* mask_next_row = mask + mask_stride; |
| for (int y = 0; y < height; ++y) { |
| for (int x = 0; x < width; ++x) { |
| const uint8_t mask_value = |
| GetMaskValue<subsampling_x, subsampling_y>(mask, mask_next_row, x); |
| prediction_1[x] = static_cast<uint8_t>(RightShiftWithRounding( |
| mask_value * prediction_1[x] + (64 - mask_value) * prediction_0[x], |
| 6)); |
| } |
| mask += mask_stride * step_y; |
| mask_next_row += mask_stride * step_y; |
| prediction_0 += width; |
| prediction_1 += prediction_stride_1; |
| } |
| } |
| |
| void Init8bpp() { |
| Dsp* const dsp = dsp_internal::GetWritableDspTable(8); |
| assert(dsp != nullptr); |
| #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS |
| dsp->mask_blend[0][0] = MaskBlend_C<8, uint8_t, false, 0, 0>; |
| dsp->mask_blend[1][0] = MaskBlend_C<8, uint8_t, false, 1, 0>; |
| dsp->mask_blend[2][0] = MaskBlend_C<8, uint8_t, false, 1, 1>; |
| // The is_inter_intra index of mask_blend[][] is replaced by |
| // inter_intra_mask_blend_8bpp[] in 8-bit. |
| dsp->mask_blend[0][1] = nullptr; |
| dsp->mask_blend[1][1] = nullptr; |
| dsp->mask_blend[2][1] = nullptr; |
| dsp->inter_intra_mask_blend_8bpp[0] = InterIntraMaskBlend8bpp_C<0, 0>; |
| dsp->inter_intra_mask_blend_8bpp[1] = InterIntraMaskBlend8bpp_C<1, 0>; |
| dsp->inter_intra_mask_blend_8bpp[2] = InterIntraMaskBlend8bpp_C<1, 1>; |
| #else // !LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS |
| static_cast<void>(dsp); |
| #ifndef LIBGAV1_Dsp8bpp_MaskBlend444 |
| dsp->mask_blend[0][0] = MaskBlend_C<8, uint8_t, false, 0, 0>; |
| #endif |
| #ifndef LIBGAV1_Dsp8bpp_MaskBlend422 |
| dsp->mask_blend[1][0] = MaskBlend_C<8, uint8_t, false, 1, 0>; |
| #endif |
| #ifndef LIBGAV1_Dsp8bpp_MaskBlend420 |
| dsp->mask_blend[2][0] = MaskBlend_C<8, uint8_t, false, 1, 1>; |
| #endif |
| // The is_inter_intra index of mask_blend[][] is replaced by |
| // inter_intra_mask_blend_8bpp[] in 8-bit. |
| dsp->mask_blend[0][1] = nullptr; |
| dsp->mask_blend[1][1] = nullptr; |
| dsp->mask_blend[2][1] = nullptr; |
| #ifndef LIBGAV1_Dsp8bpp_InterIntraMaskBlend8bpp444 |
| dsp->inter_intra_mask_blend_8bpp[0] = InterIntraMaskBlend8bpp_C<0, 0>; |
| #endif |
| #ifndef LIBGAV1_Dsp8bpp_InterIntraMaskBlend8bpp422 |
| dsp->inter_intra_mask_blend_8bpp[1] = InterIntraMaskBlend8bpp_C<1, 0>; |
| #endif |
| #ifndef LIBGAV1_Dsp8bpp_InterIntraMaskBlend8bpp420 |
| dsp->inter_intra_mask_blend_8bpp[2] = InterIntraMaskBlend8bpp_C<1, 1>; |
| #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->mask_blend[0][0] = MaskBlend_C<10, uint16_t, false, 0, 0>; |
| dsp->mask_blend[1][0] = MaskBlend_C<10, uint16_t, false, 1, 0>; |
| dsp->mask_blend[2][0] = MaskBlend_C<10, uint16_t, false, 1, 1>; |
| dsp->mask_blend[0][1] = MaskBlend_C<10, uint16_t, true, 0, 0>; |
| dsp->mask_blend[1][1] = MaskBlend_C<10, uint16_t, true, 1, 0>; |
| dsp->mask_blend[2][1] = MaskBlend_C<10, uint16_t, true, 1, 1>; |
| // These are only used with 8-bit. |
| dsp->inter_intra_mask_blend_8bpp[0] = nullptr; |
| dsp->inter_intra_mask_blend_8bpp[1] = nullptr; |
| dsp->inter_intra_mask_blend_8bpp[2] = nullptr; |
| #else // !LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS |
| static_cast<void>(dsp); |
| #ifndef LIBGAV1_Dsp10bpp_MaskBlend444 |
| dsp->mask_blend[0][0] = MaskBlend_C<10, uint16_t, false, 0, 0>; |
| #endif |
| #ifndef LIBGAV1_Dsp10bpp_MaskBlend422 |
| dsp->mask_blend[1][0] = MaskBlend_C<10, uint16_t, false, 1, 0>; |
| #endif |
| #ifndef LIBGAV1_Dsp10bpp_MaskBlend420 |
| dsp->mask_blend[2][0] = MaskBlend_C<10, uint16_t, false, 1, 1>; |
| #endif |
| #ifndef LIBGAV1_Dsp10bpp_MaskBlendInterIntra444 |
| dsp->mask_blend[0][1] = MaskBlend_C<10, uint16_t, true, 0, 0>; |
| #endif |
| #ifndef LIBGAV1_Dsp10bpp_MaskBlendInterIntra422 |
| dsp->mask_blend[1][1] = MaskBlend_C<10, uint16_t, true, 1, 0>; |
| #endif |
| #ifndef LIBGAV1_Dsp10bpp_MaskBlendInterIntra420 |
| dsp->mask_blend[2][1] = MaskBlend_C<10, uint16_t, true, 1, 1>; |
| #endif |
| // These are only used with 8-bit. |
| dsp->inter_intra_mask_blend_8bpp[0] = nullptr; |
| dsp->inter_intra_mask_blend_8bpp[1] = nullptr; |
| dsp->inter_intra_mask_blend_8bpp[2] = nullptr; |
| #endif // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS |
| } |
| #endif |
| |
| } // namespace |
| |
| void MaskBlendInit_C() { |
| Init8bpp(); |
| #if LIBGAV1_MAX_BITDEPTH >= 10 |
| Init10bpp(); |
| #endif |
| } |
| |
| } // namespace dsp |
| } // namespace libgav1 |