Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / content / renderer / gpu / compositor_output_surface.cc
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.
4
5 #include "content/renderer/gpu/compositor_output_surface.h"
6
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/gles2_interface.h"
20 #include "ipc/ipc_forwarding_message_filter.h"
21 #include "ipc/ipc_sync_channel.h"
22
23 namespace {
24 // There are several compositor surfaces in a process, but they share the same
25 // compositor thread, so we use a simple int here to track prefer-smoothness.
26 int g_prefer_smoothness_count = 0;
27 } // namespace
28
29 namespace content {
30
31 //------------------------------------------------------------------------------
32
33 // static
34 IPC::ForwardingMessageFilter* CompositorOutputSurface::CreateFilter(
35     base::TaskRunner* target_task_runner)
36 {
37   uint32 messages_to_filter[] = {
38     ViewMsg_UpdateVSyncParameters::ID,
39     ViewMsg_SwapCompositorFrameAck::ID,
40     ViewMsg_ReclaimCompositorResources::ID,
41 #if defined(OS_ANDROID)
42     ViewMsg_BeginFrame::ID
43 #endif
44   };
45
46   return new IPC::ForwardingMessageFilter(
47       messages_to_filter, arraysize(messages_to_filter),
48       target_task_runner);
49 }
50
51 CompositorOutputSurface::CompositorOutputSurface(
52     int32 routing_id,
53     uint32 output_surface_id,
54     const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
55     scoped_ptr<cc::SoftwareOutputDevice> software_device,
56     bool use_swap_compositor_frame_message)
57     : OutputSurface(context_provider, software_device.Pass()),
58       output_surface_id_(output_surface_id),
59       use_swap_compositor_frame_message_(use_swap_compositor_frame_message),
60       output_surface_filter_(
61           RenderThreadImpl::current()->compositor_output_surface_filter()),
62       routing_id_(routing_id),
63       prefers_smoothness_(false),
64 #if defined(OS_WIN)
65       // TODO(epenner): Implement PlatformThread::CurrentHandle() on windows.
66       main_thread_handle_(base::PlatformThreadHandle())
67 #else
68       main_thread_handle_(base::PlatformThread::CurrentHandle())
69 #endif
70 {
71   DCHECK(output_surface_filter_.get());
72   DetachFromThread();
73   message_sender_ = RenderThreadImpl::current()->sync_message_filter();
74   DCHECK(message_sender_.get());
75   if (OutputSurface::software_device())
76     capabilities_.max_frames_pending = 1;
77 }
78
79 CompositorOutputSurface::~CompositorOutputSurface() {
80   DCHECK(CalledOnValidThread());
81   SetNeedsBeginImplFrame(false);
82   if (!HasClient())
83     return;
84   UpdateSmoothnessTakesPriority(false);
85   if (output_surface_proxy_.get())
86     output_surface_proxy_->ClearOutputSurface();
87   output_surface_filter_->RemoveRoute(routing_id_);
88 }
89
90 bool CompositorOutputSurface::BindToClient(
91     cc::OutputSurfaceClient* client) {
92   DCHECK(CalledOnValidThread());
93
94   if (!cc::OutputSurface::BindToClient(client))
95     return false;
96
97   output_surface_proxy_ = new CompositorOutputSurfaceProxy(this);
98   output_surface_filter_->AddRoute(
99       routing_id_,
100       base::Bind(&CompositorOutputSurfaceProxy::OnMessageReceived,
101                  output_surface_proxy_));
102
103   if (!context_provider()) {
104     // Without a GPU context, the memory policy otherwise wouldn't be set.
105     client->SetMemoryPolicy(cc::ManagedMemoryPolicy(
106         64 * 1024 * 1024,
107         gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE,
108         cc::ManagedMemoryPolicy::kDefaultNumResourcesLimit));
109   }
110
111   return true;
112 }
113
114 void CompositorOutputSurface::SwapBuffers(cc::CompositorFrame* frame) {
115   if (use_swap_compositor_frame_message_) {
116     Send(new ViewHostMsg_SwapCompositorFrame(routing_id_,
117                                              output_surface_id_,
118                                              *frame));
119     DidSwapBuffers();
120     return;
121   }
122
123   if (frame->gl_frame_data) {
124     context_provider_->ContextGL()->ShallowFlushCHROMIUM();
125     ContextProviderCommandBuffer* provider_command_buffer =
126         static_cast<ContextProviderCommandBuffer*>(context_provider_.get());
127     CommandBufferProxyImpl* command_buffer_proxy =
128         provider_command_buffer->GetCommandBufferProxy();
129     DCHECK(command_buffer_proxy);
130     command_buffer_proxy->SetLatencyInfo(frame->metadata.latency_info);
131   }
132
133   OutputSurface::SwapBuffers(frame);
134 }
135
136 void CompositorOutputSurface::OnMessageReceived(const IPC::Message& message) {
137   DCHECK(CalledOnValidThread());
138   if (!HasClient())
139     return;
140   IPC_BEGIN_MESSAGE_MAP(CompositorOutputSurface, message)
141     IPC_MESSAGE_HANDLER(ViewMsg_UpdateVSyncParameters,
142                         OnUpdateVSyncParametersFromBrowser);
143     IPC_MESSAGE_HANDLER(ViewMsg_SwapCompositorFrameAck, OnSwapAck);
144     IPC_MESSAGE_HANDLER(ViewMsg_ReclaimCompositorResources, OnReclaimResources);
145 #if defined(OS_ANDROID)
146     IPC_MESSAGE_HANDLER(ViewMsg_BeginFrame, OnBeginImplFrame);
147 #endif
148   IPC_END_MESSAGE_MAP()
149 }
150
151 void CompositorOutputSurface::OnUpdateVSyncParametersFromBrowser(
152     base::TimeTicks timebase,
153     base::TimeDelta interval) {
154   DCHECK(CalledOnValidThread());
155   CommitVSyncParameters(timebase, interval);
156 }
157
158 #if defined(OS_ANDROID)
159 void CompositorOutputSurface::SetNeedsBeginImplFrame(bool enable) {
160   DCHECK(CalledOnValidThread());
161   if (needs_begin_impl_frame_ != enable)
162     Send(new ViewHostMsg_SetNeedsBeginFrame(routing_id_, enable));
163   OutputSurface::SetNeedsBeginImplFrame(enable);
164 }
165
166 void CompositorOutputSurface::OnBeginImplFrame(const cc::BeginFrameArgs& args) {
167   DCHECK(CalledOnValidThread());
168   BeginImplFrame(args);
169 }
170 #endif  // defined(OS_ANDROID)
171
172 void CompositorOutputSurface::OnSwapAck(uint32 output_surface_id,
173                                         const cc::CompositorFrameAck& ack) {
174   // Ignore message if it's a stale one coming from a different output surface
175   // (e.g. after a lost context).
176   if (output_surface_id != output_surface_id_)
177     return;
178   ReclaimResources(&ack);
179   OnSwapBuffersComplete();
180 }
181
182 void CompositorOutputSurface::OnReclaimResources(
183     uint32 output_surface_id,
184     const cc::CompositorFrameAck& ack) {
185   // Ignore message if it's a stale one coming from a different output surface
186   // (e.g. after a lost context).
187   if (output_surface_id != output_surface_id_)
188     return;
189   ReclaimResources(&ack);
190 }
191
192 bool CompositorOutputSurface::Send(IPC::Message* message) {
193   return message_sender_->Send(message);
194 }
195
196 namespace {
197 #if defined(OS_ANDROID)
198   void SetThreadPriorityToIdle(base::PlatformThreadHandle handle) {
199     base::PlatformThread::SetThreadPriority(
200        handle, base::kThreadPriority_Background);
201   }
202   void SetThreadPriorityToDefault(base::PlatformThreadHandle handle) {
203     base::PlatformThread::SetThreadPriority(
204        handle, base::kThreadPriority_Normal);
205   }
206 #else
207   void SetThreadPriorityToIdle(base::PlatformThreadHandle handle) {}
208   void SetThreadPriorityToDefault(base::PlatformThreadHandle handle) {}
209 #endif
210 }
211
212 void CompositorOutputSurface::UpdateSmoothnessTakesPriority(
213     bool prefers_smoothness) {
214 #ifndef NDEBUG
215   // If we use different compositor threads, we need to
216   // use an atomic int to track prefer smoothness count.
217   base::PlatformThreadId g_last_thread = base::PlatformThread::CurrentId();
218   DCHECK_EQ(g_last_thread, base::PlatformThread::CurrentId());
219 #endif
220   if (prefers_smoothness_ == prefers_smoothness)
221     return;
222   // If this is the first surface to start preferring smoothness,
223   // Throttle the main thread's priority.
224   if (prefers_smoothness_ == false &&
225       ++g_prefer_smoothness_count == 1) {
226     SetThreadPriorityToIdle(main_thread_handle_);
227   }
228   // If this is the last surface to stop preferring smoothness,
229   // Reset the main thread's priority to the default.
230   if (prefers_smoothness_ == true &&
231       --g_prefer_smoothness_count == 0) {
232     SetThreadPriorityToDefault(main_thread_handle_);
233   }
234   prefers_smoothness_ = prefers_smoothness;
235 }
236
237 }  // namespace content