Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(464)

Side by Side Diff: content/browser/compositor/delegated_frame_host.cc

Issue 1841153002: BrowserCompositorMac, ResizeLock, DelegatedFrameHost => content/browser/renderer_host (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed Mac Build Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "content/browser/compositor/delegated_frame_host.h"
6
7 #include <algorithm>
8 #include <string>
9 #include <utility>
10 #include <vector>
11
12 #include "base/callback_helpers.h"
13 #include "base/command_line.h"
14 #include "base/time/default_tick_clock.h"
15 #include "cc/output/compositor_frame.h"
16 #include "cc/output/compositor_frame_ack.h"
17 #include "cc/output/copy_output_request.h"
18 #include "cc/resources/single_release_callback.h"
19 #include "cc/resources/texture_mailbox.h"
20 #include "cc/surfaces/surface.h"
21 #include "cc/surfaces/surface_factory.h"
22 #include "cc/surfaces/surface_hittest.h"
23 #include "cc/surfaces/surface_manager.h"
24 #include "content/browser/compositor/gl_helper.h"
25 #include "content/browser/compositor/resize_lock.h"
26 #include "content/browser/compositor/surface_utils.h"
27 #include "content/browser/gpu/compositor_util.h"
28 #include "content/public/browser/render_widget_host_view_frame_subscriber.h"
29 #include "content/public/common/content_switches.h"
30 #include "media/base/video_frame.h"
31 #include "media/base/video_util.h"
32 #include "skia/ext/image_operations.h"
33 #include "third_party/skia/include/core/SkCanvas.h"
34 #include "third_party/skia/include/core/SkPaint.h"
35 #include "third_party/skia/include/effects/SkLumaColorFilter.h"
36 #include "ui/gfx/geometry/dip_util.h"
37
38 namespace content {
39
40 namespace {
41
42 void SatisfyCallback(cc::SurfaceManager* manager,
43 cc::SurfaceSequence sequence) {
44 std::vector<uint32_t> sequences;
45 sequences.push_back(sequence.sequence);
46 manager->DidSatisfySequences(sequence.id_namespace, &sequences);
47 }
48
49 void RequireCallback(cc::SurfaceManager* manager,
50 cc::SurfaceId id,
51 cc::SurfaceSequence sequence) {
52 cc::Surface* surface = manager->GetSurfaceForId(id);
53 if (!surface) {
54 LOG(ERROR) << "Attempting to require callback on nonexistent surface";
55 return;
56 }
57 surface->AddDestructionDependency(sequence);
58 }
59
60 } // namespace
61
62 ////////////////////////////////////////////////////////////////////////////////
63 // DelegatedFrameHost
64
65 DelegatedFrameHost::DelegatedFrameHost(DelegatedFrameHostClient* client)
66 : client_(client),
67 compositor_(nullptr),
68 tick_clock_(new base::DefaultTickClock()),
69 last_output_surface_id_(0),
70 pending_delegated_ack_count_(0),
71 skipped_frames_(false),
72 background_color_(SK_ColorRED),
73 current_scale_factor_(1.f),
74 can_lock_compositor_(YES_CAN_LOCK),
75 delegated_frame_evictor_(new DelegatedFrameEvictor(this)),
76 begin_frame_source_(nullptr) {
77 ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
78 factory->AddObserver(this);
79 id_allocator_ = factory->GetContextFactory()->CreateSurfaceIdAllocator();
80 factory->GetSurfaceManager()->RegisterSurfaceFactoryClient(
81 id_allocator_->id_namespace(), this);
82 }
83
84 void DelegatedFrameHost::WasShown(const ui::LatencyInfo& latency_info) {
85 delegated_frame_evictor_->SetVisible(true);
86
87 if (surface_id_.is_null() &&
88 !released_front_lock_.get()) {
89 if (compositor_)
90 released_front_lock_ = compositor_->GetCompositorLock();
91 }
92
93 if (compositor_) {
94 compositor_->SetLatencyInfo(latency_info);
95 }
96 }
97
98 bool DelegatedFrameHost::HasSavedFrame() {
99 return delegated_frame_evictor_->HasFrame();
100 }
101
102 void DelegatedFrameHost::WasHidden() {
103 delegated_frame_evictor_->SetVisible(false);
104 released_front_lock_ = NULL;
105 }
106
107 void DelegatedFrameHost::MaybeCreateResizeLock() {
108 if (!ShouldCreateResizeLock())
109 return;
110 DCHECK(compositor_);
111
112 bool defer_compositor_lock =
113 can_lock_compositor_ == NO_PENDING_RENDERER_FRAME ||
114 can_lock_compositor_ == NO_PENDING_COMMIT;
115
116 if (can_lock_compositor_ == YES_CAN_LOCK)
117 can_lock_compositor_ = YES_DID_LOCK;
118
119 resize_lock_ =
120 client_->DelegatedFrameHostCreateResizeLock(defer_compositor_lock);
121 }
122
123 bool DelegatedFrameHost::ShouldCreateResizeLock() {
124 if (!client_->DelegatedFrameCanCreateResizeLock())
125 return false;
126
127 if (resize_lock_)
128 return false;
129
130 gfx::Size desired_size = client_->DelegatedFrameHostDesiredSizeInDIP();
131 if (desired_size == current_frame_size_in_dip_ || desired_size.IsEmpty())
132 return false;
133
134 if (!compositor_)
135 return false;
136
137 return true;
138 }
139
140 void DelegatedFrameHost::CopyFromCompositingSurface(
141 const gfx::Rect& src_subrect,
142 const gfx::Size& output_size,
143 const ReadbackRequestCallback& callback,
144 const SkColorType preferred_color_type) {
145 // Only ARGB888 and RGB565 supported as of now.
146 bool format_support = ((preferred_color_type == kAlpha_8_SkColorType) ||
147 (preferred_color_type == kRGB_565_SkColorType) ||
148 (preferred_color_type == kN32_SkColorType));
149 DCHECK(format_support);
150 if (!CanCopyToBitmap()) {
151 callback.Run(SkBitmap(), content::READBACK_SURFACE_UNAVAILABLE);
152 return;
153 }
154
155 scoped_ptr<cc::CopyOutputRequest> request =
156 cc::CopyOutputRequest::CreateRequest(
157 base::Bind(&CopyFromCompositingSurfaceHasResult, output_size,
158 preferred_color_type, callback));
159 if (!src_subrect.IsEmpty())
160 request->set_area(src_subrect);
161 RequestCopyOfOutput(std::move(request));
162 }
163
164 void DelegatedFrameHost::CopyFromCompositingSurfaceToVideoFrame(
165 const gfx::Rect& src_subrect,
166 const scoped_refptr<media::VideoFrame>& target,
167 const base::Callback<void(const gfx::Rect&, bool)>& callback) {
168 if (!CanCopyToVideoFrame()) {
169 callback.Run(gfx::Rect(), false);
170 return;
171 }
172
173 scoped_ptr<cc::CopyOutputRequest> request =
174 cc::CopyOutputRequest::CreateRequest(base::Bind(
175 &DelegatedFrameHost::
176 CopyFromCompositingSurfaceHasResultForVideo,
177 AsWeakPtr(), // For caching the ReadbackYUVInterface on this class.
178 nullptr,
179 target,
180 callback));
181 request->set_area(src_subrect);
182 RequestCopyOfOutput(std::move(request));
183 }
184
185 bool DelegatedFrameHost::CanCopyToBitmap() const {
186 return compositor_ &&
187 client_->DelegatedFrameHostGetLayer()->has_external_content();
188 }
189
190 bool DelegatedFrameHost::CanCopyToVideoFrame() const {
191 return compositor_ &&
192 client_->DelegatedFrameHostGetLayer()->has_external_content();
193 }
194
195 void DelegatedFrameHost::BeginFrameSubscription(
196 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) {
197 frame_subscriber_ = std::move(subscriber);
198 }
199
200 void DelegatedFrameHost::EndFrameSubscription() {
201 idle_frame_subscriber_textures_.clear();
202 frame_subscriber_.reset();
203 }
204
205 uint32_t DelegatedFrameHost::GetSurfaceIdNamespace() {
206 return id_allocator_->id_namespace();
207 }
208
209 cc::SurfaceId DelegatedFrameHost::SurfaceIdAtPoint(
210 cc::SurfaceHittestDelegate* delegate,
211 const gfx::Point& point,
212 gfx::Point* transformed_point) {
213 if (surface_id_.is_null())
214 return surface_id_;
215 cc::SurfaceHittest hittest(delegate, GetSurfaceManager());
216 gfx::Transform target_transform;
217 cc::SurfaceId target_surface_id =
218 hittest.GetTargetSurfaceAtPoint(surface_id_, point, &target_transform);
219 *transformed_point = point;
220 if (!target_surface_id.is_null())
221 target_transform.TransformPoint(transformed_point);
222 return target_surface_id;
223 }
224
225 void DelegatedFrameHost::TransformPointToLocalCoordSpace(
226 const gfx::Point& point,
227 cc::SurfaceId original_surface,
228 gfx::Point* transformed_point) {
229 *transformed_point = point;
230 if (surface_id_.is_null() || original_surface == surface_id_)
231 return;
232
233 gfx::Transform transform;
234 cc::SurfaceHittest hittest(nullptr, GetSurfaceManager());
235 if (hittest.GetTransformToTargetSurface(surface_id_, original_surface,
236 &transform) &&
237 transform.GetInverse(&transform)) {
238 transform.TransformPoint(transformed_point);
239 }
240 }
241
242 bool DelegatedFrameHost::ShouldSkipFrame(gfx::Size size_in_dip) const {
243 // Should skip a frame only when another frame from the renderer is guaranteed
244 // to replace it. Otherwise may cause hangs when the renderer is waiting for
245 // the completion of latency infos (such as when taking a Snapshot.)
246 if (can_lock_compositor_ == NO_PENDING_RENDERER_FRAME ||
247 can_lock_compositor_ == NO_PENDING_COMMIT ||
248 !resize_lock_.get())
249 return false;
250
251 return size_in_dip != resize_lock_->expected_size();
252 }
253
254 void DelegatedFrameHost::WasResized() {
255 if (client_->DelegatedFrameHostDesiredSizeInDIP() !=
256 current_frame_size_in_dip_ &&
257 !client_->DelegatedFrameHostIsVisible())
258 EvictDelegatedFrame();
259 MaybeCreateResizeLock();
260 UpdateGutters();
261 }
262
263 void DelegatedFrameHost::UpdateGutters() {
264 if (surface_id_.is_null()) {
265 right_gutter_.reset();
266 bottom_gutter_.reset();
267 return;
268 }
269 if (current_frame_size_in_dip_.width() <
270 client_->DelegatedFrameHostDesiredSizeInDIP().width()) {
271 right_gutter_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR));
272 right_gutter_->SetColor(background_color_);
273 int width = client_->DelegatedFrameHostDesiredSizeInDIP().width() -
274 current_frame_size_in_dip_.width();
275 // The right gutter also includes the bottom-right corner, if necessary.
276 int height = client_->DelegatedFrameHostDesiredSizeInDIP().height();
277 right_gutter_->SetBounds(
278 gfx::Rect(current_frame_size_in_dip_.width(), 0, width, height));
279
280 client_->DelegatedFrameHostGetLayer()->Add(right_gutter_.get());
281 } else {
282 right_gutter_.reset();
283 }
284
285 if (current_frame_size_in_dip_.height() <
286 client_->DelegatedFrameHostDesiredSizeInDIP().height()) {
287 bottom_gutter_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR));
288 bottom_gutter_->SetColor(background_color_);
289 int width = current_frame_size_in_dip_.width();
290 int height = client_->DelegatedFrameHostDesiredSizeInDIP().height() -
291 current_frame_size_in_dip_.height();
292 bottom_gutter_->SetBounds(
293 gfx::Rect(0, current_frame_size_in_dip_.height(), width, height));
294 client_->DelegatedFrameHostGetLayer()->Add(bottom_gutter_.get());
295
296 } else {
297 bottom_gutter_.reset();
298 }
299 }
300
301 gfx::Size DelegatedFrameHost::GetRequestedRendererSize() const {
302 if (resize_lock_)
303 return resize_lock_->expected_size();
304 else
305 return client_->DelegatedFrameHostDesiredSizeInDIP();
306 }
307
308 void DelegatedFrameHost::CheckResizeLock() {
309 if (!resize_lock_ ||
310 resize_lock_->expected_size() != current_frame_size_in_dip_)
311 return;
312
313 // Since we got the size we were looking for, unlock the compositor. But delay
314 // the release of the lock until we've kicked a frame with the new texture, to
315 // avoid resizing the UI before we have a chance to draw a "good" frame.
316 resize_lock_->UnlockCompositor();
317 }
318
319 void DelegatedFrameHost::AttemptFrameSubscriberCapture(
320 const gfx::Rect& damage_rect) {
321 if (!frame_subscriber() || !CanCopyToVideoFrame())
322 return;
323
324 const base::TimeTicks now = tick_clock_->NowTicks();
325 base::TimeTicks present_time;
326 if (vsync_interval_ <= base::TimeDelta()) {
327 present_time = now;
328 } else {
329 const int64_t intervals_elapsed = (now - vsync_timebase_) / vsync_interval_;
330 present_time = vsync_timebase_ + (intervals_elapsed + 1) * vsync_interval_;
331 }
332
333 scoped_refptr<media::VideoFrame> frame;
334 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback;
335 if (!frame_subscriber()->ShouldCaptureFrame(damage_rect, present_time,
336 &frame, &callback))
337 return;
338
339 // Get a texture to re-use; else, create a new one.
340 scoped_refptr<OwnedMailbox> subscriber_texture;
341 if (!idle_frame_subscriber_textures_.empty()) {
342 subscriber_texture = idle_frame_subscriber_textures_.back();
343 idle_frame_subscriber_textures_.pop_back();
344 } else if (GLHelper* helper =
345 ImageTransportFactory::GetInstance()->GetGLHelper()) {
346 subscriber_texture = new OwnedMailbox(helper);
347 }
348
349 scoped_ptr<cc::CopyOutputRequest> request =
350 cc::CopyOutputRequest::CreateRequest(base::Bind(
351 &DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo,
352 AsWeakPtr(),
353 subscriber_texture,
354 frame,
355 base::Bind(callback, present_time)));
356 // Setting the source in this copy request asks that the layer abort any prior
357 // uncommitted copy requests made on behalf of the same frame subscriber.
358 // This will not affect any of the copy requests spawned elsewhere from
359 // DelegatedFrameHost (e.g., a call to CopyFromCompositingSurface() for
360 // screenshots) since those copy requests do not specify |frame_subscriber()|
361 // as a source.
362 request->set_source(frame_subscriber());
363 if (subscriber_texture.get()) {
364 request->SetTextureMailbox(cc::TextureMailbox(
365 subscriber_texture->mailbox(), subscriber_texture->sync_token(),
366 subscriber_texture->target()));
367 }
368
369 if (surface_factory_.get()) {
370 // To avoid unnecessary composites, go directly to the Surface rather than
371 // through RequestCopyOfOutput (which goes through the browser
372 // compositor).
373 if (!request_copy_of_output_callback_for_testing_.is_null())
374 request_copy_of_output_callback_for_testing_.Run(std::move(request));
375 else
376 surface_factory_->RequestCopyOfSurface(surface_id_, std::move(request));
377 } else {
378 request->set_area(gfx::Rect(current_frame_size_in_dip_));
379 RequestCopyOfOutput(std::move(request));
380 }
381 }
382
383 void DelegatedFrameHost::SwapDelegatedFrame(
384 uint32_t output_surface_id,
385 scoped_ptr<cc::CompositorFrame> frame) {
386 DCHECK(frame->delegated_frame_data.get());
387 cc::DelegatedFrameData* frame_data = frame->delegated_frame_data.get();
388 float frame_device_scale_factor = frame->metadata.device_scale_factor;
389
390 DCHECK(!frame_data->render_pass_list.empty());
391
392 cc::RenderPass* root_pass = frame_data->render_pass_list.back().get();
393
394 gfx::Size frame_size = root_pass->output_rect.size();
395 gfx::Size frame_size_in_dip =
396 gfx::ConvertSizeToDIP(frame_device_scale_factor, frame_size);
397
398 gfx::Rect damage_rect = root_pass->damage_rect;
399 damage_rect.Intersect(gfx::Rect(frame_size));
400 gfx::Rect damage_rect_in_dip =
401 gfx::ConvertRectToDIP(frame_device_scale_factor, damage_rect);
402
403 if (ShouldSkipFrame(frame_size_in_dip)) {
404 cc::CompositorFrameAck ack;
405 cc::TransferableResource::ReturnResources(frame_data->resource_list,
406 &ack.resources);
407
408 skipped_latency_info_list_.insert(skipped_latency_info_list_.end(),
409 frame->metadata.latency_info.begin(),
410 frame->metadata.latency_info.end());
411
412 client_->DelegatedFrameHostSendCompositorSwapAck(output_surface_id, ack);
413 skipped_frames_ = true;
414 return;
415 }
416
417 if (skipped_frames_) {
418 skipped_frames_ = false;
419 damage_rect = gfx::Rect(frame_size);
420 damage_rect_in_dip = gfx::Rect(frame_size_in_dip);
421
422 // Give the same damage rect to the compositor.
423 cc::RenderPass* root_pass = frame_data->render_pass_list.back().get();
424 root_pass->damage_rect = damage_rect;
425 }
426
427 if (output_surface_id != last_output_surface_id_) {
428 // Resource ids are scoped by the output surface.
429 // If the originating output surface doesn't match the last one, it
430 // indicates the renderer's output surface may have been recreated, in which
431 // case we should recreate the DelegatedRendererLayer, to avoid matching
432 // resources from the old one with resources from the new one which would
433 // have the same id. Changing the layer to showing painted content destroys
434 // the DelegatedRendererLayer.
435 EvictDelegatedFrame();
436
437 surface_factory_.reset();
438 if (!surface_returned_resources_.empty())
439 SendReturnedDelegatedResources(last_output_surface_id_);
440
441 last_output_surface_id_ = output_surface_id;
442 }
443 bool skip_frame = false;
444 pending_delegated_ack_count_++;
445
446 background_color_ = frame->metadata.root_background_color;
447
448 if (frame_size.IsEmpty()) {
449 DCHECK(frame_data->resource_list.empty());
450 EvictDelegatedFrame();
451 } else {
452 ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
453 cc::SurfaceManager* manager = factory->GetSurfaceManager();
454 if (!surface_factory_) {
455 surface_factory_ =
456 make_scoped_ptr(new cc::SurfaceFactory(manager, this));
457 }
458 if (surface_id_.is_null() || frame_size != current_surface_size_ ||
459 frame_size_in_dip != current_frame_size_in_dip_) {
460 if (!surface_id_.is_null())
461 surface_factory_->Destroy(surface_id_);
462 surface_id_ = id_allocator_->GenerateId();
463 surface_factory_->Create(surface_id_);
464 // manager must outlive compositors using it.
465 client_->DelegatedFrameHostGetLayer()->SetShowSurface(
466 surface_id_,
467 base::Bind(&SatisfyCallback, base::Unretained(manager)),
468 base::Bind(&RequireCallback, base::Unretained(manager)), frame_size,
469 frame_device_scale_factor, frame_size_in_dip);
470 current_surface_size_ = frame_size;
471 current_scale_factor_ = frame_device_scale_factor;
472 }
473
474 frame->metadata.latency_info.insert(frame->metadata.latency_info.end(),
475 skipped_latency_info_list_.begin(),
476 skipped_latency_info_list_.end());
477 skipped_latency_info_list_.clear();
478
479 gfx::Size desired_size = client_->DelegatedFrameHostDesiredSizeInDIP();
480 if (desired_size != frame_size_in_dip && !desired_size.IsEmpty())
481 skip_frame = true;
482
483 cc::SurfaceFactory::DrawCallback ack_callback;
484 if (compositor_ && !skip_frame) {
485 ack_callback = base::Bind(&DelegatedFrameHost::SurfaceDrawn,
486 AsWeakPtr(), output_surface_id);
487 }
488 surface_factory_->SubmitCompositorFrame(surface_id_, std::move(frame),
489 ack_callback);
490 }
491 released_front_lock_ = NULL;
492 current_frame_size_in_dip_ = frame_size_in_dip;
493 CheckResizeLock();
494
495 UpdateGutters();
496
497 if (!damage_rect_in_dip.IsEmpty())
498 client_->DelegatedFrameHostGetLayer()->OnDelegatedFrameDamage(
499 damage_rect_in_dip);
500
501 // Note that |compositor_| may be reset by SetShowSurface or
502 // SetShowDelegatedContent above.
503 if (!compositor_ || skip_frame) {
504 SendDelegatedFrameAck(output_surface_id);
505 } else {
506 can_lock_compositor_ = NO_PENDING_COMMIT;
507 }
508 if (!surface_id_.is_null())
509 delegated_frame_evictor_->SwappedFrame(
510 client_->DelegatedFrameHostIsVisible());
511 // Note: the frame may have been evicted immediately.
512 }
513
514 void DelegatedFrameHost::ClearDelegatedFrame() {
515 if (!surface_id_.is_null())
516 EvictDelegatedFrame();
517 }
518
519 void DelegatedFrameHost::SendDelegatedFrameAck(uint32_t output_surface_id) {
520 cc::CompositorFrameAck ack;
521 if (!surface_returned_resources_.empty())
522 ack.resources.swap(surface_returned_resources_);
523 client_->DelegatedFrameHostSendCompositorSwapAck(output_surface_id, ack);
524 DCHECK_GT(pending_delegated_ack_count_, 0);
525 pending_delegated_ack_count_--;
526 }
527
528 void DelegatedFrameHost::SurfaceDrawn(uint32_t output_surface_id,
529 cc::SurfaceDrawStatus drawn) {
530 SendDelegatedFrameAck(output_surface_id);
531 }
532
533 void DelegatedFrameHost::SendReturnedDelegatedResources(
534 uint32_t output_surface_id) {
535 cc::CompositorFrameAck ack;
536 DCHECK(!surface_returned_resources_.empty());
537 ack.resources.swap(surface_returned_resources_);
538
539 client_->DelegatedFrameHostSendReclaimCompositorResources(output_surface_id,
540 ack);
541 }
542
543 void DelegatedFrameHost::ReturnResources(
544 const cc::ReturnedResourceArray& resources) {
545 if (resources.empty())
546 return;
547 std::copy(resources.begin(),
548 resources.end(),
549 std::back_inserter(surface_returned_resources_));
550 if (!pending_delegated_ack_count_)
551 SendReturnedDelegatedResources(last_output_surface_id_);
552 }
553
554 void DelegatedFrameHost::WillDrawSurface(cc::SurfaceId id,
555 const gfx::Rect& damage_rect) {
556 if (id != surface_id_)
557 return;
558 AttemptFrameSubscriberCapture(damage_rect);
559 }
560
561 void DelegatedFrameHost::SetBeginFrameSource(
562 cc::BeginFrameSource* begin_frame_source) {
563 // TODO(enne): forward this to DelegatedFrameHostClient to observe and then to
564 // the renderer as an external begin frame source.
565 }
566
567 void DelegatedFrameHost::EvictDelegatedFrame() {
568 client_->DelegatedFrameHostGetLayer()->SetShowSolidColorContent();
569 if (!surface_id_.is_null()) {
570 surface_factory_->Destroy(surface_id_);
571 surface_id_ = cc::SurfaceId();
572 }
573 delegated_frame_evictor_->DiscardedFrame();
574 UpdateGutters();
575 }
576
577 // static
578 void DelegatedFrameHost::ReturnSubscriberTexture(
579 base::WeakPtr<DelegatedFrameHost> dfh,
580 scoped_refptr<OwnedMailbox> subscriber_texture,
581 const gpu::SyncToken& sync_token) {
582 if (!subscriber_texture.get())
583 return;
584 if (!dfh)
585 return;
586
587 subscriber_texture->UpdateSyncToken(sync_token);
588
589 if (dfh->frame_subscriber_ && subscriber_texture->texture_id())
590 dfh->idle_frame_subscriber_textures_.push_back(subscriber_texture);
591 }
592
593 // static
594 void DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo(
595 base::WeakPtr<DelegatedFrameHost> dfh,
596 const base::Callback<void(bool)>& callback,
597 scoped_refptr<OwnedMailbox> subscriber_texture,
598 scoped_ptr<cc::SingleReleaseCallback> release_callback,
599 bool result) {
600 callback.Run(result);
601
602 gpu::SyncToken sync_token;
603 if (result) {
604 GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
605 gl_helper->GenerateSyncToken(&sync_token);
606 }
607 if (release_callback) {
608 // A release callback means the texture came from the compositor, so there
609 // should be no |subscriber_texture|.
610 DCHECK(!subscriber_texture.get());
611 const bool lost_resource = !sync_token.HasData();
612 release_callback->Run(sync_token, lost_resource);
613 }
614 ReturnSubscriberTexture(dfh, subscriber_texture, sync_token);
615 }
616
617 // static
618 void DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo(
619 base::WeakPtr<DelegatedFrameHost> dfh,
620 scoped_refptr<OwnedMailbox> subscriber_texture,
621 scoped_refptr<media::VideoFrame> video_frame,
622 const base::Callback<void(const gfx::Rect&, bool)>& callback,
623 scoped_ptr<cc::CopyOutputResult> result) {
624 base::ScopedClosureRunner scoped_callback_runner(
625 base::Bind(callback, gfx::Rect(), false));
626 base::ScopedClosureRunner scoped_return_subscriber_texture(
627 base::Bind(&ReturnSubscriberTexture, dfh, subscriber_texture,
628 gpu::SyncToken()));
629
630 if (!dfh)
631 return;
632 if (result->IsEmpty())
633 return;
634 if (result->size().IsEmpty())
635 return;
636
637 // Compute the dest size we want after the letterboxing resize. Make the
638 // coordinates and sizes even because we letterbox in YUV space
639 // (see CopyRGBToVideoFrame). They need to be even for the UV samples to
640 // line up correctly.
641 // The video frame's visible_rect() and the result's size() are both physical
642 // pixels.
643 gfx::Rect region_in_frame = media::ComputeLetterboxRegion(
644 video_frame->visible_rect(), result->size());
645 region_in_frame = gfx::Rect(region_in_frame.x() & ~1,
646 region_in_frame.y() & ~1,
647 region_in_frame.width() & ~1,
648 region_in_frame.height() & ~1);
649 if (region_in_frame.IsEmpty())
650 return;
651
652 if (!result->HasTexture()) {
653 DCHECK(result->HasBitmap());
654 scoped_ptr<SkBitmap> bitmap = result->TakeBitmap();
655 // Scale the bitmap to the required size, if necessary.
656 SkBitmap scaled_bitmap;
657 if (result->size() != region_in_frame.size()) {
658 skia::ImageOperations::ResizeMethod method =
659 skia::ImageOperations::RESIZE_GOOD;
660 scaled_bitmap = skia::ImageOperations::Resize(*bitmap.get(), method,
661 region_in_frame.width(),
662 region_in_frame.height());
663 } else {
664 scaled_bitmap = *bitmap.get();
665 }
666
667 {
668 SkAutoLockPixels scaled_bitmap_locker(scaled_bitmap);
669
670 media::CopyRGBToVideoFrame(
671 reinterpret_cast<uint8_t*>(scaled_bitmap.getPixels()),
672 scaled_bitmap.rowBytes(), region_in_frame, video_frame.get());
673 }
674 ignore_result(scoped_callback_runner.Release());
675 callback.Run(region_in_frame, true);
676 return;
677 }
678
679 ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
680 GLHelper* gl_helper = factory->GetGLHelper();
681 if (!gl_helper)
682 return;
683 if (subscriber_texture.get() && !subscriber_texture->texture_id())
684 return;
685
686 cc::TextureMailbox texture_mailbox;
687 scoped_ptr<cc::SingleReleaseCallback> release_callback;
688 result->TakeTexture(&texture_mailbox, &release_callback);
689 DCHECK(texture_mailbox.IsTexture());
690
691 gfx::Rect result_rect(result->size());
692
693 content::ReadbackYUVInterface* yuv_readback_pipeline =
694 dfh->yuv_readback_pipeline_.get();
695 if (yuv_readback_pipeline == NULL ||
696 yuv_readback_pipeline->scaler()->SrcSize() != result_rect.size() ||
697 yuv_readback_pipeline->scaler()->SrcSubrect() != result_rect ||
698 yuv_readback_pipeline->scaler()->DstSize() != region_in_frame.size()) {
699 GLHelper::ScalerQuality quality = GLHelper::SCALER_QUALITY_FAST;
700 std::string quality_switch = switches::kTabCaptureDownscaleQuality;
701 // If we're scaling up, we can use the "best" quality.
702 if (result_rect.size().width() < region_in_frame.size().width() &&
703 result_rect.size().height() < region_in_frame.size().height())
704 quality_switch = switches::kTabCaptureUpscaleQuality;
705
706 std::string switch_value =
707 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
708 quality_switch);
709 if (switch_value == "fast")
710 quality = GLHelper::SCALER_QUALITY_FAST;
711 else if (switch_value == "good")
712 quality = GLHelper::SCALER_QUALITY_GOOD;
713 else if (switch_value == "best")
714 quality = GLHelper::SCALER_QUALITY_BEST;
715
716 dfh->yuv_readback_pipeline_.reset(
717 gl_helper->CreateReadbackPipelineYUV(quality,
718 result_rect.size(),
719 result_rect,
720 region_in_frame.size(),
721 true,
722 true));
723 yuv_readback_pipeline = dfh->yuv_readback_pipeline_.get();
724 }
725
726 ignore_result(scoped_callback_runner.Release());
727 ignore_result(scoped_return_subscriber_texture.Release());
728
729 base::Callback<void(bool result)> finished_callback = base::Bind(
730 &DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo,
731 dfh->AsWeakPtr(), base::Bind(callback, region_in_frame),
732 subscriber_texture, base::Passed(&release_callback));
733 yuv_readback_pipeline->ReadbackYUV(texture_mailbox.mailbox(),
734 texture_mailbox.sync_token(),
735 video_frame.get(),
736 region_in_frame.origin(),
737 finished_callback);
738 }
739
740 ////////////////////////////////////////////////////////////////////////////////
741 // DelegatedFrameHost, ui::CompositorObserver implementation:
742
743 void DelegatedFrameHost::OnCompositingDidCommit(
744 ui::Compositor* compositor) {
745 if (can_lock_compositor_ == NO_PENDING_COMMIT) {
746 can_lock_compositor_ = YES_CAN_LOCK;
747 if (resize_lock_.get() && resize_lock_->GrabDeferredLock())
748 can_lock_compositor_ = YES_DID_LOCK;
749 }
750 if (resize_lock_ &&
751 resize_lock_->expected_size() == current_frame_size_in_dip_) {
752 resize_lock_.reset();
753 client_->DelegatedFrameHostResizeLockWasReleased();
754 // We may have had a resize while we had the lock (e.g. if the lock expired,
755 // or if the UI still gave us some resizes), so make sure we grab a new lock
756 // if necessary.
757 MaybeCreateResizeLock();
758 }
759 }
760
761 void DelegatedFrameHost::OnCompositingStarted(
762 ui::Compositor* compositor, base::TimeTicks start_time) {
763 last_draw_ended_ = start_time;
764 }
765
766 void DelegatedFrameHost::OnCompositingEnded(
767 ui::Compositor* compositor) {
768 }
769
770 void DelegatedFrameHost::OnCompositingAborted(ui::Compositor* compositor) {
771 }
772
773 void DelegatedFrameHost::OnCompositingLockStateChanged(
774 ui::Compositor* compositor) {
775 // A compositor lock that is part of a resize lock timed out. We
776 // should display a renderer frame.
777 if (!compositor->IsLocked() && can_lock_compositor_ == YES_DID_LOCK) {
778 can_lock_compositor_ = NO_PENDING_RENDERER_FRAME;
779 }
780 }
781
782 void DelegatedFrameHost::OnCompositingShuttingDown(ui::Compositor* compositor) {
783 DCHECK_EQ(compositor, compositor_);
784 ResetCompositor();
785 DCHECK(!compositor_);
786 }
787
788 void DelegatedFrameHost::OnUpdateVSyncParameters(
789 base::TimeTicks timebase,
790 base::TimeDelta interval) {
791 SetVSyncParameters(timebase, interval);
792 if (client_->DelegatedFrameHostIsVisible())
793 client_->DelegatedFrameHostUpdateVSyncParameters(timebase, interval);
794 }
795
796 ////////////////////////////////////////////////////////////////////////////////
797 // DelegatedFrameHost, ImageTransportFactoryObserver implementation:
798
799 void DelegatedFrameHost::OnLostResources() {
800 if (!surface_id_.is_null())
801 EvictDelegatedFrame();
802 idle_frame_subscriber_textures_.clear();
803 yuv_readback_pipeline_.reset();
804
805 client_->DelegatedFrameHostOnLostCompositorResources();
806 }
807
808 ////////////////////////////////////////////////////////////////////////////////
809 // DelegatedFrameHost, private:
810
811 DelegatedFrameHost::~DelegatedFrameHost() {
812 DCHECK(!compositor_);
813 ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
814 factory->RemoveObserver(this);
815
816 if (!surface_id_.is_null())
817 surface_factory_->Destroy(surface_id_);
818 factory->GetSurfaceManager()->UnregisterSurfaceFactoryClient(
819 id_allocator_->id_namespace());
820
821 DCHECK(!vsync_manager_.get());
822 }
823
824 void DelegatedFrameHost::SetCompositor(ui::Compositor* compositor) {
825 DCHECK(!compositor_);
826 if (!compositor)
827 return;
828 compositor_ = compositor;
829 compositor_->AddObserver(this);
830 DCHECK(!vsync_manager_.get());
831 vsync_manager_ = compositor_->vsync_manager();
832 vsync_manager_->AddObserver(this);
833
834 ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
835 uint32_t parent = compositor->surface_id_allocator()->id_namespace();
836 factory->GetSurfaceManager()->RegisterSurfaceNamespaceHierarchy(
837 parent, id_allocator_->id_namespace());
838 }
839
840 void DelegatedFrameHost::ResetCompositor() {
841 if (!compositor_)
842 return;
843 if (resize_lock_) {
844 resize_lock_.reset();
845 client_->DelegatedFrameHostResizeLockWasReleased();
846 }
847 if (compositor_->HasObserver(this))
848 compositor_->RemoveObserver(this);
849 if (vsync_manager_.get()) {
850 vsync_manager_->RemoveObserver(this);
851 vsync_manager_ = NULL;
852 }
853
854 ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
855 uint32_t parent = compositor_->surface_id_allocator()->id_namespace();
856 factory->GetSurfaceManager()->UnregisterSurfaceNamespaceHierarchy(
857 parent, id_allocator_->id_namespace());
858
859 compositor_ = nullptr;
860 }
861
862 void DelegatedFrameHost::SetVSyncParameters(const base::TimeTicks& timebase,
863 const base::TimeDelta& interval) {
864 vsync_timebase_ = timebase;
865 vsync_interval_ = interval;
866 }
867
868 void DelegatedFrameHost::LockResources() {
869 DCHECK(!surface_id_.is_null());
870 delegated_frame_evictor_->LockFrame();
871 }
872
873 void DelegatedFrameHost::RequestCopyOfOutput(
874 scoped_ptr<cc::CopyOutputRequest> request) {
875 if (!request_copy_of_output_callback_for_testing_.is_null()) {
876 request_copy_of_output_callback_for_testing_.Run(std::move(request));
877 } else {
878 client_->DelegatedFrameHostGetLayer()->RequestCopyOfOutput(
879 std::move(request));
880 }
881 }
882
883 void DelegatedFrameHost::UnlockResources() {
884 DCHECK(!surface_id_.is_null());
885 delegated_frame_evictor_->UnlockFrame();
886 }
887
888 ////////////////////////////////////////////////////////////////////////////////
889 // DelegatedFrameHost, ui::LayerOwnerDelegate implementation:
890
891 void DelegatedFrameHost::OnLayerRecreated(ui::Layer* old_layer,
892 ui::Layer* new_layer) {
893 // The new_layer is the one that will be used by our Window, so that's the one
894 // that should keep our frame. old_layer will be returned to the
895 // RecreateLayer caller, and should have a copy.
896 if (!surface_id_.is_null()) {
897 ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
898 cc::SurfaceManager* manager = factory->GetSurfaceManager();
899 new_layer->SetShowSurface(
900 surface_id_, base::Bind(&SatisfyCallback, base::Unretained(manager)),
901 base::Bind(&RequireCallback, base::Unretained(manager)),
902 current_surface_size_, current_scale_factor_,
903 current_frame_size_in_dip_);
904 }
905 }
906
907 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/compositor/delegated_frame_host.h ('k') | content/browser/compositor/resize_lock.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698