blob: 1177d5372fcaa69b0d8012bf20243bdc572c23e9 [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
[email protected]b4da2032012-10-25 21:22:555#include "cc/resource_update_controller.h"
[email protected]94f206c12012-08-25 00:09:146
[email protected]920caa52012-12-18 22:39:507#include <limits>
8
[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]1940c4e2012-12-04 05:08:1514#include "skia/ext/refptr.h"
[email protected]920caa52012-12-18 22:39:5015#include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3D.h"
16#include "third_party/WebKit/Source/Platform/chromium/public/WebSharedGraphicsContext3D.h"
[email protected]4456eee22012-10-19 18:16:3817#include "third_party/khronos/GLES2/gl2.h"
18#include "third_party/skia/include/gpu/SkGpuDevice.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]2d86b922012-10-13 16:57:4726const size_t partialTextureUpdatesMax = 12;
[email protected]94f206c12012-08-25 00:09:1427
28// Measured in seconds.
[email protected]2d86b922012-10-13 16:57:4729const double textureUpdateTickRate = 0.004;
[email protected]94f206c12012-08-25 00:09:1430
[email protected]12695152012-09-17 22:28:1431// Measured in seconds.
[email protected]2d86b922012-10-13 16:57:4732const double uploaderBusyTickRate = 0.001;
[email protected]12695152012-09-17 22:28:1433
[email protected]b914e102012-10-02 08:11:5234// Number of blocking update intervals to allow.
[email protected]2d86b922012-10-13 16:57:4735const size_t maxBlockingUpdateIntervals = 4;
[email protected]549526e92012-09-29 15:43:0836
[email protected]1940c4e2012-12-04 05:08:1537skia::RefPtr<SkCanvas> createAcceleratedCanvas(
[email protected]f809d3bb2012-10-31 20:52:2538 GrContext* grContext, gfx::Size canvasSize, unsigned textureId)
[email protected]1e5b6bf52012-10-18 01:44:5239{
40 GrPlatformTextureDesc textureDesc;
41 textureDesc.fFlags = kRenderTarget_GrPlatformTextureFlag;
42 textureDesc.fWidth = canvasSize.width();
43 textureDesc.fHeight = canvasSize.height();
44 textureDesc.fConfig = kSkia8888_GrPixelConfig;
45 textureDesc.fTextureHandle = textureId;
[email protected]1940c4e2012-12-04 05:08:1546 skia::RefPtr<GrTexture> target =
47 skia::AdoptRef(grContext->createPlatformTexture(textureDesc));
48 skia::RefPtr<SkDevice> device =
49 skia::AdoptRef(new SkGpuDevice(grContext, target.get()));
50 return skia::AdoptRef(new SkCanvas(device.get()));
[email protected]1e5b6bf52012-10-18 01:44:5251}
52
[email protected]2d86b922012-10-13 16:57:4753} // namespace
[email protected]94f206c12012-08-25 00:09:1454
[email protected]9c88e562012-09-14 22:21:3055namespace cc {
[email protected]94f206c12012-08-25 00:09:1456
[email protected]b4da2032012-10-25 21:22:5557size_t ResourceUpdateController::maxPartialTextureUpdates()
[email protected]94f206c12012-08-25 00:09:1458{
[email protected]a7c078b2012-09-20 17:52:1259 return partialTextureUpdatesMax;
[email protected]41b8f682012-09-19 01:51:1760}
61
[email protected]b4da2032012-10-25 21:22:5562size_t ResourceUpdateController::maxFullUpdatesPerTick(
[email protected]96baf3e2012-10-22 23:09:5563 ResourceProvider* resourceProvider)
[email protected]41b8f682012-09-19 01:51:1764{
[email protected]e2249592012-10-19 06:59:0965 double texturesPerSecond = resourceProvider->estimatedUploadsPerSecond();
[email protected]41b8f682012-09-19 01:51:1766 size_t texturesPerTick = floor(textureUpdateTickRate * texturesPerSecond);
67 return texturesPerTick ? texturesPerTick : 1;
[email protected]94f206c12012-08-25 00:09:1468}
69
[email protected]61de5812012-11-08 07:03:4470ResourceUpdateController::ResourceUpdateController(ResourceUpdateControllerClient* client, Thread* thread, scoped_ptr<ResourceUpdateQueue> queue, ResourceProvider* resourceProvider, bool hasImplThread)
[email protected]3c496dc2012-09-13 23:14:2071 : m_client(client)
[email protected]61de5812012-11-08 07:03:4472 , m_hasImplThread(hasImplThread)
[email protected]b1b800c2012-10-16 05:03:5973 , m_queue(queue.Pass())
[email protected]94f206c12012-08-25 00:09:1474 , m_resourceProvider(resourceProvider)
[email protected]e2249592012-10-19 06:59:0975 , m_textureUpdatesPerTick(maxFullUpdatesPerTick(resourceProvider))
[email protected]94f206c12012-08-25 00:09:1476 , m_firstUpdateAttempt(true)
[email protected]4a0488912012-10-30 23:29:5077 , m_thread(thread)
78 , m_weakFactory(ALLOW_THIS_IN_INITIALIZER_LIST(this))
79 , m_taskPosted(false)
[email protected]94f206c12012-08-25 00:09:1480{
81}
82
[email protected]b4da2032012-10-25 21:22:5583ResourceUpdateController::~ResourceUpdateController()
[email protected]94f206c12012-08-25 00:09:1484{
85}
86
[email protected]b4da2032012-10-25 21:22:5587void ResourceUpdateController::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.
[email protected]4a0488912012-10-30 23:29:5093 if (m_taskPosted)
[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.
[email protected]bb87580f2012-11-06 23:26:5199 if (!m_firstUpdateAttempt)
[email protected]94f206c12012-08-25 00:09:14100 updateMoreTexturesNow();
[email protected]bb87580f2012-11-06 23:26:51101
102 // Post a 0-delay task when no updates were left. When it runs,
103 // readyToFinalizeTextureUpdates() will be called.
104 if (!updateMoreTexturesIfEnoughTimeRemaining()) {
105 m_taskPosted = true;
106 m_thread->postTask(
107 base::Bind(&ResourceUpdateController::onTimerFired,
108 m_weakFactory.GetWeakPtr()));
109 }
110
111 m_firstUpdateAttempt = false;
[email protected]94f206c12012-08-25 00:09:14112}
113
[email protected]b4da2032012-10-25 21:22:55114void ResourceUpdateController::discardUploadsToEvictedResources()
[email protected]77a60b9b2012-09-19 23:59:01115{
116 m_queue->clearUploadsToEvictedResources();
117}
118
[email protected]b4da2032012-10-25 21:22:55119void ResourceUpdateController::updateTexture(ResourceUpdate update)
[email protected]1e5b6bf52012-10-18 01:44:52120{
121 if (update.picture) {
[email protected]3b10a302012-11-07 21:16:40122 PrioritizedResource* texture = update.texture;
[email protected]f809d3bb2012-10-31 20:52:25123 gfx::Rect pictureRect = update.content_rect;
124 gfx::Rect sourceRect = update.source_rect;
125 gfx::Vector2d destOffset = update.dest_offset;
[email protected]1e5b6bf52012-10-18 01:44:52126
127 texture->acquireBackingTexture(m_resourceProvider);
[email protected]1d993172012-10-18 18:15:04128 DCHECK(texture->haveBackingTexture());
[email protected]1e5b6bf52012-10-18 01:44:52129
[email protected]1d993172012-10-18 18:15:04130 DCHECK(m_resourceProvider->resourceType(texture->resourceId()) ==
[email protected]96baf3e2012-10-22 23:09:55131 ResourceProvider::GLTexture);
[email protected]1e5b6bf52012-10-18 01:44:52132
[email protected]61de5812012-11-08 07:03:44133 WebGraphicsContext3D* paintContext = m_hasImplThread ?
[email protected]1e5b6bf52012-10-18 01:44:52134 WebSharedGraphicsContext3D::compositorThreadContext() :
135 WebSharedGraphicsContext3D::mainThreadContext();
[email protected]61de5812012-11-08 07:03:44136 GrContext* paintGrContext = m_hasImplThread ?
[email protected]1e5b6bf52012-10-18 01:44:52137 WebSharedGraphicsContext3D::compositorThreadGrContext() :
138 WebSharedGraphicsContext3D::mainThreadGrContext();
139
140 // Flush the context in which the backing texture is created so that it
141 // is available in other shared contexts. It is important to do here
142 // because the backing texture is created in one context while it is
143 // being written to in another.
[email protected]96baf3e2012-10-22 23:09:55144 ResourceProvider::ScopedWriteLockGL lock(
[email protected]1e5b6bf52012-10-18 01:44:52145 m_resourceProvider, texture->resourceId());
[email protected]0b2958b2013-01-09 21:06:11146 m_resourceProvider->flush();
[email protected]1e5b6bf52012-10-18 01:44:52147
148 // Make sure ganesh uses the correct GL context.
149 paintContext->makeContextCurrent();
150
151 // Create an accelerated canvas to draw on.
[email protected]1940c4e2012-12-04 05:08:15152 skia::RefPtr<SkCanvas> canvas = createAcceleratedCanvas(
[email protected]1e5b6bf52012-10-18 01:44:52153 paintGrContext, texture->size(), lock.textureId());
154
155 // The compositor expects the textures to be upside-down so it can flip
156 // the final composited image. Ganesh renders the image upright so we
157 // need to do a y-flip.
158 canvas->translate(0.0, texture->size().height());
159 canvas->scale(1.0, -1.0);
160 // Clip to the destination on the texture that must be updated.
[email protected]f809d3bb2012-10-31 20:52:25161 canvas->clipRect(SkRect::MakeXYWH(destOffset.x(),
162 destOffset.y(),
[email protected]1e5b6bf52012-10-18 01:44:52163 sourceRect.width(),
164 sourceRect.height()));
165 // Translate the origin of pictureRect to destOffset.
166 // Note that destOffset is defined relative to sourceRect.
167 canvas->translate(
[email protected]f809d3bb2012-10-31 20:52:25168 pictureRect.x() - sourceRect.x() + destOffset.x(),
169 pictureRect.y() - sourceRect.y() + destOffset.y());
[email protected]1e5b6bf52012-10-18 01:44:52170 canvas->drawPicture(*update.picture);
171
172 // Flush ganesh context so that all the rendered stuff appears on the
173 // texture.
174 paintGrContext->flush();
175
176 // Flush the GL context so rendering results from this context are
177 // visible in the compositor's context.
178 paintContext->flush();
179 }
180
181 if (update.bitmap) {
[email protected]e2249592012-10-19 06:59:09182 update.bitmap->lockPixels();
[email protected]a3d24452012-11-02 06:26:24183 update.texture->setPixels(
[email protected]e2249592012-10-19 06:59:09184 m_resourceProvider,
185 static_cast<const uint8_t*>(update.bitmap->getPixels()),
186 update.content_rect,
187 update.source_rect,
188 update.dest_offset);
189 update.bitmap->unlockPixels();
[email protected]1e5b6bf52012-10-18 01:44:52190 }
191}
192
[email protected]b4da2032012-10-25 21:22:55193void ResourceUpdateController::finalize()
[email protected]12695152012-09-17 22:28:14194{
[email protected]2b37dfd2012-11-03 20:52:32195 while (m_queue->fullUploadSize())
[email protected]1e5b6bf52012-10-18 01:44:52196 updateTexture(m_queue->takeFirstFullUpload());
[email protected]f961b792012-09-20 07:27:33197
[email protected]2b37dfd2012-11-03 20:52:32198 while (m_queue->partialUploadSize())
[email protected]1e5b6bf52012-10-18 01:44:52199 updateTexture(m_queue->takeFirstPartialUpload());
[email protected]f961b792012-09-20 07:27:33200
[email protected]2b37dfd2012-11-03 20:52:32201 m_resourceProvider->flushUploads();
[email protected]f961b792012-09-20 07:27:33202
203 if (m_queue->copySize()) {
204 TextureCopier* copier = m_resourceProvider->textureCopier();
205 while (m_queue->copySize())
206 copier->copyTexture(m_queue->takeFirstCopy());
207
208 // If we've performed any texture copies, we need to insert a flush
209 // here into the compositor context before letting the main thread
210 // proceed as it may make draw calls to the source texture of one of
211 // our copy operations.
212 copier->flush();
213 }
[email protected]12695152012-09-17 22:28:14214}
215
[email protected]b4da2032012-10-25 21:22:55216void ResourceUpdateController::onTimerFired()
[email protected]94f206c12012-08-25 00:09:14217{
[email protected]4a0488912012-10-30 23:29:50218 m_taskPosted = false;
[email protected]3c496dc2012-09-13 23:14:20219 if (!updateMoreTexturesIfEnoughTimeRemaining())
[email protected]12695152012-09-17 22:28:14220 m_client->readyToFinalizeTextureUpdates();
[email protected]94f206c12012-08-25 00:09:14221}
222
[email protected]b4da2032012-10-25 21:22:55223base::TimeTicks ResourceUpdateController::now() const
[email protected]94f206c12012-08-25 00:09:14224{
[email protected]d918afe2012-09-27 19:27:21225 return base::TimeTicks::Now();
[email protected]94f206c12012-08-25 00:09:14226}
227
[email protected]b4da2032012-10-25 21:22:55228base::TimeDelta ResourceUpdateController::updateMoreTexturesTime() const
[email protected]94f206c12012-08-25 00:09:14229{
[email protected]d918afe2012-09-27 19:27:21230 return base::TimeDelta::FromMilliseconds(textureUpdateTickRate * 1000);
[email protected]94f206c12012-08-25 00:09:14231}
232
[email protected]b4da2032012-10-25 21:22:55233size_t ResourceUpdateController::updateMoreTexturesSize() const
[email protected]94f206c12012-08-25 00:09:14234{
[email protected]41b8f682012-09-19 01:51:17235 return m_textureUpdatesPerTick;
[email protected]94f206c12012-08-25 00:09:14236}
237
[email protected]b4da2032012-10-25 21:22:55238size_t ResourceUpdateController::maxBlockingUpdates() const
[email protected]549526e92012-09-29 15:43:08239{
[email protected]b914e102012-10-02 08:11:52240 return updateMoreTexturesSize() * maxBlockingUpdateIntervals;
[email protected]549526e92012-09-29 15:43:08241}
242
[email protected]bb87580f2012-11-06 23:26:51243base::TimeDelta ResourceUpdateController::pendingUpdateTime() const
244{
245 base::TimeDelta updateOneResourceTime =
246 updateMoreTexturesTime() / updateMoreTexturesSize();
247 return updateOneResourceTime * m_resourceProvider->numBlockingUploads();
248}
249
[email protected]b4da2032012-10-25 21:22:55250bool ResourceUpdateController::updateMoreTexturesIfEnoughTimeRemaining()
[email protected]94f206c12012-08-25 00:09:14251{
[email protected]bb87580f2012-11-06 23:26:51252 while (m_resourceProvider->numBlockingUploads() < maxBlockingUpdates()) {
253 if (!m_queue->fullUploadSize())
254 return false;
255
256 if (!m_timeLimit.is_null()) {
257 // Estimated completion time of all pending updates.
258 base::TimeTicks completionTime = this->now() + pendingUpdateTime();
259
260 // Time remaining based on current completion estimate.
261 base::TimeDelta timeRemaining = m_timeLimit - completionTime;
262
263 if (timeRemaining < updateMoreTexturesTime())
264 return true;
265 }
266
267 updateMoreTexturesNow();
[email protected]12695152012-09-17 22:28:14268 }
269
[email protected]bb87580f2012-11-06 23:26:51270 m_taskPosted = true;
271 m_thread->postDelayedTask(
272 base::Bind(&ResourceUpdateController::onTimerFired,
273 m_weakFactory.GetWeakPtr()),
274 uploaderBusyTickRate * 1000);
[email protected]3c496dc2012-09-13 23:14:20275 return true;
[email protected]94f206c12012-08-25 00:09:14276}
277
[email protected]b4da2032012-10-25 21:22:55278void ResourceUpdateController::updateMoreTexturesNow()
[email protected]94f206c12012-08-25 00:09:14279{
[email protected]12695152012-09-17 22:28:14280 size_t uploads = std::min(
281 m_queue->fullUploadSize(), updateMoreTexturesSize());
[email protected]12695152012-09-17 22:28:14282
283 if (!uploads)
284 return;
285
[email protected]2b37dfd2012-11-03 20:52:32286 while (m_queue->fullUploadSize() && uploads--)
[email protected]1e5b6bf52012-10-18 01:44:52287 updateTexture(m_queue->takeFirstFullUpload());
[email protected]2b37dfd2012-11-03 20:52:32288
289 m_resourceProvider->flushUploads();
[email protected]94f206c12012-08-25 00:09:14290}
291
[email protected]2d86b922012-10-13 16:57:47292} // namespace cc