Logo Search packages:      
Sourcecode: chromium-browser version File versions  Download package

gpu_channel.cc

// Copyright (c) 2010 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 "chrome/gpu/gpu_channel.h"

#include "base/command_line.h"
#include "base/lock.h"
#include "base/process_util.h"
#include "base/string_util.h"
#include "base/waitable_event.h"
#include "build/build_config.h"
#include "chrome/common/child_process.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/gpu_messages.h"
#include "chrome/gpu/gpu_thread.h"

#if defined(OS_POSIX)
#include "ipc/ipc_channel_posix.h"
#endif

GpuChannel::GpuChannel(int renderer_id)
    : renderer_id_(renderer_id)
#if defined(OS_POSIX)
    , renderer_fd_(-1)
#endif
{
  const CommandLine* command_line = CommandLine::ForCurrentProcess();
  log_messages_ = command_line->HasSwitch(switches::kLogPluginMessages);
}

GpuChannel::~GpuChannel() {
#if defined(OS_POSIX)
  // If we still have the renderer FD, close it.
  if (renderer_fd_ != -1) {
    close(renderer_fd_);
  }
#endif
}

void GpuChannel::OnChannelConnected(int32 peer_pid) {
  if (!renderer_process_.Open(peer_pid)) {
    NOTREACHED();
  }
}

void GpuChannel::OnMessageReceived(const IPC::Message& message) {
  if (log_messages_) {
    LOG(INFO) << "received message @" << &message << " on channel @" << this
              << " with type " << message.type();
  }

  if (message.routing_id() == MSG_ROUTING_CONTROL) {
    OnControlMessageReceived(message);
  } else {
    // The sender should know not to route messages to an object after it
    // has been destroyed.
    CHECK(router_.RouteMessage(message));
  }
}

void GpuChannel::OnChannelError() {
  static_cast<GpuThread*>(ChildThread::current())->RemoveChannel(renderer_id_);
}

bool GpuChannel::Send(IPC::Message* message) {
  if (log_messages_) {
    LOG(INFO) << "sending message @" << message << " on channel @" << this
              << " with type " << message->type();
  }

  if (!channel_.get()) {
    delete message;
    return false;
  }

  return channel_->Send(message);
}

void GpuChannel::OnControlMessageReceived(const IPC::Message& msg) {
  IPC_BEGIN_MESSAGE_MAP(GpuChannel, msg)
    IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateViewCommandBuffer,
        OnCreateViewCommandBuffer)
    IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateOffscreenCommandBuffer,
        OnCreateOffscreenCommandBuffer)
    IPC_MESSAGE_HANDLER(GpuChannelMsg_DestroyCommandBuffer,
        OnDestroyCommandBuffer)
    IPC_MESSAGE_UNHANDLED_ERROR()
  IPC_END_MESSAGE_MAP()
}

int GpuChannel::GenerateRouteID() {
  static int last_id = 0;
  return ++last_id;
}

void GpuChannel::OnCreateViewCommandBuffer(gfx::NativeViewId view_id,
                                           int32* route_id) {
  *route_id = 0;

#if defined(ENABLE_GPU)

  gfx::PluginWindowHandle handle = NULL;
#if defined(OS_WIN)
  gfx::NativeView view = gfx::NativeViewFromId(view_id);

  // Check that the calling renderer is allowed to render to this window.
  // TODO(apatrick): consider killing the renderer process rather than failing.
  int view_renderer_id = reinterpret_cast<int>(
      GetProp(view, chrome::kChromiumRendererIdProperty));
  if (view_renderer_id != renderer_id_)
    return;
  handle = view;
#elif defined(OS_LINUX)
  ChildThread* gpu_thread = ChildThread::current();
  // Ask the browser for the view's XID.
  // TODO(piman): This assumes that it doesn't change. It can change however
  // when tearing off tabs. This needs a fix in the browser UI code. A possible
  // alternative would be to add a socket/plug pair like with plugins but that
  // has issues with events and focus.
  gpu_thread->Send(new GpuHostMsg_GetViewXID(view_id, &handle));
#else
  // TODO(apatrick): This needs to be something valid for mac and linux.
  // Offscreen rendering will work on these platforms but not rendering to the
  // window.
  DCHECK_EQ(view_id, 0);
#endif

  *route_id = GenerateRouteID();
  scoped_ptr<GpuCommandBufferStub> stub(new GpuCommandBufferStub(
      this, handle, NULL, gfx::Size(), 0, *route_id));
  router_.AddRoute(*route_id, stub.get());
  stubs_.AddWithID(stub.release(), *route_id);
#endif  // ENABLE_GPU
}

void GpuChannel::OnCreateOffscreenCommandBuffer(int32 parent_route_id,
                                                const gfx::Size& size,
                                                uint32 parent_texture_id,
                                                int32* route_id) {
#if defined(ENABLE_GPU)
  *route_id = GenerateRouteID();
  GpuCommandBufferStub* parent_stub = NULL;
  if (parent_route_id != 0)
    parent_stub = stubs_.Lookup(parent_route_id);

  scoped_ptr<GpuCommandBufferStub> stub(new GpuCommandBufferStub(
      this,
      NULL,
      parent_stub,
      size,
      parent_texture_id,
      *route_id));
  router_.AddRoute(*route_id, stub.get());
  stubs_.AddWithID(stub.release(), *route_id);
#else
  *route_id = 0;
#endif
}

void GpuChannel::OnDestroyCommandBuffer(int32 route_id) {
#if defined(ENABLE_GPU)
  router_.RemoveRoute(route_id);
  stubs_.Remove(route_id);
#endif
}

bool GpuChannel::Init() {
  // Check whether we're already initialized.
  if (channel_.get())
    return true;

  // Map renderer ID to a (single) channel to that process.
  std::string channel_name = GetChannelName();
#if defined(OS_POSIX)
  // This gets called when the GpuChannel is initially created. At this
  // point, create the socketpair and assign the GPU side FD to the channel
  // name. Keep the renderer side FD as a member variable in the PluginChannel
  // to be able to transmit it through IPC.
  int gpu_fd;
  IPC::SocketPair(&gpu_fd, &renderer_fd_);
  IPC::AddChannelSocket(channel_name, gpu_fd);
#endif
  channel_.reset(new IPC::SyncChannel(
      channel_name, IPC::Channel::MODE_SERVER, this, NULL,
      ChildProcess::current()->io_message_loop(), false,
      ChildProcess::current()->GetShutDownEvent()));
  return true;
}

std::string GpuChannel::GetChannelName() {
  return StringPrintf("%d.r%d", base::GetCurrentProcId(), renderer_id_);
}

Generated by  Doxygen 1.6.0   Back to index