• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The libgav1 Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/dsp/mask_blend.h"
16 
17 #include <cassert>
18 #include <cstddef>
19 #include <cstdint>
20 
21 #include "src/dsp/dsp.h"
22 #include "src/utils/common.h"
23 
24 namespace libgav1 {
25 namespace dsp {
26 namespace {
27 
GetMaskValue(const uint8_t * mask,const uint8_t * mask_next_row,int x,int subsampling_x,int subsampling_y)28 uint8_t GetMaskValue(const uint8_t* mask, const uint8_t* mask_next_row, int x,
29                      int subsampling_x, int subsampling_y) {
30   if ((subsampling_x | subsampling_y) == 0) {
31     return mask[x];
32   }
33   if (subsampling_x == 1 && subsampling_y == 0) {
34     return static_cast<uint8_t>(RightShiftWithRounding(
35         mask[MultiplyBy2(x)] + mask[MultiplyBy2(x) + 1], 1));
36   }
37   assert(subsampling_x == 1 && subsampling_y == 1);
38   return static_cast<uint8_t>(RightShiftWithRounding(
39       mask[MultiplyBy2(x)] + mask[MultiplyBy2(x) + 1] +
40           mask_next_row[MultiplyBy2(x)] + mask_next_row[MultiplyBy2(x) + 1],
41       2));
42 }
43 
44 template <int bitdepth, typename Pixel, bool is_inter_intra, int subsampling_x,
45           int subsampling_y>
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)46 void MaskBlend_C(const void* prediction_0, const void* prediction_1,
47                  const ptrdiff_t prediction_stride_1, const uint8_t* mask,
48                  const ptrdiff_t mask_stride, const int width, const int height,
49                  void* dest, const ptrdiff_t dest_stride) {
50   static_assert(!(bitdepth == 8 && is_inter_intra), "");
51   assert(mask != nullptr);
52   using PredType =
53       typename std::conditional<bitdepth == 8, int16_t, uint16_t>::type;
54   const auto* pred_0 = static_cast<const PredType*>(prediction_0);
55   const auto* pred_1 = static_cast<const PredType*>(prediction_1);
56   auto* dst = static_cast<Pixel*>(dest);
57   const ptrdiff_t dst_stride = dest_stride / sizeof(Pixel);
58   constexpr int step_y = subsampling_y ? 2 : 1;
59   const uint8_t* mask_next_row = mask + mask_stride;
60   // 7.11.3.2 Rounding variables derivation process
61   //   2 * FILTER_BITS(7) - (InterRound0(3|5) + InterRound1(7))
62   constexpr int inter_post_round_bits = (bitdepth == 12) ? 2 : 4;
63   for (int y = 0; y < height; ++y) {
64     for (int x = 0; x < width; ++x) {
65       const uint8_t mask_value =
66           GetMaskValue(mask, mask_next_row, x, subsampling_x, subsampling_y);
67       if (is_inter_intra) {
68         dst[x] = static_cast<Pixel>(RightShiftWithRounding(
69             mask_value * pred_1[x] + (64 - mask_value) * pred_0[x], 6));
70       } else {
71         assert(prediction_stride_1 == width);
72         int res = (mask_value * pred_0[x] + (64 - mask_value) * pred_1[x]) >> 6;
73         res -= (bitdepth == 8) ? 0 : kCompoundOffset;
74         dst[x] = static_cast<Pixel>(
75             Clip3(RightShiftWithRounding(res, inter_post_round_bits), 0,
76                   (1 << bitdepth) - 1));
77       }
78     }
79     dst += dst_stride;
80     mask += mask_stride * step_y;
81     mask_next_row += mask_stride * step_y;
82     pred_0 += width;
83     pred_1 += prediction_stride_1;
84   }
85 }
86 
87 template <int subsampling_x, int subsampling_y>
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)88 void InterIntraMaskBlend8bpp_C(const uint8_t* prediction_0,
89                                uint8_t* prediction_1,
90                                const ptrdiff_t prediction_stride_1,
91                                const uint8_t* mask, const ptrdiff_t mask_stride,
92                                const int width, const int height) {
93   assert(mask != nullptr);
94   constexpr int step_y = subsampling_y ? 2 : 1;
95   const uint8_t* mask_next_row = mask + mask_stride;
96   for (int y = 0; y < height; ++y) {
97     for (int x = 0; x < width; ++x) {
98       const uint8_t mask_value =
99           GetMaskValue(mask, mask_next_row, x, subsampling_x, subsampling_y);
100       prediction_1[x] = static_cast<uint8_t>(RightShiftWithRounding(
101           mask_value * prediction_1[x] + (64 - mask_value) * prediction_0[x],
102           6));
103     }
104     mask += mask_stride * step_y;
105     mask_next_row += mask_stride * step_y;
106     prediction_0 += width;
107     prediction_1 += prediction_stride_1;
108   }
109 }
110 
Init8bpp()111 void Init8bpp() {
112   Dsp* const dsp = dsp_internal::GetWritableDspTable(8);
113   assert(dsp != nullptr);
114 #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
115   dsp->mask_blend[0][0] = MaskBlend_C<8, uint8_t, false, 0, 0>;
116   dsp->mask_blend[1][0] = MaskBlend_C<8, uint8_t, false, 1, 0>;
117   dsp->mask_blend[2][0] = MaskBlend_C<8, uint8_t, false, 1, 1>;
118   // The is_inter_intra index of mask_blend[][] is replaced by
119   // inter_intra_mask_blend_8bpp[] in 8-bit.
120   dsp->mask_blend[0][1] = nullptr;
121   dsp->mask_blend[1][1] = nullptr;
122   dsp->mask_blend[2][1] = nullptr;
123   dsp->inter_intra_mask_blend_8bpp[0] = InterIntraMaskBlend8bpp_C<0, 0>;
124   dsp->inter_intra_mask_blend_8bpp[1] = InterIntraMaskBlend8bpp_C<1, 0>;
125   dsp->inter_intra_mask_blend_8bpp[2] = InterIntraMaskBlend8bpp_C<1, 1>;
126 #else  // !LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
127   static_cast<void>(dsp);
128 #ifndef LIBGAV1_Dsp8bpp_MaskBlend444
129   dsp->mask_blend[0][0] = MaskBlend_C<8, uint8_t, false, 0, 0>;
130 #endif
131 #ifndef LIBGAV1_Dsp8bpp_MaskBlend422
132   dsp->mask_blend[1][0] = MaskBlend_C<8, uint8_t, false, 1, 0>;
133 #endif
134 #ifndef LIBGAV1_Dsp8bpp_MaskBlend420
135   dsp->mask_blend[2][0] = MaskBlend_C<8, uint8_t, false, 1, 1>;
136 #endif
137   // The is_inter_intra index of mask_blend[][] is replaced by
138   // inter_intra_mask_blend_8bpp[] in 8-bit.
139   dsp->mask_blend[0][1] = nullptr;
140   dsp->mask_blend[1][1] = nullptr;
141   dsp->mask_blend[2][1] = nullptr;
142 #ifndef LIBGAV1_Dsp8bpp_InterIntraMaskBlend8bpp444
143   dsp->inter_intra_mask_blend_8bpp[0] = InterIntraMaskBlend8bpp_C<0, 0>;
144 #endif
145 #ifndef LIBGAV1_Dsp8bpp_InterIntraMaskBlend8bpp422
146   dsp->inter_intra_mask_blend_8bpp[1] = InterIntraMaskBlend8bpp_C<1, 0>;
147 #endif
148 #ifndef LIBGAV1_Dsp8bpp_InterIntraMaskBlend8bpp420
149   dsp->inter_intra_mask_blend_8bpp[2] = InterIntraMaskBlend8bpp_C<1, 1>;
150 #endif
151   static_cast<void>(GetMaskValue);
152 #endif  // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
153 }
154 
155 #if LIBGAV1_MAX_BITDEPTH >= 10
Init10bpp()156 void Init10bpp() {
157   Dsp* const dsp = dsp_internal::GetWritableDspTable(10);
158   assert(dsp != nullptr);
159 #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
160   dsp->mask_blend[0][0] = MaskBlend_C<10, uint16_t, false, 0, 0>;
161   dsp->mask_blend[1][0] = MaskBlend_C<10, uint16_t, false, 1, 0>;
162   dsp->mask_blend[2][0] = MaskBlend_C<10, uint16_t, false, 1, 1>;
163   dsp->mask_blend[0][1] = MaskBlend_C<10, uint16_t, true, 0, 0>;
164   dsp->mask_blend[1][1] = MaskBlend_C<10, uint16_t, true, 1, 0>;
165   dsp->mask_blend[2][1] = MaskBlend_C<10, uint16_t, true, 1, 1>;
166   // These are only used with 8-bit.
167   dsp->inter_intra_mask_blend_8bpp[0] = nullptr;
168   dsp->inter_intra_mask_blend_8bpp[1] = nullptr;
169   dsp->inter_intra_mask_blend_8bpp[2] = nullptr;
170 #else  // !LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
171   static_cast<void>(dsp);
172 #ifndef LIBGAV1_Dsp10bpp_MaskBlend444
173   dsp->mask_blend[0][0] = MaskBlend_C<10, uint16_t, false, 0, 0>;
174 #endif
175 #ifndef LIBGAV1_Dsp10bpp_MaskBlend422
176   dsp->mask_blend[1][0] = MaskBlend_C<10, uint16_t, false, 1, 0>;
177 #endif
178 #ifndef LIBGAV1_Dsp10bpp_MaskBlend420
179   dsp->mask_blend[2][0] = MaskBlend_C<10, uint16_t, false, 1, 1>;
180 #endif
181 #ifndef LIBGAV1_Dsp10bpp_MaskBlendInterIntra444
182   dsp->mask_blend[0][1] = MaskBlend_C<10, uint16_t, true, 0, 0>;
183 #endif
184 #ifndef LIBGAV1_Dsp10bpp_MaskBlendInterIntra422
185   dsp->mask_blend[1][1] = MaskBlend_C<10, uint16_t, true, 1, 0>;
186 #endif
187 #ifndef LIBGAV1_Dsp10bpp_MaskBlendInterIntra420
188   dsp->mask_blend[2][1] = MaskBlend_C<10, uint16_t, true, 1, 1>;
189 #endif
190   // These are only used with 8-bit.
191   dsp->inter_intra_mask_blend_8bpp[0] = nullptr;
192   dsp->inter_intra_mask_blend_8bpp[1] = nullptr;
193   dsp->inter_intra_mask_blend_8bpp[2] = nullptr;
194 #endif  // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
195 }
196 #endif
197 
198 }  // namespace
199 
MaskBlendInit_C()200 void MaskBlendInit_C() {
201   Init8bpp();
202 #if LIBGAV1_MAX_BITDEPTH >= 10
203   Init10bpp();
204 #endif
205 }
206 
207 }  // namespace dsp
208 }  // namespace libgav1
209