blob: a289935f62ef2f096c8a9094b52a24e2fe7a51ab [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]4456eee22012-10-19 18:16:387#include "cc/texture_update_controller.h"
[email protected]94f206c12012-08-25 00:09:148
[email protected]6331a1172012-10-18 11:35:139#include "base/debug/trace_event.h"
[email protected]1e5b6bf52012-10-18 01:44:5210#include "cc/prioritized_texture.h"
11#include "cc/proxy.h"
[email protected]c4040a522012-10-21 15:01:4012#include "cc/resource_provider.h"
[email protected]a8461d82012-10-16 21:11:1413#include "cc/texture_copier.h"
[email protected]4456eee22012-10-19 18:16:3814#include "third_party/khronos/GLES2/gl2.h"
15#include "third_party/skia/include/gpu/SkGpuDevice.h"
[email protected]41b8f682012-09-19 01:51:1716#include <limits>
[email protected]1e5b6bf52012-10-18 01:44:5217#include <public/WebGraphicsContext3D.h>
18#include <public/WebSharedGraphicsContext3D.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
[email protected]96baf3e2012-10-22 23:09:5560size_t TextureUpdateController::maxPartialTextureUpdates()
[email protected]94f206c12012-08-25 00:09:1461{
[email protected]a7c078b2012-09-20 17:52:1262 return partialTextureUpdatesMax;
[email protected]41b8f682012-09-19 01:51:1763}
64
[email protected]96baf3e2012-10-22 23:09:5565size_t TextureUpdateController::maxFullUpdatesPerTick(
66 ResourceProvider* resourceProvider)
[email protected]41b8f682012-09-19 01:51:1767{
[email protected]e2249592012-10-19 06:59:0968 double texturesPerSecond = resourceProvider->estimatedUploadsPerSecond();
[email protected]41b8f682012-09-19 01:51:1769 size_t texturesPerTick = floor(textureUpdateTickRate * texturesPerSecond);
70 return texturesPerTick ? texturesPerTick : 1;
[email protected]94f206c12012-08-25 00:09:1471}
72
[email protected]96baf3e2012-10-22 23:09:5573TextureUpdateController::TextureUpdateController(TextureUpdateControllerClient* client, Thread* thread, scoped_ptr<TextureUpdateQueue> queue, ResourceProvider* resourceProvider)
[email protected]3c496dc2012-09-13 23:14:2074 : m_client(client)
[email protected]96baf3e2012-10-22 23:09:5575 , m_timer(new Timer(thread, this))
[email protected]b1b800c2012-10-16 05:03:5976 , m_queue(queue.Pass())
[email protected]94f206c12012-08-25 00:09:1477 , m_resourceProvider(resourceProvider)
[email protected]e2249592012-10-19 06:59:0978 , m_textureUpdatesPerTick(maxFullUpdatesPerTick(resourceProvider))
[email protected]94f206c12012-08-25 00:09:1479 , m_firstUpdateAttempt(true)
80{
81}
82
[email protected]96baf3e2012-10-22 23:09:5583TextureUpdateController::~TextureUpdateController()
[email protected]94f206c12012-08-25 00:09:1484{
85}
86
[email protected]96baf3e2012-10-22 23:09:5587void TextureUpdateController::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]96baf3e2012-10-22 23:09:55110void TextureUpdateController::discardUploadsToEvictedResources()
[email protected]77a60b9b2012-09-19 23:59:01111{
112 m_queue->clearUploadsToEvictedResources();
113}
114
[email protected]96baf3e2012-10-22 23:09:55115void TextureUpdateController::updateTexture(ResourceUpdate update)
[email protected]1e5b6bf52012-10-18 01:44:52116{
117 if (update.picture) {
[email protected]96baf3e2012-10-22 23:09:55118 PrioritizedTexture* texture = update.texture;
[email protected]1e5b6bf52012-10-18 01:44:52119 IntRect pictureRect = update.content_rect;
120 IntRect sourceRect = update.source_rect;
121 IntSize destOffset = update.dest_offset;
122
123 texture->acquireBackingTexture(m_resourceProvider);
[email protected]1d993172012-10-18 18:15:04124 DCHECK(texture->haveBackingTexture());
[email protected]1e5b6bf52012-10-18 01:44:52125
[email protected]1d993172012-10-18 18:15:04126 DCHECK(m_resourceProvider->resourceType(texture->resourceId()) ==
[email protected]96baf3e2012-10-22 23:09:55127 ResourceProvider::GLTexture);
[email protected]1e5b6bf52012-10-18 01:44:52128
[email protected]96baf3e2012-10-22 23:09:55129 WebGraphicsContext3D* paintContext = Proxy::hasImplThread() ?
[email protected]1e5b6bf52012-10-18 01:44:52130 WebSharedGraphicsContext3D::compositorThreadContext() :
131 WebSharedGraphicsContext3D::mainThreadContext();
[email protected]96baf3e2012-10-22 23:09:55132 GrContext* paintGrContext = Proxy::hasImplThread() ?
[email protected]1e5b6bf52012-10-18 01:44:52133 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();
[email protected]96baf3e2012-10-22 23:09:55141 ResourceProvider::ScopedWriteLockGL lock(
[email protected]1e5b6bf52012-10-18 01:44:52142 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) {
[email protected]e2249592012-10-19 06:59:09178 update.bitmap->lockPixels();
179 update.texture->upload(
180 m_resourceProvider,
181 static_cast<const uint8_t*>(update.bitmap->getPixels()),
182 update.content_rect,
183 update.source_rect,
184 update.dest_offset);
185 update.bitmap->unlockPixels();
[email protected]1e5b6bf52012-10-18 01:44:52186 }
187}
188
[email protected]96baf3e2012-10-22 23:09:55189void TextureUpdateController::finalize()
[email protected]12695152012-09-17 22:28:14190{
[email protected]f961b792012-09-20 07:27:33191 size_t uploadCount = 0;
192 while (m_queue->fullUploadSize()) {
193 if (!(uploadCount % textureUploadFlushPeriod) && uploadCount)
194 m_resourceProvider->shallowFlushIfSupported();
195
[email protected]1e5b6bf52012-10-18 01:44:52196 updateTexture(m_queue->takeFirstFullUpload());
[email protected]f961b792012-09-20 07:27:33197 uploadCount++;
198 }
199
200 while (m_queue->partialUploadSize()) {
201 if (!(uploadCount % textureUploadFlushPeriod) && uploadCount)
202 m_resourceProvider->shallowFlushIfSupported();
203
[email protected]1e5b6bf52012-10-18 01:44:52204 updateTexture(m_queue->takeFirstPartialUpload());
[email protected]f961b792012-09-20 07:27:33205 uploadCount++;
206 }
207
208 if (uploadCount)
209 m_resourceProvider->shallowFlushIfSupported();
210
211 if (m_queue->copySize()) {
212 TextureCopier* copier = m_resourceProvider->textureCopier();
213 while (m_queue->copySize())
214 copier->copyTexture(m_queue->takeFirstCopy());
215
216 // If we've performed any texture copies, we need to insert a flush
217 // here into the compositor context before letting the main thread
218 // proceed as it may make draw calls to the source texture of one of
219 // our copy operations.
220 copier->flush();
221 }
[email protected]12695152012-09-17 22:28:14222}
223
[email protected]96baf3e2012-10-22 23:09:55224void TextureUpdateController::onTimerFired()
[email protected]94f206c12012-08-25 00:09:14225{
[email protected]17953082012-10-24 20:13:32226 ResourceProvider::debugNotifyEnterZone(0xB000000);
[email protected]3c496dc2012-09-13 23:14:20227 if (!updateMoreTexturesIfEnoughTimeRemaining())
[email protected]12695152012-09-17 22:28:14228 m_client->readyToFinalizeTextureUpdates();
[email protected]17953082012-10-24 20:13:32229 ResourceProvider::debugNotifyLeaveZone();
[email protected]94f206c12012-08-25 00:09:14230}
231
[email protected]96baf3e2012-10-22 23:09:55232base::TimeTicks TextureUpdateController::now() const
[email protected]94f206c12012-08-25 00:09:14233{
[email protected]d918afe2012-09-27 19:27:21234 return base::TimeTicks::Now();
[email protected]94f206c12012-08-25 00:09:14235}
236
[email protected]96baf3e2012-10-22 23:09:55237base::TimeDelta TextureUpdateController::updateMoreTexturesTime() const
[email protected]94f206c12012-08-25 00:09:14238{
[email protected]d918afe2012-09-27 19:27:21239 return base::TimeDelta::FromMilliseconds(textureUpdateTickRate * 1000);
[email protected]94f206c12012-08-25 00:09:14240}
241
[email protected]96baf3e2012-10-22 23:09:55242size_t TextureUpdateController::updateMoreTexturesSize() const
[email protected]94f206c12012-08-25 00:09:14243{
[email protected]41b8f682012-09-19 01:51:17244 return m_textureUpdatesPerTick;
[email protected]94f206c12012-08-25 00:09:14245}
246
[email protected]96baf3e2012-10-22 23:09:55247size_t TextureUpdateController::maxBlockingUpdates() const
[email protected]549526e92012-09-29 15:43:08248{
[email protected]b914e102012-10-02 08:11:52249 return updateMoreTexturesSize() * maxBlockingUpdateIntervals;
[email protected]549526e92012-09-29 15:43:08250}
251
[email protected]96baf3e2012-10-22 23:09:55252bool TextureUpdateController::updateMoreTexturesIfEnoughTimeRemaining()
[email protected]94f206c12012-08-25 00:09:14253{
[email protected]b914e102012-10-02 08:11:52254 // Blocking uploads will increase when we're too aggressive in our upload
[email protected]549526e92012-09-29 15:43:08255 // time estimate. We use a different timeout here to prevent unnecessary
[email protected]b914e102012-10-02 08:11:52256 // amounts of idle time when blocking uploads have reached the max.
[email protected]e2249592012-10-19 06:59:09257 if (m_resourceProvider->numBlockingUploads() >= maxBlockingUpdates()) {
[email protected]12695152012-09-17 22:28:14258 m_timer->startOneShot(uploaderBusyTickRate);
259 return true;
260 }
261
262 if (!m_queue->fullUploadSize())
[email protected]3c496dc2012-09-13 23:14:20263 return false;
264
[email protected]e8e410d2012-09-28 01:47:01265 bool hasTimeRemaining = m_timeLimit.is_null() ||
266 this->now() < m_timeLimit - updateMoreTexturesTime();
[email protected]94f206c12012-08-25 00:09:14267 if (hasTimeRemaining)
268 updateMoreTexturesNow();
[email protected]3c496dc2012-09-13 23:14:20269
270 return true;
[email protected]94f206c12012-08-25 00:09:14271}
272
[email protected]96baf3e2012-10-22 23:09:55273void TextureUpdateController::updateMoreTexturesNow()
[email protected]94f206c12012-08-25 00:09:14274{
[email protected]12695152012-09-17 22:28:14275 size_t uploads = std::min(
276 m_queue->fullUploadSize(), updateMoreTexturesSize());
277 m_timer->startOneShot(
[email protected]d918afe2012-09-27 19:27:21278 updateMoreTexturesTime().InSecondsF() / updateMoreTexturesSize() *
279 uploads);
[email protected]12695152012-09-17 22:28:14280
281 if (!uploads)
282 return;
283
[email protected]12695152012-09-17 22:28:14284 size_t uploadCount = 0;
[email protected]41b8f682012-09-19 01:51:17285 while (m_queue->fullUploadSize() && uploadCount < uploads) {
286 if (!(uploadCount % textureUploadFlushPeriod) && uploadCount)
[email protected]12695152012-09-17 22:28:14287 m_resourceProvider->shallowFlushIfSupported();
[email protected]1e5b6bf52012-10-18 01:44:52288 updateTexture(m_queue->takeFirstFullUpload());
[email protected]41b8f682012-09-19 01:51:17289 uploadCount++;
[email protected]12695152012-09-17 22:28:14290 }
[email protected]41b8f682012-09-19 01:51:17291 m_resourceProvider->shallowFlushIfSupported();
[email protected]94f206c12012-08-25 00:09:14292}
293
[email protected]2d86b922012-10-13 16:57:47294} // namespace cc