| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/common/gpu/image_transport_surface.h" |
| |
| #include "base/bind.h" |
| #include "base/bind_helpers.h" |
| #include "base/command_line.h" |
| #include "base/debug/trace_event.h" |
| #include "content/common/gpu/gpu_channel.h" |
| #include "content/common/gpu/gpu_channel_manager.h" |
| #include "content/common/gpu/gpu_command_buffer_stub.h" |
| #include "content/common/gpu/gpu_messages.h" |
| #include "content/common/gpu/sync_point_manager.h" |
| #include "content/common/gpu/texture_image_transport_surface.h" |
| #include "gpu/command_buffer/service/gpu_scheduler.h" |
| #include "ui/gfx/vsync_provider.h" |
| #include "ui/gl/gl_implementation.h" |
| #include "ui/gl/gl_switches.h" |
| |
| #if defined(OS_WIN) |
| #include "ui/base/win/shell.h" |
| #endif |
| |
| namespace content { |
| |
| ImageTransportSurface::ImageTransportSurface() {} |
| |
| ImageTransportSurface::~ImageTransportSurface() {} |
| |
| scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateSurface( |
| GpuChannelManager* manager, |
| GpuCommandBufferStub* stub, |
| const gfx::GLSurfaceHandle& handle) { |
| scoped_refptr<gfx::GLSurface> surface; |
| if (handle.transport_type == gfx::TEXTURE_TRANSPORT) |
| surface = new TextureImageTransportSurface(manager, stub, handle); |
| else |
| surface = CreateNativeSurface(manager, stub, handle); |
| |
| if (!surface.get() || !surface->Initialize()) |
| return NULL; |
| return surface; |
| } |
| |
| ImageTransportHelper::ImageTransportHelper(ImageTransportSurface* surface, |
| GpuChannelManager* manager, |
| GpuCommandBufferStub* stub, |
| gfx::PluginWindowHandle handle) |
| : surface_(surface), |
| manager_(manager), |
| stub_(stub->AsWeakPtr()), |
| handle_(handle) { |
| route_id_ = manager_->GenerateRouteID(); |
| manager_->AddRoute(route_id_, this); |
| } |
| |
| ImageTransportHelper::~ImageTransportHelper() { |
| if (stub_.get()) { |
| stub_->SetLatencyInfoCallback( |
| base::Callback<void(const std::vector<ui::LatencyInfo>&)>()); |
| } |
| manager_->RemoveRoute(route_id_); |
| } |
| |
| bool ImageTransportHelper::Initialize() { |
| gpu::gles2::GLES2Decoder* decoder = Decoder(); |
| |
| if (!decoder) |
| return false; |
| |
| decoder->SetResizeCallback( |
| base::Bind(&ImageTransportHelper::Resize, base::Unretained(this))); |
| |
| stub_->SetLatencyInfoCallback( |
| base::Bind(&ImageTransportHelper::SetLatencyInfo, |
| base::Unretained(this))); |
| |
| manager_->Send(new GpuHostMsg_AcceleratedSurfaceInitialized( |
| stub_->surface_id(), route_id_)); |
| |
| return true; |
| } |
| |
| void ImageTransportHelper::Destroy() {} |
| |
| bool ImageTransportHelper::OnMessageReceived(const IPC::Message& message) { |
| bool handled = true; |
| IPC_BEGIN_MESSAGE_MAP(ImageTransportHelper, message) |
| IPC_MESSAGE_HANDLER(AcceleratedSurfaceMsg_BufferPresented, |
| OnBufferPresented) |
| IPC_MESSAGE_HANDLER(AcceleratedSurfaceMsg_WakeUpGpu, OnWakeUpGpu); |
| IPC_MESSAGE_UNHANDLED(handled = false) |
| IPC_END_MESSAGE_MAP() |
| return handled; |
| } |
| |
| void ImageTransportHelper::SendAcceleratedSurfaceBuffersSwapped( |
| GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params) { |
| // TRACE_EVENT for gpu tests: |
| TRACE_EVENT_INSTANT2("test_gpu", "SwapBuffers", |
| TRACE_EVENT_SCOPE_THREAD, |
| "GLImpl", static_cast<int>(gfx::GetGLImplementation()), |
| "width", params.size.width()); |
| params.surface_id = stub_->surface_id(); |
| params.route_id = route_id_; |
| manager_->Send(new GpuHostMsg_AcceleratedSurfaceBuffersSwapped(params)); |
| } |
| |
| void ImageTransportHelper::SendAcceleratedSurfacePostSubBuffer( |
| GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params params) { |
| params.surface_id = stub_->surface_id(); |
| params.route_id = route_id_; |
| manager_->Send(new GpuHostMsg_AcceleratedSurfacePostSubBuffer(params)); |
| } |
| |
| void ImageTransportHelper::SendAcceleratedSurfaceRelease() { |
| GpuHostMsg_AcceleratedSurfaceRelease_Params params; |
| params.surface_id = stub_->surface_id(); |
| manager_->Send(new GpuHostMsg_AcceleratedSurfaceRelease(params)); |
| } |
| |
| void ImageTransportHelper::SendUpdateVSyncParameters( |
| base::TimeTicks timebase, base::TimeDelta interval) { |
| manager_->Send(new GpuHostMsg_UpdateVSyncParameters(stub_->surface_id(), |
| timebase, |
| interval)); |
| } |
| |
| void ImageTransportHelper::SendLatencyInfo( |
| const std::vector<ui::LatencyInfo>& latency_info) { |
| manager_->Send(new GpuHostMsg_FrameDrawn(latency_info)); |
| } |
| |
| void ImageTransportHelper::SetScheduled(bool is_scheduled) { |
| gpu::GpuScheduler* scheduler = Scheduler(); |
| if (!scheduler) |
| return; |
| |
| scheduler->SetScheduled(is_scheduled); |
| } |
| |
| void ImageTransportHelper::DeferToFence(base::Closure task) { |
| gpu::GpuScheduler* scheduler = Scheduler(); |
| DCHECK(scheduler); |
| |
| scheduler->DeferToFence(task); |
| } |
| |
| void ImageTransportHelper::SetPreemptByFlag( |
| scoped_refptr<gpu::PreemptionFlag> preemption_flag) { |
| stub_->channel()->SetPreemptByFlag(preemption_flag); |
| } |
| |
| bool ImageTransportHelper::MakeCurrent() { |
| gpu::gles2::GLES2Decoder* decoder = Decoder(); |
| if (!decoder) |
| return false; |
| return decoder->MakeCurrent(); |
| } |
| |
| void ImageTransportHelper::SetSwapInterval(gfx::GLContext* context) { |
| #if defined(OS_WIN) |
| // If Aero Glass is enabled, then the renderer will handle ratelimiting and |
| // there's no tearing, so waiting for vsync is unnecessary. |
| if (ui::win::IsAeroGlassEnabled()) { |
| context->SetSwapInterval(0); |
| return; |
| } |
| #endif |
| if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync)) |
| context->SetSwapInterval(0); |
| else |
| context->SetSwapInterval(1); |
| } |
| |
| void ImageTransportHelper::Suspend() { |
| manager_->Send(new GpuHostMsg_AcceleratedSurfaceSuspend(stub_->surface_id())); |
| } |
| |
| gpu::GpuScheduler* ImageTransportHelper::Scheduler() { |
| if (!stub_.get()) |
| return NULL; |
| return stub_->scheduler(); |
| } |
| |
| gpu::gles2::GLES2Decoder* ImageTransportHelper::Decoder() { |
| if (!stub_.get()) |
| return NULL; |
| return stub_->decoder(); |
| } |
| |
| void ImageTransportHelper::OnBufferPresented( |
| const AcceleratedSurfaceMsg_BufferPresented_Params& params) { |
| surface_->OnBufferPresented(params); |
| } |
| |
| void ImageTransportHelper::OnWakeUpGpu() { |
| surface_->WakeUpGpu(); |
| } |
| |
| void ImageTransportHelper::Resize(gfx::Size size, float scale_factor) { |
| surface_->OnResize(size, scale_factor); |
| |
| #if defined(OS_ANDROID) |
| manager_->gpu_memory_manager()->ScheduleManage( |
| GpuMemoryManager::kScheduleManageNow); |
| #endif |
| } |
| |
| void ImageTransportHelper::SetLatencyInfo( |
| const std::vector<ui::LatencyInfo>& latency_info) { |
| surface_->SetLatencyInfo(latency_info); |
| } |
| |
| PassThroughImageTransportSurface::PassThroughImageTransportSurface( |
| GpuChannelManager* manager, |
| GpuCommandBufferStub* stub, |
| gfx::GLSurface* surface) |
| : GLSurfaceAdapter(surface), |
| did_set_swap_interval_(false) { |
| helper_.reset(new ImageTransportHelper(this, |
| manager, |
| stub, |
| gfx::kNullPluginWindow)); |
| } |
| |
| bool PassThroughImageTransportSurface::Initialize() { |
| // The surface is assumed to have already been initialized. |
| return helper_->Initialize(); |
| } |
| |
| void PassThroughImageTransportSurface::Destroy() { |
| helper_->Destroy(); |
| GLSurfaceAdapter::Destroy(); |
| } |
| |
| void PassThroughImageTransportSurface::SetLatencyInfo( |
| const std::vector<ui::LatencyInfo>& latency_info) { |
| for (size_t i = 0; i < latency_info.size(); i++) |
| latency_info_.push_back(latency_info[i]); |
| } |
| |
| bool PassThroughImageTransportSurface::SwapBuffers() { |
| // GetVsyncValues before SwapBuffers to work around Mali driver bug: |
| // crbug.com/223558. |
| SendVSyncUpdateIfAvailable(); |
| bool result = gfx::GLSurfaceAdapter::SwapBuffers(); |
| for (size_t i = 0; i < latency_info_.size(); i++) { |
| latency_info_[i].AddLatencyNumber( |
| ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0); |
| } |
| |
| helper_->SendLatencyInfo(latency_info_); |
| latency_info_.clear(); |
| return result; |
| } |
| |
| bool PassThroughImageTransportSurface::PostSubBuffer( |
| int x, int y, int width, int height) { |
| SendVSyncUpdateIfAvailable(); |
| bool result = gfx::GLSurfaceAdapter::PostSubBuffer(x, y, width, height); |
| for (size_t i = 0; i < latency_info_.size(); i++) { |
| latency_info_[i].AddLatencyNumber( |
| ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0); |
| } |
| |
| helper_->SendLatencyInfo(latency_info_); |
| latency_info_.clear(); |
| return result; |
| } |
| |
| bool PassThroughImageTransportSurface::OnMakeCurrent(gfx::GLContext* context) { |
| if (!did_set_swap_interval_) { |
| ImageTransportHelper::SetSwapInterval(context); |
| did_set_swap_interval_ = true; |
| } |
| return true; |
| } |
| |
| void PassThroughImageTransportSurface::OnBufferPresented( |
| const AcceleratedSurfaceMsg_BufferPresented_Params& /* params */) { |
| NOTREACHED(); |
| } |
| |
| void PassThroughImageTransportSurface::OnResize(gfx::Size size, |
| float scale_factor) { |
| Resize(size); |
| } |
| |
| gfx::Size PassThroughImageTransportSurface::GetSize() { |
| return GLSurfaceAdapter::GetSize(); |
| } |
| |
| void PassThroughImageTransportSurface::WakeUpGpu() { |
| NOTIMPLEMENTED(); |
| } |
| |
| PassThroughImageTransportSurface::~PassThroughImageTransportSurface() {} |
| |
| void PassThroughImageTransportSurface::SendVSyncUpdateIfAvailable() { |
| gfx::VSyncProvider* vsync_provider = GetVSyncProvider(); |
| if (vsync_provider) { |
| vsync_provider->GetVSyncParameters( |
| base::Bind(&ImageTransportHelper::SendUpdateVSyncParameters, |
| helper_->AsWeakPtr())); |
| } |
| } |
| |
| } // namespace content |