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/bind_helpers.h" 9 #include "base/command_line.h" 10 #include "base/debug/trace_event.h" 11 #include "content/common/gpu/gpu_channel.h" 12 #include "content/common/gpu/gpu_channel_manager.h" 13 #include "content/common/gpu/gpu_command_buffer_stub.h" 14 #include "content/common/gpu/gpu_messages.h" 15 #include "content/common/gpu/texture_image_transport_surface.h" 16 #include "gpu/command_buffer/service/gpu_scheduler.h" 17 #include "ui/gl/gl_implementation.h" 18 #include "ui/gl/gl_switches.h" 19 #include "ui/gl/vsync_provider.h" 20 21 namespace content { 22 23 ImageTransportSurface::ImageTransportSurface() {} 24 25 ImageTransportSurface::~ImageTransportSurface() {} 26 27 scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateSurface( 28 GpuChannelManager* manager, 29 GpuCommandBufferStub* stub, 30 const gfx::GLSurfaceHandle& handle) { 31 scoped_refptr<gfx::GLSurface> surface; 32 if (handle.transport_type == gfx::TEXTURE_TRANSPORT) 33 surface = new TextureImageTransportSurface(manager, stub, handle); 34 else 35 surface = CreateNativeSurface(manager, stub, handle); 36 37 if (!surface.get() || !surface->Initialize()) 38 return NULL; 39 return surface; 40 } 41 42 ImageTransportHelper::ImageTransportHelper(ImageTransportSurface* surface, 43 GpuChannelManager* manager, 44 GpuCommandBufferStub* stub, 45 gfx::PluginWindowHandle handle) 46 : surface_(surface), 47 manager_(manager), 48 stub_(stub->AsWeakPtr()), 49 handle_(handle) { 50 route_id_ = manager_->GenerateRouteID(); 51 manager_->AddRoute(route_id_, this); 52 } 53 54 ImageTransportHelper::~ImageTransportHelper() { 55 if (stub_.get()) { 56 stub_->SetLatencyInfoCallback( 57 base::Callback<void(const ui::LatencyInfo&)>()); 58 } 59 manager_->RemoveRoute(route_id_); 60 } 61 62 bool ImageTransportHelper::Initialize() { 63 gpu::gles2::GLES2Decoder* decoder = Decoder(); 64 65 if (!decoder) 66 return false; 67 68 decoder->SetResizeCallback( 69 base::Bind(&ImageTransportHelper::Resize, base::Unretained(this))); 70 71 stub_->SetLatencyInfoCallback( 72 base::Bind(&ImageTransportHelper::SetLatencyInfo, 73 base::Unretained(this))); 74 75 return true; 76 } 77 78 void ImageTransportHelper::Destroy() {} 79 80 bool ImageTransportHelper::OnMessageReceived(const IPC::Message& message) { 81 bool handled = true; 82 IPC_BEGIN_MESSAGE_MAP(ImageTransportHelper, message) 83 IPC_MESSAGE_HANDLER(AcceleratedSurfaceMsg_BufferPresented, 84 OnBufferPresented) 85 IPC_MESSAGE_HANDLER(AcceleratedSurfaceMsg_ResizeViewACK, OnResizeViewACK); 86 IPC_MESSAGE_UNHANDLED(handled = false) 87 IPC_END_MESSAGE_MAP() 88 return handled; 89 } 90 91 void ImageTransportHelper::SendAcceleratedSurfaceBuffersSwapped( 92 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params) { 93 // TRACE_EVENT for gpu tests: 94 TRACE_EVENT_INSTANT2("test_gpu", "SwapBuffers", 95 TRACE_EVENT_SCOPE_THREAD, 96 "GLImpl", static_cast<int>(gfx::GetGLImplementation()), 97 "width", params.size.width()); 98 params.surface_id = stub_->surface_id(); 99 params.route_id = route_id_; 100 manager_->Send(new GpuHostMsg_AcceleratedSurfaceBuffersSwapped(params)); 101 } 102 103 void ImageTransportHelper::SendAcceleratedSurfacePostSubBuffer( 104 GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params params) { 105 params.surface_id = stub_->surface_id(); 106 params.route_id = route_id_; 107 manager_->Send(new GpuHostMsg_AcceleratedSurfacePostSubBuffer(params)); 108 } 109 110 void ImageTransportHelper::SendAcceleratedSurfaceRelease( 111 GpuHostMsg_AcceleratedSurfaceRelease_Params params) { 112 params.surface_id = stub_->surface_id(); 113 params.route_id = route_id_; 114 manager_->Send(new GpuHostMsg_AcceleratedSurfaceRelease(params)); 115 } 116 117 void ImageTransportHelper::SendResizeView(const gfx::Size& size) { 118 manager_->Send(new GpuHostMsg_ResizeView(stub_->surface_id(), 119 route_id_, 120 size)); 121 } 122 123 void ImageTransportHelper::SendUpdateVSyncParameters( 124 base::TimeTicks timebase, base::TimeDelta interval) { 125 manager_->Send(new GpuHostMsg_UpdateVSyncParameters(stub_->surface_id(), 126 timebase, 127 interval)); 128 } 129 130 void ImageTransportHelper::SendLatencyInfo( 131 const ui::LatencyInfo& latency_info) { 132 manager_->Send(new GpuHostMsg_FrameDrawn(latency_info)); 133 } 134 135 void ImageTransportHelper::SetScheduled(bool is_scheduled) { 136 gpu::GpuScheduler* scheduler = Scheduler(); 137 if (!scheduler) 138 return; 139 140 scheduler->SetScheduled(is_scheduled); 141 } 142 143 void ImageTransportHelper::DeferToFence(base::Closure task) { 144 gpu::GpuScheduler* scheduler = Scheduler(); 145 DCHECK(scheduler); 146 147 scheduler->DeferToFence(task); 148 } 149 150 void ImageTransportHelper::SetPreemptByFlag( 151 scoped_refptr<gpu::PreemptionFlag> preemption_flag) { 152 stub_->channel()->SetPreemptByFlag(preemption_flag); 153 } 154 155 bool ImageTransportHelper::MakeCurrent() { 156 gpu::gles2::GLES2Decoder* decoder = Decoder(); 157 if (!decoder) 158 return false; 159 return decoder->MakeCurrent(); 160 } 161 162 void ImageTransportHelper::SetSwapInterval(gfx::GLContext* context) { 163 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync)) 164 context->SetSwapInterval(0); 165 else 166 context->SetSwapInterval(1); 167 } 168 169 void ImageTransportHelper::Suspend() { 170 manager_->Send(new GpuHostMsg_AcceleratedSurfaceSuspend(stub_->surface_id())); 171 } 172 173 gpu::GpuScheduler* ImageTransportHelper::Scheduler() { 174 if (!stub_.get()) 175 return NULL; 176 return stub_->scheduler(); 177 } 178 179 gpu::gles2::GLES2Decoder* ImageTransportHelper::Decoder() { 180 if (!stub_.get()) 181 return NULL; 182 return stub_->decoder(); 183 } 184 185 void ImageTransportHelper::OnBufferPresented( 186 const AcceleratedSurfaceMsg_BufferPresented_Params& params) { 187 surface_->OnBufferPresented(params); 188 } 189 190 void ImageTransportHelper::OnResizeViewACK() { 191 surface_->OnResizeViewACK(); 192 } 193 194 void ImageTransportHelper::Resize(gfx::Size size, float scale_factor) { 195 surface_->OnResize(size, scale_factor); 196 197 #if defined(OS_ANDROID) 198 manager_->gpu_memory_manager()->ScheduleManage( 199 GpuMemoryManager::kScheduleManageNow); 200 #endif 201 } 202 203 void ImageTransportHelper::SetLatencyInfo( 204 const ui::LatencyInfo& latency_info) { 205 surface_->SetLatencyInfo(latency_info); 206 } 207 208 PassThroughImageTransportSurface::PassThroughImageTransportSurface( 209 GpuChannelManager* manager, 210 GpuCommandBufferStub* stub, 211 gfx::GLSurface* surface, 212 bool transport) 213 : GLSurfaceAdapter(surface), 214 transport_(transport), 215 did_set_swap_interval_(false), 216 did_unschedule_(false), 217 is_swap_buffers_pending_(false) { 218 helper_.reset(new ImageTransportHelper(this, 219 manager, 220 stub, 221 gfx::kNullPluginWindow)); 222 } 223 224 bool PassThroughImageTransportSurface::Initialize() { 225 // The surface is assumed to have already been initialized. 226 return helper_->Initialize(); 227 } 228 229 void PassThroughImageTransportSurface::Destroy() { 230 helper_->Destroy(); 231 GLSurfaceAdapter::Destroy(); 232 } 233 234 bool PassThroughImageTransportSurface::DeferDraws() { 235 if (is_swap_buffers_pending_) { 236 DCHECK(!did_unschedule_); 237 did_unschedule_ = true; 238 helper_->SetScheduled(false); 239 return true; 240 } 241 return false; 242 } 243 244 void PassThroughImageTransportSurface::SetLatencyInfo( 245 const ui::LatencyInfo& latency_info) { 246 latency_info_ = latency_info; 247 } 248 249 bool PassThroughImageTransportSurface::SwapBuffers() { 250 // GetVsyncValues before SwapBuffers to work around Mali driver bug: 251 // crbug.com/223558. 252 SendVSyncUpdateIfAvailable(); 253 bool result = gfx::GLSurfaceAdapter::SwapBuffers(); 254 latency_info_.swap_timestamp = base::TimeTicks::HighResNow(); 255 256 if (transport_) { 257 DCHECK(!is_swap_buffers_pending_); 258 is_swap_buffers_pending_ = true; 259 260 // Round trip to the browser UI thread, for throttling, by sending a dummy 261 // SwapBuffers message. 262 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; 263 params.surface_handle = 0; 264 params.latency_info = latency_info_; 265 params.size = surface()->GetSize(); 266 helper_->SendAcceleratedSurfaceBuffersSwapped(params); 267 } else { 268 helper_->SendLatencyInfo(latency_info_); 269 } 270 return result; 271 } 272 273 bool PassThroughImageTransportSurface::PostSubBuffer( 274 int x, int y, int width, int height) { 275 SendVSyncUpdateIfAvailable(); 276 bool result = gfx::GLSurfaceAdapter::PostSubBuffer(x, y, width, height); 277 latency_info_.swap_timestamp = base::TimeTicks::HighResNow(); 278 279 if (transport_) { 280 DCHECK(!is_swap_buffers_pending_); 281 is_swap_buffers_pending_ = true; 282 283 // Round trip to the browser UI thread, for throttling, by sending a dummy 284 // PostSubBuffer message. 285 GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params params; 286 params.surface_handle = 0; 287 params.latency_info = latency_info_; 288 params.surface_size = surface()->GetSize(); 289 params.x = x; 290 params.y = y; 291 params.width = width; 292 params.height = height; 293 helper_->SendAcceleratedSurfacePostSubBuffer(params); 294 295 helper_->SetScheduled(false); 296 } else { 297 helper_->SendLatencyInfo(latency_info_); 298 } 299 return result; 300 } 301 302 bool PassThroughImageTransportSurface::OnMakeCurrent(gfx::GLContext* context) { 303 if (!did_set_swap_interval_) { 304 ImageTransportHelper::SetSwapInterval(context); 305 did_set_swap_interval_ = true; 306 } 307 return true; 308 } 309 310 void PassThroughImageTransportSurface::OnBufferPresented( 311 const AcceleratedSurfaceMsg_BufferPresented_Params& /* params */) { 312 DCHECK(transport_); 313 DCHECK(is_swap_buffers_pending_); 314 is_swap_buffers_pending_ = false; 315 if (did_unschedule_) { 316 did_unschedule_ = false; 317 helper_->SetScheduled(true); 318 } 319 } 320 321 void PassThroughImageTransportSurface::OnResizeViewACK() { 322 DCHECK(transport_); 323 Resize(new_size_); 324 325 TRACE_EVENT_ASYNC_END0("gpu", "OnResize", this); 326 helper_->SetScheduled(true); 327 } 328 329 void PassThroughImageTransportSurface::OnResize(gfx::Size size, 330 float scale_factor) { 331 new_size_ = size; 332 333 if (transport_) { 334 helper_->SendResizeView(size); 335 helper_->SetScheduled(false); 336 TRACE_EVENT_ASYNC_BEGIN2("gpu", "OnResize", this, 337 "width", size.width(), "height", size.height()); 338 } else { 339 Resize(new_size_); 340 } 341 } 342 343 gfx::Size PassThroughImageTransportSurface::GetSize() { 344 return GLSurfaceAdapter::GetSize(); 345 } 346 347 PassThroughImageTransportSurface::~PassThroughImageTransportSurface() {} 348 349 void PassThroughImageTransportSurface::SendVSyncUpdateIfAvailable() { 350 gfx::VSyncProvider* vsync_provider = GetVSyncProvider(); 351 if (vsync_provider) { 352 vsync_provider->GetVSyncParameters( 353 base::Bind(&ImageTransportHelper::SendUpdateVSyncParameters, 354 helper_->AsWeakPtr())); 355 } 356 } 357 358 } // namespace content 359