Coverage Report

Created: 2025-12-11 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}