image_transport_surface_win.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
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 gfx::Size GetSize() OVERRIDE;
53
54 private:
55  virtual ~PbufferImageTransportSurface();
56  void SendBuffersSwapped();
57  void DestroySurface();
58
59  // Tracks the current buffer allocation state.
60  bool backbuffer_suggested_allocation_;
61  bool frontbuffer_suggested_allocation_;
62
63  // Whether a SwapBuffers is pending.
64  bool is_swap_buffers_pending_;
65
66  // Whether we unscheduled command buffer because of pending SwapBuffers.
67  bool did_unschedule_;
68
69  // Size to resize to when the surface becomes visible.
70  gfx::Size visible_size_;
71
72  ui::LatencyInfo latency_info_;
73
74  scoped_ptr<ImageTransportHelper> helper_;
75
76  DISALLOW_COPY_AND_ASSIGN(PbufferImageTransportSurface);
77};
78
79PbufferImageTransportSurface::PbufferImageTransportSurface(
80    GpuChannelManager* manager,
81    GpuCommandBufferStub* stub)
82    : GLSurfaceAdapter(new gfx::PbufferGLSurfaceEGL(gfx::Size(1, 1))),
83      backbuffer_suggested_allocation_(true),
84      frontbuffer_suggested_allocation_(true),
85      is_swap_buffers_pending_(false),
86      did_unschedule_(false) {
87  helper_.reset(new ImageTransportHelper(this,
88                                         manager,
89                                         stub,
90                                         gfx::kNullPluginWindow));
91}
92
93PbufferImageTransportSurface::~PbufferImageTransportSurface() {
94  Destroy();
95}
96
97bool PbufferImageTransportSurface::Initialize() {
98  // Only support this path if the GL implementation is ANGLE.
99  // IO surfaces will not work with, for example, OSMesa software renderer
100  // GL contexts.
101  if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2)
102    return false;
103
104  if (!helper_->Initialize())
105    return false;
106
107  return GLSurfaceAdapter::Initialize();
108}
109
110void PbufferImageTransportSurface::Destroy() {
111  helper_->Destroy();
112  GLSurfaceAdapter::Destroy();
113}
114
115bool PbufferImageTransportSurface::DeferDraws() {
116  // The command buffer hit a draw/clear command that could clobber the
117  // IOSurface in use by an earlier SwapBuffers. If a Swap is pending, abort
118  // processing of the command by returning true and unschedule until the Swap
119  // Ack arrives.
120  if (did_unschedule_)
121    return true;
122  if (is_swap_buffers_pending_) {
123    did_unschedule_ = true;
124    helper_->SetScheduled(false);
125    return true;
126  }
127  return false;
128}
129
130bool PbufferImageTransportSurface::IsOffscreen() {
131  return false;
132}
133
134bool PbufferImageTransportSurface::SwapBuffers() {
135  DCHECK(backbuffer_suggested_allocation_);
136  if (!frontbuffer_suggested_allocation_)
137    return true;
138
139  HANDLE surface_handle = GetShareHandle();
140  if (!surface_handle)
141    return false;
142
143  // Don't send the surface to the browser until we hit the fence that
144  // indicates the drawing to the surface has been completed.
145  // TODO(jbates) unscheduling should be deferred until draw commands from the
146  // next frame -- otherwise the GPU is potentially sitting idle.
147  helper_->DeferToFence(base::Bind(
148      &PbufferImageTransportSurface::SendBuffersSwapped,
149      AsWeakPtr()));
150
151  return true;
152}
153
154bool PbufferImageTransportSurface::PostSubBuffer(
155    int x, int y, int width, int height) {
156  NOTREACHED();
157  return false;
158}
159
160bool PbufferImageTransportSurface::SetBackbufferAllocation(bool allocation) {
161  if (backbuffer_suggested_allocation_ == allocation)
162    return true;
163  backbuffer_suggested_allocation_ = allocation;
164
165  DestroySurface();
166
167  if (backbuffer_suggested_allocation_ && visible_size_.GetArea() != 0)
168    return Resize(visible_size_);
169  else
170    return Resize(gfx::Size(1, 1));
171}
172
173void PbufferImageTransportSurface::SetFrontbufferAllocation(bool allocation) {
174  if (frontbuffer_suggested_allocation_ == allocation)
175    return;
176  frontbuffer_suggested_allocation_ = allocation;
177
178  // We recreate frontbuffer by recreating backbuffer and swapping.
179  // But we release frontbuffer by telling UI to release its handle on it.
180  if (!frontbuffer_suggested_allocation_)
181    helper_->Suspend();
182}
183
184void PbufferImageTransportSurface::DestroySurface() {
185  GpuHostMsg_AcceleratedSurfaceRelease_Params params;
186  helper_->SendAcceleratedSurfaceRelease(params);
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
243gfx::Size PbufferImageTransportSurface::GetSize() {
244  return GLSurfaceAdapter::GetSize();
245}
246
247}  // namespace anonymous
248
249// static
250scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface(
251    GpuChannelManager* manager,
252    GpuCommandBufferStub* stub,
253    const gfx::GLSurfaceHandle& handle) {
254  DCHECK(handle.handle);
255  DCHECK(handle.transport_type == gfx::NATIVE_DIRECT ||
256         handle.transport_type == gfx::NATIVE_TRANSPORT);
257  if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2 &&
258      !CommandLine::ForCurrentProcess()->HasSwitch(
259          switches::kDisableImageTransportSurface)) {
260    // This path handles two different cases.
261    //
262    // For post-Vista regular Windows, this surface will be used for
263    // renderer compositors.
264    //
265    // For Aura Windows, this will be the surface for the browser compositor
266    // (and the renderer compositors surface's will be
267    // TextureImageTransportSurface above).
268    const char* extensions = eglQueryString(
269        gfx::GLSurfaceEGL::GetHardwareDisplay(), EGL_EXTENSIONS);
270    if (extensions &&
271        strstr(extensions, "EGL_ANGLE_query_surface_pointer") &&
272        strstr(extensions, "EGL_ANGLE_surface_d3d_texture_2d_share_handle")) {
273      return scoped_refptr<gfx::GLSurface>(
274          new PbufferImageTransportSurface(manager, stub));
275    }
276  }
277
278  scoped_refptr<gfx::GLSurface> surface =
279      gfx::GLSurface::CreateViewGLSurface(handle.handle);
280  if (!surface)
281    return surface;
282  return scoped_refptr<gfx::GLSurface>(new PassThroughImageTransportSurface(
283      manager, stub, surface.get(), handle.is_transport()));
284}
285
286}  // namespace content
287