Bug 1465619 - Part 14. Add gtests for AnimationFrameRecyclingQueue. r=tnikkel
authorAndrew Osmond <aosmond@mozilla.com>
Wed, 06 Jun 2018 10:31:53 -0400
changeset 442384 2ce8f6d1a64ef8ee845c595bc441234af72422fe
parent 442383 6bf7e20ce8fcd856eb8b11853ec94fb0172a9597
child 442385 f0f7573deea111d97bc96aa6b33e2518ee89da3a
push id109156
push useraosmond@gmail.com
push dateMon, 22 Oct 2018 17:41:47 +0000
treeherdermozilla-inbound@2ce8f6d1a64e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstnikkel
bugs1465619
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1465619 - Part 14. Add gtests for AnimationFrameRecyclingQueue. r=tnikkel Differential Revision: https://phabricator.services.mozilla.com/D7519
image/test/gtest/TestAnimationFrameBuffer.cpp
--- a/image/test/gtest/TestAnimationFrameBuffer.cpp
+++ b/image/test/gtest/TestAnimationFrameBuffer.cpp
@@ -85,18 +85,43 @@ VerifyInsertInternal(AnimationFrameBuffe
   EXPECT_EQ(aFrame, frame.get());
 }
 
 static void
 VerifyAdvance(AnimationFrameBuffer& aQueue,
               size_t aExpectedFrame,
               bool aExpectedRestartDecoder)
 {
+  RefPtr<imgFrame> oldFrame;
+  size_t totalRecycled;
+  if (aQueue.IsRecycling()) {
+    AnimationFrameRecyclingQueue& queue =
+      *static_cast<AnimationFrameRecyclingQueue*>(&aQueue);
+    oldFrame = queue.Get(queue.Displayed(), false);
+    totalRecycled = queue.Recycle().size();
+  }
+
   bool restartDecoder = aQueue.AdvanceTo(aExpectedFrame);
   EXPECT_EQ(aExpectedRestartDecoder, restartDecoder);
+
+  if (aQueue.IsRecycling()) {
+    const AnimationFrameRecyclingQueue& queue =
+      *static_cast<AnimationFrameRecyclingQueue*>(&aQueue);
+    if (oldFrame->ShouldRecycle()) {
+      EXPECT_EQ(oldFrame.get(), queue.Recycle().back().mFrame.get());
+      EXPECT_FALSE(queue.Recycle().back().mDirtyRect.IsEmpty());
+      EXPECT_FALSE(queue.Recycle().back().mRecycleRect.IsEmpty());
+      EXPECT_EQ(totalRecycled + 1, queue.Recycle().size());
+    } else {
+      EXPECT_EQ(totalRecycled, queue.Recycle().size());
+      if (!queue.Recycle().empty()) {
+        EXPECT_NE(oldFrame.get(), queue.Recycle().back().mFrame.get());
+      }
+    }
+  }
 }
 
 static void
 VerifyInsertAndAdvance(AnimationFrameBuffer& aQueue,
                        size_t aExpectedFrame,
                        AnimationFrameBuffer::InsertStatus aExpectedStatus)
 {
   // Insert the decoded frame.
@@ -113,18 +138,30 @@ VerifyInsertAndAdvance(AnimationFrameBuf
   VerifyAdvance(aQueue, aExpectedFrame, expectedRestartDecoder);
 }
 
 static void
 VerifyMarkComplete(AnimationFrameBuffer& aQueue,
                    bool aExpectedContinue,
                    const IntRect& aRefreshArea = IntRect(0, 0, 1, 1))
 {
+  if (aQueue.IsRecycling() && !aQueue.SizeKnown()) {
+    const AnimationFrameRecyclingQueue& queue =
+      *static_cast<AnimationFrameRecyclingQueue*>(&aQueue);
+    EXPECT_TRUE(queue.FirstFrameRefreshArea().IsEmpty());
+  }
+
   bool keepDecoding = aQueue.MarkComplete(aRefreshArea);
   EXPECT_EQ(aExpectedContinue, keepDecoding);
+
+  if (aQueue.IsRecycling()) {
+    const AnimationFrameRecyclingQueue& queue =
+      *static_cast<AnimationFrameRecyclingQueue*>(&aQueue);
+    EXPECT_EQ(aRefreshArea, queue.FirstFrameRefreshArea());
+  }
 }
 
 static void
 VerifyInsert(AnimationFrameBuffer& aQueue,
              AnimationFrameBuffer::InsertStatus aExpectedStatus)
 {
   RefPtr<imgFrame> frame = CreateEmptyFrame();
   AnimationFrameBuffer::InsertStatus status =
@@ -152,16 +189,22 @@ VerifyReset(AnimationFrameBuffer& aQueue
   } else {
     const AnimationFrameDiscardingQueue& queue =
       *static_cast<AnimationFrameDiscardingQueue*>(&aQueue);
     EXPECT_EQ(size_t(0), queue.PendingInsert());
     EXPECT_EQ(size_t(0), queue.Display().size());
     EXPECT_EQ(aFirstFrame, queue.FirstFrame());
     EXPECT_EQ(nullptr, aQueue.Get(0, false));
   }
+
+  if (aQueue.IsRecycling()) {
+    const AnimationFrameRecyclingQueue& queue =
+      *static_cast<AnimationFrameRecyclingQueue*>(&aQueue);
+    EXPECT_EQ(size_t(0), queue.Recycle().size());
+  }
 }
 
 class ImageAnimationFrameBuffer : public ::testing::Test
 {
 public:
   ImageAnimationFrameBuffer()
   { }
 
@@ -510,16 +553,52 @@ TEST_F(ImageAnimationFrameBuffer, Discar
   const size_t kStartFrame = 0;
   AnimationFrameRetainedBuffer retained(kThreshold, kBatch, kStartFrame);
   PrepareForDiscardingQueue(retained);
   const imgFrame* firstFrame = retained.Frames()[0].get();
   AnimationFrameDiscardingQueue buffer(std::move(retained));
   TestDiscardingQueueLoop(buffer, firstFrame, kThreshold, kBatch, kStartFrame);
 }
 
+TEST_F(ImageAnimationFrameBuffer, RecyclingLoop)
+{
+  const size_t kThreshold = 5;
+  const size_t kBatch = 2;
+  const size_t kStartFrame = 0;
+  AnimationFrameRetainedBuffer retained(kThreshold, kBatch, kStartFrame);
+  PrepareForDiscardingQueue(retained);
+  const imgFrame* firstFrame = retained.Frames()[0].get();
+  AnimationFrameRecyclingQueue buffer(std::move(retained));
+
+  // We should not start with any recycled frames.
+  ASSERT_TRUE(buffer.Recycle().empty());
+
+  TestDiscardingQueueLoop(buffer, firstFrame, kThreshold, kBatch, kStartFrame);
+
+  // All the frames we inserted should have been recycleable.
+  ASSERT_FALSE(buffer.Recycle().empty());
+  while (!buffer.Recycle().empty()) {
+    IntRect expectedRect = buffer.Recycle().front().mRecycleRect;
+    RefPtr<imgFrame> expectedFrame = buffer.Recycle().front().mFrame;
+    EXPECT_FALSE(expectedRect.IsEmpty());
+    EXPECT_TRUE(expectedFrame.get() != nullptr);
+
+    IntRect gotRect;
+    RawAccessFrameRef gotFrame = buffer.RecycleFrame(gotRect);
+    EXPECT_EQ(expectedFrame.get(), gotFrame.get());
+    EXPECT_EQ(expectedRect, gotRect);
+  }
+
+  // Trying to pull a recycled frame when we have nothing should be safe too.
+  IntRect gotRect;
+  RawAccessFrameRef gotFrame = buffer.RecycleFrame(gotRect);
+  EXPECT_TRUE(gotFrame.get() == nullptr);
+  EXPECT_TRUE(gotRect.IsEmpty());
+}
+
 static void TestDiscardingQueueReset(AnimationFrameDiscardingQueue& aQueue,
                                      const imgFrame* aFirstFrame,
                                      size_t aThreshold,
                                      size_t aBatch,
                                      size_t aStartFrame)
 {
   // We should be advanced right up to the last decoded frame.
   EXPECT_TRUE(aQueue.MayDiscard());
@@ -542,8 +621,20 @@ TEST_F(ImageAnimationFrameBuffer, Discar
   const size_t kBatch = 3;
   const size_t kStartFrame = 0;
   AnimationFrameRetainedBuffer retained(kThreshold, kBatch, kStartFrame);
   PrepareForDiscardingQueue(retained);
   const imgFrame* firstFrame = retained.Frames()[0].get();
   AnimationFrameDiscardingQueue buffer(std::move(retained));
   TestDiscardingQueueReset(buffer, firstFrame, kThreshold, kBatch, kStartFrame);
 }
+
+TEST_F(ImageAnimationFrameBuffer, RecyclingReset)
+{
+  const size_t kThreshold = 8;
+  const size_t kBatch = 3;
+  const size_t kStartFrame = 0;
+  AnimationFrameRetainedBuffer retained(kThreshold, kBatch, kStartFrame);
+  PrepareForDiscardingQueue(retained);
+  const imgFrame* firstFrame = retained.Frames()[0].get();
+  AnimationFrameRecyclingQueue buffer(std::move(retained));
+  TestDiscardingQueueReset(buffer, firstFrame, kThreshold, kBatch, kStartFrame);
+}