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

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: address comments 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
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 GpuChannelListener::GpuChannelListener()
22 : orphaned_(false),
23 loop_(MessageLoopProxy::current()) {
24
25 }
26
27 GpuChannelListener::~GpuChannelListener() {
28
29 }
30
31 GpuChannelHost::MessageFilter::MessageFilter(GpuChannelHost* parent)
32 : parent_(parent) {
33 DetachFromThread();
34 }
35
36 GpuChannelHost::MessageFilter::~MessageFilter() {
37
38 }
39
40 void GpuChannelHost::MessageFilter::AddRoute(
41 int route_id,
42 scoped_refptr<GpuChannelListener> listener) {
43 DCHECK(CalledOnValidThread());
44 DCHECK(listeners_.find(route_id) == listeners_.end());
45 listeners_[route_id] = listener;
46 }
47
48 void GpuChannelHost::MessageFilter::RemoveRoute(int route_id) {
49 DCHECK(CalledOnValidThread());
50 ListenerMap::iterator it = listeners_.find(route_id);
51 if (it != listeners_.end())
52 listeners_.erase(it);
53 }
54
55 bool GpuChannelHost::MessageFilter::OnMessageReceived(
56 const IPC::Message& message) {
57 DCHECK(CalledOnValidThread());
58
59 // Never handle sync message replies or we will deadlock here.
60 if (message.is_reply())
61 return false;
62
63 DCHECK(message.routing_id() != MSG_ROUTING_CONTROL);
64
65 ListenerMap::iterator it = listeners_.find(message.routing_id());
66
67 if (it != listeners_.end()) {
68 const scoped_refptr<GpuChannelListener>& listener = it->second;
69 listener->loop()->PostTask(
70 FROM_HERE,
71 NewRunnableMethod(
72 listener.get(),
73 &GpuChannelListener::OnMessageReceived,
nduca 2011/08/15 22:28:36 i.e. post to DispatchMessage and check this->orpha
74 message));
75 }
76
77 return true;
78 }
79
80 void GpuChannelHost::MessageFilter::OnChannelError() {
81 DCHECK(CalledOnValidThread());
82
83 // Inform all the proxies that an error has occurred. This will be reported
84 // via OpenGL as a lost context.
85 for (ListenerMap::iterator it = listeners_.begin();
86 it != listeners_.end();
87 it++) {
88 const scoped_refptr<GpuChannelListener>& listener = it->second;
89 listener->loop()->PostTask(
90 FROM_HERE,
91 NewRunnableMethod(
92 listener.get(),
93 &GpuChannelListener::OnChannelError));
94 }
95
96 listeners_.clear();
97
98 ChildThread* main_thread = RenderProcess::current()->main_thread();
99 MessageLoop* main_loop = main_thread->message_loop();
100 main_loop->PostTask(FROM_HERE,
101 NewRunnableMethod(parent_,
102 &GpuChannelHost::OnChannelError));
103 }
14 104
15 GpuChannelHost::GpuChannelHost() 105 GpuChannelHost::GpuChannelHost()
16 : state_(kUnconnected), 106 : state_(kUnconnected),
17 transport_texture_service_(new TransportTextureService()) { 107 transport_texture_service_(new TransportTextureService()) {
18 } 108 }
19 109
20 GpuChannelHost::~GpuChannelHost() { 110 GpuChannelHost::~GpuChannelHost() {
21 } 111 }
22 112
23 void GpuChannelHost::Connect( 113 void GpuChannelHost::Connect(
24 const IPC::ChannelHandle& channel_handle, 114 const IPC::ChannelHandle& channel_handle,
25 base::ProcessHandle renderer_process_for_gpu) { 115 base::ProcessHandle renderer_process_for_gpu) {
26 // Open a channel to the GPU process. 116 DCHECK(RenderThread::current());
117 // Open a channel to the GPU process. We pass NULL as the main listener here
118 // since we need to filter everything to route it to the right thread.
27 channel_.reset(new IPC::SyncChannel( 119 channel_.reset(new IPC::SyncChannel(
28 channel_handle, IPC::Channel::MODE_CLIENT, this, 120 channel_handle, IPC::Channel::MODE_CLIENT, NULL,
29 ChildProcess::current()->io_message_loop_proxy(), true, 121 ChildProcess::current()->io_message_loop_proxy(), true,
30 ChildProcess::current()->GetShutDownEvent())); 122 ChildProcess::current()->GetShutDownEvent()));
31 123
124 sync_filter_.reset(new IPC::SyncMessageFilter(
125 ChildProcess::current()->GetShutDownEvent()));
126
127 channel_->AddFilter(sync_filter_.get());
128
129 channel_->AddFilter(transport_texture_service_.get());
130
131 channel_filter_ = new MessageFilter(this);
132
133 // Install the filter last, because we intercept all leftover
134 // messages.
135 channel_->AddFilter(channel_filter_.get());
136
32 // It is safe to send IPC messages before the channel completes the connection 137 // 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 138 // and receives the hello message from the GPU process. The messages get
34 // cached. 139 // cached.
35 state_ = kConnected; 140 state_ = kConnected;
36 141
37 // Notify the GPU process of our process handle. This gives it the ability 142 // Notify the GPU process of our process handle. This gives it the ability
38 // to map renderer handles into the GPU process. 143 // to map renderer handles into the GPU process.
39 Send(new GpuChannelMsg_Initialize(renderer_process_for_gpu)); 144 Send(new GpuChannelMsg_Initialize(renderer_process_for_gpu));
40 } 145 }
41 146
42 void GpuChannelHost::set_gpu_info(const GPUInfo& gpu_info) { 147 void GpuChannelHost::set_gpu_info(const GPUInfo& gpu_info) {
43 gpu_info_ = gpu_info; 148 gpu_info_ = gpu_info;
44 } 149 }
45 150
46 const GPUInfo& GpuChannelHost::gpu_info() const { 151 const GPUInfo& GpuChannelHost::gpu_info() const {
47 return gpu_info_; 152 return gpu_info_;
48 } 153 }
49 154
50 void GpuChannelHost::SetStateLost() { 155 void GpuChannelHost::SetStateLost() {
51 state_ = kLost; 156 state_ = kLost;
52 } 157 }
53 158
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() { 159 void GpuChannelHost::OnChannelError() {
65 state_ = kLost; 160 state_ = kLost;
66 161
67 // Channel is invalid and will be reinitialized if this host is requested 162 // Channel is invalid and will be reinitialized if this host is requested
68 // again. 163 // again.
69 channel_.reset(); 164 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 } 165 }
84 166
85 bool GpuChannelHost::Send(IPC::Message* message) { 167 bool GpuChannelHost::Send(IPC::Message* message) {
86 // The GPU process never sends synchronous IPCs so clear the unblock flag to 168 // The GPU process never sends synchronous IPCs so clear the unblock flag to
87 // preserve order. 169 // preserve order.
88 message->set_unblock(false); 170 message->set_unblock(false);
89 if (channel_.get()) 171
172 // Unfortunately a sync filter cannot be used on the main (listener) thread.
173 // TODO: Is that true even when we don't install a listener?
174 if (channel_.get() && RenderThread::current())
90 return channel_->Send(message); 175 return channel_->Send(message);
176 else
177 return sync_filter_->Send(message);
91 178
92 // Callee takes ownership of message, regardless of whether Send is 179 // Callee takes ownership of message, regardless of whether Send is
93 // successful. See IPC::Message::Sender. 180 // successful. See IPC::Message::Sender.
94 delete message; 181 delete message;
95 return false; 182 return false;
96 } 183 }
97 184
98 CommandBufferProxy* GpuChannelHost::CreateViewCommandBuffer( 185 scoped_refptr<CommandBufferProxy> GpuChannelHost::CreateViewCommandBuffer(
99 int render_view_id, 186 int render_view_id,
100 CommandBufferProxy* share_group, 187 CommandBufferProxy* share_group,
101 const std::string& allowed_extensions, 188 const std::string& allowed_extensions,
102 const std::vector<int32>& attribs, 189 const std::vector<int32>& attribs,
103 const GURL& active_url) { 190 const GURL& active_url) {
104 #if defined(ENABLE_GPU) 191 #if defined(ENABLE_GPU)
192 AutoLock lock(context_lock_);
105 // An error occurred. Need to get the host again to reinitialize it. 193 // An error occurred. Need to get the host again to reinitialize it.
106 if (!channel_.get()) 194 if (!channel_.get())
107 return NULL; 195 return NULL;
108 196
109 GPUCreateCommandBufferConfig init_params; 197 GPUCreateCommandBufferConfig init_params;
110 init_params.share_group_id = 198 init_params.share_group_id =
111 share_group ? share_group->route_id() : MSG_ROUTING_NONE; 199 share_group ? share_group->route_id() : MSG_ROUTING_NONE;
112 init_params.allowed_extensions = allowed_extensions; 200 init_params.allowed_extensions = allowed_extensions;
113 init_params.attribs = attribs; 201 init_params.attribs = attribs;
114 init_params.active_url = active_url; 202 init_params.active_url = active_url;
115 int32 route_id; 203 int32 route_id;
116 if (!RenderThread::current()->Send( 204 if (!RenderThread::current()->Send(
117 new GpuHostMsg_CreateViewCommandBuffer( 205 new GpuHostMsg_CreateViewCommandBuffer(
118 render_view_id, 206 render_view_id,
119 init_params, 207 init_params,
120 &route_id))) { 208 &route_id))) {
121 return NULL; 209 return NULL;
122 } 210 }
123 211
124 if (route_id == MSG_ROUTING_NONE) 212 if (route_id == MSG_ROUTING_NONE)
125 return NULL; 213 return NULL;
126 214
127 CommandBufferProxy* command_buffer = new CommandBufferProxy(this, route_id); 215 scoped_refptr<CommandBufferProxy> command_buffer =
128 router_.AddRoute(route_id, command_buffer); 216 new CommandBufferProxy(this, route_id);
217 AddRoute(route_id, command_buffer);
129 proxies_[route_id] = command_buffer; 218 proxies_[route_id] = command_buffer;
130 return command_buffer; 219 return command_buffer;
131 #else 220 #else
132 return NULL; 221 return NULL;
133 #endif 222 #endif
134 } 223 }
135 224
136 GpuVideoDecodeAcceleratorHost* GpuChannelHost::CreateVideoDecoder( 225 GpuVideoDecodeAcceleratorHost* GpuChannelHost::CreateVideoDecoder(
137 int command_buffer_route_id, 226 int command_buffer_route_id,
138 const std::vector<int32>& configs, 227 const std::vector<int32>& configs,
139 media::VideoDecodeAccelerator::Client* client) { 228 media::VideoDecodeAccelerator::Client* client) {
229 AutoLock lock(context_lock_);
140 ProxyMap::iterator it = proxies_.find(command_buffer_route_id); 230 ProxyMap::iterator it = proxies_.find(command_buffer_route_id);
141 DCHECK(it != proxies_.end()); 231 DCHECK(it != proxies_.end());
142 CommandBufferProxy* proxy = it->second; 232 CommandBufferProxy* proxy = it->second;
143 return proxy->CreateVideoDecoder(configs, client); 233 return proxy->CreateVideoDecoder(configs, client);
144 } 234 }
145 235
146 CommandBufferProxy* GpuChannelHost::CreateOffscreenCommandBuffer( 236 scoped_refptr<CommandBufferProxy> GpuChannelHost::CreateOffscreenCommandBuffer(
147 const gfx::Size& size, 237 const gfx::Size& size,
148 CommandBufferProxy* share_group, 238 CommandBufferProxy* share_group,
149 const std::string& allowed_extensions, 239 const std::string& allowed_extensions,
150 const std::vector<int32>& attribs, 240 const std::vector<int32>& attribs,
151 const GURL& active_url) { 241 const GURL& active_url) {
152 #if defined(ENABLE_GPU) 242 #if defined(ENABLE_GPU)
243 AutoLock lock(context_lock_);
153 // An error occurred. Need to get the host again to reinitialize it. 244 // An error occurred. Need to get the host again to reinitialize it.
154 if (!channel_.get()) 245 if (!channel_.get())
155 return NULL; 246 return NULL;
156 247
157 GPUCreateCommandBufferConfig init_params; 248 GPUCreateCommandBufferConfig init_params;
158 init_params.share_group_id = 249 init_params.share_group_id =
159 share_group ? share_group->route_id() : MSG_ROUTING_NONE; 250 share_group ? share_group->route_id() : MSG_ROUTING_NONE;
160 init_params.allowed_extensions = allowed_extensions; 251 init_params.allowed_extensions = allowed_extensions;
161 init_params.attribs = attribs; 252 init_params.attribs = attribs;
162 init_params.active_url = active_url; 253 init_params.active_url = active_url;
163 int32 route_id; 254 int32 route_id;
164 if (!Send(new GpuChannelMsg_CreateOffscreenCommandBuffer(size, 255 if (!Send(new GpuChannelMsg_CreateOffscreenCommandBuffer(size,
165 init_params, 256 init_params,
166 &route_id))) { 257 &route_id))) {
167 return NULL; 258 return NULL;
168 } 259 }
169 260
170 if (route_id == MSG_ROUTING_NONE) 261 if (route_id == MSG_ROUTING_NONE)
171 return NULL; 262 return NULL;
172 263
173 CommandBufferProxy* command_buffer = new CommandBufferProxy(this, route_id); 264 scoped_refptr<CommandBufferProxy> command_buffer =
174 router_.AddRoute(route_id, command_buffer); 265 new CommandBufferProxy(this, route_id);
266 AddRoute(route_id, command_buffer);
175 proxies_[route_id] = command_buffer; 267 proxies_[route_id] = command_buffer;
176 return command_buffer; 268 return command_buffer;
177 #else 269 #else
178 return NULL; 270 return NULL;
179 #endif 271 #endif
180 } 272 }
181 273
182 void GpuChannelHost::DestroyCommandBuffer(CommandBufferProxy* command_buffer) { 274 void GpuChannelHost::DestroyCommandBuffer(CommandBufferProxy* command_buffer) {
183 #if defined(ENABLE_GPU) 275 #if defined(ENABLE_GPU)
276 AutoLock lock(context_lock_);
184 Send(new GpuChannelMsg_DestroyCommandBuffer(command_buffer->route_id())); 277 Send(new GpuChannelMsg_DestroyCommandBuffer(command_buffer->route_id()));
185 278
186 // Check the proxy has not already been removed after a channel error. 279 // Check the proxy has not already been removed after a channel error.
187 int route_id = command_buffer->route_id(); 280 int route_id = command_buffer->route_id();
188 if (proxies_.find(command_buffer->route_id()) != proxies_.end()) { 281 if (proxies_.find(command_buffer->route_id()) != proxies_.end())
189 proxies_.erase(route_id); 282 proxies_.erase(route_id);
190 router_.RemoveRoute(route_id); 283 RemoveRoute(route_id);
191 } 284 command_buffer->Orphan();
192
193 delete command_buffer;
194 #endif 285 #endif
195 } 286 }
196 287
197 GpuSurfaceProxy* GpuChannelHost::CreateOffscreenSurface(const gfx::Size& size) { 288 scoped_refptr<GpuSurfaceProxy> GpuChannelHost::CreateOffscreenSurface(
289 const gfx::Size& size) {
198 #if defined(ENABLE_GPU) 290 #if defined(ENABLE_GPU)
291 AutoLock lock(context_lock_);
199 int route_id; 292 int route_id;
200 if (!Send(new GpuChannelMsg_CreateOffscreenSurface(size, &route_id))) 293 if (!Send(new GpuChannelMsg_CreateOffscreenSurface(size, &route_id)))
201 return NULL; 294 return NULL;
202 295
203 scoped_ptr<GpuSurfaceProxy> surface(new GpuSurfaceProxy(this, route_id)); 296 scoped_refptr<GpuSurfaceProxy> surface(new GpuSurfaceProxy(this, route_id));
204 router_.AddRoute(route_id, surface.get()); 297 AddRoute(route_id, surface.get());
205 298
206 return surface.release(); 299 return surface;
207 #endif 300 #endif
208 } 301 }
209 302
210 void GpuChannelHost::DestroySurface(GpuSurfaceProxy* surface) { 303 void GpuChannelHost::DestroySurface(GpuSurfaceProxy* surface) {
211 #if defined(ENABLE_GPU) 304 #if defined(ENABLE_GPU)
305 AutoLock lock(context_lock_);
212 Send(new GpuChannelMsg_DestroySurface(surface->route_id())); 306 Send(new GpuChannelMsg_DestroySurface(surface->route_id()));
213 if (router_.ResolveRoute(surface->route_id()))
214 router_.RemoveRoute(surface->route_id());
215 307
216 delete surface; 308 RemoveRoute(surface->route_id());
309 surface->Orphan();
217 #endif 310 #endif
218 } 311 }
312
313 void GpuChannelHost::AddRoute(
314 int route_id, scoped_refptr<GpuChannelListener> listener) {
315 DCHECK(listener->loop() && listener->loop() == MessageLoopProxy::current());
316
317 MessageLoopProxy* io_loop = RenderProcess::current()->io_message_loop_proxy();
318 io_loop->PostTask(FROM_HERE,
319 NewRunnableMethod(
320 channel_filter_.get(),
321 &GpuChannelHost::MessageFilter::AddRoute,
322 route_id, listener));
323 }
324
325 void GpuChannelHost::RemoveRoute(int route_id) {
326 MessageLoopProxy* io_loop = RenderProcess::current()->io_message_loop_proxy();
327 io_loop->PostTask(FROM_HERE,
328 NewRunnableMethod(
329 channel_filter_.get(),
330 &GpuChannelHost::MessageFilter::RemoveRoute,
331 route_id));
332 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698