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
22 namespace content {
23
ImageOperation(int32 sync_point,base::Closure callback)24 GpuChannelManager::ImageOperation::ImageOperation(
25 int32 sync_point, base::Closure callback)
26 : sync_point(sync_point),
27 callback(callback) {
28 }
29
~ImageOperation()30 GpuChannelManager::ImageOperation::~ImageOperation() {
31 }
32
GpuChannelManager(MessageRouter * router,GpuWatchdog * watchdog,base::MessageLoopProxy * io_message_loop,base::WaitableEvent * shutdown_event)33 GpuChannelManager::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
~GpuChannelManager()51 GpuChannelManager::~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
program_cache()60 gpu::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
71 gpu::gles2::ShaderTranslatorCache*
shader_translator_cache()72 GpuChannelManager::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
RemoveChannel(int client_id)78 void GpuChannelManager::RemoveChannel(int client_id) {
79 Send(new GpuHostMsg_DestroyChannel(client_id));
80 gpu_channels_.erase(client_id);
81 }
82
GenerateRouteID()83 int GpuChannelManager::GenerateRouteID() {
84 static int last_id = 0;
85 return ++last_id;
86 }
87
AddRoute(int32 routing_id,IPC::Listener * listener)88 void GpuChannelManager::AddRoute(int32 routing_id, IPC::Listener* listener) {
89 router_->AddRoute(routing_id, listener);
90 }
91
RemoveRoute(int32 routing_id)92 void GpuChannelManager::RemoveRoute(int32 routing_id) {
93 router_->RemoveRoute(routing_id);
94 }
95
LookupChannel(int32 client_id)96 GpuChannel* 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
OnMessageReceived(const IPC::Message & msg)104 bool 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
Send(IPC::Message * msg)121 bool GpuChannelManager::Send(IPC::Message* msg) { return router_->Send(msg); }
122
OnEstablishChannel(int client_id,bool share_context)123 void 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
OnCloseChannel(const IPC::ChannelHandle & channel_handle)156 void 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
OnCreateViewCommandBuffer(const gfx::GLSurfaceHandle & window,int32 surface_id,int32 client_id,const GPUCreateCommandBufferConfig & init_params,int32 route_id)167 void 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
CreateImage(gfx::PluginWindowHandle window,int32 client_id,int32 image_id)185 void 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
OnCreateImage(gfx::PluginWindowHandle window,int32 client_id,int32 image_id)197 void 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
DeleteImage(int32 client_id,int32 image_id)213 void 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
OnDeleteImage(int32 client_id,int32 image_id,int32 sync_point)220 void 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
OnDeleteImageSyncPointRetired(ImageOperation * image_operation)243 void 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
OnCreateGpuMemoryBuffer(const gfx::GpuMemoryBufferHandle & handle,const gfx::Size & size,unsigned internalformat,unsigned usage)260 void 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
OnDestroyGpuMemoryBuffer(const gfx::GpuMemoryBufferHandle & handle,int32 sync_point)268 void GpuChannelManager::OnDestroyGpuMemoryBuffer(
269 const gfx::GpuMemoryBufferHandle& handle,
270 int32 sync_point) {
271 }
272
OnLoadedShader(std::string program_proto)273 void GpuChannelManager::OnLoadedShader(std::string program_proto) {
274 if (program_cache())
275 program_cache()->LoadProgram(program_proto);
276 }
277
HandleMessagesScheduled()278 bool 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
MessagesProcessed()287 uint64 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
LoseAllContexts()297 void 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
OnLoseAllContexts()308 void GpuChannelManager::OnLoseAllContexts() {
309 gpu_channels_.clear();
310 }
311
GetDefaultOffscreenSurface()312 gfx::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