image_transport_surface.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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
22namespace content {
23
24ImageTransportSurface::ImageTransportSurface() {}
25
26ImageTransportSurface::~ImageTransportSurface() {}
27
28scoped_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
43ImageTransportHelper::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
55ImageTransportHelper::~ImageTransportHelper() {
56  if (stub_.get()) {
57    stub_->SetLatencyInfoCallback(
58        base::Callback<void(const std::vector<ui::LatencyInfo>&)>());
59  }
60  manager_->RemoveRoute(route_id_);
61}
62
63bool 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
82void ImageTransportHelper::Destroy() {}
83
84bool 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
96void 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
108void 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
115void ImageTransportHelper::SendAcceleratedSurfaceRelease() {
116  GpuHostMsg_AcceleratedSurfaceRelease_Params params;
117  params.surface_id = stub_->surface_id();
118  manager_->Send(new GpuHostMsg_AcceleratedSurfaceRelease(params));
119}
120
121void ImageTransportHelper::SendResizeView(const gfx::Size& size) {
122  manager_->Send(new GpuHostMsg_ResizeView(stub_->surface_id(),
123                                           route_id_,
124                                           size));
125}
126
127void ImageTransportHelper::SendUpdateVSyncParameters(
128      base::TimeTicks timebase, base::TimeDelta interval) {
129  manager_->Send(new GpuHostMsg_UpdateVSyncParameters(stub_->surface_id(),
130                                                      timebase,
131                                                      interval));
132}
133
134void ImageTransportHelper::SendLatencyInfo(
135    const std::vector<ui::LatencyInfo>& latency_info) {
136  manager_->Send(new GpuHostMsg_FrameDrawn(latency_info));
137}
138
139void ImageTransportHelper::SetScheduled(bool is_scheduled) {
140  gpu::GpuScheduler* scheduler = Scheduler();
141  if (!scheduler)
142    return;
143
144  scheduler->SetScheduled(is_scheduled);
145}
146
147void ImageTransportHelper::DeferToFence(base::Closure task) {
148  gpu::GpuScheduler* scheduler = Scheduler();
149  DCHECK(scheduler);
150
151  scheduler->DeferToFence(task);
152}
153
154void ImageTransportHelper::SetPreemptByFlag(
155    scoped_refptr<gpu::PreemptionFlag> preemption_flag) {
156  stub_->channel()->SetPreemptByFlag(preemption_flag);
157}
158
159bool ImageTransportHelper::MakeCurrent() {
160  gpu::gles2::GLES2Decoder* decoder = Decoder();
161  if (!decoder)
162    return false;
163  return decoder->MakeCurrent();
164}
165
166void ImageTransportHelper::SetSwapInterval(gfx::GLContext* context) {
167  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync))
168    context->SetSwapInterval(0);
169  else
170    context->SetSwapInterval(1);
171}
172
173void ImageTransportHelper::Suspend() {
174  manager_->Send(new GpuHostMsg_AcceleratedSurfaceSuspend(stub_->surface_id()));
175}
176
177gpu::GpuScheduler* ImageTransportHelper::Scheduler() {
178  if (!stub_.get())
179    return NULL;
180  return stub_->scheduler();
181}
182
183gpu::gles2::GLES2Decoder* ImageTransportHelper::Decoder() {
184  if (!stub_.get())
185    return NULL;
186  return stub_->decoder();
187}
188
189void ImageTransportHelper::OnBufferPresented(
190    const AcceleratedSurfaceMsg_BufferPresented_Params& params) {
191  surface_->OnBufferPresented(params);
192}
193
194void ImageTransportHelper::OnResizeViewACK() {
195  surface_->OnResizeViewACK();
196}
197
198void ImageTransportHelper::OnWakeUpGpu() {
199  surface_->WakeUpGpu();
200}
201
202void 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
211void ImageTransportHelper::SetLatencyInfo(
212    const std::vector<ui::LatencyInfo>& latency_info) {
213  surface_->SetLatencyInfo(latency_info);
214}
215
216PassThroughImageTransportSurface::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
232bool PassThroughImageTransportSurface::Initialize() {
233  // The surface is assumed to have already been initialized.
234  return helper_->Initialize();
235}
236
237void PassThroughImageTransportSurface::Destroy() {
238  helper_->Destroy();
239  GLSurfaceAdapter::Destroy();
240}
241
242bool 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
252void PassThroughImageTransportSurface::SetLatencyInfo(
253    const std::vector<ui::LatencyInfo>& latency_info) {
254  for (size_t i = 0; i < latency_info.size(); i++)
255    latency_info_.push_back(latency_info[i]);
256}
257
258bool PassThroughImageTransportSurface::SwapBuffers() {
259  // GetVsyncValues before SwapBuffers to work around Mali driver bug:
260  // crbug.com/223558.
261  SendVSyncUpdateIfAvailable();
262  bool result = gfx::GLSurfaceAdapter::SwapBuffers();
263  for (size_t i = 0; i < latency_info_.size(); i++) {
264    latency_info_[i].AddLatencyNumber(
265        ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0);
266  }
267
268  if (transport_) {
269    DCHECK(!is_swap_buffers_pending_);
270    is_swap_buffers_pending_ = true;
271
272    // Round trip to the browser UI thread, for throttling, by sending a dummy
273    // SwapBuffers message.
274    GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params;
275    params.surface_handle = 0;
276    params.latency_info.swap(latency_info_);
277    params.size = surface()->GetSize();
278    helper_->SendAcceleratedSurfaceBuffersSwapped(params);
279  } else {
280    helper_->SendLatencyInfo(latency_info_);
281  }
282  latency_info_.clear();
283  return result;
284}
285
286bool PassThroughImageTransportSurface::PostSubBuffer(
287    int x, int y, int width, int height) {
288  SendVSyncUpdateIfAvailable();
289  bool result = gfx::GLSurfaceAdapter::PostSubBuffer(x, y, width, height);
290  for (size_t i = 0; i < latency_info_.size(); i++) {
291    latency_info_[i].AddLatencyNumber(
292        ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0);
293  }
294
295  if (transport_) {
296    DCHECK(!is_swap_buffers_pending_);
297    is_swap_buffers_pending_ = true;
298
299    // Round trip to the browser UI thread, for throttling, by sending a dummy
300    // PostSubBuffer message.
301    GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params params;
302    params.surface_handle = 0;
303    params.latency_info.swap(latency_info_);
304    params.surface_size = surface()->GetSize();
305    params.x = x;
306    params.y = y;
307    params.width = width;
308    params.height = height;
309    helper_->SendAcceleratedSurfacePostSubBuffer(params);
310
311    helper_->SetScheduled(false);
312  } else {
313    helper_->SendLatencyInfo(latency_info_);
314  }
315  latency_info_.clear();
316  return result;
317}
318
319bool PassThroughImageTransportSurface::OnMakeCurrent(gfx::GLContext* context) {
320  if (!did_set_swap_interval_) {
321    ImageTransportHelper::SetSwapInterval(context);
322    did_set_swap_interval_ = true;
323  }
324  return true;
325}
326
327void PassThroughImageTransportSurface::OnBufferPresented(
328    const AcceleratedSurfaceMsg_BufferPresented_Params& /* params */) {
329  DCHECK(transport_);
330  DCHECK(is_swap_buffers_pending_);
331  is_swap_buffers_pending_ = false;
332  if (did_unschedule_) {
333    did_unschedule_ = false;
334    helper_->SetScheduled(true);
335  }
336}
337
338void PassThroughImageTransportSurface::OnResizeViewACK() {
339  DCHECK(transport_);
340  Resize(new_size_);
341
342  TRACE_EVENT_ASYNC_END0("gpu", "OnResize", this);
343  helper_->SetScheduled(true);
344}
345
346void PassThroughImageTransportSurface::OnResize(gfx::Size size,
347                                                float scale_factor) {
348  new_size_ = size;
349
350  if (transport_) {
351    helper_->SendResizeView(size);
352    helper_->SetScheduled(false);
353    TRACE_EVENT_ASYNC_BEGIN2("gpu", "OnResize", this,
354                             "width", size.width(), "height", size.height());
355  } else {
356    Resize(new_size_);
357  }
358}
359
360gfx::Size PassThroughImageTransportSurface::GetSize() {
361  return GLSurfaceAdapter::GetSize();
362}
363
364void PassThroughImageTransportSurface::WakeUpGpu() {
365  NOTIMPLEMENTED();
366}
367
368PassThroughImageTransportSurface::~PassThroughImageTransportSurface() {}
369
370void PassThroughImageTransportSurface::SendVSyncUpdateIfAvailable() {
371  gfx::VSyncProvider* vsync_provider = GetVSyncProvider();
372  if (vsync_provider) {
373    vsync_provider->GetVSyncParameters(
374      base::Bind(&ImageTransportHelper::SendUpdateVSyncParameters,
375                 helper_->AsWeakPtr()));
376  }
377}
378
379}  // namespace content
380