blob: 684d113fa9ef59158aa95f84a22f7a260479f012 [file] [log] [blame]
/*
* Copyright © 2018, VideoLAN and dav1d authors
* Copyright © 2018, Two Orioles, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include <stdlib.h>
#include "common/attributes.h"
#include "src/intra_edge.h"
#include "src/levels.h"
struct ModeSelMem {
EdgeBranch *nwc[3 /* 64x64, 32x32, 16x16 */];
EdgeTip *nt;
};
static void init_edges(EdgeNode *const node,
const enum BlockLevel bl,
const enum EdgeFlags edge_flags)
{
node->o = edge_flags;
#define ALL_FL(t) (EDGE_I444_##t | EDGE_I422_##t | EDGE_I420_##t)
if (bl == BL_8X8) {
EdgeTip *const nt = (EdgeTip *) node;
node->h[0] = edge_flags | ALL_FL(LEFT_HAS_BOTTOM);
node->h[1] = edge_flags & (ALL_FL(LEFT_HAS_BOTTOM) |
EDGE_I420_TOP_HAS_RIGHT);
node->v[0] = edge_flags | ALL_FL(TOP_HAS_RIGHT);
node->v[1] = edge_flags & (ALL_FL(TOP_HAS_RIGHT) |
EDGE_I420_LEFT_HAS_BOTTOM |
EDGE_I422_LEFT_HAS_BOTTOM);
nt->split[0] = ALL_FL(TOP_HAS_RIGHT) | ALL_FL(LEFT_HAS_BOTTOM);
nt->split[1] = (edge_flags & ALL_FL(TOP_HAS_RIGHT)) |
EDGE_I422_LEFT_HAS_BOTTOM;
nt->split[2] = edge_flags | EDGE_I444_TOP_HAS_RIGHT;
nt->split[3] = edge_flags & (EDGE_I420_TOP_HAS_RIGHT |
EDGE_I420_LEFT_HAS_BOTTOM |
EDGE_I422_LEFT_HAS_BOTTOM);
} else {
EdgeBranch *const nwc = (EdgeBranch *) node;
node->h[0] = edge_flags | ALL_FL(LEFT_HAS_BOTTOM);
node->h[1] = edge_flags & ALL_FL(LEFT_HAS_BOTTOM);
node->v[0] = edge_flags | ALL_FL(TOP_HAS_RIGHT);
node->v[1] = edge_flags & ALL_FL(TOP_HAS_RIGHT);
nwc->h4[0] = edge_flags | ALL_FL(LEFT_HAS_BOTTOM);
nwc->h4[1] =
nwc->h4[2] = ALL_FL(LEFT_HAS_BOTTOM);
nwc->h4[3] = edge_flags & ALL_FL(LEFT_HAS_BOTTOM);
if (bl == BL_16X16)
nwc->h4[1] |= edge_flags & EDGE_I420_TOP_HAS_RIGHT;
nwc->v4[0] = edge_flags | ALL_FL(TOP_HAS_RIGHT);
nwc->v4[1] =
nwc->v4[2] = ALL_FL(TOP_HAS_RIGHT);
nwc->v4[3] = edge_flags & ALL_FL(TOP_HAS_RIGHT);
if (bl == BL_16X16)
nwc->v4[1] |= edge_flags & (EDGE_I420_LEFT_HAS_BOTTOM |
EDGE_I422_LEFT_HAS_BOTTOM);
nwc->tls[0] = ALL_FL(TOP_HAS_RIGHT) | ALL_FL(LEFT_HAS_BOTTOM);
nwc->tls[1] = edge_flags & ALL_FL(LEFT_HAS_BOTTOM);
nwc->tls[2] = edge_flags & ALL_FL(TOP_HAS_RIGHT);
nwc->trs[0] = edge_flags | ALL_FL(TOP_HAS_RIGHT);
nwc->trs[1] = edge_flags | ALL_FL(LEFT_HAS_BOTTOM);
nwc->trs[2] = 0;
nwc->tts[0] = ALL_FL(TOP_HAS_RIGHT) | ALL_FL(LEFT_HAS_BOTTOM);
nwc->tts[1] = edge_flags & ALL_FL(TOP_HAS_RIGHT);
nwc->tts[2] = edge_flags & ALL_FL(LEFT_HAS_BOTTOM);
nwc->tbs[0] = edge_flags | ALL_FL(LEFT_HAS_BOTTOM);
nwc->tbs[1] = edge_flags | ALL_FL(TOP_HAS_RIGHT);
nwc->tbs[2] = 0;
}
}
static void init_mode_node(EdgeBranch *const nwc,
const enum BlockLevel bl,
struct ModeSelMem *const mem,
const int top_has_right,
const int left_has_bottom)
{
init_edges(&nwc->node, bl,
(top_has_right ? ALL_FL(TOP_HAS_RIGHT) : 0) |
(left_has_bottom ? ALL_FL(LEFT_HAS_BOTTOM) : 0));
if (bl == BL_16X16) {
for (int n = 0; n < 4; n++) {
EdgeTip *const nt = mem->nt++;
nwc->split[n] = &nt->node;
init_edges(&nt->node, bl + 1,
((n == 3 || (n == 1 && !top_has_right)) ? 0 :
ALL_FL(TOP_HAS_RIGHT)) |
(!(n == 0 || (n == 2 && left_has_bottom)) ? 0 :
ALL_FL(LEFT_HAS_BOTTOM)));
}
} else {
for (int n = 0; n < 4; n++) {
EdgeBranch *const nwc_child = mem->nwc[bl]++;
nwc->split[n] = &nwc_child->node;
init_mode_node(nwc_child, bl + 1, mem,
!(n == 3 || (n == 1 && !top_has_right)),
n == 0 || (n == 2 && left_has_bottom));
}
}
}
void dav1d_init_mode_tree(EdgeNode *const root_node, EdgeTip *const nt,
const int allow_sb128)
{
EdgeBranch *const root = (EdgeBranch *) root_node;
struct ModeSelMem mem;
mem.nt = nt;
if (allow_sb128) {
mem.nwc[BL_128X128] = &root[1];
mem.nwc[BL_64X64] = &root[1 + 4];
mem.nwc[BL_32X32] = &root[1 + 4 + 16];
init_mode_node(root, BL_128X128, &mem, 1, 0);
assert(mem.nwc[BL_128X128] == &root[1 + 4]);
assert(mem.nwc[BL_64X64] == &root[1 + 4 + 16]);
assert(mem.nwc[BL_32X32] == &root[1 + 4 + 16 + 64]);
assert(mem.nt == &nt[256]);
} else {
mem.nwc[BL_128X128] = NULL;
mem.nwc[BL_64X64] = &root[1];
mem.nwc[BL_32X32] = &root[1 + 4];
init_mode_node(root, BL_64X64, &mem, 1, 0);
assert(mem.nwc[BL_64X64] == &root[1 + 4]);
assert(mem.nwc[BL_32X32] == &root[1 + 4 + 16]);
assert(mem.nt == &nt[64]);
}
}