image_transport_surface_win.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
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 if (!params.vsync_timebase.is_null() && 212 params.vsync_interval != base::TimeDelta()) { 213 helper_->SendUpdateVSyncParameters(params.vsync_timebase, 214 params.vsync_interval); 215 } 216 is_swap_buffers_pending_ = false; 217 if (did_unschedule_) { 218 did_unschedule_ = false; 219 helper_->SetScheduled(true); 220 } 221} 222 223void PbufferImageTransportSurface::OnResizeViewACK() { 224 NOTREACHED(); 225} 226 227void PbufferImageTransportSurface::OnResize(gfx::Size size, 228 float scale_factor) { 229 DCHECK(backbuffer_suggested_allocation_); 230 DCHECK(frontbuffer_suggested_allocation_); 231 Resize(size); 232 233 DestroySurface(); 234 235 visible_size_ = size; 236} 237 238void PbufferImageTransportSurface::SetLatencyInfo( 239 const ui::LatencyInfo& latency_info) { 240 latency_info_ = latency_info; 241} 242 243gfx::Size PbufferImageTransportSurface::GetSize() { 244 return GLSurfaceAdapter::GetSize(); 245} 246 247} // namespace anonymous 248 249// static 250scoped_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. 261 // 262 // For post-Vista regular Windows, this surface will be used for 263 // renderer compositors. 264 // 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); 270 if (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)); 275 } 276 } 277 278 scoped_refptr<gfx::GLSurface> surface = 279 gfx::GLSurface::CreateViewGLSurface(handle.handle); 280 if (!surface) 281 return surface; 282 return scoped_refptr<gfx::GLSurface>(new PassThroughImageTransportSurface( 283 manager, stub, surface.get(), handle.is_transport())); 284} 285 286} // namespace content 287