blob: 1cbfaf081749621702ccb9445269fa44188f4c1e [file] [log] [blame]
// 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.
#if defined(OS_WIN)
#include <windows.h>
#endif
#include "content/browser/renderer_host/gpu_message_filter.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
#include "content/browser/gpu/gpu_data_manager_impl_private.h"
#include "content/browser/gpu/gpu_process_host.h"
#include "content/browser/gpu/gpu_surface_tracker.h"
#include "content/browser/renderer_host/render_widget_helper.h"
#include "content/common/gpu/gpu_messages.h"
#include "content/public/browser/render_widget_host_view_frame_subscriber.h"
#include "content/public/common/content_switches.h"
#include "gpu/command_buffer/service/gpu_switches.h"
namespace content {
struct GpuMessageFilter::CreateViewCommandBufferRequest {
CreateViewCommandBufferRequest(
int32 surface_id,
const GPUCreateCommandBufferConfig& init_params,
scoped_ptr<IPC::Message> reply)
: surface_id(surface_id),
init_params(init_params),
reply(reply.Pass()) {
}
int32 surface_id;
GPUCreateCommandBufferConfig init_params;
scoped_ptr<IPC::Message> reply;
};
struct GpuMessageFilter::FrameSubscription {
FrameSubscription(
int in_route_id,
scoped_ptr<RenderWidgetHostViewFrameSubscriber> in_subscriber)
: route_id(in_route_id),
surface_id(0),
subscriber(in_subscriber.Pass()),
factory(subscriber.get()) {
}
int route_id;
int surface_id;
scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber;
base::WeakPtrFactory<RenderWidgetHostViewFrameSubscriber> factory;
};
GpuMessageFilter::GpuMessageFilter(int render_process_id,
RenderWidgetHelper* render_widget_helper)
: BrowserMessageFilter(GpuMsgStart),
gpu_process_id_(0),
render_process_id_(render_process_id),
render_widget_helper_(render_widget_helper),
weak_ptr_factory_(this) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
}
GpuMessageFilter::~GpuMessageFilter() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
EndAllFrameSubscriptions();
}
bool GpuMessageFilter::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(GpuMessageFilter, message)
IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuHostMsg_EstablishGpuChannel,
OnEstablishGpuChannel)
IPC_MESSAGE_HANDLER_DELAY_REPLY(GpuHostMsg_CreateViewCommandBuffer,
OnCreateViewCommandBuffer)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void GpuMessageFilter::BeginFrameSubscription(
int route_id,
scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
linked_ptr<FrameSubscription> subscription(
new FrameSubscription(route_id, subscriber.Pass()));
BeginFrameSubscriptionInternal(subscription);
}
void GpuMessageFilter::EndFrameSubscription(int route_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
FrameSubscriptionList frame_subscription_list;
frame_subscription_list.swap(frame_subscription_list_);
for (FrameSubscriptionList::iterator it = frame_subscription_list.begin();
it != frame_subscription_list.end(); ++it) {
if ((*it)->route_id != route_id)
frame_subscription_list_.push_back(*it);
else
EndFrameSubscriptionInternal(*it);
}
}
void GpuMessageFilter::OnEstablishGpuChannel(
CauseForGpuLaunch cause_for_gpu_launch,
IPC::Message* reply_ptr) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
scoped_ptr<IPC::Message> reply(reply_ptr);
// TODO(apatrick): Eventually, this will return the route ID of a
// GpuProcessStub, from which the renderer process will create a
// GpuProcessProxy. The renderer will use the proxy for all subsequent
// communication with the GPU process. This means if the GPU process
// terminates, the renderer process will not find itself unknowingly sending
// IPCs to a newly launched GPU process. Also, I will rename this function
// to something like OnCreateGpuProcess.
GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
if (!host) {
host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
cause_for_gpu_launch);
if (!host) {
reply->set_reply_error();
Send(reply.release());
return;
}
gpu_process_id_ = host->host_id();
// Apply all frame subscriptions to the new GpuProcessHost.
BeginAllFrameSubscriptions();
}
bool share_contexts = true;
host->EstablishGpuChannel(
render_process_id_,
share_contexts,
base::Bind(&GpuMessageFilter::EstablishChannelCallback,
weak_ptr_factory_.GetWeakPtr(),
base::Passed(&reply)));
}
void GpuMessageFilter::OnCreateViewCommandBuffer(
int32 surface_id,
const GPUCreateCommandBufferConfig& init_params,
int32 route_id,
IPC::Message* reply_ptr) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
scoped_ptr<IPC::Message> reply(reply_ptr);
GpuSurfaceTracker* surface_tracker = GpuSurfaceTracker::Get();
gfx::GLSurfaceHandle compositing_surface;
int renderer_id = 0;
int render_widget_id = 0;
bool result = surface_tracker->GetRenderWidgetIDForSurface(
surface_id, &renderer_id, &render_widget_id);
if (result && renderer_id == render_process_id_) {
compositing_surface = surface_tracker->GetSurfaceHandle(surface_id);
} else {
DLOG(ERROR) << "Renderer " << render_process_id_
<< " tried to access a surface for renderer " << renderer_id;
}
if (compositing_surface.parent_client_id &&
!GpuDataManagerImpl::GetInstance()->CanUseGpuBrowserCompositor()) {
// For the renderer to fall back to software also.
compositing_surface = gfx::GLSurfaceHandle();
}
GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
if (!host || compositing_surface.is_null()) {
// TODO(apatrick): Eventually, this IPC message will be routed to a
// GpuProcessStub with a particular routing ID. The error will be set if
// the GpuProcessStub with that routing ID is not in the MessageRouter.
reply->set_reply_error();
Send(reply.release());
return;
}
host->CreateViewCommandBuffer(
compositing_surface,
surface_id,
render_process_id_,
init_params,
route_id,
base::Bind(&GpuMessageFilter::CreateCommandBufferCallback,
weak_ptr_factory_.GetWeakPtr(),
base::Passed(&reply)));
}
void GpuMessageFilter::EstablishChannelCallback(
scoped_ptr<IPC::Message> reply,
const IPC::ChannelHandle& channel,
const gpu::GPUInfo& gpu_info) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
GpuHostMsg_EstablishGpuChannel::WriteReplyParams(
reply.get(), render_process_id_, channel, gpu_info);
Send(reply.release());
}
void GpuMessageFilter::CreateCommandBufferCallback(
scoped_ptr<IPC::Message> reply, CreateCommandBufferResult result) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
GpuHostMsg_CreateViewCommandBuffer::WriteReplyParams(reply.get(), result);
Send(reply.release());
}
void GpuMessageFilter::BeginAllFrameSubscriptions() {
FrameSubscriptionList frame_subscription_list;
frame_subscription_list.swap(frame_subscription_list_);
for (FrameSubscriptionList::iterator it = frame_subscription_list.begin();
it != frame_subscription_list.end(); ++it) {
BeginFrameSubscriptionInternal(*it);
}
}
void GpuMessageFilter::EndAllFrameSubscriptions() {
for (FrameSubscriptionList::iterator it = frame_subscription_list_.begin();
it != frame_subscription_list_.end(); ++it) {
EndFrameSubscriptionInternal(*it);
}
frame_subscription_list_.clear();
}
void GpuMessageFilter::BeginFrameSubscriptionInternal(
linked_ptr<FrameSubscription> subscription) {
if (!subscription->surface_id) {
GpuSurfaceTracker* surface_tracker = GpuSurfaceTracker::Get();
subscription->surface_id = surface_tracker->LookupSurfaceForRenderer(
render_process_id_, subscription->route_id);
// If the surface ID cannot be found this subscription is dropped.
if (!subscription->surface_id)
return;
}
frame_subscription_list_.push_back(subscription);
// Frame subscriber is owned by this object, but it is shared with
// GpuProcessHost. GpuProcessHost can be destroyed in the case of crashing
// and we do not get a signal. This object can also be destroyed independent
// of GpuProcessHost. To ensure that GpuProcessHost does not reference a
// deleted frame subscriber, a weak reference is shared.
GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
if (!host)
return;
host->BeginFrameSubscription(subscription->surface_id,
subscription->factory.GetWeakPtr());
}
void GpuMessageFilter::EndFrameSubscriptionInternal(
linked_ptr<FrameSubscription> subscription) {
GpuProcessHost* host = GpuProcessHost::FromID(gpu_process_id_);
// An empty surface ID means subscription has never started in GpuProcessHost
// so it is not necessary to end it.
if (!host || !subscription->surface_id)
return;
// Note that GpuProcessHost here might not be the same one that frame
// subscription has applied.
host->EndFrameSubscription(subscription->surface_id);
}
} // namespace content