Commit 90e8646a authored by David Flynn's avatar David Flynn
Browse files

geom/m43600: bit-wise occupancy prediction framework

This commit provides the ability to contextualise occupancy bits using
a prediction.  Three context sets cover the not predicted, predicted
unoccupied and predicted occupied cases.
parent d3560c60
...@@ -55,15 +55,18 @@ public: ...@@ -55,15 +55,18 @@ public:
int decodePositionLeafNumPoints(); int decodePositionLeafNumPoints();
int decodeOccupancyNeighZ(); int decodeOccupancyNeighZ(int mappedOccIsPredicted, int mappedOccPrediction);
int decodeOccupancyNeighNZ(int neighPattern10); int decodeOccupancyNeighNZ(
int neighPattern10, int mappedOccIsPredicted, int mappedOccPrediction);
int decodeOccupancyBitwise(int neighPattern); int decodeOccupancyBitwise(
int neighPattern, int mappedOccIsPredicted, int mappedOccPrediction);
int decodeOccupancyBytewise(int neighPattern); int decodeOccupancyBytewise(int neighPattern);
uint32_t decodeOccupancy(int neighPattern); uint32_t decodeOccupancy(
int neighPattern, int occupancyIsPredicted, int occupancyPrediction);
PCCVector3<uint32_t> decodePointPosition(int nodeSizeLog2); PCCVector3<uint32_t> decodePointPosition(int nodeSizeLog2);
...@@ -86,8 +89,11 @@ private: ...@@ -86,8 +89,11 @@ private:
o3dgc::Adaptive_Bit_Model _ctxNumIdcmPointsEq1; o3dgc::Adaptive_Bit_Model _ctxNumIdcmPointsEq1;
// For bitwise occupancy coding // For bitwise occupancy coding
// map 0 = not predicted
// map 1 = predicted unnoccupied
// map 2 = predicted occupied
CtxModelOctreeOccupancy _ctxOccupancy; CtxModelOctreeOccupancy _ctxOccupancy;
CtxMapOctreeOccupancy _ctxIdxMap; CtxMapOctreeOccupancy _ctxIdxMaps[3];
// For bytewise occupancy coding // For bytewise occupancy coding
DualLutCoder<true> _bytewiseOccupancyCoder[10]; DualLutCoder<true> _bytewiseOccupancyCoder[10];
...@@ -139,24 +145,31 @@ GeometryOctreeDecoder::decodePositionLeafNumPoints() ...@@ -139,24 +145,31 @@ GeometryOctreeDecoder::decodePositionLeafNumPoints()
// decode occupancy bits (neighPattern10 == 0 case) // decode occupancy bits (neighPattern10 == 0 case)
int int
GeometryOctreeDecoder::decodeOccupancyNeighZ() GeometryOctreeDecoder::decodeOccupancyNeighZ(
int mappedOccIsPredicted, int mappedOccPrediction)
{ {
static const int8_t occupancyCodingOrder[8]{1, 7, 5, 3, 2, 4, 6, 0}; static const int8_t bitCodingOrder[8]{1, 7, 5, 3, 2, 4, 6, 0};
int minOccupied = 2; int minOccupied = 2;
int numOccupiedAcc = 0; int numOccupiedAcc = 0;
int occupancy = 0; int occupancy = 0;
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
int bit = 1; int bit = 1;
int bitIsPredicted = (mappedOccIsPredicted >> bitCodingOrder[i]) & 1;
int bitPrediction = (mappedOccPrediction >> bitCodingOrder[i]) & 1;
int ctxIdxMapIdx = bitIsPredicted + bitPrediction;
auto& ctxIdxMap = _ctxIdxMaps[ctxIdxMapIdx];
// NB: There must be at least two occupied child nodes // NB: There must be at least two occupied child nodes
// -- avoid coding the occupancy bit if it is implied. // -- avoid coding the occupancy bit if it is implied.
if (numOccupiedAcc >= minOccupied + i - 7) { if (numOccupiedAcc >= minOccupied + i - 7) {
int ctxIdx = _ctxIdxMap[i][numOccupiedAcc]; int ctxIdx = ctxIdxMap[i][numOccupiedAcc];
bit = _arithmeticDecoder->decode(_ctxOccupancy[ctxIdx]); bit = _arithmeticDecoder->decode(_ctxOccupancy[ctxIdx]);
} }
_ctxIdxMap.evolve(bit, &_ctxIdxMap[i][numOccupiedAcc]); ctxIdxMap.evolve(bit, &ctxIdxMap[i][numOccupiedAcc]);
numOccupiedAcc += bit; numOccupiedAcc += bit;
occupancy |= bit << occupancyCodingOrder[i]; occupancy |= bit << bitCodingOrder[i];
} }
return occupancy; return occupancy;
...@@ -166,9 +179,10 @@ GeometryOctreeDecoder::decodeOccupancyNeighZ() ...@@ -166,9 +179,10 @@ GeometryOctreeDecoder::decodeOccupancyNeighZ()
// decode occupancy bits (neighPattern10 != 0 case) // decode occupancy bits (neighPattern10 != 0 case)
int int
GeometryOctreeDecoder::decodeOccupancyNeighNZ(int neighPattern10) GeometryOctreeDecoder::decodeOccupancyNeighNZ(
int neighPattern10, int mappedOccIsPredicted, int mappedOccPrediction)
{ {
static const int8_t occupancyCodingOrder[8]{1, 7, 5, 3, 2, 4, 6, 0}; static const int8_t bitCodingOrder[8]{1, 7, 5, 3, 2, 4, 6, 0};
int neighPattern7 = kNeighPattern10to7[neighPattern10]; int neighPattern7 = kNeighPattern10to7[neighPattern10];
int neighPattern5 = kNeighPattern7to5[neighPattern7]; int neighPattern5 = kNeighPattern7to5[neighPattern7];
...@@ -193,14 +207,20 @@ GeometryOctreeDecoder::decodeOccupancyNeighNZ(int neighPattern10) ...@@ -193,14 +207,20 @@ GeometryOctreeDecoder::decodeOccupancyNeighNZ(int neighPattern10)
// NB: if firt 7 bits are 0, then the last is implicitly 1. // NB: if firt 7 bits are 0, then the last is implicitly 1.
int bit = 1; int bit = 1;
int bitIsPredicted = (mappedOccIsPredicted >> bitCodingOrder[i]) & 1;
int bitPrediction = (mappedOccPrediction >> bitCodingOrder[i]) & 1;
int ctxIdxMapIdx = bitIsPredicted + bitPrediction;
auto& ctxIdxMap = _ctxIdxMaps[ctxIdxMapIdx];
if (i < 7 || partialOccupancy) { if (i < 7 || partialOccupancy) {
int ctxIdx = _ctxIdxMap[i][idx]; int ctxIdx = ctxIdxMap[i][idx];
bit = _arithmeticDecoder->decode(_ctxOccupancy[ctxIdx]); bit = _arithmeticDecoder->decode(_ctxOccupancy[ctxIdx]);
} }
_ctxIdxMap.evolve(bit, &_ctxIdxMap[i][idx]); ctxIdxMap.evolve(bit, &ctxIdxMap[i][idx]);
partialOccupancy |= bit << i; partialOccupancy |= bit << i;
occupancy |= bit << occupancyCodingOrder[i]; occupancy |= bit << bitCodingOrder[i];
} }
return occupancy; return occupancy;
...@@ -209,16 +229,18 @@ GeometryOctreeDecoder::decodeOccupancyNeighNZ(int neighPattern10) ...@@ -209,16 +229,18 @@ GeometryOctreeDecoder::decodeOccupancyNeighNZ(int neighPattern10)
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
int int
GeometryOctreeDecoder::decodeOccupancyBitwise(int neighPattern) GeometryOctreeDecoder::decodeOccupancyBitwise(
int neighPattern, int mappedOccIsPredicted, int mappedOccPrediction)
{ {
if (neighPattern == 0) { if (neighPattern == 0) {
return decodeOccupancyNeighZ(); return decodeOccupancyNeighZ(mappedOccIsPredicted, mappedOccPrediction);
} }
// code occupancy using the neighbour configuration context // code occupancy using the neighbour configuration context
// with reduction from 64 states to 10 (or 6). // with reduction from 64 states to 10 (or 6).
int neighPatternR1 = _neighPattern64toR1[neighPattern]; int neighPatternR1 = _neighPattern64toR1[neighPattern];
return decodeOccupancyNeighNZ(neighPatternR1); return decodeOccupancyNeighNZ(
neighPatternR1, mappedOccIsPredicted, mappedOccPrediction);
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
...@@ -238,7 +260,8 @@ GeometryOctreeDecoder::decodeOccupancyBytewise(int neighPattern) ...@@ -238,7 +260,8 @@ GeometryOctreeDecoder::decodeOccupancyBytewise(int neighPattern)
// //
uint32_t uint32_t
GeometryOctreeDecoder::decodeOccupancy(int neighPattern) GeometryOctreeDecoder::decodeOccupancy(
int neighPattern, int occupancyIsPred, int occupancyPred)
{ {
// decode occupancy pattern // decode occupancy pattern
uint32_t occupancy; uint32_t occupancy;
...@@ -253,10 +276,12 @@ GeometryOctreeDecoder::decodeOccupancy(int neighPattern) ...@@ -253,10 +276,12 @@ GeometryOctreeDecoder::decodeOccupancy(int neighPattern)
} }
} }
uint32_t mapOccIsP = mapGeometryOccupancy(occupancyIsPred, neighPattern);
uint32_t mapOccP = mapGeometryOccupancy(occupancyPred, neighPattern);
uint32_t mappedOccupancy; uint32_t mappedOccupancy;
if (_useBitwiseOccupancyCoder) if (_useBitwiseOccupancyCoder)
mappedOccupancy = decodeOccupancyBitwise(neighPattern); mappedOccupancy = decodeOccupancyBitwise(neighPattern, mapOccIsP, mapOccP);
else else
mappedOccupancy = decodeOccupancyBytewise(neighPattern); mappedOccupancy = decodeOccupancyBytewise(neighPattern);
...@@ -385,8 +410,12 @@ decodeGeometryOctree( ...@@ -385,8 +410,12 @@ decodeGeometryOctree(
makeGeometryNeighPattern(node0.pos, nodeSizeLog2, occupancyAtlas); makeGeometryNeighPattern(node0.pos, nodeSizeLog2, occupancyAtlas);
} }
int occupancyIsPredicted = 0;
int occupancyPrediction = 0;
// decode occupancy pattern // decode occupancy pattern
uint8_t occupancy = decoder.decodeOccupancy(node0.neighPattern); uint8_t occupancy = decoder.decodeOccupancy(
node0.neighPattern, occupancyIsPredicted, occupancyPrediction);
assert(occupancy > 0); assert(occupancy > 0);
......
...@@ -55,15 +55,28 @@ public: ...@@ -55,15 +55,28 @@ public:
int encodePositionLeafNumPoints(int count); int encodePositionLeafNumPoints(int count);
void encodeOccupancyNeighZ(int mappedOccupancy); void encodeOccupancyNeighZ(
int mappedOccupancy, int mappedOccIsPredicted, int mappedOccPrediction);
void encodeOccupancyNeighNZ(int mappedOccupancy, int neighPattern10); void encodeOccupancyNeighNZ(
int neighPattern10,
int mappedOccupancy,
int mappedOccIsPredicted,
int mappedOccPrediction);
void encodeOccupancyBitwise(int mappedOccupancy, int neighPattern); void encodeOccupancyBitwise(
int neighPattern,
int mappedOccupancy,
int mappedOccIsPredicted,
int mappedOccPrediction);
void encodeOccupancyBytewise(int mappedOccupancy, int neighPattern); void encodeOccupancyBytewise(int neighPattern, int mappedOccupancy);
void encodeOccupancy(int occupancy, int neighPattern); void encodeOccupancy(
int neighPattern,
int occupancy,
int occupancyIsPredicted,
int occupancyPrediction);
void encodePointPosition(int nodeSizeLog2, const PCCVector3<uint32_t>& pos); void encodePointPosition(int nodeSizeLog2, const PCCVector3<uint32_t>& pos);
...@@ -87,8 +100,11 @@ private: ...@@ -87,8 +100,11 @@ private:
o3dgc::Adaptive_Bit_Model _ctxNumIdcmPointsEq1; o3dgc::Adaptive_Bit_Model _ctxNumIdcmPointsEq1;
// For bitwise occupancy coding // For bitwise occupancy coding
// map 0 = not predicted
// map 1 = predicted unnoccupied
// map 2 = predicted occupied
CtxModelOctreeOccupancy _ctxOccupancy; CtxModelOctreeOccupancy _ctxOccupancy;
CtxMapOctreeOccupancy _ctxIdxMap; CtxMapOctreeOccupancy _ctxIdxMaps[3];
// For bytewise occupancy coding // For bytewise occupancy coding
DualLutCoder<true> _bytewiseOccupancyCoder[10]; DualLutCoder<true> _bytewiseOccupancyCoder[10];
...@@ -140,25 +156,31 @@ GeometryOctreeEncoder::encodePositionLeafNumPoints(int count) ...@@ -140,25 +156,31 @@ GeometryOctreeEncoder::encodePositionLeafNumPoints(int count)
// encode occupancy bits (neighPattern10 == 0 case) // encode occupancy bits (neighPattern10 == 0 case)
void void
GeometryOctreeEncoder::encodeOccupancyNeighZ(int mappedOccupancy) GeometryOctreeEncoder::encodeOccupancyNeighZ(
int mappedOccupancy, int mappedOccIsPredicted, int mappedOccPrediction)
{ {
static const int8_t occupancyCodingOrder[8]{1, 7, 5, 3, 2, 4, 6, 0}; static const int8_t bitCodingOrder[8]{1, 7, 5, 3, 2, 4, 6, 0};
int minOccupied = 2; int minOccupied = 2;
int numOccupiedAcc = 0; int numOccupiedAcc = 0;
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
int occupancyBit = (mappedOccupancy >> occupancyCodingOrder[i]) & 1; int bit = (mappedOccupancy >> bitCodingOrder[i]) & 1;
int bitIsPredicted = (mappedOccIsPredicted >> bitCodingOrder[i]) & 1;
int bitPrediction = (mappedOccPrediction >> bitCodingOrder[i]) & 1;
int ctxIdxMapIdx = bitIsPredicted + bitPrediction;
auto& ctxIdxMap = _ctxIdxMaps[ctxIdxMapIdx];
int idx = numOccupiedAcc; int idx = numOccupiedAcc;
int ctxIdx = _ctxIdxMap.evolve(occupancyBit, &_ctxIdxMap[i][idx]); int ctxIdx = ctxIdxMap.evolve(bit, &ctxIdxMap[i][idx]);
// NB: There must be at least minOccupied child nodes // NB: There must be at least minOccupied child nodes
// -- avoid coding the occupancyBit if it is implied. // -- avoid coding the occupancyBit if it is implied.
if (numOccupiedAcc >= minOccupied + i - 7) { if (numOccupiedAcc >= minOccupied + i - 7) {
_arithmeticEncoder->encode(occupancyBit, _ctxOccupancy[ctxIdx]); _arithmeticEncoder->encode(bit, _ctxOccupancy[ctxIdx]);
} }
numOccupiedAcc += occupancyBit; numOccupiedAcc += bit;
} }
} }
...@@ -167,9 +189,12 @@ GeometryOctreeEncoder::encodeOccupancyNeighZ(int mappedOccupancy) ...@@ -167,9 +189,12 @@ GeometryOctreeEncoder::encodeOccupancyNeighZ(int mappedOccupancy)
void void
GeometryOctreeEncoder::encodeOccupancyNeighNZ( GeometryOctreeEncoder::encodeOccupancyNeighNZ(
int mappedOccupancy, int neighPattern10) int neighPattern10,
int mappedOccupancy,
int mappedOccIsPredicted,
int mappedOccPrediction)
{ {
static const int8_t occupancyCodingOrder[8]{1, 7, 5, 3, 2, 4, 6, 0}; static const int8_t bitCodingOrder[8]{1, 7, 5, 3, 2, 4, 6, 0};
int neighPattern7 = kNeighPattern10to7[neighPattern10]; int neighPattern7 = kNeighPattern10to7[neighPattern10];
int neighPattern5 = kNeighPattern7to5[neighPattern7]; int neighPattern5 = kNeighPattern7to5[neighPattern7];
...@@ -178,8 +203,6 @@ GeometryOctreeEncoder::encodeOccupancyNeighNZ( ...@@ -178,8 +203,6 @@ GeometryOctreeEncoder::encodeOccupancyNeighNZ(
// NB: it is impossible for pattern to be 0 (handled in Z case). // NB: it is impossible for pattern to be 0 (handled in Z case).
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
int occupancyBit = (mappedOccupancy >> occupancyCodingOrder[i]) & 1;
int idx; int idx;
if (i < 6) { if (i < 6) {
idx = ((neighPattern10 - 1) << i) + partialOccupancy + i + 1; idx = ((neighPattern10 - 1) << i) + partialOccupancy + i + 1;
...@@ -192,13 +215,20 @@ GeometryOctreeEncoder::encodeOccupancyNeighNZ( ...@@ -192,13 +215,20 @@ GeometryOctreeEncoder::encodeOccupancyNeighNZ(
break; break;
} }
int ctxIdx = _ctxIdxMap.evolve(occupancyBit, &_ctxIdxMap[i][idx]); int bit = (mappedOccupancy >> bitCodingOrder[i]) & 1;
int bitIsPredicted = (mappedOccIsPredicted >> bitCodingOrder[i]) & 1;
int bitPrediction = (mappedOccPrediction >> bitCodingOrder[i]) & 1;
int ctxIdxMapIdx = bitIsPredicted + bitPrediction;
auto& ctxIdxMap = _ctxIdxMaps[ctxIdxMapIdx];
int ctxIdx = ctxIdxMap.evolve(bit, &ctxIdxMap[i][idx]);
// NB: if firt 7 bits are 0, then the last is implicitly 1. // NB: if firt 7 bits are 0, then the last is implicitly 1.
if (i < 7 || partialOccupancy) if (i < 7 || partialOccupancy)
_arithmeticEncoder->encode(occupancyBit, _ctxOccupancy[ctxIdx]); _arithmeticEncoder->encode(bit, _ctxOccupancy[ctxIdx]);
partialOccupancy |= occupancyBit << i; partialOccupancy |= bit << i;
} }
} }
...@@ -206,17 +236,23 @@ GeometryOctreeEncoder::encodeOccupancyNeighNZ( ...@@ -206,17 +236,23 @@ GeometryOctreeEncoder::encodeOccupancyNeighNZ(
void void
GeometryOctreeEncoder::encodeOccupancyBitwise( GeometryOctreeEncoder::encodeOccupancyBitwise(
int mappedOccupancy, int neighPattern) int neighPattern,
int mappedOccupancy,
int mappedOccIsPredicted,
int mappedOccPrediction)
{ {
if (neighPattern == 0) { if (neighPattern == 0) {
encodeOccupancyNeighZ(mappedOccupancy); encodeOccupancyNeighZ(
mappedOccupancy, mappedOccIsPredicted, mappedOccPrediction);
return; return;
} }
// code occupancy using the neighbour configuration context // code occupancy using the neighbour configuration context
// with reduction from 64 states to 10 (or 6). // with reduction from 64 states to 10 (or 6).
int neighPatternR1 = _neighPattern64toR1[neighPattern]; int neighPatternR1 = _neighPattern64toR1[neighPattern];
encodeOccupancyNeighNZ(mappedOccupancy, neighPatternR1); encodeOccupancyNeighNZ(
neighPatternR1, mappedOccupancy, mappedOccIsPredicted,
mappedOccPrediction);
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
...@@ -237,7 +273,8 @@ GeometryOctreeEncoder::encodeOccupancyBytewise( ...@@ -237,7 +273,8 @@ GeometryOctreeEncoder::encodeOccupancyBytewise(
// //
void void
GeometryOctreeEncoder::encodeOccupancy(int occupancy, int neighPattern) GeometryOctreeEncoder::encodeOccupancy(
int neighPattern, int occupancy, int occupancyIsPred, int occupancyPred)
{ {
if (neighPattern == 0) { if (neighPattern == 0) {
bool singleChild = !popcntGt1(occupancy); bool singleChild = !popcntGt1(occupancy);
...@@ -252,12 +289,14 @@ GeometryOctreeEncoder::encodeOccupancy(int occupancy, int neighPattern) ...@@ -252,12 +289,14 @@ GeometryOctreeEncoder::encodeOccupancy(int occupancy, int neighPattern)
} }
} }
uint32_t mappedOccupancy = mapGeometryOccupancy(occupancy, neighPattern); uint32_t mapOcc = mapGeometryOccupancy(occupancy, neighPattern);
uint32_t mapOccIsP = mapGeometryOccupancy(occupancyIsPred, neighPattern);
uint32_t mapOccP = mapGeometryOccupancy(occupancyPred, neighPattern);
if (_useBitwiseOccupancyCoder) if (_useBitwiseOccupancyCoder)
encodeOccupancyBitwise(mappedOccupancy, neighPattern); encodeOccupancyBitwise(neighPattern, mapOcc, mapOccIsP, mapOccP);
else else
encodeOccupancyBytewise(mappedOccupancy, neighPattern); encodeOccupancyBytewise(neighPattern, mapOcc);
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
...@@ -410,9 +449,14 @@ encodeGeometryOctree( ...@@ -410,9 +449,14 @@ encodeGeometryOctree(
makeGeometryNeighPattern(node0.pos, nodeSizeLog2, occupancyAtlas); makeGeometryNeighPattern(node0.pos, nodeSizeLog2, occupancyAtlas);
} }
int occupancyIsPredicted = 0;
int occupancyPrediction = 0;
// encode child occupancy map // encode child occupancy map
assert(occupancy > 0); assert(occupancy > 0);
encoder.encodeOccupancy(occupancy, node0.neighPattern); encoder.encodeOccupancy(
node0.neighPattern, occupancy, occupancyIsPredicted,
occupancyPrediction);
// when nodeSizeLog2 == 1, children are indivisible (ie leaf nodes) // when nodeSizeLog2 == 1, children are indivisible (ie leaf nodes)
// and are immediately coded. No further splitting occurs. // 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