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

Side by Side Diff: content/browser/gpu/browser_gpu_memory_buffer_manager.cc

Issue 1189943002: content: Fix lost context handling when using native GpuMemoryBuffers. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: retry logic and remove singleton Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698