// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "config.h" #include "CCTextureUpdateController.h" #include "CCSchedulerTestCommon.h" #include "CCSingleThreadProxy.h" // For DebugScopedSetImplThread #include "CCTiledLayerTestCommon.h" #include "FakeWebCompositorOutputSurface.h" #include "FakeWebGraphicsContext3D.h" #include "WebCompositorInitializer.h" #include #include #include using namespace cc; using namespace WebKit; using namespace WebKitTests; using testing::Test; namespace { const int kFlushPeriodFull = 4; const int kFlushPeriodPartial = kFlushPeriodFull; class CCTextureUpdateControllerTest; class WebGraphicsContext3DForUploadTest : public FakeWebGraphicsContext3D { public: WebGraphicsContext3DForUploadTest(CCTextureUpdateControllerTest *test) : m_test(test) , m_supportShallowFlush(true) { } virtual void flush(void); virtual void shallowFlushCHROMIUM(void); virtual GrGLInterface* onCreateGrGLInterface() { return 0; } virtual WebString getString(WGC3Denum name) { if (m_supportShallowFlush) return WebString("GL_CHROMIUM_shallow_flush"); return WebString(""); } private: CCTextureUpdateControllerTest* m_test; bool m_supportShallowFlush; }; class TextureUploaderForUploadTest : public FakeTextureUploader { public: TextureUploaderForUploadTest(CCTextureUpdateControllerTest *test) : m_test(test) { } virtual void beginUploads() OVERRIDE; virtual void endUploads() OVERRIDE; virtual void uploadTexture(cc::CCResourceProvider*, Parameters) OVERRIDE; private: CCTextureUpdateControllerTest* m_test; }; class TextureForUploadTest : public LayerTextureUpdater::Texture { public: TextureForUploadTest() : LayerTextureUpdater::Texture(adoptPtr(0)) { } virtual void updateRect(CCResourceProvider*, const IntRect& sourceRect, const IntSize& destOffset) { } }; class CCTextureUpdateControllerTest : public Test { public: CCTextureUpdateControllerTest() : m_queue(adoptPtr(new CCTextureUpdateQueue)) , m_uploader(this) , m_compositorInitializer(m_thread.get()) , m_fullUploadCountExpected(0) , m_partialCountExpected(0) , m_totalUploadCountExpected(0) , m_maxUploadCountPerUpdate(0) , m_numBeginUploads(0) , m_numEndUploads(0) , m_numConsecutiveFlushes(0) , m_numDanglingUploads(0) , m_numTotalUploads(0) , m_numTotalFlushes(0) , m_numPreviousUploads(0) , m_numPreviousFlushes(0) { } public: void onFlush() { // Check for back-to-back flushes. EXPECT_EQ(0, m_numConsecutiveFlushes) << "Back-to-back flushes detected."; // Check for premature flushes if (m_numPreviousUploads != m_maxUploadCountPerUpdate) { if (m_numTotalUploads < m_fullUploadCountExpected) EXPECT_GE(m_numDanglingUploads, kFlushPeriodFull) << "Premature flush detected in full uploads."; else if (m_numTotalUploads > m_fullUploadCountExpected && m_numTotalUploads < m_totalUploadCountExpected) EXPECT_GE(m_numDanglingUploads, kFlushPeriodPartial) << "Premature flush detected in partial uploads."; } m_numDanglingUploads = 0; m_numConsecutiveFlushes++; m_numTotalFlushes++; m_numPreviousFlushes++; } void onBeginUploads() { m_numPreviousFlushes = 0; m_numPreviousUploads = 0; m_numBeginUploads++; } void onUpload() { // Check for too many consecutive uploads if (m_numTotalUploads < m_fullUploadCountExpected) EXPECT_LT(m_numDanglingUploads, kFlushPeriodFull) << "Too many consecutive full uploads detected."; else EXPECT_LT(m_numDanglingUploads, kFlushPeriodPartial) << "Too many consecutive partial uploads detected."; m_numConsecutiveFlushes = 0; m_numDanglingUploads++; m_numTotalUploads++; m_numPreviousUploads++; } void onEndUploads() { EXPECT_EQ(0, m_numDanglingUploads) << "Last upload wasn't followed by a flush."; // Note: The m_numTotalUploads != m_fullUploadCountExpected comparison // allows for the quota not to be hit in the case where we are trasitioning // from full uploads to partial uploads. if (m_numTotalUploads != m_totalUploadCountExpected && m_numTotalUploads != m_fullUploadCountExpected) { EXPECT_EQ(m_maxUploadCountPerUpdate, m_numPreviousUploads) << "endUpload() was called when there are textures to upload, but the upload quota hasn't been filled."; } m_numEndUploads++; } protected: virtual void SetUp() { m_context = FakeWebCompositorOutputSurface::create(adoptPtr(new WebGraphicsContext3DForUploadTest(this))); DebugScopedSetImplThread implThread; m_resourceProvider = CCResourceProvider::create(m_context.get()); } void appendFullUploadsToUpdateQueue(int count) { m_fullUploadCountExpected += count; m_totalUploadCountExpected += count; const IntRect rect(0, 0, 300, 150); const TextureUploader::Parameters upload = { &m_texture, rect, IntSize() }; for (int i = 0; i < count; i++) m_queue->appendFullUpload(upload); } void appendPartialUploadsToUpdateQueue(int count) { m_partialCountExpected += count; m_totalUploadCountExpected += count; const IntRect rect(0, 0, 100, 100); const TextureUploader::Parameters upload = { &m_texture, rect, IntSize() }; for (int i = 0; i < count; i++) m_queue->appendPartialUpload(upload); } void setMaxUploadCountPerUpdate(int count) { m_maxUploadCountPerUpdate = count; } protected: // Classes required to interact and test the CCTextureUpdateController OwnPtr m_context; OwnPtr m_resourceProvider; OwnPtr m_queue; TextureForUploadTest m_texture; FakeTextureCopier m_copier; TextureUploaderForUploadTest m_uploader; OwnPtr m_thread; WebCompositorInitializer m_compositorInitializer; // Properties / expectations of this test int m_fullUploadCountExpected; int m_partialCountExpected; int m_totalUploadCountExpected; int m_maxUploadCountPerUpdate; // Dynamic properties of this test int m_numBeginUploads; int m_numEndUploads; int m_numConsecutiveFlushes; int m_numDanglingUploads; int m_numTotalUploads; int m_numTotalFlushes; int m_numPreviousUploads; int m_numPreviousFlushes; }; void WebGraphicsContext3DForUploadTest::flush(void) { m_test->onFlush(); } void WebGraphicsContext3DForUploadTest::shallowFlushCHROMIUM(void) { m_test->onFlush(); } void TextureUploaderForUploadTest::beginUploads() { m_test->onBeginUploads(); } void TextureUploaderForUploadTest::endUploads() { m_test->onEndUploads(); } void TextureUploaderForUploadTest::uploadTexture(cc::CCResourceProvider*, Parameters) { m_test->onUpload(); } // ZERO UPLOADS TESTS TEST_F(CCTextureUpdateControllerTest, ZeroUploads) { appendFullUploadsToUpdateQueue(0); appendPartialUploadsToUpdateQueue(0); CCTextureUpdateController::updateTextures(m_resourceProvider.get(), &m_copier, &m_uploader, m_queue.get(), m_totalUploadCountExpected); EXPECT_EQ(0, m_numBeginUploads); EXPECT_EQ(0, m_numEndUploads); EXPECT_EQ(0, m_numPreviousFlushes); EXPECT_EQ(0, m_numPreviousUploads); } // ONE UPLOAD TESTS TEST_F(CCTextureUpdateControllerTest, OneFullUpload) { appendFullUploadsToUpdateQueue(1); appendPartialUploadsToUpdateQueue(0); DebugScopedSetImplThread implThread; CCTextureUpdateController::updateTextures(m_resourceProvider.get(), &m_copier, &m_uploader, m_queue.get(), m_totalUploadCountExpected); EXPECT_EQ(1, m_numBeginUploads); EXPECT_EQ(1, m_numEndUploads); EXPECT_EQ(1, m_numPreviousFlushes); EXPECT_EQ(1, m_numPreviousUploads); } TEST_F(CCTextureUpdateControllerTest, OnePartialUpload) { appendFullUploadsToUpdateQueue(0); appendPartialUploadsToUpdateQueue(1); DebugScopedSetImplThread implThread; CCTextureUpdateController::updateTextures(m_resourceProvider.get(), &m_copier, &m_uploader, m_queue.get(), m_totalUploadCountExpected); EXPECT_EQ(1, m_numBeginUploads); EXPECT_EQ(1, m_numEndUploads); EXPECT_EQ(1, m_numPreviousFlushes); EXPECT_EQ(1, m_numPreviousUploads); } TEST_F(CCTextureUpdateControllerTest, OneFullOnePartialUpload) { appendFullUploadsToUpdateQueue(1); appendPartialUploadsToUpdateQueue(1); DebugScopedSetImplThread implThread; CCTextureUpdateController::updateTextures(m_resourceProvider.get(), &m_copier, &m_uploader, m_queue.get(), m_totalUploadCountExpected); // We expect the full uploads to be followed by a flush // before the partial uploads begin. EXPECT_EQ(1, m_numBeginUploads); EXPECT_EQ(1, m_numEndUploads); EXPECT_EQ(2, m_numPreviousFlushes); EXPECT_EQ(2, m_numPreviousUploads); } // NO REMAINDER TESTS // This class of tests upload a number of textures that is a multiple of the flush period. const int fullUploadFlushMultipler = 7; const int fullNoRemainderCount = fullUploadFlushMultipler * kFlushPeriodFull; const int partialUploadFlushMultipler = 11; const int partialNoRemainderCount = partialUploadFlushMultipler * kFlushPeriodPartial; TEST_F(CCTextureUpdateControllerTest, ManyFullUploadsNoRemainder) { appendFullUploadsToUpdateQueue(fullNoRemainderCount); appendPartialUploadsToUpdateQueue(0); DebugScopedSetImplThread implThread; CCTextureUpdateController::updateTextures(m_resourceProvider.get(), &m_copier, &m_uploader, m_queue.get(), m_totalUploadCountExpected); EXPECT_EQ(1, m_numBeginUploads); EXPECT_EQ(1, m_numEndUploads); EXPECT_EQ(fullUploadFlushMultipler, m_numPreviousFlushes); EXPECT_EQ(fullNoRemainderCount, m_numPreviousUploads); } TEST_F(CCTextureUpdateControllerTest, ManyPartialUploadsNoRemainder) { appendFullUploadsToUpdateQueue(0); appendPartialUploadsToUpdateQueue(partialNoRemainderCount); DebugScopedSetImplThread implThread; CCTextureUpdateController::updateTextures(m_resourceProvider.get(), &m_copier, &m_uploader, m_queue.get(), m_totalUploadCountExpected); EXPECT_EQ(1, m_numBeginUploads); EXPECT_EQ(1, m_numEndUploads); EXPECT_EQ(partialUploadFlushMultipler, m_numPreviousFlushes); EXPECT_EQ(partialNoRemainderCount, m_numPreviousUploads); } TEST_F(CCTextureUpdateControllerTest, ManyFullManyPartialUploadsNoRemainder) { appendFullUploadsToUpdateQueue(fullNoRemainderCount); appendPartialUploadsToUpdateQueue(partialNoRemainderCount); DebugScopedSetImplThread implThread; CCTextureUpdateController::updateTextures(m_resourceProvider.get(), &m_copier, &m_uploader, m_queue.get(), m_totalUploadCountExpected); EXPECT_EQ(1, m_numBeginUploads); EXPECT_EQ(1, m_numEndUploads); EXPECT_EQ(fullUploadFlushMultipler + partialUploadFlushMultipler, m_numPreviousFlushes); EXPECT_EQ(fullNoRemainderCount + partialNoRemainderCount, m_numPreviousUploads); } // MIN/MAX REMAINDER TESTS // This class of tests mix and match uploading 1 more and 1 less texture // than a multiple of the flush period. const int fullMinRemainderCount = fullNoRemainderCount + 1; const int fullMaxRemainderCount = fullNoRemainderCount - 1; const int partialMinRemainderCount = partialNoRemainderCount + 1; const int partialMaxRemainderCount = partialNoRemainderCount - 1; TEST_F(CCTextureUpdateControllerTest, ManyFullAndPartialMinRemainder) { appendFullUploadsToUpdateQueue(fullMinRemainderCount); appendPartialUploadsToUpdateQueue(partialMinRemainderCount); DebugScopedSetImplThread implThread; CCTextureUpdateController::updateTextures(m_resourceProvider.get(), &m_copier, &m_uploader, m_queue.get(), m_totalUploadCountExpected); EXPECT_EQ(1, m_numBeginUploads); EXPECT_EQ(1, m_numEndUploads); EXPECT_EQ(fullUploadFlushMultipler + partialUploadFlushMultipler + 2, m_numPreviousFlushes); EXPECT_EQ(fullMinRemainderCount + partialMinRemainderCount, m_numPreviousUploads); } TEST_F(CCTextureUpdateControllerTest, ManyFullAndPartialUploadsMaxRemainder) { appendFullUploadsToUpdateQueue(fullMaxRemainderCount); appendPartialUploadsToUpdateQueue(partialMaxRemainderCount); DebugScopedSetImplThread implThread; CCTextureUpdateController::updateTextures(m_resourceProvider.get(), &m_copier, &m_uploader, m_queue.get(), m_totalUploadCountExpected); EXPECT_EQ(1, m_numBeginUploads); EXPECT_EQ(1, m_numEndUploads); EXPECT_EQ(fullUploadFlushMultipler + partialUploadFlushMultipler, m_numPreviousFlushes); EXPECT_EQ(fullMaxRemainderCount + partialMaxRemainderCount, m_numPreviousUploads); } TEST_F(CCTextureUpdateControllerTest, ManyFullMinRemainderManyPartialMaxRemainder) { appendFullUploadsToUpdateQueue(fullMinRemainderCount); appendPartialUploadsToUpdateQueue(partialMaxRemainderCount); DebugScopedSetImplThread implThread; CCTextureUpdateController::updateTextures(m_resourceProvider.get(), &m_copier, &m_uploader, m_queue.get(), m_totalUploadCountExpected); EXPECT_EQ(1, m_numBeginUploads); EXPECT_EQ(1, m_numEndUploads); EXPECT_EQ((fullUploadFlushMultipler+1) + partialUploadFlushMultipler, m_numPreviousFlushes); EXPECT_EQ(fullMinRemainderCount + partialMaxRemainderCount, m_numPreviousUploads); } TEST_F(CCTextureUpdateControllerTest, ManyFullMaxRemainderManyPartialMinRemainder) { appendFullUploadsToUpdateQueue(fullMaxRemainderCount); appendPartialUploadsToUpdateQueue(partialMinRemainderCount); DebugScopedSetImplThread implThread; CCTextureUpdateController::updateTextures(m_resourceProvider.get(), &m_copier, &m_uploader, m_queue.get(), m_totalUploadCountExpected); EXPECT_EQ(1, m_numBeginUploads); EXPECT_EQ(1, m_numEndUploads); EXPECT_EQ(fullUploadFlushMultipler + (partialUploadFlushMultipler+1), m_numPreviousFlushes); EXPECT_EQ(fullMaxRemainderCount + partialMinRemainderCount, m_numPreviousUploads); } // MULTIPLE UPDATE TESTS // These tests attempt to upload too many textures at once, requiring // multiple calls to update(). int expectedFlushes(int uploads, int flushPeriod) { return (uploads + flushPeriod - 1) / flushPeriod; } TEST_F(CCTextureUpdateControllerTest, TripleUpdateFinalUpdateFullAndPartial) { const int kMaxUploadsPerUpdate = 40; const int kFullUploads = 100; const int kPartialUploads = 20; int expectedPreviousFlushes = 0; int expectedPreviousUploads = 0; setMaxUploadCountPerUpdate(kMaxUploadsPerUpdate); appendFullUploadsToUpdateQueue(kFullUploads); appendPartialUploadsToUpdateQueue(kPartialUploads); // First update (40 full) DebugScopedSetImplThread implThread; CCTextureUpdateController::updateTextures(m_resourceProvider.get(), &m_copier, &m_uploader, m_queue.get(), kMaxUploadsPerUpdate); EXPECT_EQ(1, m_numBeginUploads); EXPECT_EQ(1, m_numEndUploads); expectedPreviousFlushes = expectedFlushes(kMaxUploadsPerUpdate, kFlushPeriodFull); EXPECT_EQ(expectedPreviousFlushes, m_numPreviousFlushes); expectedPreviousUploads = kMaxUploadsPerUpdate; EXPECT_EQ(expectedPreviousUploads, m_numPreviousUploads); // Second update (40 full) CCTextureUpdateController::updateTextures(m_resourceProvider.get(), &m_copier, &m_uploader, m_queue.get(), kMaxUploadsPerUpdate); EXPECT_EQ(2, m_numBeginUploads); EXPECT_EQ(2, m_numEndUploads); expectedPreviousFlushes = expectedFlushes(kMaxUploadsPerUpdate, kFlushPeriodFull); EXPECT_EQ(expectedPreviousFlushes, m_numPreviousFlushes); expectedPreviousUploads = kMaxUploadsPerUpdate; EXPECT_EQ(expectedPreviousUploads, m_numPreviousUploads); // Third update (20 full, 20 partial) CCTextureUpdateController::updateTextures(m_resourceProvider.get(), &m_copier, &m_uploader, m_queue.get(), kMaxUploadsPerUpdate); EXPECT_EQ(3, m_numBeginUploads); EXPECT_EQ(3, m_numEndUploads); expectedPreviousFlushes = expectedFlushes(kFullUploads-kMaxUploadsPerUpdate*2, kFlushPeriodFull) + expectedFlushes(kPartialUploads, kFlushPeriodPartial); EXPECT_EQ(expectedPreviousFlushes, m_numPreviousFlushes); expectedPreviousUploads = (kFullUploads-kMaxUploadsPerUpdate*2)+kPartialUploads; EXPECT_EQ(expectedPreviousUploads, m_numPreviousUploads); // Final sanity checks EXPECT_EQ(kFullUploads + kPartialUploads, m_numTotalUploads); } TEST_F(CCTextureUpdateControllerTest, TripleUpdateFinalUpdateAllPartial) { const int kMaxUploadsPerUpdate = 40; const int kFullUploads = 70; const int kPartialUploads = 30; int expectedPreviousFlushes = 0; int expectedPreviousUploads = 0; setMaxUploadCountPerUpdate(kMaxUploadsPerUpdate); appendFullUploadsToUpdateQueue(kFullUploads); appendPartialUploadsToUpdateQueue(kPartialUploads); // First update (40 full) DebugScopedSetImplThread implThread; CCTextureUpdateController::updateTextures(m_resourceProvider.get(), &m_copier, &m_uploader, m_queue.get(), kMaxUploadsPerUpdate); EXPECT_EQ(1, m_numBeginUploads); EXPECT_EQ(1, m_numEndUploads); expectedPreviousFlushes = expectedFlushes(kMaxUploadsPerUpdate, kFlushPeriodFull); EXPECT_EQ(expectedPreviousFlushes, m_numPreviousFlushes); expectedPreviousUploads = kMaxUploadsPerUpdate; EXPECT_EQ(expectedPreviousUploads, m_numPreviousUploads); // Second update (30 full, optionally 10 partial) CCTextureUpdateController::updateTextures(m_resourceProvider.get(), &m_copier, &m_uploader, m_queue.get(), kMaxUploadsPerUpdate); EXPECT_EQ(2, m_numBeginUploads); EXPECT_EQ(2, m_numEndUploads); EXPECT_LE(m_numPreviousUploads, kMaxUploadsPerUpdate); // Be lenient on the exact number of flushes here, as the number of flushes // will depend on whether some partial uploads were performed. // onFlush(), onUpload(), and onEndUpload() will do basic flush checks for us anyway. // Third update (30 partial OR 20 partial if 10 partial uploaded in second update) CCTextureUpdateController::updateTextures(m_resourceProvider.get(), &m_copier, &m_uploader, m_queue.get(), kMaxUploadsPerUpdate); EXPECT_EQ(3, m_numBeginUploads); EXPECT_EQ(3, m_numEndUploads); EXPECT_LE(m_numPreviousUploads, kMaxUploadsPerUpdate); // Be lenient on the exact number of flushes here as well. // Final sanity checks EXPECT_EQ(kFullUploads + kPartialUploads, m_numTotalUploads); } class FakeCCTextureUpdateControllerClient : public cc::CCTextureUpdateControllerClient { public: FakeCCTextureUpdateControllerClient() { reset(); } void reset() { m_completedCalled = false; } bool completedCalled() const { return m_completedCalled; } virtual void updateTexturesCompleted() OVERRIDE { m_completedCalled = true; } protected: bool m_completedCalled; }; class FakeCCTextureUpdateController : public cc::CCTextureUpdateController { public: static PassOwnPtr create(cc::CCTextureUpdateControllerClient* client, cc::CCThread* thread, PassOwnPtr queue, CCResourceProvider* resourceProvider, TextureCopier* copier, TextureUploader* uploader) { return adoptPtr(new FakeCCTextureUpdateController(client, thread, queue, resourceProvider, copier, uploader)); } void setMonotonicTimeNow(double time) { m_monotonicTimeNow = time; } virtual double monotonicTimeNow() const OVERRIDE { return m_monotonicTimeNow; } void setUpdateMoreTexturesTime(double time) { m_updateMoreTexturesTime = time; } virtual double updateMoreTexturesTime() const OVERRIDE { return m_updateMoreTexturesTime; } void setUpdateMoreTexturesSize(size_t size) { m_updateMoreTexturesSize = size; } virtual size_t updateMoreTexturesSize() const OVERRIDE { return m_updateMoreTexturesSize; } protected: FakeCCTextureUpdateController(cc::CCTextureUpdateControllerClient* client, cc::CCThread* thread, PassOwnPtr queue, CCResourceProvider* resourceProvider, TextureCopier* copier, TextureUploader* uploader) : cc::CCTextureUpdateController(client, thread, queue, resourceProvider, copier, uploader) , m_monotonicTimeNow(0) , m_updateMoreTexturesTime(0) , m_updateMoreTexturesSize(0) { } double m_monotonicTimeNow; double m_updateMoreTexturesTime; size_t m_updateMoreTexturesSize; }; static void runPendingTask(FakeCCThread* thread, FakeCCTextureUpdateController* controller) { EXPECT_TRUE(thread->hasPendingTask()); controller->setMonotonicTimeNow(controller->monotonicTimeNow() + thread->pendingDelayMs() / 1000.0); thread->runPendingTask(); } TEST_F(CCTextureUpdateControllerTest, UpdateMoreTextures) { FakeCCTextureUpdateControllerClient client; FakeCCThread thread; setMaxUploadCountPerUpdate(1); appendFullUploadsToUpdateQueue(3); appendPartialUploadsToUpdateQueue(0); DebugScopedSetImplThread implThread; OwnPtr controller(FakeCCTextureUpdateController::create(&client, &thread, m_queue.release(), m_resourceProvider.get(), &m_copier, &m_uploader)); controller->setMonotonicTimeNow(0); controller->setUpdateMoreTexturesTime(0.1); controller->setUpdateMoreTexturesSize(1); // Not enough time for any updates. controller->updateMoreTextures(0.09); EXPECT_FALSE(thread.hasPendingTask()); EXPECT_EQ(0, m_numBeginUploads); EXPECT_EQ(0, m_numEndUploads); controller->setMonotonicTimeNow(0); controller->setUpdateMoreTexturesTime(0.1); controller->setUpdateMoreTexturesSize(1); // Only enough time for 1 update. controller->updateMoreTextures(0.12); runPendingTask(&thread, controller.get()); EXPECT_FALSE(thread.hasPendingTask()); EXPECT_EQ(1, m_numBeginUploads); EXPECT_EQ(1, m_numEndUploads); EXPECT_EQ(1, m_numTotalUploads); controller->setMonotonicTimeNow(0); controller->setUpdateMoreTexturesTime(0.1); controller->setUpdateMoreTexturesSize(1); // Enough time for 2 updates. controller->updateMoreTextures(0.22); runPendingTask(&thread, controller.get()); runPendingTask(&thread, controller.get()); EXPECT_FALSE(thread.hasPendingTask()); EXPECT_TRUE(client.completedCalled()); EXPECT_EQ(3, m_numBeginUploads); EXPECT_EQ(3, m_numEndUploads); EXPECT_EQ(3, m_numTotalUploads); } TEST_F(CCTextureUpdateControllerTest, NoMoreUpdates) { FakeCCTextureUpdateControllerClient client; FakeCCThread thread; setMaxUploadCountPerUpdate(1); appendFullUploadsToUpdateQueue(2); appendPartialUploadsToUpdateQueue(0); DebugScopedSetImplThread implThread; OwnPtr controller(FakeCCTextureUpdateController::create(&client, &thread, m_queue.release(), m_resourceProvider.get(), &m_copier, &m_uploader)); controller->setMonotonicTimeNow(0); controller->setUpdateMoreTexturesTime(0.1); controller->setUpdateMoreTexturesSize(1); // Enough time for 3 updates but only 2 necessary. controller->updateMoreTextures(0.31); runPendingTask(&thread, controller.get()); runPendingTask(&thread, controller.get()); EXPECT_FALSE(thread.hasPendingTask()); EXPECT_TRUE(client.completedCalled()); EXPECT_EQ(2, m_numBeginUploads); EXPECT_EQ(2, m_numEndUploads); EXPECT_EQ(2, m_numTotalUploads); controller->setMonotonicTimeNow(0); controller->setUpdateMoreTexturesTime(0.1); controller->setUpdateMoreTexturesSize(1); // Enough time for updates but no more updates left. controller->updateMoreTextures(0.31); // 0-delay task used to call updateTexturesCompleted(). runPendingTask(&thread, controller.get()); EXPECT_FALSE(thread.hasPendingTask()); EXPECT_TRUE(client.completedCalled()); EXPECT_EQ(2, m_numBeginUploads); EXPECT_EQ(2, m_numEndUploads); EXPECT_EQ(2, m_numTotalUploads); } TEST_F(CCTextureUpdateControllerTest, UpdatesCompleteInFiniteTime) { FakeCCTextureUpdateControllerClient client; FakeCCThread thread; setMaxUploadCountPerUpdate(1); appendFullUploadsToUpdateQueue(2); appendPartialUploadsToUpdateQueue(0); DebugScopedSetImplThread implThread; OwnPtr controller(FakeCCTextureUpdateController::create(&client, &thread, m_queue.release(), m_resourceProvider.get(), &m_copier, &m_uploader)); controller->setMonotonicTimeNow(0); controller->setUpdateMoreTexturesTime(0.5); controller->setUpdateMoreTexturesSize(1); for (int i = 0; i < 100; i++) { if (client.completedCalled()) break; // Not enough time for any updates. controller->updateMoreTextures(0.4); if (thread.hasPendingTask()) runPendingTask(&thread, controller.get()); } EXPECT_FALSE(thread.hasPendingTask()); EXPECT_TRUE(client.completedCalled()); EXPECT_EQ(2, m_numBeginUploads); EXPECT_EQ(2, m_numEndUploads); EXPECT_EQ(2, m_numTotalUploads); } } // namespace