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 GpuHostMsg_AcceleratedSurfaceRelease_Params params
;
186 helper_
->SendAcceleratedSurfaceRelease(params
);
189 std::string
PbufferImageTransportSurface::GetExtensions() {
190 std::string extensions
= gfx::GLSurface::GetExtensions();
191 extensions
+= extensions
.empty() ? "" : " ";
192 extensions
+= "GL_CHROMIUM_front_buffer_cached";
196 void 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_
;
203 helper_
->SendAcceleratedSurfaceBuffersSwapped(params
);
205 DCHECK(!is_swap_buffers_pending_
);
206 is_swap_buffers_pending_
= true;
209 void 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
);
216 is_swap_buffers_pending_
= false;
217 if (did_unschedule_
) {
218 did_unschedule_
= false;
219 helper_
->SetScheduled(true);
223 void PbufferImageTransportSurface::OnResizeViewACK() {
227 void PbufferImageTransportSurface::OnResize(gfx::Size size
,
228 float scale_factor
) {
229 DCHECK(backbuffer_suggested_allocation_
);
230 DCHECK(frontbuffer_suggested_allocation_
);
235 visible_size_
= size
;
238 void PbufferImageTransportSurface::SetLatencyInfo(
239 const ui::LatencyInfo
& latency_info
) {
240 latency_info_
= latency_info
;
243 gfx::Size
PbufferImageTransportSurface::GetSize() {
244 return GLSurfaceAdapter::GetSize();
247 } // namespace anonymous
250 scoped_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.
262 // For post-Vista regular Windows, this surface will be used for
263 // renderer compositors.
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
);
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
));
278 scoped_refptr
<gfx::GLSurface
> surface
=
279 gfx::GLSurface::CreateViewGLSurface(handle
.handle
);
282 return scoped_refptr
<gfx::GLSurface
>(new PassThroughImageTransportSurface(
283 manager
, stub
, surface
.get(), handle
.is_transport()));
286 } // namespace content