diff options
Diffstat (limited to 'src/dsp/mask_blend.cc')
-rw-r--r-- | src/dsp/mask_blend.cc | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/src/dsp/mask_blend.cc b/src/dsp/mask_blend.cc new file mode 100644 index 0000000..101c410 --- /dev/null +++ b/src/dsp/mask_blend.cc @@ -0,0 +1,207 @@ +// 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 |