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/child/child_thread.h"
10#include "content/common/gpu/gpu_channel.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 "gpu/command_buffer/service/feature_info.h"
15#include "gpu/command_buffer/service/gpu_switches.h"
16#include "gpu/command_buffer/service/mailbox_manager.h"
17#include "gpu/command_buffer/service/memory_program_cache.h"
18#include "ui/gl/gl_bindings.h"
19#include "ui/gl/gl_share_group.h"
20
21namespace content {
22
23GpuChannelManager::ImageOperation::ImageOperation(
24    int32 sync_point, base::Closure callback)
25    : sync_point(sync_point),
26      callback(callback) {
27}
28
29GpuChannelManager::ImageOperation::~ImageOperation() {
30}
31
32GpuChannelManager::GpuChannelManager(ChildThread* gpu_child_thread,
33                                     GpuWatchdog* watchdog,
34                                     base::MessageLoopProxy* io_message_loop,
35                                     base::WaitableEvent* shutdown_event)
36    : weak_factory_(this),
37      io_message_loop_(io_message_loop),
38      shutdown_event_(shutdown_event),
39      gpu_child_thread_(gpu_child_thread),
40      gpu_memory_manager_(
41          this,
42          GpuMemoryManager::kDefaultMaxSurfacesWithFrontbufferSoftLimit),
43      watchdog_(watchdog),
44      sync_point_manager_(new SyncPointManager) {
45  DCHECK(gpu_child_thread);
46  DCHECK(io_message_loop);
47  DCHECK(shutdown_event);
48}
49
50GpuChannelManager::~GpuChannelManager() {
51  gpu_channels_.clear();
52  if (default_offscreen_surface_.get()) {
53    default_offscreen_surface_->Destroy();
54    default_offscreen_surface_ = NULL;
55  }
56  DCHECK(image_operations_.empty());
57}
58
59gpu::gles2::ProgramCache* GpuChannelManager::program_cache() {
60  if (!program_cache_.get() &&
61      (gfx::g_driver_gl.ext.b_ARB_get_program_binary ||
62       gfx::g_driver_gl.ext.b_OES_get_program_binary) &&
63      !CommandLine::ForCurrentProcess()->HasSwitch(
64          switches::kDisableGpuProgramCache)) {
65    program_cache_.reset(new gpu::gles2::MemoryProgramCache());
66  }
67  return program_cache_.get();
68}
69
70void GpuChannelManager::RemoveChannel(int client_id) {
71  Send(new GpuHostMsg_DestroyChannel(client_id));
72  gpu_channels_.erase(client_id);
73}
74
75int GpuChannelManager::GenerateRouteID() {
76  static int last_id = 0;
77  return ++last_id;
78}
79
80void GpuChannelManager::AddRoute(int32 routing_id, IPC::Listener* listener) {
81  gpu_child_thread_->AddRoute(routing_id, listener);
82}
83
84void GpuChannelManager::RemoveRoute(int32 routing_id) {
85  gpu_child_thread_->RemoveRoute(routing_id);
86}
87
88GpuChannel* GpuChannelManager::LookupChannel(int32 client_id) {
89  GpuChannelMap::const_iterator iter = gpu_channels_.find(client_id);
90  if (iter == gpu_channels_.end())
91    return NULL;
92  else
93    return iter->second.get();
94}
95
96bool GpuChannelManager::OnMessageReceived(const IPC::Message& msg) {
97  bool msg_is_ok = true;
98  bool handled = true;
99  IPC_BEGIN_MESSAGE_MAP_EX(GpuChannelManager, msg, msg_is_ok)
100    IPC_MESSAGE_HANDLER(GpuMsg_EstablishChannel, OnEstablishChannel)
101    IPC_MESSAGE_HANDLER(GpuMsg_CloseChannel, OnCloseChannel)
102    IPC_MESSAGE_HANDLER(GpuMsg_CreateViewCommandBuffer,
103                        OnCreateViewCommandBuffer)
104    IPC_MESSAGE_HANDLER(GpuMsg_CreateImage, OnCreateImage)
105    IPC_MESSAGE_HANDLER(GpuMsg_DeleteImage, OnDeleteImage)
106    IPC_MESSAGE_HANDLER(GpuMsg_LoadedShader, OnLoadedShader)
107    IPC_MESSAGE_UNHANDLED(handled = false)
108  IPC_END_MESSAGE_MAP_EX()
109  return handled;
110}
111
112bool GpuChannelManager::Send(IPC::Message* msg) {
113  return gpu_child_thread_->Send(msg);
114}
115
116void GpuChannelManager::OnEstablishChannel(int client_id, bool share_context) {
117  IPC::ChannelHandle channel_handle;
118
119  gfx::GLShareGroup* share_group = NULL;
120  gpu::gles2::MailboxManager* mailbox_manager = NULL;
121  if (share_context) {
122    if (!share_group_.get()) {
123      share_group_ = new gfx::GLShareGroup;
124      DCHECK(!mailbox_manager_.get());
125      mailbox_manager_ = new gpu::gles2::MailboxManager;
126    }
127    share_group = share_group_.get();
128    mailbox_manager = mailbox_manager_.get();
129  }
130
131  scoped_refptr<GpuChannel> channel = new GpuChannel(this,
132                                                     watchdog_,
133                                                     share_group,
134                                                     mailbox_manager,
135                                                     client_id,
136                                                     false);
137  if (channel->Init(io_message_loop_.get(), shutdown_event_)) {
138    gpu_channels_[client_id] = channel;
139    channel_handle.name = channel->GetChannelName();
140
141#if defined(OS_POSIX)
142    // On POSIX, pass the renderer-side FD. Also mark it as auto-close so
143    // that it gets closed after it has been sent.
144    int renderer_fd = channel->TakeRendererFileDescriptor();
145    DCHECK_NE(-1, renderer_fd);
146    channel_handle.socket = base::FileDescriptor(renderer_fd, true);
147#endif
148  }
149
150  Send(new GpuHostMsg_ChannelEstablished(channel_handle));
151}
152
153void GpuChannelManager::OnCloseChannel(
154    const IPC::ChannelHandle& channel_handle) {
155  for (GpuChannelMap::iterator iter = gpu_channels_.begin();
156       iter != gpu_channels_.end(); ++iter) {
157    if (iter->second->GetChannelName() == channel_handle.name) {
158      gpu_channels_.erase(iter);
159      return;
160    }
161  }
162}
163
164void GpuChannelManager::OnCreateViewCommandBuffer(
165    const gfx::GLSurfaceHandle& window,
166    int32 surface_id,
167    int32 client_id,
168    const GPUCreateCommandBufferConfig& init_params) {
169  DCHECK(surface_id);
170  int32 route_id = MSG_ROUTING_NONE;
171
172  GpuChannelMap::const_iterator iter = gpu_channels_.find(client_id);
173  if (iter != gpu_channels_.end()) {
174    iter->second->CreateViewCommandBuffer(
175        window, surface_id, init_params, &route_id);
176  }
177
178  Send(new GpuHostMsg_CommandBufferCreated(route_id));
179}
180
181void GpuChannelManager::CreateImage(
182    gfx::PluginWindowHandle window, int32 client_id, int32 image_id) {
183  gfx::Size size;
184
185  GpuChannelMap::const_iterator iter = gpu_channels_.find(client_id);
186  if (iter != gpu_channels_.end()) {
187    iter->second->CreateImage(window, image_id, &size);
188  }
189
190  Send(new GpuHostMsg_ImageCreated(size));
191}
192
193void GpuChannelManager::OnCreateImage(
194    gfx::PluginWindowHandle window, int32 client_id, int32 image_id) {
195  DCHECK(image_id);
196
197  if (image_operations_.empty()) {
198    CreateImage(window, client_id, image_id);
199  } else {
200    image_operations_.push_back(
201        new ImageOperation(0, base::Bind(&GpuChannelManager::CreateImage,
202                                         base::Unretained(this),
203                                         window,
204                                         client_id,
205                                         image_id)));
206  }
207}
208
209void GpuChannelManager::DeleteImage(int32 client_id, int32 image_id) {
210  GpuChannelMap::const_iterator iter = gpu_channels_.find(client_id);
211  if (iter != gpu_channels_.end()) {
212    iter->second->DeleteImage(image_id);
213  }
214}
215
216void GpuChannelManager::OnDeleteImage(
217    int32 client_id, int32 image_id, int32 sync_point) {
218  DCHECK(image_id);
219
220  if (!sync_point && image_operations_.empty()) {
221    DeleteImage(client_id, image_id);
222  } else {
223    image_operations_.push_back(
224        new ImageOperation(sync_point,
225                           base::Bind(&GpuChannelManager::DeleteImage,
226                                      base::Unretained(this),
227                                      client_id,
228                                      image_id)));
229    if (sync_point) {
230      sync_point_manager()->AddSyncPointCallback(
231          sync_point,
232          base::Bind(&GpuChannelManager::OnDeleteImageSyncPointRetired,
233                     base::Unretained(this),
234                     image_operations_.back()));
235    }
236  }
237}
238
239void GpuChannelManager::OnDeleteImageSyncPointRetired(
240    ImageOperation* image_operation) {
241  // Mark operation as no longer having a pending sync point.
242  image_operation->sync_point = 0;
243
244  // De-queue operations until we reach a pending sync point.
245  while (!image_operations_.empty()) {
246    // Check if operation has a pending sync point.
247    if (image_operations_.front()->sync_point)
248      return;
249
250    image_operations_.front()->callback.Run();
251    delete image_operations_.front();
252    image_operations_.pop_front();
253  }
254}
255
256void GpuChannelManager::OnLoadedShader(std::string program_proto) {
257  if (program_cache())
258    program_cache()->LoadProgram(program_proto);
259}
260
261bool GpuChannelManager::HandleMessagesScheduled() {
262  for (GpuChannelMap::iterator iter = gpu_channels_.begin();
263       iter != gpu_channels_.end(); ++iter) {
264    if (iter->second->handle_messages_scheduled())
265      return true;
266  }
267  return false;
268}
269
270uint64 GpuChannelManager::MessagesProcessed() {
271  uint64 messages_processed = 0;
272
273  for (GpuChannelMap::iterator iter = gpu_channels_.begin();
274       iter != gpu_channels_.end(); ++iter) {
275    messages_processed += iter->second->messages_processed();
276  }
277  return messages_processed;
278}
279
280void GpuChannelManager::LoseAllContexts() {
281  for (GpuChannelMap::iterator iter = gpu_channels_.begin();
282       iter != gpu_channels_.end(); ++iter) {
283    iter->second->MarkAllContextsLost();
284  }
285  base::MessageLoop::current()->PostTask(
286      FROM_HERE,
287      base::Bind(&GpuChannelManager::OnLoseAllContexts,
288                 weak_factory_.GetWeakPtr()));
289}
290
291void GpuChannelManager::OnLoseAllContexts() {
292  gpu_channels_.clear();
293}
294
295gfx::GLSurface* GpuChannelManager::GetDefaultOffscreenSurface() {
296  if (!default_offscreen_surface_.get()) {
297    default_offscreen_surface_ =
298        gfx::GLSurface::CreateOffscreenGLSurface(gfx::Size(1, 1));
299  }
300  return default_offscreen_surface_.get();
301}
302
303}  // namespace content
304