| OLD | NEW |
| (Empty) |
| 1 // 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 "cc/resource_update_controller.h" | |
| 6 | |
| 7 #include <limits> | |
| 8 | |
| 9 #include "base/debug/trace_event.h" | |
| 10 #include "cc/base/thread.h" | |
| 11 #include "cc/output/context_provider.h" | |
| 12 #include "cc/output/texture_copier.h" | |
| 13 #include "cc/prioritized_resource.h" | |
| 14 #include "cc/resource_provider.h" | |
| 15 #include "skia/ext/refptr.h" | |
| 16 #include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3
D.h" | |
| 17 #include "third_party/khronos/GLES2/gl2.h" | |
| 18 #include "third_party/skia/include/gpu/SkGpuDevice.h" | |
| 19 | |
| 20 using WebKit::WebGraphicsContext3D; | |
| 21 | |
| 22 namespace { | |
| 23 | |
| 24 // Number of partial updates we allow. | |
| 25 const size_t kPartialTextureUpdatesMax = 12; | |
| 26 | |
| 27 // Measured in seconds. | |
| 28 const double kTextureUpdateTickRate = 0.004; | |
| 29 | |
| 30 // Measured in seconds. | |
| 31 const double kUploaderBusyTickRate = 0.001; | |
| 32 | |
| 33 // Number of blocking update intervals to allow. | |
| 34 const size_t kMaxBlockingUpdateIntervals = 4; | |
| 35 | |
| 36 skia::RefPtr<SkCanvas> CreateAcceleratedCanvas( | |
| 37 GrContext* gr_context, gfx::Size canvasSize, unsigned textureId) { | |
| 38 GrBackendTextureDesc texture_desc; | |
| 39 texture_desc.fFlags = kRenderTarget_GrBackendTextureFlag; | |
| 40 texture_desc.fWidth = canvasSize.width(); | |
| 41 texture_desc.fHeight = canvasSize.height(); | |
| 42 texture_desc.fConfig = kSkia8888_GrPixelConfig; | |
| 43 texture_desc.fTextureHandle = textureId; | |
| 44 skia::RefPtr<GrTexture> target = | |
| 45 skia::AdoptRef(gr_context->wrapBackendTexture(texture_desc)); | |
| 46 skia::RefPtr<SkDevice> device = | |
| 47 skia::AdoptRef(new SkGpuDevice(gr_context, target.get())); | |
| 48 return skia::AdoptRef(new SkCanvas(device.get())); | |
| 49 } | |
| 50 | |
| 51 } // namespace | |
| 52 | |
| 53 namespace cc { | |
| 54 | |
| 55 size_t ResourceUpdateController::MaxPartialTextureUpdates() { | |
| 56 return kPartialTextureUpdatesMax; | |
| 57 } | |
| 58 | |
| 59 size_t ResourceUpdateController::MaxFullUpdatesPerTick( | |
| 60 ResourceProvider* resource_provider) { | |
| 61 double textures_per_second = resource_provider->EstimatedUploadsPerSecond(); | |
| 62 size_t textures_per_tick = | |
| 63 floor(kTextureUpdateTickRate * textures_per_second); | |
| 64 return textures_per_tick ? textures_per_tick : 1; | |
| 65 } | |
| 66 | |
| 67 ResourceUpdateController::ResourceUpdateController( | |
| 68 ResourceUpdateControllerClient* client, | |
| 69 Thread* thread, | |
| 70 scoped_ptr<ResourceUpdateQueue> queue, | |
| 71 ResourceProvider* resource_provider) | |
| 72 : client_(client), | |
| 73 queue_(queue.Pass()), | |
| 74 resource_provider_(resource_provider), | |
| 75 texture_updates_per_tick_(MaxFullUpdatesPerTick(resource_provider)), | |
| 76 first_update_attempt_(true), | |
| 77 thread_(thread), | |
| 78 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), | |
| 79 task_posted_(false) {} | |
| 80 | |
| 81 ResourceUpdateController::~ResourceUpdateController() {} | |
| 82 | |
| 83 void ResourceUpdateController::PerformMoreUpdates( | |
| 84 base::TimeTicks timeLimit) { | |
| 85 time_limit_ = timeLimit; | |
| 86 | |
| 87 // Update already in progress. | |
| 88 if (task_posted_) | |
| 89 return; | |
| 90 | |
| 91 // Call UpdateMoreTexturesNow() directly unless it's the first update | |
| 92 // attempt. This ensures that we empty the update queue in a finite | |
| 93 // amount of time. | |
| 94 if (!first_update_attempt_) | |
| 95 UpdateMoreTexturesNow(); | |
| 96 | |
| 97 // Post a 0-delay task when no updates were left. When it runs, | |
| 98 // ReadyToFinalizeTextureUpdates() will be called. | |
| 99 if (!UpdateMoreTexturesIfEnoughTimeRemaining()) { | |
| 100 task_posted_ = true; | |
| 101 thread_->PostTask( | |
| 102 base::Bind(&ResourceUpdateController::OnTimerFired, | |
| 103 weak_factory_.GetWeakPtr())); | |
| 104 } | |
| 105 | |
| 106 first_update_attempt_ = false; | |
| 107 } | |
| 108 | |
| 109 void ResourceUpdateController::DiscardUploadsToEvictedResources() { | |
| 110 queue_->clearUploadsToEvictedResources(); | |
| 111 } | |
| 112 | |
| 113 void ResourceUpdateController::UpdateTexture(ResourceUpdate update) { | |
| 114 if (update.picture) { | |
| 115 PrioritizedResource* texture = update.texture; | |
| 116 gfx::Rect picture_rect = update.content_rect; | |
| 117 gfx::Rect source_rect = update.source_rect; | |
| 118 gfx::Vector2d dest_offset = update.dest_offset; | |
| 119 | |
| 120 texture->acquireBackingTexture(resource_provider_); | |
| 121 DCHECK(texture->haveBackingTexture()); | |
| 122 | |
| 123 DCHECK(resource_provider_->GetResourceType(texture->resourceId()) == | |
| 124 ResourceProvider::GLTexture); | |
| 125 | |
| 126 cc::ContextProvider* offscreen_contexts = | |
| 127 resource_provider_->offscreen_context_provider(); | |
| 128 | |
| 129 ResourceProvider::ScopedWriteLockGL lock( | |
| 130 resource_provider_, texture->resourceId()); | |
| 131 | |
| 132 // Flush the compositor context to ensure that textures there are available | |
| 133 // in the shared context. Do this after locking/creating the compositor | |
| 134 // texture. | |
| 135 resource_provider_->Flush(); | |
| 136 | |
| 137 // Make sure skia uses the correct GL context. | |
| 138 offscreen_contexts->Context3d()->makeContextCurrent(); | |
| 139 | |
| 140 // Create an accelerated canvas to draw on. | |
| 141 skia::RefPtr<SkCanvas> canvas = CreateAcceleratedCanvas( | |
| 142 offscreen_contexts->GrContext(), texture->size(), lock.texture_id()); | |
| 143 | |
| 144 // The compositor expects the textures to be upside-down so it can flip | |
| 145 // the final composited image. Ganesh renders the image upright so we | |
| 146 // need to do a y-flip. | |
| 147 canvas->translate(0.0, texture->size().height()); | |
| 148 canvas->scale(1.0, -1.0); | |
| 149 // Clip to the destination on the texture that must be updated. | |
| 150 canvas->clipRect(SkRect::MakeXYWH(dest_offset.x(), | |
| 151 dest_offset.y(), | |
| 152 source_rect.width(), | |
| 153 source_rect.height())); | |
| 154 // Translate the origin of picture_rect to dest_offset. | |
| 155 // Note that dest_offset is defined relative to source_rect. | |
| 156 canvas->translate( | |
| 157 picture_rect.x() - source_rect.x() + dest_offset.x(), | |
| 158 picture_rect.y() - source_rect.y() + dest_offset.y()); | |
| 159 canvas->drawPicture(*update.picture); | |
| 160 | |
| 161 // Flush skia context so that all the rendered stuff appears on the | |
| 162 // texture. | |
| 163 offscreen_contexts->GrContext()->flush(); | |
| 164 | |
| 165 // Flush the GL context so rendering results from this context are | |
| 166 // visible in the compositor's context. | |
| 167 offscreen_contexts->Context3d()->flush(); | |
| 168 | |
| 169 // Use the compositor's GL context again. | |
| 170 resource_provider_->GraphicsContext3D()->makeContextCurrent(); | |
| 171 } | |
| 172 | |
| 173 if (update.bitmap) { | |
| 174 update.bitmap->lockPixels(); | |
| 175 update.texture->setPixels( | |
| 176 resource_provider_, | |
| 177 static_cast<const uint8_t*>(update.bitmap->getPixels()), | |
| 178 update.content_rect, | |
| 179 update.source_rect, | |
| 180 update.dest_offset); | |
| 181 update.bitmap->unlockPixels(); | |
| 182 } | |
| 183 } | |
| 184 | |
| 185 void ResourceUpdateController::Finalize() { | |
| 186 while (queue_->fullUploadSize()) | |
| 187 UpdateTexture(queue_->takeFirstFullUpload()); | |
| 188 | |
| 189 while (queue_->partialUploadSize()) | |
| 190 UpdateTexture(queue_->takeFirstPartialUpload()); | |
| 191 | |
| 192 resource_provider_->FlushUploads(); | |
| 193 | |
| 194 if (queue_->copySize()) { | |
| 195 TextureCopier* copier = resource_provider_->texture_copier(); | |
| 196 while (queue_->copySize()) | |
| 197 copier->CopyTexture(queue_->takeFirstCopy()); | |
| 198 | |
| 199 // If we've performed any texture copies, we need to insert a flush | |
| 200 // here into the compositor context before letting the main thread | |
| 201 // proceed as it may make draw calls to the source texture of one of | |
| 202 // our copy operations. | |
| 203 copier->Flush(); | |
| 204 } | |
| 205 } | |
| 206 | |
| 207 void ResourceUpdateController::OnTimerFired() { | |
| 208 task_posted_ = false; | |
| 209 if (!UpdateMoreTexturesIfEnoughTimeRemaining()) | |
| 210 client_->ReadyToFinalizeTextureUpdates(); | |
| 211 } | |
| 212 | |
| 213 base::TimeTicks ResourceUpdateController::Now() const { | |
| 214 return base::TimeTicks::Now(); | |
| 215 } | |
| 216 | |
| 217 base::TimeDelta ResourceUpdateController::UpdateMoreTexturesTime() const { | |
| 218 return base::TimeDelta::FromMilliseconds(kTextureUpdateTickRate * 1000); | |
| 219 } | |
| 220 | |
| 221 size_t ResourceUpdateController::UpdateMoreTexturesSize() const { | |
| 222 return texture_updates_per_tick_; | |
| 223 } | |
| 224 | |
| 225 size_t ResourceUpdateController::MaxBlockingUpdates() const { | |
| 226 return UpdateMoreTexturesSize() * kMaxBlockingUpdateIntervals; | |
| 227 } | |
| 228 | |
| 229 base::TimeDelta ResourceUpdateController::PendingUpdateTime() const { | |
| 230 base::TimeDelta update_one_resource_time = | |
| 231 UpdateMoreTexturesTime() / UpdateMoreTexturesSize(); | |
| 232 return update_one_resource_time * resource_provider_->NumBlockingUploads(); | |
| 233 } | |
| 234 | |
| 235 bool ResourceUpdateController::UpdateMoreTexturesIfEnoughTimeRemaining() { | |
| 236 while (resource_provider_->NumBlockingUploads() < MaxBlockingUpdates()) { | |
| 237 if (!queue_->fullUploadSize()) | |
| 238 return false; | |
| 239 | |
| 240 if (!time_limit_.is_null()) { | |
| 241 // Estimated completion time of all pending updates. | |
| 242 base::TimeTicks completion_time = Now() + PendingUpdateTime(); | |
| 243 | |
| 244 // Time remaining based on current completion estimate. | |
| 245 base::TimeDelta time_remaining = time_limit_ - completion_time; | |
| 246 | |
| 247 if (time_remaining < UpdateMoreTexturesTime()) | |
| 248 return true; | |
| 249 } | |
| 250 | |
| 251 UpdateMoreTexturesNow(); | |
| 252 } | |
| 253 | |
| 254 task_posted_ = true; | |
| 255 thread_->PostDelayedTask( | |
| 256 base::Bind(&ResourceUpdateController::OnTimerFired, | |
| 257 weak_factory_.GetWeakPtr()), | |
| 258 base::TimeDelta::FromMilliseconds(kUploaderBusyTickRate * 1000)); | |
| 259 return true; | |
| 260 } | |
| 261 | |
| 262 void ResourceUpdateController::UpdateMoreTexturesNow() { | |
| 263 size_t uploads = std::min( | |
| 264 queue_->fullUploadSize(), UpdateMoreTexturesSize()); | |
| 265 | |
| 266 if (!uploads) | |
| 267 return; | |
| 268 | |
| 269 while (queue_->fullUploadSize() && uploads--) | |
| 270 UpdateTexture(queue_->takeFirstFullUpload()); | |
| 271 | |
| 272 resource_provider_->FlushUploads(); | |
| 273 } | |
| 274 | |
| 275 } // namespace cc | |
| OLD | NEW |