image_transport_surface_win.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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) OVERRIDE; 51 virtual void SetLatencyInfo(const cc::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 cc::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(false, 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_) 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 DCHECK(backbuffer_suggested_allocation_); 224 DCHECK(frontbuffer_suggested_allocation_); 225 Resize(size); 226 227 DestroySurface(); 228 229 visible_size_ = size; 230} 231 232void PbufferImageTransportSurface::SetLatencyInfo( 233 const cc::LatencyInfo& latency_info) { 234 latency_info_ = latency_info; 235} 236 237gfx::Size PbufferImageTransportSurface::GetSize() { 238 return GLSurfaceAdapter::GetSize(); 239} 240 241} // namespace anonymous 242 243// static 244scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface( 245 GpuChannelManager* manager, 246 GpuCommandBufferStub* stub, 247 const gfx::GLSurfaceHandle& handle) { 248 DCHECK(handle.handle); 249 DCHECK(handle.transport_type == gfx::NATIVE_DIRECT || 250 handle.transport_type == gfx::NATIVE_TRANSPORT); 251 if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2 && 252 !CommandLine::ForCurrentProcess()->HasSwitch( 253 switches::kDisableImageTransportSurface)) { 254 // This path handles two different cases. 255 // 256 // For post-Vista regular Windows, this surface will be used for 257 // renderer compositors. 258 // 259 // For Aura Windows, this will be the surface for the browser compositor 260 // (and the renderer compositors surface's will be 261 // TextureImageTransportSurface above). 262 const char* extensions = eglQueryString( 263 eglGetDisplay(EGL_DEFAULT_DISPLAY), EGL_EXTENSIONS); 264 if (strstr(extensions, "EGL_ANGLE_query_surface_pointer") && 265 strstr(extensions, "EGL_ANGLE_surface_d3d_texture_2d_share_handle")) { 266 return scoped_refptr<gfx::GLSurface>( 267 new PbufferImageTransportSurface(manager, stub)); 268 } 269 } 270 271 scoped_refptr<gfx::GLSurface> surface = 272 gfx::GLSurface::CreateViewGLSurface(false, handle.handle); 273 if (!surface) 274 return surface; 275 return scoped_refptr<gfx::GLSurface>(new PassThroughImageTransportSurface( 276 manager, stub, surface.get(), handle.is_transport())); 277} 278 279} // namespace content 280