| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/compositor/delegated_frame_host.h" | 5 #include "content/browser/compositor/delegated_frame_host.h" |
| 6 | 6 |
| 7 #include "base/callback_helpers.h" | 7 #include "base/callback_helpers.h" |
| 8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "cc/output/compositor_frame.h" | 9 #include "cc/output/compositor_frame.h" |
| 10 #include "cc/output/compositor_frame_ack.h" | 10 #include "cc/output/compositor_frame_ack.h" |
| 11 #include "cc/output/copy_output_request.h" | 11 #include "cc/output/copy_output_request.h" |
| 12 #include "cc/resources/single_release_callback.h" | 12 #include "cc/resources/single_release_callback.h" |
| 13 #include "cc/resources/texture_mailbox.h" | 13 #include "cc/resources/texture_mailbox.h" |
| 14 #include "cc/surfaces/surface_factory.h" |
| 15 #include "content/browser/compositor/delegated_frame_layer_host.h" |
| 16 #include "content/browser/compositor/delegated_frame_surface_host.h" |
| 14 #include "content/browser/compositor/resize_lock.h" | 17 #include "content/browser/compositor/resize_lock.h" |
| 15 #include "content/common/gpu/client/gl_helper.h" | 18 #include "content/common/gpu/client/gl_helper.h" |
| 16 #include "content/public/browser/render_widget_host_view_frame_subscriber.h" | 19 #include "content/public/browser/render_widget_host_view_frame_subscriber.h" |
| 17 #include "content/public/common/content_switches.h" | 20 #include "content/public/common/content_switches.h" |
| 18 #include "media/base/video_frame.h" | 21 #include "media/base/video_frame.h" |
| 19 #include "media/base/video_util.h" | 22 #include "media/base/video_util.h" |
| 20 #include "skia/ext/image_operations.h" | 23 #include "skia/ext/image_operations.h" |
| 21 | 24 |
| 22 namespace content { | 25 namespace content { |
| 23 | 26 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 36 #else | 39 #else |
| 37 return GetDelegatedFrameHost()->ShouldCreateResizeLock(); | 40 return GetDelegatedFrameHost()->ShouldCreateResizeLock(); |
| 38 #endif | 41 #endif |
| 39 } | 42 } |
| 40 | 43 |
| 41 void DelegatedFrameHostClient::RequestCopyOfOutput( | 44 void DelegatedFrameHostClient::RequestCopyOfOutput( |
| 42 scoped_ptr<cc::CopyOutputRequest> request) { | 45 scoped_ptr<cc::CopyOutputRequest> request) { |
| 43 GetDelegatedFrameHost()->RequestCopyOfOutput(request.Pass()); | 46 GetDelegatedFrameHost()->RequestCopyOfOutput(request.Pass()); |
| 44 } | 47 } |
| 45 | 48 |
| 46 //////////////////////////////////////////////////////////////////////////////// | 49 // static |
| 47 // DelegatedFrameHost | 50 DelegatedFrameHost* DelegatedFrameHost::Create( |
| 48 | 51 DelegatedFrameHostClient* client) { |
| 49 DelegatedFrameHost::DelegatedFrameHost(DelegatedFrameHostClient* client) | 52 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 50 : client_(client), | 53 switches::kUseSurfaces)) { |
| 51 last_output_surface_id_(0), | 54 return new DelegatedFrameSurfaceHost(client); |
| 52 pending_delegated_ack_count_(0), | 55 } else { |
| 53 skipped_frames_(false), | 56 return new DelegatedFrameLayerHost(client); |
| 54 can_lock_compositor_(YES_CAN_LOCK), | |
| 55 delegated_frame_evictor_(new DelegatedFrameEvictor(this)) { | |
| 56 ImageTransportFactory::GetInstance()->AddObserver(this); | |
| 57 } | |
| 58 | |
| 59 void DelegatedFrameHost::WasShown() { | |
| 60 delegated_frame_evictor_->SetVisible(true); | |
| 61 | |
| 62 if (!released_front_lock_.get()) { | |
| 63 ui::Compositor* compositor = client_->GetCompositor(); | |
| 64 if (compositor) | |
| 65 released_front_lock_ = compositor->GetCompositorLock(); | |
| 66 } | 57 } |
| 67 } | 58 } |
| 68 | 59 |
| 69 void DelegatedFrameHost::WasHidden() { | |
| 70 delegated_frame_evictor_->SetVisible(false); | |
| 71 released_front_lock_ = NULL; | |
| 72 } | |
| 73 | |
| 74 void DelegatedFrameHost::MaybeCreateResizeLock() { | |
| 75 if (!client_->ShouldCreateResizeLock()) | |
| 76 return; | |
| 77 DCHECK(client_->GetCompositor()); | |
| 78 | |
| 79 // Listen to changes in the compositor lock state. | |
| 80 ui::Compositor* compositor = client_->GetCompositor(); | |
| 81 if (!compositor->HasObserver(this)) | |
| 82 compositor->AddObserver(this); | |
| 83 | |
| 84 bool defer_compositor_lock = | |
| 85 can_lock_compositor_ == NO_PENDING_RENDERER_FRAME || | |
| 86 can_lock_compositor_ == NO_PENDING_COMMIT; | |
| 87 | |
| 88 if (can_lock_compositor_ == YES_CAN_LOCK) | |
| 89 can_lock_compositor_ = YES_DID_LOCK; | |
| 90 | |
| 91 resize_lock_ = client_->CreateResizeLock(defer_compositor_lock); | |
| 92 } | |
| 93 | |
| 94 bool DelegatedFrameHost::ShouldCreateResizeLock() { | |
| 95 RenderWidgetHostImpl* host = client_->GetHost(); | |
| 96 | |
| 97 if (resize_lock_) | |
| 98 return false; | |
| 99 | |
| 100 if (host->should_auto_resize()) | |
| 101 return false; | |
| 102 | |
| 103 gfx::Size desired_size = client_->DesiredFrameSize(); | |
| 104 if (desired_size == current_frame_size_in_dip_ || desired_size.IsEmpty()) | |
| 105 return false; | |
| 106 | |
| 107 ui::Compositor* compositor = client_->GetCompositor(); | |
| 108 if (!compositor) | |
| 109 return false; | |
| 110 | |
| 111 return true; | |
| 112 } | |
| 113 | |
| 114 void DelegatedFrameHost::RequestCopyOfOutput( | |
| 115 scoped_ptr<cc::CopyOutputRequest> request) { | |
| 116 client_->GetLayer()->RequestCopyOfOutput(request.Pass()); | |
| 117 } | |
| 118 | |
| 119 void DelegatedFrameHost::CopyFromCompositingSurface( | |
| 120 const gfx::Rect& src_subrect, | |
| 121 const gfx::Size& dst_size, | |
| 122 const base::Callback<void(bool, const SkBitmap&)>& callback, | |
| 123 const SkColorType color_type) { | |
| 124 // Only ARGB888 and RGB565 supported as of now. | |
| 125 bool format_support = ((color_type == kRGB_565_SkColorType) || | |
| 126 (color_type == kN32_SkColorType)); | |
| 127 DCHECK(format_support); | |
| 128 if (!CanCopyToBitmap()) { | |
| 129 callback.Run(false, SkBitmap()); | |
| 130 return; | |
| 131 } | |
| 132 | |
| 133 const gfx::Size& dst_size_in_pixel = | |
| 134 client_->ConvertViewSizeToPixel(dst_size); | |
| 135 scoped_ptr<cc::CopyOutputRequest> request = | |
| 136 cc::CopyOutputRequest::CreateRequest(base::Bind( | |
| 137 &DelegatedFrameHost::CopyFromCompositingSurfaceHasResult, | |
| 138 dst_size_in_pixel, | |
| 139 color_type, | |
| 140 callback)); | |
| 141 gfx::Rect src_subrect_in_pixel = | |
| 142 ConvertRectToPixel(client_->CurrentDeviceScaleFactor(), src_subrect); | |
| 143 request->set_area(src_subrect_in_pixel); | |
| 144 client_->RequestCopyOfOutput(request.Pass()); | |
| 145 } | |
| 146 | |
| 147 void DelegatedFrameHost::CopyFromCompositingSurfaceToVideoFrame( | |
| 148 const gfx::Rect& src_subrect, | |
| 149 const scoped_refptr<media::VideoFrame>& target, | |
| 150 const base::Callback<void(bool)>& callback) { | |
| 151 if (!CanCopyToVideoFrame()) { | |
| 152 callback.Run(false); | |
| 153 return; | |
| 154 } | |
| 155 | |
| 156 // Try get a texture to reuse. | |
| 157 scoped_refptr<OwnedMailbox> subscriber_texture; | |
| 158 if (frame_subscriber_) { | |
| 159 if (!idle_frame_subscriber_textures_.empty()) { | |
| 160 subscriber_texture = idle_frame_subscriber_textures_.back(); | |
| 161 idle_frame_subscriber_textures_.pop_back(); | |
| 162 } else if (GLHelper* helper = | |
| 163 ImageTransportFactory::GetInstance()->GetGLHelper()) { | |
| 164 subscriber_texture = new OwnedMailbox(helper); | |
| 165 } | |
| 166 } | |
| 167 | |
| 168 scoped_ptr<cc::CopyOutputRequest> request = | |
| 169 cc::CopyOutputRequest::CreateRequest(base::Bind( | |
| 170 &DelegatedFrameHost:: | |
| 171 CopyFromCompositingSurfaceHasResultForVideo, | |
| 172 AsWeakPtr(), // For caching the ReadbackYUVInterface on this class. | |
| 173 subscriber_texture, | |
| 174 target, | |
| 175 callback)); | |
| 176 gfx::Rect src_subrect_in_pixel = | |
| 177 ConvertRectToPixel(client_->CurrentDeviceScaleFactor(), src_subrect); | |
| 178 request->set_area(src_subrect_in_pixel); | |
| 179 if (subscriber_texture.get()) { | |
| 180 request->SetTextureMailbox( | |
| 181 cc::TextureMailbox(subscriber_texture->mailbox(), | |
| 182 subscriber_texture->target(), | |
| 183 subscriber_texture->sync_point())); | |
| 184 } | |
| 185 client_->RequestCopyOfOutput(request.Pass()); | |
| 186 } | |
| 187 | |
| 188 bool DelegatedFrameHost::CanCopyToBitmap() const { | |
| 189 return client_->GetCompositor() && | |
| 190 client_->GetLayer()->has_external_content(); | |
| 191 } | |
| 192 | |
| 193 bool DelegatedFrameHost::CanCopyToVideoFrame() const { | |
| 194 return client_->GetCompositor() && | |
| 195 client_->GetLayer()->has_external_content(); | |
| 196 } | |
| 197 | |
| 198 bool DelegatedFrameHost::CanSubscribeFrame() const { | |
| 199 return true; | |
| 200 } | |
| 201 | |
| 202 void DelegatedFrameHost::BeginFrameSubscription( | |
| 203 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) { | |
| 204 frame_subscriber_ = subscriber.Pass(); | |
| 205 } | |
| 206 | |
| 207 void DelegatedFrameHost::EndFrameSubscription() { | |
| 208 idle_frame_subscriber_textures_.clear(); | |
| 209 frame_subscriber_.reset(); | |
| 210 } | |
| 211 | |
| 212 bool DelegatedFrameHost::ShouldSkipFrame(gfx::Size size_in_dip) const { | |
| 213 // Should skip a frame only when another frame from the renderer is guaranteed | |
| 214 // to replace it. Otherwise may cause hangs when the renderer is waiting for | |
| 215 // the completion of latency infos (such as when taking a Snapshot.) | |
| 216 if (can_lock_compositor_ == NO_PENDING_RENDERER_FRAME || | |
| 217 can_lock_compositor_ == NO_PENDING_COMMIT || | |
| 218 !resize_lock_.get()) | |
| 219 return false; | |
| 220 | |
| 221 return size_in_dip != resize_lock_->expected_size(); | |
| 222 } | |
| 223 | |
| 224 void DelegatedFrameHost::WasResized() { | |
| 225 MaybeCreateResizeLock(); | |
| 226 } | |
| 227 | |
| 228 gfx::Size DelegatedFrameHost::GetRequestedRendererSize() const { | |
| 229 if (resize_lock_) | |
| 230 return resize_lock_->expected_size(); | |
| 231 else | |
| 232 return client_->DesiredFrameSize(); | |
| 233 } | |
| 234 | |
| 235 void DelegatedFrameHost::CheckResizeLock() { | |
| 236 if (!resize_lock_ || | |
| 237 resize_lock_->expected_size() != current_frame_size_in_dip_) | |
| 238 return; | |
| 239 | |
| 240 // Since we got the size we were looking for, unlock the compositor. But delay | |
| 241 // the release of the lock until we've kicked a frame with the new texture, to | |
| 242 // avoid resizing the UI before we have a chance to draw a "good" frame. | |
| 243 resize_lock_->UnlockCompositor(); | |
| 244 ui::Compositor* compositor = client_->GetCompositor(); | |
| 245 if (compositor) { | |
| 246 if (!compositor->HasObserver(this)) | |
| 247 compositor->AddObserver(this); | |
| 248 } | |
| 249 } | |
| 250 | |
| 251 void DelegatedFrameHost::DidReceiveFrameFromRenderer() { | |
| 252 if (frame_subscriber() && CanCopyToVideoFrame()) { | |
| 253 const base::TimeTicks present_time = base::TimeTicks::Now(); | |
| 254 scoped_refptr<media::VideoFrame> frame; | |
| 255 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback; | |
| 256 if (frame_subscriber()->ShouldCaptureFrame(present_time, | |
| 257 &frame, &callback)) { | |
| 258 CopyFromCompositingSurfaceToVideoFrame( | |
| 259 gfx::Rect(current_frame_size_in_dip_), | |
| 260 frame, | |
| 261 base::Bind(callback, present_time)); | |
| 262 } | |
| 263 } | |
| 264 } | |
| 265 | |
| 266 void DelegatedFrameHost::SwapDelegatedFrame( | |
| 267 uint32 output_surface_id, | |
| 268 scoped_ptr<cc::DelegatedFrameData> frame_data, | |
| 269 float frame_device_scale_factor, | |
| 270 const std::vector<ui::LatencyInfo>& latency_info) { | |
| 271 RenderWidgetHostImpl* host = client_->GetHost(); | |
| 272 DCHECK(!frame_data->render_pass_list.empty()); | |
| 273 | |
| 274 cc::RenderPass* root_pass = frame_data->render_pass_list.back(); | |
| 275 | |
| 276 gfx::Size frame_size = root_pass->output_rect.size(); | |
| 277 gfx::Size frame_size_in_dip = | |
| 278 ConvertSizeToDIP(frame_device_scale_factor, frame_size); | |
| 279 | |
| 280 gfx::Rect damage_rect = gfx::ToEnclosingRect(root_pass->damage_rect); | |
| 281 damage_rect.Intersect(gfx::Rect(frame_size)); | |
| 282 gfx::Rect damage_rect_in_dip = | |
| 283 ConvertRectToDIP(frame_device_scale_factor, damage_rect); | |
| 284 | |
| 285 if (ShouldSkipFrame(frame_size_in_dip)) { | |
| 286 cc::CompositorFrameAck ack; | |
| 287 cc::TransferableResource::ReturnResources(frame_data->resource_list, | |
| 288 &ack.resources); | |
| 289 | |
| 290 skipped_latency_info_list_.insert(skipped_latency_info_list_.end(), | |
| 291 latency_info.begin(), latency_info.end()); | |
| 292 | |
| 293 RenderWidgetHostImpl::SendSwapCompositorFrameAck( | |
| 294 host->GetRoutingID(), output_surface_id, | |
| 295 host->GetProcess()->GetID(), ack); | |
| 296 skipped_frames_ = true; | |
| 297 return; | |
| 298 } | |
| 299 | |
| 300 if (skipped_frames_) { | |
| 301 skipped_frames_ = false; | |
| 302 damage_rect = gfx::Rect(frame_size); | |
| 303 damage_rect_in_dip = gfx::Rect(frame_size_in_dip); | |
| 304 | |
| 305 // Give the same damage rect to the compositor. | |
| 306 cc::RenderPass* root_pass = frame_data->render_pass_list.back(); | |
| 307 root_pass->damage_rect = damage_rect; | |
| 308 } | |
| 309 | |
| 310 if (output_surface_id != last_output_surface_id_) { | |
| 311 // Resource ids are scoped by the output surface. | |
| 312 // If the originating output surface doesn't match the last one, it | |
| 313 // indicates the renderer's output surface may have been recreated, in which | |
| 314 // case we should recreate the DelegatedRendererLayer, to avoid matching | |
| 315 // resources from the old one with resources from the new one which would | |
| 316 // have the same id. Changing the layer to showing painted content destroys | |
| 317 // the DelegatedRendererLayer. | |
| 318 EvictDelegatedFrame(); | |
| 319 | |
| 320 // Drop the cc::DelegatedFrameResourceCollection so that we will not return | |
| 321 // any resources from the old output surface with the new output surface id. | |
| 322 if (resource_collection_.get()) { | |
| 323 resource_collection_->SetClient(NULL); | |
| 324 | |
| 325 if (resource_collection_->LoseAllResources()) | |
| 326 SendReturnedDelegatedResources(last_output_surface_id_); | |
| 327 | |
| 328 resource_collection_ = NULL; | |
| 329 } | |
| 330 last_output_surface_id_ = output_surface_id; | |
| 331 } | |
| 332 if (frame_size.IsEmpty()) { | |
| 333 DCHECK(frame_data->resource_list.empty()); | |
| 334 EvictDelegatedFrame(); | |
| 335 } else { | |
| 336 if (!resource_collection_) { | |
| 337 resource_collection_ = new cc::DelegatedFrameResourceCollection; | |
| 338 resource_collection_->SetClient(this); | |
| 339 } | |
| 340 // If the physical frame size changes, we need a new |frame_provider_|. If | |
| 341 // the physical frame size is the same, but the size in DIP changed, we | |
| 342 // need to adjust the scale at which the frames will be drawn, and we do | |
| 343 // this by making a new |frame_provider_| also to ensure the scale change | |
| 344 // is presented in sync with the new frame content. | |
| 345 if (!frame_provider_.get() || frame_size != frame_provider_->frame_size() || | |
| 346 frame_size_in_dip != current_frame_size_in_dip_) { | |
| 347 frame_provider_ = new cc::DelegatedFrameProvider( | |
| 348 resource_collection_.get(), frame_data.Pass()); | |
| 349 client_->GetLayer()->SetShowDelegatedContent(frame_provider_.get(), | |
| 350 frame_size_in_dip); | |
| 351 } else { | |
| 352 frame_provider_->SetFrameData(frame_data.Pass()); | |
| 353 } | |
| 354 } | |
| 355 released_front_lock_ = NULL; | |
| 356 current_frame_size_in_dip_ = frame_size_in_dip; | |
| 357 CheckResizeLock(); | |
| 358 | |
| 359 client_->SchedulePaintInRect(damage_rect_in_dip); | |
| 360 | |
| 361 pending_delegated_ack_count_++; | |
| 362 | |
| 363 ui::Compositor* compositor = client_->GetCompositor(); | |
| 364 if (!compositor) { | |
| 365 SendDelegatedFrameAck(output_surface_id); | |
| 366 } else { | |
| 367 std::vector<ui::LatencyInfo>::const_iterator it; | |
| 368 for (it = latency_info.begin(); it != latency_info.end(); ++it) | |
| 369 compositor->SetLatencyInfo(*it); | |
| 370 // If we've previously skipped any latency infos add them. | |
| 371 for (it = skipped_latency_info_list_.begin(); | |
| 372 it != skipped_latency_info_list_.end(); | |
| 373 ++it) | |
| 374 compositor->SetLatencyInfo(*it); | |
| 375 skipped_latency_info_list_.clear(); | |
| 376 AddOnCommitCallbackAndDisableLocks( | |
| 377 base::Bind(&DelegatedFrameHost::SendDelegatedFrameAck, | |
| 378 AsWeakPtr(), | |
| 379 output_surface_id)); | |
| 380 } | |
| 381 DidReceiveFrameFromRenderer(); | |
| 382 if (frame_provider_.get()) | |
| 383 delegated_frame_evictor_->SwappedFrame(!host->is_hidden()); | |
| 384 // Note: the frame may have been evicted immediately. | |
| 385 } | |
| 386 | |
| 387 void DelegatedFrameHost::SendDelegatedFrameAck(uint32 output_surface_id) { | |
| 388 RenderWidgetHostImpl* host = client_->GetHost(); | |
| 389 cc::CompositorFrameAck ack; | |
| 390 if (resource_collection_) | |
| 391 resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources); | |
| 392 RenderWidgetHostImpl::SendSwapCompositorFrameAck(host->GetRoutingID(), | |
| 393 output_surface_id, | |
| 394 host->GetProcess()->GetID(), | |
| 395 ack); | |
| 396 DCHECK_GT(pending_delegated_ack_count_, 0); | |
| 397 pending_delegated_ack_count_--; | |
| 398 } | |
| 399 | |
| 400 void DelegatedFrameHost::UnusedResourcesAreAvailable() { | |
| 401 if (pending_delegated_ack_count_) | |
| 402 return; | |
| 403 | |
| 404 SendReturnedDelegatedResources(last_output_surface_id_); | |
| 405 } | |
| 406 | |
| 407 void DelegatedFrameHost::SendReturnedDelegatedResources( | |
| 408 uint32 output_surface_id) { | |
| 409 RenderWidgetHostImpl* host = client_->GetHost(); | |
| 410 DCHECK(resource_collection_); | |
| 411 | |
| 412 cc::CompositorFrameAck ack; | |
| 413 resource_collection_->TakeUnusedResourcesForChildCompositor(&ack.resources); | |
| 414 DCHECK(!ack.resources.empty()); | |
| 415 | |
| 416 RenderWidgetHostImpl::SendReclaimCompositorResources( | |
| 417 host->GetRoutingID(), | |
| 418 output_surface_id, | |
| 419 host->GetProcess()->GetID(), | |
| 420 ack); | |
| 421 } | |
| 422 | |
| 423 void DelegatedFrameHost::EvictDelegatedFrame() { | |
| 424 client_->GetLayer()->SetShowPaintedContent(); | |
| 425 frame_provider_ = NULL; | |
| 426 delegated_frame_evictor_->DiscardedFrame(); | |
| 427 } | |
| 428 | |
| 429 // static | |
| 430 void DelegatedFrameHost::CopyFromCompositingSurfaceHasResult( | |
| 431 const gfx::Size& dst_size_in_pixel, | |
| 432 const SkColorType color_type, | |
| 433 const base::Callback<void(bool, const SkBitmap&)>& callback, | |
| 434 scoped_ptr<cc::CopyOutputResult> result) { | |
| 435 if (result->IsEmpty() || result->size().IsEmpty()) { | |
| 436 callback.Run(false, SkBitmap()); | |
| 437 return; | |
| 438 } | |
| 439 | |
| 440 if (result->HasTexture()) { | |
| 441 PrepareTextureCopyOutputResult(dst_size_in_pixel, color_type, | |
| 442 callback, | |
| 443 result.Pass()); | |
| 444 return; | |
| 445 } | |
| 446 | |
| 447 DCHECK(result->HasBitmap()); | |
| 448 PrepareBitmapCopyOutputResult(dst_size_in_pixel, color_type, callback, | |
| 449 result.Pass()); | |
| 450 } | |
| 451 | |
| 452 static void CopyFromCompositingSurfaceFinished( | |
| 453 const base::Callback<void(bool, const SkBitmap&)>& callback, | |
| 454 scoped_ptr<cc::SingleReleaseCallback> release_callback, | |
| 455 scoped_ptr<SkBitmap> bitmap, | |
| 456 scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock, | |
| 457 bool result) { | |
| 458 bitmap_pixels_lock.reset(); | |
| 459 | |
| 460 uint32 sync_point = 0; | |
| 461 if (result) { | |
| 462 GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper(); | |
| 463 sync_point = gl_helper->InsertSyncPoint(); | |
| 464 } | |
| 465 bool lost_resource = sync_point == 0; | |
| 466 release_callback->Run(sync_point, lost_resource); | |
| 467 | |
| 468 callback.Run(result, *bitmap); | |
| 469 } | |
| 470 | |
| 471 // static | |
| 472 void DelegatedFrameHost::PrepareTextureCopyOutputResult( | |
| 473 const gfx::Size& dst_size_in_pixel, | |
| 474 const SkColorType color_type, | |
| 475 const base::Callback<void(bool, const SkBitmap&)>& callback, | |
| 476 scoped_ptr<cc::CopyOutputResult> result) { | |
| 477 DCHECK(result->HasTexture()); | |
| 478 base::ScopedClosureRunner scoped_callback_runner( | |
| 479 base::Bind(callback, false, SkBitmap())); | |
| 480 | |
| 481 scoped_ptr<SkBitmap> bitmap(new SkBitmap); | |
| 482 if (!bitmap->allocPixels(SkImageInfo::Make(dst_size_in_pixel.width(), | |
| 483 dst_size_in_pixel.height(), | |
| 484 color_type, | |
| 485 kOpaque_SkAlphaType))) | |
| 486 return; | |
| 487 | |
| 488 ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); | |
| 489 GLHelper* gl_helper = factory->GetGLHelper(); | |
| 490 if (!gl_helper) | |
| 491 return; | |
| 492 | |
| 493 scoped_ptr<SkAutoLockPixels> bitmap_pixels_lock( | |
| 494 new SkAutoLockPixels(*bitmap)); | |
| 495 uint8* pixels = static_cast<uint8*>(bitmap->getPixels()); | |
| 496 | |
| 497 cc::TextureMailbox texture_mailbox; | |
| 498 scoped_ptr<cc::SingleReleaseCallback> release_callback; | |
| 499 result->TakeTexture(&texture_mailbox, &release_callback); | |
| 500 DCHECK(texture_mailbox.IsTexture()); | |
| 501 | |
| 502 ignore_result(scoped_callback_runner.Release()); | |
| 503 | |
| 504 gl_helper->CropScaleReadbackAndCleanMailbox( | |
| 505 texture_mailbox.mailbox(), | |
| 506 texture_mailbox.sync_point(), | |
| 507 result->size(), | |
| 508 gfx::Rect(result->size()), | |
| 509 dst_size_in_pixel, | |
| 510 pixels, | |
| 511 color_type, | |
| 512 base::Bind(&CopyFromCompositingSurfaceFinished, | |
| 513 callback, | |
| 514 base::Passed(&release_callback), | |
| 515 base::Passed(&bitmap), | |
| 516 base::Passed(&bitmap_pixels_lock)), | |
| 517 GLHelper::SCALER_QUALITY_FAST); | |
| 518 } | |
| 519 | |
| 520 // static | |
| 521 void DelegatedFrameHost::PrepareBitmapCopyOutputResult( | |
| 522 const gfx::Size& dst_size_in_pixel, | |
| 523 const SkColorType color_type, | |
| 524 const base::Callback<void(bool, const SkBitmap&)>& callback, | |
| 525 scoped_ptr<cc::CopyOutputResult> result) { | |
| 526 if (color_type != kN32_SkColorType) { | |
| 527 NOTIMPLEMENTED(); | |
| 528 callback.Run(false, SkBitmap()); | |
| 529 return; | |
| 530 } | |
| 531 DCHECK(result->HasBitmap()); | |
| 532 scoped_ptr<SkBitmap> source = result->TakeBitmap(); | |
| 533 DCHECK(source); | |
| 534 SkBitmap bitmap = skia::ImageOperations::Resize( | |
| 535 *source, | |
| 536 skia::ImageOperations::RESIZE_BEST, | |
| 537 dst_size_in_pixel.width(), | |
| 538 dst_size_in_pixel.height()); | |
| 539 callback.Run(true, bitmap); | |
| 540 } | |
| 541 | |
| 542 // static | |
| 543 void DelegatedFrameHost::ReturnSubscriberTexture( | |
| 544 base::WeakPtr<DelegatedFrameHost> dfh, | |
| 545 scoped_refptr<OwnedMailbox> subscriber_texture, | |
| 546 uint32 sync_point) { | |
| 547 if (!subscriber_texture.get()) | |
| 548 return; | |
| 549 if (!dfh) | |
| 550 return; | |
| 551 | |
| 552 subscriber_texture->UpdateSyncPoint(sync_point); | |
| 553 | |
| 554 if (dfh->frame_subscriber_ && subscriber_texture->texture_id()) | |
| 555 dfh->idle_frame_subscriber_textures_.push_back(subscriber_texture); | |
| 556 } | |
| 557 | |
| 558 void DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo( | |
| 559 base::WeakPtr<DelegatedFrameHost> dfh, | |
| 560 const base::Callback<void(bool)>& callback, | |
| 561 scoped_refptr<OwnedMailbox> subscriber_texture, | |
| 562 scoped_ptr<cc::SingleReleaseCallback> release_callback, | |
| 563 bool result) { | |
| 564 callback.Run(result); | |
| 565 | |
| 566 uint32 sync_point = 0; | |
| 567 if (result) { | |
| 568 GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper(); | |
| 569 sync_point = gl_helper->InsertSyncPoint(); | |
| 570 } | |
| 571 if (release_callback) { | |
| 572 // A release callback means the texture came from the compositor, so there | |
| 573 // should be no |subscriber_texture|. | |
| 574 DCHECK(!subscriber_texture); | |
| 575 bool lost_resource = sync_point == 0; | |
| 576 release_callback->Run(sync_point, lost_resource); | |
| 577 } | |
| 578 ReturnSubscriberTexture(dfh, subscriber_texture, sync_point); | |
| 579 } | |
| 580 | |
| 581 // static | |
| 582 void DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo( | |
| 583 base::WeakPtr<DelegatedFrameHost> dfh, | |
| 584 scoped_refptr<OwnedMailbox> subscriber_texture, | |
| 585 scoped_refptr<media::VideoFrame> video_frame, | |
| 586 const base::Callback<void(bool)>& callback, | |
| 587 scoped_ptr<cc::CopyOutputResult> result) { | |
| 588 base::ScopedClosureRunner scoped_callback_runner(base::Bind(callback, false)); | |
| 589 base::ScopedClosureRunner scoped_return_subscriber_texture( | |
| 590 base::Bind(&ReturnSubscriberTexture, dfh, subscriber_texture, 0)); | |
| 591 | |
| 592 if (!dfh) | |
| 593 return; | |
| 594 if (result->IsEmpty()) | |
| 595 return; | |
| 596 if (result->size().IsEmpty()) | |
| 597 return; | |
| 598 | |
| 599 // Compute the dest size we want after the letterboxing resize. Make the | |
| 600 // coordinates and sizes even because we letterbox in YUV space | |
| 601 // (see CopyRGBToVideoFrame). They need to be even for the UV samples to | |
| 602 // line up correctly. | |
| 603 // The video frame's coded_size() and the result's size() are both physical | |
| 604 // pixels. | |
| 605 gfx::Rect region_in_frame = | |
| 606 media::ComputeLetterboxRegion(gfx::Rect(video_frame->coded_size()), | |
| 607 result->size()); | |
| 608 region_in_frame = gfx::Rect(region_in_frame.x() & ~1, | |
| 609 region_in_frame.y() & ~1, | |
| 610 region_in_frame.width() & ~1, | |
| 611 region_in_frame.height() & ~1); | |
| 612 if (region_in_frame.IsEmpty()) | |
| 613 return; | |
| 614 | |
| 615 if (!result->HasTexture()) { | |
| 616 DCHECK(result->HasBitmap()); | |
| 617 scoped_ptr<SkBitmap> bitmap = result->TakeBitmap(); | |
| 618 // Scale the bitmap to the required size, if necessary. | |
| 619 SkBitmap scaled_bitmap; | |
| 620 if (result->size().width() != region_in_frame.width() || | |
| 621 result->size().height() != region_in_frame.height()) { | |
| 622 skia::ImageOperations::ResizeMethod method = | |
| 623 skia::ImageOperations::RESIZE_GOOD; | |
| 624 scaled_bitmap = skia::ImageOperations::Resize(*bitmap.get(), method, | |
| 625 region_in_frame.width(), | |
| 626 region_in_frame.height()); | |
| 627 } else { | |
| 628 scaled_bitmap = *bitmap.get(); | |
| 629 } | |
| 630 | |
| 631 { | |
| 632 SkAutoLockPixels scaled_bitmap_locker(scaled_bitmap); | |
| 633 | |
| 634 media::CopyRGBToVideoFrame( | |
| 635 reinterpret_cast<uint8*>(scaled_bitmap.getPixels()), | |
| 636 scaled_bitmap.rowBytes(), | |
| 637 region_in_frame, | |
| 638 video_frame.get()); | |
| 639 } | |
| 640 ignore_result(scoped_callback_runner.Release()); | |
| 641 callback.Run(true); | |
| 642 return; | |
| 643 } | |
| 644 | |
| 645 ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); | |
| 646 GLHelper* gl_helper = factory->GetGLHelper(); | |
| 647 if (!gl_helper) | |
| 648 return; | |
| 649 if (subscriber_texture.get() && !subscriber_texture->texture_id()) | |
| 650 return; | |
| 651 | |
| 652 cc::TextureMailbox texture_mailbox; | |
| 653 scoped_ptr<cc::SingleReleaseCallback> release_callback; | |
| 654 result->TakeTexture(&texture_mailbox, &release_callback); | |
| 655 DCHECK(texture_mailbox.IsTexture()); | |
| 656 | |
| 657 gfx::Rect result_rect(result->size()); | |
| 658 | |
| 659 content::ReadbackYUVInterface* yuv_readback_pipeline = | |
| 660 dfh->yuv_readback_pipeline_.get(); | |
| 661 if (yuv_readback_pipeline == NULL || | |
| 662 yuv_readback_pipeline->scaler()->SrcSize() != result_rect.size() || | |
| 663 yuv_readback_pipeline->scaler()->SrcSubrect() != result_rect || | |
| 664 yuv_readback_pipeline->scaler()->DstSize() != region_in_frame.size()) { | |
| 665 GLHelper::ScalerQuality quality = GLHelper::SCALER_QUALITY_FAST; | |
| 666 std::string quality_switch = switches::kTabCaptureDownscaleQuality; | |
| 667 // If we're scaling up, we can use the "best" quality. | |
| 668 if (result_rect.size().width() < region_in_frame.size().width() && | |
| 669 result_rect.size().height() < region_in_frame.size().height()) | |
| 670 quality_switch = switches::kTabCaptureUpscaleQuality; | |
| 671 | |
| 672 std::string switch_value = | |
| 673 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(quality_switch); | |
| 674 if (switch_value == "fast") | |
| 675 quality = GLHelper::SCALER_QUALITY_FAST; | |
| 676 else if (switch_value == "good") | |
| 677 quality = GLHelper::SCALER_QUALITY_GOOD; | |
| 678 else if (switch_value == "best") | |
| 679 quality = GLHelper::SCALER_QUALITY_BEST; | |
| 680 | |
| 681 dfh->yuv_readback_pipeline_.reset( | |
| 682 gl_helper->CreateReadbackPipelineYUV(quality, | |
| 683 result_rect.size(), | |
| 684 result_rect, | |
| 685 video_frame->coded_size(), | |
| 686 region_in_frame, | |
| 687 true, | |
| 688 true)); | |
| 689 yuv_readback_pipeline = dfh->yuv_readback_pipeline_.get(); | |
| 690 } | |
| 691 | |
| 692 ignore_result(scoped_callback_runner.Release()); | |
| 693 ignore_result(scoped_return_subscriber_texture.Release()); | |
| 694 base::Callback<void(bool result)> finished_callback = base::Bind( | |
| 695 &DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo, | |
| 696 dfh->AsWeakPtr(), | |
| 697 callback, | |
| 698 subscriber_texture, | |
| 699 base::Passed(&release_callback)); | |
| 700 yuv_readback_pipeline->ReadbackYUV(texture_mailbox.mailbox(), | |
| 701 texture_mailbox.sync_point(), | |
| 702 video_frame.get(), | |
| 703 finished_callback); | |
| 704 } | |
| 705 | |
| 706 //////////////////////////////////////////////////////////////////////////////// | |
| 707 // DelegatedFrameHost, ui::CompositorObserver implementation: | |
| 708 | |
| 709 void DelegatedFrameHost::OnCompositingDidCommit( | |
| 710 ui::Compositor* compositor) { | |
| 711 RenderWidgetHostImpl* host = client_->GetHost(); | |
| 712 if (can_lock_compositor_ == NO_PENDING_COMMIT) { | |
| 713 can_lock_compositor_ = YES_CAN_LOCK; | |
| 714 if (resize_lock_.get() && resize_lock_->GrabDeferredLock()) | |
| 715 can_lock_compositor_ = YES_DID_LOCK; | |
| 716 } | |
| 717 RunOnCommitCallbacks(); | |
| 718 if (resize_lock_ && | |
| 719 resize_lock_->expected_size() == current_frame_size_in_dip_) { | |
| 720 resize_lock_.reset(); | |
| 721 host->WasResized(); | |
| 722 // We may have had a resize while we had the lock (e.g. if the lock expired, | |
| 723 // or if the UI still gave us some resizes), so make sure we grab a new lock | |
| 724 // if necessary. | |
| 725 MaybeCreateResizeLock(); | |
| 726 } | |
| 727 } | |
| 728 | |
| 729 void DelegatedFrameHost::OnCompositingStarted( | |
| 730 ui::Compositor* compositor, base::TimeTicks start_time) { | |
| 731 last_draw_ended_ = start_time; | |
| 732 } | |
| 733 | |
| 734 void DelegatedFrameHost::OnCompositingEnded( | |
| 735 ui::Compositor* compositor) { | |
| 736 } | |
| 737 | |
| 738 void DelegatedFrameHost::OnCompositingAborted(ui::Compositor* compositor) { | |
| 739 } | |
| 740 | |
| 741 void DelegatedFrameHost::OnCompositingLockStateChanged( | |
| 742 ui::Compositor* compositor) { | |
| 743 // A compositor lock that is part of a resize lock timed out. We | |
| 744 // should display a renderer frame. | |
| 745 if (!compositor->IsLocked() && can_lock_compositor_ == YES_DID_LOCK) { | |
| 746 can_lock_compositor_ = NO_PENDING_RENDERER_FRAME; | |
| 747 } | |
| 748 } | |
| 749 | |
| 750 void DelegatedFrameHost::OnUpdateVSyncParameters( | |
| 751 base::TimeTicks timebase, | |
| 752 base::TimeDelta interval) { | |
| 753 RenderWidgetHostImpl* host = client_->GetHost(); | |
| 754 if (client_->IsVisible()) | |
| 755 host->UpdateVSyncParameters(timebase, interval); | |
| 756 } | |
| 757 | |
| 758 //////////////////////////////////////////////////////////////////////////////// | |
| 759 // RenderWidgetHostViewAura, ImageTransportFactoryObserver implementation: | |
| 760 | |
| 761 void DelegatedFrameHost::OnLostResources() { | |
| 762 RenderWidgetHostImpl* host = client_->GetHost(); | |
| 763 if (frame_provider_.get()) | |
| 764 EvictDelegatedFrame(); | |
| 765 idle_frame_subscriber_textures_.clear(); | |
| 766 yuv_readback_pipeline_.reset(); | |
| 767 | |
| 768 host->ScheduleComposite(); | |
| 769 } | |
| 770 | |
| 771 //////////////////////////////////////////////////////////////////////////////// | |
| 772 // DelegatedFrameHost, private: | |
| 773 | |
| 774 DelegatedFrameHost::~DelegatedFrameHost() { | |
| 775 ImageTransportFactory::GetInstance()->RemoveObserver(this); | |
| 776 | |
| 777 if (resource_collection_.get()) | |
| 778 resource_collection_->SetClient(NULL); | |
| 779 | |
| 780 DCHECK(!vsync_manager_); | |
| 781 } | |
| 782 | |
| 783 void DelegatedFrameHost::RunOnCommitCallbacks() { | |
| 784 for (std::vector<base::Closure>::const_iterator | |
| 785 it = on_compositing_did_commit_callbacks_.begin(); | |
| 786 it != on_compositing_did_commit_callbacks_.end(); ++it) { | |
| 787 it->Run(); | |
| 788 } | |
| 789 on_compositing_did_commit_callbacks_.clear(); | |
| 790 } | |
| 791 | |
| 792 void DelegatedFrameHost::AddOnCommitCallbackAndDisableLocks( | |
| 793 const base::Closure& callback) { | |
| 794 ui::Compositor* compositor = client_->GetCompositor(); | |
| 795 DCHECK(compositor); | |
| 796 | |
| 797 if (!compositor->HasObserver(this)) | |
| 798 compositor->AddObserver(this); | |
| 799 | |
| 800 can_lock_compositor_ = NO_PENDING_COMMIT; | |
| 801 on_compositing_did_commit_callbacks_.push_back(callback); | |
| 802 } | |
| 803 | |
| 804 void DelegatedFrameHost::AddedToWindow() { | |
| 805 ui::Compositor* compositor = client_->GetCompositor(); | |
| 806 if (compositor) { | |
| 807 DCHECK(!vsync_manager_); | |
| 808 vsync_manager_ = compositor->vsync_manager(); | |
| 809 vsync_manager_->AddObserver(this); | |
| 810 } | |
| 811 } | |
| 812 | |
| 813 void DelegatedFrameHost::RemovingFromWindow() { | |
| 814 RunOnCommitCallbacks(); | |
| 815 resize_lock_.reset(); | |
| 816 client_->GetHost()->WasResized(); | |
| 817 ui::Compositor* compositor = client_->GetCompositor(); | |
| 818 if (compositor && compositor->HasObserver(this)) | |
| 819 compositor->RemoveObserver(this); | |
| 820 | |
| 821 if (vsync_manager_) { | |
| 822 vsync_manager_->RemoveObserver(this); | |
| 823 vsync_manager_ = NULL; | |
| 824 } | |
| 825 } | |
| 826 | |
| 827 void DelegatedFrameHost::LockResources() { | |
| 828 DCHECK(frame_provider_); | |
| 829 delegated_frame_evictor_->LockFrame(); | |
| 830 } | |
| 831 | |
| 832 void DelegatedFrameHost::UnlockResources() { | |
| 833 DCHECK(frame_provider_); | |
| 834 delegated_frame_evictor_->UnlockFrame(); | |
| 835 } | |
| 836 | |
| 837 //////////////////////////////////////////////////////////////////////////////// | |
| 838 // DelegatedFrameHost, ui::LayerOwnerDelegate implementation: | |
| 839 | |
| 840 void DelegatedFrameHost::OnLayerRecreated(ui::Layer* old_layer, | |
| 841 ui::Layer* new_layer) { | |
| 842 // The new_layer is the one that will be used by our Window, so that's the one | |
| 843 // that should keep our frame. old_layer will be returned to the | |
| 844 // RecreateLayer caller, and should have a copy. | |
| 845 if (frame_provider_.get()) { | |
| 846 new_layer->SetShowDelegatedContent(frame_provider_.get(), | |
| 847 current_frame_size_in_dip_); | |
| 848 } | |
| 849 } | |
| 850 | |
| 851 } // namespace content | 60 } // namespace content |
| 852 | 61 |
| OLD | NEW |