Commit 1d95e5fa authored by David Flynn's avatar David Flynn
Browse files

geom/m46149: occupancy contextualisation using unoccupied child neighbours

This commit adds an extra contextualisation bit for occupancy coding
based on there being an unoccupied adjacent child neighbour, rather
than just depending upon the number of occupied neighbours.
parent 783d83ab
......@@ -116,6 +116,7 @@ updatePatternFromNeighOccupancy(
if (gnp.neighPattern & patternBit) {
uint8_t child_occ = occupancyAtlas.getChildOcc(x, y, z);
uint8_t child_unocc = ~child_occ;
child_occ &= childMask;
if (!child_occ) {
/* neighbour is falsely occupied */
......@@ -125,6 +126,9 @@ updatePatternFromNeighOccupancy(
gnp.adjacencyGt1 |= gnp.adjacencyGt0 & child_occ;
gnp.adjacencyGt0 |= child_occ;
}
// map of children with any unoccupied adjacent child
gnp.adjacencyUnocc |= (child_unocc & childMask) >> adjacencyShift;
}
return gnp;
......@@ -170,7 +174,7 @@ makeGeometryNeighPattern(
// NB: the process of updating neighpattern below also derives
// the occupancy contextualisation bits.
GeometryNeighPattern gnp = {neighPattern, 0, 0};
GeometryNeighPattern gnp = {neighPattern, 0, 0, 0};
if (!adjacent_child_contextualization_enabled_flag)
return gnp;
......
......@@ -161,8 +161,12 @@ struct GeometryNeighPattern {
// Mask indicating presence of neigbours of the corresponding tree node
uint8_t neighPattern;
// mask indicating the number of external child neighbours
uint8_t adjacencyGt0;
uint8_t adjacencyGt1;
// mask indicating unoccupied external child neighbours
uint8_t adjacencyUnocc;
};
//============================================================================
......
......@@ -59,21 +59,24 @@ public:
int mappedOccIsPredicted,
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1);
int mappedOccAdjGt1,
int mappedOccAdjUnocc);
int decodeOccupancyNeighNZ(
int neighPattern,
int mappedOccIsPredicted,
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1);
int mappedOccAdjGt1,
int mappedOccAdjUnocc);
int decodeOccupancyBitwise(
int neighPattern,
int mappedOccIsPredicted,
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1);
int mappedOccAdjGt1,
int mappedOccAdjUnocc);
int decodeOccupancyBytewise(int neighPattern);
......@@ -82,7 +85,8 @@ public:
int occupancyIsPredicted,
int occupancyPrediction,
int occupancyAdjGt0,
int occupancyAdjGt1);
int occupancyAdjGt1,
int occupancyAdjUncc);
Vec3<uint32_t> decodePointPosition(int nodeSizeLog2);
......@@ -105,14 +109,8 @@ private:
AdaptiveBitModel _ctxNumIdcmPointsEq1;
// For bitwise occupancy coding
// maps 0 + i: no adjacency
// maps 3 + i: adjacency > 0
// maps 6 + i: adjacency > 1
// map i = 0 = not predicted
// map i = 1 = predicted unnoccupied
// map i = 2 = predicted occupied
CtxModelOctreeOccupancy _ctxOccupancy;
CtxMapOctreeOccupancy _ctxIdxMaps[9];
CtxMapOctreeOccupancy _ctxIdxMaps[18];
// For bytewise occupancy coding
DualLutCoder<true> _bytewiseOccupancyCoder[10];
......@@ -169,7 +167,8 @@ GeometryOctreeDecoder::decodeOccupancyNeighZ(
int mappedOccIsPredicted,
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1)
int mappedOccAdjGt1,
int mappedOccAdjUnocc)
{
int minOccupied = 2;
int numOccupiedAcc = 0;
......@@ -181,9 +180,16 @@ GeometryOctreeDecoder::decodeOccupancyNeighZ(
int bitPrediction = (mappedOccPrediction >> kOccBitCodingOrder[i]) & 1;
int bitAdjGt0 = (mappedOccAdjGt0 >> kOccBitCodingOrder[i]) & 1;
int bitAdjGt1 = (mappedOccAdjGt1 >> kOccBitCodingOrder[i]) & 1;
int bitAdjUnocc = (mappedOccAdjUnocc >> kOccBitCodingOrder[i]) & 1;
int ctxIdxMapIdx =
3 * (bitAdjGt0 + bitAdjGt1) + bitIsPredicted + bitPrediction;
int numAdj = bitAdjGt0 + bitAdjGt1;
int idxAdj = bitAdjUnocc + 2 * numAdj;
if (i > 4) {
static const int8_t kCtxIdxAdjReduc567[6] = {0, 0, 1, 2, 3, 3};
idxAdj = kCtxIdxAdjReduc567[idxAdj];
}
int ctxIdxMapIdx = 3 * idxAdj + bitIsPredicted + bitPrediction;
auto& ctxIdxMap = _ctxIdxMaps[ctxIdxMapIdx];
// NB: There must be at least two occupied child nodes
......@@ -209,7 +215,8 @@ GeometryOctreeDecoder::decodeOccupancyNeighNZ(
int mappedOccIsPredicted,
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1)
int mappedOccAdjGt1,
int mappedOccAdjUnocc)
{
// code occupancy using the neighbour configuration context
// with reduction from 64 states to 9 (or 6).
......@@ -247,9 +254,16 @@ GeometryOctreeDecoder::decodeOccupancyNeighNZ(
int bitPrediction = (mappedOccPrediction >> kOccBitCodingOrder[i]) & 1;
int bitAdjGt0 = (mappedOccAdjGt0 >> kOccBitCodingOrder[i]) & 1;
int bitAdjGt1 = (mappedOccAdjGt1 >> kOccBitCodingOrder[i]) & 1;
int bitAdjUnocc = (mappedOccAdjUnocc >> kOccBitCodingOrder[i]) & 1;
int numAdj = bitAdjGt0 + bitAdjGt1;
int idxAdj = bitAdjUnocc + 2 * numAdj;
if (i > 4) {
static const int8_t kCtxIdxAdjReduc567[6] = {0, 0, 1, 2, 3, 3};
idxAdj = kCtxIdxAdjReduc567[idxAdj];
}
int ctxIdxMapIdx =
3 * (bitAdjGt0 + bitAdjGt1) + bitIsPredicted + bitPrediction;
int ctxIdxMapIdx = 3 * idxAdj + bitIsPredicted + bitPrediction;
auto& ctxIdxMap = _ctxIdxMaps[ctxIdxMapIdx];
if (i < 7 || partialOccupancy) {
......@@ -273,17 +287,18 @@ GeometryOctreeDecoder::decodeOccupancyBitwise(
int mappedOccIsPredicted,
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1)
int mappedOccAdjGt1,
int mappedOccAdjUnocc)
{
if (neighPattern == 0) {
return decodeOccupancyNeighZ(
mappedOccIsPredicted, mappedOccPrediction, mappedOccAdjGt0,
mappedOccAdjGt1);
mappedOccAdjGt1, mappedOccAdjUnocc);
}
return decodeOccupancyNeighNZ(
neighPattern, mappedOccIsPredicted, mappedOccPrediction, mappedOccAdjGt0,
mappedOccAdjGt1);
mappedOccAdjGt1, mappedOccAdjUnocc);
}
//-------------------------------------------------------------------------
......@@ -308,7 +323,8 @@ GeometryOctreeDecoder::decodeOccupancy(
int occupancyIsPred,
int occupancyPred,
int occupancyAdjGt0,
int occupancyAdjGt1)
int occupancyAdjGt1,
int occupancyAdjUnocc)
{
// decode occupancy pattern
uint32_t occupancy;
......@@ -327,11 +343,12 @@ GeometryOctreeDecoder::decodeOccupancy(
uint32_t mapOccP = mapGeometryOccupancy(occupancyPred, neighPattern);
uint32_t mapAdjGt0 = mapGeometryOccupancy(occupancyAdjGt0, neighPattern);
uint32_t mapAdjGt1 = mapGeometryOccupancy(occupancyAdjGt1, neighPattern);
uint32_t mapAdjUnocc = mapGeometryOccupancy(occupancyAdjUnocc, neighPattern);
uint32_t mappedOccupancy;
if (_useBitwiseOccupancyCoder)
mappedOccupancy = decodeOccupancyBitwise(
neighPattern, mapOccIsP, mapOccP, mapAdjGt0, mapAdjGt1);
neighPattern, mapOccIsP, mapOccP, mapAdjGt0, mapAdjGt1, mapAdjUnocc);
else
mappedOccupancy = decodeOccupancyBytewise(neighPattern);
......@@ -448,6 +465,7 @@ decodeGeometryOctree(
int occupancyAdjacencyGt0 = 0;
int occupancyAdjacencyGt1 = 0;
int occupancyAdjacencyUnocc = 0;
if (gps.neighbour_avail_boundary_log2) {
updateGeometryOccupancyAtlas(
......@@ -461,6 +479,7 @@ decodeGeometryOctree(
node0.neighPattern = gnp.neighPattern;
occupancyAdjacencyGt0 = gnp.adjacencyGt0;
occupancyAdjacencyGt1 = gnp.adjacencyGt1;
occupancyAdjacencyUnocc = gnp.adjacencyUnocc;
}
int occupancyIsPredicted = 0;
......@@ -476,7 +495,7 @@ decodeGeometryOctree(
// decode occupancy pattern
uint8_t occupancy = decoder.decodeOccupancy(
node0.neighPattern, occupancyIsPredicted, occupancyPrediction,
occupancyAdjacencyGt0, occupancyAdjacencyGt1);
occupancyAdjacencyGt0, occupancyAdjacencyGt1, occupancyAdjacencyUnocc);
assert(occupancy > 0);
......
......@@ -60,7 +60,8 @@ public:
int mappedOccIsPredicted,
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1);
int mappedOccAdjGt1,
int mappedOccAdjUnocc);
void encodeOccupancyNeighNZ(
int neighPattern,
......@@ -68,7 +69,8 @@ public:
int mappedOccIsPredicted,
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1);
int mappedOccAdjGt1,
int mappedOccAdjUnocc);
void encodeOccupancyBitwise(
int neighPattern,
......@@ -76,7 +78,8 @@ public:
int mappedOccIsPredicted,
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1);
int mappedOccAdjGt1,
int mappedOccAdjUnocc);
void encodeOccupancyBytewise(int neighPattern, int mappedOccupancy);
......@@ -86,7 +89,8 @@ public:
int occupancyIsPredicted,
int occupancyPrediction,
int occupancyAdjGt0,
int occupancyAdjGt1);
int occupancyAdjGt1,
int occupancyAdjUnocc);
void encodePointPosition(int nodeSizeLog2, const Vec3<uint32_t>& pos);
......@@ -110,14 +114,8 @@ private:
AdaptiveBitModel _ctxNumIdcmPointsEq1;
// For bitwise occupancy coding
// maps 0 + i: no adjacency
// maps 3 + i: adjacency > 0
// maps 6 + i: adjacency > 1
// map i = 0 = not predicted
// map i = 1 = predicted unnoccupied
// map i = 2 = predicted occupied
CtxModelOctreeOccupancy _ctxOccupancy;
CtxMapOctreeOccupancy _ctxIdxMaps[9];
CtxMapOctreeOccupancy _ctxIdxMaps[18];
// For bytewise occupancy coding
DualLutCoder<true> _bytewiseOccupancyCoder[10];
......@@ -174,7 +172,8 @@ GeometryOctreeEncoder::encodeOccupancyNeighZ(
int mappedOccIsPredicted,
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1)
int mappedOccAdjGt1,
int mappedOccAdjUnocc)
{
int minOccupied = 2;
int numOccupiedAcc = 0;
......@@ -185,9 +184,16 @@ GeometryOctreeEncoder::encodeOccupancyNeighZ(
int bitPrediction = (mappedOccPrediction >> kOccBitCodingOrder[i]) & 1;
int bitAdjGt0 = (mappedOccAdjGt0 >> kOccBitCodingOrder[i]) & 1;
int bitAdjGt1 = (mappedOccAdjGt1 >> kOccBitCodingOrder[i]) & 1;
int bitAdjUnocc = (mappedOccAdjUnocc >> kOccBitCodingOrder[i]) & 1;
int ctxIdxMapIdx =
3 * (bitAdjGt0 + bitAdjGt1) + bitIsPredicted + bitPrediction;
int numAdj = bitAdjGt0 + bitAdjGt1;
int idxAdj = bitAdjUnocc + 2 * numAdj;
if (i > 4) {
static const int8_t kCtxIdxAdjReduc567[6] = {0, 0, 1, 2, 3, 3};
idxAdj = kCtxIdxAdjReduc567[idxAdj];
}
int ctxIdxMapIdx = 3 * idxAdj + bitIsPredicted + bitPrediction;
auto& ctxIdxMap = _ctxIdxMaps[ctxIdxMapIdx];
int idx = numOccupiedAcc;
......@@ -213,7 +219,8 @@ GeometryOctreeEncoder::encodeOccupancyNeighNZ(
int mappedOccIsPredicted,
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1)
int mappedOccAdjGt1,
int mappedOccAdjUnocc)
{
// code occupancy using the neighbour configuration context
// with reduction from 64 states to 9 (or 6).
......@@ -249,9 +256,16 @@ GeometryOctreeEncoder::encodeOccupancyNeighNZ(
int bitPrediction = (mappedOccPrediction >> kOccBitCodingOrder[i]) & 1;
int bitAdjGt0 = (mappedOccAdjGt0 >> kOccBitCodingOrder[i]) & 1;
int bitAdjGt1 = (mappedOccAdjGt1 >> kOccBitCodingOrder[i]) & 1;
int bitAdjUnocc = (mappedOccAdjUnocc >> kOccBitCodingOrder[i]) & 1;
int numAdj = bitAdjGt0 + bitAdjGt1;
int idxAdj = bitAdjUnocc + 2 * numAdj;
if (i > 4) {
static const int8_t kCtxIdxAdjReduc567[6] = {0, 0, 1, 2, 3, 3};
idxAdj = kCtxIdxAdjReduc567[idxAdj];
}
int ctxIdxMapIdx =
3 * (bitAdjGt0 + bitAdjGt1) + bitIsPredicted + bitPrediction;
int ctxIdxMapIdx = 3 * idxAdj + bitIsPredicted + bitPrediction;
auto& ctxIdxMap = _ctxIdxMaps[ctxIdxMapIdx];
int ctxIdx = ctxIdxMap.evolve(bit, &ctxIdxMap[i][idx]);
......@@ -273,18 +287,19 @@ GeometryOctreeEncoder::encodeOccupancyBitwise(
int mappedOccIsPredicted,
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1)
int mappedOccAdjGt1,
int mappedOccAdjUnocc)
{
if (neighPattern == 0) {
encodeOccupancyNeighZ(
mappedOccupancy, mappedOccIsPredicted, mappedOccPrediction,
mappedOccAdjGt0, mappedOccAdjGt1);
mappedOccAdjGt0, mappedOccAdjGt1, mappedOccAdjUnocc);
return;
}
encodeOccupancyNeighNZ(
neighPattern, mappedOccupancy, mappedOccIsPredicted, mappedOccPrediction,
mappedOccAdjGt0, mappedOccAdjGt1);
mappedOccAdjGt0, mappedOccAdjGt1, mappedOccAdjUnocc);
}
//-------------------------------------------------------------------------
......@@ -311,7 +326,8 @@ GeometryOctreeEncoder::encodeOccupancy(
int occupancyIsPred,
int occupancyPred,
int occupancyAdjGt0,
int occupancyAdjGt1)
int occupancyAdjGt1,
int occupancyAdjUnocc)
{
if (neighPattern == 0) {
bool singleChild = !popcntGt1(occupancy);
......@@ -331,10 +347,12 @@ GeometryOctreeEncoder::encodeOccupancy(
uint32_t mapOccP = mapGeometryOccupancy(occupancyPred, neighPattern);
uint32_t mapAdjGt0 = mapGeometryOccupancy(occupancyAdjGt0, neighPattern);
uint32_t mapAdjGt1 = mapGeometryOccupancy(occupancyAdjGt1, neighPattern);
uint32_t mapAdjUnocc = mapGeometryOccupancy(occupancyAdjUnocc, neighPattern);
if (_useBitwiseOccupancyCoder)
encodeOccupancyBitwise(
neighPattern, mapOcc, mapOccIsP, mapOccP, mapAdjGt0, mapAdjGt1);
neighPattern, mapOcc, mapOccIsP, mapOccP, mapAdjGt0, mapAdjGt1,
mapAdjUnocc);
else
encodeOccupancyBytewise(neighPattern, mapOcc);
}
......@@ -477,6 +495,7 @@ encodeGeometryOctree(
int occupancyAdjacencyGt0 = 0;
int occupancyAdjacencyGt1 = 0;
int occupancyAdjacencyUnocc = 0;
if (gps.neighbour_avail_boundary_log2) {
updateGeometryOccupancyAtlas(
......@@ -490,6 +509,7 @@ encodeGeometryOctree(
node0.neighPattern = gnp.neighPattern;
occupancyAdjacencyGt0 = gnp.adjacencyGt0;
occupancyAdjacencyGt1 = gnp.adjacencyGt1;
occupancyAdjacencyUnocc = gnp.adjacencyUnocc;
}
int occupancyIsPredicted = 0;
......@@ -512,7 +532,7 @@ encodeGeometryOctree(
assert(occupancy > 0);
encoder.encodeOccupancy(
node0.neighPattern, occupancy, occupancyIsPredicted, occupancyPrediction,
occupancyAdjacencyGt0, occupancyAdjacencyGt1);
occupancyAdjacencyGt0, occupancyAdjacencyGt1, occupancyAdjacencyUnocc);
// when nodeSizeLog2 == 1, children are indivisible (ie leaf nodes)
// and are immediately coded. No further splitting occurs.
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment