blob: 1d28f324497bc78f811a05d4e46036e2863a8043 [file] [log] [blame]
// Copyright (c) 2012 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/renderer/gpu/renderer_compositor_frame_sink.h"
#include <utility>
#include "base/command_line.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "cc/output/compositor_frame.h"
#include "cc/output/compositor_frame_sink_client.h"
#include "cc/output/managed_memory_policy.h"
#include "content/common/view_messages.h"
#include "content/public/common/content_switches.h"
#include "content/renderer/gpu/frame_swap_message_queue.h"
#include "content/renderer/render_thread_impl.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/ipc/client/command_buffer_proxy_impl.h"
#include "ipc/ipc_sync_channel.h"
#include "services/ui/public/cpp/gpu/context_provider_command_buffer.h"
namespace content {
RendererCompositorFrameSink::RendererCompositorFrameSink(
int32_t routing_id,
std::unique_ptr<cc::SyntheticBeginFrameSource> synthetic_begin_frame_source,
scoped_refptr<cc::ContextProvider> context_provider,
scoped_refptr<cc::ContextProvider> worker_context_provider,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
cc::SharedBitmapManager* shared_bitmap_manager,
scoped_refptr<FrameSwapMessageQueue> swap_frame_message_queue)
: CompositorFrameSink(std::move(context_provider),
std::move(worker_context_provider),
gpu_memory_buffer_manager,
shared_bitmap_manager),
compositor_frame_sink_filter_(
RenderThreadImpl::current()->compositor_message_filter()),
message_sender_(RenderThreadImpl::current()->sync_message_filter()),
frame_swap_message_queue_(swap_frame_message_queue),
synthetic_begin_frame_source_(std::move(synthetic_begin_frame_source)),
external_begin_frame_source_(
synthetic_begin_frame_source_
? nullptr
: base::MakeUnique<cc::ExternalBeginFrameSource>(this)),
routing_id_(routing_id),
sink_client_binding_(this) {
DCHECK(compositor_frame_sink_filter_);
DCHECK(frame_swap_message_queue_);
DCHECK(message_sender_);
thread_checker_.DetachFromThread();
EstablishMojoConnection();
}
RendererCompositorFrameSink::RendererCompositorFrameSink(
int32_t routing_id,
std::unique_ptr<cc::SyntheticBeginFrameSource> synthetic_begin_frame_source,
scoped_refptr<cc::VulkanContextProvider> vulkan_context_provider,
scoped_refptr<FrameSwapMessageQueue> swap_frame_message_queue)
: CompositorFrameSink(std::move(vulkan_context_provider)),
compositor_frame_sink_filter_(
RenderThreadImpl::current()->compositor_message_filter()),
message_sender_(RenderThreadImpl::current()->sync_message_filter()),
frame_swap_message_queue_(swap_frame_message_queue),
synthetic_begin_frame_source_(std::move(synthetic_begin_frame_source)),
external_begin_frame_source_(
synthetic_begin_frame_source_
? nullptr
: base::MakeUnique<cc::ExternalBeginFrameSource>(this)),
routing_id_(routing_id),
sink_client_binding_(this) {
DCHECK(compositor_frame_sink_filter_);
DCHECK(frame_swap_message_queue_);
DCHECK(message_sender_);
thread_checker_.DetachFromThread();
EstablishMojoConnection();
}
RendererCompositorFrameSink::~RendererCompositorFrameSink() {
// TODO(crbug.com/702764): If not detached then IPC messages would crash
// after this class is destroyed.
CHECK(!bound_);
}
bool RendererCompositorFrameSink::BindToClient(
cc::CompositorFrameSinkClient* client) {
DCHECK(thread_checker_.CalledOnValidThread());
if (!cc::CompositorFrameSink::BindToClient(client))
return false;
sink_.Bind(std::move(sink_ptr_info_));
sink_client_binding_.Bind(std::move(sink_client_request_));
if (synthetic_begin_frame_source_)
client_->SetBeginFrameSource(synthetic_begin_frame_source_.get());
else
client_->SetBeginFrameSource(external_begin_frame_source_.get());
compositor_frame_sink_proxy_ = new RendererCompositorFrameSinkProxy(this);
compositor_frame_sink_filter_handler_ =
base::Bind(&RendererCompositorFrameSinkProxy::OnMessageReceived,
compositor_frame_sink_proxy_);
compositor_frame_sink_filter_->AddHandlerOnCompositorThread(
routing_id_, compositor_frame_sink_filter_handler_);
bound_ = true;
return true;
}
void RendererCompositorFrameSink::DetachFromClient() {
DCHECK(thread_checker_.CalledOnValidThread());
client_->SetBeginFrameSource(nullptr);
// Destroy the begin frame source on the same thread it was bound on.
// The CompositorFrameSink itself is destroyed on the main thread.
external_begin_frame_source_ = nullptr;
synthetic_begin_frame_source_ = nullptr;
compositor_frame_sink_proxy_->ClearCompositorFrameSink();
compositor_frame_sink_filter_->RemoveHandlerOnCompositorThread(
routing_id_, compositor_frame_sink_filter_handler_);
sink_.reset();
sink_client_binding_.Close();
cc::CompositorFrameSink::DetachFromClient();
bound_ = false;
}
void RendererCompositorFrameSink::SubmitCompositorFrame(
cc::CompositorFrame frame) {
// We should only submit CompositorFrames with valid BeginFrameAcks.
DCHECK_LE(cc::BeginFrameArgs::kStartingFrameNumber,
frame.metadata.begin_frame_ack.sequence_number);
if (ShouldAllocateNewLocalSurfaceId(frame))
local_surface_id_ = id_allocator_.GenerateId();
UpdateFrameData(frame);
{
std::unique_ptr<FrameSwapMessageQueue::SendMessageScope>
send_message_scope =
frame_swap_message_queue_->AcquireSendMessageScope();
std::vector<std::unique_ptr<IPC::Message>> messages;
frame_swap_message_queue_->DrainMessages(&messages);
std::vector<IPC::Message> messages_to_send;
FrameSwapMessageQueue::TransferMessages(&messages, &messages_to_send);
uint32_t frame_token = 0;
if (!messages_to_send.empty())
frame_token = frame_swap_message_queue_->AllocateFrameToken();
frame.metadata.frame_token = frame_token;
sink_->SubmitCompositorFrame(local_surface_id_, std::move(frame));
if (frame_token) {
message_sender_->Send(new ViewHostMsg_FrameSwapMessages(
routing_id_, frame_token, messages_to_send));
}
// ~send_message_scope.
}
}
void RendererCompositorFrameSink::OnMessageReceived(
const IPC::Message& message) {
DCHECK(thread_checker_.CalledOnValidThread());
IPC_BEGIN_MESSAGE_MAP(RendererCompositorFrameSink, message)
IPC_MESSAGE_HANDLER(ViewMsg_BeginFrame, OnBeginFrameIPC)
IPC_END_MESSAGE_MAP()
}
void RendererCompositorFrameSink::OnBeginFrameIPC(
const cc::BeginFrameArgs& args) {
if (external_begin_frame_source_)
external_begin_frame_source_->OnBeginFrame(args);
}
bool RendererCompositorFrameSink::ShouldAllocateNewLocalSurfaceId(
const cc::CompositorFrame& frame) {
cc::RenderPass* root_pass = frame.render_pass_list.back().get();
gfx::Size frame_size = root_pass->output_rect.size();
// Once the proposal in crbug.com/689754 is implemented, the LocalSurfaceId
// allocation logic will be unified across all platforms.
return !local_surface_id_.is_valid() ||
current_frame_data_.device_scale_factor !=
frame.metadata.device_scale_factor ||
#ifdef OS_ANDROID
current_frame_data_.top_controls_height !=
frame.metadata.top_controls_height ||
current_frame_data_.top_controls_shown_ratio !=
frame.metadata.top_controls_shown_ratio ||
current_frame_data_.bottom_controls_height !=
frame.metadata.bottom_controls_height ||
current_frame_data_.bottom_controls_shown_ratio !=
frame.metadata.bottom_controls_shown_ratio ||
current_frame_data_.viewport_selection != frame.metadata.selection ||
current_frame_data_.has_transparent_background !=
root_pass->has_transparent_background ||
#endif
current_frame_data_.frame_size != frame_size;
}
void RendererCompositorFrameSink::UpdateFrameData(
const cc::CompositorFrame& frame) {
cc::RenderPass* root_pass = frame.render_pass_list.back().get();
gfx::Size frame_size = root_pass->output_rect.size();
current_frame_data_.frame_size = frame_size;
current_frame_data_.device_scale_factor = frame.metadata.device_scale_factor;
#ifdef OS_ANDROID
current_frame_data_.top_controls_height = frame.metadata.top_controls_height;
current_frame_data_.top_controls_shown_ratio =
frame.metadata.top_controls_shown_ratio;
current_frame_data_.bottom_controls_height =
frame.metadata.bottom_controls_height;
current_frame_data_.bottom_controls_shown_ratio =
frame.metadata.bottom_controls_shown_ratio;
current_frame_data_.viewport_selection = frame.metadata.selection;
current_frame_data_.has_transparent_background =
root_pass->has_transparent_background;
#endif
}
void RendererCompositorFrameSink::DidReceiveCompositorFrameAck(
const cc::ReturnedResourceArray& resources) {
ReclaimResources(resources);
client_->DidReceiveCompositorFrameAck();
}
void RendererCompositorFrameSink::OnBeginFrame(const cc::BeginFrameArgs& args) {
// See crbug.com/709689.
NOTREACHED() << "BeginFrames are delivered using Chrome IPC.";
}
void RendererCompositorFrameSink::ReclaimResources(
const cc::ReturnedResourceArray& resources) {
client_->ReclaimResources(resources);
}
void RendererCompositorFrameSink::OnNeedsBeginFrames(bool needs_begin_frames) {
sink_->SetNeedsBeginFrame(needs_begin_frames);
}
void RendererCompositorFrameSink::OnDidFinishFrame(
const cc::BeginFrameAck& ack) {
DCHECK_LE(cc::BeginFrameArgs::kStartingFrameNumber, ack.sequence_number);
// If there was damage, ViewHostMsg_SwapCompositorFrame includes the ack.
if (!ack.has_damage)
sink_->BeginFrameDidNotSwap(ack);
}
void RendererCompositorFrameSink::EstablishMojoConnection() {
cc::mojom::MojoCompositorFrameSinkPtr sink;
cc::mojom::MojoCompositorFrameSinkRequest sink_request =
mojo::MakeRequest(&sink);
cc::mojom::MojoCompositorFrameSinkClientPtr sink_client;
sink_client_request_ = mojo::MakeRequest(&sink_client);
RenderThreadImpl::current()->GetFrameSinkProvider()->CreateForWidget(
routing_id_, std::move(sink_request), std::move(sink_client));
sink_ptr_info_ = sink.PassInterface();
}
} // namespace content