diff --git a/av1/common/mvref_common.h b/av1/common/mvref_common.h index b854304b25656535c86adae2868ddc5666dcbfa0..ea131d1c08bd291039a60c8966452ee5fefb0b54 100644 --- a/av1/common/mvref_common.h +++ b/av1/common/mvref_common.h @@ -438,8 +438,11 @@ static INLINE void av1_find_ref_dv(int_mv *ref_dv, int mi_row, int mi_col) { } } -static INLINE int is_dv_valid(const MV dv, const TileInfo *const tile, - int mi_row, int mi_col, BLOCK_SIZE bsize) { +#define INTRABC_DELAY 0 // Writing back delay in units of super-block. +#define USE_WAVE_FRONT 0 // Use only top left area of frame for reference. +static INLINE int av1_is_dv_valid(const MV dv, const TileInfo *const tile, + int mi_row, int mi_col, BLOCK_SIZE bsize, + int mib_size_log2) { const int bw = block_size_wide[bsize]; const int bh = block_size_high[bsize]; const int SCALE_PX_TO_MV = 8; @@ -461,17 +464,26 @@ static INLINE int is_dv_valid(const MV dv, const TileInfo *const tile, const int src_right_edge = (mi_col * MI_SIZE + bw) * SCALE_PX_TO_MV + dv.col; const int tile_right_edge = tile->mi_col_end * MI_SIZE * SCALE_PX_TO_MV; if (src_right_edge > tile_right_edge) return 0; - // Is the bottom right within an already coded SB? - const int active_sb_top_edge = - (mi_row & ~MAX_MIB_MASK) * MI_SIZE * SCALE_PX_TO_MV; - const int active_sb_bottom_edge = - ((mi_row & ~MAX_MIB_MASK) + MAX_MIB_SIZE) * MI_SIZE * SCALE_PX_TO_MV; - const int active_sb_left_edge = - (mi_col & ~MAX_MIB_MASK) * MI_SIZE * SCALE_PX_TO_MV; - if (src_bottom_edge > active_sb_bottom_edge) return 0; - if (src_bottom_edge > active_sb_top_edge && - src_right_edge > active_sb_left_edge) + + // Is the bottom right within an already coded SB? Also consider additional + // constraints to facilitate HW decoder. + const int max_mib_size = 1 << mib_size_log2; + const int active_sb_row = mi_row >> mib_size_log2; + const int active_sb_col = mi_col >> mib_size_log2; + const int sb_size = max_mib_size * MI_SIZE; + const int src_sb_row = ((src_bottom_edge >> 3) - 1) / sb_size; + const int src_sb_col = ((src_right_edge >> 3) - 1) / sb_size; +#if USE_WAVE_FRONT + if (src_sb_row > active_sb_row || + src_sb_col >= + active_sb_col - INTRABC_DELAY + 2 * (active_sb_row - src_sb_row)) + return 0; +#else + if (src_sb_row > active_sb_row || + (src_sb_row == active_sb_row && + src_sb_col >= active_sb_col - INTRABC_DELAY)) return 0; +#endif return 1; } #endif // CONFIG_INTRABC diff --git a/av1/decoder/decodemv.c b/av1/decoder/decodemv.c index 49e95e7630d5c6a91f196f9d0bb771006607009f..2a8ac337815ae00a0f312d246b82fd9d49294778 100644 --- a/av1/decoder/decodemv.c +++ b/av1/decoder/decodemv.c @@ -997,7 +997,8 @@ static INLINE int assign_dv(AV1_COMMON *cm, MACROBLOCKD *xd, int_mv *mv, mv->as_mv.col = (mv->as_mv.col >> 3) << 3; mv->as_mv.row = (mv->as_mv.row >> 3) << 3; int valid = is_mv_valid(&mv->as_mv) && - is_dv_valid(mv->as_mv, &xd->tile, mi_row, mi_col, bsize); + av1_is_dv_valid(mv->as_mv, &xd->tile, mi_row, mi_col, bsize, + cm->mib_size_log2); return valid; } #endif // CONFIG_INTRABC diff --git a/av1/encoder/mcomp.c b/av1/encoder/mcomp.c index 63f81056eeaa4ace7b279d85c73cf94843dfc4c1..66b6c724cfb49ac48111af37a02b94fe1f45625a 100644 --- a/av1/encoder/mcomp.c +++ b/av1/encoder/mcomp.c @@ -2699,21 +2699,28 @@ int av1_full_pixel_search(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize, break; } +#if CONFIG_INTRABC + MACROBLOCKD *const xd = &x->e_mbd; + const TileInfo *tile = &xd->tile; + const int mi_col = x_pos / MI_SIZE; + const int mi_row = y_pos / MI_SIZE; +#endif // CONFIG_INTRABC Iterator iterator = av1_hash_get_first_iterator(ref_frame_hash, hash_value1); for (i = 0; i < count; i++, iterator_increment(&iterator)) { block_hash ref_block_hash = *(block_hash *)(iterator_get(&iterator)); if (hash_value2 == ref_block_hash.hash_value2) { - // for intra, make sure the prediction is from valid area - // not predict from current block. - // TODO(roger): check if the constrain is necessary - if (intra && - ref_block_hash.y + block_height > - ((y_pos >> MAX_SB_SIZE_LOG2) << MAX_SB_SIZE_LOG2) && - ref_block_hash.x + block_width > - ((x_pos >> MAX_SB_SIZE_LOG2) << MAX_SB_SIZE_LOG2)) { - continue; +// for intra, make sure the prediction is from valid area +// not predict from current block. +#if CONFIG_INTRABC + if (intra) { + const MV dv = { 8 * (ref_block_hash.y - y_pos), + 8 * (ref_block_hash.x - x_pos) }; + if (!av1_is_dv_valid(dv, tile, mi_row, mi_col, bsize, + cpi->common.mib_size_log2)) + continue; } +#endif // CONFIG_INTRABC int refCost = abs(ref_block_hash.x - x_pos) + abs(ref_block_hash.y - y_pos); add_to_sort_table(block_hashes, costs, &existing, diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c index 779d4177036dbd98ec8072412084704fe3591e4e..682f56865e56b256742111659dece9b31ca9beda 100644 --- a/av1/encoder/rdopt.c +++ b/av1/encoder/rdopt.c @@ -8856,7 +8856,8 @@ static int64_t rd_pick_intrabc_mode_sb(const AV1_COMP *cpi, MACROBLOCK *x, mvp_full = x->best_mv.as_mv; MV dv = {.row = mvp_full.row * 8, .col = mvp_full.col * 8 }; if (mv_check_bounds(&x->mv_limits, &dv)) continue; - if (!is_dv_valid(dv, tile, mi_row, mi_col, bsize)) continue; + if (!av1_is_dv_valid(dv, tile, mi_row, mi_col, bsize, cm->mib_size_log2)) + continue; // DV should not have sub-pel. assert((dv.col & 7) == 0); diff --git a/test/intrabc_test.cc b/test/intrabc_test.cc index 84cfa5c4855eb8bca0536e153cc46fac7755ac80..5f6e90e9bf11834e530962cf5bf129d576d38675 100644 --- a/test/intrabc_test.cc +++ b/test/intrabc_test.cc @@ -147,10 +147,10 @@ TEST(IntrabcTest, DvValidation) { tile.mi_col_end = tile.mi_col_start + kTileMaxMibWidth * MAX_MIB_SIZE; for (int i = 0; i < static_cast(GTEST_ARRAY_SIZE_(kDvCases)); ++i) { EXPECT_EQ(kDvCases[i].valid, - is_dv_valid(kDvCases[i].dv, &tile, - tile.mi_row_start + kDvCases[i].mi_row_offset, - tile.mi_col_start + kDvCases[i].mi_col_offset, - kDvCases[i].bsize)) + av1_is_dv_valid(kDvCases[i].dv, &tile, + tile.mi_row_start + kDvCases[i].mi_row_offset, + tile.mi_col_start + kDvCases[i].mi_col_offset, + kDvCases[i].bsize, MAX_MIB_SIZE_LOG2)) << "DvCases[" << i << "]"; } }