| 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 "cc/raster/one_copy_tile_task_worker_pool.h" | 5 #include "cc/raster/one_copy_tile_task_worker_pool.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <limits> | 10 #include <limits> |
| 11 #include <utility> | 11 #include <utility> |
| 12 | 12 |
| 13 #include "base/macros.h" | 13 #include "base/macros.h" |
| 14 #include "base/strings/stringprintf.h" | |
| 15 #include "base/thread_task_runner_handle.h" | |
| 16 #include "base/trace_event/memory_dump_manager.h" | |
| 17 #include "base/trace_event/trace_event.h" | |
| 18 #include "base/trace_event/trace_event_argument.h" | |
| 19 #include "cc/base/container_util.h" | |
| 20 #include "cc/base/math_util.h" | 14 #include "cc/base/math_util.h" |
| 21 #include "cc/debug/traced_value.h" | |
| 22 #include "cc/raster/raster_buffer.h" | 15 #include "cc/raster/raster_buffer.h" |
| 16 #include "cc/raster/staging_buffer_pool.h" |
| 23 #include "cc/resources/platform_color.h" | 17 #include "cc/resources/platform_color.h" |
| 24 #include "cc/resources/resource_format.h" | 18 #include "cc/resources/resource_format.h" |
| 25 #include "cc/resources/resource_util.h" | 19 #include "cc/resources/resource_util.h" |
| 26 #include "cc/resources/scoped_resource.h" | 20 #include "cc/resources/scoped_resource.h" |
| 27 #include "gpu/GLES2/gl2extchromium.h" | 21 #include "gpu/GLES2/gl2extchromium.h" |
| 28 #include "gpu/command_buffer/client/gles2_interface.h" | 22 #include "gpu/command_buffer/client/gles2_interface.h" |
| 29 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h" | 23 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h" |
| 30 #include "ui/gfx/buffer_format_util.h" | 24 #include "ui/gfx/buffer_format_util.h" |
| 31 | 25 |
| 32 namespace cc { | 26 namespace cc { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 61 | 55 |
| 62 private: | 56 private: |
| 63 OneCopyTileTaskWorkerPool* worker_pool_; | 57 OneCopyTileTaskWorkerPool* worker_pool_; |
| 64 const Resource* resource_; | 58 const Resource* resource_; |
| 65 ResourceProvider::ScopedWriteLockGL lock_; | 59 ResourceProvider::ScopedWriteLockGL lock_; |
| 66 uint64_t previous_content_id_; | 60 uint64_t previous_content_id_; |
| 67 | 61 |
| 68 DISALLOW_COPY_AND_ASSIGN(RasterBufferImpl); | 62 DISALLOW_COPY_AND_ASSIGN(RasterBufferImpl); |
| 69 }; | 63 }; |
| 70 | 64 |
| 71 // Delay between checking for query result to be available. | |
| 72 const int kCheckForQueryResultAvailableTickRateMs = 1; | |
| 73 | |
| 74 // Number of attempts to allow before we perform a check that will wait for | |
| 75 // query to complete. | |
| 76 const int kMaxCheckForQueryResultAvailableAttempts = 256; | |
| 77 | |
| 78 // 4MiB is the size of 4 512x512 tiles, which has proven to be a good | 65 // 4MiB is the size of 4 512x512 tiles, which has proven to be a good |
| 79 // default batch size for copy operations. | 66 // default batch size for copy operations. |
| 80 const int kMaxBytesPerCopyOperation = 1024 * 1024 * 4; | 67 const int kMaxBytesPerCopyOperation = 1024 * 1024 * 4; |
| 81 | 68 |
| 82 // Delay before a staging buffer might be released. | |
| 83 const int kStagingBufferExpirationDelayMs = 1000; | |
| 84 | |
| 85 bool CheckForQueryResult(gpu::gles2::GLES2Interface* gl, unsigned query_id) { | |
| 86 unsigned complete = 1; | |
| 87 gl->GetQueryObjectuivEXT(query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &complete); | |
| 88 return !!complete; | |
| 89 } | |
| 90 | |
| 91 void WaitForQueryResult(gpu::gles2::GLES2Interface* gl, unsigned query_id) { | |
| 92 TRACE_EVENT0("cc", "WaitForQueryResult"); | |
| 93 | |
| 94 int attempts_left = kMaxCheckForQueryResultAvailableAttempts; | |
| 95 while (attempts_left--) { | |
| 96 if (CheckForQueryResult(gl, query_id)) | |
| 97 break; | |
| 98 | |
| 99 // We have to flush the context to be guaranteed that a query result will | |
| 100 // be available in a finite amount of time. | |
| 101 gl->ShallowFlushCHROMIUM(); | |
| 102 | |
| 103 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds( | |
| 104 kCheckForQueryResultAvailableTickRateMs)); | |
| 105 } | |
| 106 | |
| 107 unsigned result = 0; | |
| 108 gl->GetQueryObjectuivEXT(query_id, GL_QUERY_RESULT_EXT, &result); | |
| 109 } | |
| 110 | |
| 111 } // namespace | 69 } // namespace |
| 112 | 70 |
| 113 OneCopyTileTaskWorkerPool::StagingBuffer::StagingBuffer(const gfx::Size& size, | |
| 114 ResourceFormat format) | |
| 115 : size(size), | |
| 116 format(format), | |
| 117 texture_id(0), | |
| 118 image_id(0), | |
| 119 query_id(0), | |
| 120 content_id(0) {} | |
| 121 | |
| 122 OneCopyTileTaskWorkerPool::StagingBuffer::~StagingBuffer() { | |
| 123 DCHECK_EQ(texture_id, 0u); | |
| 124 DCHECK_EQ(image_id, 0u); | |
| 125 DCHECK_EQ(query_id, 0u); | |
| 126 } | |
| 127 | |
| 128 void OneCopyTileTaskWorkerPool::StagingBuffer::DestroyGLResources( | |
| 129 gpu::gles2::GLES2Interface* gl) { | |
| 130 if (query_id) { | |
| 131 gl->DeleteQueriesEXT(1, &query_id); | |
| 132 query_id = 0; | |
| 133 } | |
| 134 if (image_id) { | |
| 135 gl->DestroyImageCHROMIUM(image_id); | |
| 136 image_id = 0; | |
| 137 } | |
| 138 if (texture_id) { | |
| 139 gl->DeleteTextures(1, &texture_id); | |
| 140 texture_id = 0; | |
| 141 } | |
| 142 } | |
| 143 | |
| 144 void OneCopyTileTaskWorkerPool::StagingBuffer::OnMemoryDump( | |
| 145 base::trace_event::ProcessMemoryDump* pmd, | |
| 146 ResourceFormat format, | |
| 147 bool in_free_list) const { | |
| 148 if (!gpu_memory_buffer) | |
| 149 return; | |
| 150 | |
| 151 gfx::GpuMemoryBufferId buffer_id = gpu_memory_buffer->GetId(); | |
| 152 std::string buffer_dump_name = | |
| 153 base::StringPrintf("cc/one_copy/staging_memory/buffer_%d", buffer_id.id); | |
| 154 base::trace_event::MemoryAllocatorDump* buffer_dump = | |
| 155 pmd->CreateAllocatorDump(buffer_dump_name); | |
| 156 | |
| 157 uint64_t buffer_size_in_bytes = | |
| 158 ResourceUtil::UncheckedSizeInBytes<uint64_t>(size, format); | |
| 159 buffer_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, | |
| 160 base::trace_event::MemoryAllocatorDump::kUnitsBytes, | |
| 161 buffer_size_in_bytes); | |
| 162 buffer_dump->AddScalar("free_size", | |
| 163 base::trace_event::MemoryAllocatorDump::kUnitsBytes, | |
| 164 in_free_list ? buffer_size_in_bytes : 0); | |
| 165 | |
| 166 // Emit an ownership edge towards a global allocator dump node. | |
| 167 const uint64_t tracing_process_id = | |
| 168 base::trace_event::MemoryDumpManager::GetInstance() | |
| 169 ->GetTracingProcessId(); | |
| 170 base::trace_event::MemoryAllocatorDumpGuid shared_buffer_guid = | |
| 171 gfx::GetGpuMemoryBufferGUIDForTracing(tracing_process_id, buffer_id); | |
| 172 pmd->CreateSharedGlobalAllocatorDump(shared_buffer_guid); | |
| 173 | |
| 174 // By creating an edge with a higher |importance| (w.r.t. browser-side dumps) | |
| 175 // the tracing UI will account the effective size of the buffer to the child. | |
| 176 const int kImportance = 2; | |
| 177 pmd->AddOwnershipEdge(buffer_dump->guid(), shared_buffer_guid, kImportance); | |
| 178 } | |
| 179 | |
| 180 // static | 71 // static |
| 181 scoped_ptr<TileTaskWorkerPool> OneCopyTileTaskWorkerPool::Create( | 72 scoped_ptr<TileTaskWorkerPool> OneCopyTileTaskWorkerPool::Create( |
| 182 base::SequencedTaskRunner* task_runner, | 73 base::SequencedTaskRunner* task_runner, |
| 183 TaskGraphRunner* task_graph_runner, | 74 TaskGraphRunner* task_graph_runner, |
| 184 ContextProvider* context_provider, | 75 ContextProvider* context_provider, |
| 185 ResourceProvider* resource_provider, | 76 ResourceProvider* resource_provider, |
| 186 int max_copy_texture_chromium_size, | 77 int max_copy_texture_chromium_size, |
| 187 bool use_partial_raster, | 78 bool use_partial_raster, |
| 188 int max_staging_buffer_usage_in_bytes, | 79 int max_staging_buffer_usage_in_bytes, |
| 189 ResourceFormat preferred_tile_format) { | 80 ResourceFormat preferred_tile_format) { |
| 190 return make_scoped_ptr<TileTaskWorkerPool>(new OneCopyTileTaskWorkerPool( | 81 return make_scoped_ptr<TileTaskWorkerPool>(new OneCopyTileTaskWorkerPool( |
| 191 task_runner, task_graph_runner, resource_provider, | 82 task_runner, task_graph_runner, resource_provider, |
| 192 max_copy_texture_chromium_size, use_partial_raster, | 83 max_copy_texture_chromium_size, use_partial_raster, |
| 193 max_staging_buffer_usage_in_bytes, preferred_tile_format)); | 84 max_staging_buffer_usage_in_bytes, preferred_tile_format)); |
| 194 } | 85 } |
| 195 | 86 |
| 196 OneCopyTileTaskWorkerPool::OneCopyTileTaskWorkerPool( | 87 OneCopyTileTaskWorkerPool::OneCopyTileTaskWorkerPool( |
| 197 base::SequencedTaskRunner* task_runner, | 88 base::SequencedTaskRunner* task_runner, |
| 198 TaskGraphRunner* task_graph_runner, | 89 TaskGraphRunner* task_graph_runner, |
| 199 ResourceProvider* resource_provider, | 90 ResourceProvider* resource_provider, |
| 200 int max_copy_texture_chromium_size, | 91 int max_copy_texture_chromium_size, |
| 201 bool use_partial_raster, | 92 bool use_partial_raster, |
| 202 int max_staging_buffer_usage_in_bytes, | 93 int max_staging_buffer_usage_in_bytes, |
| 203 ResourceFormat preferred_tile_format) | 94 ResourceFormat preferred_tile_format) |
| 204 : task_runner_(task_runner), | 95 : task_graph_runner_(task_graph_runner), |
| 205 task_graph_runner_(task_graph_runner), | |
| 206 namespace_token_(task_graph_runner->GetNamespaceToken()), | 96 namespace_token_(task_graph_runner->GetNamespaceToken()), |
| 207 resource_provider_(resource_provider), | 97 resource_provider_(resource_provider), |
| 208 max_bytes_per_copy_operation_( | 98 max_bytes_per_copy_operation_( |
| 209 max_copy_texture_chromium_size | 99 max_copy_texture_chromium_size |
| 210 ? std::min(kMaxBytesPerCopyOperation, | 100 ? std::min(kMaxBytesPerCopyOperation, |
| 211 max_copy_texture_chromium_size) | 101 max_copy_texture_chromium_size) |
| 212 : kMaxBytesPerCopyOperation), | 102 : kMaxBytesPerCopyOperation), |
| 213 use_partial_raster_(use_partial_raster), | 103 use_partial_raster_(use_partial_raster), |
| 214 bytes_scheduled_since_last_flush_(0), | 104 bytes_scheduled_since_last_flush_(0), |
| 215 max_staging_buffer_usage_in_bytes_(max_staging_buffer_usage_in_bytes), | 105 preferred_tile_format_(preferred_tile_format) { |
| 216 preferred_tile_format_(preferred_tile_format), | 106 staging_pool_ = StagingBufferPool::Create(task_runner, resource_provider, |
| 217 staging_buffer_usage_in_bytes_(0), | 107 use_partial_raster, |
| 218 free_staging_buffer_usage_in_bytes_(0), | 108 max_staging_buffer_usage_in_bytes); |
| 219 staging_buffer_expiration_delay_( | |
| 220 base::TimeDelta::FromMilliseconds(kStagingBufferExpirationDelayMs)), | |
| 221 reduce_memory_usage_pending_(false), | |
| 222 weak_ptr_factory_(this) { | |
| 223 base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( | |
| 224 this, "OneCopyTileTaskWorkerPool", base::ThreadTaskRunnerHandle::Get()); | |
| 225 reduce_memory_usage_callback_ = | |
| 226 base::Bind(&OneCopyTileTaskWorkerPool::ReduceMemoryUsage, | |
| 227 weak_ptr_factory_.GetWeakPtr()); | |
| 228 } | 109 } |
| 229 | 110 |
| 230 OneCopyTileTaskWorkerPool::~OneCopyTileTaskWorkerPool() { | 111 OneCopyTileTaskWorkerPool::~OneCopyTileTaskWorkerPool() { |
| 231 base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( | |
| 232 this); | |
| 233 } | 112 } |
| 234 | 113 |
| 235 TileTaskRunner* OneCopyTileTaskWorkerPool::AsTileTaskRunner() { | 114 TileTaskRunner* OneCopyTileTaskWorkerPool::AsTileTaskRunner() { |
| 236 return this; | 115 return this; |
| 237 } | 116 } |
| 238 | 117 |
| 239 void OneCopyTileTaskWorkerPool::Shutdown() { | 118 void OneCopyTileTaskWorkerPool::Shutdown() { |
| 240 TRACE_EVENT0("cc", "OneCopyTileTaskWorkerPool::Shutdown"); | 119 TRACE_EVENT0("cc", "OneCopyTileTaskWorkerPool::Shutdown"); |
| 241 | 120 |
| 242 TaskGraph empty; | 121 TaskGraph empty; |
| 243 task_graph_runner_->ScheduleTasks(namespace_token_, &empty); | 122 task_graph_runner_->ScheduleTasks(namespace_token_, &empty); |
| 244 task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_); | 123 task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_); |
| 245 | 124 |
| 246 base::AutoLock lock(lock_); | 125 staging_pool_->Shutdown(); |
| 247 | |
| 248 if (buffers_.empty()) | |
| 249 return; | |
| 250 | |
| 251 ReleaseBuffersNotUsedSince(base::TimeTicks() + base::TimeDelta::Max()); | |
| 252 DCHECK_EQ(staging_buffer_usage_in_bytes_, 0); | |
| 253 DCHECK_EQ(free_staging_buffer_usage_in_bytes_, 0); | |
| 254 } | 126 } |
| 255 | 127 |
| 256 void OneCopyTileTaskWorkerPool::ScheduleTasks(TaskGraph* graph) { | 128 void OneCopyTileTaskWorkerPool::ScheduleTasks(TaskGraph* graph) { |
| 257 TRACE_EVENT0("cc", "OneCopyTileTaskWorkerPool::ScheduleTasks"); | 129 TRACE_EVENT0("cc", "OneCopyTileTaskWorkerPool::ScheduleTasks"); |
| 258 | 130 |
| 259 ScheduleTasksOnOriginThread(this, graph); | 131 ScheduleTasksOnOriginThread(this, graph); |
| 260 | 132 |
| 261 // Barrier to sync any new resources to the worker context. | 133 // Barrier to sync any new resources to the worker context. |
| 262 resource_provider_->output_surface() | 134 resource_provider_->output_surface() |
| 263 ->context_provider() | 135 ->context_provider() |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 319 void OneCopyTileTaskWorkerPool::PlaybackAndCopyOnWorkerThread( | 191 void OneCopyTileTaskWorkerPool::PlaybackAndCopyOnWorkerThread( |
| 320 const Resource* resource, | 192 const Resource* resource, |
| 321 ResourceProvider::ScopedWriteLockGL* resource_lock, | 193 ResourceProvider::ScopedWriteLockGL* resource_lock, |
| 322 const RasterSource* raster_source, | 194 const RasterSource* raster_source, |
| 323 const gfx::Rect& raster_full_rect, | 195 const gfx::Rect& raster_full_rect, |
| 324 const gfx::Rect& raster_dirty_rect, | 196 const gfx::Rect& raster_dirty_rect, |
| 325 float scale, | 197 float scale, |
| 326 const RasterSource::PlaybackSettings& playback_settings, | 198 const RasterSource::PlaybackSettings& playback_settings, |
| 327 uint64_t previous_content_id, | 199 uint64_t previous_content_id, |
| 328 uint64_t new_content_id) { | 200 uint64_t new_content_id) { |
| 329 base::AutoLock lock(lock_); | 201 scoped_ptr<StagingBuffer> staging_buffer = |
| 202 staging_pool_->AcquireStagingBuffer(resource, previous_content_id); |
| 330 | 203 |
| 331 scoped_ptr<StagingBuffer> staging_buffer = | 204 PlaybackToStagingBuffer(staging_buffer.get(), resource, raster_source, |
| 332 AcquireStagingBuffer(resource, previous_content_id); | 205 raster_full_rect, raster_dirty_rect, scale, |
| 333 DCHECK(staging_buffer); | 206 playback_settings, previous_content_id, |
| 207 new_content_id); |
| 334 | 208 |
| 335 { | 209 CopyOnWorkerThread(staging_buffer.get(), resource, resource_lock, |
| 336 base::AutoUnlock unlock(lock_); | 210 raster_source, previous_content_id, new_content_id); |
| 337 | 211 |
| 338 // Allocate GpuMemoryBuffer if necessary. If using partial raster, we | 212 staging_pool_->ReleaseStagingBuffer(std::move(staging_buffer)); |
| 339 // must allocate a buffer with BufferUsage CPU_READ_WRITE_PERSISTENT. | 213 } |
| 340 if (!staging_buffer->gpu_memory_buffer) { | |
| 341 staging_buffer->gpu_memory_buffer = | |
| 342 resource_provider_->gpu_memory_buffer_manager() | |
| 343 ->AllocateGpuMemoryBuffer( | |
| 344 staging_buffer->size, BufferFormat(resource->format()), | |
| 345 use_partial_raster_ | |
| 346 ? gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT | |
| 347 : gfx::BufferUsage::GPU_READ_CPU_READ_WRITE, | |
| 348 0 /* surface_id */); | |
| 349 } | |
| 350 | 214 |
| 351 gfx::Rect playback_rect = raster_full_rect; | 215 void OneCopyTileTaskWorkerPool::PlaybackToStagingBuffer( |
| 352 if (use_partial_raster_ && previous_content_id) { | 216 StagingBuffer* staging_buffer, |
| 353 // Reduce playback rect to dirty region if the content id of the staging | 217 const Resource* resource, |
| 354 // buffer matches the prevous content id. | 218 const RasterSource* raster_source, |
| 355 if (previous_content_id == staging_buffer->content_id) | 219 const gfx::Rect& raster_full_rect, |
| 356 playback_rect.Intersect(raster_dirty_rect); | 220 const gfx::Rect& raster_dirty_rect, |
| 357 } | 221 float scale, |
| 358 | 222 const RasterSource::PlaybackSettings& playback_settings, |
| 359 if (staging_buffer->gpu_memory_buffer) { | 223 uint64_t previous_content_id, |
| 360 gfx::GpuMemoryBuffer* buffer = staging_buffer->gpu_memory_buffer.get(); | 224 uint64_t new_content_id) { |
| 361 DCHECK_EQ(1u, gfx::NumberOfPlanesForBufferFormat(buffer->GetFormat())); | 225 // Allocate GpuMemoryBuffer if necessary. If using partial raster, we |
| 362 bool rv = buffer->Map(); | 226 // must allocate a buffer with BufferUsage CPU_READ_WRITE_PERSISTENT. |
| 363 DCHECK(rv); | 227 if (!staging_buffer->gpu_memory_buffer) { |
| 364 DCHECK(buffer->memory(0)); | 228 staging_buffer->gpu_memory_buffer = |
| 365 // TileTaskWorkerPool::PlaybackToMemory only supports unsigned strides. | 229 resource_provider_->gpu_memory_buffer_manager() |
| 366 DCHECK_GE(buffer->stride(0), 0); | 230 ->AllocateGpuMemoryBuffer( |
| 367 | 231 staging_buffer->size, BufferFormat(resource->format()), |
| 368 DCHECK(!playback_rect.IsEmpty()) | 232 use_partial_raster_ |
| 369 << "Why are we rastering a tile that's not dirty?"; | 233 ? gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT |
| 370 TileTaskWorkerPool::PlaybackToMemory( | 234 : gfx::BufferUsage::GPU_READ_CPU_READ_WRITE, |
| 371 buffer->memory(0), resource->format(), staging_buffer->size, | 235 0 /* surface_id */); |
| 372 buffer->stride(0), raster_source, raster_full_rect, playback_rect, | |
| 373 scale, playback_settings); | |
| 374 buffer->Unmap(); | |
| 375 staging_buffer->content_id = new_content_id; | |
| 376 } | |
| 377 } | 236 } |
| 378 | 237 |
| 238 gfx::Rect playback_rect = raster_full_rect; |
| 239 if (use_partial_raster_ && previous_content_id) { |
| 240 // Reduce playback rect to dirty region if the content id of the staging |
| 241 // buffer matches the prevous content id. |
| 242 if (previous_content_id == staging_buffer->content_id) |
| 243 playback_rect.Intersect(raster_dirty_rect); |
| 244 } |
| 245 |
| 246 if (staging_buffer->gpu_memory_buffer) { |
| 247 gfx::GpuMemoryBuffer* buffer = staging_buffer->gpu_memory_buffer.get(); |
| 248 DCHECK_EQ(1u, gfx::NumberOfPlanesForBufferFormat(buffer->GetFormat())); |
| 249 bool rv = buffer->Map(); |
| 250 DCHECK(rv); |
| 251 DCHECK(buffer->memory(0)); |
| 252 // TileTaskWorkerPool::PlaybackToMemory only supports unsigned strides. |
| 253 DCHECK_GE(buffer->stride(0), 0); |
| 254 |
| 255 DCHECK(!playback_rect.IsEmpty()) |
| 256 << "Why are we rastering a tile that's not dirty?"; |
| 257 TileTaskWorkerPool::PlaybackToMemory( |
| 258 buffer->memory(0), resource->format(), staging_buffer->size, |
| 259 buffer->stride(0), raster_source, raster_full_rect, playback_rect, |
| 260 scale, playback_settings); |
| 261 buffer->Unmap(); |
| 262 staging_buffer->content_id = new_content_id; |
| 263 } |
| 264 } |
| 265 |
| 266 void OneCopyTileTaskWorkerPool::CopyOnWorkerThread( |
| 267 StagingBuffer* staging_buffer, |
| 268 const Resource* resource, |
| 269 ResourceProvider::ScopedWriteLockGL* resource_lock, |
| 270 const RasterSource* raster_source, |
| 271 uint64_t previous_content_id, |
| 272 uint64_t new_content_id) { |
| 379 ContextProvider* context_provider = | 273 ContextProvider* context_provider = |
| 380 resource_provider_->output_surface()->worker_context_provider(); | 274 resource_provider_->output_surface()->worker_context_provider(); |
| 381 DCHECK(context_provider); | 275 DCHECK(context_provider); |
| 382 | 276 |
| 383 { | 277 { |
| 384 ContextProvider::ScopedContextLock scoped_context(context_provider); | 278 ContextProvider::ScopedContextLock scoped_context(context_provider); |
| 385 | 279 |
| 386 gpu::gles2::GLES2Interface* gl = scoped_context.ContextGL(); | 280 gpu::gles2::GLES2Interface* gl = scoped_context.ContextGL(); |
| 387 DCHECK(gl); | 281 DCHECK(gl); |
| 388 | 282 |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 479 const uint64_t fence_sync = gl->InsertFenceSyncCHROMIUM(); | 373 const uint64_t fence_sync = gl->InsertFenceSyncCHROMIUM(); |
| 480 | 374 |
| 481 // Barrier to sync worker context output to cc context. | 375 // Barrier to sync worker context output to cc context. |
| 482 gl->OrderingBarrierCHROMIUM(); | 376 gl->OrderingBarrierCHROMIUM(); |
| 483 | 377 |
| 484 // Generate sync token after the barrier for cross context synchronization. | 378 // Generate sync token after the barrier for cross context synchronization. |
| 485 gpu::SyncToken sync_token; | 379 gpu::SyncToken sync_token; |
| 486 gl->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData()); | 380 gl->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData()); |
| 487 resource_lock->UpdateResourceSyncToken(sync_token); | 381 resource_lock->UpdateResourceSyncToken(sync_token); |
| 488 } | 382 } |
| 489 | |
| 490 staging_buffer->last_usage = base::TimeTicks::Now(); | |
| 491 busy_buffers_.push_back(std::move(staging_buffer)); | |
| 492 | |
| 493 ScheduleReduceMemoryUsage(); | |
| 494 } | |
| 495 | |
| 496 bool OneCopyTileTaskWorkerPool::OnMemoryDump( | |
| 497 const base::trace_event::MemoryDumpArgs& args, | |
| 498 base::trace_event::ProcessMemoryDump* pmd) { | |
| 499 base::AutoLock lock(lock_); | |
| 500 | |
| 501 for (const auto* buffer : buffers_) { | |
| 502 auto in_free_buffers = | |
| 503 std::find_if(free_buffers_.begin(), free_buffers_.end(), | |
| 504 [buffer](const scoped_ptr<StagingBuffer>& b) { | |
| 505 return b.get() == buffer; | |
| 506 }); | |
| 507 buffer->OnMemoryDump(pmd, buffer->format, | |
| 508 in_free_buffers != free_buffers_.end()); | |
| 509 } | |
| 510 | |
| 511 return true; | |
| 512 } | |
| 513 | |
| 514 void OneCopyTileTaskWorkerPool::AddStagingBuffer( | |
| 515 const StagingBuffer* staging_buffer, | |
| 516 ResourceFormat format) { | |
| 517 lock_.AssertAcquired(); | |
| 518 | |
| 519 DCHECK(buffers_.find(staging_buffer) == buffers_.end()); | |
| 520 buffers_.insert(staging_buffer); | |
| 521 int buffer_usage_in_bytes = | |
| 522 ResourceUtil::UncheckedSizeInBytes<int>(staging_buffer->size, format); | |
| 523 staging_buffer_usage_in_bytes_ += buffer_usage_in_bytes; | |
| 524 } | |
| 525 | |
| 526 void OneCopyTileTaskWorkerPool::RemoveStagingBuffer( | |
| 527 const StagingBuffer* staging_buffer) { | |
| 528 lock_.AssertAcquired(); | |
| 529 | |
| 530 DCHECK(buffers_.find(staging_buffer) != buffers_.end()); | |
| 531 buffers_.erase(staging_buffer); | |
| 532 int buffer_usage_in_bytes = ResourceUtil::UncheckedSizeInBytes<int>( | |
| 533 staging_buffer->size, staging_buffer->format); | |
| 534 DCHECK_GE(staging_buffer_usage_in_bytes_, buffer_usage_in_bytes); | |
| 535 staging_buffer_usage_in_bytes_ -= buffer_usage_in_bytes; | |
| 536 } | |
| 537 | |
| 538 void OneCopyTileTaskWorkerPool::MarkStagingBufferAsFree( | |
| 539 const StagingBuffer* staging_buffer) { | |
| 540 lock_.AssertAcquired(); | |
| 541 | |
| 542 int buffer_usage_in_bytes = ResourceUtil::UncheckedSizeInBytes<int>( | |
| 543 staging_buffer->size, staging_buffer->format); | |
| 544 free_staging_buffer_usage_in_bytes_ += buffer_usage_in_bytes; | |
| 545 } | |
| 546 | |
| 547 void OneCopyTileTaskWorkerPool::MarkStagingBufferAsBusy( | |
| 548 const StagingBuffer* staging_buffer) { | |
| 549 lock_.AssertAcquired(); | |
| 550 | |
| 551 int buffer_usage_in_bytes = ResourceUtil::UncheckedSizeInBytes<int>( | |
| 552 staging_buffer->size, staging_buffer->format); | |
| 553 DCHECK_GE(free_staging_buffer_usage_in_bytes_, buffer_usage_in_bytes); | |
| 554 free_staging_buffer_usage_in_bytes_ -= buffer_usage_in_bytes; | |
| 555 } | |
| 556 | |
| 557 scoped_ptr<OneCopyTileTaskWorkerPool::StagingBuffer> | |
| 558 OneCopyTileTaskWorkerPool::AcquireStagingBuffer(const Resource* resource, | |
| 559 uint64_t previous_content_id) { | |
| 560 lock_.AssertAcquired(); | |
| 561 | |
| 562 scoped_ptr<StagingBuffer> staging_buffer; | |
| 563 | |
| 564 ContextProvider* context_provider = | |
| 565 resource_provider_->output_surface()->worker_context_provider(); | |
| 566 DCHECK(context_provider); | |
| 567 | |
| 568 ContextProvider::ScopedContextLock scoped_context(context_provider); | |
| 569 | |
| 570 gpu::gles2::GLES2Interface* gl = scoped_context.ContextGL(); | |
| 571 DCHECK(gl); | |
| 572 | |
| 573 // Check if any busy buffers have become available. | |
| 574 if (resource_provider_->use_sync_query()) { | |
| 575 while (!busy_buffers_.empty()) { | |
| 576 if (!CheckForQueryResult(gl, busy_buffers_.front()->query_id)) | |
| 577 break; | |
| 578 | |
| 579 MarkStagingBufferAsFree(busy_buffers_.front().get()); | |
| 580 free_buffers_.push_back(PopFront(&busy_buffers_)); | |
| 581 } | |
| 582 } | |
| 583 | |
| 584 // Wait for memory usage of non-free buffers to become less than the limit. | |
| 585 while ( | |
| 586 (staging_buffer_usage_in_bytes_ - free_staging_buffer_usage_in_bytes_) >= | |
| 587 max_staging_buffer_usage_in_bytes_) { | |
| 588 // Stop when there are no more busy buffers to wait for. | |
| 589 if (busy_buffers_.empty()) | |
| 590 break; | |
| 591 | |
| 592 if (resource_provider_->use_sync_query()) { | |
| 593 WaitForQueryResult(gl, busy_buffers_.front()->query_id); | |
| 594 MarkStagingBufferAsFree(busy_buffers_.front().get()); | |
| 595 free_buffers_.push_back(PopFront(&busy_buffers_)); | |
| 596 } else { | |
| 597 // Fall-back to glFinish if CHROMIUM_sync_query is not available. | |
| 598 gl->Finish(); | |
| 599 while (!busy_buffers_.empty()) { | |
| 600 MarkStagingBufferAsFree(busy_buffers_.front().get()); | |
| 601 free_buffers_.push_back(PopFront(&busy_buffers_)); | |
| 602 } | |
| 603 } | |
| 604 } | |
| 605 | |
| 606 // Find a staging buffer that allows us to perform partial raster when | |
| 607 // using persistent GpuMemoryBuffers. | |
| 608 if (use_partial_raster_ && previous_content_id) { | |
| 609 StagingBufferDeque::iterator it = std::find_if( | |
| 610 free_buffers_.begin(), free_buffers_.end(), | |
| 611 [previous_content_id](const scoped_ptr<StagingBuffer>& buffer) { | |
| 612 return buffer->content_id == previous_content_id; | |
| 613 }); | |
| 614 if (it != free_buffers_.end()) { | |
| 615 staging_buffer = std::move(*it); | |
| 616 free_buffers_.erase(it); | |
| 617 MarkStagingBufferAsBusy(staging_buffer.get()); | |
| 618 } | |
| 619 } | |
| 620 | |
| 621 // Find staging buffer of correct size and format. | |
| 622 if (!staging_buffer) { | |
| 623 StagingBufferDeque::iterator it = | |
| 624 std::find_if(free_buffers_.begin(), free_buffers_.end(), | |
| 625 [resource](const scoped_ptr<StagingBuffer>& buffer) { | |
| 626 return buffer->size == resource->size() && | |
| 627 buffer->format == resource->format(); | |
| 628 }); | |
| 629 if (it != free_buffers_.end()) { | |
| 630 staging_buffer = std::move(*it); | |
| 631 free_buffers_.erase(it); | |
| 632 MarkStagingBufferAsBusy(staging_buffer.get()); | |
| 633 } | |
| 634 } | |
| 635 | |
| 636 // Create new staging buffer if necessary. | |
| 637 if (!staging_buffer) { | |
| 638 staging_buffer = make_scoped_ptr( | |
| 639 new StagingBuffer(resource->size(), resource->format())); | |
| 640 AddStagingBuffer(staging_buffer.get(), resource->format()); | |
| 641 } | |
| 642 | |
| 643 // Release enough free buffers to stay within the limit. | |
| 644 while (staging_buffer_usage_in_bytes_ > max_staging_buffer_usage_in_bytes_) { | |
| 645 if (free_buffers_.empty()) | |
| 646 break; | |
| 647 | |
| 648 free_buffers_.front()->DestroyGLResources(gl); | |
| 649 MarkStagingBufferAsBusy(free_buffers_.front().get()); | |
| 650 RemoveStagingBuffer(free_buffers_.front().get()); | |
| 651 free_buffers_.pop_front(); | |
| 652 } | |
| 653 | |
| 654 return staging_buffer; | |
| 655 } | |
| 656 | |
| 657 base::TimeTicks OneCopyTileTaskWorkerPool::GetUsageTimeForLRUBuffer() { | |
| 658 lock_.AssertAcquired(); | |
| 659 | |
| 660 if (!free_buffers_.empty()) | |
| 661 return free_buffers_.front()->last_usage; | |
| 662 | |
| 663 if (!busy_buffers_.empty()) | |
| 664 return busy_buffers_.front()->last_usage; | |
| 665 | |
| 666 return base::TimeTicks(); | |
| 667 } | |
| 668 | |
| 669 void OneCopyTileTaskWorkerPool::ScheduleReduceMemoryUsage() { | |
| 670 lock_.AssertAcquired(); | |
| 671 | |
| 672 if (reduce_memory_usage_pending_) | |
| 673 return; | |
| 674 | |
| 675 reduce_memory_usage_pending_ = true; | |
| 676 | |
| 677 // Schedule a call to ReduceMemoryUsage at the time when the LRU buffer | |
| 678 // should be released. | |
| 679 base::TimeTicks reduce_memory_usage_time = | |
| 680 GetUsageTimeForLRUBuffer() + staging_buffer_expiration_delay_; | |
| 681 task_runner_->PostDelayedTask( | |
| 682 FROM_HERE, reduce_memory_usage_callback_, | |
| 683 reduce_memory_usage_time - base::TimeTicks::Now()); | |
| 684 } | |
| 685 | |
| 686 void OneCopyTileTaskWorkerPool::ReduceMemoryUsage() { | |
| 687 base::AutoLock lock(lock_); | |
| 688 | |
| 689 reduce_memory_usage_pending_ = false; | |
| 690 | |
| 691 if (free_buffers_.empty() && busy_buffers_.empty()) | |
| 692 return; | |
| 693 | |
| 694 base::TimeTicks current_time = base::TimeTicks::Now(); | |
| 695 ReleaseBuffersNotUsedSince(current_time - staging_buffer_expiration_delay_); | |
| 696 | |
| 697 if (free_buffers_.empty() && busy_buffers_.empty()) | |
| 698 return; | |
| 699 | |
| 700 reduce_memory_usage_pending_ = true; | |
| 701 | |
| 702 // Schedule another call to ReduceMemoryUsage at the time when the next | |
| 703 // buffer should be released. | |
| 704 base::TimeTicks reduce_memory_usage_time = | |
| 705 GetUsageTimeForLRUBuffer() + staging_buffer_expiration_delay_; | |
| 706 task_runner_->PostDelayedTask(FROM_HERE, reduce_memory_usage_callback_, | |
| 707 reduce_memory_usage_time - current_time); | |
| 708 } | |
| 709 | |
| 710 void OneCopyTileTaskWorkerPool::ReleaseBuffersNotUsedSince( | |
| 711 base::TimeTicks time) { | |
| 712 lock_.AssertAcquired(); | |
| 713 | |
| 714 ContextProvider* context_provider = | |
| 715 resource_provider_->output_surface()->worker_context_provider(); | |
| 716 DCHECK(context_provider); | |
| 717 | |
| 718 { | |
| 719 ContextProvider::ScopedContextLock scoped_context(context_provider); | |
| 720 | |
| 721 gpu::gles2::GLES2Interface* gl = scoped_context.ContextGL(); | |
| 722 DCHECK(gl); | |
| 723 | |
| 724 // Note: Front buffer is guaranteed to be LRU so we can stop releasing | |
| 725 // buffers as soon as we find a buffer that has been used since |time|. | |
| 726 while (!free_buffers_.empty()) { | |
| 727 if (free_buffers_.front()->last_usage > time) | |
| 728 return; | |
| 729 | |
| 730 free_buffers_.front()->DestroyGLResources(gl); | |
| 731 MarkStagingBufferAsBusy(free_buffers_.front().get()); | |
| 732 RemoveStagingBuffer(free_buffers_.front().get()); | |
| 733 free_buffers_.pop_front(); | |
| 734 } | |
| 735 | |
| 736 while (!busy_buffers_.empty()) { | |
| 737 if (busy_buffers_.front()->last_usage > time) | |
| 738 return; | |
| 739 | |
| 740 busy_buffers_.front()->DestroyGLResources(gl); | |
| 741 RemoveStagingBuffer(busy_buffers_.front().get()); | |
| 742 busy_buffers_.pop_front(); | |
| 743 } | |
| 744 } | |
| 745 } | 383 } |
| 746 | 384 |
| 747 } // namespace cc | 385 } // namespace cc |
| OLD | NEW |