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