src/ui/scenic/lib/gfx/tests/gfx_apptest.cc
// There is a tricky race condition where if there is an OnFramePresented event in between
// QueuePresent() and Present2 handled on the Scenic side, SafePresenter's tracking of how many
// times it can present can fall out of sync and lead to it going over budget.
There is a tricky race condition where if there is an OnFramePresented event in between
QueuePresent() and Present2 handled on the Scenic side, SafePresenter's tracking of how many
times it can present can fall out of sync and lead to it going over budget.
There is a tricky race condition where if there is an OnFramePresented event in between QueuePresent () and Present2 handled on the Scenic side SafePresenter ' s tracking of how many times it can present can fall out of sync and lead to it going over budget .
TEST_F(GfxSystemTest, SafePresenter_OnFramePresentedRace) {
  async::TestLoop scenic_loop;
  async_set_default_dispatcher(scenic_loop.dispatcher());
  auto session = std::make_unique<scenic::Session>(scenic(), scenic_loop.dispatcher());
  EXPECT_EQ(1U, scenic()->num_sessions());
  auto safe_presenter = std::make_unique<root_presenter::SafePresenter>(session.get());
  int count = 0;
  int expected_count = 0;
  safe_presenter->QueuePresent([&count] { ++count; });
  ++expected_count;
  scenic_loop.RunUntilIdle();
  RunLoopFor(zx::sec(1));
  for (int i = 0; i < 4; ++i) {
    safe_presenter->QueuePresent([&count] { ++count; });
    ++expected_count;
  }
  scenic_loop.RunUntilIdle();
  for (int i = 0; i < 2; ++i) {
    safe_presenter->QueuePresent([&count] { ++count; });
    ++expected_count;
  }
  scenic_loop.RunUntilIdle();
  for (int i = 0; i < 2; ++i) {
    RunLoopFor(zx::sec(1));
    scenic_loop.RunUntilIdle();
  }
  EXPECT_EQ(1U, scenic()->num_sessions());
  EXPECT_EQ(count, expected_count);
}
TEST_F ( GfxSystemTest , SafePresenter_OnFramePresentedRace ) { async :: TestLoop scenic_loop ; async_set_default_dispatcher ( scenic_loop . dispatcher ( ) ) ; auto session = std :: make_unique < scenic :: Session > ( scenic ( ) , scenic_loop . dispatcher ( ) ) ; EXPECT_EQ ( 1U , scenic ( ) -> num_sessions ( ) ) ; auto safe_presenter = std :: make_unique < root_presenter :: SafePresenter > ( session . get ( ) ) ; int count = 0 ; int expected_count = 0 ; safe_presenter -> QueuePresent ( [ & count ] { ++ count ; } ) ; ++ expected_count ; scenic_loop . RunUntilIdle ( ) ; RunLoopFor ( zx :: sec ( 1 ) ) ; for ( int i = 0 ; i < 4 ; ++ i ) { safe_presenter -> QueuePresent ( [ & count ] { ++ count ; } ) ; ++ expected_count ; } scenic_loop . RunUntilIdle ( ) ; for ( int i = 0 ; i < 2 ; ++ i ) { safe_presenter -> QueuePresent ( [ & count ] { ++ count ; } ) ; ++ expected_count ; } scenic_loop . RunUntilIdle ( ) ; for ( int i = 0 ; i < 2 ; ++ i ) { RunLoopFor ( zx :: sec ( 1 ) ) ; scenic_loop . RunUntilIdle ( ) ; } EXPECT_EQ ( 1U , scenic ( ) -> num_sessions ( ) ) ; EXPECT_EQ ( count , expected_count ) ; }
There is a tricky race condition where if there is an OnFramePresented event in between
QueuePresent() and Present2 handled on the Scenic side, SafePresenter's tracking of how many
times it can present can fall out of sync and lead to it going over budget.
There is a tricky race condition where if there is an OnFramePresented event in between QueuePresent () and Present2 handled on the Scenic side SafePresenter ' s tracking of how many times it can present can fall out of sync and lead to it going over budget .
// Create the session's test loop. Scenic relies on the default dispatcher so we set that here. // Create Session // Create SafePresenter // SafePresenter calls Present2 and Scenic receives it. // When we advance this loop, Scenic renders and reaches vsync, thereby firing the // OnFramePresented event. // Before SafePresenter receives the OnFramePresented event, it fires 4 more Present2s. // SafePresenter now knows it has 0 presents left. // When we advance this loop, SafePresenter finally receives the OnFramePresented event. // At this point, SafePresenter thinks it has 5 Present2s left because of the OnFramePresented() // event that fired at the end of the last loop run, which did not take into account the 4 // QueuePresent()s that happened simultaneously. // Scenic knows there is actually only 1 Present2 left, however. Let's enqueue 2 more Present2s to // cause the session to potentially get killed. // If SafePresenter did not handle its bookkeeping correctly, it would crash on this next line. // Finish up to fire the callbacks.