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 template <typename Pixel>
DirectionalIntraPredictorZone2_C(void * LIBGAV1_RESTRICT const dest,ptrdiff_t stride,const void * LIBGAV1_RESTRICT const top_row,const void * LIBGAV1_RESTRICT const left_column,const int width,const int height,const int xstep,const int ystep,const bool upsampled_top,const bool upsampled_left)98 void DirectionalIntraPredictorZone2_C(
99 void* LIBGAV1_RESTRICT const dest, ptrdiff_t stride,
100 const void* LIBGAV1_RESTRICT const top_row,
101 const void* LIBGAV1_RESTRICT const left_column, const int width,
102 const int height, const int xstep, const int ystep,
103 const bool upsampled_top, const bool upsampled_left) {
104 const auto* const top = static_cast<const Pixel*>(top_row);
105 const auto* const left = static_cast<const Pixel*>(left_column);
106 auto* dst = static_cast<Pixel*>(dest);
107 stride /= sizeof(Pixel);
108
109 assert(xstep > 0);
110 assert(ystep > 0);
111
112 const int upsample_top_shift = static_cast<int>(upsampled_top);
113 const int upsample_left_shift = static_cast<int>(upsampled_left);
114 const int scale_bits_x = 6 - upsample_top_shift;
115 const int scale_bits_y = 6 - upsample_left_shift;
116 const int min_base_x = -(1 << upsample_top_shift);
117 const int base_step_x = 1 << upsample_top_shift;
118 int y = 0;
119 int top_x = -xstep;
120 do {
121 int top_base_x = top_x >> scale_bits_x;
122 int left_y = (y << 6) - ystep;
123 int x = 0;
124 do {
125 int val;
126 if (top_base_x >= min_base_x) {
127 const int shift = ((top_x * (1 << upsample_top_shift)) & 0x3F) >> 1;
128 val = top[top_base_x] * (32 - shift) + top[top_base_x + 1] * shift;
129 } else {
130 // Note this assumes an arithmetic shift to handle negative values.
131 const int left_base_y = left_y >> scale_bits_y;
132 const int shift = ((left_y * (1 << upsample_left_shift)) & 0x3F) >> 1;
133 assert(left_base_y >= -(1 << upsample_left_shift));
134 val = left[left_base_y] * (32 - shift) + left[left_base_y + 1] * shift;
135 }
136 dst[x] = RightShiftWithRounding(val, 5);
137 top_base_x += base_step_x;
138 left_y -= ystep;
139 } while (++x < width);
140
141 top_x -= xstep;
142 dst += stride;
143 } while (++y < height);
144 }
145
146 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)147 void DirectionalIntraPredictorZone3_C(
148 void* LIBGAV1_RESTRICT const dest, ptrdiff_t stride,
149 const void* LIBGAV1_RESTRICT const left_column, const int width,
150 const int height, const int ystep, const bool upsampled_left) {
151 const auto* const left = static_cast<const Pixel*>(left_column);
152 stride /= sizeof(Pixel);
153
154 assert(ystep > 0);
155
156 const int upsample_shift = static_cast<int>(upsampled_left);
157 const int scale_bits = 6 - upsample_shift;
158 const int base_step = 1 << upsample_shift;
159 // Zone3 never runs out of left_column values.
160 assert((width + height - 1) << upsample_shift > // max_base_y
161 ((ystep * width) >> scale_bits) +
162 base_step * (height - 1)); // left_base_y
163
164 int left_y = ystep;
165 int x = 0;
166 do {
167 auto* dst = static_cast<Pixel*>(dest);
168
169 int left_base_y = left_y >> scale_bits;
170 int y = 0;
171 do {
172 const int shift = ((left_y << upsample_shift) & 0x3F) >> 1;
173 const int val =
174 left[left_base_y] * (32 - shift) + left[left_base_y + 1] * shift;
175 dst[x] = RightShiftWithRounding(val, 5);
176 dst += stride;
177 left_base_y += base_step;
178 } while (++y < height);
179
180 left_y += ystep;
181 } while (++x < width);
182 }
183
Init8bpp()184 void Init8bpp() {
185 Dsp* const dsp = dsp_internal::GetWritableDspTable(8);
186 assert(dsp != nullptr);
187 #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
188 dsp->directional_intra_predictor_zone1 =
189 DirectionalIntraPredictorZone1_C<uint8_t>;
190 dsp->directional_intra_predictor_zone2 =
191 DirectionalIntraPredictorZone2_C<uint8_t>;
192 dsp->directional_intra_predictor_zone3 =
193 DirectionalIntraPredictorZone3_C<uint8_t>;
194 #else // !LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
195 static_cast<void>(dsp);
196 #ifndef LIBGAV1_Dsp8bpp_DirectionalIntraPredictorZone1
197 dsp->directional_intra_predictor_zone1 =
198 DirectionalIntraPredictorZone1_C<uint8_t>;
199 #endif
200 #ifndef LIBGAV1_Dsp8bpp_DirectionalIntraPredictorZone2
201 dsp->directional_intra_predictor_zone2 =
202 DirectionalIntraPredictorZone2_C<uint8_t>;
203 #endif
204 #ifndef LIBGAV1_Dsp8bpp_DirectionalIntraPredictorZone3
205 dsp->directional_intra_predictor_zone3 =
206 DirectionalIntraPredictorZone3_C<uint8_t>;
207 #endif
208 #endif // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
209 }
210
211 #if LIBGAV1_MAX_BITDEPTH >= 10
Init10bpp()212 void Init10bpp() {
213 Dsp* const dsp = dsp_internal::GetWritableDspTable(10);
214 assert(dsp != nullptr);
215 #if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
216 dsp->directional_intra_predictor_zone1 =
217 DirectionalIntraPredictorZone1_C<uint16_t>;
218 dsp->directional_intra_predictor_zone2 =
219 DirectionalIntraPredictorZone2_C<uint16_t>;
220 dsp->directional_intra_predictor_zone3 =
221 DirectionalIntraPredictorZone3_C<uint16_t>;
222 #endif // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
223 static_cast<void>(dsp);
224 #ifndef LIBGAV1_Dsp10bpp_DirectionalIntraPredictorZone1
225 dsp->directional_intra_predictor_zone1 =
226 DirectionalIntraPredictorZone1_C<uint16_t>;
227 #endif
228 #ifndef LIBGAV1_Dsp10bpp_DirectionalIntraPredictorZone2
229 dsp->directional_intra_predictor_zone2 =
230 DirectionalIntraPredictorZone2_C<uint16_t>;
231 #endif
232 #ifndef LIBGAV1_Dsp10bpp_DirectionalIntraPredictorZone3
233 dsp->directional_intra_predictor_zone3 =
234 DirectionalIntraPredictorZone3_C<uint16_t>;
235 #endif
236 }
237 #endif // LIBGAV1_MAX_BITDEPTH >= 10
238
239 } // namespace
240
IntraPredDirectionalInit_C()241 void IntraPredDirectionalInit_C() {
242 Init8bpp();
243 #if LIBGAV1_MAX_BITDEPTH >= 10
244 Init10bpp();
245 #endif
246 }
247
248 } // namespace dsp
249 } // namespace libgav1
250