diff options
author | brianderson@chromium.org <brianderson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-19 01:51:17 +0000 |
---|---|---|
committer | brianderson@chromium.org <brianderson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-19 01:51:17 +0000 |
commit | 41b8f68e385878d06d578febf0e6e700fb2a99ba (patch) | |
tree | 137928af89d5a22fadc7b68966979b9a9204b77a /cc | |
parent | 835af8b9cd3b376b6784a581cefa3dc4df4bf9d0 (diff) | |
download | chromium_src-41b8f68e385878d06d578febf0e6e700fb2a99ba.zip chromium_src-41b8f68e385878d06d578febf0e6e700fb2a99ba.tar.gz chromium_src-41b8f68e385878d06d578febf0e6e700fb2a99ba.tar.bz2 |
Adaptively throttle texture uploads
We need adaptive texture uploading because we run on a wide variety
of systems and a one size fits all policy will not work.
This patch maintains a tick rate of 4ms and default upload count of
12 textures per tick, but allows for more textures per tick if we've
measured that we can be faster.
The number of partial updates allowed is also communicated from the
impl thread to the main thread at the beggining of each frame.
BUG=145825
Review URL: https://chromiumcodereview.appspot.com/10916292
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@157473 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc')
-rw-r--r-- | cc/CCTextureUpdateController.cpp | 36 | ||||
-rw-r--r-- | cc/CCTextureUpdateController.h | 3 | ||||
-rw-r--r-- | cc/CCTextureUpdateControllerTest.cpp | 10 | ||||
-rw-r--r-- | cc/TextureUploader.h | 3 | ||||
-rw-r--r-- | cc/ThrottledTextureUploader.cpp | 67 | ||||
-rw-r--r-- | cc/ThrottledTextureUploader.h | 11 | ||||
-rw-r--r-- | cc/UnthrottledTextureUploader.h | 1 | ||||
-rw-r--r-- | cc/test/CCTiledLayerTestCommon.h | 1 |
8 files changed, 108 insertions, 24 deletions
diff --git a/cc/CCTextureUpdateController.cpp b/cc/CCTextureUpdateController.cpp index 49a98a4..8b27385 100644 --- a/cc/CCTextureUpdateController.cpp +++ b/cc/CCTextureUpdateController.cpp @@ -9,12 +9,14 @@ #include "GraphicsContext3D.h" #include "TextureCopier.h" #include "TextureUploader.h" +#include "TraceEvent.h" +#include <limits> #include <wtf/CurrentTime.h> namespace { -// Number of textures to update with each call to updateMoreTexturesIfEnoughTimeRemaining(). -static const size_t textureUpdatesPerTick = 12; +// Number of partial updates we allow. +static const size_t maxPartialTextureUpdatesMax = 12; // Measured in seconds. static const double textureUpdateTickRate = 0.004; @@ -31,7 +33,14 @@ namespace cc { size_t CCTextureUpdateController::maxPartialTextureUpdates() { - return textureUpdatesPerTick; + return maxPartialTextureUpdatesMax; +} + +size_t CCTextureUpdateController::maxFullUpdatesPerTick(TextureUploader* uploader) +{ + double texturesPerSecond = uploader->estimatedTexturesPerSecond(); + size_t texturesPerTick = floor(textureUpdateTickRate * texturesPerSecond); + return texturesPerTick ? texturesPerTick : 1; } void CCTextureUpdateController::updateTextures(CCResourceProvider* resourceProvider, TextureUploader* uploader, CCTextureUpdateQueue* queue) @@ -78,6 +87,7 @@ CCTextureUpdateController::CCTextureUpdateController(CCTextureUpdateControllerCl , m_resourceProvider(resourceProvider) , m_uploader(uploader) , m_monotonicTimeLimit(0) + , m_textureUpdatesPerTick(maxFullUpdatesPerTick(uploader)) , m_firstUpdateAttempt(true) { } @@ -133,7 +143,7 @@ double CCTextureUpdateController::updateMoreTexturesTime() const size_t CCTextureUpdateController::updateMoreTexturesSize() const { - return textureUpdatesPerTick; + return m_textureUpdatesPerTick; } bool CCTextureUpdateController::updateMoreTexturesIfEnoughTimeRemaining() @@ -166,22 +176,16 @@ void CCTextureUpdateController::updateMoreTexturesNow() if (!uploads) return; - m_uploader->beginUploads(); - size_t uploadCount = 0; - while (uploads--) { - m_uploader->uploadTexture( - m_resourceProvider, m_queue->takeFirstFullUpload()); - uploadCount++; - if (!(uploadCount % textureUploadFlushPeriod)) + m_uploader->beginUploads(); + while (m_queue->fullUploadSize() && uploadCount < uploads) { + if (!(uploadCount % textureUploadFlushPeriod) && uploadCount) m_resourceProvider->shallowFlushIfSupported(); + m_uploader->uploadTexture(m_resourceProvider, m_queue->takeFirstFullUpload()); + uploadCount++; } - - // Make sure there are no dangling partial uploads without a flush. - if (uploadCount % textureUploadFlushPeriod) - m_resourceProvider->shallowFlushIfSupported(); - m_uploader->endUploads(); + m_resourceProvider->shallowFlushIfSupported(); } } diff --git a/cc/CCTextureUpdateController.h b/cc/CCTextureUpdateController.h index de928e4..6cf726e 100644 --- a/cc/CCTextureUpdateController.h +++ b/cc/CCTextureUpdateController.h @@ -48,6 +48,8 @@ public: protected: CCTextureUpdateController(CCTextureUpdateControllerClient*, CCThread*, PassOwnPtr<CCTextureUpdateQueue>, CCResourceProvider*, TextureUploader*); + static size_t maxFullUpdatesPerTick(TextureUploader*); + // This returns true when there were textures left to update. bool updateMoreTexturesIfEnoughTimeRemaining(); void updateMoreTexturesNow(); @@ -59,6 +61,7 @@ protected: CCResourceProvider* m_resourceProvider; TextureUploader* m_uploader; double m_monotonicTimeLimit; + size_t m_textureUpdatesPerTick; bool m_firstUpdateAttempt; }; diff --git a/cc/CCTextureUpdateControllerTest.cpp b/cc/CCTextureUpdateControllerTest.cpp index 418aeb3..2eeaa9d 100644 --- a/cc/CCTextureUpdateControllerTest.cpp +++ b/cc/CCTextureUpdateControllerTest.cpp @@ -115,6 +115,8 @@ public: void onBeginUploads() { + EXPECT_EQ(0, m_numDanglingUploads) << "Last upload wasn't followed by a flush."; + m_numPreviousFlushes = 0; m_numPreviousUploads = 0; m_numBeginUploads++; @@ -136,8 +138,6 @@ public: 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. @@ -261,6 +261,7 @@ TEST_F(CCTextureUpdateControllerTest, OneFullUpload) EXPECT_EQ(1, m_numPreviousFlushes); EXPECT_EQ(1, m_numPreviousUploads); + EXPECT_EQ(0, m_numDanglingUploads) << "Last upload wasn't followed by a flush."; } TEST_F(CCTextureUpdateControllerTest, OnePartialUpload) @@ -272,6 +273,7 @@ TEST_F(CCTextureUpdateControllerTest, OnePartialUpload) EXPECT_EQ(1, m_numPreviousFlushes); EXPECT_EQ(1, m_numPreviousUploads); + EXPECT_EQ(0, m_numDanglingUploads) << "Last upload wasn't followed by a flush."; } TEST_F(CCTextureUpdateControllerTest, OneFullOnePartialUpload) @@ -283,6 +285,7 @@ TEST_F(CCTextureUpdateControllerTest, OneFullOnePartialUpload) EXPECT_EQ(1, m_numPreviousFlushes); EXPECT_EQ(2, m_numPreviousUploads); + EXPECT_EQ(0, m_numDanglingUploads) << "Last upload wasn't followed by a flush."; } @@ -302,6 +305,7 @@ TEST_F(CCTextureUpdateControllerTest, ManyFullUploads) EXPECT_EQ(fullUploadFlushMultipler, m_numPreviousFlushes); EXPECT_EQ(fullCount, m_numPreviousUploads); + EXPECT_EQ(0, m_numDanglingUploads) << "Last upload wasn't followed by a flush."; } TEST_F(CCTextureUpdateControllerTest, ManyPartialUploads) @@ -313,6 +317,7 @@ TEST_F(CCTextureUpdateControllerTest, ManyPartialUploads) EXPECT_EQ(partialUploadFlushMultipler, m_numPreviousFlushes); EXPECT_EQ(partialCount, m_numPreviousUploads); + EXPECT_EQ(0, m_numDanglingUploads) << "Last upload wasn't followed by a flush."; } TEST_F(CCTextureUpdateControllerTest, ManyFullManyPartialUploads) @@ -324,6 +329,7 @@ TEST_F(CCTextureUpdateControllerTest, ManyFullManyPartialUploads) EXPECT_EQ(fullUploadFlushMultipler + partialUploadFlushMultipler, m_numPreviousFlushes); EXPECT_EQ(fullCount + partialCount, m_numPreviousUploads); + EXPECT_EQ(0, m_numDanglingUploads) << "Last upload wasn't followed by a flush."; } class FakeCCTextureUpdateControllerClient : public cc::CCTextureUpdateControllerClient { diff --git a/cc/TextureUploader.h b/cc/TextureUploader.h index abb6089..d7cd55d 100644 --- a/cc/TextureUploader.h +++ b/cc/TextureUploader.h @@ -20,6 +20,9 @@ public: virtual ~TextureUploader() { } virtual bool isBusy() = 0; + + // Returns our throughput on the GPU process + virtual double estimatedTexturesPerSecond() = 0; virtual void beginUploads() = 0; virtual void endUploads() = 0; virtual void uploadTexture(CCResourceProvider*, Parameters) = 0; diff --git a/cc/ThrottledTextureUploader.cpp b/cc/ThrottledTextureUploader.cpp index 274205d..f9de78c 100644 --- a/cc/ThrottledTextureUploader.cpp +++ b/cc/ThrottledTextureUploader.cpp @@ -3,17 +3,26 @@ // found in the LICENSE file. #include "config.h" - #include "ThrottledTextureUploader.h" #include "Extensions3DChromium.h" +#include <algorithm> #include <public/WebGraphicsContext3D.h> +#include <vector> namespace { // Number of pending texture update queries to allow. static const size_t maxPendingQueries = 2; +// How many previous uploads to use when predicting future throughput. +static const size_t uploadHistorySize = 10; + +// Global estimated number of textures per second to maintain estimates across +// subsequent instances of ThrottledTextureUploader. +// More than one thread will not access this variable, so we do not need to synchronize access. +static double estimatedTexturesPerSecondGlobal = 48.0 * 60.0; + } // anonymous namespace namespace cc { @@ -21,6 +30,9 @@ namespace cc { ThrottledTextureUploader::Query::Query(WebKit::WebGraphicsContext3D* context) : m_context(context) , m_queryId(0) + , m_value(0) + , m_hasValue(false) + , m_texturesUploaded(0) { m_queryId = m_context->createQueryEXT(); } @@ -35,9 +47,10 @@ void ThrottledTextureUploader::Query::begin() m_context->beginQueryEXT(Extensions3DChromium::COMMANDS_ISSUED_CHROMIUM, m_queryId); } -void ThrottledTextureUploader::Query::end() +void ThrottledTextureUploader::Query::end(double texturesUploaded) { m_context->endQueryEXT(Extensions3DChromium::COMMANDS_ISSUED_CHROMIUM); + m_texturesUploaded = texturesUploaded; } bool ThrottledTextureUploader::Query::isPending() @@ -49,19 +62,37 @@ bool ThrottledTextureUploader::Query::isPending() void ThrottledTextureUploader::Query::wait() { - unsigned result; - m_context->getQueryObjectuivEXT(m_queryId, Extensions3DChromium::QUERY_RESULT_EXT, &result); + value(); + return; +} + +unsigned ThrottledTextureUploader::Query::value() +{ + if (!m_hasValue) { + m_context->getQueryObjectuivEXT(m_queryId, Extensions3DChromium::QUERY_RESULT_EXT, &m_value); + m_hasValue = true; + } + return m_value; +} + +double ThrottledTextureUploader::Query::texturesUploaded() +{ + return m_texturesUploaded; } ThrottledTextureUploader::ThrottledTextureUploader(WebKit::WebGraphicsContext3D* context) : m_context(context) , m_maxPendingQueries(maxPendingQueries) + , m_texturesPerSecondHistory(uploadHistorySize, estimatedTexturesPerSecondGlobal) + , m_texturesUploaded(0) { } ThrottledTextureUploader::ThrottledTextureUploader(WebKit::WebGraphicsContext3D* context, size_t pendingUploadLimit) : m_context(context) , m_maxPendingQueries(pendingUploadLimit) + , m_texturesPerSecondHistory(uploadHistorySize, estimatedTexturesPerSecondGlobal) + , m_texturesUploaded(0) { ASSERT(m_context); } @@ -84,8 +115,26 @@ bool ThrottledTextureUploader::isBusy() return false; } +double ThrottledTextureUploader::estimatedTexturesPerSecond() +{ + processQueries(); + + // The history should never be empty because we initialize all elements with an estimate. + ASSERT(m_texturesPerSecondHistory.size() == uploadHistorySize); + + // Sort the history and use the median as our estimate. + std::vector<double> sortedHistory(m_texturesPerSecondHistory.begin(), + m_texturesPerSecondHistory.end()); + std::sort(sortedHistory.begin(), sortedHistory.end()); + + estimatedTexturesPerSecondGlobal = sortedHistory[sortedHistory.size() / 2]; + return estimatedTexturesPerSecondGlobal; +} + void ThrottledTextureUploader::beginUploads() { + m_texturesUploaded = 0; + // Wait for query to become available. while (isBusy()) m_pendingQueries.first()->wait(); @@ -96,12 +145,13 @@ void ThrottledTextureUploader::beginUploads() void ThrottledTextureUploader::endUploads() { - m_availableQueries.first()->end(); + m_availableQueries.first()->end(m_texturesUploaded); m_pendingQueries.append(m_availableQueries.takeFirst()); } void ThrottledTextureUploader::uploadTexture(CCResourceProvider* resourceProvider, Parameters upload) { + m_texturesUploaded++; upload.texture->updateRect(resourceProvider, upload.sourceRect, upload.destOffset); } @@ -111,6 +161,13 @@ void ThrottledTextureUploader::processQueries() if (m_pendingQueries.first()->isPending()) break; + unsigned usElapsed = m_pendingQueries.first()->value(); + double texturesPerSecond = m_pendingQueries.first()->texturesUploaded() / (usElapsed * 1e-6); + + // Remove the oldest values from our history and insert the new one + m_texturesPerSecondHistory.pop_back(); + m_texturesPerSecondHistory.push_front(texturesPerSecond); + m_availableQueries.append(m_pendingQueries.takeFirst()); } } diff --git a/cc/ThrottledTextureUploader.h b/cc/ThrottledTextureUploader.h index b462e07..0b5acc4 100644 --- a/cc/ThrottledTextureUploader.h +++ b/cc/ThrottledTextureUploader.h @@ -7,6 +7,7 @@ #include "TextureUploader.h" +#include <deque> #include <wtf/Deque.h> namespace WebKit { @@ -29,6 +30,7 @@ public: virtual ~ThrottledTextureUploader(); virtual bool isBusy() OVERRIDE; + virtual double estimatedTexturesPerSecond() OVERRIDE; virtual void beginUploads() OVERRIDE; virtual void endUploads() OVERRIDE; virtual void uploadTexture(CCResourceProvider*, Parameters) OVERRIDE; @@ -41,15 +43,20 @@ private: virtual ~Query(); void begin(); - void end(); + void end(double texturesUploaded); bool isPending(); void wait(); + unsigned value(); + double texturesUploaded(); private: explicit Query(WebKit::WebGraphicsContext3D*); WebKit::WebGraphicsContext3D* m_context; unsigned m_queryId; + unsigned m_value; + bool m_hasValue; + double m_texturesUploaded; }; ThrottledTextureUploader(WebKit::WebGraphicsContext3D*); @@ -61,6 +68,8 @@ private: size_t m_maxPendingQueries; Deque<OwnPtr<Query> > m_pendingQueries; Deque<OwnPtr<Query> > m_availableQueries; + std::deque<double> m_texturesPerSecondHistory; + double m_texturesUploaded; }; } diff --git a/cc/UnthrottledTextureUploader.h b/cc/UnthrottledTextureUploader.h index 3e24d90..4f97baf 100644 --- a/cc/UnthrottledTextureUploader.h +++ b/cc/UnthrottledTextureUploader.h @@ -20,6 +20,7 @@ public: virtual ~UnthrottledTextureUploader() { } virtual bool isBusy() OVERRIDE { return false; } + virtual double estimatedTexturesPerSecond() { return std::numeric_limits<double>::max(); } virtual void beginUploads() OVERRIDE { } virtual void endUploads() OVERRIDE { } virtual void uploadTexture(CCResourceProvider* resourceProvider, Parameters upload) OVERRIDE { upload.texture->updateRect(resourceProvider, upload.sourceRect, upload.destOffset); } diff --git a/cc/test/CCTiledLayerTestCommon.h b/cc/test/CCTiledLayerTestCommon.h index 7cfa93b..39bbe81 100644 --- a/cc/test/CCTiledLayerTestCommon.h +++ b/cc/test/CCTiledLayerTestCommon.h @@ -131,6 +131,7 @@ protected: class FakeTextureUploader : public cc::TextureUploader { public: virtual bool isBusy() OVERRIDE; + virtual double estimatedTexturesPerSecond() OVERRIDE { return std::numeric_limits<double>::max(); } virtual void beginUploads() OVERRIDE { } virtual void endUploads() OVERRIDE { } virtual void uploadTexture(cc::CCResourceProvider*, Parameters upload) OVERRIDE; |