1 // Copyright (c) 2012 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.
5 #include "content/renderer/gpu/compositor_output_surface.h"
7 #include "base/command_line.h"
8 #include "base/message_loop/message_loop_proxy.h"
9 #include "cc/output/compositor_frame.h"
10 #include "cc/output/compositor_frame_ack.h"
11 #include "cc/output/managed_memory_policy.h"
12 #include "cc/output/output_surface_client.h"
13 #include "content/common/gpu/client/command_buffer_proxy_impl.h"
14 #include "content/common/gpu/client/context_provider_command_buffer.h"
15 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
16 #include "content/common/view_messages.h"
17 #include "content/public/common/content_switches.h"
18 #include "content/renderer/render_thread_impl.h"
19 #include "gpu/command_buffer/client/context_support.h"
20 #include "gpu/command_buffer/client/gles2_interface.h"
21 #include "ipc/ipc_forwarding_message_filter.h"
22 #include "ipc/ipc_sync_channel.h"
25 // There are several compositor surfaces in a process, but they share the same
26 // compositor thread, so we use a simple int here to track prefer-smoothness.
27 int g_prefer_smoothness_count = 0;
32 //------------------------------------------------------------------------------
35 IPC::ForwardingMessageFilter* CompositorOutputSurface::CreateFilter(
36 base::TaskRunner* target_task_runner)
38 uint32 messages_to_filter[] = {
39 ViewMsg_UpdateVSyncParameters::ID,
40 ViewMsg_SwapCompositorFrameAck::ID,
41 ViewMsg_ReclaimCompositorResources::ID,
42 #if defined(OS_ANDROID)
43 ViewMsg_BeginFrame::ID
47 return new IPC::ForwardingMessageFilter(
48 messages_to_filter, arraysize(messages_to_filter),
52 CompositorOutputSurface::CompositorOutputSurface(
54 uint32 output_surface_id,
55 const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
56 scoped_ptr<cc::SoftwareOutputDevice> software_device,
57 bool use_swap_compositor_frame_message)
58 : OutputSurface(context_provider, software_device.Pass()),
59 output_surface_id_(output_surface_id),
60 use_swap_compositor_frame_message_(use_swap_compositor_frame_message),
61 output_surface_filter_(
62 RenderThreadImpl::current()->compositor_output_surface_filter()),
63 routing_id_(routing_id),
64 prefers_smoothness_(false),
66 // TODO(epenner): Implement PlatformThread::CurrentHandle() on windows.
67 main_thread_handle_(base::PlatformThreadHandle()),
69 main_thread_handle_(base::PlatformThread::CurrentHandle()),
71 layout_test_mode_(RenderThreadImpl::current()->layout_test_mode()),
73 DCHECK(output_surface_filter_.get());
75 message_sender_ = RenderThreadImpl::current()->sync_message_filter();
76 DCHECK(message_sender_.get());
77 if (OutputSurface::software_device())
78 capabilities_.max_frames_pending = 1;
81 CompositorOutputSurface::~CompositorOutputSurface() {
82 DCHECK(CalledOnValidThread());
83 SetNeedsBeginFrame(false);
86 UpdateSmoothnessTakesPriority(false);
87 if (output_surface_proxy_.get())
88 output_surface_proxy_->ClearOutputSurface();
89 output_surface_filter_->RemoveRoute(routing_id_);
92 bool CompositorOutputSurface::BindToClient(
93 cc::OutputSurfaceClient* client) {
94 DCHECK(CalledOnValidThread());
96 if (!cc::OutputSurface::BindToClient(client))
99 output_surface_proxy_ = new CompositorOutputSurfaceProxy(this);
100 output_surface_filter_->AddRoute(
102 base::Bind(&CompositorOutputSurfaceProxy::OnMessageReceived,
103 output_surface_proxy_));
105 if (!context_provider()) {
106 // Without a GPU context, the memory policy otherwise wouldn't be set.
107 client->SetMemoryPolicy(cc::ManagedMemoryPolicy(
109 gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE,
110 cc::ManagedMemoryPolicy::kDefaultNumResourcesLimit));
116 void CompositorOutputSurface::ShortcutSwapAck(
117 uint32 output_surface_id,
118 scoped_ptr<cc::GLFrameData> gl_frame_data,
119 scoped_ptr<cc::SoftwareFrameData> software_frame_data) {
120 if (!layout_test_previous_frame_ack_) {
121 layout_test_previous_frame_ack_.reset(new cc::CompositorFrameAck);
122 layout_test_previous_frame_ack_->gl_frame_data.reset(new cc::GLFrameData);
125 OnSwapAck(output_surface_id, *layout_test_previous_frame_ack_);
127 layout_test_previous_frame_ack_->gl_frame_data = gl_frame_data.Pass();
128 layout_test_previous_frame_ack_->last_software_frame_id =
129 software_frame_data ? software_frame_data->id : 0;
132 void CompositorOutputSurface::SwapBuffers(cc::CompositorFrame* frame) {
133 if (layout_test_mode_ && use_swap_compositor_frame_message_) {
134 // This code path is here to support layout tests that are currently
135 // doing a readback in the renderer instead of the browser. So they
136 // are using deprecated code paths in the renderer and don't need to
137 // actually swap anything to the browser. We shortcut the swap to the
138 // browser here and just ack directly within the renderer process.
139 // Once crbug.com/311404 is fixed, this can be removed.
141 // This would indicate that crbug.com/311404 is being fixed, and this
142 // block needs to be removed.
143 DCHECK(!frame->delegated_frame_data);
145 base::Closure closure =
146 base::Bind(&CompositorOutputSurface::ShortcutSwapAck,
147 weak_ptrs_.GetWeakPtr(),
149 base::Passed(&frame->gl_frame_data),
150 base::Passed(&frame->software_frame_data));
152 if (context_provider_) {
153 gpu::gles2::GLES2Interface* context = context_provider_->ContextGL();
155 uint32 sync_point = context->InsertSyncPointCHROMIUM();
156 context_provider_->ContextSupport()->SignalSyncPoint(sync_point, closure);
158 base::MessageLoopProxy::current()->PostTask(FROM_HERE, closure);
160 client_->DidSwapBuffers();
164 if (use_swap_compositor_frame_message_) {
165 Send(new ViewHostMsg_SwapCompositorFrame(routing_id_,
168 client_->DidSwapBuffers();
172 if (frame->gl_frame_data) {
173 context_provider_->ContextGL()->ShallowFlushCHROMIUM();
174 ContextProviderCommandBuffer* provider_command_buffer =
175 static_cast<ContextProviderCommandBuffer*>(context_provider_.get());
176 CommandBufferProxyImpl* command_buffer_proxy =
177 provider_command_buffer->GetCommandBufferProxy();
178 DCHECK(command_buffer_proxy);
179 command_buffer_proxy->SetLatencyInfo(frame->metadata.latency_info);
182 OutputSurface::SwapBuffers(frame);
185 void CompositorOutputSurface::OnMessageReceived(const IPC::Message& message) {
186 DCHECK(CalledOnValidThread());
189 IPC_BEGIN_MESSAGE_MAP(CompositorOutputSurface, message)
190 IPC_MESSAGE_HANDLER(ViewMsg_UpdateVSyncParameters,
191 OnUpdateVSyncParametersFromBrowser);
192 IPC_MESSAGE_HANDLER(ViewMsg_SwapCompositorFrameAck, OnSwapAck);
193 IPC_MESSAGE_HANDLER(ViewMsg_ReclaimCompositorResources, OnReclaimResources);
194 #if defined(OS_ANDROID)
195 IPC_MESSAGE_HANDLER(ViewMsg_BeginFrame, OnBeginFrame);
197 IPC_END_MESSAGE_MAP()
200 void CompositorOutputSurface::OnUpdateVSyncParametersFromBrowser(
201 base::TimeTicks timebase,
202 base::TimeDelta interval) {
203 DCHECK(CalledOnValidThread());
204 CommitVSyncParameters(timebase, interval);
207 #if defined(OS_ANDROID)
208 void CompositorOutputSurface::SetNeedsBeginFrame(bool enable) {
209 DCHECK(CalledOnValidThread());
210 Send(new ViewHostMsg_SetNeedsBeginFrame(routing_id_, enable));
213 void CompositorOutputSurface::OnBeginFrame(const cc::BeginFrameArgs& args) {
214 DCHECK(CalledOnValidThread());
215 client_->BeginFrame(args);
217 #endif // defined(OS_ANDROID)
219 void CompositorOutputSurface::OnSwapAck(uint32 output_surface_id,
220 const cc::CompositorFrameAck& ack) {
221 // Ignore message if it's a stale one coming from a different output surface
222 // (e.g. after a lost context).
223 if (output_surface_id != output_surface_id_)
225 ReclaimResources(&ack);
226 client_->DidSwapBuffersComplete();
229 void CompositorOutputSurface::OnReclaimResources(
230 uint32 output_surface_id,
231 const cc::CompositorFrameAck& ack) {
232 // Ignore message if it's a stale one coming from a different output surface
233 // (e.g. after a lost context).
234 if (output_surface_id != output_surface_id_)
236 ReclaimResources(&ack);
239 bool CompositorOutputSurface::Send(IPC::Message* message) {
240 return message_sender_->Send(message);
244 #if defined(OS_ANDROID)
245 void SetThreadPriorityToIdle(base::PlatformThreadHandle handle) {
246 base::PlatformThread::SetThreadPriority(
247 handle, base::kThreadPriority_Background);
249 void SetThreadPriorityToDefault(base::PlatformThreadHandle handle) {
250 base::PlatformThread::SetThreadPriority(
251 handle, base::kThreadPriority_Normal);
254 void SetThreadPriorityToIdle(base::PlatformThreadHandle handle) {}
255 void SetThreadPriorityToDefault(base::PlatformThreadHandle handle) {}
259 void CompositorOutputSurface::UpdateSmoothnessTakesPriority(
260 bool prefers_smoothness) {
262 // If we use different compositor threads, we need to
263 // use an atomic int to track prefer smoothness count.
264 base::PlatformThreadId g_last_thread = base::PlatformThread::CurrentId();
265 DCHECK_EQ(g_last_thread, base::PlatformThread::CurrentId());
267 if (prefers_smoothness_ == prefers_smoothness)
269 // If this is the first surface to start preferring smoothness,
270 // Throttle the main thread's priority.
271 if (prefers_smoothness_ == false &&
272 ++g_prefer_smoothness_count == 1) {
273 SetThreadPriorityToIdle(main_thread_handle_);
275 // If this is the last surface to stop preferring smoothness,
276 // Reset the main thread's priority to the default.
277 if (prefers_smoothness_ == true &&
278 --g_prefer_smoothness_count == 0) {
279 SetThreadPriorityToDefault(main_thread_handle_);
281 prefers_smoothness_ = prefers_smoothness;
284 } // namespace content