| Index: content/browser/compositor/delegated_frame_host.cc
|
| diff --git a/content/browser/compositor/delegated_frame_host.cc b/content/browser/compositor/delegated_frame_host.cc
|
| deleted file mode 100644
|
| index 348e436946f935edc45ce61480ebe41ba4f2da83..0000000000000000000000000000000000000000
|
| --- a/content/browser/compositor/delegated_frame_host.cc
|
| +++ /dev/null
|
| @@ -1,907 +0,0 @@
|
| -// Copyright 2014 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "content/browser/compositor/delegated_frame_host.h"
|
| -
|
| -#include <algorithm>
|
| -#include <string>
|
| -#include <utility>
|
| -#include <vector>
|
| -
|
| -#include "base/callback_helpers.h"
|
| -#include "base/command_line.h"
|
| -#include "base/time/default_tick_clock.h"
|
| -#include "cc/output/compositor_frame.h"
|
| -#include "cc/output/compositor_frame_ack.h"
|
| -#include "cc/output/copy_output_request.h"
|
| -#include "cc/resources/single_release_callback.h"
|
| -#include "cc/resources/texture_mailbox.h"
|
| -#include "cc/surfaces/surface.h"
|
| -#include "cc/surfaces/surface_factory.h"
|
| -#include "cc/surfaces/surface_hittest.h"
|
| -#include "cc/surfaces/surface_manager.h"
|
| -#include "content/browser/compositor/gl_helper.h"
|
| -#include "content/browser/compositor/resize_lock.h"
|
| -#include "content/browser/compositor/surface_utils.h"
|
| -#include "content/browser/gpu/compositor_util.h"
|
| -#include "content/public/browser/render_widget_host_view_frame_subscriber.h"
|
| -#include "content/public/common/content_switches.h"
|
| -#include "media/base/video_frame.h"
|
| -#include "media/base/video_util.h"
|
| -#include "skia/ext/image_operations.h"
|
| -#include "third_party/skia/include/core/SkCanvas.h"
|
| -#include "third_party/skia/include/core/SkPaint.h"
|
| -#include "third_party/skia/include/effects/SkLumaColorFilter.h"
|
| -#include "ui/gfx/geometry/dip_util.h"
|
| -
|
| -namespace content {
|
| -
|
| -namespace {
|
| -
|
| -void SatisfyCallback(cc::SurfaceManager* manager,
|
| - cc::SurfaceSequence sequence) {
|
| - std::vector<uint32_t> sequences;
|
| - sequences.push_back(sequence.sequence);
|
| - manager->DidSatisfySequences(sequence.id_namespace, &sequences);
|
| -}
|
| -
|
| -void RequireCallback(cc::SurfaceManager* manager,
|
| - cc::SurfaceId id,
|
| - cc::SurfaceSequence sequence) {
|
| - cc::Surface* surface = manager->GetSurfaceForId(id);
|
| - if (!surface) {
|
| - LOG(ERROR) << "Attempting to require callback on nonexistent surface";
|
| - return;
|
| - }
|
| - surface->AddDestructionDependency(sequence);
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -// DelegatedFrameHost
|
| -
|
| -DelegatedFrameHost::DelegatedFrameHost(DelegatedFrameHostClient* client)
|
| - : client_(client),
|
| - compositor_(nullptr),
|
| - tick_clock_(new base::DefaultTickClock()),
|
| - last_output_surface_id_(0),
|
| - pending_delegated_ack_count_(0),
|
| - skipped_frames_(false),
|
| - background_color_(SK_ColorRED),
|
| - current_scale_factor_(1.f),
|
| - can_lock_compositor_(YES_CAN_LOCK),
|
| - delegated_frame_evictor_(new DelegatedFrameEvictor(this)),
|
| - begin_frame_source_(nullptr) {
|
| - ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
|
| - factory->AddObserver(this);
|
| - id_allocator_ = factory->GetContextFactory()->CreateSurfaceIdAllocator();
|
| - factory->GetSurfaceManager()->RegisterSurfaceFactoryClient(
|
| - id_allocator_->id_namespace(), this);
|
| -}
|
| -
|
| -void DelegatedFrameHost::WasShown(const ui::LatencyInfo& latency_info) {
|
| - delegated_frame_evictor_->SetVisible(true);
|
| -
|
| - if (surface_id_.is_null() &&
|
| - !released_front_lock_.get()) {
|
| - if (compositor_)
|
| - released_front_lock_ = compositor_->GetCompositorLock();
|
| - }
|
| -
|
| - if (compositor_) {
|
| - compositor_->SetLatencyInfo(latency_info);
|
| - }
|
| -}
|
| -
|
| -bool DelegatedFrameHost::HasSavedFrame() {
|
| - return delegated_frame_evictor_->HasFrame();
|
| -}
|
| -
|
| -void DelegatedFrameHost::WasHidden() {
|
| - delegated_frame_evictor_->SetVisible(false);
|
| - released_front_lock_ = NULL;
|
| -}
|
| -
|
| -void DelegatedFrameHost::MaybeCreateResizeLock() {
|
| - if (!ShouldCreateResizeLock())
|
| - return;
|
| - DCHECK(compositor_);
|
| -
|
| - bool defer_compositor_lock =
|
| - can_lock_compositor_ == NO_PENDING_RENDERER_FRAME ||
|
| - can_lock_compositor_ == NO_PENDING_COMMIT;
|
| -
|
| - if (can_lock_compositor_ == YES_CAN_LOCK)
|
| - can_lock_compositor_ = YES_DID_LOCK;
|
| -
|
| - resize_lock_ =
|
| - client_->DelegatedFrameHostCreateResizeLock(defer_compositor_lock);
|
| -}
|
| -
|
| -bool DelegatedFrameHost::ShouldCreateResizeLock() {
|
| - if (!client_->DelegatedFrameCanCreateResizeLock())
|
| - return false;
|
| -
|
| - if (resize_lock_)
|
| - return false;
|
| -
|
| - gfx::Size desired_size = client_->DelegatedFrameHostDesiredSizeInDIP();
|
| - if (desired_size == current_frame_size_in_dip_ || desired_size.IsEmpty())
|
| - return false;
|
| -
|
| - if (!compositor_)
|
| - return false;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -void DelegatedFrameHost::CopyFromCompositingSurface(
|
| - const gfx::Rect& src_subrect,
|
| - const gfx::Size& output_size,
|
| - const ReadbackRequestCallback& callback,
|
| - const SkColorType preferred_color_type) {
|
| - // Only ARGB888 and RGB565 supported as of now.
|
| - bool format_support = ((preferred_color_type == kAlpha_8_SkColorType) ||
|
| - (preferred_color_type == kRGB_565_SkColorType) ||
|
| - (preferred_color_type == kN32_SkColorType));
|
| - DCHECK(format_support);
|
| - if (!CanCopyToBitmap()) {
|
| - callback.Run(SkBitmap(), content::READBACK_SURFACE_UNAVAILABLE);
|
| - return;
|
| - }
|
| -
|
| - scoped_ptr<cc::CopyOutputRequest> request =
|
| - cc::CopyOutputRequest::CreateRequest(
|
| - base::Bind(&CopyFromCompositingSurfaceHasResult, output_size,
|
| - preferred_color_type, callback));
|
| - if (!src_subrect.IsEmpty())
|
| - request->set_area(src_subrect);
|
| - RequestCopyOfOutput(std::move(request));
|
| -}
|
| -
|
| -void DelegatedFrameHost::CopyFromCompositingSurfaceToVideoFrame(
|
| - const gfx::Rect& src_subrect,
|
| - const scoped_refptr<media::VideoFrame>& target,
|
| - const base::Callback<void(const gfx::Rect&, bool)>& callback) {
|
| - if (!CanCopyToVideoFrame()) {
|
| - callback.Run(gfx::Rect(), false);
|
| - return;
|
| - }
|
| -
|
| - scoped_ptr<cc::CopyOutputRequest> request =
|
| - cc::CopyOutputRequest::CreateRequest(base::Bind(
|
| - &DelegatedFrameHost::
|
| - CopyFromCompositingSurfaceHasResultForVideo,
|
| - AsWeakPtr(), // For caching the ReadbackYUVInterface on this class.
|
| - nullptr,
|
| - target,
|
| - callback));
|
| - request->set_area(src_subrect);
|
| - RequestCopyOfOutput(std::move(request));
|
| -}
|
| -
|
| -bool DelegatedFrameHost::CanCopyToBitmap() const {
|
| - return compositor_ &&
|
| - client_->DelegatedFrameHostGetLayer()->has_external_content();
|
| -}
|
| -
|
| -bool DelegatedFrameHost::CanCopyToVideoFrame() const {
|
| - return compositor_ &&
|
| - client_->DelegatedFrameHostGetLayer()->has_external_content();
|
| -}
|
| -
|
| -void DelegatedFrameHost::BeginFrameSubscription(
|
| - scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) {
|
| - frame_subscriber_ = std::move(subscriber);
|
| -}
|
| -
|
| -void DelegatedFrameHost::EndFrameSubscription() {
|
| - idle_frame_subscriber_textures_.clear();
|
| - frame_subscriber_.reset();
|
| -}
|
| -
|
| -uint32_t DelegatedFrameHost::GetSurfaceIdNamespace() {
|
| - return id_allocator_->id_namespace();
|
| -}
|
| -
|
| -cc::SurfaceId DelegatedFrameHost::SurfaceIdAtPoint(
|
| - cc::SurfaceHittestDelegate* delegate,
|
| - const gfx::Point& point,
|
| - gfx::Point* transformed_point) {
|
| - if (surface_id_.is_null())
|
| - return surface_id_;
|
| - cc::SurfaceHittest hittest(delegate, GetSurfaceManager());
|
| - gfx::Transform target_transform;
|
| - cc::SurfaceId target_surface_id =
|
| - hittest.GetTargetSurfaceAtPoint(surface_id_, point, &target_transform);
|
| - *transformed_point = point;
|
| - if (!target_surface_id.is_null())
|
| - target_transform.TransformPoint(transformed_point);
|
| - return target_surface_id;
|
| -}
|
| -
|
| -void DelegatedFrameHost::TransformPointToLocalCoordSpace(
|
| - const gfx::Point& point,
|
| - cc::SurfaceId original_surface,
|
| - gfx::Point* transformed_point) {
|
| - *transformed_point = point;
|
| - if (surface_id_.is_null() || original_surface == surface_id_)
|
| - return;
|
| -
|
| - gfx::Transform transform;
|
| - cc::SurfaceHittest hittest(nullptr, GetSurfaceManager());
|
| - if (hittest.GetTransformToTargetSurface(surface_id_, original_surface,
|
| - &transform) &&
|
| - transform.GetInverse(&transform)) {
|
| - transform.TransformPoint(transformed_point);
|
| - }
|
| -}
|
| -
|
| -bool DelegatedFrameHost::ShouldSkipFrame(gfx::Size size_in_dip) const {
|
| - // Should skip a frame only when another frame from the renderer is guaranteed
|
| - // to replace it. Otherwise may cause hangs when the renderer is waiting for
|
| - // the completion of latency infos (such as when taking a Snapshot.)
|
| - if (can_lock_compositor_ == NO_PENDING_RENDERER_FRAME ||
|
| - can_lock_compositor_ == NO_PENDING_COMMIT ||
|
| - !resize_lock_.get())
|
| - return false;
|
| -
|
| - return size_in_dip != resize_lock_->expected_size();
|
| -}
|
| -
|
| -void DelegatedFrameHost::WasResized() {
|
| - if (client_->DelegatedFrameHostDesiredSizeInDIP() !=
|
| - current_frame_size_in_dip_ &&
|
| - !client_->DelegatedFrameHostIsVisible())
|
| - EvictDelegatedFrame();
|
| - MaybeCreateResizeLock();
|
| - UpdateGutters();
|
| -}
|
| -
|
| -void DelegatedFrameHost::UpdateGutters() {
|
| - if (surface_id_.is_null()) {
|
| - right_gutter_.reset();
|
| - bottom_gutter_.reset();
|
| - return;
|
| - }
|
| - if (current_frame_size_in_dip_.width() <
|
| - client_->DelegatedFrameHostDesiredSizeInDIP().width()) {
|
| - right_gutter_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR));
|
| - right_gutter_->SetColor(background_color_);
|
| - int width = client_->DelegatedFrameHostDesiredSizeInDIP().width() -
|
| - current_frame_size_in_dip_.width();
|
| - // The right gutter also includes the bottom-right corner, if necessary.
|
| - int height = client_->DelegatedFrameHostDesiredSizeInDIP().height();
|
| - right_gutter_->SetBounds(
|
| - gfx::Rect(current_frame_size_in_dip_.width(), 0, width, height));
|
| -
|
| - client_->DelegatedFrameHostGetLayer()->Add(right_gutter_.get());
|
| - } else {
|
| - right_gutter_.reset();
|
| - }
|
| -
|
| - if (current_frame_size_in_dip_.height() <
|
| - client_->DelegatedFrameHostDesiredSizeInDIP().height()) {
|
| - bottom_gutter_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR));
|
| - bottom_gutter_->SetColor(background_color_);
|
| - int width = current_frame_size_in_dip_.width();
|
| - int height = client_->DelegatedFrameHostDesiredSizeInDIP().height() -
|
| - current_frame_size_in_dip_.height();
|
| - bottom_gutter_->SetBounds(
|
| - gfx::Rect(0, current_frame_size_in_dip_.height(), width, height));
|
| - client_->DelegatedFrameHostGetLayer()->Add(bottom_gutter_.get());
|
| -
|
| - } else {
|
| - bottom_gutter_.reset();
|
| - }
|
| -}
|
| -
|
| -gfx::Size DelegatedFrameHost::GetRequestedRendererSize() const {
|
| - if (resize_lock_)
|
| - return resize_lock_->expected_size();
|
| - else
|
| - return client_->DelegatedFrameHostDesiredSizeInDIP();
|
| -}
|
| -
|
| -void DelegatedFrameHost::CheckResizeLock() {
|
| - if (!resize_lock_ ||
|
| - resize_lock_->expected_size() != current_frame_size_in_dip_)
|
| - return;
|
| -
|
| - // Since we got the size we were looking for, unlock the compositor. But delay
|
| - // the release of the lock until we've kicked a frame with the new texture, to
|
| - // avoid resizing the UI before we have a chance to draw a "good" frame.
|
| - resize_lock_->UnlockCompositor();
|
| -}
|
| -
|
| -void DelegatedFrameHost::AttemptFrameSubscriberCapture(
|
| - const gfx::Rect& damage_rect) {
|
| - if (!frame_subscriber() || !CanCopyToVideoFrame())
|
| - return;
|
| -
|
| - const base::TimeTicks now = tick_clock_->NowTicks();
|
| - base::TimeTicks present_time;
|
| - if (vsync_interval_ <= base::TimeDelta()) {
|
| - present_time = now;
|
| - } else {
|
| - const int64_t intervals_elapsed = (now - vsync_timebase_) / vsync_interval_;
|
| - present_time = vsync_timebase_ + (intervals_elapsed + 1) * vsync_interval_;
|
| - }
|
| -
|
| - scoped_refptr<media::VideoFrame> frame;
|
| - RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback;
|
| - if (!frame_subscriber()->ShouldCaptureFrame(damage_rect, present_time,
|
| - &frame, &callback))
|
| - return;
|
| -
|
| - // Get a texture to re-use; else, create a new one.
|
| - scoped_refptr<OwnedMailbox> subscriber_texture;
|
| - if (!idle_frame_subscriber_textures_.empty()) {
|
| - subscriber_texture = idle_frame_subscriber_textures_.back();
|
| - idle_frame_subscriber_textures_.pop_back();
|
| - } else if (GLHelper* helper =
|
| - ImageTransportFactory::GetInstance()->GetGLHelper()) {
|
| - subscriber_texture = new OwnedMailbox(helper);
|
| - }
|
| -
|
| - scoped_ptr<cc::CopyOutputRequest> request =
|
| - cc::CopyOutputRequest::CreateRequest(base::Bind(
|
| - &DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo,
|
| - AsWeakPtr(),
|
| - subscriber_texture,
|
| - frame,
|
| - base::Bind(callback, present_time)));
|
| - // Setting the source in this copy request asks that the layer abort any prior
|
| - // uncommitted copy requests made on behalf of the same frame subscriber.
|
| - // This will not affect any of the copy requests spawned elsewhere from
|
| - // DelegatedFrameHost (e.g., a call to CopyFromCompositingSurface() for
|
| - // screenshots) since those copy requests do not specify |frame_subscriber()|
|
| - // as a source.
|
| - request->set_source(frame_subscriber());
|
| - if (subscriber_texture.get()) {
|
| - request->SetTextureMailbox(cc::TextureMailbox(
|
| - subscriber_texture->mailbox(), subscriber_texture->sync_token(),
|
| - subscriber_texture->target()));
|
| - }
|
| -
|
| - if (surface_factory_.get()) {
|
| - // To avoid unnecessary composites, go directly to the Surface rather than
|
| - // through RequestCopyOfOutput (which goes through the browser
|
| - // compositor).
|
| - if (!request_copy_of_output_callback_for_testing_.is_null())
|
| - request_copy_of_output_callback_for_testing_.Run(std::move(request));
|
| - else
|
| - surface_factory_->RequestCopyOfSurface(surface_id_, std::move(request));
|
| - } else {
|
| - request->set_area(gfx::Rect(current_frame_size_in_dip_));
|
| - RequestCopyOfOutput(std::move(request));
|
| - }
|
| -}
|
| -
|
| -void DelegatedFrameHost::SwapDelegatedFrame(
|
| - uint32_t output_surface_id,
|
| - scoped_ptr<cc::CompositorFrame> frame) {
|
| - DCHECK(frame->delegated_frame_data.get());
|
| - cc::DelegatedFrameData* frame_data = frame->delegated_frame_data.get();
|
| - float frame_device_scale_factor = frame->metadata.device_scale_factor;
|
| -
|
| - DCHECK(!frame_data->render_pass_list.empty());
|
| -
|
| - cc::RenderPass* root_pass = frame_data->render_pass_list.back().get();
|
| -
|
| - gfx::Size frame_size = root_pass->output_rect.size();
|
| - gfx::Size frame_size_in_dip =
|
| - gfx::ConvertSizeToDIP(frame_device_scale_factor, frame_size);
|
| -
|
| - gfx::Rect damage_rect = root_pass->damage_rect;
|
| - damage_rect.Intersect(gfx::Rect(frame_size));
|
| - gfx::Rect damage_rect_in_dip =
|
| - gfx::ConvertRectToDIP(frame_device_scale_factor, damage_rect);
|
| -
|
| - if (ShouldSkipFrame(frame_size_in_dip)) {
|
| - cc::CompositorFrameAck ack;
|
| - cc::TransferableResource::ReturnResources(frame_data->resource_list,
|
| - &ack.resources);
|
| -
|
| - skipped_latency_info_list_.insert(skipped_latency_info_list_.end(),
|
| - frame->metadata.latency_info.begin(),
|
| - frame->metadata.latency_info.end());
|
| -
|
| - client_->DelegatedFrameHostSendCompositorSwapAck(output_surface_id, ack);
|
| - skipped_frames_ = true;
|
| - return;
|
| - }
|
| -
|
| - if (skipped_frames_) {
|
| - skipped_frames_ = false;
|
| - damage_rect = gfx::Rect(frame_size);
|
| - damage_rect_in_dip = gfx::Rect(frame_size_in_dip);
|
| -
|
| - // Give the same damage rect to the compositor.
|
| - cc::RenderPass* root_pass = frame_data->render_pass_list.back().get();
|
| - root_pass->damage_rect = damage_rect;
|
| - }
|
| -
|
| - if (output_surface_id != last_output_surface_id_) {
|
| - // Resource ids are scoped by the output surface.
|
| - // If the originating output surface doesn't match the last one, it
|
| - // indicates the renderer's output surface may have been recreated, in which
|
| - // case we should recreate the DelegatedRendererLayer, to avoid matching
|
| - // resources from the old one with resources from the new one which would
|
| - // have the same id. Changing the layer to showing painted content destroys
|
| - // the DelegatedRendererLayer.
|
| - EvictDelegatedFrame();
|
| -
|
| - surface_factory_.reset();
|
| - if (!surface_returned_resources_.empty())
|
| - SendReturnedDelegatedResources(last_output_surface_id_);
|
| -
|
| - last_output_surface_id_ = output_surface_id;
|
| - }
|
| - bool skip_frame = false;
|
| - pending_delegated_ack_count_++;
|
| -
|
| - background_color_ = frame->metadata.root_background_color;
|
| -
|
| - if (frame_size.IsEmpty()) {
|
| - DCHECK(frame_data->resource_list.empty());
|
| - EvictDelegatedFrame();
|
| - } else {
|
| - ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
|
| - cc::SurfaceManager* manager = factory->GetSurfaceManager();
|
| - if (!surface_factory_) {
|
| - surface_factory_ =
|
| - make_scoped_ptr(new cc::SurfaceFactory(manager, this));
|
| - }
|
| - if (surface_id_.is_null() || frame_size != current_surface_size_ ||
|
| - frame_size_in_dip != current_frame_size_in_dip_) {
|
| - if (!surface_id_.is_null())
|
| - surface_factory_->Destroy(surface_id_);
|
| - surface_id_ = id_allocator_->GenerateId();
|
| - surface_factory_->Create(surface_id_);
|
| - // manager must outlive compositors using it.
|
| - client_->DelegatedFrameHostGetLayer()->SetShowSurface(
|
| - surface_id_,
|
| - base::Bind(&SatisfyCallback, base::Unretained(manager)),
|
| - base::Bind(&RequireCallback, base::Unretained(manager)), frame_size,
|
| - frame_device_scale_factor, frame_size_in_dip);
|
| - current_surface_size_ = frame_size;
|
| - current_scale_factor_ = frame_device_scale_factor;
|
| - }
|
| -
|
| - frame->metadata.latency_info.insert(frame->metadata.latency_info.end(),
|
| - skipped_latency_info_list_.begin(),
|
| - skipped_latency_info_list_.end());
|
| - skipped_latency_info_list_.clear();
|
| -
|
| - gfx::Size desired_size = client_->DelegatedFrameHostDesiredSizeInDIP();
|
| - if (desired_size != frame_size_in_dip && !desired_size.IsEmpty())
|
| - skip_frame = true;
|
| -
|
| - cc::SurfaceFactory::DrawCallback ack_callback;
|
| - if (compositor_ && !skip_frame) {
|
| - ack_callback = base::Bind(&DelegatedFrameHost::SurfaceDrawn,
|
| - AsWeakPtr(), output_surface_id);
|
| - }
|
| - surface_factory_->SubmitCompositorFrame(surface_id_, std::move(frame),
|
| - ack_callback);
|
| - }
|
| - released_front_lock_ = NULL;
|
| - current_frame_size_in_dip_ = frame_size_in_dip;
|
| - CheckResizeLock();
|
| -
|
| - UpdateGutters();
|
| -
|
| - if (!damage_rect_in_dip.IsEmpty())
|
| - client_->DelegatedFrameHostGetLayer()->OnDelegatedFrameDamage(
|
| - damage_rect_in_dip);
|
| -
|
| - // Note that |compositor_| may be reset by SetShowSurface or
|
| - // SetShowDelegatedContent above.
|
| - if (!compositor_ || skip_frame) {
|
| - SendDelegatedFrameAck(output_surface_id);
|
| - } else {
|
| - can_lock_compositor_ = NO_PENDING_COMMIT;
|
| - }
|
| - if (!surface_id_.is_null())
|
| - delegated_frame_evictor_->SwappedFrame(
|
| - client_->DelegatedFrameHostIsVisible());
|
| - // Note: the frame may have been evicted immediately.
|
| -}
|
| -
|
| -void DelegatedFrameHost::ClearDelegatedFrame() {
|
| - if (!surface_id_.is_null())
|
| - EvictDelegatedFrame();
|
| -}
|
| -
|
| -void DelegatedFrameHost::SendDelegatedFrameAck(uint32_t output_surface_id) {
|
| - cc::CompositorFrameAck ack;
|
| - if (!surface_returned_resources_.empty())
|
| - ack.resources.swap(surface_returned_resources_);
|
| - client_->DelegatedFrameHostSendCompositorSwapAck(output_surface_id, ack);
|
| - DCHECK_GT(pending_delegated_ack_count_, 0);
|
| - pending_delegated_ack_count_--;
|
| -}
|
| -
|
| -void DelegatedFrameHost::SurfaceDrawn(uint32_t output_surface_id,
|
| - cc::SurfaceDrawStatus drawn) {
|
| - SendDelegatedFrameAck(output_surface_id);
|
| -}
|
| -
|
| -void DelegatedFrameHost::SendReturnedDelegatedResources(
|
| - uint32_t output_surface_id) {
|
| - cc::CompositorFrameAck ack;
|
| - DCHECK(!surface_returned_resources_.empty());
|
| - ack.resources.swap(surface_returned_resources_);
|
| -
|
| - client_->DelegatedFrameHostSendReclaimCompositorResources(output_surface_id,
|
| - ack);
|
| -}
|
| -
|
| -void DelegatedFrameHost::ReturnResources(
|
| - const cc::ReturnedResourceArray& resources) {
|
| - if (resources.empty())
|
| - return;
|
| - std::copy(resources.begin(),
|
| - resources.end(),
|
| - std::back_inserter(surface_returned_resources_));
|
| - if (!pending_delegated_ack_count_)
|
| - SendReturnedDelegatedResources(last_output_surface_id_);
|
| -}
|
| -
|
| -void DelegatedFrameHost::WillDrawSurface(cc::SurfaceId id,
|
| - const gfx::Rect& damage_rect) {
|
| - if (id != surface_id_)
|
| - return;
|
| - AttemptFrameSubscriberCapture(damage_rect);
|
| -}
|
| -
|
| -void DelegatedFrameHost::SetBeginFrameSource(
|
| - cc::BeginFrameSource* begin_frame_source) {
|
| - // TODO(enne): forward this to DelegatedFrameHostClient to observe and then to
|
| - // the renderer as an external begin frame source.
|
| -}
|
| -
|
| -void DelegatedFrameHost::EvictDelegatedFrame() {
|
| - client_->DelegatedFrameHostGetLayer()->SetShowSolidColorContent();
|
| - if (!surface_id_.is_null()) {
|
| - surface_factory_->Destroy(surface_id_);
|
| - surface_id_ = cc::SurfaceId();
|
| - }
|
| - delegated_frame_evictor_->DiscardedFrame();
|
| - UpdateGutters();
|
| -}
|
| -
|
| -// static
|
| -void DelegatedFrameHost::ReturnSubscriberTexture(
|
| - base::WeakPtr<DelegatedFrameHost> dfh,
|
| - scoped_refptr<OwnedMailbox> subscriber_texture,
|
| - const gpu::SyncToken& sync_token) {
|
| - if (!subscriber_texture.get())
|
| - return;
|
| - if (!dfh)
|
| - return;
|
| -
|
| - subscriber_texture->UpdateSyncToken(sync_token);
|
| -
|
| - if (dfh->frame_subscriber_ && subscriber_texture->texture_id())
|
| - dfh->idle_frame_subscriber_textures_.push_back(subscriber_texture);
|
| -}
|
| -
|
| -// static
|
| -void DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo(
|
| - base::WeakPtr<DelegatedFrameHost> dfh,
|
| - const base::Callback<void(bool)>& callback,
|
| - scoped_refptr<OwnedMailbox> subscriber_texture,
|
| - scoped_ptr<cc::SingleReleaseCallback> release_callback,
|
| - bool result) {
|
| - callback.Run(result);
|
| -
|
| - gpu::SyncToken sync_token;
|
| - if (result) {
|
| - GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
|
| - gl_helper->GenerateSyncToken(&sync_token);
|
| - }
|
| - if (release_callback) {
|
| - // A release callback means the texture came from the compositor, so there
|
| - // should be no |subscriber_texture|.
|
| - DCHECK(!subscriber_texture.get());
|
| - const bool lost_resource = !sync_token.HasData();
|
| - release_callback->Run(sync_token, lost_resource);
|
| - }
|
| - ReturnSubscriberTexture(dfh, subscriber_texture, sync_token);
|
| -}
|
| -
|
| -// static
|
| -void DelegatedFrameHost::CopyFromCompositingSurfaceHasResultForVideo(
|
| - base::WeakPtr<DelegatedFrameHost> dfh,
|
| - scoped_refptr<OwnedMailbox> subscriber_texture,
|
| - scoped_refptr<media::VideoFrame> video_frame,
|
| - const base::Callback<void(const gfx::Rect&, bool)>& callback,
|
| - scoped_ptr<cc::CopyOutputResult> result) {
|
| - base::ScopedClosureRunner scoped_callback_runner(
|
| - base::Bind(callback, gfx::Rect(), false));
|
| - base::ScopedClosureRunner scoped_return_subscriber_texture(
|
| - base::Bind(&ReturnSubscriberTexture, dfh, subscriber_texture,
|
| - gpu::SyncToken()));
|
| -
|
| - if (!dfh)
|
| - return;
|
| - if (result->IsEmpty())
|
| - return;
|
| - if (result->size().IsEmpty())
|
| - return;
|
| -
|
| - // Compute the dest size we want after the letterboxing resize. Make the
|
| - // coordinates and sizes even because we letterbox in YUV space
|
| - // (see CopyRGBToVideoFrame). They need to be even for the UV samples to
|
| - // line up correctly.
|
| - // The video frame's visible_rect() and the result's size() are both physical
|
| - // pixels.
|
| - gfx::Rect region_in_frame = media::ComputeLetterboxRegion(
|
| - video_frame->visible_rect(), result->size());
|
| - region_in_frame = gfx::Rect(region_in_frame.x() & ~1,
|
| - region_in_frame.y() & ~1,
|
| - region_in_frame.width() & ~1,
|
| - region_in_frame.height() & ~1);
|
| - if (region_in_frame.IsEmpty())
|
| - return;
|
| -
|
| - if (!result->HasTexture()) {
|
| - DCHECK(result->HasBitmap());
|
| - scoped_ptr<SkBitmap> bitmap = result->TakeBitmap();
|
| - // Scale the bitmap to the required size, if necessary.
|
| - SkBitmap scaled_bitmap;
|
| - if (result->size() != region_in_frame.size()) {
|
| - skia::ImageOperations::ResizeMethod method =
|
| - skia::ImageOperations::RESIZE_GOOD;
|
| - scaled_bitmap = skia::ImageOperations::Resize(*bitmap.get(), method,
|
| - region_in_frame.width(),
|
| - region_in_frame.height());
|
| - } else {
|
| - scaled_bitmap = *bitmap.get();
|
| - }
|
| -
|
| - {
|
| - SkAutoLockPixels scaled_bitmap_locker(scaled_bitmap);
|
| -
|
| - media::CopyRGBToVideoFrame(
|
| - reinterpret_cast<uint8_t*>(scaled_bitmap.getPixels()),
|
| - scaled_bitmap.rowBytes(), region_in_frame, video_frame.get());
|
| - }
|
| - ignore_result(scoped_callback_runner.Release());
|
| - callback.Run(region_in_frame, true);
|
| - return;
|
| - }
|
| -
|
| - ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
|
| - GLHelper* gl_helper = factory->GetGLHelper();
|
| - if (!gl_helper)
|
| - return;
|
| - if (subscriber_texture.get() && !subscriber_texture->texture_id())
|
| - return;
|
| -
|
| - cc::TextureMailbox texture_mailbox;
|
| - scoped_ptr<cc::SingleReleaseCallback> release_callback;
|
| - result->TakeTexture(&texture_mailbox, &release_callback);
|
| - DCHECK(texture_mailbox.IsTexture());
|
| -
|
| - gfx::Rect result_rect(result->size());
|
| -
|
| - content::ReadbackYUVInterface* yuv_readback_pipeline =
|
| - dfh->yuv_readback_pipeline_.get();
|
| - if (yuv_readback_pipeline == NULL ||
|
| - yuv_readback_pipeline->scaler()->SrcSize() != result_rect.size() ||
|
| - yuv_readback_pipeline->scaler()->SrcSubrect() != result_rect ||
|
| - yuv_readback_pipeline->scaler()->DstSize() != region_in_frame.size()) {
|
| - GLHelper::ScalerQuality quality = GLHelper::SCALER_QUALITY_FAST;
|
| - std::string quality_switch = switches::kTabCaptureDownscaleQuality;
|
| - // If we're scaling up, we can use the "best" quality.
|
| - if (result_rect.size().width() < region_in_frame.size().width() &&
|
| - result_rect.size().height() < region_in_frame.size().height())
|
| - quality_switch = switches::kTabCaptureUpscaleQuality;
|
| -
|
| - std::string switch_value =
|
| - base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
|
| - quality_switch);
|
| - if (switch_value == "fast")
|
| - quality = GLHelper::SCALER_QUALITY_FAST;
|
| - else if (switch_value == "good")
|
| - quality = GLHelper::SCALER_QUALITY_GOOD;
|
| - else if (switch_value == "best")
|
| - quality = GLHelper::SCALER_QUALITY_BEST;
|
| -
|
| - dfh->yuv_readback_pipeline_.reset(
|
| - gl_helper->CreateReadbackPipelineYUV(quality,
|
| - result_rect.size(),
|
| - result_rect,
|
| - region_in_frame.size(),
|
| - true,
|
| - true));
|
| - yuv_readback_pipeline = dfh->yuv_readback_pipeline_.get();
|
| - }
|
| -
|
| - ignore_result(scoped_callback_runner.Release());
|
| - ignore_result(scoped_return_subscriber_texture.Release());
|
| -
|
| - base::Callback<void(bool result)> finished_callback = base::Bind(
|
| - &DelegatedFrameHost::CopyFromCompositingSurfaceFinishedForVideo,
|
| - dfh->AsWeakPtr(), base::Bind(callback, region_in_frame),
|
| - subscriber_texture, base::Passed(&release_callback));
|
| - yuv_readback_pipeline->ReadbackYUV(texture_mailbox.mailbox(),
|
| - texture_mailbox.sync_token(),
|
| - video_frame.get(),
|
| - region_in_frame.origin(),
|
| - finished_callback);
|
| -}
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -// DelegatedFrameHost, ui::CompositorObserver implementation:
|
| -
|
| -void DelegatedFrameHost::OnCompositingDidCommit(
|
| - ui::Compositor* compositor) {
|
| - if (can_lock_compositor_ == NO_PENDING_COMMIT) {
|
| - can_lock_compositor_ = YES_CAN_LOCK;
|
| - if (resize_lock_.get() && resize_lock_->GrabDeferredLock())
|
| - can_lock_compositor_ = YES_DID_LOCK;
|
| - }
|
| - if (resize_lock_ &&
|
| - resize_lock_->expected_size() == current_frame_size_in_dip_) {
|
| - resize_lock_.reset();
|
| - client_->DelegatedFrameHostResizeLockWasReleased();
|
| - // We may have had a resize while we had the lock (e.g. if the lock expired,
|
| - // or if the UI still gave us some resizes), so make sure we grab a new lock
|
| - // if necessary.
|
| - MaybeCreateResizeLock();
|
| - }
|
| -}
|
| -
|
| -void DelegatedFrameHost::OnCompositingStarted(
|
| - ui::Compositor* compositor, base::TimeTicks start_time) {
|
| - last_draw_ended_ = start_time;
|
| -}
|
| -
|
| -void DelegatedFrameHost::OnCompositingEnded(
|
| - ui::Compositor* compositor) {
|
| -}
|
| -
|
| -void DelegatedFrameHost::OnCompositingAborted(ui::Compositor* compositor) {
|
| -}
|
| -
|
| -void DelegatedFrameHost::OnCompositingLockStateChanged(
|
| - ui::Compositor* compositor) {
|
| - // A compositor lock that is part of a resize lock timed out. We
|
| - // should display a renderer frame.
|
| - if (!compositor->IsLocked() && can_lock_compositor_ == YES_DID_LOCK) {
|
| - can_lock_compositor_ = NO_PENDING_RENDERER_FRAME;
|
| - }
|
| -}
|
| -
|
| -void DelegatedFrameHost::OnCompositingShuttingDown(ui::Compositor* compositor) {
|
| - DCHECK_EQ(compositor, compositor_);
|
| - ResetCompositor();
|
| - DCHECK(!compositor_);
|
| -}
|
| -
|
| -void DelegatedFrameHost::OnUpdateVSyncParameters(
|
| - base::TimeTicks timebase,
|
| - base::TimeDelta interval) {
|
| - SetVSyncParameters(timebase, interval);
|
| - if (client_->DelegatedFrameHostIsVisible())
|
| - client_->DelegatedFrameHostUpdateVSyncParameters(timebase, interval);
|
| -}
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -// DelegatedFrameHost, ImageTransportFactoryObserver implementation:
|
| -
|
| -void DelegatedFrameHost::OnLostResources() {
|
| - if (!surface_id_.is_null())
|
| - EvictDelegatedFrame();
|
| - idle_frame_subscriber_textures_.clear();
|
| - yuv_readback_pipeline_.reset();
|
| -
|
| - client_->DelegatedFrameHostOnLostCompositorResources();
|
| -}
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -// DelegatedFrameHost, private:
|
| -
|
| -DelegatedFrameHost::~DelegatedFrameHost() {
|
| - DCHECK(!compositor_);
|
| - ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
|
| - factory->RemoveObserver(this);
|
| -
|
| - if (!surface_id_.is_null())
|
| - surface_factory_->Destroy(surface_id_);
|
| - factory->GetSurfaceManager()->UnregisterSurfaceFactoryClient(
|
| - id_allocator_->id_namespace());
|
| -
|
| - DCHECK(!vsync_manager_.get());
|
| -}
|
| -
|
| -void DelegatedFrameHost::SetCompositor(ui::Compositor* compositor) {
|
| - DCHECK(!compositor_);
|
| - if (!compositor)
|
| - return;
|
| - compositor_ = compositor;
|
| - compositor_->AddObserver(this);
|
| - DCHECK(!vsync_manager_.get());
|
| - vsync_manager_ = compositor_->vsync_manager();
|
| - vsync_manager_->AddObserver(this);
|
| -
|
| - ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
|
| - uint32_t parent = compositor->surface_id_allocator()->id_namespace();
|
| - factory->GetSurfaceManager()->RegisterSurfaceNamespaceHierarchy(
|
| - parent, id_allocator_->id_namespace());
|
| -}
|
| -
|
| -void DelegatedFrameHost::ResetCompositor() {
|
| - if (!compositor_)
|
| - return;
|
| - if (resize_lock_) {
|
| - resize_lock_.reset();
|
| - client_->DelegatedFrameHostResizeLockWasReleased();
|
| - }
|
| - if (compositor_->HasObserver(this))
|
| - compositor_->RemoveObserver(this);
|
| - if (vsync_manager_.get()) {
|
| - vsync_manager_->RemoveObserver(this);
|
| - vsync_manager_ = NULL;
|
| - }
|
| -
|
| - ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
|
| - uint32_t parent = compositor_->surface_id_allocator()->id_namespace();
|
| - factory->GetSurfaceManager()->UnregisterSurfaceNamespaceHierarchy(
|
| - parent, id_allocator_->id_namespace());
|
| -
|
| - compositor_ = nullptr;
|
| -}
|
| -
|
| -void DelegatedFrameHost::SetVSyncParameters(const base::TimeTicks& timebase,
|
| - const base::TimeDelta& interval) {
|
| - vsync_timebase_ = timebase;
|
| - vsync_interval_ = interval;
|
| -}
|
| -
|
| -void DelegatedFrameHost::LockResources() {
|
| - DCHECK(!surface_id_.is_null());
|
| - delegated_frame_evictor_->LockFrame();
|
| -}
|
| -
|
| -void DelegatedFrameHost::RequestCopyOfOutput(
|
| - scoped_ptr<cc::CopyOutputRequest> request) {
|
| - if (!request_copy_of_output_callback_for_testing_.is_null()) {
|
| - request_copy_of_output_callback_for_testing_.Run(std::move(request));
|
| - } else {
|
| - client_->DelegatedFrameHostGetLayer()->RequestCopyOfOutput(
|
| - std::move(request));
|
| - }
|
| -}
|
| -
|
| -void DelegatedFrameHost::UnlockResources() {
|
| - DCHECK(!surface_id_.is_null());
|
| - delegated_frame_evictor_->UnlockFrame();
|
| -}
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -// DelegatedFrameHost, ui::LayerOwnerDelegate implementation:
|
| -
|
| -void DelegatedFrameHost::OnLayerRecreated(ui::Layer* old_layer,
|
| - ui::Layer* new_layer) {
|
| - // The new_layer is the one that will be used by our Window, so that's the one
|
| - // that should keep our frame. old_layer will be returned to the
|
| - // RecreateLayer caller, and should have a copy.
|
| - if (!surface_id_.is_null()) {
|
| - ImageTransportFactory* factory = ImageTransportFactory::GetInstance();
|
| - cc::SurfaceManager* manager = factory->GetSurfaceManager();
|
| - new_layer->SetShowSurface(
|
| - surface_id_, base::Bind(&SatisfyCallback, base::Unretained(manager)),
|
| - base::Bind(&RequireCallback, base::Unretained(manager)),
|
| - current_surface_size_, current_scale_factor_,
|
| - current_frame_size_in_dip_);
|
| - }
|
| -}
|
| -
|
| -} // namespace content
|
|
|