blob: 09de28338d21d660e953684cccbe71963b8a8247 [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]b4da2032012-10-25 21:22:557#include "cc/resource_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]3b10a302012-11-07 21:16:4010#include "cc/prioritized_resource.h"
[email protected]c4040a522012-10-21 15:01:4011#include "cc/resource_provider.h"
[email protected]a8461d82012-10-16 21:11:1412#include "cc/texture_copier.h"
[email protected]4a0488912012-10-30 23:29:5013#include "cc/thread.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
[email protected]1e5b6bf52012-10-18 01:44:5220using WebKit::WebGraphicsContext3D;
21using WebKit::WebSharedGraphicsContext3D;
22
[email protected]94f206c12012-08-25 00:09:1423namespace {
24
[email protected]41b8f682012-09-19 01:51:1725// Number of partial updates we allow.
[email protected]8284dcb2012-11-07 04:40:1226#if defined(OS_ANDROID)
27const size_t partialTextureUpdatesMax = 0;
28#else
[email protected]2d86b922012-10-13 16:57:4729const size_t partialTextureUpdatesMax = 12;
[email protected]8284dcb2012-11-07 04:40:1230#endif
[email protected]94f206c12012-08-25 00:09:1431
32// Measured in seconds.
[email protected]2d86b922012-10-13 16:57:4733const double textureUpdateTickRate = 0.004;
[email protected]94f206c12012-08-25 00:09:1434
[email protected]12695152012-09-17 22:28:1435// Measured in seconds.
[email protected]2d86b922012-10-13 16:57:4736const double uploaderBusyTickRate = 0.001;
[email protected]12695152012-09-17 22:28: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(
[email protected]f809d3bb2012-10-31 20:52:2542 GrContext* grContext, gfx::Size canvasSize, unsigned textureId)
[email protected]1e5b6bf52012-10-18 01:44:5243{
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]b4da2032012-10-25 21:22:5560size_t ResourceUpdateController::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]b4da2032012-10-25 21:22:5565size_t ResourceUpdateController::maxFullUpdatesPerTick(
[email protected]96baf3e2012-10-22 23:09:5566 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]61de5812012-11-08 07:03:4473ResourceUpdateController::ResourceUpdateController(ResourceUpdateControllerClient* client, Thread* thread, scoped_ptr<ResourceUpdateQueue> queue, ResourceProvider* resourceProvider, bool hasImplThread)
[email protected]3c496dc2012-09-13 23:14:2074 : m_client(client)
[email protected]61de5812012-11-08 07:03:4475 , m_hasImplThread(hasImplThread)
[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)
[email protected]4a0488912012-10-30 23:29:5080 , m_thread(thread)
81 , m_weakFactory(ALLOW_THIS_IN_INITIALIZER_LIST(this))
82 , m_taskPosted(false)
[email protected]94f206c12012-08-25 00:09:1483{
84}
85
[email protected]b4da2032012-10-25 21:22:5586ResourceUpdateController::~ResourceUpdateController()
[email protected]94f206c12012-08-25 00:09:1487{
88}
89
[email protected]b4da2032012-10-25 21:22:5590void ResourceUpdateController::performMoreUpdates(
[email protected]d918afe2012-09-27 19:27:2191 base::TimeTicks timeLimit)
[email protected]94f206c12012-08-25 00:09:1492{
[email protected]d918afe2012-09-27 19:27:2193 m_timeLimit = timeLimit;
[email protected]94f206c12012-08-25 00:09:1494
[email protected]3c496dc2012-09-13 23:14:2095 // Update already in progress.
[email protected]4a0488912012-10-30 23:29:5096 if (m_taskPosted)
[email protected]94f206c12012-08-25 00:09:1497 return;
98
99 // Call updateMoreTexturesNow() directly unless it's the first update
100 // attempt. This ensures that we empty the update queue in a finite
101 // amount of time.
[email protected]bb87580f2012-11-06 23:26:51102 if (!m_firstUpdateAttempt)
[email protected]94f206c12012-08-25 00:09:14103 updateMoreTexturesNow();
[email protected]bb87580f2012-11-06 23:26:51104
105 // Post a 0-delay task when no updates were left. When it runs,
106 // readyToFinalizeTextureUpdates() will be called.
107 if (!updateMoreTexturesIfEnoughTimeRemaining()) {
108 m_taskPosted = true;
109 m_thread->postTask(
110 base::Bind(&ResourceUpdateController::onTimerFired,
111 m_weakFactory.GetWeakPtr()));
112 }
113
114 m_firstUpdateAttempt = false;
[email protected]94f206c12012-08-25 00:09:14115}
116
[email protected]b4da2032012-10-25 21:22:55117void ResourceUpdateController::discardUploadsToEvictedResources()
[email protected]77a60b9b2012-09-19 23:59:01118{
119 m_queue->clearUploadsToEvictedResources();
120}
121
[email protected]b4da2032012-10-25 21:22:55122void ResourceUpdateController::updateTexture(ResourceUpdate update)
[email protected]1e5b6bf52012-10-18 01:44:52123{
124 if (update.picture) {
[email protected]3b10a302012-11-07 21:16:40125 PrioritizedResource* texture = update.texture;
[email protected]f809d3bb2012-10-31 20:52:25126 gfx::Rect pictureRect = update.content_rect;
127 gfx::Rect sourceRect = update.source_rect;
128 gfx::Vector2d destOffset = update.dest_offset;
[email protected]1e5b6bf52012-10-18 01:44:52129
130 texture->acquireBackingTexture(m_resourceProvider);
[email protected]1d993172012-10-18 18:15:04131 DCHECK(texture->haveBackingTexture());
[email protected]1e5b6bf52012-10-18 01:44:52132
[email protected]1d993172012-10-18 18:15:04133 DCHECK(m_resourceProvider->resourceType(texture->resourceId()) ==
[email protected]96baf3e2012-10-22 23:09:55134 ResourceProvider::GLTexture);
[email protected]1e5b6bf52012-10-18 01:44:52135
[email protected]61de5812012-11-08 07:03:44136 WebGraphicsContext3D* paintContext = m_hasImplThread ?
[email protected]1e5b6bf52012-10-18 01:44:52137 WebSharedGraphicsContext3D::compositorThreadContext() :
138 WebSharedGraphicsContext3D::mainThreadContext();
[email protected]61de5812012-11-08 07:03:44139 GrContext* paintGrContext = m_hasImplThread ?
[email protected]1e5b6bf52012-10-18 01:44:52140 WebSharedGraphicsContext3D::compositorThreadGrContext() :
141 WebSharedGraphicsContext3D::mainThreadGrContext();
142
143 // Flush the context in which the backing texture is created so that it
144 // is available in other shared contexts. It is important to do here
145 // because the backing texture is created in one context while it is
146 // being written to in another.
147 m_resourceProvider->flush();
[email protected]96baf3e2012-10-22 23:09:55148 ResourceProvider::ScopedWriteLockGL lock(
[email protected]1e5b6bf52012-10-18 01:44:52149 m_resourceProvider, texture->resourceId());
150
151 // Make sure ganesh uses the correct GL context.
152 paintContext->makeContextCurrent();
153
154 // Create an accelerated canvas to draw on.
155 scoped_ptr<SkCanvas> canvas = createAcceleratedCanvas(
156 paintGrContext, texture->size(), lock.textureId());
157
158 // The compositor expects the textures to be upside-down so it can flip
159 // the final composited image. Ganesh renders the image upright so we
160 // need to do a y-flip.
161 canvas->translate(0.0, texture->size().height());
162 canvas->scale(1.0, -1.0);
163 // Clip to the destination on the texture that must be updated.
[email protected]f809d3bb2012-10-31 20:52:25164 canvas->clipRect(SkRect::MakeXYWH(destOffset.x(),
165 destOffset.y(),
[email protected]1e5b6bf52012-10-18 01:44:52166 sourceRect.width(),
167 sourceRect.height()));
168 // Translate the origin of pictureRect to destOffset.
169 // Note that destOffset is defined relative to sourceRect.
170 canvas->translate(
[email protected]f809d3bb2012-10-31 20:52:25171 pictureRect.x() - sourceRect.x() + destOffset.x(),
172 pictureRect.y() - sourceRect.y() + destOffset.y());
[email protected]1e5b6bf52012-10-18 01:44:52173 canvas->drawPicture(*update.picture);
174
175 // Flush ganesh context so that all the rendered stuff appears on the
176 // texture.
177 paintGrContext->flush();
178
179 // Flush the GL context so rendering results from this context are
180 // visible in the compositor's context.
181 paintContext->flush();
182 }
183
184 if (update.bitmap) {
[email protected]e2249592012-10-19 06:59:09185 update.bitmap->lockPixels();
[email protected]a3d24452012-11-02 06:26:24186 update.texture->setPixels(
[email protected]e2249592012-10-19 06:59:09187 m_resourceProvider,
188 static_cast<const uint8_t*>(update.bitmap->getPixels()),
189 update.content_rect,
190 update.source_rect,
191 update.dest_offset);
192 update.bitmap->unlockPixels();
[email protected]1e5b6bf52012-10-18 01:44:52193 }
194}
195
[email protected]b4da2032012-10-25 21:22:55196void ResourceUpdateController::finalize()
[email protected]12695152012-09-17 22:28:14197{
[email protected]2b37dfd2012-11-03 20:52:32198 while (m_queue->fullUploadSize())
[email protected]1e5b6bf52012-10-18 01:44:52199 updateTexture(m_queue->takeFirstFullUpload());
[email protected]f961b792012-09-20 07:27:33200
[email protected]2b37dfd2012-11-03 20:52:32201 while (m_queue->partialUploadSize())
[email protected]1e5b6bf52012-10-18 01:44:52202 updateTexture(m_queue->takeFirstPartialUpload());
[email protected]f961b792012-09-20 07:27:33203
[email protected]2b37dfd2012-11-03 20:52:32204 m_resourceProvider->flushUploads();
[email protected]f961b792012-09-20 07:27:33205
206 if (m_queue->copySize()) {
207 TextureCopier* copier = m_resourceProvider->textureCopier();
208 while (m_queue->copySize())
209 copier->copyTexture(m_queue->takeFirstCopy());
210
211 // If we've performed any texture copies, we need to insert a flush
212 // here into the compositor context before letting the main thread
213 // proceed as it may make draw calls to the source texture of one of
214 // our copy operations.
215 copier->flush();
216 }
[email protected]12695152012-09-17 22:28:14217}
218
[email protected]b4da2032012-10-25 21:22:55219void ResourceUpdateController::onTimerFired()
[email protected]94f206c12012-08-25 00:09:14220{
[email protected]4a0488912012-10-30 23:29:50221 m_taskPosted = false;
[email protected]17953082012-10-24 20:13:32222 ResourceProvider::debugNotifyEnterZone(0xB000000);
[email protected]3c496dc2012-09-13 23:14:20223 if (!updateMoreTexturesIfEnoughTimeRemaining())
[email protected]12695152012-09-17 22:28:14224 m_client->readyToFinalizeTextureUpdates();
[email protected]17953082012-10-24 20:13:32225 ResourceProvider::debugNotifyLeaveZone();
[email protected]94f206c12012-08-25 00:09:14226}
227
[email protected]b4da2032012-10-25 21:22:55228base::TimeTicks ResourceUpdateController::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]b4da2032012-10-25 21:22:55233base::TimeDelta ResourceUpdateController::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
[email protected]b4da2032012-10-25 21:22:55238size_t ResourceUpdateController::updateMoreTexturesSize() const
[email protected]94f206c12012-08-25 00:09:14239{
[email protected]41b8f682012-09-19 01:51:17240 return m_textureUpdatesPerTick;
[email protected]94f206c12012-08-25 00:09:14241}
242
[email protected]b4da2032012-10-25 21:22:55243size_t ResourceUpdateController::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]bb87580f2012-11-06 23:26:51248base::TimeDelta ResourceUpdateController::pendingUpdateTime() const
249{
250 base::TimeDelta updateOneResourceTime =
251 updateMoreTexturesTime() / updateMoreTexturesSize();
252 return updateOneResourceTime * m_resourceProvider->numBlockingUploads();
253}
254
[email protected]b4da2032012-10-25 21:22:55255bool ResourceUpdateController::updateMoreTexturesIfEnoughTimeRemaining()
[email protected]94f206c12012-08-25 00:09:14256{
[email protected]bb87580f2012-11-06 23:26:51257 while (m_resourceProvider->numBlockingUploads() < maxBlockingUpdates()) {
258 if (!m_queue->fullUploadSize())
259 return false;
260
261 if (!m_timeLimit.is_null()) {
262 // Estimated completion time of all pending updates.
263 base::TimeTicks completionTime = this->now() + pendingUpdateTime();
264
265 // Time remaining based on current completion estimate.
266 base::TimeDelta timeRemaining = m_timeLimit - completionTime;
267
268 if (timeRemaining < updateMoreTexturesTime())
269 return true;
270 }
271
272 updateMoreTexturesNow();
[email protected]12695152012-09-17 22:28:14273 }
274
[email protected]bb87580f2012-11-06 23:26:51275 m_taskPosted = true;
276 m_thread->postDelayedTask(
277 base::Bind(&ResourceUpdateController::onTimerFired,
278 m_weakFactory.GetWeakPtr()),
279 uploaderBusyTickRate * 1000);
[email protected]3c496dc2012-09-13 23:14:20280 return true;
[email protected]94f206c12012-08-25 00:09:14281}
282
[email protected]b4da2032012-10-25 21:22:55283void ResourceUpdateController::updateMoreTexturesNow()
[email protected]94f206c12012-08-25 00:09:14284{
[email protected]12695152012-09-17 22:28:14285 size_t uploads = std::min(
286 m_queue->fullUploadSize(), updateMoreTexturesSize());
[email protected]12695152012-09-17 22:28:14287
288 if (!uploads)
289 return;
290
[email protected]2b37dfd2012-11-03 20:52:32291 while (m_queue->fullUploadSize() && uploads--)
[email protected]1e5b6bf52012-10-18 01:44:52292 updateTexture(m_queue->takeFirstFullUpload());
[email protected]2b37dfd2012-11-03 20:52:32293
294 m_resourceProvider->flushUploads();
[email protected]94f206c12012-08-25 00:09:14295}
296
[email protected]2d86b922012-10-13 16:57:47297} // namespace cc