// Copyright 2012 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 "cc/resources/prioritized_resource.h"
#include <algorithm>
#include "cc/resources/platform_color.h"
#include "cc/resources/prioritized_resource_manager.h"
#include "cc/resources/priority_calculator.h"
#include "cc/trees/proxy.h"
namespace cc {
PrioritizedResource::PrioritizedResource(PrioritizedResourceManager* manager,
gfx::Size size,
ResourceFormat format)
: size_(size),
format_(format),
bytes_(0),
contents_swizzled_(false),
priority_(PriorityCalculator::LowestPriority()),
is_above_priority_cutoff_(false),
is_self_managed_(false),
backing_(NULL),
manager_(NULL) {
bytes_ = Resource::MemorySizeBytes(size, format);
if (manager)
manager->RegisterTexture(this);
}
PrioritizedResource::~PrioritizedResource() {
if (manager_)
manager_->UnregisterTexture(this);
}
void PrioritizedResource::SetTextureManager(
PrioritizedResourceManager* manager) {
if (manager_ == manager)
return;
if (manager_)
manager_->UnregisterTexture(this);
if (manager)
manager->RegisterTexture(this);
}
void PrioritizedResource::SetDimensions(gfx::Size size, ResourceFormat format) {
if (format_ != format || size_ != size) {
is_above_priority_cutoff_ = false;
format_ = format;
size_ = size;
bytes_ = Resource::MemorySizeBytes(size, format);
DCHECK(manager_ || !backing_);
if (manager_)
manager_->ReturnBackingTexture(this);
}
}
bool PrioritizedResource::RequestLate() {
if (!manager_)
return false;
return manager_->RequestLate(this);
}
bool PrioritizedResource::BackingResourceWasEvicted() const {
return backing_ ? backing_->ResourceHasBeenDeleted() : false;
}
void PrioritizedResource::AcquireBackingTexture(
ResourceProvider* resource_provider) {
DCHECK(is_above_priority_cutoff_);
if (is_above_priority_cutoff_)
manager_->AcquireBackingTextureIfNeeded(this, resource_provider);
}
void PrioritizedResource::SetPixels(ResourceProvider* resource_provider,
const uint8_t* image,
gfx::Rect image_rect,
gfx::Rect source_rect,
gfx::Vector2d dest_offset) {
DCHECK(is_above_priority_cutoff_);
if (is_above_priority_cutoff_)
AcquireBackingTexture(resource_provider);
DCHECK(backing_);
resource_provider->SetPixels(
resource_id(), image, image_rect, source_rect, dest_offset);
// The component order may be bgra if we uploaded bgra pixels to rgba
// texture. Mark contents as swizzled if image component order is
// different than texture format.
contents_swizzled_ = !PlatformColor::SameComponentOrder(format_);
}
void PrioritizedResource::Link(Backing* backing) {
DCHECK(backing);
DCHECK(!backing->owner_);
DCHECK(!backing_);
backing_ = backing;
backing_->owner_ = this;
}
void PrioritizedResource::Unlink() {
DCHECK(backing_);
DCHECK(backing_->owner_ == this);
backing_->owner_ = NULL;
backing_ = NULL;
}
void PrioritizedResource::SetToSelfManagedMemoryPlaceholder(size_t bytes) {
SetDimensions(gfx::Size(), RGBA_8888);
set_is_self_managed(true);
bytes_ = bytes;
}
PrioritizedResource::Backing::Backing(unsigned id,
ResourceProvider* resource_provider,
gfx::Size size,
ResourceFormat format)
: Resource(id, size, format),
owner_(NULL),
priority_at_last_priority_update_(PriorityCalculator::LowestPriority()),
was_above_priority_cutoff_at_last_priority_update_(false),
in_drawing_impl_tree_(false),
in_parent_compositor_(false),
#ifdef NDEBUG
resource_has_been_deleted_(false) {}
#else
resource_has_been_deleted_(false),
resource_provider_(resource_provider) {}
#endif
PrioritizedResource::Backing::~Backing() {
DCHECK(!owner_);
DCHECK(resource_has_been_deleted_);
}
void PrioritizedResource::Backing::DeleteResource(
ResourceProvider* resource_provider) {
DCHECK(!proxy() || proxy()->IsImplThread());
DCHECK(!resource_has_been_deleted_);
#ifndef NDEBUG
DCHECK(resource_provider == resource_provider_);
#endif
resource_provider->DeleteResource(id());
set_id(0);
resource_has_been_deleted_ = true;
}
bool PrioritizedResource::Backing::ResourceHasBeenDeleted() const {
DCHECK(!proxy() || proxy()->IsImplThread());
return resource_has_been_deleted_;
}
bool PrioritizedResource::Backing::CanBeRecycledIfNotInExternalUse() const {
DCHECK(!proxy() || proxy()->IsImplThread());
return !was_above_priority_cutoff_at_last_priority_update_ &&
!in_drawing_impl_tree_;
}
void PrioritizedResource::Backing::UpdatePriority() {
DCHECK(!proxy() ||
(proxy()->IsImplThread() && proxy()->IsMainThreadBlocked()));
if (owner_) {
priority_at_last_priority_update_ = owner_->request_priority();
was_above_priority_cutoff_at_last_priority_update_ =
owner_->is_above_priority_cutoff();
} else {
priority_at_last_priority_update_ = PriorityCalculator::LowestPriority();
was_above_priority_cutoff_at_last_priority_update_ = false;
}
}
void PrioritizedResource::Backing::UpdateState(
ResourceProvider* resource_provider) {
DCHECK(!proxy() ||
(proxy()->IsImplThread() && proxy()->IsMainThreadBlocked()));
in_drawing_impl_tree_ = !!owner();
in_parent_compositor_ = resource_provider->InUseByConsumer(id());
if (!in_drawing_impl_tree_) {
DCHECK_EQ(priority_at_last_priority_update_,
PriorityCalculator::LowestPriority());
}
}
void PrioritizedResource::ReturnBackingTexture() {
DCHECK(manager_ || !backing_);
if (manager_)
manager_->ReturnBackingTexture(this);
}
const Proxy* PrioritizedResource::Backing::proxy() const {
if (!owner_ || !owner_->resource_manager())
return NULL;
return owner_->resource_manager()->ProxyForDebug();
}
} // namespace cc