image_transport_surface_win.cc revision f2477e01787aa58f445919b809d89e252beef54f
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/command_line.h"
9#include "base/compiler_specific.h"
10#include "base/memory/scoped_ptr.h"
11#include "base/memory/weak_ptr.h"
12#include "base/win/windows_version.h"
13#include "content/common/gpu/gpu_messages.h"
14#include "content/public/common/content_switches.h"
15#include "ui/gfx/native_widget_types.h"
16#include "ui/gl/gl_bindings.h"
17#include "ui/gl/gl_context.h"
18#include "ui/gl/gl_implementation.h"
19#include "ui/gl/gl_surface_egl.h"
20
21namespace content {
22namespace {
23
24// We are backed by an Pbuffer offscreen surface through which ANGLE provides
25// a handle to the corresponding render target texture through an extension.
26class PbufferImageTransportSurface
27    : public gfx::GLSurfaceAdapter,
28      public ImageTransportSurface,
29      public base::SupportsWeakPtr<PbufferImageTransportSurface> {
30 public:
31  PbufferImageTransportSurface(GpuChannelManager* manager,
32                               GpuCommandBufferStub* stub);
33
34  // gfx::GLSurface implementation
35  virtual bool Initialize() OVERRIDE;
36  virtual void Destroy() OVERRIDE;
37  virtual bool DeferDraws() OVERRIDE;
38  virtual bool IsOffscreen() OVERRIDE;
39  virtual bool SwapBuffers() OVERRIDE;
40  virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE;
41  virtual std::string GetExtensions() OVERRIDE;
42  virtual bool SetBackbufferAllocation(bool allocated) OVERRIDE;
43  virtual void SetFrontbufferAllocation(bool allocated) OVERRIDE;
44
45 protected:
46  // ImageTransportSurface implementation
47  virtual void OnBufferPresented(
48      const AcceleratedSurfaceMsg_BufferPresented_Params& params) OVERRIDE;
49  virtual void OnResizeViewACK() OVERRIDE;
50  virtual void OnResize(gfx::Size size, float scale_factor) OVERRIDE;
51  virtual void SetLatencyInfo(const ui::LatencyInfo&) OVERRIDE;
52  virtual void WakeUpGpu() OVERRIDE;
53  virtual gfx::Size GetSize() OVERRIDE;
54
55 private:
56  virtual ~PbufferImageTransportSurface();
57  void SendBuffersSwapped();
58  void DestroySurface();
59
60  // Tracks the current buffer allocation state.
61  bool backbuffer_suggested_allocation_;
62  bool frontbuffer_suggested_allocation_;
63
64  // Whether a SwapBuffers is pending.
65  bool is_swap_buffers_pending_;
66
67  // Whether we unscheduled command buffer because of pending SwapBuffers.
68  bool did_unschedule_;
69
70  // Size to resize to when the surface becomes visible.
71  gfx::Size visible_size_;
72
73  ui::LatencyInfo latency_info_;
74
75  scoped_ptr<ImageTransportHelper> helper_;
76
77  DISALLOW_COPY_AND_ASSIGN(PbufferImageTransportSurface);
78};
79
80PbufferImageTransportSurface::PbufferImageTransportSurface(
81    GpuChannelManager* manager,
82    GpuCommandBufferStub* stub)
83    : GLSurfaceAdapter(new gfx::PbufferGLSurfaceEGL(gfx::Size(1, 1))),
84      backbuffer_suggested_allocation_(true),
85      frontbuffer_suggested_allocation_(true),
86      is_swap_buffers_pending_(false),
87      did_unschedule_(false) {
88  helper_.reset(new ImageTransportHelper(this,
89                                         manager,
90                                         stub,
91                                         gfx::kNullPluginWindow));
92}
93
94PbufferImageTransportSurface::~PbufferImageTransportSurface() {
95  Destroy();
96}
97
98bool PbufferImageTransportSurface::Initialize() {
99  // Only support this path if the GL implementation is ANGLE.
100  // IO surfaces will not work with, for example, OSMesa software renderer
101  // GL contexts.
102  if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2)
103    return false;
104
105  if (!helper_->Initialize())
106    return false;
107
108  return GLSurfaceAdapter::Initialize();
109}
110
111void PbufferImageTransportSurface::Destroy() {
112  helper_->Destroy();
113  GLSurfaceAdapter::Destroy();
114}
115
116bool PbufferImageTransportSurface::DeferDraws() {
117  // The command buffer hit a draw/clear command that could clobber the
118  // IOSurface in use by an earlier SwapBuffers. If a Swap is pending, abort
119  // processing of the command by returning true and unschedule until the Swap
120  // Ack arrives.
121  if (did_unschedule_)
122    return true;
123  if (is_swap_buffers_pending_) {
124    did_unschedule_ = true;
125    helper_->SetScheduled(false);
126    return true;
127  }
128  return false;
129}
130
131bool PbufferImageTransportSurface::IsOffscreen() {
132  return false;
133}
134
135bool PbufferImageTransportSurface::SwapBuffers() {
136  DCHECK(backbuffer_suggested_allocation_);
137  if (!frontbuffer_suggested_allocation_)
138    return true;
139
140  HANDLE surface_handle = GetShareHandle();
141  if (!surface_handle)
142    return false;
143
144  // Don't send the surface to the browser until we hit the fence that
145  // indicates the drawing to the surface has been completed.
146  // TODO(jbates) unscheduling should be deferred until draw commands from the
147  // next frame -- otherwise the GPU is potentially sitting idle.
148  helper_->DeferToFence(base::Bind(
149      &PbufferImageTransportSurface::SendBuffersSwapped,
150      AsWeakPtr()));
151
152  return true;
153}
154
155bool PbufferImageTransportSurface::PostSubBuffer(
156    int x, int y, int width, int height) {
157  NOTREACHED();
158  return false;
159}
160
161bool PbufferImageTransportSurface::SetBackbufferAllocation(bool allocation) {
162  if (backbuffer_suggested_allocation_ == allocation)
163    return true;
164  backbuffer_suggested_allocation_ = allocation;
165
166  DestroySurface();
167
168  if (backbuffer_suggested_allocation_ && visible_size_.GetArea() != 0)
169    return Resize(visible_size_);
170  else
171    return Resize(gfx::Size(1, 1));
172}
173
174void PbufferImageTransportSurface::SetFrontbufferAllocation(bool allocation) {
175  if (frontbuffer_suggested_allocation_ == allocation)
176    return;
177  frontbuffer_suggested_allocation_ = allocation;
178
179  // We recreate frontbuffer by recreating backbuffer and swapping.
180  // But we release frontbuffer by telling UI to release its handle on it.
181  if (!frontbuffer_suggested_allocation_)
182    helper_->Suspend();
183}
184
185void PbufferImageTransportSurface::DestroySurface() {
186  helper_->SendAcceleratedSurfaceRelease();
187}
188
189std::string PbufferImageTransportSurface::GetExtensions() {
190  std::string extensions = gfx::GLSurface::GetExtensions();
191  extensions += extensions.empty() ? "" : " ";
192  extensions += "GL_CHROMIUM_front_buffer_cached";
193  return extensions;
194}
195
196void PbufferImageTransportSurface::SendBuffersSwapped() {
197  GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params;
198  params.surface_handle = reinterpret_cast<int64>(GetShareHandle());
199  CHECK(params.surface_handle);
200  params.size = GetSize();
201  params.latency_info = latency_info_;
202
203  helper_->SendAcceleratedSurfaceBuffersSwapped(params);
204
205  DCHECK(!is_swap_buffers_pending_);
206  is_swap_buffers_pending_ = true;
207}
208
209void PbufferImageTransportSurface::OnBufferPresented(
210    const AcceleratedSurfaceMsg_BufferPresented_Params& params) {
211  if (!params.vsync_timebase.is_null() &&
212      params.vsync_interval != base::TimeDelta()) {
213    helper_->SendUpdateVSyncParameters(params.vsync_timebase,
214                                       params.vsync_interval);
215  }
216  is_swap_buffers_pending_ = false;
217  if (did_unschedule_) {
218    did_unschedule_ = false;
219    helper_->SetScheduled(true);
220  }
221}
222
223void PbufferImageTransportSurface::OnResizeViewACK() {
224  NOTREACHED();
225}
226
227void PbufferImageTransportSurface::OnResize(gfx::Size size,
228                                            float scale_factor) {
229  DCHECK(backbuffer_suggested_allocation_);
230  DCHECK(frontbuffer_suggested_allocation_);
231  Resize(size);
232
233  DestroySurface();
234
235  visible_size_ = size;
236}
237
238void PbufferImageTransportSurface::SetLatencyInfo(
239    const ui::LatencyInfo& latency_info) {
240  latency_info_ = latency_info;
241}
242
243void PbufferImageTransportSurface::WakeUpGpu() {
244  NOTIMPLEMENTED();
245}
246
247gfx::Size PbufferImageTransportSurface::GetSize() {
248  return GLSurfaceAdapter::GetSize();
249}
250
251}  // namespace anonymous
252
253// static
254scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface(
255    GpuChannelManager* manager,
256    GpuCommandBufferStub* stub,
257    const gfx::GLSurfaceHandle& handle) {
258  DCHECK(handle.handle);
259  DCHECK(handle.transport_type == gfx::NATIVE_DIRECT ||
260         handle.transport_type == gfx::NATIVE_TRANSPORT);
261  if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2 &&
262      !CommandLine::ForCurrentProcess()->HasSwitch(
263          switches::kDisableImageTransportSurface)) {
264    // This path handles two different cases.
265    //
266    // For post-Vista regular Windows, this surface will be used for
267    // renderer compositors.
268    //
269    // For Aura Windows, this will be the surface for the browser compositor
270    // (and the renderer compositors surface's will be
271    // TextureImageTransportSurface above).
272    const char* extensions = eglQueryString(
273        gfx::GLSurfaceEGL::GetHardwareDisplay(), EGL_EXTENSIONS);
274    if (extensions &&
275        strstr(extensions, "EGL_ANGLE_query_surface_pointer") &&
276        strstr(extensions, "EGL_ANGLE_surface_d3d_texture_2d_share_handle")) {
277      return scoped_refptr<gfx::GLSurface>(
278          new PbufferImageTransportSurface(manager, stub));
279    }
280  }
281
282  scoped_refptr<gfx::GLSurface> surface =
283      gfx::GLSurface::CreateViewGLSurface(handle.handle);
284  if (!surface)
285    return surface;
286  return scoped_refptr<gfx::GLSurface>(new PassThroughImageTransportSurface(
287      manager, stub, surface.get(), handle.is_transport()));
288}
289
290}  // namespace content
291