OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2017 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 "gpu/command_buffer/service/service_discardable_manager.h" |
| 6 |
| 7 #include "base/memory/singleton.h" |
| 8 |
| 9 namespace gpu { |
| 10 namespace { |
| 11 // TODO(ericrk): Arbitrary limit, refine this once we actually use this class in |
| 12 // production. crbug.com/706456 |
| 13 const size_t kMaxSize = 256 * 1024 * 1024; |
| 14 } |
| 15 |
| 16 ServiceDiscardableManager::GpuDiscardableEntry::GpuDiscardableEntry( |
| 17 ServiceDiscardableHandle handle, |
| 18 size_t size) |
| 19 : handle(handle), size(size) {} |
| 20 ServiceDiscardableManager::GpuDiscardableEntry::GpuDiscardableEntry( |
| 21 const GpuDiscardableEntry& other) = default; |
| 22 ServiceDiscardableManager::GpuDiscardableEntry::GpuDiscardableEntry( |
| 23 GpuDiscardableEntry&& other) = default; |
| 24 ServiceDiscardableManager::GpuDiscardableEntry::~GpuDiscardableEntry() = |
| 25 default; |
| 26 |
| 27 ServiceDiscardableManager::ServiceDiscardableManager() |
| 28 : entries_(EntryCache::NO_AUTO_EVICT) {} |
| 29 ServiceDiscardableManager::~ServiceDiscardableManager() { |
| 30 #if DCHECK_IS_ON() |
| 31 for (const auto& entry : entries_) { |
| 32 DCHECK(nullptr == entry.second.unlocked_texture_ref); |
| 33 } |
| 34 #endif |
| 35 } |
| 36 |
| 37 void ServiceDiscardableManager::InsertLockedTexture( |
| 38 uint32_t texture_id, |
| 39 size_t texture_size, |
| 40 gles2::TextureManager* texture_manager, |
| 41 ServiceDiscardableHandle handle) { |
| 42 total_size_ += texture_size; |
| 43 entries_.Put({texture_id, texture_manager}, |
| 44 GpuDiscardableEntry{handle, texture_size}); |
| 45 EnforceLimits(); |
| 46 } |
| 47 |
| 48 bool ServiceDiscardableManager::UnlockTexture( |
| 49 uint32_t texture_id, |
| 50 gles2::TextureManager* texture_manager, |
| 51 gles2::TextureRef** texture_to_unbind) { |
| 52 *texture_to_unbind = nullptr; |
| 53 |
| 54 auto found = entries_.Get({texture_id, texture_manager}); |
| 55 if (found == entries_.end()) |
| 56 return false; |
| 57 |
| 58 found->second.handle.Unlock(); |
| 59 if (--found->second.service_ref_count_ == 0) { |
| 60 found->second.unlocked_texture_ref = |
| 61 texture_manager->TakeTexture(texture_id); |
| 62 *texture_to_unbind = found->second.unlocked_texture_ref.get(); |
| 63 } |
| 64 |
| 65 return true; |
| 66 } |
| 67 |
| 68 bool ServiceDiscardableManager::LockTexture( |
| 69 uint32_t texture_id, |
| 70 gles2::TextureManager* texture_manager) { |
| 71 auto found = entries_.Peek({texture_id, texture_manager}); |
| 72 if (found == entries_.end()) |
| 73 return false; |
| 74 |
| 75 ++found->second.service_ref_count_; |
| 76 if (found->second.unlocked_texture_ref) { |
| 77 texture_manager->ReturnTexture( |
| 78 std::move(found->second.unlocked_texture_ref)); |
| 79 } |
| 80 |
| 81 return true; |
| 82 } |
| 83 |
| 84 void ServiceDiscardableManager::OnTextureManagerDestruction( |
| 85 gles2::TextureManager* texture_manager) { |
| 86 for (auto& entry : entries_) { |
| 87 if (entry.first.texture_manager == texture_manager && |
| 88 entry.second.unlocked_texture_ref) { |
| 89 texture_manager->ReturnTexture( |
| 90 std::move(entry.second.unlocked_texture_ref)); |
| 91 } |
| 92 } |
| 93 } |
| 94 |
| 95 void ServiceDiscardableManager::OnTextureDeleted( |
| 96 uint32_t texture_id, |
| 97 gles2::TextureManager* texture_manager) { |
| 98 auto found = entries_.Get({texture_id, texture_manager}); |
| 99 if (found == entries_.end()) |
| 100 return; |
| 101 |
| 102 found->second.handle.ForceDelete(); |
| 103 total_size_ -= found->second.size; |
| 104 entries_.Erase(found); |
| 105 } |
| 106 |
| 107 void ServiceDiscardableManager::OnTextureSizeChanged( |
| 108 uint32_t texture_id, |
| 109 gles2::TextureManager* texture_manager, |
| 110 size_t new_size) { |
| 111 auto found = entries_.Get({texture_id, texture_manager}); |
| 112 if (found == entries_.end()) |
| 113 return; |
| 114 |
| 115 total_size_ -= found->second.size; |
| 116 found->second.size = new_size; |
| 117 total_size_ += found->second.size; |
| 118 |
| 119 EnforceLimits(); |
| 120 } |
| 121 |
| 122 void ServiceDiscardableManager::EnforceLimits() { |
| 123 for (auto it = entries_.rbegin(); it != entries_.rend();) { |
| 124 if (total_size_ <= kMaxSize) { |
| 125 return; |
| 126 } |
| 127 if (!it->second.handle.Delete()) { |
| 128 ++it; |
| 129 continue; |
| 130 } |
| 131 |
| 132 total_size_ -= it->second.size; |
| 133 |
| 134 gles2::TextureManager* texture_manager = it->first.texture_manager; |
| 135 uint32_t texture_id = it->first.texture_id; |
| 136 |
| 137 // While unlocked, we hold the texture ref. Return this to the texture |
| 138 // manager for cleanup. |
| 139 texture_manager->ReturnTexture(std::move(it->second.unlocked_texture_ref)); |
| 140 |
| 141 // Erase before calling texture_manager->RemoveTexture, to avoid attempting |
| 142 // to remove the texture from entries_ twice. |
| 143 it = entries_.Erase(it); |
| 144 texture_manager->RemoveTexture(texture_id); |
| 145 } |
| 146 } |
| 147 |
| 148 bool ServiceDiscardableManager::IsEntryLockedForTesting( |
| 149 uint32_t texture_id, |
| 150 gles2::TextureManager* texture_manager) const { |
| 151 auto found = entries_.Peek({texture_id, texture_manager}); |
| 152 DCHECK(found != entries_.end()); |
| 153 |
| 154 return found->second.handle.IsLockedForTesting(); |
| 155 } |
| 156 |
| 157 gles2::TextureRef* ServiceDiscardableManager::UnlockedTextureRefForTesting( |
| 158 uint32_t texture_id, |
| 159 gles2::TextureManager* texture_manager) const { |
| 160 auto found = entries_.Peek({texture_id, texture_manager}); |
| 161 DCHECK(found != entries_.end()); |
| 162 |
| 163 return found->second.unlocked_texture_ref.get(); |
| 164 } |
| 165 |
| 166 } // namespace gpu |
OLD | NEW |