gpu_channel_host.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/common/gpu/client/gpu_channel_host.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 77d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include <algorithm> 87d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/debug/trace_event.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/message_loop.h" 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h" 13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/posix/eintr_wrapper.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_restrictions.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/common/gpu/client/command_buffer_proxy_impl.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/common/gpu/gpu_messages.h" 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "gpu/command_buffer/common/mailbox.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ipc/ipc_sync_message_filter.h" 197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_WIN) 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/common/sandbox_init.h" 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::AutoLock; 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::MessageLoopProxy; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content { 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GpuListenerInfo::GpuListenerInfo() {} 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GpuListenerInfo::~GpuListenerInfo() {} 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// static 357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)scoped_refptr<GpuChannelHost> GpuChannelHost::Create( 367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) GpuChannelHostFactory* factory, 377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) int gpu_host_id, 387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) int client_id, 397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const gpu::GPUInfo& gpu_info, 407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const IPC::ChannelHandle& channel_handle) { 417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK(factory->IsMainThread()); 427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) scoped_refptr<GpuChannelHost> host = new GpuChannelHost( 437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) factory, gpu_host_id, client_id, gpu_info); 447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) host->Connect(channel_handle); 457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return host; 467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)GpuChannelHost::GpuChannelHost(GpuChannelHostFactory* factory, 497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) int gpu_host_id, 507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) int client_id, 517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const gpu::GPUInfo& gpu_info) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : factory_(factory), 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_id_(client_id), 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gpu_host_id_(gpu_host_id), 557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) gpu_info_(gpu_info) { 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) next_transfer_buffer_id_.GetNext(); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void GpuChannelHost::Connect(const IPC::ChannelHandle& channel_handle) { 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Open a channel to the GPU process. We pass NULL as the main listener here 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // since we need to filter everything to route it to the right thread. 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<base::MessageLoopProxy> io_loop = factory_->GetIOLoopProxy(); 63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) channel_.reset(new IPC::SyncChannel(channel_handle, 64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) IPC::Channel::MODE_CLIENT, 65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) NULL, 66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) io_loop.get(), 67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) true, 68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) factory_->GetShutDownEvent())); 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sync_filter_ = new IPC::SyncMessageFilter( 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) factory_->GetShutDownEvent()); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) channel_->AddFilter(sync_filter_.get()); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) channel_filter_ = new MessageFilter(); 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Install the filter last, because we intercept all leftover 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // messages. 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) channel_->AddFilter(channel_filter_.get()); 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool GpuChannelHost::Send(IPC::Message* msg) { 837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // Callee takes ownership of message, regardless of whether Send is 847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // successful. See IPC::Sender. 857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) scoped_ptr<IPC::Message> message(msg); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The GPU process never sends synchronous IPCs so clear the unblock flag to 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // preserve order. 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) message->set_unblock(false); 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Currently we need to choose between two different mechanisms for sending. 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // On the main thread we use the regular channel Send() method, on another 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // thread we use SyncMessageFilter. We also have to be careful interpreting 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // IsMainThread() since it might return false during shutdown, 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // impl we are actually calling from the main thread (discard message then). 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO: Can we just always use sync_filter_ since we setup the channel 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // without a main listener? 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (factory_->IsMainThread()) { 997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // http://crbug.com/125264 1007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) base::ThreadRestrictions::ScopedAllowWait allow_wait; 1017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return channel_->Send(message.release()); 102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else if (base::MessageLoop::current()) { 1037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return sync_filter_->Send(message.release()); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CommandBufferProxyImpl* GpuChannelHost::CreateViewCommandBuffer( 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int32 surface_id, 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CommandBufferProxyImpl* share_group, 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& allowed_extensions, 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::vector<int32>& attribs, 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL& active_url, 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::GpuPreference gpu_preference) { 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TRACE_EVENT1("gpu", 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "GpuChannelHost::CreateViewCommandBuffer", 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "surface_id", 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) surface_id); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GPUCreateCommandBufferConfig init_params; 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) init_params.share_group_id = 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) share_group ? share_group->GetRouteID() : MSG_ROUTING_NONE; 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) init_params.allowed_extensions = allowed_extensions; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) init_params.attribs = attribs; 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) init_params.active_url = active_url; 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) init_params.gpu_preference = gpu_preference; 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int32 route_id = factory_->CreateViewCommandBuffer(surface_id, init_params); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (route_id == MSG_ROUTING_NONE) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CommandBufferProxyImpl* command_buffer = 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new CommandBufferProxyImpl(this, route_id); 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddRoute(route_id, command_buffer->AsWeakPtr()); 1357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) AutoLock lock(context_lock_); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) proxies_[route_id] = command_buffer; 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return command_buffer; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CommandBufferProxyImpl* GpuChannelHost::CreateOffscreenCommandBuffer( 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::Size& size, 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CommandBufferProxyImpl* share_group, 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& allowed_extensions, 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::vector<int32>& attribs, 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL& active_url, 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::GpuPreference gpu_preference) { 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TRACE_EVENT0("gpu", "GpuChannelHost::CreateOffscreenCommandBuffer"); 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GPUCreateCommandBufferConfig init_params; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) init_params.share_group_id = 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) share_group ? share_group->GetRouteID() : MSG_ROUTING_NONE; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) init_params.allowed_extensions = allowed_extensions; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) init_params.attribs = attribs; 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) init_params.active_url = active_url; 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) init_params.gpu_preference = gpu_preference; 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int32 route_id; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!Send(new GpuChannelMsg_CreateOffscreenCommandBuffer(size, 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) init_params, 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &route_id))) { 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (route_id == MSG_ROUTING_NONE) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CommandBufferProxyImpl* command_buffer = 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new CommandBufferProxyImpl(this, route_id); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AddRoute(route_id, command_buffer->AsWeakPtr()); 1707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) AutoLock lock(context_lock_); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) proxies_[route_id] = command_buffer; 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return command_buffer; 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)scoped_ptr<media::VideoDecodeAccelerator> GpuChannelHost::CreateVideoDecoder( 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int command_buffer_route_id, 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) media::VideoCodecProfile profile, 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) media::VideoDecodeAccelerator::Client* client) { 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutoLock lock(context_lock_); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProxyMap::iterator it = proxies_.find(command_buffer_route_id); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(it != proxies_.end()); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CommandBufferProxyImpl* proxy = it->second; 184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return proxy->CreateVideoDecoder(profile, client).Pass(); 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GpuChannelHost::DestroyCommandBuffer( 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CommandBufferProxyImpl* command_buffer) { 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TRACE_EVENT0("gpu", "GpuChannelHost::DestroyCommandBuffer"); 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int route_id = command_buffer->GetRouteID(); 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Send(new GpuChannelMsg_DestroyCommandBuffer(route_id)); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RemoveRoute(route_id); 1947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 1957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) AutoLock lock(context_lock_); 1967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) proxies_.erase(route_id); 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete command_buffer; 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GpuChannelHost::CollectRenderingStatsForSurface( 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int surface_id, GpuRenderingStats* stats) { 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TRACE_EVENT0("gpu", "GpuChannelHost::CollectRenderingStats"); 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Send(new GpuChannelMsg_CollectRenderingStatsForSurface(surface_id, 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stats)); 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GpuChannelHost::AddRoute( 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int route_id, base::WeakPtr<IPC::Listener> listener) { 2107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK(MessageLoopProxy::current().get()); 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<base::MessageLoopProxy> io_loop = factory_->GetIOLoopProxy(); 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) io_loop->PostTask(FROM_HERE, 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&GpuChannelHost::MessageFilter::AddRoute, 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) channel_filter_.get(), route_id, listener, 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MessageLoopProxy::current())); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GpuChannelHost::RemoveRoute(int route_id) { 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<base::MessageLoopProxy> io_loop = factory_->GetIOLoopProxy(); 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) io_loop->PostTask(FROM_HERE, 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&GpuChannelHost::MessageFilter::RemoveRoute, 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) channel_filter_.get(), route_id)); 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::SharedMemoryHandle GpuChannelHost::ShareToGpuProcess( 227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::SharedMemoryHandle source_handle) { 2287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (IsLost()) 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return base::SharedMemory::NULLHandle(); 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_WIN) 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Windows needs to explicitly duplicate the handle out to another process. 233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::SharedMemoryHandle target_handle; 234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!BrokerDuplicateHandle(source_handle, 2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) channel_->peer_pid(), 236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &target_handle, 237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 0, 238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DUPLICATE_SAME_ACCESS)) { 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return base::SharedMemory::NULLHandle(); 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return target_handle; 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else 244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int duped_handle = HANDLE_EINTR(dup(source_handle.fd)); 245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (duped_handle < 0) 2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return base::SharedMemory::NULLHandle(); 2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return base::FileDescriptor(duped_handle, true); 249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif 2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GpuChannelHost::GenerateMailboxNames(unsigned num, 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::vector<gpu::Mailbox>* names) { 2547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK(names->empty()); 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TRACE_EVENT0("gpu", "GenerateMailboxName"); 2567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) size_t generate_count = channel_filter_->GetMailboxNames(num, names); 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (names->size() < num) { 2597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) std::vector<gpu::Mailbox> new_names; 2607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (!Send(new GpuChannelMsg_GenerateMailboxNames(num - names->size(), 2617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) &new_names))) 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) names->insert(names->end(), new_names.begin(), new_names.end()); 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (generate_count > 0) 2677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) Send(new GpuChannelMsg_GenerateMailboxNamesAsync(generate_count)); 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int32 GpuChannelHost::ReserveTransferBufferId() { 2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return next_transfer_buffer_id_.GetNext(); 2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)GpuChannelHost::~GpuChannelHost() { 2777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // channel_ must be destroyed on the main thread. 2787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (!factory_->IsMainThread()) 2797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) factory_->GetMainLoop()->DeleteSoon(FROM_HERE, channel_.release()); 2807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)GpuChannelHost::MessageFilter::MessageFilter() 2847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) : lost_(false), 2857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) requested_mailboxes_(0) { 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GpuChannelHost::MessageFilter::~MessageFilter() {} 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GpuChannelHost::MessageFilter::AddRoute( 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int route_id, 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::WeakPtr<IPC::Listener> listener, 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<MessageLoopProxy> loop) { 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(listeners_.find(route_id) == listeners_.end()); 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GpuListenerInfo info; 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info.listener = listener; 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info.loop = loop; 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) listeners_[route_id] = info; 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GpuChannelHost::MessageFilter::RemoveRoute(int route_id) { 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ListenerMap::iterator it = listeners_.find(route_id); 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it != listeners_.end()) 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) listeners_.erase(it); 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GpuChannelHost::MessageFilter::OnMessageReceived( 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const IPC::Message& message) { 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Never handle sync message replies or we will deadlock here. 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (message.is_reply()) 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (message.routing_id() == MSG_ROUTING_CONTROL) 3147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return OnControlMessageReceived(message); 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ListenerMap::iterator it = listeners_.find(message.routing_id()); 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it != listeners_.end()) { 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GpuListenerInfo& info = it->second; 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info.loop->PostTask( 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind( 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IgnoreResult(&IPC::Listener::OnMessageReceived), 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info.listener, 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) message)); 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GpuChannelHost::MessageFilter::OnChannelError() { 3327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // Set the lost state before signalling the proxies. That way, if they 3337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // themselves post a task to recreate the context, they will not try to re-use 3347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // this channel host. 3357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) { 3367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) AutoLock lock(lock_); 3377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) lost_ = true; 3387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) } 3397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Inform all the proxies that an error has occurred. This will be reported 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // via OpenGL as a lost context. 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (ListenerMap::iterator it = listeners_.begin(); 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != listeners_.end(); 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it++) { 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GpuListenerInfo& info = it->second; 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info.loop->PostTask( 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&IPC::Listener::OnChannelError, info.listener)); 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) listeners_.clear(); 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool GpuChannelHost::MessageFilter::IsLost() const { 3557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) AutoLock lock(lock_); 3567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return lost_; 3577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 3587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)size_t GpuChannelHost::MessageFilter::GetMailboxNames( 3607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) size_t num, std::vector<gpu::Mailbox>* names) { 3617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) AutoLock lock(lock_); 3627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) size_t count = std::min(num, mailbox_name_pool_.size()); 3637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) names->insert(names->begin(), 3647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) mailbox_name_pool_.end() - count, 3657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) mailbox_name_pool_.end()); 3667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) mailbox_name_pool_.erase(mailbox_name_pool_.end() - count, 3677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) mailbox_name_pool_.end()); 3687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const size_t ideal_mailbox_pool_size = 100; 3707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) size_t total = mailbox_name_pool_.size() + requested_mailboxes_; 3717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK_LE(total, ideal_mailbox_pool_size); 3727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (total >= ideal_mailbox_pool_size / 2) 3737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return 0; 3747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) size_t request = ideal_mailbox_pool_size - total; 3757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) requested_mailboxes_ += request; 3767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return request; 3777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 3787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool GpuChannelHost::MessageFilter::OnControlMessageReceived( 3807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const IPC::Message& message) { 3817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) bool handled = true; 3827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) IPC_BEGIN_MESSAGE_MAP(GpuChannelHost::MessageFilter, message) 3847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) IPC_MESSAGE_HANDLER(GpuChannelMsg_GenerateMailboxNamesReply, 3857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) OnGenerateMailboxNamesReply) 3867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) IPC_MESSAGE_UNHANDLED(handled = false) 3877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) IPC_END_MESSAGE_MAP() 3887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK(handled); 3907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return handled; 3917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 3927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 3937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void GpuChannelHost::MessageFilter::OnGenerateMailboxNamesReply( 3947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) const std::vector<gpu::Mailbox>& names) { 3957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) TRACE_EVENT0("gpu", "OnGenerateMailboxNamesReply"); 3967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) AutoLock lock(lock_); 3977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK_LE(names.size(), requested_mailboxes_); 3987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) requested_mailboxes_ -= names.size(); 3997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) mailbox_name_pool_.insert(mailbox_name_pool_.end(), 4007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) names.begin(), 4017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) names.end()); 4027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 4037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 4047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace content 406