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/gpu_channel_manager.h"
6
7#include "base/bind.h"
8#include "base/command_line.h"
9#include "content/common/gpu/gpu_channel.h"
10#include "content/common/gpu/gpu_memory_buffer_factory.h"
11#include "content/common/gpu/gpu_memory_manager.h"
12#include "content/common/gpu/gpu_messages.h"
13#include "content/common/gpu/sync_point_manager.h"
14#include "content/common/message_router.h"
15#include "gpu/command_buffer/service/feature_info.h"
16#include "gpu/command_buffer/service/gpu_switches.h"
17#include "gpu/command_buffer/service/mailbox_manager.h"
18#include "gpu/command_buffer/service/memory_program_cache.h"
19#include "gpu/command_buffer/service/shader_translator_cache.h"
20#include "ipc/message_filter.h"
21#include "ui/gl/gl_bindings.h"
22#include "ui/gl/gl_share_group.h"
23
24namespace content {
25
26namespace {
27
28class GpuChannelManagerMessageFilter : public IPC::MessageFilter {
29 public:
30  GpuChannelManagerMessageFilter(
31      GpuMemoryBufferFactory* gpu_memory_buffer_factory)
32      : sender_(NULL), gpu_memory_buffer_factory_(gpu_memory_buffer_factory) {}
33
34  virtual void OnFilterAdded(IPC::Sender* sender) OVERRIDE {
35    DCHECK(!sender_);
36    sender_ = sender;
37  }
38
39  virtual void OnFilterRemoved() OVERRIDE {
40    DCHECK(sender_);
41    sender_ = NULL;
42  }
43
44  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
45    DCHECK(sender_);
46    bool handled = true;
47    IPC_BEGIN_MESSAGE_MAP(GpuChannelManagerMessageFilter, message)
48      IPC_MESSAGE_HANDLER(GpuMsg_CreateGpuMemoryBuffer, OnCreateGpuMemoryBuffer)
49      IPC_MESSAGE_UNHANDLED(handled = false)
50    IPC_END_MESSAGE_MAP()
51    return handled;
52  }
53
54 protected:
55  virtual ~GpuChannelManagerMessageFilter() {}
56
57  void OnCreateGpuMemoryBuffer(const gfx::GpuMemoryBufferHandle& handle,
58                               const gfx::Size& size,
59                               unsigned internalformat,
60                               unsigned usage) {
61    TRACE_EVENT2("gpu",
62                 "GpuChannelManagerMessageFilter::OnCreateGpuMemoryBuffer",
63                 "primary_id",
64                 handle.global_id.primary_id,
65                 "secondary_id",
66                 handle.global_id.secondary_id);
67    sender_->Send(new GpuHostMsg_GpuMemoryBufferCreated(
68        gpu_memory_buffer_factory_->CreateGpuMemoryBuffer(
69            handle, size, internalformat, usage)));
70  }
71
72  IPC::Sender* sender_;
73  GpuMemoryBufferFactory* gpu_memory_buffer_factory_;
74};
75
76}  // namespace
77
78GpuChannelManager::GpuChannelManager(MessageRouter* router,
79                                     GpuWatchdog* watchdog,
80                                     base::MessageLoopProxy* io_message_loop,
81                                     base::WaitableEvent* shutdown_event,
82                                     IPC::SyncChannel* channel)
83    : io_message_loop_(io_message_loop),
84      shutdown_event_(shutdown_event),
85      router_(router),
86      gpu_memory_manager_(
87          this,
88          GpuMemoryManager::kDefaultMaxSurfacesWithFrontbufferSoftLimit),
89      watchdog_(watchdog),
90      sync_point_manager_(new SyncPointManager),
91      gpu_memory_buffer_factory_(GpuMemoryBufferFactory::Create()),
92      channel_(channel),
93      filter_(new GpuChannelManagerMessageFilter(
94          gpu_memory_buffer_factory_.get())),
95      weak_factory_(this) {
96  DCHECK(router_);
97  DCHECK(io_message_loop);
98  DCHECK(shutdown_event);
99  channel_->AddFilter(filter_.get());
100}
101
102GpuChannelManager::~GpuChannelManager() {
103  gpu_channels_.clear();
104  if (default_offscreen_surface_.get()) {
105    default_offscreen_surface_->Destroy();
106    default_offscreen_surface_ = NULL;
107  }
108}
109
110gpu::gles2::ProgramCache* GpuChannelManager::program_cache() {
111  if (!program_cache_.get() &&
112      (gfx::g_driver_gl.ext.b_GL_ARB_get_program_binary ||
113       gfx::g_driver_gl.ext.b_GL_OES_get_program_binary) &&
114      !CommandLine::ForCurrentProcess()->HasSwitch(
115          switches::kDisableGpuProgramCache)) {
116    program_cache_.reset(new gpu::gles2::MemoryProgramCache());
117  }
118  return program_cache_.get();
119}
120
121gpu::gles2::ShaderTranslatorCache*
122GpuChannelManager::shader_translator_cache() {
123  if (!shader_translator_cache_.get())
124    shader_translator_cache_ = new gpu::gles2::ShaderTranslatorCache;
125  return shader_translator_cache_.get();
126}
127
128void GpuChannelManager::RemoveChannel(int client_id) {
129  Send(new GpuHostMsg_DestroyChannel(client_id));
130  gpu_channels_.erase(client_id);
131}
132
133int GpuChannelManager::GenerateRouteID() {
134  static int last_id = 0;
135  return ++last_id;
136}
137
138void GpuChannelManager::AddRoute(int32 routing_id, IPC::Listener* listener) {
139  router_->AddRoute(routing_id, listener);
140}
141
142void GpuChannelManager::RemoveRoute(int32 routing_id) {
143  router_->RemoveRoute(routing_id);
144}
145
146GpuChannel* GpuChannelManager::LookupChannel(int32 client_id) {
147  GpuChannelMap::const_iterator iter = gpu_channels_.find(client_id);
148  if (iter == gpu_channels_.end())
149    return NULL;
150  else
151    return iter->second;
152}
153
154bool GpuChannelManager::OnMessageReceived(const IPC::Message& msg) {
155  bool handled = true;
156  IPC_BEGIN_MESSAGE_MAP(GpuChannelManager, msg)
157    IPC_MESSAGE_HANDLER(GpuMsg_EstablishChannel, OnEstablishChannel)
158    IPC_MESSAGE_HANDLER(GpuMsg_CloseChannel, OnCloseChannel)
159    IPC_MESSAGE_HANDLER(GpuMsg_CreateViewCommandBuffer,
160                        OnCreateViewCommandBuffer)
161    IPC_MESSAGE_HANDLER(GpuMsg_DestroyGpuMemoryBuffer, OnDestroyGpuMemoryBuffer)
162    IPC_MESSAGE_HANDLER(GpuMsg_LoadedShader, OnLoadedShader)
163    IPC_MESSAGE_UNHANDLED(handled = false)
164  IPC_END_MESSAGE_MAP()
165  return handled;
166}
167
168bool GpuChannelManager::Send(IPC::Message* msg) { return router_->Send(msg); }
169
170void GpuChannelManager::OnEstablishChannel(int client_id,
171                                           bool share_context,
172                                           bool allow_future_sync_points) {
173  IPC::ChannelHandle channel_handle;
174
175  gfx::GLShareGroup* share_group = NULL;
176  gpu::gles2::MailboxManager* mailbox_manager = NULL;
177  if (share_context) {
178    if (!share_group_.get()) {
179      share_group_ = new gfx::GLShareGroup;
180      DCHECK(!mailbox_manager_.get());
181      mailbox_manager_ = new gpu::gles2::MailboxManager;
182    }
183    share_group = share_group_.get();
184    mailbox_manager = mailbox_manager_.get();
185  }
186
187  scoped_ptr<GpuChannel> channel(new GpuChannel(this,
188                                                watchdog_,
189                                                share_group,
190                                                mailbox_manager,
191                                                client_id,
192                                                false,
193                                                allow_future_sync_points));
194  channel->Init(io_message_loop_.get(), shutdown_event_);
195  channel_handle.name = channel->GetChannelName();
196
197#if defined(OS_POSIX)
198  // On POSIX, pass the renderer-side FD. Also mark it as auto-close so
199  // that it gets closed after it has been sent.
200  int renderer_fd = channel->TakeRendererFileDescriptor();
201  DCHECK_NE(-1, renderer_fd);
202  channel_handle.socket = base::FileDescriptor(renderer_fd, true);
203#endif
204
205  gpu_channels_.set(client_id, channel.Pass());
206
207  Send(new GpuHostMsg_ChannelEstablished(channel_handle));
208}
209
210void GpuChannelManager::OnCloseChannel(
211    const IPC::ChannelHandle& channel_handle) {
212  for (GpuChannelMap::iterator iter = gpu_channels_.begin();
213       iter != gpu_channels_.end(); ++iter) {
214    if (iter->second->GetChannelName() == channel_handle.name) {
215      gpu_channels_.erase(iter);
216      return;
217    }
218  }
219}
220
221void GpuChannelManager::OnCreateViewCommandBuffer(
222    const gfx::GLSurfaceHandle& window,
223    int32 surface_id,
224    int32 client_id,
225    const GPUCreateCommandBufferConfig& init_params,
226    int32 route_id) {
227  DCHECK(surface_id);
228  CreateCommandBufferResult result = CREATE_COMMAND_BUFFER_FAILED;
229
230  GpuChannelMap::const_iterator iter = gpu_channels_.find(client_id);
231  if (iter != gpu_channels_.end()) {
232    result = iter->second->CreateViewCommandBuffer(
233        window, surface_id, init_params, route_id);
234  }
235
236  Send(new GpuHostMsg_CommandBufferCreated(result));
237}
238void GpuChannelManager::DestroyGpuMemoryBuffer(
239    const gfx::GpuMemoryBufferHandle& handle) {
240  io_message_loop_->PostTask(
241      FROM_HERE,
242      base::Bind(&GpuChannelManager::DestroyGpuMemoryBufferOnIO,
243                 base::Unretained(this),
244                 handle));
245}
246
247void GpuChannelManager::DestroyGpuMemoryBufferOnIO(
248    const gfx::GpuMemoryBufferHandle& handle) {
249  gpu_memory_buffer_factory_->DestroyGpuMemoryBuffer(handle);
250}
251
252void GpuChannelManager::OnDestroyGpuMemoryBuffer(
253    const gfx::GpuMemoryBufferHandle& handle,
254    int32 sync_point) {
255  if (!sync_point) {
256    DestroyGpuMemoryBuffer(handle);
257  } else {
258    sync_point_manager()->AddSyncPointCallback(
259        sync_point,
260        base::Bind(&GpuChannelManager::DestroyGpuMemoryBuffer,
261                   base::Unretained(this),
262                   handle));
263  }
264}
265
266void GpuChannelManager::OnLoadedShader(std::string program_proto) {
267  if (program_cache())
268    program_cache()->LoadProgram(program_proto);
269}
270
271bool GpuChannelManager::HandleMessagesScheduled() {
272  for (GpuChannelMap::iterator iter = gpu_channels_.begin();
273       iter != gpu_channels_.end(); ++iter) {
274    if (iter->second->handle_messages_scheduled())
275      return true;
276  }
277  return false;
278}
279
280uint64 GpuChannelManager::MessagesProcessed() {
281  uint64 messages_processed = 0;
282
283  for (GpuChannelMap::iterator iter = gpu_channels_.begin();
284       iter != gpu_channels_.end(); ++iter) {
285    messages_processed += iter->second->messages_processed();
286  }
287  return messages_processed;
288}
289
290void GpuChannelManager::LoseAllContexts() {
291  for (GpuChannelMap::iterator iter = gpu_channels_.begin();
292       iter != gpu_channels_.end(); ++iter) {
293    iter->second->MarkAllContextsLost();
294  }
295  base::MessageLoop::current()->PostTask(
296      FROM_HERE,
297      base::Bind(&GpuChannelManager::OnLoseAllContexts,
298                 weak_factory_.GetWeakPtr()));
299}
300
301void GpuChannelManager::OnLoseAllContexts() {
302  gpu_channels_.clear();
303}
304
305gfx::GLSurface* GpuChannelManager::GetDefaultOffscreenSurface() {
306  if (!default_offscreen_surface_.get()) {
307    default_offscreen_surface_ =
308        gfx::GLSurface::CreateOffscreenGLSurface(gfx::Size());
309  }
310  return default_offscreen_surface_.get();
311}
312
313}  // namespace content
314