xref: /aosp_15_r20/external/libdav1d/src/ipred_prepare_tmpl.c (revision c09093415860a1c2373dacd84c4fde00c507cdfd)
1 /*
2  * Copyright © 2018, VideoLAN and dav1d authors
3  * Copyright © 2018, Two Orioles, LLC
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice, this
10  *    list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  *    this list of conditions and the following disclaimer in the documentation
14  *    and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "config.h"
29 
30 #include <stdint.h>
31 #include <string.h>
32 
33 #include "common/intops.h"
34 
35 #include "src/ipred_prepare.h"
36 
37 static const uint8_t av1_mode_conv[N_INTRA_PRED_MODES]
38                                   [2 /* have_left */][2 /* have_top */] =
39 {
40     [DC_PRED]    = { { DC_128_PRED,  TOP_DC_PRED },
41                      { LEFT_DC_PRED, DC_PRED     } },
42     [PAETH_PRED] = { { DC_128_PRED,  VERT_PRED   },
43                      { HOR_PRED,     PAETH_PRED  } },
44 };
45 
46 static const uint8_t av1_mode_to_angle_map[8] = {
47     90, 180, 45, 135, 113, 157, 203, 67
48 };
49 
50 static const struct {
51     uint8_t needs_left:1;
52     uint8_t needs_top:1;
53     uint8_t needs_topleft:1;
54     uint8_t needs_topright:1;
55     uint8_t needs_bottomleft:1;
56 } av1_intra_prediction_edges[N_IMPL_INTRA_PRED_MODES] = {
57     [DC_PRED]       = { .needs_top  = 1, .needs_left = 1 },
58     [VERT_PRED]     = { .needs_top  = 1 },
59     [HOR_PRED]      = { .needs_left = 1 },
60     [LEFT_DC_PRED]  = { .needs_left = 1 },
61     [TOP_DC_PRED]   = { .needs_top  = 1 },
62     [DC_128_PRED]   = { 0 },
63     [Z1_PRED]       = { .needs_top = 1, .needs_topright = 1,
64                         .needs_topleft = 1 },
65     [Z2_PRED]       = { .needs_left = 1, .needs_top = 1, .needs_topleft = 1 },
66     [Z3_PRED]       = { .needs_left = 1, .needs_bottomleft = 1,
67                         .needs_topleft = 1 },
68     [SMOOTH_PRED]   = { .needs_left = 1, .needs_top = 1 },
69     [SMOOTH_V_PRED] = { .needs_left = 1, .needs_top = 1 },
70     [SMOOTH_H_PRED] = { .needs_left = 1, .needs_top = 1 },
71     [PAETH_PRED]    = { .needs_left = 1, .needs_top = 1, .needs_topleft = 1 },
72     [FILTER_PRED]   = { .needs_left = 1, .needs_top = 1, .needs_topleft = 1 },
73 };
74 
75 enum IntraPredMode
bytefn(dav1d_prepare_intra_edges)76 bytefn(dav1d_prepare_intra_edges)(const int x, const int have_left,
77                                   const int y, const int have_top,
78                                   const int w, const int h,
79                                   const enum EdgeFlags edge_flags,
80                                   const pixel *const dst,
81                                   const ptrdiff_t stride,
82                                   const pixel *prefilter_toplevel_sb_edge,
83                                   enum IntraPredMode mode, int *const angle,
84                                   const int tw, const int th, const int filter_edge,
85                                   pixel *const topleft_out HIGHBD_DECL_SUFFIX)
86 {
87     const int bitdepth = bitdepth_from_max(bitdepth_max);
88     assert(y < h && x < w);
89 
90     switch (mode) {
91     case VERT_PRED:
92     case HOR_PRED:
93     case DIAG_DOWN_LEFT_PRED:
94     case DIAG_DOWN_RIGHT_PRED:
95     case VERT_RIGHT_PRED:
96     case HOR_DOWN_PRED:
97     case HOR_UP_PRED:
98     case VERT_LEFT_PRED: {
99         *angle = av1_mode_to_angle_map[mode - VERT_PRED] + 3 * *angle;
100 
101         if (*angle <= 90)
102             mode = *angle < 90 && have_top ? Z1_PRED : VERT_PRED;
103         else if (*angle < 180)
104             mode = Z2_PRED;
105         else
106             mode = *angle > 180 && have_left ? Z3_PRED : HOR_PRED;
107         break;
108     }
109     case DC_PRED:
110     case PAETH_PRED:
111         mode = av1_mode_conv[mode][have_left][have_top];
112         break;
113     default:
114         break;
115     }
116 
117     const pixel *dst_top;
118     if (have_top &&
119         (av1_intra_prediction_edges[mode].needs_top ||
120          av1_intra_prediction_edges[mode].needs_topleft ||
121          (av1_intra_prediction_edges[mode].needs_left && !have_left)))
122     {
123         if (prefilter_toplevel_sb_edge) {
124             dst_top = &prefilter_toplevel_sb_edge[x * 4];
125         } else {
126             dst_top = &dst[-PXSTRIDE(stride)];
127         }
128     }
129 
130     if (av1_intra_prediction_edges[mode].needs_left) {
131         const int sz = th << 2;
132         pixel *const left = &topleft_out[-sz];
133 
134         if (have_left) {
135             const int px_have = imin(sz, (h - y) << 2);
136 
137             for (int i = 0; i < px_have; i++)
138                 left[sz - 1 - i] = dst[PXSTRIDE(stride) * i - 1];
139             if (px_have < sz)
140                 pixel_set(left, left[sz - px_have], sz - px_have);
141         } else {
142             pixel_set(left, have_top ? *dst_top : ((1 << bitdepth) >> 1) + 1, sz);
143         }
144 
145         if (av1_intra_prediction_edges[mode].needs_bottomleft) {
146             const int have_bottomleft = (!have_left || y + th >= h) ? 0 :
147                                         (edge_flags & EDGE_I444_LEFT_HAS_BOTTOM);
148 
149             if (have_bottomleft) {
150                 const int px_have = imin(sz, (h - y - th) << 2);
151 
152                 for (int i = 0; i < px_have; i++)
153                     left[-(i + 1)] = dst[(sz + i) * PXSTRIDE(stride) - 1];
154                 if (px_have < sz)
155                     pixel_set(left - sz, left[-px_have], sz - px_have);
156             } else {
157                 pixel_set(left - sz, left[0], sz);
158             }
159         }
160     }
161 
162     if (av1_intra_prediction_edges[mode].needs_top) {
163         const int sz = tw << 2;
164         pixel *const top = &topleft_out[1];
165 
166         if (have_top) {
167             const int px_have = imin(sz, (w - x) << 2);
168             pixel_copy(top, dst_top, px_have);
169             if (px_have < sz)
170                 pixel_set(top + px_have, top[px_have - 1], sz - px_have);
171         } else {
172             pixel_set(top, have_left ? dst[-1] : ((1 << bitdepth) >> 1) - 1, sz);
173         }
174 
175         if (av1_intra_prediction_edges[mode].needs_topright) {
176             const int have_topright = (!have_top || x + tw >= w) ? 0 :
177                                       (edge_flags & EDGE_I444_TOP_HAS_RIGHT);
178 
179             if (have_topright) {
180                 const int px_have = imin(sz, (w - x - tw) << 2);
181 
182                 pixel_copy(top + sz, &dst_top[sz], px_have);
183                 if (px_have < sz)
184                     pixel_set(top + sz + px_have, top[sz + px_have - 1],
185                               sz - px_have);
186             } else {
187                 pixel_set(top + sz, top[sz - 1], sz);
188             }
189         }
190     }
191 
192     if (av1_intra_prediction_edges[mode].needs_topleft) {
193         if (have_left)
194             *topleft_out = have_top ? dst_top[-1] : dst[-1];
195         else
196             *topleft_out = have_top ? *dst_top : (1 << bitdepth) >> 1;
197 
198         if (mode == Z2_PRED && tw + th >= 6 && filter_edge)
199             *topleft_out = ((topleft_out[-1] + topleft_out[1]) * 5 +
200                             topleft_out[0] * 6 + 8) >> 4;
201     }
202 
203     return mode;
204 }
205