| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/browser/gpu/browser_gpu_memory_buffer_manager.h" | 5 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h" |
| 6 | 6 |
| 7 #include "base/atomic_sequence_num.h" | 7 #include "base/atomic_sequence_num.h" |
| 8 #include "base/bind.h" | 8 #include "base/bind.h" |
| 9 #include "base/command_line.h" |
| 9 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
| 10 #include "base/synchronization/waitable_event.h" | 11 #include "base/synchronization/waitable_event.h" |
| 11 #include "base/threading/thread_restrictions.h" | 12 #include "base/threading/thread_restrictions.h" |
| 12 #include "base/trace_event/process_memory_dump.h" | 13 #include "base/trace_event/process_memory_dump.h" |
| 13 #include "base/trace_event/trace_event.h" | 14 #include "base/trace_event/trace_event.h" |
| 14 #include "content/common/gpu/client/gpu_memory_buffer_factory_host.h" | 15 #include "content/browser/gpu/gpu_process_host.h" |
| 15 #include "content/common/gpu/client/gpu_memory_buffer_impl.h" | 16 #include "content/common/gpu/client/gpu_memory_buffer_impl.h" |
| 16 #include "content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h" | 17 #include "content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h" |
| 18 #include "content/common/gpu/gpu_memory_buffer_factory_shared_memory.h" |
| 17 #include "content/public/browser/browser_thread.h" | 19 #include "content/public/browser/browser_thread.h" |
| 20 #include "content/public/common/content_switches.h" |
| 21 #include "gpu/GLES2/gl2extchromium.h" |
| 22 |
| 23 #if defined(OS_MACOSX) |
| 24 #include "content/common/gpu/gpu_memory_buffer_factory_io_surface.h" |
| 25 #endif |
| 26 |
| 27 #if defined(OS_ANDROID) |
| 28 #include "content/common/gpu/gpu_memory_buffer_factory_surface_texture.h" |
| 29 #endif |
| 30 |
| 31 #if defined(USE_OZONE) |
| 32 #include "content/common/gpu/gpu_memory_buffer_factory_ozone_native_buffer.h" |
| 33 #endif |
| 18 | 34 |
| 19 namespace content { | 35 namespace content { |
| 20 namespace { | 36 namespace { |
| 21 | 37 |
| 38 void GpuMemoryBufferDeleted( |
| 39 scoped_refptr<base::SingleThreadTaskRunner> destruction_task_runner, |
| 40 const GpuMemoryBufferImpl::DestructionCallback& destruction_callback, |
| 41 uint32 sync_point) { |
| 42 destruction_task_runner->PostTask( |
| 43 FROM_HERE, base::Bind(destruction_callback, sync_point)); |
| 44 } |
| 45 |
| 46 bool IsGpuMemoryBufferFactoryConfigurationSupported( |
| 47 gfx::GpuMemoryBufferType type, |
| 48 const GpuMemoryBufferFactory::Configuration& configuration) { |
| 49 switch (type) { |
| 50 case gfx::SHARED_MEMORY_BUFFER: |
| 51 return GpuMemoryBufferFactorySharedMemory:: |
| 52 IsGpuMemoryBufferConfigurationSupported(configuration.format, |
| 53 configuration.usage); |
| 54 #if defined(OS_MACOSX) |
| 55 case gfx::IO_SURFACE_BUFFER: |
| 56 return GpuMemoryBufferFactoryIOSurface:: |
| 57 IsGpuMemoryBufferConfigurationSupported(configuration.format, |
| 58 configuration.usage); |
| 59 #endif |
| 60 #if defined(OS_ANDROID) |
| 61 case gfx::SURFACE_TEXTURE_BUFFER: |
| 62 return GpuMemoryBufferFactorySurfaceTexture:: |
| 63 IsGpuMemoryBufferConfigurationSupported(configuration.format, |
| 64 configuration.usage); |
| 65 #endif |
| 66 #if defined(USE_OZONE) |
| 67 case gfx::OZONE_NATIVE_BUFFER: |
| 68 return GpuMemoryBufferFactoryOzoneNativeBuffer:: |
| 69 IsGpuMemoryBufferConfigurationSupported(configuration.format, |
| 70 configuration.usage); |
| 71 #endif |
| 72 default: |
| 73 NOTREACHED(); |
| 74 return false; |
| 75 } |
| 76 } |
| 77 |
| 78 gfx::GpuMemoryBufferType GetGpuMemoryBufferFactoryType() { |
| 79 std::vector<gfx::GpuMemoryBufferType> supported_types; |
| 80 GpuMemoryBufferFactory::GetSupportedTypes(&supported_types); |
| 81 DCHECK(!supported_types.empty()); |
| 82 |
| 83 // The GPU service will always use the preferred type. |
| 84 return supported_types[0]; |
| 85 } |
| 86 |
| 87 std::vector<GpuMemoryBufferFactory::Configuration> |
| 88 GetSupportedGpuMemoryBufferConfigurations(gfx::GpuMemoryBufferType type) { |
| 89 std::vector<GpuMemoryBufferFactory::Configuration> configurations; |
| 90 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 91 switches::kEnableNativeGpuMemoryBuffers)) { |
| 92 const GpuMemoryBufferFactory::Configuration kNativeConfigurations[] = { |
| 93 {gfx::GpuMemoryBuffer::R_8, gfx::GpuMemoryBuffer::MAP}, |
| 94 {gfx::GpuMemoryBuffer::R_8, gfx::GpuMemoryBuffer::PERSISTENT_MAP}, |
| 95 {gfx::GpuMemoryBuffer::RGBA_4444, gfx::GpuMemoryBuffer::MAP}, |
| 96 {gfx::GpuMemoryBuffer::RGBA_4444, gfx::GpuMemoryBuffer::PERSISTENT_MAP}, |
| 97 {gfx::GpuMemoryBuffer::RGBA_8888, gfx::GpuMemoryBuffer::MAP}, |
| 98 {gfx::GpuMemoryBuffer::RGBA_8888, gfx::GpuMemoryBuffer::PERSISTENT_MAP}, |
| 99 {gfx::GpuMemoryBuffer::BGRA_8888, gfx::GpuMemoryBuffer::MAP}, |
| 100 {gfx::GpuMemoryBuffer::BGRA_8888, |
| 101 gfx::GpuMemoryBuffer::PERSISTENT_MAP}}; |
| 102 for (auto& configuration : kNativeConfigurations) { |
| 103 if (IsGpuMemoryBufferFactoryConfigurationSupported(type, configuration)) |
| 104 configurations.push_back(configuration); |
| 105 } |
| 106 } |
| 107 |
| 108 #if defined(USE_OZONE) |
| 109 const GpuMemoryBufferFactory::Configuration kScanoutConfigurations[] = { |
| 110 {gfx::GpuMemoryBuffer::BGRA_8888, gfx::GpuMemoryBuffer::SCANOUT}, |
| 111 {gfx::GpuMemoryBuffer::RGBX_8888, gfx::GpuMemoryBuffer::SCANOUT}}; |
| 112 for (auto& configuration : kScanoutConfigurations) { |
| 113 if (IsGpuMemoryBufferFactoryConfigurationSupported(type, configuration)) |
| 114 configurations.push_back(configuration); |
| 115 } |
| 116 #endif |
| 117 |
| 118 return configurations; |
| 119 } |
| 120 |
| 22 BrowserGpuMemoryBufferManager* g_gpu_memory_buffer_manager = nullptr; | 121 BrowserGpuMemoryBufferManager* g_gpu_memory_buffer_manager = nullptr; |
| 23 | 122 |
| 24 // Global atomic to generate gpu memory buffer unique IDs. | 123 // Global atomic to generate gpu memory buffer unique IDs. |
| 25 base::StaticAtomicSequenceNumber g_next_gpu_memory_buffer_id; | 124 base::StaticAtomicSequenceNumber g_next_gpu_memory_buffer_id; |
| 26 | 125 |
| 27 const char kMemoryAllocatorName[] = "gpumemorybuffer"; | 126 const char kMemoryAllocatorName[] = "gpumemorybuffer"; |
| 28 | 127 |
| 29 } // namespace | 128 } // namespace |
| 30 | 129 |
| 31 struct BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferRequest { | 130 struct BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferRequest { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 43 ~AllocateGpuMemoryBufferRequest() {} | 142 ~AllocateGpuMemoryBufferRequest() {} |
| 44 base::WaitableEvent event; | 143 base::WaitableEvent event; |
| 45 gfx::Size size; | 144 gfx::Size size; |
| 46 gfx::GpuMemoryBuffer::Format format; | 145 gfx::GpuMemoryBuffer::Format format; |
| 47 gfx::GpuMemoryBuffer::Usage usage; | 146 gfx::GpuMemoryBuffer::Usage usage; |
| 48 int client_id; | 147 int client_id; |
| 49 int surface_id; | 148 int surface_id; |
| 50 scoped_ptr<gfx::GpuMemoryBuffer> result; | 149 scoped_ptr<gfx::GpuMemoryBuffer> result; |
| 51 }; | 150 }; |
| 52 | 151 |
| 53 BrowserGpuMemoryBufferManager::BrowserGpuMemoryBufferManager( | 152 BrowserGpuMemoryBufferManager::BrowserGpuMemoryBufferManager(int gpu_client_id) |
| 54 GpuMemoryBufferFactoryHost* gpu_memory_buffer_factory_host, | 153 : factory_type_(GetGpuMemoryBufferFactoryType()), |
| 55 int gpu_client_id) | 154 supported_configurations_( |
| 56 : gpu_memory_buffer_factory_host_(gpu_memory_buffer_factory_host), | 155 GetSupportedGpuMemoryBufferConfigurations(factory_type_)), |
| 57 gpu_client_id_(gpu_client_id), | 156 gpu_client_id_(gpu_client_id), |
| 157 gpu_host_id_(0), |
| 58 weak_ptr_factory_(this) { | 158 weak_ptr_factory_(this) { |
| 59 DCHECK(!g_gpu_memory_buffer_manager); | 159 DCHECK(!g_gpu_memory_buffer_manager); |
| 60 g_gpu_memory_buffer_manager = this; | 160 g_gpu_memory_buffer_manager = this; |
| 61 } | 161 } |
| 62 | 162 |
| 63 BrowserGpuMemoryBufferManager::~BrowserGpuMemoryBufferManager() { | 163 BrowserGpuMemoryBufferManager::~BrowserGpuMemoryBufferManager() { |
| 64 g_gpu_memory_buffer_manager = nullptr; | 164 g_gpu_memory_buffer_manager = nullptr; |
| 65 } | 165 } |
| 66 | 166 |
| 67 // static | 167 // static |
| 68 BrowserGpuMemoryBufferManager* BrowserGpuMemoryBufferManager::current() { | 168 BrowserGpuMemoryBufferManager* BrowserGpuMemoryBufferManager::current() { |
| 69 return g_gpu_memory_buffer_manager; | 169 return g_gpu_memory_buffer_manager; |
| 70 } | 170 } |
| 71 | 171 |
| 172 // static |
| 173 uint32 BrowserGpuMemoryBufferManager::GetImageTextureTarget( |
| 174 gfx::GpuMemoryBuffer::Format format, |
| 175 gfx::GpuMemoryBuffer::Usage usage) { |
| 176 gfx::GpuMemoryBufferType type = GetGpuMemoryBufferFactoryType(); |
| 177 for (auto& configuration : GetSupportedGpuMemoryBufferConfigurations(type)) { |
| 178 if (configuration.format != format || configuration.usage != usage) |
| 179 continue; |
| 180 |
| 181 switch (type) { |
| 182 case gfx::SURFACE_TEXTURE_BUFFER: |
| 183 case gfx::OZONE_NATIVE_BUFFER: |
| 184 // GPU memory buffers that are shared with the GL using EGLImages |
| 185 // require TEXTURE_EXTERNAL_OES. |
| 186 return GL_TEXTURE_EXTERNAL_OES; |
| 187 case gfx::IO_SURFACE_BUFFER: |
| 188 // IOSurface backed images require GL_TEXTURE_RECTANGLE_ARB. |
| 189 return GL_TEXTURE_RECTANGLE_ARB; |
| 190 default: |
| 191 return GL_TEXTURE_2D; |
| 192 } |
| 193 } |
| 194 |
| 195 return GL_TEXTURE_2D; |
| 196 } |
| 197 |
| 72 scoped_ptr<gfx::GpuMemoryBuffer> | 198 scoped_ptr<gfx::GpuMemoryBuffer> |
| 73 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBuffer( | 199 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBuffer( |
| 74 const gfx::Size& size, | 200 const gfx::Size& size, |
| 75 gfx::GpuMemoryBuffer::Format format, | 201 gfx::GpuMemoryBuffer::Format format, |
| 76 gfx::GpuMemoryBuffer::Usage usage) { | 202 gfx::GpuMemoryBuffer::Usage usage) { |
| 77 return AllocateGpuMemoryBufferCommon(size, format, usage, 0); | 203 return AllocateGpuMemoryBufferForSurface(size, format, usage, 0); |
| 78 } | 204 } |
| 79 | 205 |
| 80 scoped_ptr<gfx::GpuMemoryBuffer> | 206 scoped_ptr<gfx::GpuMemoryBuffer> |
| 81 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForScanout( | 207 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForScanout( |
| 82 const gfx::Size& size, | 208 const gfx::Size& size, |
| 83 gfx::GpuMemoryBuffer::Format format, | 209 gfx::GpuMemoryBuffer::Format format, |
| 84 int32 surface_id) { | 210 int32 surface_id) { |
| 85 DCHECK_GT(surface_id, 0); | 211 DCHECK_GT(surface_id, 0); |
| 86 return AllocateGpuMemoryBufferCommon( | 212 return AllocateGpuMemoryBufferForSurface( |
| 87 size, format, gfx::GpuMemoryBuffer::SCANOUT, surface_id); | 213 size, format, gfx::GpuMemoryBuffer::SCANOUT, surface_id); |
| 88 } | 214 } |
| 89 | 215 |
| 90 scoped_ptr<gfx::GpuMemoryBuffer> | |
| 91 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferCommon( | |
| 92 const gfx::Size& size, | |
| 93 gfx::GpuMemoryBuffer::Format format, | |
| 94 gfx::GpuMemoryBuffer::Usage usage, | |
| 95 int32 surface_id) { | |
| 96 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 97 | |
| 98 // Fallback to shared memory buffer if |format| and |usage| are not supported | |
| 99 // by factory. | |
| 100 if (!gpu_memory_buffer_factory_host_->IsGpuMemoryBufferConfigurationSupported( | |
| 101 format, usage)) { | |
| 102 DCHECK(GpuMemoryBufferImplSharedMemory::IsFormatSupported(format)) | |
| 103 << format; | |
| 104 DCHECK(GpuMemoryBufferImplSharedMemory::IsUsageSupported(usage)) << usage; | |
| 105 return GpuMemoryBufferImplSharedMemory::Create( | |
| 106 g_next_gpu_memory_buffer_id.GetNext(), size, format); | |
| 107 } | |
| 108 | |
| 109 AllocateGpuMemoryBufferRequest request(size, format, usage, gpu_client_id_, | |
| 110 surface_id); | |
| 111 BrowserThread::PostTask( | |
| 112 BrowserThread::IO, | |
| 113 FROM_HERE, | |
| 114 base::Bind(&BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferOnIO, | |
| 115 base::Unretained(this), // Safe as we wait for result below. | |
| 116 base::Unretained(&request))); | |
| 117 | |
| 118 // We're blocking the UI thread, which is generally undesirable. | |
| 119 TRACE_EVENT0("browser", | |
| 120 "BrowserGpuMemoryBufferManager::AllocateGpuMemoryBuffer"); | |
| 121 base::ThreadRestrictions::ScopedAllowWait allow_wait; | |
| 122 request.event.Wait(); | |
| 123 return request.result.Pass(); | |
| 124 } | |
| 125 | |
| 126 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForChildProcess( | 216 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForChildProcess( |
| 127 const gfx::Size& size, | 217 const gfx::Size& size, |
| 128 gfx::GpuMemoryBuffer::Format format, | 218 gfx::GpuMemoryBuffer::Format format, |
| 129 gfx::GpuMemoryBuffer::Usage usage, | 219 gfx::GpuMemoryBuffer::Usage usage, |
| 130 base::ProcessHandle child_process_handle, | 220 base::ProcessHandle child_process_handle, |
| 131 int child_client_id, | 221 int child_client_id, |
| 132 const AllocationCallback& callback) { | 222 const AllocationCallback& callback) { |
| 133 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 223 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 134 | 224 |
| 135 gfx::GpuMemoryBufferId new_id = g_next_gpu_memory_buffer_id.GetNext(); | 225 gfx::GpuMemoryBufferId new_id = g_next_gpu_memory_buffer_id.GetNext(); |
| 136 | 226 |
| 227 // Use service side allocation if this is a supported configuration. |
| 228 if (IsGpuMemoryBufferConfigurationSupported(format, usage)) { |
| 229 AllocateGpuMemoryBufferOnIO(new_id, size, format, usage, child_client_id, 0, |
| 230 false, callback); |
| 231 return; |
| 232 } |
| 233 |
| 234 // Early out if we cannot fallback to shared memory buffer. |
| 235 if (!GpuMemoryBufferImplSharedMemory::IsFormatSupported(format) || |
| 236 !GpuMemoryBufferImplSharedMemory::IsUsageSupported(usage) || |
| 237 !GpuMemoryBufferImplSharedMemory::IsSizeValidForFormat(size, format)) { |
| 238 callback.Run(gfx::GpuMemoryBufferHandle()); |
| 239 return; |
| 240 } |
| 241 |
| 137 BufferMap& buffers = clients_[child_client_id]; | 242 BufferMap& buffers = clients_[child_client_id]; |
| 138 DCHECK(buffers.find(new_id) == buffers.end()); | 243 DCHECK(buffers.find(new_id) == buffers.end()); |
| 139 | 244 |
| 140 // Fallback to shared memory buffer if |format| and |usage| are not supported | 245 // Allocate shared memory buffer as fallback. |
| 141 // by factory. | 246 buffers[new_id] = |
| 142 if (!gpu_memory_buffer_factory_host_->IsGpuMemoryBufferConfigurationSupported( | 247 BufferInfo(size, gfx::SHARED_MEMORY_BUFFER, format, usage, 0); |
| 143 format, usage)) { | 248 callback.Run(GpuMemoryBufferImplSharedMemory::AllocateForChildProcess( |
| 144 // Early out if we cannot fallback to shared memory buffer. | 249 new_id, size, format, child_process_handle)); |
| 145 if (!GpuMemoryBufferImplSharedMemory::IsFormatSupported(format) || | |
| 146 !GpuMemoryBufferImplSharedMemory::IsUsageSupported(usage) || | |
| 147 !GpuMemoryBufferImplSharedMemory::IsSizeValidForFormat(size, format)) { | |
| 148 callback.Run(gfx::GpuMemoryBufferHandle()); | |
| 149 return; | |
| 150 } | |
| 151 | |
| 152 buffers[new_id] = BufferInfo(size, format, gfx::SHARED_MEMORY_BUFFER); | |
| 153 callback.Run(GpuMemoryBufferImplSharedMemory::AllocateForChildProcess( | |
| 154 new_id, size, format, child_process_handle)); | |
| 155 return; | |
| 156 } | |
| 157 | |
| 158 // Note: Handling of cases where the child process is removed before the | |
| 159 // allocation completes is less subtle if we set the buffer type to | |
| 160 // EMPTY_BUFFER here and verify that this has not changed when allocation | |
| 161 // completes. | |
| 162 buffers[new_id] = BufferInfo(size, format, gfx::EMPTY_BUFFER); | |
| 163 | |
| 164 gpu_memory_buffer_factory_host_->CreateGpuMemoryBuffer( | |
| 165 new_id, size, format, usage, child_client_id, 0, | |
| 166 base::Bind(&BrowserGpuMemoryBufferManager:: | |
| 167 GpuMemoryBufferAllocatedForChildProcess, | |
| 168 weak_ptr_factory_.GetWeakPtr(), new_id, child_client_id, | |
| 169 callback)); | |
| 170 } | 250 } |
| 171 | 251 |
| 172 gfx::GpuMemoryBuffer* | 252 gfx::GpuMemoryBuffer* |
| 173 BrowserGpuMemoryBufferManager::GpuMemoryBufferFromClientBuffer( | 253 BrowserGpuMemoryBufferManager::GpuMemoryBufferFromClientBuffer( |
| 174 ClientBuffer buffer) { | 254 ClientBuffer buffer) { |
| 175 return GpuMemoryBufferImpl::FromClientBuffer(buffer); | 255 return GpuMemoryBufferImpl::FromClientBuffer(buffer); |
| 176 } | 256 } |
| 177 | 257 |
| 178 void BrowserGpuMemoryBufferManager::SetDestructionSyncPoint( | 258 void BrowserGpuMemoryBufferManager::SetDestructionSyncPoint( |
| 179 gfx::GpuMemoryBuffer* buffer, | 259 gfx::GpuMemoryBuffer* buffer, |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 212 | 292 |
| 213 return true; | 293 return true; |
| 214 } | 294 } |
| 215 | 295 |
| 216 void BrowserGpuMemoryBufferManager::ChildProcessDeletedGpuMemoryBuffer( | 296 void BrowserGpuMemoryBufferManager::ChildProcessDeletedGpuMemoryBuffer( |
| 217 gfx::GpuMemoryBufferId id, | 297 gfx::GpuMemoryBufferId id, |
| 218 base::ProcessHandle child_process_handle, | 298 base::ProcessHandle child_process_handle, |
| 219 int child_client_id, | 299 int child_client_id, |
| 220 uint32 sync_point) { | 300 uint32 sync_point) { |
| 221 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 301 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 222 DCHECK(clients_.find(child_client_id) != clients_.end()); | |
| 223 | 302 |
| 224 BufferMap& buffers = clients_[child_client_id]; | 303 DestroyGpuMemoryBufferOnIO(id, child_client_id, sync_point); |
| 225 | |
| 226 BufferMap::iterator buffer_it = buffers.find(id); | |
| 227 if (buffer_it == buffers.end()) { | |
| 228 LOG(ERROR) << "Invalid GpuMemoryBuffer ID for child process."; | |
| 229 return; | |
| 230 } | |
| 231 | |
| 232 // This can happen if a child process managed to trigger a call to this while | |
| 233 // a buffer is in the process of being allocated. | |
| 234 if (buffer_it->second.type == gfx::EMPTY_BUFFER) { | |
| 235 LOG(ERROR) << "Invalid GpuMemoryBuffer type."; | |
| 236 return; | |
| 237 } | |
| 238 | |
| 239 // Buffers allocated using the factory need to be destroyed through the | |
| 240 // factory. | |
| 241 if (buffer_it->second.type != gfx::SHARED_MEMORY_BUFFER) { | |
| 242 gpu_memory_buffer_factory_host_->DestroyGpuMemoryBuffer(id, | |
| 243 child_client_id, | |
| 244 sync_point); | |
| 245 } | |
| 246 | |
| 247 buffers.erase(buffer_it); | |
| 248 } | 304 } |
| 249 | 305 |
| 250 void BrowserGpuMemoryBufferManager::ProcessRemoved( | 306 void BrowserGpuMemoryBufferManager::ProcessRemoved( |
| 251 base::ProcessHandle process_handle, | 307 base::ProcessHandle process_handle, |
| 252 int client_id) { | 308 int client_id) { |
| 253 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 309 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 254 | 310 |
| 255 ClientMap::iterator client_it = clients_.find(client_id); | 311 ClientMap::iterator client_it = clients_.find(client_id); |
| 256 if (client_it == clients_.end()) | 312 if (client_it == clients_.end()) |
| 257 return; | 313 return; |
| 258 | 314 |
| 259 for (const auto& buffer : client_it->second) { | 315 for (const auto& buffer : client_it->second) { |
| 260 // This might happen if buffer is currenlty in the process of being | 316 // This might happen if buffer is currenlty in the process of being |
| 261 // allocated. The buffer will in that case be cleaned up when allocation | 317 // allocated. The buffer will in that case be cleaned up when allocation |
| 262 // completes. | 318 // completes. |
| 263 if (buffer.second.type == gfx::EMPTY_BUFFER) | 319 if (buffer.second.type == gfx::EMPTY_BUFFER) |
| 264 continue; | 320 continue; |
| 265 | 321 |
| 266 // Skip shared memory buffers as they were not allocated using the factory. | 322 GpuProcessHost* host = GpuProcessHost::FromID(buffer.second.gpu_host_id); |
| 267 if (buffer.second.type == gfx::SHARED_MEMORY_BUFFER) | 323 if (host) |
| 268 continue; | 324 host->DestroyGpuMemoryBuffer(buffer.first, client_id, 0); |
| 269 | |
| 270 gpu_memory_buffer_factory_host_->DestroyGpuMemoryBuffer(buffer.first, | |
| 271 client_id, 0); | |
| 272 } | 325 } |
| 273 | 326 |
| 274 clients_.erase(client_it); | 327 clients_.erase(client_it); |
| 275 } | 328 } |
| 276 | 329 |
| 277 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferOnIO( | 330 scoped_ptr<gfx::GpuMemoryBuffer> |
| 278 AllocateGpuMemoryBufferRequest* request) { | 331 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForSurface( |
| 279 // Note: Unretained is safe as this is only used for synchronous allocation | 332 const gfx::Size& size, |
| 280 // from a non-IO thread. | 333 gfx::GpuMemoryBuffer::Format format, |
| 281 gpu_memory_buffer_factory_host_->CreateGpuMemoryBuffer( | 334 gfx::GpuMemoryBuffer::Usage usage, |
| 282 g_next_gpu_memory_buffer_id.GetNext(), request->size, request->format, | 335 int32 surface_id) { |
| 283 request->usage, request->client_id, request->surface_id, | 336 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 284 base::Bind(&BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO, | 337 |
| 285 base::Unretained(this), base::Unretained(request))); | 338 AllocateGpuMemoryBufferRequest request(size, format, usage, gpu_client_id_, |
| 339 surface_id); |
| 340 BrowserThread::PostTask( |
| 341 BrowserThread::IO, FROM_HERE, |
| 342 base::Bind( |
| 343 &BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForSurfaceOnIO, |
| 344 base::Unretained(this), // Safe as we wait for result below. |
| 345 base::Unretained(&request))); |
| 346 |
| 347 // We're blocking the UI thread, which is generally undesirable. |
| 348 TRACE_EVENT0( |
| 349 "browser", |
| 350 "BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForSurface"); |
| 351 base::ThreadRestrictions::ScopedAllowWait allow_wait; |
| 352 request.event.Wait(); |
| 353 return request.result.Pass(); |
| 286 } | 354 } |
| 287 | 355 |
| 288 void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO( | 356 bool BrowserGpuMemoryBufferManager::IsGpuMemoryBufferConfigurationSupported( |
| 357 gfx::GpuMemoryBuffer::Format format, |
| 358 gfx::GpuMemoryBuffer::Usage usage) const { |
| 359 for (auto& configuration : supported_configurations_) { |
| 360 if (configuration.format == format && configuration.usage == usage) |
| 361 return true; |
| 362 } |
| 363 return false; |
| 364 } |
| 365 |
| 366 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForSurfaceOnIO( |
| 367 AllocateGpuMemoryBufferRequest* request) { |
| 368 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 369 |
| 370 gfx::GpuMemoryBufferId new_id = g_next_gpu_memory_buffer_id.GetNext(); |
| 371 |
| 372 // Use service side allocation if this is a supported configuration. |
| 373 if (IsGpuMemoryBufferConfigurationSupported(request->format, |
| 374 request->usage)) { |
| 375 // Note: Unretained is safe as this is only used for synchronous allocation |
| 376 // from a non-IO thread. |
| 377 AllocateGpuMemoryBufferOnIO( |
| 378 new_id, request->size, request->format, request->usage, |
| 379 request->client_id, request->surface_id, false, |
| 380 base::Bind(&BrowserGpuMemoryBufferManager:: |
| 381 GpuMemoryBufferAllocatedForSurfaceOnIO, |
| 382 base::Unretained(this), base::Unretained(request))); |
| 383 return; |
| 384 } |
| 385 |
| 386 DCHECK(GpuMemoryBufferImplSharedMemory::IsFormatSupported(request->format)) |
| 387 << request->format; |
| 388 DCHECK(GpuMemoryBufferImplSharedMemory::IsUsageSupported(request->usage)) |
| 389 << request->usage; |
| 390 |
| 391 BufferMap& buffers = clients_[request->client_id]; |
| 392 DCHECK(buffers.find(new_id) == buffers.end()); |
| 393 |
| 394 // Allocate shared memory buffer as fallback. |
| 395 buffers[new_id] = BufferInfo(request->size, gfx::SHARED_MEMORY_BUFFER, |
| 396 request->format, request->usage, 0); |
| 397 request->result = GpuMemoryBufferImplSharedMemory::Create( |
| 398 new_id, request->size, request->format); |
| 399 request->event.Signal(); |
| 400 } |
| 401 |
| 402 void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedForSurfaceOnIO( |
| 289 AllocateGpuMemoryBufferRequest* request, | 403 AllocateGpuMemoryBufferRequest* request, |
| 290 const gfx::GpuMemoryBufferHandle& handle) { | 404 const gfx::GpuMemoryBufferHandle& handle) { |
| 291 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 405 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 292 | 406 |
| 293 // Early out if factory failed to allocate the buffer. | 407 // Early out if factory failed to allocate the buffer. |
| 294 if (handle.is_null()) { | 408 if (handle.is_null()) { |
| 295 request->event.Signal(); | 409 request->event.Signal(); |
| 296 return; | 410 return; |
| 297 } | 411 } |
| 298 | 412 |
| 299 DCHECK_NE(handle.type, gfx::SHARED_MEMORY_BUFFER); | |
| 300 request->result = GpuMemoryBufferImpl::CreateFromHandle( | 413 request->result = GpuMemoryBufferImpl::CreateFromHandle( |
| 301 handle, request->size, request->format, request->usage, | 414 handle, request->size, request->format, request->usage, |
| 302 base::Bind(&BrowserGpuMemoryBufferManager::GpuMemoryBufferDeleted, | 415 base::Bind( |
| 303 weak_ptr_factory_.GetWeakPtr(), handle.id, | 416 &GpuMemoryBufferDeleted, |
| 304 request->client_id)); | 417 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO), |
| 418 base::Bind(&BrowserGpuMemoryBufferManager::DestroyGpuMemoryBufferOnIO, |
| 419 weak_ptr_factory_.GetWeakPtr(), handle.id, |
| 420 request->client_id))); |
| 305 request->event.Signal(); | 421 request->event.Signal(); |
| 306 } | 422 } |
| 307 | 423 |
| 308 void BrowserGpuMemoryBufferManager::GpuMemoryBufferDeleted( | 424 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferOnIO( |
| 425 gfx::GpuMemoryBufferId id, |
| 426 const gfx::Size& size, |
| 427 gfx::GpuMemoryBuffer::Format format, |
| 428 gfx::GpuMemoryBuffer::Usage usage, |
| 429 int client_id, |
| 430 int surface_id, |
| 431 bool reused_gpu_process, |
| 432 const AllocationCallback& callback) { |
| 433 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 434 |
| 435 BufferMap& buffers = clients_[client_id]; |
| 436 DCHECK(buffers.find(id) == buffers.end()); |
| 437 |
| 438 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id_); |
| 439 if (!host) { |
| 440 host = GpuProcessHost::Get(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED, |
| 441 CAUSE_FOR_GPU_LAUNCH_GPU_MEMORY_BUFFER_ALLOCATE); |
| 442 if (!host) { |
| 443 LOG(ERROR) << "Failed to launch GPU process."; |
| 444 callback.Run(gfx::GpuMemoryBufferHandle()); |
| 445 return; |
| 446 } |
| 447 gpu_host_id_ = host->host_id(); |
| 448 reused_gpu_process = false; |
| 449 } else { |
| 450 if (reused_gpu_process) { |
| 451 // We come here if we retried to allocate the buffer because of a |
| 452 // failure in GpuMemoryBufferAllocatedOnIO, but we ended up with the |
| 453 // same process ID, meaning the failure was not because of a channel |
| 454 // error, but another reason. So fail now. |
| 455 LOG(ERROR) << "Failed to allocate GpuMemoryBuffer."; |
| 456 callback.Run(gfx::GpuMemoryBufferHandle()); |
| 457 return; |
| 458 } |
| 459 reused_gpu_process = true; |
| 460 } |
| 461 |
| 462 // Note: Handling of cases where the client is removed before the allocation |
| 463 // completes is less subtle if we set the buffer type to EMPTY_BUFFER here |
| 464 // and verify that this has not changed when allocation completes. |
| 465 buffers[id] = BufferInfo(size, gfx::EMPTY_BUFFER, format, usage, 0); |
| 466 |
| 467 host->CreateGpuMemoryBuffer( |
| 468 id, size, format, usage, client_id, surface_id, |
| 469 base::Bind(&BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO, |
| 470 weak_ptr_factory_.GetWeakPtr(), id, client_id, surface_id, |
| 471 gpu_host_id_, reused_gpu_process, callback)); |
| 472 } |
| 473 |
| 474 void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO( |
| 309 gfx::GpuMemoryBufferId id, | 475 gfx::GpuMemoryBufferId id, |
| 310 int client_id, | 476 int client_id, |
| 311 uint32 sync_point) { | 477 int surface_id, |
| 312 gpu_memory_buffer_factory_host_->DestroyGpuMemoryBuffer(id, | 478 int gpu_host_id, |
| 313 client_id, | 479 bool reused_gpu_process, |
| 314 sync_point); | |
| 315 } | |
| 316 | |
| 317 void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedForChildProcess( | |
| 318 gfx::GpuMemoryBufferId id, | |
| 319 int child_client_id, | |
| 320 const AllocationCallback& callback, | 480 const AllocationCallback& callback, |
| 321 const gfx::GpuMemoryBufferHandle& handle) { | 481 const gfx::GpuMemoryBufferHandle& handle) { |
| 322 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 482 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 323 | 483 |
| 324 ClientMap::iterator client_it = clients_.find(child_client_id); | 484 ClientMap::iterator client_it = clients_.find(client_id); |
| 325 | 485 |
| 326 // This can happen if the child process is removed while the buffer is being | 486 // This can happen if client is removed while the buffer is being allocated. |
| 327 // allocated. | |
| 328 if (client_it == clients_.end()) { | 487 if (client_it == clients_.end()) { |
| 329 if (!handle.is_null()) { | 488 if (!handle.is_null()) { |
| 330 gpu_memory_buffer_factory_host_->DestroyGpuMemoryBuffer( | 489 GpuProcessHost* host = GpuProcessHost::FromID(gpu_host_id); |
| 331 handle.id, child_client_id, 0); | 490 if (host) |
| 491 host->DestroyGpuMemoryBuffer(handle.id, client_id, 0); |
| 332 } | 492 } |
| 333 callback.Run(gfx::GpuMemoryBufferHandle()); | 493 callback.Run(gfx::GpuMemoryBufferHandle()); |
| 334 return; | 494 return; |
| 335 } | 495 } |
| 336 | 496 |
| 337 BufferMap& buffers = client_it->second; | 497 BufferMap& buffers = client_it->second; |
| 338 | 498 |
| 339 BufferMap::iterator buffer_it = buffers.find(id); | 499 BufferMap::iterator buffer_it = buffers.find(id); |
| 340 DCHECK(buffer_it != buffers.end()); | 500 DCHECK(buffer_it != buffers.end()); |
| 341 DCHECK_EQ(buffer_it->second.type, gfx::EMPTY_BUFFER); | 501 DCHECK_EQ(buffer_it->second.type, gfx::EMPTY_BUFFER); |
| 342 | 502 |
| 343 // If the handle isn't valid, that means that the GPU process crashed or is | 503 // If the handle isn't valid, that means that the GPU process crashed or is |
| 344 // misbehaving so we remove the buffer entry and run the allocation callback | 504 // misbehaving. |
| 345 // with an empty handle to indicate failure. | 505 bool valid_handle = !handle.is_null() && handle.id == id; |
| 346 bool valid_handle = !handle.is_null() && handle.id == id && | |
| 347 handle.type != gfx::SHARED_MEMORY_BUFFER; | |
| 348 if (!valid_handle) { | 506 if (!valid_handle) { |
| 349 buffers.erase(buffer_it); | 507 // If we failed after re-using the GPU process, it may have died in the |
| 350 callback.Run(gfx::GpuMemoryBufferHandle()); | 508 // mean time. Retry to have a chance to create a fresh GPU process. |
| 509 if (handle.is_null() && reused_gpu_process) { |
| 510 DVLOG(1) << "Failed to create buffer through existing GPU process. " |
| 511 "Trying to restart GPU process."; |
| 512 // If the GPU process has already been restarted, retry without failure |
| 513 // when GPU process host ID already exists. |
| 514 if (gpu_host_id != gpu_host_id_) |
| 515 reused_gpu_process = false; |
| 516 gfx::Size size = buffer_it->second.size; |
| 517 gfx::GpuMemoryBuffer::Format format = buffer_it->second.format; |
| 518 gfx::GpuMemoryBuffer::Usage usage = buffer_it->second.usage; |
| 519 // Remove the buffer entry and call AllocateGpuMemoryBufferOnIO again. |
| 520 buffers.erase(buffer_it); |
| 521 AllocateGpuMemoryBufferOnIO(id, size, format, usage, client_id, |
| 522 surface_id, reused_gpu_process, callback); |
| 523 } else { |
| 524 // Remove the buffer entry and run the allocation callback with an empty |
| 525 // handle to indicate failure. |
| 526 buffers.erase(buffer_it); |
| 527 callback.Run(gfx::GpuMemoryBufferHandle()); |
| 528 } |
| 351 return; | 529 return; |
| 352 } | 530 } |
| 353 | 531 |
| 354 // Store the type of this buffer so it can be cleaned up if the child | 532 // Store the type and host id of this buffer so it can be cleaned up if the |
| 355 // process is removed. | 533 // client is removed. |
| 356 buffer_it->second.type = handle.type; | 534 buffer_it->second.type = handle.type; |
| 535 buffer_it->second.gpu_host_id = gpu_host_id; |
| 357 | 536 |
| 358 callback.Run(handle); | 537 callback.Run(handle); |
| 359 } | 538 } |
| 360 | 539 |
| 540 void BrowserGpuMemoryBufferManager::DestroyGpuMemoryBufferOnIO( |
| 541 gfx::GpuMemoryBufferId id, |
| 542 int client_id, |
| 543 uint32 sync_point) { |
| 544 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 545 DCHECK(clients_.find(client_id) != clients_.end()); |
| 546 |
| 547 BufferMap& buffers = clients_[client_id]; |
| 548 |
| 549 BufferMap::iterator buffer_it = buffers.find(id); |
| 550 if (buffer_it == buffers.end()) { |
| 551 LOG(ERROR) << "Invalid GpuMemoryBuffer ID for client."; |
| 552 return; |
| 553 } |
| 554 |
| 555 // This can happen if a client managed to call this while a buffer is in the |
| 556 // process of being allocated. |
| 557 if (buffer_it->second.type == gfx::EMPTY_BUFFER) { |
| 558 LOG(ERROR) << "Invalid GpuMemoryBuffer type."; |
| 559 return; |
| 560 } |
| 561 |
| 562 GpuProcessHost* host = GpuProcessHost::FromID(buffer_it->second.gpu_host_id); |
| 563 if (host) |
| 564 host->DestroyGpuMemoryBuffer(id, client_id, sync_point); |
| 565 |
| 566 buffers.erase(buffer_it); |
| 567 } |
| 568 |
| 361 } // namespace content | 569 } // namespace content |
| OLD | NEW |