| // 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/gpu/client/context_provider_command_buffer.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" |
| |
| namespace content { |
| |
| RendererCompositorFrameSink::RendererCompositorFrameSink( |
| int32_t routing_id, |
| uint32_t compositor_frame_sink_id, |
| std::unique_ptr<cc::BeginFrameSource> begin_frame_source, |
| scoped_refptr<cc::ContextProvider> context_provider, |
| scoped_refptr<cc::ContextProvider> worker_context_provider, |
| scoped_refptr<FrameSwapMessageQueue> swap_frame_message_queue) |
| : CompositorFrameSink(std::move(context_provider), |
| std::move(worker_context_provider)), |
| compositor_frame_sink_id_(compositor_frame_sink_id), |
| compositor_frame_sink_filter_( |
| RenderThreadImpl::current()->compositor_message_filter()), |
| message_sender_(RenderThreadImpl::current()->sync_message_filter()), |
| frame_swap_message_queue_(swap_frame_message_queue), |
| begin_frame_source_(std::move(begin_frame_source)), |
| routing_id_(routing_id) { |
| DCHECK(compositor_frame_sink_filter_); |
| DCHECK(frame_swap_message_queue_); |
| DCHECK(message_sender_); |
| DCHECK(begin_frame_source_); |
| } |
| |
| RendererCompositorFrameSink::RendererCompositorFrameSink( |
| int32_t routing_id, |
| uint32_t compositor_frame_sink_id, |
| std::unique_ptr<cc::BeginFrameSource> 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_id_(compositor_frame_sink_id), |
| compositor_frame_sink_filter_( |
| RenderThreadImpl::current()->compositor_message_filter()), |
| message_sender_(RenderThreadImpl::current()->sync_message_filter()), |
| frame_swap_message_queue_(swap_frame_message_queue), |
| begin_frame_source_(std::move(begin_frame_source)), |
| routing_id_(routing_id) { |
| DCHECK(compositor_frame_sink_filter_); |
| DCHECK(frame_swap_message_queue_); |
| DCHECK(message_sender_); |
| DCHECK(begin_frame_source_); |
| } |
| |
| RendererCompositorFrameSink::~RendererCompositorFrameSink() = default; |
| |
| bool RendererCompositorFrameSink::BindToClient( |
| cc::CompositorFrameSinkClient* client) { |
| if (!cc::CompositorFrameSink::BindToClient(client)) |
| return false; |
| |
| DCHECK(begin_frame_source_); |
| client_->SetBeginFrameSource(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_); |
| return true; |
| } |
| |
| void RendererCompositorFrameSink::DetachFromClient() { |
| if (!HasClient()) |
| return; |
| 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. |
| begin_frame_source_ = nullptr; |
| |
| if (compositor_frame_sink_proxy_) { |
| compositor_frame_sink_proxy_->ClearCompositorFrameSink(); |
| compositor_frame_sink_filter_->RemoveHandlerOnCompositorThread( |
| routing_id_, compositor_frame_sink_filter_handler_); |
| } |
| cc::CompositorFrameSink::DetachFromClient(); |
| } |
| |
| void RendererCompositorFrameSink::SwapBuffers(cc::CompositorFrame frame) { |
| { |
| std::unique_ptr<FrameSwapMessageQueue::SendMessageScope> |
| send_message_scope = |
| frame_swap_message_queue_->AcquireSendMessageScope(); |
| std::vector<std::unique_ptr<IPC::Message>> messages; |
| std::vector<IPC::Message> messages_to_deliver_with_frame; |
| frame_swap_message_queue_->DrainMessages(&messages); |
| FrameSwapMessageQueue::TransferMessages(&messages, |
| &messages_to_deliver_with_frame); |
| Send(new ViewHostMsg_SwapCompositorFrame(routing_id_, |
| compositor_frame_sink_id_, frame, |
| messages_to_deliver_with_frame)); |
| // ~send_message_scope. |
| } |
| } |
| |
| void RendererCompositorFrameSink::OnMessageReceived( |
| const IPC::Message& message) { |
| DCHECK(client_thread_checker_.CalledOnValidThread()); |
| if (!HasClient()) |
| return; |
| IPC_BEGIN_MESSAGE_MAP(RendererCompositorFrameSink, message) |
| IPC_MESSAGE_HANDLER(ViewMsg_ReclaimCompositorResources, |
| OnReclaimCompositorResources); |
| IPC_END_MESSAGE_MAP() |
| } |
| |
| void RendererCompositorFrameSink::OnReclaimCompositorResources( |
| uint32_t compositor_frame_sink_id, |
| bool is_swap_ack, |
| const cc::ReturnedResourceArray& resources) { |
| // Ignore message if it's a stale one coming from a different output surface |
| // (e.g. after a lost context). |
| if (compositor_frame_sink_id != compositor_frame_sink_id_) |
| return; |
| client_->ReclaimResources(resources); |
| if (is_swap_ack) |
| client_->DidSwapBuffersComplete(); |
| } |
| |
| bool RendererCompositorFrameSink::Send(IPC::Message* message) { |
| return message_sender_->Send(message); |
| } |
| |
| } // namespace content |