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/common/gpu/image_transport_surface.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/command_line.h"
10 #include "base/debug/trace_event.h"
11 #include "content/common/gpu/gpu_channel.h"
12 #include "content/common/gpu/gpu_channel_manager.h"
13 #include "content/common/gpu/gpu_command_buffer_stub.h"
14 #include "content/common/gpu/gpu_messages.h"
15 #include "content/common/gpu/sync_point_manager.h"
16 #include "content/common/gpu/texture_image_transport_surface.h"
17 #include "gpu/command_buffer/service/gpu_scheduler.h"
18 #include "ui/gfx/vsync_provider.h"
19 #include "ui/gl/gl_implementation.h"
20 #include "ui/gl/gl_switches.h"
21
22 namespace content {
23
ImageTransportSurface()24 ImageTransportSurface::ImageTransportSurface() {}
25
~ImageTransportSurface()26 ImageTransportSurface::~ImageTransportSurface() {}
27
CreateSurface(GpuChannelManager * manager,GpuCommandBufferStub * stub,const gfx::GLSurfaceHandle & handle)28 scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateSurface(
29 GpuChannelManager* manager,
30 GpuCommandBufferStub* stub,
31 const gfx::GLSurfaceHandle& handle) {
32 scoped_refptr<gfx::GLSurface> surface;
33 if (handle.transport_type == gfx::TEXTURE_TRANSPORT)
34 surface = new TextureImageTransportSurface(manager, stub, handle);
35 else
36 surface = CreateNativeSurface(manager, stub, handle);
37
38 if (!surface.get() || !surface->Initialize())
39 return NULL;
40 return surface;
41 }
42
ImageTransportHelper(ImageTransportSurface * surface,GpuChannelManager * manager,GpuCommandBufferStub * stub,gfx::PluginWindowHandle handle)43 ImageTransportHelper::ImageTransportHelper(ImageTransportSurface* surface,
44 GpuChannelManager* manager,
45 GpuCommandBufferStub* stub,
46 gfx::PluginWindowHandle handle)
47 : surface_(surface),
48 manager_(manager),
49 stub_(stub->AsWeakPtr()),
50 handle_(handle) {
51 route_id_ = manager_->GenerateRouteID();
52 manager_->AddRoute(route_id_, this);
53 }
54
~ImageTransportHelper()55 ImageTransportHelper::~ImageTransportHelper() {
56 if (stub_.get()) {
57 stub_->SetLatencyInfoCallback(
58 base::Callback<void(const ui::LatencyInfo&)>());
59 }
60 manager_->RemoveRoute(route_id_);
61 }
62
Initialize()63 bool ImageTransportHelper::Initialize() {
64 gpu::gles2::GLES2Decoder* decoder = Decoder();
65
66 if (!decoder)
67 return false;
68
69 decoder->SetResizeCallback(
70 base::Bind(&ImageTransportHelper::Resize, base::Unretained(this)));
71
72 stub_->SetLatencyInfoCallback(
73 base::Bind(&ImageTransportHelper::SetLatencyInfo,
74 base::Unretained(this)));
75
76 manager_->Send(new GpuHostMsg_AcceleratedSurfaceInitialized(
77 stub_->surface_id(), route_id_));
78
79 return true;
80 }
81
Destroy()82 void ImageTransportHelper::Destroy() {}
83
OnMessageReceived(const IPC::Message & message)84 bool ImageTransportHelper::OnMessageReceived(const IPC::Message& message) {
85 bool handled = true;
86 IPC_BEGIN_MESSAGE_MAP(ImageTransportHelper, message)
87 IPC_MESSAGE_HANDLER(AcceleratedSurfaceMsg_BufferPresented,
88 OnBufferPresented)
89 IPC_MESSAGE_HANDLER(AcceleratedSurfaceMsg_ResizeViewACK, OnResizeViewACK);
90 IPC_MESSAGE_HANDLER(AcceleratedSurfaceMsg_WakeUpGpu, OnWakeUpGpu);
91 IPC_MESSAGE_UNHANDLED(handled = false)
92 IPC_END_MESSAGE_MAP()
93 return handled;
94 }
95
SendAcceleratedSurfaceBuffersSwapped(GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params)96 void ImageTransportHelper::SendAcceleratedSurfaceBuffersSwapped(
97 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params) {
98 // TRACE_EVENT for gpu tests:
99 TRACE_EVENT_INSTANT2("test_gpu", "SwapBuffers",
100 TRACE_EVENT_SCOPE_THREAD,
101 "GLImpl", static_cast<int>(gfx::GetGLImplementation()),
102 "width", params.size.width());
103 params.surface_id = stub_->surface_id();
104 params.route_id = route_id_;
105 manager_->Send(new GpuHostMsg_AcceleratedSurfaceBuffersSwapped(params));
106 }
107
SendAcceleratedSurfacePostSubBuffer(GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params params)108 void ImageTransportHelper::SendAcceleratedSurfacePostSubBuffer(
109 GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params params) {
110 params.surface_id = stub_->surface_id();
111 params.route_id = route_id_;
112 manager_->Send(new GpuHostMsg_AcceleratedSurfacePostSubBuffer(params));
113 }
114
SendAcceleratedSurfaceRelease()115 void ImageTransportHelper::SendAcceleratedSurfaceRelease() {
116 GpuHostMsg_AcceleratedSurfaceRelease_Params params;
117 params.surface_id = stub_->surface_id();
118 manager_->Send(new GpuHostMsg_AcceleratedSurfaceRelease(params));
119 }
120
SendResizeView(const gfx::Size & size)121 void ImageTransportHelper::SendResizeView(const gfx::Size& size) {
122 manager_->Send(new GpuHostMsg_ResizeView(stub_->surface_id(),
123 route_id_,
124 size));
125 }
126
SendUpdateVSyncParameters(base::TimeTicks timebase,base::TimeDelta interval)127 void ImageTransportHelper::SendUpdateVSyncParameters(
128 base::TimeTicks timebase, base::TimeDelta interval) {
129 manager_->Send(new GpuHostMsg_UpdateVSyncParameters(stub_->surface_id(),
130 timebase,
131 interval));
132 }
133
SendLatencyInfo(const ui::LatencyInfo & latency_info)134 void ImageTransportHelper::SendLatencyInfo(
135 const ui::LatencyInfo& latency_info) {
136 manager_->Send(new GpuHostMsg_FrameDrawn(latency_info));
137 }
138
SetScheduled(bool is_scheduled)139 void ImageTransportHelper::SetScheduled(bool is_scheduled) {
140 gpu::GpuScheduler* scheduler = Scheduler();
141 if (!scheduler)
142 return;
143
144 scheduler->SetScheduled(is_scheduled);
145 }
146
DeferToFence(base::Closure task)147 void ImageTransportHelper::DeferToFence(base::Closure task) {
148 gpu::GpuScheduler* scheduler = Scheduler();
149 DCHECK(scheduler);
150
151 scheduler->DeferToFence(task);
152 }
153
SetPreemptByFlag(scoped_refptr<gpu::PreemptionFlag> preemption_flag)154 void ImageTransportHelper::SetPreemptByFlag(
155 scoped_refptr<gpu::PreemptionFlag> preemption_flag) {
156 stub_->channel()->SetPreemptByFlag(preemption_flag);
157 }
158
MakeCurrent()159 bool ImageTransportHelper::MakeCurrent() {
160 gpu::gles2::GLES2Decoder* decoder = Decoder();
161 if (!decoder)
162 return false;
163 return decoder->MakeCurrent();
164 }
165
SetSwapInterval(gfx::GLContext * context)166 void ImageTransportHelper::SetSwapInterval(gfx::GLContext* context) {
167 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync))
168 context->SetSwapInterval(0);
169 else
170 context->SetSwapInterval(1);
171 }
172
Suspend()173 void ImageTransportHelper::Suspend() {
174 manager_->Send(new GpuHostMsg_AcceleratedSurfaceSuspend(stub_->surface_id()));
175 }
176
Scheduler()177 gpu::GpuScheduler* ImageTransportHelper::Scheduler() {
178 if (!stub_.get())
179 return NULL;
180 return stub_->scheduler();
181 }
182
Decoder()183 gpu::gles2::GLES2Decoder* ImageTransportHelper::Decoder() {
184 if (!stub_.get())
185 return NULL;
186 return stub_->decoder();
187 }
188
OnBufferPresented(const AcceleratedSurfaceMsg_BufferPresented_Params & params)189 void ImageTransportHelper::OnBufferPresented(
190 const AcceleratedSurfaceMsg_BufferPresented_Params& params) {
191 surface_->OnBufferPresented(params);
192 }
193
OnResizeViewACK()194 void ImageTransportHelper::OnResizeViewACK() {
195 surface_->OnResizeViewACK();
196 }
197
OnWakeUpGpu()198 void ImageTransportHelper::OnWakeUpGpu() {
199 surface_->WakeUpGpu();
200 }
201
Resize(gfx::Size size,float scale_factor)202 void ImageTransportHelper::Resize(gfx::Size size, float scale_factor) {
203 surface_->OnResize(size, scale_factor);
204
205 #if defined(OS_ANDROID)
206 manager_->gpu_memory_manager()->ScheduleManage(
207 GpuMemoryManager::kScheduleManageNow);
208 #endif
209 }
210
SetLatencyInfo(const ui::LatencyInfo & latency_info)211 void ImageTransportHelper::SetLatencyInfo(
212 const ui::LatencyInfo& latency_info) {
213 surface_->SetLatencyInfo(latency_info);
214 }
215
PassThroughImageTransportSurface(GpuChannelManager * manager,GpuCommandBufferStub * stub,gfx::GLSurface * surface,bool transport)216 PassThroughImageTransportSurface::PassThroughImageTransportSurface(
217 GpuChannelManager* manager,
218 GpuCommandBufferStub* stub,
219 gfx::GLSurface* surface,
220 bool transport)
221 : GLSurfaceAdapter(surface),
222 transport_(transport),
223 did_set_swap_interval_(false),
224 did_unschedule_(false),
225 is_swap_buffers_pending_(false) {
226 helper_.reset(new ImageTransportHelper(this,
227 manager,
228 stub,
229 gfx::kNullPluginWindow));
230 }
231
Initialize()232 bool PassThroughImageTransportSurface::Initialize() {
233 // The surface is assumed to have already been initialized.
234 return helper_->Initialize();
235 }
236
Destroy()237 void PassThroughImageTransportSurface::Destroy() {
238 helper_->Destroy();
239 GLSurfaceAdapter::Destroy();
240 }
241
DeferDraws()242 bool PassThroughImageTransportSurface::DeferDraws() {
243 if (is_swap_buffers_pending_) {
244 DCHECK(!did_unschedule_);
245 did_unschedule_ = true;
246 helper_->SetScheduled(false);
247 return true;
248 }
249 return false;
250 }
251
SetLatencyInfo(const ui::LatencyInfo & latency_info)252 void PassThroughImageTransportSurface::SetLatencyInfo(
253 const ui::LatencyInfo& latency_info) {
254 latency_info_ = latency_info;
255 }
256
SwapBuffers()257 bool PassThroughImageTransportSurface::SwapBuffers() {
258 // GetVsyncValues before SwapBuffers to work around Mali driver bug:
259 // crbug.com/223558.
260 SendVSyncUpdateIfAvailable();
261 bool result = gfx::GLSurfaceAdapter::SwapBuffers();
262 latency_info_.AddLatencyNumber(
263 ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0);
264
265 if (transport_) {
266 DCHECK(!is_swap_buffers_pending_);
267 is_swap_buffers_pending_ = true;
268
269 // Round trip to the browser UI thread, for throttling, by sending a dummy
270 // SwapBuffers message.
271 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params;
272 params.surface_handle = 0;
273 params.latency_info = latency_info_;
274 params.size = surface()->GetSize();
275 helper_->SendAcceleratedSurfaceBuffersSwapped(params);
276 } else {
277 helper_->SendLatencyInfo(latency_info_);
278 }
279 return result;
280 }
281
PostSubBuffer(int x,int y,int width,int height)282 bool PassThroughImageTransportSurface::PostSubBuffer(
283 int x, int y, int width, int height) {
284 SendVSyncUpdateIfAvailable();
285 bool result = gfx::GLSurfaceAdapter::PostSubBuffer(x, y, width, height);
286 latency_info_.AddLatencyNumber(
287 ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0);
288
289 if (transport_) {
290 DCHECK(!is_swap_buffers_pending_);
291 is_swap_buffers_pending_ = true;
292
293 // Round trip to the browser UI thread, for throttling, by sending a dummy
294 // PostSubBuffer message.
295 GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params params;
296 params.surface_handle = 0;
297 params.latency_info = latency_info_;
298 params.surface_size = surface()->GetSize();
299 params.x = x;
300 params.y = y;
301 params.width = width;
302 params.height = height;
303 helper_->SendAcceleratedSurfacePostSubBuffer(params);
304
305 helper_->SetScheduled(false);
306 } else {
307 helper_->SendLatencyInfo(latency_info_);
308 }
309 return result;
310 }
311
OnMakeCurrent(gfx::GLContext * context)312 bool PassThroughImageTransportSurface::OnMakeCurrent(gfx::GLContext* context) {
313 if (!did_set_swap_interval_) {
314 ImageTransportHelper::SetSwapInterval(context);
315 did_set_swap_interval_ = true;
316 }
317 return true;
318 }
319
OnBufferPresented(const AcceleratedSurfaceMsg_BufferPresented_Params &)320 void PassThroughImageTransportSurface::OnBufferPresented(
321 const AcceleratedSurfaceMsg_BufferPresented_Params& /* params */) {
322 DCHECK(transport_);
323 DCHECK(is_swap_buffers_pending_);
324 is_swap_buffers_pending_ = false;
325 if (did_unschedule_) {
326 did_unschedule_ = false;
327 helper_->SetScheduled(true);
328 }
329 }
330
OnResizeViewACK()331 void PassThroughImageTransportSurface::OnResizeViewACK() {
332 DCHECK(transport_);
333 Resize(new_size_);
334
335 TRACE_EVENT_ASYNC_END0("gpu", "OnResize", this);
336 helper_->SetScheduled(true);
337 }
338
OnResize(gfx::Size size,float scale_factor)339 void PassThroughImageTransportSurface::OnResize(gfx::Size size,
340 float scale_factor) {
341 new_size_ = size;
342
343 if (transport_) {
344 helper_->SendResizeView(size);
345 helper_->SetScheduled(false);
346 TRACE_EVENT_ASYNC_BEGIN2("gpu", "OnResize", this,
347 "width", size.width(), "height", size.height());
348 } else {
349 Resize(new_size_);
350 }
351 }
352
GetSize()353 gfx::Size PassThroughImageTransportSurface::GetSize() {
354 return GLSurfaceAdapter::GetSize();
355 }
356
WakeUpGpu()357 void PassThroughImageTransportSurface::WakeUpGpu() {
358 NOTIMPLEMENTED();
359 }
360
~PassThroughImageTransportSurface()361 PassThroughImageTransportSurface::~PassThroughImageTransportSurface() {}
362
SendVSyncUpdateIfAvailable()363 void PassThroughImageTransportSurface::SendVSyncUpdateIfAvailable() {
364 gfx::VSyncProvider* vsync_provider = GetVSyncProvider();
365 if (vsync_provider) {
366 vsync_provider->GetVSyncParameters(
367 base::Bind(&ImageTransportHelper::SendUpdateVSyncParameters,
368 helper_->AsWeakPtr()));
369 }
370 }
371
372 } // namespace content
373