Chromium Code Reviews| Index: gpu/command_buffer/service/service_discardable_manager.cc |
| diff --git a/gpu/command_buffer/service/service_discardable_manager.cc b/gpu/command_buffer/service/service_discardable_manager.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..77b20f4673bd9e6a5874c7e9f8247e9baa52cacc |
| --- /dev/null |
| +++ b/gpu/command_buffer/service/service_discardable_manager.cc |
| @@ -0,0 +1,149 @@ |
| +// Copyright (c) 2017 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "gpu/command_buffer/service/service_discardable_manager.h" |
| + |
| +#include "base/memory/singleton.h" |
| + |
| +namespace gpu { |
| +namespace { |
| +// TODO(ericrk): Arbitrary limit, refine this once we actually use this class in |
| +// production. crbug.com/706456 |
| +const size_t kMaxSize = 256 * 1024 * 1024; |
| +} |
| + |
| +ServiceDiscardableManager::GpuDiscardableEntry::GpuDiscardableEntry( |
| + ServiceDiscardableHandle handle, |
| + size_t size) |
| + : handle(handle), size(size) {} |
| +ServiceDiscardableManager::GpuDiscardableEntry::GpuDiscardableEntry( |
| + const GpuDiscardableEntry& other) = default; |
| +ServiceDiscardableManager::GpuDiscardableEntry::GpuDiscardableEntry( |
| + GpuDiscardableEntry&& other) = default; |
| +ServiceDiscardableManager::GpuDiscardableEntry::~GpuDiscardableEntry() = |
| + default; |
| + |
| +ServiceDiscardableManager::ServiceDiscardableManager() |
| + : entries_(EntryCache::NO_AUTO_EVICT) {} |
| +ServiceDiscardableManager::~ServiceDiscardableManager() { |
| +#if DCHECK_IS_ON() |
| + for (const auto& entry : entries_) { |
| + DCHECK(nullptr == entry.second.unlocked_texture_ref); |
| + } |
| +#endif |
| +} |
| + |
| +void ServiceDiscardableManager::InsertLockedTexture( |
| + uint32_t texture_id, |
| + size_t texture_size, |
| + gles2::TextureManager* texture_manager, |
| + ServiceDiscardableHandle handle) { |
| + total_size_ += texture_size; |
| + entries_.Put({texture_id, texture_manager}, |
| + GpuDiscardableEntry{handle, texture_size}); |
| + EnforceLimits(); |
| +} |
| + |
| +bool ServiceDiscardableManager::UnlockTexture( |
| + uint32_t texture_id, |
| + gles2::TextureManager* texture_manager, |
| + gles2::TextureRef** texture_to_unbind) { |
| + *texture_to_unbind = nullptr; |
| + |
| + auto found = entries_.Get({texture_id, texture_manager}); |
| + if (found == entries_.end()) |
| + return false; |
| + |
| + found->second.handle.Unlock(); |
| + if (--found->second.service_ref_count_ == 0) { |
| + found->second.unlocked_texture_ref = |
| + texture_manager->TakeTexture(texture_id); |
| + *texture_to_unbind = found->second.unlocked_texture_ref.get(); |
| + } |
| + |
| + return true; |
| +} |
| + |
| +bool ServiceDiscardableManager::LockTexture( |
| + uint32_t texture_id, |
| + gles2::TextureManager* texture_manager) { |
| + auto found = entries_.Peek({texture_id, texture_manager}); |
| + if (found == entries_.end()) |
| + return false; |
| + |
| + ++found->second.service_ref_count_; |
| + if (found->second.unlocked_texture_ref) { |
| + texture_manager->ReturnTexture( |
| + std::move(found->second.unlocked_texture_ref)); |
| + } |
| + |
| + return true; |
| +} |
| + |
| +void ServiceDiscardableManager::OnTextureManagerDestruction( |
| + gles2::TextureManager* texture_manager) { |
| + for (auto& entry : entries_) { |
| + if (entry.first.texture_manager == texture_manager && |
| + entry.second.unlocked_texture_ref) { |
| + texture_manager->ReturnTexture( |
| + std::move(entry.second.unlocked_texture_ref)); |
| + } |
| + } |
| +} |
| + |
| +void ServiceDiscardableManager::OnTextureDeleted( |
| + uint32_t texture_id, |
| + gles2::TextureManager* texture_manager) { |
| + auto found = entries_.Get({texture_id, texture_manager}); |
| + if (found == entries_.end()) |
| + return; |
| + |
| + found->second.handle.ForceDelete(); |
| + total_size_ -= found->second.size; |
| + entries_.Erase(found); |
| +} |
| + |
| +void ServiceDiscardableManager::OnTextureSizeChanged( |
| + uint32_t texture_id, |
| + gles2::TextureManager* texture_manager, |
| + size_t new_size) { |
| + auto found = entries_.Get({texture_id, texture_manager}); |
| + if (found == entries_.end()) |
| + return; |
| + |
| + total_size_ -= found->second.size; |
| + found->second.size = new_size; |
| + total_size_ += found->second.size; |
| + |
| + EnforceLimits(); |
| +} |
| + |
| +void ServiceDiscardableManager::EnforceLimits() { |
| + for (auto it = entries_.rbegin(); it != entries_.rend();) { |
| + if (total_size_ <= kMaxSize) { |
| + return; |
| + } |
| + if (!it->second.handle.Delete()) { |
| + ++it; |
| + continue; |
| + } |
| + |
| + total_size_ -= it->second.size; |
| + it->first.texture_manager->ReturnTexture( |
| + std::move(it->second.unlocked_texture_ref)); |
| + it->first.texture_manager->RemoveTexture(it->first.texture_id); |
| + it = entries_.Erase(it); |
|
piman
2017/05/10 22:13:59
Won't texture_manager->RemoveTexture above call in
ericrk
2017/05/12 16:22:11
yes, we should :D
|
| + } |
| +} |
| + |
| +bool ServiceDiscardableManager::IsEntryLockedForTesting( |
| + uint32_t texture_id, |
| + gles2::TextureManager* texture_manager) const { |
| + auto found = entries_.Peek({texture_id, texture_manager}); |
| + DCHECK(found != entries_.end()); |
| + |
| + return found->second.handle.IsLockedForTesting(); |
| +} |
| + |
| +} // namespace gpu |