xref: /aosp_15_r20/external/libgav1/src/dsp/intrapred_directional.cc (revision 095378508e87ed692bf8dfeb34008b65b3735891)
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 * LIBGAV1_RESTRICT const dest,ptrdiff_t stride,const void * LIBGAV1_RESTRICT const top_row,const int width,const int height,const int xstep,const bool upsampled_top)36 void DirectionalIntraPredictorZone1_C(
37     void* LIBGAV1_RESTRICT const dest, ptrdiff_t stride,
38     const void* LIBGAV1_RESTRICT const top_row, const int width,
39     const int height, const int xstep, const bool upsampled_top) {
40   const auto* const top = static_cast<const Pixel*>(top_row);
41   auto* dst = static_cast<Pixel*>(dest);
42   stride /= sizeof(Pixel);
43 
44   assert(xstep > 0);
45 
46   // If xstep == 64 then |shift| always evaluates to 0 which sets |val| to
47   // |top[top_base_x]|. This corresponds to a 45 degree prediction.
48   if (xstep == 64) {
49     // 7.11.2.10. Intra edge upsample selection process
50     // if ( d <= 0 || d >= 40 ) useUpsample = 0
51     // For |upsampled_top| the delta is |predictor_angle - 90|. Since the
52     // |predictor_angle| is 45 the delta is also 45.
53     assert(!upsampled_top);
54     const Pixel* top_ptr = top + 1;
55     for (int y = 0; y < height; ++y, dst += stride, ++top_ptr) {
56       memcpy(dst, top_ptr, sizeof(*top_ptr) * width);
57     }
58     return;
59   }
60 
61   const int upsample_shift = static_cast<int>(upsampled_top);
62   const int max_base_x = ((width + height) - 1) << upsample_shift;
63   const int scale_bits = 6 - upsample_shift;
64   const int base_step = 1 << upsample_shift;
65   int top_x = xstep;
66   int y = 0;
67   do {
68     int top_base_x = top_x >> scale_bits;
69 
70     if (top_base_x >= max_base_x) {
71       for (int i = y; i < height; ++i) {
72         Memset(dst, top[max_base_x], width);
73         dst += stride;
74       }
75       return;
76     }
77 
78     const int shift = ((top_x << upsample_shift) & 0x3F) >> 1;
79     int x = 0;
80     do {
81       if (top_base_x >= max_base_x) {
82         Memset(dst + x, top[max_base_x], width - x);
83         break;
84       }
85 
86       const int val =
87           top[top_base_x] * (32 - shift) + top[top_base_x + 1] * shift;
88       dst[x] = RightShiftWithRounding(val, 5 /*log2(32)*/);
89       top_base_x += base_step;
90     } while (++x < width);
91 
92     dst += stride;
93     top_x += xstep;
94   } while (++y < height);
95 }
96 
97 // clang 14.0.0 produces incorrect code with LIBGAV1_RESTRICT.
98 // https://github.com/llvm/llvm-project/issues/54427
99 #if defined(__clang__) && __clang_major__ == 14
100 #define LOCAL_RESTRICT
101 #else
102 #define LOCAL_RESTRICT LIBGAV1_RESTRICT
103 #endif
104 
105 template <typename Pixel>
DirectionalIntraPredictorZone2_C(void * LOCAL_RESTRICT const dest,ptrdiff_t stride,const void * LOCAL_RESTRICT const top_row,const void * LOCAL_RESTRICT const left_column,const int width,const int height,const int xstep,const int ystep,const bool upsampled_top,const bool upsampled_left)106 void DirectionalIntraPredictorZone2_C(
107     void* LOCAL_RESTRICT const dest, ptrdiff_t stride,
108     const void* LOCAL_RESTRICT const top_row,
109     const void* LOCAL_RESTRICT const left_column, const int width,
110     const int height, const int xstep, const int ystep,
111     const bool upsampled_top, const bool upsampled_left) {
112   const auto* const top = static_cast<const Pixel*>(top_row);
113   const auto* const left = static_cast<const Pixel*>(left_column);
114   auto* dst = static_cast<Pixel*>(dest);
115   stride /= sizeof(Pixel);
116 
117   assert(xstep > 0);
118   assert(ystep > 0);
119 
120   const int upsample_top_shift = static_cast<int>(upsampled_top);
121   const int upsample_left_shift = static_cast<int>(upsampled_left);
122   const int scale_bits_x = 6 - upsample_top_shift;
123   const int scale_bits_y = 6 - upsample_left_shift;
124   const int min_base_x = -(1 << upsample_top_shift);
125   const int base_step_x = 1 << upsample_top_shift;
126   int y = 0;
127   int top_x = -xstep;
128   do {
129     int top_base_x = top_x >> scale_bits_x;
130     int left_y = (y << 6) - ystep;
131     int x = 0;
132     do {
133       int val;
134       if (top_base_x >= min_base_x) {
135         const int shift = ((top_x * (1 << upsample_top_shift)) & 0x3F) >> 1;
136         val = top[top_base_x] * (32 - shift) + top[top_base_x + 1] * shift;
137       } else {
138         // Note this assumes an arithmetic shift to handle negative values.
139         const int left_base_y = left_y >> scale_bits_y;
140         const int shift = ((left_y * (1 << upsample_left_shift)) & 0x3F) >> 1;
141         assert(left_base_y >= -(1 << upsample_left_shift));
142         val = left[left_base_y] * (32 - shift) + left[left_base_y + 1] * shift;
143       }
144       dst[x] = RightShiftWithRounding(val, 5);
145       top_base_x += base_step_x;
146       left_y -= ystep;
147     } while (++x < width);
148 
149     top_x -= xstep;
150     dst += stride;
151   } while (++y < height);
152 }
153 
154 #undef LOCAL_RESTRICT
155 
156 template <typename Pixel>
DirectionalIntraPredictorZone3_C(void * LIBGAV1_RESTRICT const dest,ptrdiff_t stride,const void * LIBGAV1_RESTRICT const left_column,const int width,const int height,const int ystep,const bool upsampled_left)157 void DirectionalIntraPredictorZone3_C(
158     void* LIBGAV1_RESTRICT const dest, ptrdiff_t stride,
159     const void* LIBGAV1_RESTRICT const left_column, const int width,
160     const int height, const int ystep, const bool upsampled_left) {
161   const auto* const left = static_cast<const Pixel*>(left_column);
162   stride /= sizeof(Pixel);
163 
164   assert(ystep > 0);
165 
166   const int upsample_shift = static_cast<int>(upsampled_left);
167   const int scale_bits = 6 - upsample_shift;
168   const int base_step = 1 << upsample_shift;
169   // Zone3 never runs out of left_column values.
170   assert((width + height - 1) << upsample_shift >  // max_base_y
171          ((ystep * width) >> scale_bits) +
172              base_step * (height - 1));  // left_base_y
173 
174   int left_y = ystep;
175   int x = 0;
176   do {
177     auto* dst = static_cast<Pixel*>(dest);
178 
179     int left_base_y = left_y >> scale_bits;
180     int y = 0;
181     do {
182       const int shift = ((left_y << upsample_shift) & 0x3F) >> 1;
183       const int val =
184           left[left_base_y] * (32 - shift) + left[left_base_y + 1] * shift;
185       dst[x] = RightShiftWithRounding(val, 5);
186       dst += stride;
187       left_base_y += base_step;
188     } while (++y < height);
189 
190     left_y += ystep;
191   } while (++x < width);
192 }
193 
Init8bpp()194 void Init8bpp() {
195   Dsp* const dsp = dsp_internal::GetWritableDspTable(8);
196   assert(dsp != nullptr);
197 #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
198   dsp->directional_intra_predictor_zone1 =
199       DirectionalIntraPredictorZone1_C<uint8_t>;
200   dsp->directional_intra_predictor_zone2 =
201       DirectionalIntraPredictorZone2_C<uint8_t>;
202   dsp->directional_intra_predictor_zone3 =
203       DirectionalIntraPredictorZone3_C<uint8_t>;
204 #else  // !LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
205   static_cast<void>(dsp);
206 #ifndef LIBGAV1_Dsp8bpp_DirectionalIntraPredictorZone1
207   dsp->directional_intra_predictor_zone1 =
208       DirectionalIntraPredictorZone1_C<uint8_t>;
209 #endif
210 #ifndef LIBGAV1_Dsp8bpp_DirectionalIntraPredictorZone2
211   dsp->directional_intra_predictor_zone2 =
212       DirectionalIntraPredictorZone2_C<uint8_t>;
213 #endif
214 #ifndef LIBGAV1_Dsp8bpp_DirectionalIntraPredictorZone3
215   dsp->directional_intra_predictor_zone3 =
216       DirectionalIntraPredictorZone3_C<uint8_t>;
217 #endif
218 #endif  // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
219 }
220 
221 #if LIBGAV1_MAX_BITDEPTH >= 10
Init10bpp()222 void Init10bpp() {
223   Dsp* const dsp = dsp_internal::GetWritableDspTable(10);
224   assert(dsp != nullptr);
225 #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
226   dsp->directional_intra_predictor_zone1 =
227       DirectionalIntraPredictorZone1_C<uint16_t>;
228   dsp->directional_intra_predictor_zone2 =
229       DirectionalIntraPredictorZone2_C<uint16_t>;
230   dsp->directional_intra_predictor_zone3 =
231       DirectionalIntraPredictorZone3_C<uint16_t>;
232 #endif  // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
233   static_cast<void>(dsp);
234 #ifndef LIBGAV1_Dsp10bpp_DirectionalIntraPredictorZone1
235   dsp->directional_intra_predictor_zone1 =
236       DirectionalIntraPredictorZone1_C<uint16_t>;
237 #endif
238 #ifndef LIBGAV1_Dsp10bpp_DirectionalIntraPredictorZone2
239   dsp->directional_intra_predictor_zone2 =
240       DirectionalIntraPredictorZone2_C<uint16_t>;
241 #endif
242 #ifndef LIBGAV1_Dsp10bpp_DirectionalIntraPredictorZone3
243   dsp->directional_intra_predictor_zone3 =
244       DirectionalIntraPredictorZone3_C<uint16_t>;
245 #endif
246 }
247 #endif  // LIBGAV1_MAX_BITDEPTH >= 10
248 
249 #if LIBGAV1_MAX_BITDEPTH == 12
Init12bpp()250 void Init12bpp() {
251   Dsp* const dsp = dsp_internal::GetWritableDspTable(12);
252   assert(dsp != nullptr);
253 #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
254   dsp->directional_intra_predictor_zone1 =
255       DirectionalIntraPredictorZone1_C<uint16_t>;
256   dsp->directional_intra_predictor_zone2 =
257       DirectionalIntraPredictorZone2_C<uint16_t>;
258   dsp->directional_intra_predictor_zone3 =
259       DirectionalIntraPredictorZone3_C<uint16_t>;
260 #endif  // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
261   static_cast<void>(dsp);
262 #ifndef LIBGAV1_Dsp12bpp_DirectionalIntraPredictorZone1
263   dsp->directional_intra_predictor_zone1 =
264       DirectionalIntraPredictorZone1_C<uint16_t>;
265 #endif
266 #ifndef LIBGAV1_Dsp12bpp_DirectionalIntraPredictorZone2
267   dsp->directional_intra_predictor_zone2 =
268       DirectionalIntraPredictorZone2_C<uint16_t>;
269 #endif
270 #ifndef LIBGAV1_Dsp12bpp_DirectionalIntraPredictorZone3
271   dsp->directional_intra_predictor_zone3 =
272       DirectionalIntraPredictorZone3_C<uint16_t>;
273 #endif
274 }
275 #endif  // LIBGAV1_MAX_BITDEPTH == 12
276 
277 }  // namespace
278 
IntraPredDirectionalInit_C()279 void IntraPredDirectionalInit_C() {
280   Init8bpp();
281 #if LIBGAV1_MAX_BITDEPTH >= 10
282   Init10bpp();
283 #endif
284 #if LIBGAV1_MAX_BITDEPTH == 12
285   Init12bpp();
286 #endif
287 }
288 
289 }  // namespace dsp
290 }  // namespace libgav1
291