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