blob: 98831259d87fc6f96d9800899f3be906faab31cd [file] [log] [blame]
[email protected]94f206c12012-08-25 00:09:141// Copyright 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "config.h"
6
[email protected]1c0088f2012-10-17 00:29:307#include "CCTextureUpdateController.h"
[email protected]94f206c12012-08-25 00:09:148
[email protected]1c0088f2012-10-17 00:29:309#include "CCResourceProvider.h"
[email protected]41b8f682012-09-19 01:51:1710#include "TraceEvent.h"
[email protected]1e5b6bf52012-10-18 01:44:5211#include "cc/prioritized_texture.h"
12#include "cc/proxy.h"
[email protected]a8461d82012-10-16 21:11:1413#include "cc/texture_copier.h"
14#include "cc/texture_uploader.h"
[email protected]41b8f682012-09-19 01:51:1715#include <limits>
[email protected]1e5b6bf52012-10-18 01:44:5216#include <public/WebGraphicsContext3D.h>
17#include <public/WebSharedGraphicsContext3D.h>
18#include "third_party/skia/include/gpu/SkGpuDevice.h"
[email protected]94f206c12012-08-25 00:09:1419#include <wtf/CurrentTime.h>
20
[email protected]1e5b6bf52012-10-18 01:44:5221using WebKit::WebGraphicsContext3D;
22using WebKit::WebSharedGraphicsContext3D;
23
[email protected]94f206c12012-08-25 00:09:1424namespace {
25
[email protected]41b8f682012-09-19 01:51:1726// Number of partial updates we allow.
[email protected]2d86b922012-10-13 16:57:4727const size_t partialTextureUpdatesMax = 12;
[email protected]94f206c12012-08-25 00:09:1428
29// Measured in seconds.
[email protected]2d86b922012-10-13 16:57:4730const double textureUpdateTickRate = 0.004;
[email protected]94f206c12012-08-25 00:09:1431
[email protected]12695152012-09-17 22:28:1432// Measured in seconds.
[email protected]2d86b922012-10-13 16:57:4733const double uploaderBusyTickRate = 0.001;
[email protected]12695152012-09-17 22:28:1434
[email protected]94f206c12012-08-25 00:09:1435// Flush interval when performing texture uploads.
[email protected]2d86b922012-10-13 16:57:4736const int textureUploadFlushPeriod = 4;
[email protected]94f206c12012-08-25 00:09:1437
[email protected]b914e102012-10-02 08:11:5238// Number of blocking update intervals to allow.
[email protected]2d86b922012-10-13 16:57:4739const size_t maxBlockingUpdateIntervals = 4;
[email protected]549526e92012-09-29 15:43:0840
[email protected]1e5b6bf52012-10-18 01:44:5241scoped_ptr<SkCanvas> createAcceleratedCanvas(
42 GrContext* grContext, cc::IntSize canvasSize, unsigned textureId)
43{
44 GrPlatformTextureDesc textureDesc;
45 textureDesc.fFlags = kRenderTarget_GrPlatformTextureFlag;
46 textureDesc.fWidth = canvasSize.width();
47 textureDesc.fHeight = canvasSize.height();
48 textureDesc.fConfig = kSkia8888_GrPixelConfig;
49 textureDesc.fTextureHandle = textureId;
50 SkAutoTUnref<GrTexture> target(
51 grContext->createPlatformTexture(textureDesc));
52 SkAutoTUnref<SkDevice> device(new SkGpuDevice(grContext, target.get()));
53 return make_scoped_ptr(new SkCanvas(device.get()));
54}
55
[email protected]2d86b922012-10-13 16:57:4756} // namespace
[email protected]94f206c12012-08-25 00:09:1457
[email protected]9c88e562012-09-14 22:21:3058namespace cc {
[email protected]94f206c12012-08-25 00:09:1459
60size_t CCTextureUpdateController::maxPartialTextureUpdates()
61{
[email protected]a7c078b2012-09-20 17:52:1262 return partialTextureUpdatesMax;
[email protected]41b8f682012-09-19 01:51:1763}
64
65size_t CCTextureUpdateController::maxFullUpdatesPerTick(TextureUploader* uploader)
66{
67 double texturesPerSecond = uploader->estimatedTexturesPerSecond();
68 size_t texturesPerTick = floor(textureUpdateTickRate * texturesPerSecond);
69 return texturesPerTick ? texturesPerTick : 1;
[email protected]94f206c12012-08-25 00:09:1470}
71
[email protected]b1b800c2012-10-16 05:03:5972CCTextureUpdateController::CCTextureUpdateController(CCTextureUpdateControllerClient* client, CCThread* thread, scoped_ptr<CCTextureUpdateQueue> queue, CCResourceProvider* resourceProvider, TextureUploader* uploader)
[email protected]3c496dc2012-09-13 23:14:2073 : m_client(client)
[email protected]2d86b922012-10-13 16:57:4774 , m_timer(new CCTimer(thread, this))
[email protected]b1b800c2012-10-16 05:03:5975 , m_queue(queue.Pass())
[email protected]94f206c12012-08-25 00:09:1476 , m_resourceProvider(resourceProvider)
[email protected]94f206c12012-08-25 00:09:1477 , m_uploader(uploader)
[email protected]41b8f682012-09-19 01:51:1778 , m_textureUpdatesPerTick(maxFullUpdatesPerTick(uploader))
[email protected]94f206c12012-08-25 00:09:1479 , m_firstUpdateAttempt(true)
80{
81}
82
83CCTextureUpdateController::~CCTextureUpdateController()
84{
85}
86
[email protected]12695152012-09-17 22:28:1487void CCTextureUpdateController::performMoreUpdates(
[email protected]d918afe2012-09-27 19:27:2188 base::TimeTicks timeLimit)
[email protected]94f206c12012-08-25 00:09:1489{
[email protected]d918afe2012-09-27 19:27:2190 m_timeLimit = timeLimit;
[email protected]94f206c12012-08-25 00:09:1491
[email protected]3c496dc2012-09-13 23:14:2092 // Update already in progress.
93 if (m_timer->isActive())
[email protected]94f206c12012-08-25 00:09:1494 return;
95
96 // Call updateMoreTexturesNow() directly unless it's the first update
97 // attempt. This ensures that we empty the update queue in a finite
98 // amount of time.
99 if (m_firstUpdateAttempt) {
[email protected]3c496dc2012-09-13 23:14:20100 // Post a 0-delay task when no updates were left. When it runs,
[email protected]12695152012-09-17 22:28:14101 // readyToFinalizeTextureUpdates() will be called.
[email protected]3c496dc2012-09-13 23:14:20102 if (!updateMoreTexturesIfEnoughTimeRemaining())
103 m_timer->startOneShot(0);
104
[email protected]94f206c12012-08-25 00:09:14105 m_firstUpdateAttempt = false;
106 } else
107 updateMoreTexturesNow();
108}
109
[email protected]77a60b9b2012-09-19 23:59:01110void CCTextureUpdateController::discardUploadsToEvictedResources()
111{
112 m_queue->clearUploadsToEvictedResources();
113}
114
[email protected]1e5b6bf52012-10-18 01:44:52115void CCTextureUpdateController::updateTexture(ResourceUpdate update)
116{
117 if (update.picture) {
118 CCPrioritizedTexture* texture = update.texture;
119 IntRect pictureRect = update.content_rect;
120 IntRect sourceRect = update.source_rect;
121 IntSize destOffset = update.dest_offset;
122
123 texture->acquireBackingTexture(m_resourceProvider);
124 ASSERT(texture->haveBackingTexture());
125
126 ASSERT(m_resourceProvider->resourceType(texture->resourceId()) ==
127 CCResourceProvider::GLTexture);
128
129 WebGraphicsContext3D* paintContext = CCProxy::hasImplThread() ?
130 WebSharedGraphicsContext3D::compositorThreadContext() :
131 WebSharedGraphicsContext3D::mainThreadContext();
132 GrContext* paintGrContext = CCProxy::hasImplThread() ?
133 WebSharedGraphicsContext3D::compositorThreadGrContext() :
134 WebSharedGraphicsContext3D::mainThreadGrContext();
135
136 // Flush the context in which the backing texture is created so that it
137 // is available in other shared contexts. It is important to do here
138 // because the backing texture is created in one context while it is
139 // being written to in another.
140 m_resourceProvider->flush();
141 CCResourceProvider::ScopedWriteLockGL lock(
142 m_resourceProvider, texture->resourceId());
143
144 // Make sure ganesh uses the correct GL context.
145 paintContext->makeContextCurrent();
146
147 // Create an accelerated canvas to draw on.
148 scoped_ptr<SkCanvas> canvas = createAcceleratedCanvas(
149 paintGrContext, texture->size(), lock.textureId());
150
151 // The compositor expects the textures to be upside-down so it can flip
152 // the final composited image. Ganesh renders the image upright so we
153 // need to do a y-flip.
154 canvas->translate(0.0, texture->size().height());
155 canvas->scale(1.0, -1.0);
156 // Clip to the destination on the texture that must be updated.
157 canvas->clipRect(SkRect::MakeXYWH(destOffset.width(),
158 destOffset.height(),
159 sourceRect.width(),
160 sourceRect.height()));
161 // Translate the origin of pictureRect to destOffset.
162 // Note that destOffset is defined relative to sourceRect.
163 canvas->translate(
164 pictureRect.x() - sourceRect.x() + destOffset.width(),
165 pictureRect.y() - sourceRect.y() + destOffset.height());
166 canvas->drawPicture(*update.picture);
167
168 // Flush ganesh context so that all the rendered stuff appears on the
169 // texture.
170 paintGrContext->flush();
171
172 // Flush the GL context so rendering results from this context are
173 // visible in the compositor's context.
174 paintContext->flush();
175 }
176
177 if (update.bitmap) {
178 m_uploader->uploadTexture(m_resourceProvider,
179 update.texture,
180 update.bitmap,
181 update.content_rect,
182 update.source_rect,
183 update.dest_offset);
184 }
185}
186
[email protected]12695152012-09-17 22:28:14187void CCTextureUpdateController::finalize()
188{
[email protected]f961b792012-09-20 07:27:33189 size_t uploadCount = 0;
190 while (m_queue->fullUploadSize()) {
191 if (!(uploadCount % textureUploadFlushPeriod) && uploadCount)
192 m_resourceProvider->shallowFlushIfSupported();
193
[email protected]1e5b6bf52012-10-18 01:44:52194 updateTexture(m_queue->takeFirstFullUpload());
[email protected]f961b792012-09-20 07:27:33195 uploadCount++;
196 }
197
198 while (m_queue->partialUploadSize()) {
199 if (!(uploadCount % textureUploadFlushPeriod) && uploadCount)
200 m_resourceProvider->shallowFlushIfSupported();
201
[email protected]1e5b6bf52012-10-18 01:44:52202 updateTexture(m_queue->takeFirstPartialUpload());
[email protected]f961b792012-09-20 07:27:33203 uploadCount++;
204 }
205
206 if (uploadCount)
207 m_resourceProvider->shallowFlushIfSupported();
208
209 if (m_queue->copySize()) {
210 TextureCopier* copier = m_resourceProvider->textureCopier();
211 while (m_queue->copySize())
212 copier->copyTexture(m_queue->takeFirstCopy());
213
214 // If we've performed any texture copies, we need to insert a flush
215 // here into the compositor context before letting the main thread
216 // proceed as it may make draw calls to the source texture of one of
217 // our copy operations.
218 copier->flush();
219 }
[email protected]12695152012-09-17 22:28:14220}
221
[email protected]94f206c12012-08-25 00:09:14222void CCTextureUpdateController::onTimerFired()
223{
[email protected]3c496dc2012-09-13 23:14:20224 if (!updateMoreTexturesIfEnoughTimeRemaining())
[email protected]12695152012-09-17 22:28:14225 m_client->readyToFinalizeTextureUpdates();
[email protected]94f206c12012-08-25 00:09:14226}
227
[email protected]d918afe2012-09-27 19:27:21228base::TimeTicks CCTextureUpdateController::now() const
[email protected]94f206c12012-08-25 00:09:14229{
[email protected]d918afe2012-09-27 19:27:21230 return base::TimeTicks::Now();
[email protected]94f206c12012-08-25 00:09:14231}
232
[email protected]d918afe2012-09-27 19:27:21233base::TimeDelta CCTextureUpdateController::updateMoreTexturesTime() const
[email protected]94f206c12012-08-25 00:09:14234{
[email protected]d918afe2012-09-27 19:27:21235 return base::TimeDelta::FromMilliseconds(textureUpdateTickRate * 1000);
[email protected]94f206c12012-08-25 00:09:14236}
237
238size_t CCTextureUpdateController::updateMoreTexturesSize() const
239{
[email protected]41b8f682012-09-19 01:51:17240 return m_textureUpdatesPerTick;
[email protected]94f206c12012-08-25 00:09:14241}
242
[email protected]b914e102012-10-02 08:11:52243size_t CCTextureUpdateController::maxBlockingUpdates() const
[email protected]549526e92012-09-29 15:43:08244{
[email protected]b914e102012-10-02 08:11:52245 return updateMoreTexturesSize() * maxBlockingUpdateIntervals;
[email protected]549526e92012-09-29 15:43:08246}
247
[email protected]3c496dc2012-09-13 23:14:20248bool CCTextureUpdateController::updateMoreTexturesIfEnoughTimeRemaining()
[email protected]94f206c12012-08-25 00:09:14249{
[email protected]b914e102012-10-02 08:11:52250 // Blocking uploads will increase when we're too aggressive in our upload
[email protected]549526e92012-09-29 15:43:08251 // time estimate. We use a different timeout here to prevent unnecessary
[email protected]b914e102012-10-02 08:11:52252 // amounts of idle time when blocking uploads have reached the max.
253 if (m_uploader->numBlockingUploads() >= maxBlockingUpdates()) {
[email protected]12695152012-09-17 22:28:14254 m_timer->startOneShot(uploaderBusyTickRate);
255 return true;
256 }
257
258 if (!m_queue->fullUploadSize())
[email protected]3c496dc2012-09-13 23:14:20259 return false;
260
[email protected]e8e410d2012-09-28 01:47:01261 bool hasTimeRemaining = m_timeLimit.is_null() ||
262 this->now() < m_timeLimit - updateMoreTexturesTime();
[email protected]94f206c12012-08-25 00:09:14263 if (hasTimeRemaining)
264 updateMoreTexturesNow();
[email protected]3c496dc2012-09-13 23:14:20265
266 return true;
[email protected]94f206c12012-08-25 00:09:14267}
268
269void CCTextureUpdateController::updateMoreTexturesNow()
270{
[email protected]12695152012-09-17 22:28:14271 size_t uploads = std::min(
272 m_queue->fullUploadSize(), updateMoreTexturesSize());
273 m_timer->startOneShot(
[email protected]d918afe2012-09-27 19:27:21274 updateMoreTexturesTime().InSecondsF() / updateMoreTexturesSize() *
275 uploads);
[email protected]12695152012-09-17 22:28:14276
277 if (!uploads)
278 return;
279
[email protected]12695152012-09-17 22:28:14280 size_t uploadCount = 0;
[email protected]41b8f682012-09-19 01:51:17281 while (m_queue->fullUploadSize() && uploadCount < uploads) {
282 if (!(uploadCount % textureUploadFlushPeriod) && uploadCount)
[email protected]12695152012-09-17 22:28:14283 m_resourceProvider->shallowFlushIfSupported();
[email protected]1e5b6bf52012-10-18 01:44:52284 updateTexture(m_queue->takeFirstFullUpload());
[email protected]41b8f682012-09-19 01:51:17285 uploadCount++;
[email protected]12695152012-09-17 22:28:14286 }
[email protected]41b8f682012-09-19 01:51:17287 m_resourceProvider->shallowFlushIfSupported();
[email protected]94f206c12012-08-25 00:09:14288}
289
[email protected]2d86b922012-10-13 16:57:47290} // namespace cc