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