image_transport_surface_win.cc revision a36e5920737c6adbddd3e43b760e5de8431db6e0
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  is_swap_buffers_pending_ = false;
212  if (did_unschedule_) {
213    did_unschedule_ = false;
214    helper_->SetScheduled(true);
215  }
216}
217
218void PbufferImageTransportSurface::OnResizeViewACK() {
219  NOTREACHED();
220}
221
222void PbufferImageTransportSurface::OnResize(gfx::Size size,
223                                            float scale_factor) {
224  DCHECK(backbuffer_suggested_allocation_);
225  DCHECK(frontbuffer_suggested_allocation_);
226  Resize(size);
227
228  DestroySurface();
229
230  visible_size_ = size;
231}
232
233void PbufferImageTransportSurface::SetLatencyInfo(
234    const ui::LatencyInfo& latency_info) {
235  latency_info_ = latency_info;
236}
237
238gfx::Size PbufferImageTransportSurface::GetSize() {
239  return GLSurfaceAdapter::GetSize();
240}
241
242}  // namespace anonymous
243
244// static
245scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface(
246    GpuChannelManager* manager,
247    GpuCommandBufferStub* stub,
248    const gfx::GLSurfaceHandle& handle) {
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        gfx::GLSurfaceEGL::GetHardwareDisplay(), EGL_EXTENSIONS);
265    if (extensions &&
266        strstr(extensions, "EGL_ANGLE_query_surface_pointer") &&
267        strstr(extensions, "EGL_ANGLE_surface_d3d_texture_2d_share_handle")) {
268      return scoped_refptr<gfx::GLSurface>(
269          new PbufferImageTransportSurface(manager, stub));
270    }
271  }
272
273  scoped_refptr<gfx::GLSurface> surface =
274      gfx::GLSurface::CreateViewGLSurface(handle.handle);
275  if (!surface)
276    return surface;
277  return scoped_refptr<gfx::GLSurface>(new PassThroughImageTransportSurface(
278      manager, stub, surface.get(), handle.is_transport()));
279}
280
281}  // namespace content
282