/src/dav1d/src/intra_edge.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright © 2018-2023, VideoLAN and dav1d authors |
3 | | * Copyright © 2018-2023, 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 <stdlib.h> |
31 | | |
32 | | #include "common/attributes.h" |
33 | | |
34 | | #include "src/intra_edge.h" |
35 | | #include "src/levels.h" |
36 | | |
37 | | struct ModeSelMem { |
38 | | EdgeBranch *nwc[3 /* 64x64, 32x32, 16x16 */]; |
39 | | EdgeTip *nt; |
40 | | }; |
41 | | |
42 | | /* Because we're using 16-bit offsets to refer to other nodes those arrays |
43 | | * are placed in a struct to ensure they're consecutive in memory. */ |
44 | | static struct { |
45 | | EdgeBranch branch_sb128[1 + 4 + 16 + 64]; |
46 | | EdgeTip tip_sb128[256]; |
47 | | EdgeBranch branch_sb64[1 + 4 + 16]; |
48 | | EdgeTip tip_sb64[64]; |
49 | | } ALIGN(nodes, 16); |
50 | | |
51 | | const EdgeNode *dav1d_intra_edge_tree[2] = { |
52 | | (EdgeNode*)nodes.branch_sb128, (EdgeNode*)nodes.branch_sb64 |
53 | | }; |
54 | | |
55 | | static COLD void init_edges(EdgeNode *const node, |
56 | | const enum BlockLevel bl, |
57 | | const enum EdgeFlags edge_flags) |
58 | 852 | { |
59 | 852 | node->o = edge_flags; |
60 | 852 | node->h[0] = edge_flags | EDGE_ALL_LEFT_HAS_BOTTOM; |
61 | 852 | node->v[0] = edge_flags | EDGE_ALL_TOP_HAS_RIGHT; |
62 | | |
63 | 852 | if (bl == BL_8X8) { |
64 | 640 | EdgeTip *const nt = (EdgeTip *) node; |
65 | | |
66 | 640 | node->h[1] = edge_flags & (EDGE_ALL_LEFT_HAS_BOTTOM | |
67 | 640 | EDGE_I420_TOP_HAS_RIGHT); |
68 | 640 | node->v[1] = edge_flags & (EDGE_ALL_TOP_HAS_RIGHT | |
69 | 640 | EDGE_I420_LEFT_HAS_BOTTOM | |
70 | 640 | EDGE_I422_LEFT_HAS_BOTTOM); |
71 | | |
72 | 640 | nt->split[0] = (edge_flags & EDGE_ALL_TOP_HAS_RIGHT) | |
73 | 640 | EDGE_I422_LEFT_HAS_BOTTOM; |
74 | 640 | nt->split[1] = edge_flags | EDGE_I444_TOP_HAS_RIGHT; |
75 | 640 | nt->split[2] = edge_flags & (EDGE_I420_TOP_HAS_RIGHT | |
76 | 640 | EDGE_I420_LEFT_HAS_BOTTOM | |
77 | 640 | EDGE_I422_LEFT_HAS_BOTTOM); |
78 | 640 | } else { |
79 | 212 | EdgeBranch *const nwc = (EdgeBranch *) node; |
80 | | |
81 | 212 | node->h[1] = edge_flags & EDGE_ALL_LEFT_HAS_BOTTOM; |
82 | 212 | node->v[1] = edge_flags & EDGE_ALL_TOP_HAS_RIGHT; |
83 | | |
84 | 212 | nwc->h4 = EDGE_ALL_LEFT_HAS_BOTTOM; |
85 | 212 | nwc->v4 = EDGE_ALL_TOP_HAS_RIGHT; |
86 | 212 | if (bl == BL_16X16) { |
87 | 160 | nwc->h4 |= edge_flags & EDGE_I420_TOP_HAS_RIGHT; |
88 | 160 | nwc->v4 |= edge_flags & (EDGE_I420_LEFT_HAS_BOTTOM | |
89 | 160 | EDGE_I422_LEFT_HAS_BOTTOM); |
90 | 160 | } |
91 | 212 | } |
92 | 852 | } |
93 | | |
94 | 848 | #define PTR_OFFSET(a, b) ((uint16_t)((uintptr_t)(b) - (uintptr_t)(a))) |
95 | | |
96 | | static COLD void init_mode_node(EdgeBranch *const nwc, |
97 | | const enum BlockLevel bl, |
98 | | struct ModeSelMem *const mem, |
99 | | const int top_has_right, |
100 | | const int left_has_bottom) |
101 | 212 | { |
102 | 212 | init_edges(&nwc->node, bl, |
103 | 212 | (top_has_right ? EDGE_ALL_TOP_HAS_RIGHT : 0) | |
104 | 212 | (left_has_bottom ? EDGE_ALL_LEFT_HAS_BOTTOM : 0)); |
105 | 212 | if (bl == BL_16X16) { |
106 | 800 | for (int n = 0; n < 4; n++) { |
107 | 640 | EdgeTip *const nt = mem->nt++; |
108 | 640 | nwc->split_offset[n] = PTR_OFFSET(nwc, nt); |
109 | 640 | init_edges(&nt->node, bl + 1, |
110 | 640 | ((n == 3 || (n == 1 && !top_has_right)) ? 0 : |
111 | 640 | EDGE_ALL_TOP_HAS_RIGHT) | |
112 | 640 | (!(n == 0 || (n == 2 && left_has_bottom)) ? 0 : |
113 | 640 | EDGE_ALL_LEFT_HAS_BOTTOM)); |
114 | 640 | } |
115 | 160 | } else { |
116 | 260 | for (int n = 0; n < 4; n++) { |
117 | 208 | EdgeBranch *const nwc_child = mem->nwc[bl]++; |
118 | 208 | nwc->split_offset[n] = PTR_OFFSET(nwc, nwc_child); |
119 | 208 | init_mode_node(nwc_child, bl + 1, mem, |
120 | 208 | !(n == 3 || (n == 1 && !top_has_right)), |
121 | 208 | n == 0 || (n == 2 && left_has_bottom)); |
122 | 208 | } |
123 | 52 | } |
124 | 212 | } |
125 | | |
126 | 2 | COLD void dav1d_init_intra_edge_tree(void) { |
127 | | // This function is guaranteed to be called only once |
128 | 2 | struct ModeSelMem mem; |
129 | | |
130 | 2 | mem.nwc[BL_128X128] = &nodes.branch_sb128[1]; |
131 | 2 | mem.nwc[BL_64X64] = &nodes.branch_sb128[1 + 4]; |
132 | 2 | mem.nwc[BL_32X32] = &nodes.branch_sb128[1 + 4 + 16]; |
133 | 2 | mem.nt = nodes.tip_sb128; |
134 | 2 | init_mode_node(nodes.branch_sb128, BL_128X128, &mem, 1, 0); |
135 | 2 | assert(mem.nwc[BL_128X128] == &nodes.branch_sb128[1 + 4]); |
136 | 2 | assert(mem.nwc[BL_64X64] == &nodes.branch_sb128[1 + 4 + 16]); |
137 | 2 | assert(mem.nwc[BL_32X32] == &nodes.branch_sb128[1 + 4 + 16 + 64]); |
138 | 2 | assert(mem.nt == &nodes.tip_sb128[256]); |
139 | | |
140 | 2 | mem.nwc[BL_128X128] = NULL; |
141 | 2 | mem.nwc[BL_64X64] = &nodes.branch_sb64[1]; |
142 | 2 | mem.nwc[BL_32X32] = &nodes.branch_sb64[1 + 4]; |
143 | 2 | mem.nt = nodes.tip_sb64; |
144 | 2 | init_mode_node(nodes.branch_sb64, BL_64X64, &mem, 1, 0); |
145 | 2 | assert(mem.nwc[BL_64X64] == &nodes.branch_sb64[1 + 4]); |
146 | 2 | assert(mem.nwc[BL_32X32] == &nodes.branch_sb64[1 + 4 + 16]); |
147 | 2 | assert(mem.nt == &nodes.tip_sb64[64]); |
148 | 2 | } |