Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(257)

Side by Side Diff: content/renderer/gpu/gpu_channel_host.cc

Issue 7634019: Allow cmdbuffer creation from compositor thread. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: weak ptr version Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « content/renderer/gpu/gpu_channel_host.h ('k') | content/renderer/gpu/gpu_surface_proxy.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/gpu/gpu_channel_host.h" 5 #include "content/renderer/gpu/gpu_channel_host.h"
6 6
7 #include "base/message_loop_proxy.h"
7 #include "content/common/child_process.h" 8 #include "content/common/child_process.h"
8 #include "content/common/gpu/gpu_messages.h" 9 #include "content/common/gpu/gpu_messages.h"
9 #include "content/renderer/gpu/command_buffer_proxy.h" 10 #include "content/renderer/gpu/command_buffer_proxy.h"
10 #include "content/renderer/gpu/gpu_surface_proxy.h" 11 #include "content/renderer/gpu/gpu_surface_proxy.h"
11 #include "content/renderer/gpu/transport_texture_service.h" 12 #include "content/renderer/gpu/transport_texture_service.h"
13 #include "content/renderer/render_process.h"
12 #include "content/renderer/render_thread.h" 14 #include "content/renderer/render_thread.h"
13 #include "googleurl/src/gurl.h" 15 #include "googleurl/src/gurl.h"
16 #include "ipc/ipc_sync_message_filter.h"
17
18 using base::AutoLock;
19 using base::MessageLoopProxy;
20
21 // An shim class for working with listeners between threads.
22 // It is used to post a task to the thread that owns the listener,
23 // and where it's safe to dereference the weak pointer.
24 class GpuChannelListener :
25 public base::RefCountedThreadSafe<GpuChannelListener> {
26 public:
27 GpuChannelListener(base::WeakPtr<IPC::Channel::Listener> listener,
28 scoped_refptr<base::MessageLoopProxy> loop);
29 virtual ~GpuChannelListener();
30
31 void DispatchMessage(const IPC::Message& msg);
32 void DispatchError();
33
34 scoped_refptr<base::MessageLoopProxy> loop() { return loop_; }
35
36 private:
37 base::WeakPtr<IPC::Channel::Listener> listener_;
38 scoped_refptr<base::MessageLoopProxy> loop_;
39 };
nduca 2011/08/19 15:56:13 Does the style guide say to put the implementation
no sievers 2011/08/22 22:45:17 Good point. It would have to be put inside an anon
40
41 GpuChannelListener::GpuChannelListener(
42 base::WeakPtr<IPC::Channel::Listener> listener,
43 scoped_refptr<base::MessageLoopProxy> loop)
44 : listener_(listener),
45 loop_(loop) {
46
47 }
48
49 GpuChannelListener::~GpuChannelListener() {
50
51 }
52
53 void GpuChannelListener::DispatchMessage(const IPC::Message& msg) {
54 if (listener_.get())
55 listener_->OnMessageReceived(msg);
56 }
57
58 void GpuChannelListener::DispatchError() {
59 if (listener_.get())
60 listener_->OnChannelError();
61 }
62
63 GpuChannelHost::MessageFilter::MessageFilter(GpuChannelHost* parent)
64 : parent_(parent) {
65 DetachFromThread();
66 }
67
68 GpuChannelHost::MessageFilter::~MessageFilter() {
69
70 }
71
72 void GpuChannelHost::MessageFilter::AddRoute(
73 int route_id,
74 base::WeakPtr<IPC::Channel::Listener> listener,
75 scoped_refptr<MessageLoopProxy> loop) {
76 DCHECK(CalledOnValidThread());
77 DCHECK(listeners_.find(route_id) == listeners_.end());
78 listeners_[route_id] = new GpuChannelListener(listener,
79 loop);
80 }
81
82 void GpuChannelHost::MessageFilter::RemoveRoute(int route_id) {
83 DCHECK(CalledOnValidThread());
84 ListenerMap::iterator it = listeners_.find(route_id);
85 if (it != listeners_.end())
86 listeners_.erase(it);
87 }
88
89 bool GpuChannelHost::MessageFilter::OnMessageReceived(
90 const IPC::Message& message) {
91 DCHECK(CalledOnValidThread());
92
93 // Never handle sync message replies or we will deadlock here.
94 if (message.is_reply())
95 return false;
96
97 DCHECK(message.routing_id() != MSG_ROUTING_CONTROL);
98
99 ListenerMap::iterator it = listeners_.find(message.routing_id());
100
101 if (it != listeners_.end()) {
102 const scoped_refptr<GpuChannelListener>& listener = it->second;
103 listener->loop()->PostTask(
104 FROM_HERE,
105 NewRunnableMethod(
106 listener.get(),
107 &GpuChannelListener::DispatchMessage,
108 message));
109 }
110
111 return true;
112 }
113
114 void GpuChannelHost::MessageFilter::OnChannelError() {
115 DCHECK(CalledOnValidThread());
116
117 // Inform all the proxies that an error has occurred. This will be reported
118 // via OpenGL as a lost context.
119 for (ListenerMap::iterator it = listeners_.begin();
120 it != listeners_.end();
121 it++) {
122 const scoped_refptr<GpuChannelListener>& listener = it->second;
123 listener->loop()->PostTask(
124 FROM_HERE,
125 NewRunnableMethod(
126 listener.get(),
127 &GpuChannelListener::DispatchError));
128 }
129
130 listeners_.clear();
131
132 ChildThread* main_thread = RenderProcess::current()->main_thread();
133 MessageLoop* main_loop = main_thread->message_loop();
134 main_loop->PostTask(FROM_HERE,
135 NewRunnableMethod(parent_,
136 &GpuChannelHost::OnChannelError));
137 }
14 138
15 GpuChannelHost::GpuChannelHost() 139 GpuChannelHost::GpuChannelHost()
16 : state_(kUnconnected), 140 : state_(kUnconnected),
17 transport_texture_service_(new TransportTextureService()) { 141 transport_texture_service_(new TransportTextureService()) {
18 } 142 }
19 143
20 GpuChannelHost::~GpuChannelHost() { 144 GpuChannelHost::~GpuChannelHost() {
21 } 145 }
22 146
23 void GpuChannelHost::Connect( 147 void GpuChannelHost::Connect(
24 const IPC::ChannelHandle& channel_handle, 148 const IPC::ChannelHandle& channel_handle,
25 base::ProcessHandle renderer_process_for_gpu) { 149 base::ProcessHandle renderer_process_for_gpu) {
26 // Open a channel to the GPU process. 150 DCHECK(RenderThread::current());
151 // Open a channel to the GPU process. We pass NULL as the main listener here
152 // since we need to filter everything to route it to the right thread.
27 channel_.reset(new IPC::SyncChannel( 153 channel_.reset(new IPC::SyncChannel(
28 channel_handle, IPC::Channel::MODE_CLIENT, this, 154 channel_handle, IPC::Channel::MODE_CLIENT, NULL,
29 ChildProcess::current()->io_message_loop_proxy(), true, 155 ChildProcess::current()->io_message_loop_proxy(), true,
30 ChildProcess::current()->GetShutDownEvent())); 156 ChildProcess::current()->GetShutDownEvent()));
31 157
158 sync_filter_ = new IPC::SyncMessageFilter(
159 ChildProcess::current()->GetShutDownEvent());
160
161 channel_->AddFilter(sync_filter_.get());
162
163 channel_->AddFilter(transport_texture_service_.get());
164
165 channel_filter_ = new MessageFilter(this);
166
167 // Install the filter last, because we intercept all leftover
168 // messages.
169 channel_->AddFilter(channel_filter_.get());
170
32 // It is safe to send IPC messages before the channel completes the connection 171 // It is safe to send IPC messages before the channel completes the connection
33 // and receives the hello message from the GPU process. The messages get 172 // and receives the hello message from the GPU process. The messages get
34 // cached. 173 // cached.
35 state_ = kConnected; 174 state_ = kConnected;
36 175
37 // Notify the GPU process of our process handle. This gives it the ability 176 // Notify the GPU process of our process handle. This gives it the ability
38 // to map renderer handles into the GPU process. 177 // to map renderer handles into the GPU process.
39 Send(new GpuChannelMsg_Initialize(renderer_process_for_gpu)); 178 Send(new GpuChannelMsg_Initialize(renderer_process_for_gpu));
40 } 179 }
41 180
42 void GpuChannelHost::set_gpu_info(const GPUInfo& gpu_info) { 181 void GpuChannelHost::set_gpu_info(const GPUInfo& gpu_info) {
43 gpu_info_ = gpu_info; 182 gpu_info_ = gpu_info;
44 } 183 }
45 184
46 const GPUInfo& GpuChannelHost::gpu_info() const { 185 const GPUInfo& GpuChannelHost::gpu_info() const {
47 return gpu_info_; 186 return gpu_info_;
48 } 187 }
49 188
50 void GpuChannelHost::SetStateLost() { 189 void GpuChannelHost::SetStateLost() {
51 state_ = kLost; 190 state_ = kLost;
52 } 191 }
53 192
54 bool GpuChannelHost::OnMessageReceived(const IPC::Message& message) {
55 DCHECK(message.routing_id() != MSG_ROUTING_CONTROL);
56
57 return router_.RouteMessage(message);
58 }
59
60 void GpuChannelHost::OnChannelConnected(int32 peer_pid) {
61 channel_->AddFilter(transport_texture_service_.get());
62 }
63
64 void GpuChannelHost::OnChannelError() { 193 void GpuChannelHost::OnChannelError() {
65 state_ = kLost; 194 state_ = kLost;
66 195
67 // Channel is invalid and will be reinitialized if this host is requested 196 // Channel is invalid and will be reinitialized if this host is requested
68 // again. 197 // again.
69 channel_.reset(); 198 channel_.reset();
70
71 // Inform all the proxies that an error has occured. This will be reported via
72 // OpenGL as a lost context.
73 for (ProxyMap::iterator iter = proxies_.begin();
74 iter != proxies_.end(); iter++) {
75 router_.RemoveRoute(iter->first);
76 iter->second->OnChannelError();
77 }
78
79 // The proxies are reference counted so this will not result in their
80 // destruction if the client still holds a reference. The proxy will report
81 // a lost context, indicating to the client that it needs to be recreated.
82 proxies_.clear();
83 } 199 }
84 200
85 bool GpuChannelHost::Send(IPC::Message* message) { 201 bool GpuChannelHost::Send(IPC::Message* message) {
86 // The GPU process never sends synchronous IPCs so clear the unblock flag to 202 // The GPU process never sends synchronous IPCs so clear the unblock flag to
87 // preserve order. 203 // preserve order.
88 message->set_unblock(false); 204 message->set_unblock(false);
89 if (channel_.get()) 205
90 return channel_->Send(message); 206 // Unfortunately a sync filter cannot be used on the main (listener) thread.
207 // TODO: Is that true even when we don't install a listener?
208 if (RenderThread::current()) {
209 if (channel_.get())
210 return channel_->Send(message);
211 } else {
212 return sync_filter_->Send(message);
213 }
91 214
92 // Callee takes ownership of message, regardless of whether Send is 215 // Callee takes ownership of message, regardless of whether Send is
93 // successful. See IPC::Message::Sender. 216 // successful. See IPC::Message::Sender.
94 delete message; 217 delete message;
95 return false; 218 return false;
96 } 219 }
97 220
98 CommandBufferProxy* GpuChannelHost::CreateViewCommandBuffer( 221 CommandBufferProxy* GpuChannelHost::CreateViewCommandBuffer(
99 int render_view_id, 222 int render_view_id,
100 CommandBufferProxy* share_group, 223 CommandBufferProxy* share_group,
101 const std::string& allowed_extensions, 224 const std::string& allowed_extensions,
102 const std::vector<int32>& attribs, 225 const std::vector<int32>& attribs,
103 const GURL& active_url) { 226 const GURL& active_url) {
104 #if defined(ENABLE_GPU) 227 #if defined(ENABLE_GPU)
228 AutoLock lock(context_lock_);
105 // An error occurred. Need to get the host again to reinitialize it. 229 // An error occurred. Need to get the host again to reinitialize it.
106 if (!channel_.get()) 230 if (!channel_.get())
107 return NULL; 231 return NULL;
108 232
109 GPUCreateCommandBufferConfig init_params; 233 GPUCreateCommandBufferConfig init_params;
110 init_params.share_group_id = 234 init_params.share_group_id =
111 share_group ? share_group->route_id() : MSG_ROUTING_NONE; 235 share_group ? share_group->route_id() : MSG_ROUTING_NONE;
112 init_params.allowed_extensions = allowed_extensions; 236 init_params.allowed_extensions = allowed_extensions;
113 init_params.attribs = attribs; 237 init_params.attribs = attribs;
114 init_params.active_url = active_url; 238 init_params.active_url = active_url;
115 int32 route_id; 239 int32 route_id;
116 if (!RenderThread::current()->Send( 240 if (!RenderThread::current()->Send(
117 new GpuHostMsg_CreateViewCommandBuffer( 241 new GpuHostMsg_CreateViewCommandBuffer(
118 render_view_id, 242 render_view_id,
119 init_params, 243 init_params,
120 &route_id))) { 244 &route_id))) {
121 return NULL; 245 return NULL;
122 } 246 }
123 247
124 if (route_id == MSG_ROUTING_NONE) 248 if (route_id == MSG_ROUTING_NONE)
125 return NULL; 249 return NULL;
126 250
127 CommandBufferProxy* command_buffer = new CommandBufferProxy(this, route_id); 251 CommandBufferProxy* command_buffer = new CommandBufferProxy(this, route_id);
128 router_.AddRoute(route_id, command_buffer); 252 AddRoute(route_id, command_buffer->AsWeakPtr());
129 proxies_[route_id] = command_buffer; 253 proxies_[route_id] = command_buffer;
130 return command_buffer; 254 return command_buffer;
131 #else 255 #else
132 return NULL; 256 return NULL;
133 #endif 257 #endif
134 } 258 }
135 259
136 GpuVideoDecodeAcceleratorHost* GpuChannelHost::CreateVideoDecoder( 260 GpuVideoDecodeAcceleratorHost* GpuChannelHost::CreateVideoDecoder(
137 int command_buffer_route_id, 261 int command_buffer_route_id,
138 const std::vector<int32>& configs, 262 const std::vector<int32>& configs,
139 media::VideoDecodeAccelerator::Client* client) { 263 media::VideoDecodeAccelerator::Client* client) {
264 AutoLock lock(context_lock_);
140 ProxyMap::iterator it = proxies_.find(command_buffer_route_id); 265 ProxyMap::iterator it = proxies_.find(command_buffer_route_id);
141 DCHECK(it != proxies_.end()); 266 DCHECK(it != proxies_.end());
142 CommandBufferProxy* proxy = it->second; 267 CommandBufferProxy* proxy = it->second;
143 return proxy->CreateVideoDecoder(configs, client); 268 return proxy->CreateVideoDecoder(configs, client);
144 } 269 }
145 270
146 CommandBufferProxy* GpuChannelHost::CreateOffscreenCommandBuffer( 271 CommandBufferProxy* GpuChannelHost::CreateOffscreenCommandBuffer(
147 const gfx::Size& size, 272 const gfx::Size& size,
148 CommandBufferProxy* share_group, 273 CommandBufferProxy* share_group,
149 const std::string& allowed_extensions, 274 const std::string& allowed_extensions,
150 const std::vector<int32>& attribs, 275 const std::vector<int32>& attribs,
151 const GURL& active_url) { 276 const GURL& active_url) {
152 #if defined(ENABLE_GPU) 277 #if defined(ENABLE_GPU)
278 AutoLock lock(context_lock_);
153 // An error occurred. Need to get the host again to reinitialize it. 279 // An error occurred. Need to get the host again to reinitialize it.
154 if (!channel_.get()) 280 if (!channel_.get())
155 return NULL; 281 return NULL;
156 282
157 GPUCreateCommandBufferConfig init_params; 283 GPUCreateCommandBufferConfig init_params;
158 init_params.share_group_id = 284 init_params.share_group_id =
159 share_group ? share_group->route_id() : MSG_ROUTING_NONE; 285 share_group ? share_group->route_id() : MSG_ROUTING_NONE;
160 init_params.allowed_extensions = allowed_extensions; 286 init_params.allowed_extensions = allowed_extensions;
161 init_params.attribs = attribs; 287 init_params.attribs = attribs;
162 init_params.active_url = active_url; 288 init_params.active_url = active_url;
163 int32 route_id; 289 int32 route_id;
164 if (!Send(new GpuChannelMsg_CreateOffscreenCommandBuffer(size, 290 if (!Send(new GpuChannelMsg_CreateOffscreenCommandBuffer(size,
165 init_params, 291 init_params,
166 &route_id))) { 292 &route_id))) {
167 return NULL; 293 return NULL;
168 } 294 }
169 295
170 if (route_id == MSG_ROUTING_NONE) 296 if (route_id == MSG_ROUTING_NONE)
171 return NULL; 297 return NULL;
172 298
173 CommandBufferProxy* command_buffer = new CommandBufferProxy(this, route_id); 299 CommandBufferProxy* command_buffer = new CommandBufferProxy(this, route_id);
174 router_.AddRoute(route_id, command_buffer); 300 AddRoute(route_id, command_buffer->AsWeakPtr());
175 proxies_[route_id] = command_buffer; 301 proxies_[route_id] = command_buffer;
176 return command_buffer; 302 return command_buffer;
177 #else 303 #else
178 return NULL; 304 return NULL;
179 #endif 305 #endif
180 } 306 }
181 307
182 void GpuChannelHost::AddRoute(int32 route_id,
183 IPC::Channel::Listener* listener) {
184 router_.AddRoute(route_id, listener);
185 }
186
187 void GpuChannelHost::RemoveRoute(int32 route_id) {
188 router_.RemoveRoute(route_id);
189 }
190
191 void GpuChannelHost::DestroyCommandBuffer(CommandBufferProxy* command_buffer) { 308 void GpuChannelHost::DestroyCommandBuffer(CommandBufferProxy* command_buffer) {
192 #if defined(ENABLE_GPU) 309 #if defined(ENABLE_GPU)
310 AutoLock lock(context_lock_);
193 Send(new GpuChannelMsg_DestroyCommandBuffer(command_buffer->route_id())); 311 Send(new GpuChannelMsg_DestroyCommandBuffer(command_buffer->route_id()));
194 312
195 // Check the proxy has not already been removed after a channel error. 313 // Check the proxy has not already been removed after a channel error.
196 int route_id = command_buffer->route_id(); 314 int route_id = command_buffer->route_id();
197 if (proxies_.find(command_buffer->route_id()) != proxies_.end()) { 315 if (proxies_.find(command_buffer->route_id()) != proxies_.end())
198 proxies_.erase(route_id); 316 proxies_.erase(route_id);
199 router_.RemoveRoute(route_id); 317 RemoveRoute(route_id);
200 }
201
202 delete command_buffer; 318 delete command_buffer;
nduca 2011/08/19 15:56:13 Deletion as part of removing from the host is a sc
no sievers 2011/08/22 22:45:17 We discussed this and will approach this separatel
203 #endif 319 #endif
204 } 320 }
205 321
206 GpuSurfaceProxy* GpuChannelHost::CreateOffscreenSurface(const gfx::Size& size) { 322 GpuSurfaceProxy* GpuChannelHost::CreateOffscreenSurface(
323 const gfx::Size& size) {
207 #if defined(ENABLE_GPU) 324 #if defined(ENABLE_GPU)
325 AutoLock lock(context_lock_);
208 int route_id; 326 int route_id;
209 if (!Send(new GpuChannelMsg_CreateOffscreenSurface(size, &route_id))) 327 if (!Send(new GpuChannelMsg_CreateOffscreenSurface(size, &route_id)))
210 return NULL; 328 return NULL;
211 329
212 scoped_ptr<GpuSurfaceProxy> surface(new GpuSurfaceProxy(this, route_id)); 330 scoped_ptr<GpuSurfaceProxy> surface(new GpuSurfaceProxy(this, route_id));
213 router_.AddRoute(route_id, surface.get()); 331 AddRoute(route_id, surface->AsWeakPtr());
214 332
215 return surface.release(); 333 return surface.release();
216 #endif 334 #endif
217 } 335 }
218 336
219 void GpuChannelHost::DestroySurface(GpuSurfaceProxy* surface) { 337 void GpuChannelHost::DestroySurface(GpuSurfaceProxy* surface) {
220 #if defined(ENABLE_GPU) 338 #if defined(ENABLE_GPU)
339 AutoLock lock(context_lock_);
221 Send(new GpuChannelMsg_DestroySurface(surface->route_id())); 340 Send(new GpuChannelMsg_DestroySurface(surface->route_id()));
222 if (router_.ResolveRoute(surface->route_id()))
223 router_.RemoveRoute(surface->route_id());
224 341
342 RemoveRoute(surface->route_id());
225 delete surface; 343 delete surface;
226 #endif 344 #endif
227 } 345 }
346
347 void GpuChannelHost::AddRoute(
348 int route_id, base::WeakPtr<IPC::Channel::Listener> listener) {
349 DCHECK(MessageLoopProxy::current());
350
351 MessageLoopProxy* io_loop = RenderProcess::current()->io_message_loop_proxy();
352 io_loop->PostTask(FROM_HERE,
353 NewRunnableMethod(
354 channel_filter_.get(),
355 &GpuChannelHost::MessageFilter::AddRoute,
356 route_id, listener, MessageLoopProxy::current()));
357 }
358
359 void GpuChannelHost::RemoveRoute(int route_id) {
360 MessageLoopProxy* io_loop = RenderProcess::current()->io_message_loop_proxy();
361 io_loop->PostTask(FROM_HERE,
362 NewRunnableMethod(
363 channel_filter_.get(),
364 &GpuChannelHost::MessageFilter::RemoveRoute,
365 route_id));
366 }
OLDNEW
« no previous file with comments | « content/renderer/gpu/gpu_channel_host.h ('k') | content/renderer/gpu/gpu_surface_proxy.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698