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