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

Side by Side Diff: cc/raster/staging_buffer_pool.cc

Issue 1861623003: cc: Refactor OneCopyTileTaskWorkerPool. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@dependency_task
Patch Set: rebase Created 4 years, 8 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
« no previous file with comments | « cc/raster/staging_buffer_pool.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 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.
4
5 #include "cc/raster/staging_buffer_pool.h"
6
7 #include "base/strings/stringprintf.h"
8 #include "base/thread_task_runner_handle.h"
9 #include "base/trace_event/memory_dump_manager.h"
10 #include "cc/base/container_util.h"
11 #include "cc/debug/traced_value.h"
12 #include "cc/resources/scoped_resource.h"
13 #include "gpu/command_buffer/client/gles2_interface.h"
14
15 namespace cc {
16 namespace {
17
18 // Delay between checking for query result to be available.
19 const int kCheckForQueryResultAvailableTickRateMs = 1;
20
21 // Number of attempts to allow before we perform a check that will wait for
22 // query to complete.
23 const int kMaxCheckForQueryResultAvailableAttempts = 256;
24
25 // Delay before a staging buffer might be released.
26 const int kStagingBufferExpirationDelayMs = 1000;
27
28 bool CheckForQueryResult(gpu::gles2::GLES2Interface* gl, unsigned query_id) {
29 unsigned complete = 1;
30 gl->GetQueryObjectuivEXT(query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &complete);
31 return !!complete;
32 }
33
34 void WaitForQueryResult(gpu::gles2::GLES2Interface* gl, unsigned query_id) {
35 TRACE_EVENT0("cc", "WaitForQueryResult");
36
37 int attempts_left = kMaxCheckForQueryResultAvailableAttempts;
38 while (attempts_left--) {
39 if (CheckForQueryResult(gl, query_id))
40 break;
41
42 // We have to flush the context to be guaranteed that a query result will
43 // be available in a finite amount of time.
44 gl->ShallowFlushCHROMIUM();
45
46 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(
47 kCheckForQueryResultAvailableTickRateMs));
48 }
49
50 unsigned result = 0;
51 gl->GetQueryObjectuivEXT(query_id, GL_QUERY_RESULT_EXT, &result);
52 }
53
54 } // namespace
55
56 StagingBuffer::StagingBuffer(const gfx::Size& size, ResourceFormat format)
57 : size(size),
58 format(format),
59 texture_id(0),
60 image_id(0),
61 query_id(0),
62 content_id(0) {}
63
64 StagingBuffer::~StagingBuffer() {
65 DCHECK_EQ(texture_id, 0u);
66 DCHECK_EQ(image_id, 0u);
67 DCHECK_EQ(query_id, 0u);
68 }
69
70 void StagingBuffer::DestroyGLResources(gpu::gles2::GLES2Interface* gl) {
71 if (query_id) {
72 gl->DeleteQueriesEXT(1, &query_id);
73 query_id = 0;
74 }
75 if (image_id) {
76 gl->DestroyImageCHROMIUM(image_id);
77 image_id = 0;
78 }
79 if (texture_id) {
80 gl->DeleteTextures(1, &texture_id);
81 texture_id = 0;
82 }
83 }
84
85 void StagingBuffer::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
86 ResourceFormat format,
87 bool in_free_list) const {
88 if (!gpu_memory_buffer)
89 return;
90
91 gfx::GpuMemoryBufferId buffer_id = gpu_memory_buffer->GetId();
92 std::string buffer_dump_name =
93 base::StringPrintf("cc/one_copy/staging_memory/buffer_%d", buffer_id.id);
94 base::trace_event::MemoryAllocatorDump* buffer_dump =
95 pmd->CreateAllocatorDump(buffer_dump_name);
96
97 uint64_t buffer_size_in_bytes =
98 ResourceUtil::UncheckedSizeInBytes<uint64_t>(size, format);
99 buffer_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
100 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
101 buffer_size_in_bytes);
102 buffer_dump->AddScalar("free_size",
103 base::trace_event::MemoryAllocatorDump::kUnitsBytes,
104 in_free_list ? buffer_size_in_bytes : 0);
105
106 // Emit an ownership edge towards a global allocator dump node.
107 const uint64_t tracing_process_id =
108 base::trace_event::MemoryDumpManager::GetInstance()
109 ->GetTracingProcessId();
110 base::trace_event::MemoryAllocatorDumpGuid shared_buffer_guid =
111 gfx::GetGpuMemoryBufferGUIDForTracing(tracing_process_id, buffer_id);
112 pmd->CreateSharedGlobalAllocatorDump(shared_buffer_guid);
113
114 // By creating an edge with a higher |importance| (w.r.t. browser-side dumps)
115 // the tracing UI will account the effective size of the buffer to the child.
116 const int kImportance = 2;
117 pmd->AddOwnershipEdge(buffer_dump->guid(), shared_buffer_guid, kImportance);
118 }
119
120 // static
121 scoped_ptr<StagingBufferPool> StagingBufferPool::Create(
122 base::SequencedTaskRunner* task_runner,
123 ResourceProvider* resource_provider,
124 bool use_partial_raster,
125 int max_staging_buffer_usage_in_bytes) {
126 return make_scoped_ptr<StagingBufferPool>(
127 new StagingBufferPool(task_runner, resource_provider, use_partial_raster,
128 max_staging_buffer_usage_in_bytes));
129 }
130
131 StagingBufferPool::StagingBufferPool(base::SequencedTaskRunner* task_runner,
132 ResourceProvider* resource_provider,
133 bool use_partial_raster,
134 int max_staging_buffer_usage_in_bytes)
135 : task_runner_(task_runner),
136 resource_provider_(resource_provider),
137 use_partial_raster_(use_partial_raster),
138 max_staging_buffer_usage_in_bytes_(max_staging_buffer_usage_in_bytes),
139 staging_buffer_usage_in_bytes_(0),
140 free_staging_buffer_usage_in_bytes_(0),
141 staging_buffer_expiration_delay_(
142 base::TimeDelta::FromMilliseconds(kStagingBufferExpirationDelayMs)),
143 reduce_memory_usage_pending_(false),
144 weak_ptr_factory_(this) {
145 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
146 this, "cc::StagingBufferPool", base::ThreadTaskRunnerHandle::Get());
147 reduce_memory_usage_callback_ = base::Bind(
148 &StagingBufferPool::ReduceMemoryUsage, weak_ptr_factory_.GetWeakPtr());
149 }
150
151 StagingBufferPool::~StagingBufferPool() {
152 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
153 this);
154 }
155
156 void StagingBufferPool::Shutdown() {
157 base::AutoLock lock(lock_);
158 if (buffers_.empty())
159 return;
160
161 ReleaseBuffersNotUsedSince(base::TimeTicks() + base::TimeDelta::Max());
162 DCHECK_EQ(staging_buffer_usage_in_bytes_, 0);
163 DCHECK_EQ(free_staging_buffer_usage_in_bytes_, 0);
164 }
165
166 void StagingBufferPool::ReleaseStagingBuffer(
167 scoped_ptr<StagingBuffer> staging_buffer) {
168 base::AutoLock lock(lock_);
169
170 staging_buffer->last_usage = base::TimeTicks::Now();
171 busy_buffers_.push_back(std::move(staging_buffer));
172
173 ScheduleReduceMemoryUsage();
174 }
175
176 bool StagingBufferPool::OnMemoryDump(
177 const base::trace_event::MemoryDumpArgs& args,
178 base::trace_event::ProcessMemoryDump* pmd) {
179 base::AutoLock lock(lock_);
180
181 for (const auto* buffer : buffers_) {
182 auto in_free_buffers =
183 std::find_if(free_buffers_.begin(), free_buffers_.end(),
184 [buffer](const scoped_ptr<StagingBuffer>& b) {
185 return b.get() == buffer;
186 });
187 buffer->OnMemoryDump(pmd, buffer->format,
188 in_free_buffers != free_buffers_.end());
189 }
190
191 return true;
192 }
193
194 void StagingBufferPool::AddStagingBuffer(const StagingBuffer* staging_buffer,
195 ResourceFormat format) {
196 lock_.AssertAcquired();
197
198 DCHECK(buffers_.find(staging_buffer) == buffers_.end());
199 buffers_.insert(staging_buffer);
200 int buffer_usage_in_bytes =
201 ResourceUtil::UncheckedSizeInBytes<int>(staging_buffer->size, format);
202 staging_buffer_usage_in_bytes_ += buffer_usage_in_bytes;
203 }
204
205 void StagingBufferPool::RemoveStagingBuffer(
206 const StagingBuffer* staging_buffer) {
207 lock_.AssertAcquired();
208
209 DCHECK(buffers_.find(staging_buffer) != buffers_.end());
210 buffers_.erase(staging_buffer);
211 int buffer_usage_in_bytes = ResourceUtil::UncheckedSizeInBytes<int>(
212 staging_buffer->size, staging_buffer->format);
213 DCHECK_GE(staging_buffer_usage_in_bytes_, buffer_usage_in_bytes);
214 staging_buffer_usage_in_bytes_ -= buffer_usage_in_bytes;
215 }
216
217 void StagingBufferPool::MarkStagingBufferAsFree(
218 const StagingBuffer* staging_buffer) {
219 lock_.AssertAcquired();
220
221 int buffer_usage_in_bytes = ResourceUtil::UncheckedSizeInBytes<int>(
222 staging_buffer->size, staging_buffer->format);
223 free_staging_buffer_usage_in_bytes_ += buffer_usage_in_bytes;
224 }
225
226 void StagingBufferPool::MarkStagingBufferAsBusy(
227 const StagingBuffer* staging_buffer) {
228 lock_.AssertAcquired();
229
230 int buffer_usage_in_bytes = ResourceUtil::UncheckedSizeInBytes<int>(
231 staging_buffer->size, staging_buffer->format);
232 DCHECK_GE(free_staging_buffer_usage_in_bytes_, buffer_usage_in_bytes);
233 free_staging_buffer_usage_in_bytes_ -= buffer_usage_in_bytes;
234 }
235
236 scoped_ptr<StagingBuffer> StagingBufferPool::AcquireStagingBuffer(
237 const Resource* resource,
238 uint64_t previous_content_id) {
239 base::AutoLock lock(lock_);
240
241 scoped_ptr<StagingBuffer> staging_buffer;
242
243 ContextProvider* context_provider =
244 resource_provider_->output_surface()->worker_context_provider();
245 DCHECK(context_provider);
246
247 ContextProvider::ScopedContextLock scoped_context(context_provider);
248
249 gpu::gles2::GLES2Interface* gl = scoped_context.ContextGL();
250 DCHECK(gl);
251
252 // Check if any busy buffers have become available.
253 if (resource_provider_->use_sync_query()) {
254 while (!busy_buffers_.empty()) {
255 if (!CheckForQueryResult(gl, busy_buffers_.front()->query_id))
256 break;
257
258 MarkStagingBufferAsFree(busy_buffers_.front().get());
259 free_buffers_.push_back(PopFront(&busy_buffers_));
260 }
261 }
262
263 // Wait for memory usage of non-free buffers to become less than the limit.
264 while (
265 (staging_buffer_usage_in_bytes_ - free_staging_buffer_usage_in_bytes_) >=
266 max_staging_buffer_usage_in_bytes_) {
267 // Stop when there are no more busy buffers to wait for.
268 if (busy_buffers_.empty())
269 break;
270
271 if (resource_provider_->use_sync_query()) {
272 WaitForQueryResult(gl, busy_buffers_.front()->query_id);
273 MarkStagingBufferAsFree(busy_buffers_.front().get());
274 free_buffers_.push_back(PopFront(&busy_buffers_));
275 } else {
276 // Fall-back to glFinish if CHROMIUM_sync_query is not available.
277 gl->Finish();
278 while (!busy_buffers_.empty()) {
279 MarkStagingBufferAsFree(busy_buffers_.front().get());
280 free_buffers_.push_back(PopFront(&busy_buffers_));
281 }
282 }
283 }
284
285 // Find a staging buffer that allows us to perform partial raster when
286 // using persistent GpuMemoryBuffers.
287 if (use_partial_raster_ && previous_content_id) {
288 StagingBufferDeque::iterator it = std::find_if(
289 free_buffers_.begin(), free_buffers_.end(),
290 [previous_content_id](const scoped_ptr<StagingBuffer>& buffer) {
291 return buffer->content_id == previous_content_id;
292 });
293 if (it != free_buffers_.end()) {
294 staging_buffer = std::move(*it);
295 free_buffers_.erase(it);
296 MarkStagingBufferAsBusy(staging_buffer.get());
297 }
298 }
299
300 // Find staging buffer of correct size and format.
301 if (!staging_buffer) {
302 StagingBufferDeque::iterator it =
303 std::find_if(free_buffers_.begin(), free_buffers_.end(),
304 [resource](const scoped_ptr<StagingBuffer>& buffer) {
305 return buffer->size == resource->size() &&
306 buffer->format == resource->format();
307 });
308 if (it != free_buffers_.end()) {
309 staging_buffer = std::move(*it);
310 free_buffers_.erase(it);
311 MarkStagingBufferAsBusy(staging_buffer.get());
312 }
313 }
314
315 // Create new staging buffer if necessary.
316 if (!staging_buffer) {
317 staging_buffer = make_scoped_ptr(
318 new StagingBuffer(resource->size(), resource->format()));
319 AddStagingBuffer(staging_buffer.get(), resource->format());
320 }
321
322 // Release enough free buffers to stay within the limit.
323 while (staging_buffer_usage_in_bytes_ > max_staging_buffer_usage_in_bytes_) {
324 if (free_buffers_.empty())
325 break;
326
327 free_buffers_.front()->DestroyGLResources(gl);
328 MarkStagingBufferAsBusy(free_buffers_.front().get());
329 RemoveStagingBuffer(free_buffers_.front().get());
330 free_buffers_.pop_front();
331 }
332
333 return staging_buffer;
334 }
335
336 base::TimeTicks StagingBufferPool::GetUsageTimeForLRUBuffer() {
337 lock_.AssertAcquired();
338
339 if (!free_buffers_.empty())
340 return free_buffers_.front()->last_usage;
341
342 if (!busy_buffers_.empty())
343 return busy_buffers_.front()->last_usage;
344
345 return base::TimeTicks();
346 }
347
348 void StagingBufferPool::ScheduleReduceMemoryUsage() {
349 lock_.AssertAcquired();
350
351 if (reduce_memory_usage_pending_)
352 return;
353
354 reduce_memory_usage_pending_ = true;
355
356 // Schedule a call to ReduceMemoryUsage at the time when the LRU buffer
357 // should be released.
358 base::TimeTicks reduce_memory_usage_time =
359 GetUsageTimeForLRUBuffer() + staging_buffer_expiration_delay_;
360 task_runner_->PostDelayedTask(
361 FROM_HERE, reduce_memory_usage_callback_,
362 reduce_memory_usage_time - base::TimeTicks::Now());
363 }
364
365 void StagingBufferPool::ReduceMemoryUsage() {
366 base::AutoLock lock(lock_);
367
368 reduce_memory_usage_pending_ = false;
369
370 if (free_buffers_.empty() && busy_buffers_.empty())
371 return;
372
373 base::TimeTicks current_time = base::TimeTicks::Now();
374 ReleaseBuffersNotUsedSince(current_time - staging_buffer_expiration_delay_);
375
376 if (free_buffers_.empty() && busy_buffers_.empty())
377 return;
378
379 reduce_memory_usage_pending_ = true;
380
381 // Schedule another call to ReduceMemoryUsage at the time when the next
382 // buffer should be released.
383 base::TimeTicks reduce_memory_usage_time =
384 GetUsageTimeForLRUBuffer() + staging_buffer_expiration_delay_;
385 task_runner_->PostDelayedTask(FROM_HERE, reduce_memory_usage_callback_,
386 reduce_memory_usage_time - current_time);
387 }
388
389 void StagingBufferPool::ReleaseBuffersNotUsedSince(base::TimeTicks time) {
390 lock_.AssertAcquired();
391
392 ContextProvider* context_provider =
393 resource_provider_->output_surface()->worker_context_provider();
394 DCHECK(context_provider);
395
396 {
397 ContextProvider::ScopedContextLock scoped_context(context_provider);
398
399 gpu::gles2::GLES2Interface* gl = scoped_context.ContextGL();
400 DCHECK(gl);
401
402 // Note: Front buffer is guaranteed to be LRU so we can stop releasing
403 // buffers as soon as we find a buffer that has been used since |time|.
404 while (!free_buffers_.empty()) {
405 if (free_buffers_.front()->last_usage > time)
406 return;
407
408 free_buffers_.front()->DestroyGLResources(gl);
409 MarkStagingBufferAsBusy(free_buffers_.front().get());
410 RemoveStagingBuffer(free_buffers_.front().get());
411 free_buffers_.pop_front();
412 }
413
414 while (!busy_buffers_.empty()) {
415 if (busy_buffers_.front()->last_usage > time)
416 return;
417
418 busy_buffers_.front()->DestroyGLResources(gl);
419 RemoveStagingBuffer(busy_buffers_.front().get());
420 busy_buffers_.pop_front();
421 }
422 }
423 }
424
425 } // namespace cc
OLDNEW
« no previous file with comments | « cc/raster/staging_buffer_pool.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698