rtc: Reset the IntraBC flag in setup_planes setup_planes() builds the superblock prediction for the variance partitioning with the mode info of the superblock. Nonrd doesn't clear the mode info between frames. e161f898a0 reset the fields this prediction reads, but not use_intrabc, so after a key frame coded with IntraBC the flag can still be set. The prediction then takes the IntraBC path and copies from the frame being coded instead of LAST. Those pixels are either not coded yet or being coded by another thread, so the partition depends on thread timing and on the thread count. Clear use_intrabc with the other fields. The new AVxEncoderThreadRTIntraBCTest codes screendata.y4m with IntraBC, 2x2 tiles and row mt at speeds 7 to 11, and checks that 1, 2 and 4 threads give the same output. It fails at every speed without the fix and passes with it, in realtime only and default builds, on arm and x86. On a 2558x1372 screen recording at 4 threads with an active map, slower threads gave a stream that differed by 1 byte in two frames. With the fix all 6 runs give the same stream. Encodes without IntraBC are bit exact. Change-Id: Iccd0c25edc6696a5ec57fa74740db64778c89349
diff --git a/av1/encoder/var_based_part.c b/av1/encoder/var_based_part.c index cce5da9..24b367f 100644 --- a/av1/encoder/var_based_part.c +++ b/av1/encoder/var_based_part.c
@@ -1468,6 +1468,7 @@ mi->bsize = cm->seq_params->sb_size; mi->mv[0].as_int = 0; mi->interp_filters = av1_broadcast_interp_filter(BILINEAR); + mi->use_intrabc = 0; if (use_last_ref) { av1_setup_pre_planes(
diff --git a/test/ethread_test.cc b/test/ethread_test.cc index b366422..215f740 100644 --- a/test/ethread_test.cc +++ b/test/ethread_test.cc
@@ -466,6 +466,72 @@ ::testing::Values(0, 2), ::testing::Values(0, 2), ::testing::Values(0, 1)); +// Codes a key frame with IntraBC and then screen content in motion, with two +// tile rows so that several threads code the inter frames at once. The output +// must not depend on the number of threads. +class AVxEncoderThreadRTIntraBCTest + : public ::libaom_test::CodecTestWithParam<int>, + public ::libaom_test::EncoderTest { + protected: + static const int kFrames = 10; + + AVxEncoderThreadRTIntraBCTest() + : EncoderTest(GET_PARAM(0)), cpu_used_(GET_PARAM(1)) {} + ~AVxEncoderThreadRTIntraBCTest() override = default; + + void SetUp() override { + InitializeConfig(::libaom_test::kRealTime); + cfg_.g_lag_in_frames = 0; + cfg_.rc_end_usage = AOM_CBR; + cfg_.rc_target_bitrate = 1000; + cfg_.kf_max_dist = 90000; + } + + void PreEncodeFrameHook(::libaom_test::VideoSource *video, + ::libaom_test::Encoder *encoder) override { + if (video->frame() != 0) return; + encoder->Control(AOME_SET_CPUUSED, cpu_used_); + encoder->Control(AV1E_SET_TUNE_CONTENT, AOM_CONTENT_SCREEN); + encoder->Control(AV1E_SET_ENABLE_INTRABC, 1); + encoder->Control(AV1E_SET_AQ_MODE, 0); + encoder->Control(AV1E_SET_ROW_MT, 1); + encoder->Control(AV1E_SET_TILE_COLUMNS, 1); + encoder->Control(AV1E_SET_TILE_ROWS, 1); + // Costs updated per superblock differ between one thread and row mt. + encoder->Control(AV1E_SET_COEFF_COST_UPD_FREQ, 3); + encoder->Control(AV1E_SET_MODE_COST_UPD_FREQ, 3); + encoder->Control(AV1E_SET_MV_COST_UPD_FREQ, 3); + } + + void FramePktHook(const aom_codec_cx_pkt_t *pkt) override { + ::libaom_test::MD5 md5; + md5.Add(static_cast<const uint8_t *>(pkt->data.frame.buf), + pkt->data.frame.sz); + md5_.push_back(md5.Get()); + } + + std::vector<std::string> Encode(int threads) { + cfg_.g_threads = threads; + md5_.clear(); + ::libaom_test::Y4mVideoSource video("screendata.y4m", 0, kFrames); + EXPECT_NO_FATAL_FAILURE(RunLoop(&video)); + return md5_; + } + + int cpu_used_; + std::vector<std::string> md5_; +}; + +TEST_P(AVxEncoderThreadRTIntraBCTest, SameOutput) { + const std::vector<std::string> ref = Encode(1); + ASSERT_EQ(ref.size(), static_cast<size_t>(kFrames)); + EXPECT_EQ(ref, Encode(2)); + EXPECT_EQ(ref, Encode(4)); +} + +AV1_INSTANTIATE_TEST_SUITE(AVxEncoderThreadRTIntraBCTest, + ::testing::Range(7, 12)); + #if !CONFIG_REALTIME_ONLY // The AVxEncoderThreadTestLarge takes up ~14% of total run-time of the