This source file includes following definitions.
- MaxNumberOfBackingStores
- MaxBackingStoreMemory
- ExpireBackingStoreAt
- ExpireLastBackingStore
- CreateCacheSpace
- CreateBackingStore
- ComputeTotalArea
- GetBackingStore
- PrepareBackingStore
- Lookup
- RemoveBackingStore
- MemorySize
#include "content/browser/renderer_host/backing_store_manager.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/containers/mru_cache.h"
#include "base/sys_info.h"
#include "content/browser/renderer_host/backing_store.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/public/common/content_switches.h"
namespace content {
namespace {
typedef base::OwningMRUCache<RenderWidgetHost*, BackingStore*>
BackingStoreCache;
BackingStoreCache* large_cache = NULL;
BackingStoreCache* small_cache = NULL;
const size_t kSmallThreshold = 4 * 32 * 1920;
const size_t kMemoryMultiplier = 4 * 1920 * 1200;
static size_t MaxNumberOfBackingStores() {
static bool unlimited = false;
const CommandLine& command = *CommandLine::ForCurrentProcess();
unlimited = command.HasSwitch(switches::kDisableBackingStoreLimit);
if (unlimited) {
return 100;
} else {
return std::min(5, 2 + (base::SysInfo::AmountOfPhysicalMemoryMB() / 256));
}
}
static size_t MaxBackingStoreMemory() {
return MaxNumberOfBackingStores() * kMemoryMultiplier;
}
void ExpireBackingStoreAt(BackingStoreCache* cache,
BackingStoreCache::iterator backing_store) {
cache->Erase(backing_store);
}
size_t ExpireLastBackingStore(BackingStoreCache* cache) {
if (cache->size() < 1)
return 0;
BackingStoreCache::iterator entry = --cache->rbegin().base();
size_t entry_size = entry->second->MemorySize();
ExpireBackingStoreAt(cache, entry);
return entry_size;
}
void CreateCacheSpace(size_t size) {
while (size > 0 && (large_cache->size() > 1 || small_cache->size() > 1)) {
BackingStoreCache* cache =
(large_cache->size() > 1) ? large_cache : small_cache;
while (size > 0 && cache->size() > 1) {
size_t entry_size = ExpireLastBackingStore(cache);
if (size > entry_size)
size -= entry_size;
else
size = 0;
}
}
DCHECK(size == 0);
}
BackingStore* CreateBackingStore(RenderWidgetHost* host,
const gfx::Size& backing_store_size) {
BackingStoreManager::RemoveBackingStore(host);
if (!large_cache) {
large_cache = new BackingStoreCache(BackingStoreCache::NO_AUTO_EVICT);
small_cache = new BackingStoreCache(BackingStoreCache::NO_AUTO_EVICT);
}
size_t new_mem = backing_store_size.GetArea() * 4;
size_t current_mem = BackingStoreManager::MemorySize();
size_t max_mem = MaxBackingStoreMemory();
DCHECK(new_mem < max_mem);
if (current_mem + new_mem > max_mem) {
CreateCacheSpace((current_mem + new_mem) - max_mem);
}
DCHECK((BackingStoreManager::MemorySize() + new_mem) <= max_mem);
BackingStoreCache* cache;
if (new_mem > kSmallThreshold) {
if (large_cache->size() >= MaxNumberOfBackingStores())
ExpireLastBackingStore(large_cache);
cache = large_cache;
} else {
cache = small_cache;
}
BackingStore* backing_store = RenderWidgetHostImpl::From(
host)->AllocBackingStore(backing_store_size);
if (backing_store)
cache->Put(host, backing_store);
return backing_store;
}
int ComputeTotalArea(const std::vector<gfx::Rect>& rects) {
#ifndef NDEBUG
for (size_t i = 0; i < rects.size(); ++i) {
for (size_t j = 0; j < rects.size(); ++j) {
if (i != j)
DCHECK(!rects[i].Intersects(rects[j]));
}
}
#endif
int area = 0;
for (size_t i = 0; i < rects.size(); ++i)
area += rects[i].size().GetArea();
return area;
}
}
BackingStore* BackingStoreManager::GetBackingStore(
RenderWidgetHost* host,
const gfx::Size& desired_size) {
BackingStore* backing_store = Lookup(host);
if (backing_store) {
if (backing_store->size() == desired_size)
return backing_store;
backing_store = NULL;
}
return backing_store;
}
void BackingStoreManager::PrepareBackingStore(
RenderWidgetHost* host,
const gfx::Size& backing_store_size,
TransportDIB::Id bitmap,
const gfx::Rect& bitmap_rect,
const std::vector<gfx::Rect>& copy_rects,
float scale_factor,
const base::Closure& completion_callback,
bool* needs_full_paint,
bool* scheduled_completion_callback) {
BackingStore* backing_store = GetBackingStore(host, backing_store_size);
if (!backing_store) {
if (bitmap_rect.size() != backing_store_size ||
bitmap_rect.x() != 0 || bitmap_rect.y() != 0 ||
ComputeTotalArea(copy_rects) != backing_store_size.GetArea() ||
!(backing_store = CreateBackingStore(host, backing_store_size))) {
DCHECK(needs_full_paint != NULL);
*needs_full_paint = true;
*scheduled_completion_callback = false;
return;
}
}
backing_store->PaintToBackingStore(host->GetProcess(), bitmap,
bitmap_rect, copy_rects, scale_factor,
completion_callback,
scheduled_completion_callback);
}
BackingStore* BackingStoreManager::Lookup(RenderWidgetHost* host) {
if (large_cache) {
BackingStoreCache::iterator it = large_cache->Get(host);
if (it != large_cache->end())
return it->second;
it = small_cache->Get(host);
if (it != small_cache->end())
return it->second;
}
return NULL;
}
void BackingStoreManager::RemoveBackingStore(RenderWidgetHost* host) {
if (!large_cache)
return;
BackingStoreCache* cache = large_cache;
BackingStoreCache::iterator it = cache->Peek(host);
if (it == cache->end()) {
cache = small_cache;
it = cache->Peek(host);
if (it == cache->end())
return;
}
cache->Erase(it);
}
size_t BackingStoreManager::MemorySize() {
if (!large_cache)
return 0;
size_t mem = 0;
BackingStoreCache::iterator it;
for (it = large_cache->begin(); it != large_cache->end(); ++it)
mem += it->second->MemorySize();
for (it = small_cache->begin(); it != small_cache->end(); ++it)
mem += it->second->MemorySize();
return mem;
}
}