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.
5 #include "content/common/gpu/image_transport_surface.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"
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.
26 class PbufferImageTransportSurface
27 : public gfx::GLSurfaceAdapter,
28 public ImageTransportSurface,
29 public base::SupportsWeakPtr<PbufferImageTransportSurface> {
31 PbufferImageTransportSurface(GpuChannelManager* manager,
32 GpuCommandBufferStub* stub);
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;
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;
55 virtual ~PbufferImageTransportSurface();
56 void SendBuffersSwapped();
57 void DestroySurface();
59 // Tracks the current buffer allocation state.
60 bool backbuffer_suggested_allocation_;
61 bool frontbuffer_suggested_allocation_;
63 // Whether a SwapBuffers is pending.
64 bool is_swap_buffers_pending_;
66 // Whether we unscheduled command buffer because of pending SwapBuffers.
69 // Size to resize to when the surface becomes visible.
70 gfx::Size visible_size_;
72 ui::LatencyInfo latency_info_;
74 scoped_ptr<ImageTransportHelper> helper_;
76 DISALLOW_COPY_AND_ASSIGN(PbufferImageTransportSurface);
79 PbufferImageTransportSurface::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,
90 gfx::kNullPluginWindow));
93 PbufferImageTransportSurface::~PbufferImageTransportSurface() {
97 bool 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
101 if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2)
104 if (!helper_->Initialize())
107 return GLSurfaceAdapter::Initialize();
110 void PbufferImageTransportSurface::Destroy() {
112 GLSurfaceAdapter::Destroy();
115 bool 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
122 if (is_swap_buffers_pending_) {
123 did_unschedule_ = true;
124 helper_->SetScheduled(false);
130 bool PbufferImageTransportSurface::IsOffscreen() {
134 bool PbufferImageTransportSurface::SwapBuffers() {
135 DCHECK(backbuffer_suggested_allocation_);
136 if (!frontbuffer_suggested_allocation_)
139 HANDLE surface_handle = GetShareHandle();
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,
154 bool PbufferImageTransportSurface::PostSubBuffer(
155 int x, int y, int width, int height) {
160 bool PbufferImageTransportSurface::SetBackbufferAllocation(bool allocation) {
161 if (backbuffer_suggested_allocation_ == allocation)
163 backbuffer_suggested_allocation_ = allocation;
167 if (backbuffer_suggested_allocation_ && visible_size_.GetArea() != 0)
168 return Resize(visible_size_);
170 return Resize(gfx::Size(1, 1));
173 void PbufferImageTransportSurface::SetFrontbufferAllocation(bool allocation) {
174 if (frontbuffer_suggested_allocation_ == allocation)
176 frontbuffer_suggested_allocation_ = allocation;
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_)
184 void PbufferImageTransportSurface::DestroySurface() {
185 helper_->SendAcceleratedSurfaceRelease();
188 std::string PbufferImageTransportSurface::GetExtensions() {
189 std::string extensions = gfx::GLSurface::GetExtensions();
190 extensions += extensions.empty() ? "" : " ";
191 extensions += "GL_CHROMIUM_front_buffer_cached";
195 void PbufferImageTransportSurface::SendBuffersSwapped() {
196 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params;
197 params.surface_handle = reinterpret_cast<int64>(GetShareHandle());
198 CHECK(params.surface_handle);
199 params.size = GetSize();
200 params.latency_info = latency_info_;
202 helper_->SendAcceleratedSurfaceBuffersSwapped(params);
204 DCHECK(!is_swap_buffers_pending_);
205 is_swap_buffers_pending_ = true;
208 void PbufferImageTransportSurface::OnBufferPresented(
209 const AcceleratedSurfaceMsg_BufferPresented_Params& params) {
210 if (!params.vsync_timebase.is_null() &&
211 params.vsync_interval != base::TimeDelta()) {
212 helper_->SendUpdateVSyncParameters(params.vsync_timebase,
213 params.vsync_interval);
215 is_swap_buffers_pending_ = false;
216 if (did_unschedule_) {
217 did_unschedule_ = false;
218 helper_->SetScheduled(true);
222 void PbufferImageTransportSurface::OnResizeViewACK() {
226 void PbufferImageTransportSurface::OnResize(gfx::Size size,
227 float scale_factor) {
228 DCHECK(backbuffer_suggested_allocation_);
229 DCHECK(frontbuffer_suggested_allocation_);
234 visible_size_ = size;
237 void PbufferImageTransportSurface::SetLatencyInfo(
238 const ui::LatencyInfo& latency_info) {
239 latency_info_ = latency_info;
242 gfx::Size PbufferImageTransportSurface::GetSize() {
243 return GLSurfaceAdapter::GetSize();
246 } // namespace anonymous
249 scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface(
250 GpuChannelManager* manager,
251 GpuCommandBufferStub* stub,
252 const gfx::GLSurfaceHandle& handle) {
253 DCHECK(handle.handle);
254 DCHECK(handle.transport_type == gfx::NATIVE_DIRECT ||
255 handle.transport_type == gfx::NATIVE_TRANSPORT);
256 if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2 &&
257 !CommandLine::ForCurrentProcess()->HasSwitch(
258 switches::kDisableImageTransportSurface)) {
259 // This path handles two different cases.
261 // For post-Vista regular Windows, this surface will be used for
262 // renderer compositors.
264 // For Aura Windows, this will be the surface for the browser compositor
265 // (and the renderer compositors surface's will be
266 // TextureImageTransportSurface above).
267 const char* extensions = eglQueryString(
268 gfx::GLSurfaceEGL::GetHardwareDisplay(), EGL_EXTENSIONS);
270 strstr(extensions, "EGL_ANGLE_query_surface_pointer") &&
271 strstr(extensions, "EGL_ANGLE_surface_d3d_texture_2d_share_handle")) {
272 return scoped_refptr<gfx::GLSurface>(
273 new PbufferImageTransportSurface(manager, stub));
277 scoped_refptr<gfx::GLSurface> surface =
278 gfx::GLSurface::CreateViewGLSurface(handle.handle);
281 return scoped_refptr<gfx::GLSurface>(new PassThroughImageTransportSurface(
282 manager, stub, surface.get(), handle.is_transport()));
285 } // namespace content