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