// 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/browser/gpu/gpu_process_host_ui_shim.h" #include #include "base/bind.h" #include "base/callback_helpers.h" #include "base/id_map.h" #include "base/lazy_instance.h" #include "base/strings/string_number_conversions.h" #include "base/trace_event/trace_event.h" #include "content/browser/compositor/gpu_process_transport_factory.h" #include "content/browser/gpu/compositor_util.h" #include "content/browser/gpu/gpu_data_manager_impl.h" #include "content/browser/gpu/gpu_process_host.h" #include "content/browser/gpu/gpu_surface_tracker.h" #include "content/browser/renderer_host/render_process_host_impl.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/renderer_host/render_widget_helper.h" #include "content/browser/renderer_host/render_widget_host_view_base.h" #include "content/common/gpu/gpu_messages.h" #include "content/public/browser/browser_thread.h" #if defined(OS_MACOSX) #include "content/browser/browser_io_surface_manager_mac.h" #include "ui/accelerated_widget_mac/accelerated_widget_mac.h" #endif #if defined(USE_OZONE) #include "ui/ozone/public/gpu_platform_support_host.h" #include "ui/ozone/public/ozone_platform.h" #endif namespace content { namespace { // One of the linux specific headers defines this as a macro. #ifdef DestroyAll #undef DestroyAll #endif base::LazyInstance > g_hosts_by_id = LAZY_INSTANCE_INITIALIZER; void SendOnIOThreadTask(int host_id, IPC::Message* msg) { GpuProcessHost* host = GpuProcessHost::FromID(host_id); if (host) host->Send(msg); else delete msg; } void StopGpuProcessOnIO(int host_id) { GpuProcessHost* host = GpuProcessHost::FromID(host_id); if (host) host->StopGpuProcess(); } } // namespace void RouteToGpuProcessHostUIShimTask(int host_id, const IPC::Message& msg) { GpuProcessHostUIShim* ui_shim = GpuProcessHostUIShim::FromID(host_id); if (ui_shim) ui_shim->OnMessageReceived(msg); } GpuProcessHostUIShim::GpuProcessHostUIShim(int host_id) : host_id_(host_id) { g_hosts_by_id.Pointer()->AddWithID(this, host_id_); #if defined(USE_OZONE) ui::OzonePlatform::GetInstance() ->GetGpuPlatformSupportHost() ->OnChannelEstablished( host_id, BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO), base::Bind(&SendOnIOThreadTask, host_id_)); #endif } // static GpuProcessHostUIShim* GpuProcessHostUIShim::Create(int host_id) { DCHECK(!FromID(host_id)); return new GpuProcessHostUIShim(host_id); } // static void GpuProcessHostUIShim::Destroy(int host_id, const std::string& message) { DCHECK_CURRENTLY_ON(BrowserThread::UI); GpuDataManagerImpl::GetInstance()->AddLogMessage( logging::LOG_ERROR, "GpuProcessHostUIShim", message); #if defined(USE_OZONE) ui::OzonePlatform::GetInstance() ->GetGpuPlatformSupportHost() ->OnChannelDestroyed(host_id); #endif delete FromID(host_id); } // static void GpuProcessHostUIShim::DestroyAll() { DCHECK_CURRENTLY_ON(BrowserThread::UI); while (!g_hosts_by_id.Pointer()->IsEmpty()) { IDMap::iterator it(g_hosts_by_id.Pointer()); delete it.GetCurrentValue(); } } // static GpuProcessHostUIShim* GpuProcessHostUIShim::FromID(int host_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); return g_hosts_by_id.Pointer()->Lookup(host_id); } // static GpuProcessHostUIShim* GpuProcessHostUIShim::GetOneInstance() { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (g_hosts_by_id.Pointer()->IsEmpty()) return NULL; IDMap::iterator it(g_hosts_by_id.Pointer()); return it.GetCurrentValue(); } bool GpuProcessHostUIShim::Send(IPC::Message* msg) { DCHECK(CalledOnValidThread()); return BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(&SendOnIOThreadTask, host_id_, msg)); } bool GpuProcessHostUIShim::OnMessageReceived(const IPC::Message& message) { DCHECK(CalledOnValidThread()); #if defined(USE_OZONE) if (ui::OzonePlatform::GetInstance() ->GetGpuPlatformSupportHost() ->OnMessageReceived(message)) return true; #endif if (message.routing_id() != MSG_ROUTING_CONTROL) return false; return OnControlMessageReceived(message); } void GpuProcessHostUIShim::StopGpuProcess(const base::Closure& callback) { close_callback_ = callback; BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&StopGpuProcessOnIO, host_id_)); } void GpuProcessHostUIShim::SimulateRemoveAllContext() { Send(new GpuMsg_Clean()); } void GpuProcessHostUIShim::SimulateCrash() { Send(new GpuMsg_Crash()); } void GpuProcessHostUIShim::SimulateHang() { Send(new GpuMsg_Hang()); } GpuProcessHostUIShim::~GpuProcessHostUIShim() { DCHECK(CalledOnValidThread()); if (!close_callback_.is_null()) base::ResetAndReturn(&close_callback_).Run(); g_hosts_by_id.Pointer()->Remove(host_id_); } bool GpuProcessHostUIShim::OnControlMessageReceived( const IPC::Message& message) { DCHECK(CalledOnValidThread()); IPC_BEGIN_MESSAGE_MAP(GpuProcessHostUIShim, message) IPC_MESSAGE_HANDLER(GpuHostMsg_OnLogMessage, OnLogMessage) #if defined(OS_MACOSX) IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped, OnAcceleratedSurfaceBuffersSwapped) #endif IPC_MESSAGE_HANDLER(GpuHostMsg_GraphicsInfoCollected, OnGraphicsInfoCollected) IPC_MESSAGE_HANDLER(GpuHostMsg_VideoMemoryUsageStats, OnVideoMemoryUsageStatsReceived); IPC_MESSAGE_HANDLER(GpuHostMsg_AddSubscription, OnAddSubscription); IPC_MESSAGE_HANDLER(GpuHostMsg_RemoveSubscription, OnRemoveSubscription); IPC_MESSAGE_UNHANDLED_ERROR() IPC_END_MESSAGE_MAP() return true; } void GpuProcessHostUIShim::OnLogMessage( int level, const std::string& header, const std::string& message) { GpuDataManagerImpl::GetInstance()->AddLogMessage( level, header, message); } void GpuProcessHostUIShim::OnGraphicsInfoCollected( const gpu::GPUInfo& gpu_info) { // OnGraphicsInfoCollected is sent back after the GPU process successfully // initializes GL. TRACE_EVENT0("test_gpu", "OnGraphicsInfoCollected"); GpuDataManagerImpl::GetInstance()->UpdateGpuInfo(gpu_info); } #if defined(OS_MACOSX) void GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped( const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params) { TRACE_EVENT0("renderer", "GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped"); if (!ui::LatencyInfo::Verify(params.latency_info, "GpuHostMsg_AcceleratedSurfaceBuffersSwapped")) { return; } // On Mac with delegated rendering, accelerated surfaces are not necessarily // associated with a RenderWidgetHostViewBase. AcceleratedSurfaceMsg_BufferPresented_Params ack_params; // If the frame was intended for an NSView that the gfx::AcceleratedWidget is // no longer attached to, do not pass the frame along to the widget. Just ack // it to the GPU process immediately, so we can proceed to the next frame. bool should_not_show_frame = content::ImageTransportFactory::GetInstance() ->SurfaceShouldNotShowFramesAfterSuspendForRecycle(params.surface_id); if (!should_not_show_frame) { gfx::AcceleratedWidget native_widget = content::GpuSurfaceTracker::Get()->AcquireNativeWidget( params.surface_id); base::ScopedCFTypeRef io_surface; CAContextID ca_context_id = 0; switch (ui::GetSurfaceHandleType(params.surface_handle)) { case ui::kSurfaceHandleTypeIOSurface: { IOSurfaceID io_surface_id = ui::IOSurfaceIDFromSurfaceHandle(params.surface_handle); io_surface.reset( BrowserIOSurfaceManager::GetInstance()->AcquireIOSurface( gfx::GenericSharedMemoryId(io_surface_id))); break; } case ui::kSurfaceHandleTypeCAContext: { ca_context_id = ui::CAContextIDFromSurfaceHandle(params.surface_handle); break; } default: DLOG(ERROR) << "Unrecognized accelerated frame type."; return; } ui::AcceleratedWidgetMacGotFrame(native_widget, ca_context_id, io_surface, params.size, params.scale_factor, &ack_params.vsync_timebase, &ack_params.vsync_interval); } content::ImageTransportFactory::GetInstance()->OnGpuSwapBuffersCompleted( params.surface_id, params.latency_info, gfx::SwapResult::SWAP_ACK); Send(new AcceleratedSurfaceMsg_BufferPresented(params.route_id, ack_params)); } #endif void GpuProcessHostUIShim::OnVideoMemoryUsageStatsReceived( const GPUVideoMemoryUsageStats& video_memory_usage_stats) { GpuDataManagerImpl::GetInstance()->UpdateVideoMemoryUsageStats( video_memory_usage_stats); } void GpuProcessHostUIShim::OnAddSubscription( int32 process_id, unsigned int target) { RenderProcessHost* rph = RenderProcessHost::FromID(process_id); if (rph) { rph->OnAddSubscription(target); } } void GpuProcessHostUIShim::OnRemoveSubscription( int32 process_id, unsigned int target) { RenderProcessHost* rph = RenderProcessHost::FromID(process_id); if (rph) { rph->OnRemoveSubscription(target); } } } // namespace content