- add sources.
[platform/framework/web/crosswalk.git] / src / content / common / gpu / gpu_channel_manager.cc
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
21 namespace content {
22
23 GpuChannelManager::ImageOperation::ImageOperation(
24     int32 sync_point, base::Closure callback)
25     : sync_point(sync_point),
26       callback(callback) {
27 }
28
29 GpuChannelManager::ImageOperation::~ImageOperation() {
30 }
31
32 GpuChannelManager::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
50 GpuChannelManager::~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
59 gpu::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
70 void GpuChannelManager::RemoveChannel(int client_id) {
71   Send(new GpuHostMsg_DestroyChannel(client_id));
72   gpu_channels_.erase(client_id);
73 }
74
75 int GpuChannelManager::GenerateRouteID() {
76   static int last_id = 0;
77   return ++last_id;
78 }
79
80 void GpuChannelManager::AddRoute(int32 routing_id, IPC::Listener* listener) {
81   gpu_child_thread_->AddRoute(routing_id, listener);
82 }
83
84 void GpuChannelManager::RemoveRoute(int32 routing_id) {
85   gpu_child_thread_->RemoveRoute(routing_id);
86 }
87
88 GpuChannel* 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
96 bool 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
112 bool GpuChannelManager::Send(IPC::Message* msg) {
113   return gpu_child_thread_->Send(msg);
114 }
115
116 void 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
153 void 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
164 void 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
181 void 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
193 void 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
209 void 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
216 void 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
239 void 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
256 void GpuChannelManager::OnLoadedShader(std::string program_proto) {
257   if (program_cache())
258     program_cache()->LoadProgram(program_proto);
259 }
260
261 bool 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
270 uint64 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
280 void 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
291 void GpuChannelManager::OnLoseAllContexts() {
292   gpu_channels_.clear();
293 }
294
295 gfx::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