• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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/intrapred_directional.h"
16 
17 #include <cassert>
18 #include <cstddef>
19 #include <cstdint>
20 #include <cstring>
21 
22 #include "src/dsp/constants.h"
23 #include "src/dsp/dsp.h"
24 #include "src/utils/common.h"
25 #include "src/utils/constants.h"
26 #include "src/utils/memory.h"
27 
28 namespace libgav1 {
29 namespace dsp {
30 namespace {
31 
32 //------------------------------------------------------------------------------
33 // 7.11.2.4. Directional intra prediction process
34 
35 template <typename Pixel>
DirectionalIntraPredictorZone1_C(void * const dest,ptrdiff_t stride,const void * const top_row,const int width,const int height,const int xstep,const bool upsampled_top)36 void DirectionalIntraPredictorZone1_C(void* const dest, ptrdiff_t stride,
37                                       const void* const top_row,
38                                       const int width, const int height,
39                                       const int xstep,
40                                       const bool upsampled_top) {
41   const auto* const top = static_cast<const Pixel*>(top_row);
42   auto* dst = static_cast<Pixel*>(dest);
43   stride /= sizeof(Pixel);
44 
45   assert(xstep > 0);
46 
47   // If xstep == 64 then |shift| always evaluates to 0 which sets |val| to
48   // |top[top_base_x]|. This corresponds to a 45 degree prediction.
49   if (xstep == 64) {
50     // 7.11.2.10. Intra edge upsample selection process
51     // if ( d <= 0 || d >= 40 ) useUpsample = 0
52     // For |upsampled_top| the delta is |predictor_angle - 90|. Since the
53     // |predictor_angle| is 45 the delta is also 45.
54     assert(!upsampled_top);
55     const Pixel* top_ptr = top + 1;
56     for (int y = 0; y < height; ++y, dst += stride, ++top_ptr) {
57       memcpy(dst, top_ptr, sizeof(*top_ptr) * width);
58     }
59     return;
60   }
61 
62   const int upsample_shift = static_cast<int>(upsampled_top);
63   const int max_base_x = ((width + height) - 1) << upsample_shift;
64   const int scale_bits = 6 - upsample_shift;
65   const int base_step = 1 << upsample_shift;
66   int top_x = xstep;
67   int y = 0;
68   do {
69     int top_base_x = top_x >> scale_bits;
70 
71     if (top_base_x >= max_base_x) {
72       for (int i = y; i < height; ++i) {
73         Memset(dst, top[max_base_x], width);
74         dst += stride;
75       }
76       return;
77     }
78 
79     const int shift = ((top_x << upsample_shift) & 0x3F) >> 1;
80     int x = 0;
81     do {
82       if (top_base_x >= max_base_x) {
83         Memset(dst + x, top[max_base_x], width - x);
84         break;
85       }
86 
87       const int val =
88           top[top_base_x] * (32 - shift) + top[top_base_x + 1] * shift;
89       dst[x] = RightShiftWithRounding(val, 5 /*log2(32)*/);
90       top_base_x += base_step;
91     } while (++x < width);
92 
93     dst += stride;
94     top_x += xstep;
95   } while (++y < height);
96 }
97 
98 template <typename Pixel>
DirectionalIntraPredictorZone2_C(void * const dest,ptrdiff_t stride,const void * const top_row,const void * const left_column,const int width,const int height,const int xstep,const int ystep,const bool upsampled_top,const bool upsampled_left)99 void DirectionalIntraPredictorZone2_C(void* const dest, ptrdiff_t stride,
100                                       const void* const top_row,
101                                       const void* const left_column,
102                                       const int width, const int height,
103                                       const int xstep, const int ystep,
104                                       const bool upsampled_top,
105                                       const bool upsampled_left) {
106   const auto* const top = static_cast<const Pixel*>(top_row);
107   const auto* const left = static_cast<const Pixel*>(left_column);
108   auto* dst = static_cast<Pixel*>(dest);
109   stride /= sizeof(Pixel);
110 
111   assert(xstep > 0);
112   assert(ystep > 0);
113 
114   const int upsample_top_shift = static_cast<int>(upsampled_top);
115   const int upsample_left_shift = static_cast<int>(upsampled_left);
116   const int scale_bits_x = 6 - upsample_top_shift;
117   const int scale_bits_y = 6 - upsample_left_shift;
118   const int min_base_x = -(1 << upsample_top_shift);
119   const int base_step_x = 1 << upsample_top_shift;
120   int y = 0;
121   int top_x = -xstep;
122   do {
123     int top_base_x = top_x >> scale_bits_x;
124     int left_y = (y << 6) - ystep;
125     int x = 0;
126     do {
127       int val;
128       if (top_base_x >= min_base_x) {
129         const int shift = ((top_x * (1 << upsample_top_shift)) & 0x3F) >> 1;
130         val = top[top_base_x] * (32 - shift) + top[top_base_x + 1] * shift;
131       } else {
132         // Note this assumes an arithmetic shift to handle negative values.
133         const int left_base_y = left_y >> scale_bits_y;
134         const int shift = ((left_y * (1 << upsample_left_shift)) & 0x3F) >> 1;
135         assert(left_base_y >= -(1 << upsample_left_shift));
136         val = left[left_base_y] * (32 - shift) + left[left_base_y + 1] * shift;
137       }
138       dst[x] = RightShiftWithRounding(val, 5);
139       top_base_x += base_step_x;
140       left_y -= ystep;
141     } while (++x < width);
142 
143     top_x -= xstep;
144     dst += stride;
145   } while (++y < height);
146 }
147 
148 template <typename Pixel>
DirectionalIntraPredictorZone3_C(void * const dest,ptrdiff_t stride,const void * const left_column,const int width,const int height,const int ystep,const bool upsampled_left)149 void DirectionalIntraPredictorZone3_C(void* const dest, ptrdiff_t stride,
150                                       const void* const left_column,
151                                       const int width, const int height,
152                                       const int ystep,
153                                       const bool upsampled_left) {
154   const auto* const left = static_cast<const Pixel*>(left_column);
155   stride /= sizeof(Pixel);
156 
157   assert(ystep > 0);
158 
159   const int upsample_shift = static_cast<int>(upsampled_left);
160   const int scale_bits = 6 - upsample_shift;
161   const int base_step = 1 << upsample_shift;
162   // Zone3 never runs out of left_column values.
163   assert((width + height - 1) << upsample_shift >  // max_base_y
164          ((ystep * width) >> scale_bits) +
165              base_step * (height - 1));  // left_base_y
166 
167   int left_y = ystep;
168   int x = 0;
169   do {
170     auto* dst = static_cast<Pixel*>(dest);
171 
172     int left_base_y = left_y >> scale_bits;
173     int y = 0;
174     do {
175       const int shift = ((left_y << upsample_shift) & 0x3F) >> 1;
176       const int val =
177           left[left_base_y] * (32 - shift) + left[left_base_y + 1] * shift;
178       dst[x] = RightShiftWithRounding(val, 5);
179       dst += stride;
180       left_base_y += base_step;
181     } while (++y < height);
182 
183     left_y += ystep;
184   } while (++x < width);
185 }
186 
Init8bpp()187 void Init8bpp() {
188   Dsp* const dsp = dsp_internal::GetWritableDspTable(8);
189   assert(dsp != nullptr);
190 #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
191   dsp->directional_intra_predictor_zone1 =
192       DirectionalIntraPredictorZone1_C<uint8_t>;
193   dsp->directional_intra_predictor_zone2 =
194       DirectionalIntraPredictorZone2_C<uint8_t>;
195   dsp->directional_intra_predictor_zone3 =
196       DirectionalIntraPredictorZone3_C<uint8_t>;
197 #else  // !LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
198   static_cast<void>(dsp);
199 #ifndef LIBGAV1_Dsp8bpp_DirectionalIntraPredictorZone1
200   dsp->directional_intra_predictor_zone1 =
201       DirectionalIntraPredictorZone1_C<uint8_t>;
202 #endif
203 #ifndef LIBGAV1_Dsp8bpp_DirectionalIntraPredictorZone2
204   dsp->directional_intra_predictor_zone2 =
205       DirectionalIntraPredictorZone2_C<uint8_t>;
206 #endif
207 #ifndef LIBGAV1_Dsp8bpp_DirectionalIntraPredictorZone3
208   dsp->directional_intra_predictor_zone3 =
209       DirectionalIntraPredictorZone3_C<uint8_t>;
210 #endif
211 #endif  // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
212 }
213 
214 #if LIBGAV1_MAX_BITDEPTH >= 10
Init10bpp()215 void Init10bpp() {
216   Dsp* const dsp = dsp_internal::GetWritableDspTable(10);
217   assert(dsp != nullptr);
218 #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
219   dsp->directional_intra_predictor_zone1 =
220       DirectionalIntraPredictorZone1_C<uint16_t>;
221   dsp->directional_intra_predictor_zone2 =
222       DirectionalIntraPredictorZone2_C<uint16_t>;
223   dsp->directional_intra_predictor_zone3 =
224       DirectionalIntraPredictorZone3_C<uint16_t>;
225 #endif  // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
226   static_cast<void>(dsp);
227 #ifndef LIBGAV1_Dsp10bpp_DirectionalIntraPredictorZone1
228   dsp->directional_intra_predictor_zone1 =
229       DirectionalIntraPredictorZone1_C<uint16_t>;
230 #endif
231 #ifndef LIBGAV1_Dsp10bpp_DirectionalIntraPredictorZone2
232   dsp->directional_intra_predictor_zone2 =
233       DirectionalIntraPredictorZone2_C<uint16_t>;
234 #endif
235 #ifndef LIBGAV1_Dsp10bpp_DirectionalIntraPredictorZone3
236   dsp->directional_intra_predictor_zone3 =
237       DirectionalIntraPredictorZone3_C<uint16_t>;
238 #endif
239 }
240 #endif  // LIBGAV1_MAX_BITDEPTH >= 10
241 
242 }  // namespace
243 
IntraPredDirectionalInit_C()244 void IntraPredDirectionalInit_C() {
245   Init8bpp();
246 #if LIBGAV1_MAX_BITDEPTH >= 10
247   Init10bpp();
248 #endif
249 }
250 
251 }  // namespace dsp
252 }  // namespace libgav1
253