| 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..18810e6cef562f668d43cabbd8e18f28b191f247
|
| --- /dev/null
|
| +++ b/gpu/command_buffer/service/service_discardable_manager.cc
|
| @@ -0,0 +1,177 @@
|
| +// 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"
|
| +#include "gpu/command_buffer/service/texture_manager.h"
|
| +
|
| +namespace gpu {
|
| +
|
| +const size_t ServiceDiscardableManager::kMaxSize;
|
| +
|
| +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) {
|
| + auto found = entries_.Get({texture_id, texture_manager});
|
| + if (found != entries_.end()) {
|
| + // We have somehow initialized a texture twice. The client *shouldn't* send
|
| + // this command, but if it does, we will clean up the old entry and use
|
| + // the new one.
|
| + total_size_ -= found->second.size;
|
| + if (found->second.unlocked_texture_ref) {
|
| + texture_manager->ReturnTexture(
|
| + std::move(found->second.unlocked_texture_ref));
|
| + }
|
| + entries_.Erase(found);
|
| + }
|
| +
|
| + 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;
|
| +
|
| + gles2::TextureManager* texture_manager = it->first.texture_manager;
|
| + uint32_t texture_id = it->first.texture_id;
|
| +
|
| + // While unlocked, we hold the texture ref. Return this to the texture
|
| + // manager for cleanup.
|
| + texture_manager->ReturnTexture(std::move(it->second.unlocked_texture_ref));
|
| +
|
| + // Erase before calling texture_manager->RemoveTexture, to avoid attempting
|
| + // to remove the texture from entries_ twice.
|
| + it = entries_.Erase(it);
|
| + texture_manager->RemoveTexture(texture_id);
|
| + }
|
| +}
|
| +
|
| +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();
|
| +}
|
| +
|
| +gles2::TextureRef* ServiceDiscardableManager::UnlockedTextureRefForTesting(
|
| + uint32_t texture_id,
|
| + gles2::TextureManager* texture_manager) const {
|
| + auto found = entries_.Peek({texture_id, texture_manager});
|
| + DCHECK(found != entries_.end());
|
| +
|
| + return found->second.unlocked_texture_ref.get();
|
| +}
|
| +
|
| +} // namespace gpu
|
|
|