1// Copyright 2012 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 "cc/resources/prioritized_resource.h"
6
7#include <algorithm>
8
9#include "cc/resources/platform_color.h"
10#include "cc/resources/prioritized_resource_manager.h"
11#include "cc/resources/priority_calculator.h"
12#include "cc/trees/proxy.h"
13
14namespace cc {
15
16PrioritizedResource::PrioritizedResource(PrioritizedResourceManager* manager,
17                                         gfx::Size size,
18                                         ResourceFormat format)
19    : size_(size),
20      format_(format),
21      bytes_(0),
22      contents_swizzled_(false),
23      priority_(PriorityCalculator::LowestPriority()),
24      is_above_priority_cutoff_(false),
25      is_self_managed_(false),
26      backing_(NULL),
27      manager_(NULL) {
28  bytes_ = Resource::MemorySizeBytes(size, format);
29  if (manager)
30    manager->RegisterTexture(this);
31}
32
33PrioritizedResource::~PrioritizedResource() {
34  if (manager_)
35    manager_->UnregisterTexture(this);
36}
37
38void PrioritizedResource::SetTextureManager(
39    PrioritizedResourceManager* manager) {
40  if (manager_ == manager)
41    return;
42  if (manager_)
43    manager_->UnregisterTexture(this);
44  if (manager)
45    manager->RegisterTexture(this);
46}
47
48void PrioritizedResource::SetDimensions(gfx::Size size, ResourceFormat format) {
49  if (format_ != format || size_ != size) {
50    is_above_priority_cutoff_ = false;
51    format_ = format;
52    size_ = size;
53    bytes_ = Resource::MemorySizeBytes(size, format);
54    DCHECK(manager_ || !backing_);
55    if (manager_)
56      manager_->ReturnBackingTexture(this);
57  }
58}
59
60bool PrioritizedResource::RequestLate() {
61  if (!manager_)
62    return false;
63  return manager_->RequestLate(this);
64}
65
66bool PrioritizedResource::BackingResourceWasEvicted() const {
67  return backing_ ? backing_->ResourceHasBeenDeleted() : false;
68}
69
70void PrioritizedResource::AcquireBackingTexture(
71    ResourceProvider* resource_provider) {
72  DCHECK(is_above_priority_cutoff_);
73  if (is_above_priority_cutoff_)
74    manager_->AcquireBackingTextureIfNeeded(this, resource_provider);
75}
76
77void PrioritizedResource::SetPixels(ResourceProvider* resource_provider,
78                                    const uint8_t* image,
79                                    gfx::Rect image_rect,
80                                    gfx::Rect source_rect,
81                                    gfx::Vector2d dest_offset) {
82  DCHECK(is_above_priority_cutoff_);
83  if (is_above_priority_cutoff_)
84    AcquireBackingTexture(resource_provider);
85  DCHECK(backing_);
86  resource_provider->SetPixels(
87      resource_id(), image, image_rect, source_rect, dest_offset);
88
89  // The component order may be bgra if we uploaded bgra pixels to rgba
90  // texture. Mark contents as swizzled if image component order is
91  // different than texture format.
92  contents_swizzled_ = !PlatformColor::SameComponentOrder(format_);
93}
94
95void PrioritizedResource::Link(Backing* backing) {
96  DCHECK(backing);
97  DCHECK(!backing->owner_);
98  DCHECK(!backing_);
99
100  backing_ = backing;
101  backing_->owner_ = this;
102}
103
104void PrioritizedResource::Unlink() {
105  DCHECK(backing_);
106  DCHECK(backing_->owner_ == this);
107
108  backing_->owner_ = NULL;
109  backing_ = NULL;
110}
111
112void PrioritizedResource::SetToSelfManagedMemoryPlaceholder(size_t bytes) {
113  SetDimensions(gfx::Size(), RGBA_8888);
114  set_is_self_managed(true);
115  bytes_ = bytes;
116}
117
118PrioritizedResource::Backing::Backing(unsigned id,
119                                      ResourceProvider* resource_provider,
120                                      gfx::Size size,
121                                      ResourceFormat format)
122    : Resource(id, size, format),
123      owner_(NULL),
124      priority_at_last_priority_update_(PriorityCalculator::LowestPriority()),
125      was_above_priority_cutoff_at_last_priority_update_(false),
126      in_drawing_impl_tree_(false),
127      in_parent_compositor_(false),
128#ifdef NDEBUG
129      resource_has_been_deleted_(false) {}
130#else
131      resource_has_been_deleted_(false),
132      resource_provider_(resource_provider) {}
133#endif
134
135PrioritizedResource::Backing::~Backing() {
136  DCHECK(!owner_);
137  DCHECK(resource_has_been_deleted_);
138}
139
140void PrioritizedResource::Backing::DeleteResource(
141    ResourceProvider* resource_provider) {
142  DCHECK(!proxy() || proxy()->IsImplThread());
143  DCHECK(!resource_has_been_deleted_);
144#ifndef NDEBUG
145  DCHECK(resource_provider == resource_provider_);
146#endif
147
148  resource_provider->DeleteResource(id());
149  set_id(0);
150  resource_has_been_deleted_ = true;
151}
152
153bool PrioritizedResource::Backing::ResourceHasBeenDeleted() const {
154  DCHECK(!proxy() || proxy()->IsImplThread());
155  return resource_has_been_deleted_;
156}
157
158bool PrioritizedResource::Backing::CanBeRecycledIfNotInExternalUse() const {
159  DCHECK(!proxy() || proxy()->IsImplThread());
160  return !was_above_priority_cutoff_at_last_priority_update_ &&
161         !in_drawing_impl_tree_;
162}
163
164void PrioritizedResource::Backing::UpdatePriority() {
165  DCHECK(!proxy() ||
166         (proxy()->IsImplThread() && proxy()->IsMainThreadBlocked()));
167  if (owner_) {
168    priority_at_last_priority_update_ = owner_->request_priority();
169    was_above_priority_cutoff_at_last_priority_update_ =
170        owner_->is_above_priority_cutoff();
171  } else {
172    priority_at_last_priority_update_ = PriorityCalculator::LowestPriority();
173    was_above_priority_cutoff_at_last_priority_update_ = false;
174  }
175}
176
177void PrioritizedResource::Backing::UpdateState(
178    ResourceProvider* resource_provider) {
179  DCHECK(!proxy() ||
180         (proxy()->IsImplThread() && proxy()->IsMainThreadBlocked()));
181  in_drawing_impl_tree_ = !!owner();
182  in_parent_compositor_ = resource_provider->InUseByConsumer(id());
183  if (!in_drawing_impl_tree_) {
184    DCHECK_EQ(priority_at_last_priority_update_,
185              PriorityCalculator::LowestPriority());
186  }
187}
188
189void PrioritizedResource::ReturnBackingTexture() {
190  DCHECK(manager_ || !backing_);
191  if (manager_)
192    manager_->ReturnBackingTexture(this);
193}
194
195const Proxy* PrioritizedResource::Backing::proxy() const {
196  if (!owner_ || !owner_->resource_manager())
197    return NULL;
198  return owner_->resource_manager()->ProxyForDebug();
199}
200
201}  // namespace cc
202