Add an exponential backoff to rechecking the app list doodle.
[chromium-blink-merge.git] / content / browser / gpu / browser_gpu_memory_buffer_manager.cc
blob59b2ed7f26f9081b053248e234bbc7ee58914df1
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
3 // found in the LICENSE file.
5 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
7 #include "base/atomic_sequence_num.h"
8 #include "base/bind.h"
9 #include "base/lazy_instance.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "base/threading/thread_restrictions.h"
12 #include "base/trace_event/trace_event.h"
13 #include "content/common/gpu/client/gpu_memory_buffer_factory_host.h"
14 #include "content/common/gpu/client/gpu_memory_buffer_impl.h"
15 #include "content/common/gpu/client/gpu_memory_buffer_impl_shared_memory.h"
16 #include "content/public/browser/browser_thread.h"
18 namespace content {
19 namespace {
21 BrowserGpuMemoryBufferManager* g_gpu_memory_buffer_manager = nullptr;
23 // Global atomic to generate gpu memory buffer unique IDs.
24 base::StaticAtomicSequenceNumber g_next_gpu_memory_buffer_id;
26 } // namespace
28 struct BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferRequest {
29 AllocateGpuMemoryBufferRequest(const gfx::Size& size,
30 gfx::GpuMemoryBuffer::Format format,
31 gfx::GpuMemoryBuffer::Usage usage,
32 int client_id,
33 int surface_id)
34 : event(true, false),
35 size(size),
36 format(format),
37 usage(usage),
38 client_id(client_id),
39 surface_id(surface_id) {}
40 ~AllocateGpuMemoryBufferRequest() {}
41 base::WaitableEvent event;
42 gfx::Size size;
43 gfx::GpuMemoryBuffer::Format format;
44 gfx::GpuMemoryBuffer::Usage usage;
45 int client_id;
46 int surface_id;
47 scoped_ptr<gfx::GpuMemoryBuffer> result;
50 BrowserGpuMemoryBufferManager::BrowserGpuMemoryBufferManager(
51 GpuMemoryBufferFactoryHost* gpu_memory_buffer_factory_host,
52 int gpu_client_id)
53 : gpu_memory_buffer_factory_host_(gpu_memory_buffer_factory_host),
54 gpu_client_id_(gpu_client_id),
55 weak_ptr_factory_(this) {
56 DCHECK(!g_gpu_memory_buffer_manager);
57 g_gpu_memory_buffer_manager = this;
60 BrowserGpuMemoryBufferManager::~BrowserGpuMemoryBufferManager() {
61 g_gpu_memory_buffer_manager = nullptr;
64 // static
65 BrowserGpuMemoryBufferManager* BrowserGpuMemoryBufferManager::current() {
66 return g_gpu_memory_buffer_manager;
69 scoped_ptr<gfx::GpuMemoryBuffer>
70 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBuffer(
71 const gfx::Size& size,
72 gfx::GpuMemoryBuffer::Format format,
73 gfx::GpuMemoryBuffer::Usage usage) {
74 return AllocateGpuMemoryBufferCommon(size, format, usage, 0);
77 scoped_ptr<gfx::GpuMemoryBuffer>
78 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForScanout(
79 const gfx::Size& size,
80 gfx::GpuMemoryBuffer::Format format,
81 int32 surface_id) {
82 DCHECK_GT(surface_id, 0);
83 return AllocateGpuMemoryBufferCommon(
84 size, format, gfx::GpuMemoryBuffer::SCANOUT, surface_id);
87 scoped_ptr<gfx::GpuMemoryBuffer>
88 BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferCommon(
89 const gfx::Size& size,
90 gfx::GpuMemoryBuffer::Format format,
91 gfx::GpuMemoryBuffer::Usage usage,
92 int32 surface_id) {
93 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
95 // Fallback to shared memory buffer if |format| and |usage| are not supported
96 // by factory.
97 if (!gpu_memory_buffer_factory_host_->IsGpuMemoryBufferConfigurationSupported(
98 format, usage)) {
99 DCHECK(GpuMemoryBufferImplSharedMemory::IsFormatSupported(format));
100 DCHECK_EQ(usage, gfx::GpuMemoryBuffer::MAP);
101 return GpuMemoryBufferImplSharedMemory::Create(
102 g_next_gpu_memory_buffer_id.GetNext(), size, format);
105 AllocateGpuMemoryBufferRequest request(size, format, usage, gpu_client_id_,
106 surface_id);
107 BrowserThread::PostTask(
108 BrowserThread::IO,
109 FROM_HERE,
110 base::Bind(&BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferOnIO,
111 base::Unretained(this), // Safe as we wait for result below.
112 base::Unretained(&request)));
114 // We're blocking the UI thread, which is generally undesirable.
115 TRACE_EVENT0("browser",
116 "BrowserGpuMemoryBufferManager::AllocateGpuMemoryBuffer");
117 base::ThreadRestrictions::ScopedAllowWait allow_wait;
118 request.event.Wait();
119 return request.result.Pass();
122 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferForChildProcess(
123 const gfx::Size& size,
124 gfx::GpuMemoryBuffer::Format format,
125 gfx::GpuMemoryBuffer::Usage usage,
126 base::ProcessHandle child_process_handle,
127 int child_client_id,
128 const AllocationCallback& callback) {
129 DCHECK_CURRENTLY_ON(BrowserThread::IO);
131 gfx::GpuMemoryBufferId new_id = g_next_gpu_memory_buffer_id.GetNext();
133 BufferMap& buffers = clients_[child_client_id];
134 DCHECK(buffers.find(new_id) == buffers.end());
136 // Fallback to shared memory buffer if |format| and |usage| are not supported
137 // by factory.
138 if (!gpu_memory_buffer_factory_host_->IsGpuMemoryBufferConfigurationSupported(
139 format, usage)) {
140 // Early out if we cannot fallback to shared memory buffer.
141 if (!GpuMemoryBufferImplSharedMemory::IsFormatSupported(format) ||
142 !GpuMemoryBufferImplSharedMemory::IsSizeValidForFormat(size, format) ||
143 usage != gfx::GpuMemoryBuffer::MAP) {
144 callback.Run(gfx::GpuMemoryBufferHandle());
145 return;
148 buffers[new_id] = gfx::SHARED_MEMORY_BUFFER;
149 callback.Run(GpuMemoryBufferImplSharedMemory::AllocateForChildProcess(
150 new_id, size, format, child_process_handle));
151 return;
154 // Note: Handling of cases where the child process is removed before the
155 // allocation completes is less subtle if we set the buffer type to
156 // EMPTY_BUFFER here and verify that this has not changed when allocation
157 // completes.
158 buffers[new_id] = gfx::EMPTY_BUFFER;
160 gpu_memory_buffer_factory_host_->CreateGpuMemoryBuffer(
161 new_id, size, format, usage, child_client_id, 0,
162 base::Bind(&BrowserGpuMemoryBufferManager::
163 GpuMemoryBufferAllocatedForChildProcess,
164 weak_ptr_factory_.GetWeakPtr(), child_client_id, callback));
167 gfx::GpuMemoryBuffer*
168 BrowserGpuMemoryBufferManager::GpuMemoryBufferFromClientBuffer(
169 ClientBuffer buffer) {
170 return GpuMemoryBufferImpl::FromClientBuffer(buffer);
173 void BrowserGpuMemoryBufferManager::SetDestructionSyncPoint(
174 gfx::GpuMemoryBuffer* buffer,
175 uint32 sync_point) {
176 static_cast<GpuMemoryBufferImpl*>(buffer)
177 ->set_destruction_sync_point(sync_point);
180 void BrowserGpuMemoryBufferManager::ChildProcessDeletedGpuMemoryBuffer(
181 gfx::GpuMemoryBufferId id,
182 base::ProcessHandle child_process_handle,
183 int child_client_id,
184 uint32 sync_point) {
185 DCHECK_CURRENTLY_ON(BrowserThread::IO);
186 DCHECK(clients_.find(child_client_id) != clients_.end());
188 BufferMap& buffers = clients_[child_client_id];
190 BufferMap::iterator buffer_it = buffers.find(id);
191 if (buffer_it == buffers.end()) {
192 LOG(ERROR) << "Invalid GpuMemoryBuffer ID for child process.";
193 return;
196 // This can happen if a child process managed to trigger a call to this while
197 // a buffer is in the process of being allocated.
198 if (buffer_it->second == gfx::EMPTY_BUFFER) {
199 LOG(ERROR) << "Invalid GpuMemoryBuffer type.";
200 return;
203 // Buffers allocated using the factory need to be destroyed through the
204 // factory.
205 if (buffer_it->second != gfx::SHARED_MEMORY_BUFFER) {
206 gpu_memory_buffer_factory_host_->DestroyGpuMemoryBuffer(id,
207 child_client_id,
208 sync_point);
211 buffers.erase(buffer_it);
214 void BrowserGpuMemoryBufferManager::ProcessRemoved(
215 base::ProcessHandle process_handle,
216 int client_id) {
217 DCHECK_CURRENTLY_ON(BrowserThread::IO);
219 ClientMap::iterator client_it = clients_.find(client_id);
220 if (client_it == clients_.end())
221 return;
223 for (auto &buffer_it : client_it->second) {
224 // This might happen if buffer is currenlty in the process of being
225 // allocated. The buffer will in that case be cleaned up when allocation
226 // completes.
227 if (buffer_it.second == gfx::EMPTY_BUFFER)
228 continue;
230 // Skip shared memory buffers as they were not allocated using the factory.
231 if (buffer_it.second == gfx::SHARED_MEMORY_BUFFER)
232 continue;
234 gpu_memory_buffer_factory_host_->DestroyGpuMemoryBuffer(buffer_it.first,
235 client_id,
239 clients_.erase(client_it);
242 void BrowserGpuMemoryBufferManager::AllocateGpuMemoryBufferOnIO(
243 AllocateGpuMemoryBufferRequest* request) {
244 // Note: Unretained is safe as this is only used for synchronous allocation
245 // from a non-IO thread.
246 gpu_memory_buffer_factory_host_->CreateGpuMemoryBuffer(
247 g_next_gpu_memory_buffer_id.GetNext(), request->size, request->format,
248 request->usage, request->client_id, request->surface_id,
249 base::Bind(&BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO,
250 base::Unretained(this), base::Unretained(request)));
253 void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedOnIO(
254 AllocateGpuMemoryBufferRequest* request,
255 const gfx::GpuMemoryBufferHandle& handle) {
256 DCHECK_CURRENTLY_ON(BrowserThread::IO);
258 // Early out if factory failed to allocate the buffer.
259 if (handle.is_null()) {
260 request->event.Signal();
261 return;
264 DCHECK_NE(handle.type, gfx::SHARED_MEMORY_BUFFER);
265 request->result = GpuMemoryBufferImpl::CreateFromHandle(
266 handle,
267 request->size,
268 request->format,
269 base::Bind(&BrowserGpuMemoryBufferManager::GpuMemoryBufferDeleted,
270 weak_ptr_factory_.GetWeakPtr(),
271 handle.id,
272 request->client_id));
273 request->event.Signal();
276 void BrowserGpuMemoryBufferManager::GpuMemoryBufferDeleted(
277 gfx::GpuMemoryBufferId id,
278 int client_id,
279 uint32 sync_point) {
280 gpu_memory_buffer_factory_host_->DestroyGpuMemoryBuffer(id,
281 client_id,
282 sync_point);
285 void BrowserGpuMemoryBufferManager::GpuMemoryBufferAllocatedForChildProcess(
286 int child_client_id,
287 const AllocationCallback& callback,
288 const gfx::GpuMemoryBufferHandle& handle) {
289 DCHECK_CURRENTLY_ON(BrowserThread::IO);
291 ClientMap::iterator client_it = clients_.find(child_client_id);
293 // This can happen if the child process is removed while the buffer is being
294 // allocated.
295 if (client_it == clients_.end()) {
296 if (!handle.is_null()) {
297 gpu_memory_buffer_factory_host_->DestroyGpuMemoryBuffer(
298 handle.id, child_client_id, 0);
300 callback.Run(gfx::GpuMemoryBufferHandle());
301 return;
304 BufferMap& buffers = client_it->second;
306 BufferMap::iterator buffer_it = buffers.find(handle.id);
307 DCHECK(buffer_it != buffers.end());
308 DCHECK_EQ(buffer_it->second, gfx::EMPTY_BUFFER);
310 if (handle.is_null()) {
311 buffers.erase(buffer_it);
312 callback.Run(gfx::GpuMemoryBufferHandle());
313 return;
316 // The factory should never return a shared memory backed buffer.
317 DCHECK_NE(handle.type, gfx::SHARED_MEMORY_BUFFER);
319 // Store the type of this buffer so it can be cleaned up if the child
320 // process is removed.
321 buffer_it->second = handle.type;
323 callback.Run(handle);
326 } // namespace content