image_transport_surface_win.cc revision f2477e01787aa58f445919b809d89e252beef54f
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 void WakeUpGpu() OVERRIDE; 53 virtual gfx::Size GetSize() OVERRIDE; 54 55 private: 56 virtual ~PbufferImageTransportSurface(); 57 void SendBuffersSwapped(); 58 void DestroySurface(); 59 60 // Tracks the current buffer allocation state. 61 bool backbuffer_suggested_allocation_; 62 bool frontbuffer_suggested_allocation_; 63 64 // Whether a SwapBuffers is pending. 65 bool is_swap_buffers_pending_; 66 67 // Whether we unscheduled command buffer because of pending SwapBuffers. 68 bool did_unschedule_; 69 70 // Size to resize to when the surface becomes visible. 71 gfx::Size visible_size_; 72 73 ui::LatencyInfo latency_info_; 74 75 scoped_ptr<ImageTransportHelper> helper_; 76 77 DISALLOW_COPY_AND_ASSIGN(PbufferImageTransportSurface); 78}; 79 80PbufferImageTransportSurface::PbufferImageTransportSurface( 81 GpuChannelManager* manager, 82 GpuCommandBufferStub* stub) 83 : GLSurfaceAdapter(new gfx::PbufferGLSurfaceEGL(gfx::Size(1, 1))), 84 backbuffer_suggested_allocation_(true), 85 frontbuffer_suggested_allocation_(true), 86 is_swap_buffers_pending_(false), 87 did_unschedule_(false) { 88 helper_.reset(new ImageTransportHelper(this, 89 manager, 90 stub, 91 gfx::kNullPluginWindow)); 92} 93 94PbufferImageTransportSurface::~PbufferImageTransportSurface() { 95 Destroy(); 96} 97 98bool PbufferImageTransportSurface::Initialize() { 99 // Only support this path if the GL implementation is ANGLE. 100 // IO surfaces will not work with, for example, OSMesa software renderer 101 // GL contexts. 102 if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) 103 return false; 104 105 if (!helper_->Initialize()) 106 return false; 107 108 return GLSurfaceAdapter::Initialize(); 109} 110 111void PbufferImageTransportSurface::Destroy() { 112 helper_->Destroy(); 113 GLSurfaceAdapter::Destroy(); 114} 115 116bool PbufferImageTransportSurface::DeferDraws() { 117 // The command buffer hit a draw/clear command that could clobber the 118 // IOSurface in use by an earlier SwapBuffers. If a Swap is pending, abort 119 // processing of the command by returning true and unschedule until the Swap 120 // Ack arrives. 121 if (did_unschedule_) 122 return true; 123 if (is_swap_buffers_pending_) { 124 did_unschedule_ = true; 125 helper_->SetScheduled(false); 126 return true; 127 } 128 return false; 129} 130 131bool PbufferImageTransportSurface::IsOffscreen() { 132 return false; 133} 134 135bool PbufferImageTransportSurface::SwapBuffers() { 136 DCHECK(backbuffer_suggested_allocation_); 137 if (!frontbuffer_suggested_allocation_) 138 return true; 139 140 HANDLE surface_handle = GetShareHandle(); 141 if (!surface_handle) 142 return false; 143 144 // Don't send the surface to the browser until we hit the fence that 145 // indicates the drawing to the surface has been completed. 146 // TODO(jbates) unscheduling should be deferred until draw commands from the 147 // next frame -- otherwise the GPU is potentially sitting idle. 148 helper_->DeferToFence(base::Bind( 149 &PbufferImageTransportSurface::SendBuffersSwapped, 150 AsWeakPtr())); 151 152 return true; 153} 154 155bool PbufferImageTransportSurface::PostSubBuffer( 156 int x, int y, int width, int height) { 157 NOTREACHED(); 158 return false; 159} 160 161bool PbufferImageTransportSurface::SetBackbufferAllocation(bool allocation) { 162 if (backbuffer_suggested_allocation_ == allocation) 163 return true; 164 backbuffer_suggested_allocation_ = allocation; 165 166 DestroySurface(); 167 168 if (backbuffer_suggested_allocation_ && visible_size_.GetArea() != 0) 169 return Resize(visible_size_); 170 else 171 return Resize(gfx::Size(1, 1)); 172} 173 174void PbufferImageTransportSurface::SetFrontbufferAllocation(bool allocation) { 175 if (frontbuffer_suggested_allocation_ == allocation) 176 return; 177 frontbuffer_suggested_allocation_ = allocation; 178 179 // We recreate frontbuffer by recreating backbuffer and swapping. 180 // But we release frontbuffer by telling UI to release its handle on it. 181 if (!frontbuffer_suggested_allocation_) 182 helper_->Suspend(); 183} 184 185void PbufferImageTransportSurface::DestroySurface() { 186 helper_->SendAcceleratedSurfaceRelease(); 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 243void PbufferImageTransportSurface::WakeUpGpu() { 244 NOTIMPLEMENTED(); 245} 246 247gfx::Size PbufferImageTransportSurface::GetSize() { 248 return GLSurfaceAdapter::GetSize(); 249} 250 251} // namespace anonymous 252 253// static 254scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface( 255 GpuChannelManager* manager, 256 GpuCommandBufferStub* stub, 257 const gfx::GLSurfaceHandle& handle) { 258 DCHECK(handle.handle); 259 DCHECK(handle.transport_type == gfx::NATIVE_DIRECT || 260 handle.transport_type == gfx::NATIVE_TRANSPORT); 261 if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2 && 262 !CommandLine::ForCurrentProcess()->HasSwitch( 263 switches::kDisableImageTransportSurface)) { 264 // This path handles two different cases. 265 // 266 // For post-Vista regular Windows, this surface will be used for 267 // renderer compositors. 268 // 269 // For Aura Windows, this will be the surface for the browser compositor 270 // (and the renderer compositors surface's will be 271 // TextureImageTransportSurface above). 272 const char* extensions = eglQueryString( 273 gfx::GLSurfaceEGL::GetHardwareDisplay(), EGL_EXTENSIONS); 274 if (extensions && 275 strstr(extensions, "EGL_ANGLE_query_surface_pointer") && 276 strstr(extensions, "EGL_ANGLE_surface_d3d_texture_2d_share_handle")) { 277 return scoped_refptr<gfx::GLSurface>( 278 new PbufferImageTransportSurface(manager, stub)); 279 } 280 } 281 282 scoped_refptr<gfx::GLSurface> surface = 283 gfx::GLSurface::CreateViewGLSurface(handle.handle); 284 if (!surface) 285 return surface; 286 return scoped_refptr<gfx::GLSurface>(new PassThroughImageTransportSurface( 287 manager, stub, surface.get(), handle.is_transport())); 288} 289 290} // namespace content 291