1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include "GrGpuResource.h"
10#include "GrContext.h"
11#include "GrResourceCache.h"
12#include "GrGpu.h"
13#include "GrGpuResourcePriv.h"
14#include "SkTraceMemoryDump.h"
15
16static inline GrResourceCache* get_resource_cache(GrGpu* gpu) {
17    SkASSERT(gpu);
18    SkASSERT(gpu->getContext());
19    SkASSERT(gpu->getContext()->getResourceCache());
20    return gpu->getContext()->getResourceCache();
21}
22
23GrGpuResource::GrGpuResource(GrGpu* gpu, LifeCycle lifeCycle)
24    : fGpu(gpu)
25    , fGpuMemorySize(kInvalidGpuMemorySize)
26    , fLifeCycle(lifeCycle)
27    , fUniqueID(CreateUniqueID()) {
28    SkDEBUGCODE(fCacheArrayIndex = -1);
29}
30
31void GrGpuResource::registerWithCache() {
32    get_resource_cache(fGpu)->resourceAccess().insertResource(this);
33}
34
35GrGpuResource::~GrGpuResource() {
36    // The cache should have released or destroyed this resource.
37    SkASSERT(this->wasDestroyed());
38}
39
40void GrGpuResource::release() {
41    SkASSERT(fGpu);
42    this->onRelease();
43    get_resource_cache(fGpu)->resourceAccess().removeResource(this);
44    fGpu = nullptr;
45    fGpuMemorySize = 0;
46}
47
48void GrGpuResource::abandon() {
49    if (this->wasDestroyed()) {
50        return;
51    }
52    SkASSERT(fGpu);
53    this->onAbandon();
54    get_resource_cache(fGpu)->resourceAccess().removeResource(this);
55    fGpu = nullptr;
56    fGpuMemorySize = 0;
57}
58
59void GrGpuResource::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
60    // Dump resource as "skia/gpu_resources/resource_#".
61    SkString dumpName("skia/gpu_resources/resource_");
62    dumpName.appendS32(this->getUniqueID());
63
64    traceMemoryDump->dumpNumericValue(dumpName.c_str(), "size", "bytes", this->gpuMemorySize());
65
66    if (this->isPurgeable()) {
67        traceMemoryDump->dumpNumericValue(dumpName.c_str(), "purgeable_size", "bytes",
68                                          this->gpuMemorySize());
69    }
70
71    // Call setMemoryBacking to allow sub-classes with implementation specific backings (such as GL
72    // objects) to provide additional information.
73    this->setMemoryBacking(traceMemoryDump, dumpName);
74}
75
76const SkData* GrGpuResource::setCustomData(const SkData* data) {
77    SkSafeRef(data);
78    fData.reset(data);
79    return data;
80}
81
82const GrContext* GrGpuResource::getContext() const {
83    if (fGpu) {
84        return fGpu->getContext();
85    } else {
86        return nullptr;
87    }
88}
89
90GrContext* GrGpuResource::getContext() {
91    if (fGpu) {
92        return fGpu->getContext();
93    } else {
94        return nullptr;
95    }
96}
97
98void GrGpuResource::didChangeGpuMemorySize() const {
99    if (this->wasDestroyed()) {
100        return;
101    }
102
103    size_t oldSize = fGpuMemorySize;
104    SkASSERT(kInvalidGpuMemorySize != oldSize);
105    fGpuMemorySize = kInvalidGpuMemorySize;
106    get_resource_cache(fGpu)->resourceAccess().didChangeGpuMemorySize(this, oldSize);
107}
108
109void GrGpuResource::removeUniqueKey() {
110    if (this->wasDestroyed()) {
111        return;
112    }
113    SkASSERT(fUniqueKey.isValid());
114    get_resource_cache(fGpu)->resourceAccess().removeUniqueKey(this);
115}
116
117void GrGpuResource::setUniqueKey(const GrUniqueKey& key) {
118    SkASSERT(this->internalHasRef());
119    SkASSERT(key.isValid());
120
121    // Wrapped and uncached resources can never have a unique key.
122    if (SkBudgeted::kNo == this->resourcePriv().isBudgeted()) {
123        return;
124    }
125
126    if (this->wasDestroyed()) {
127        return;
128    }
129
130    get_resource_cache(fGpu)->resourceAccess().changeUniqueKey(this, key);
131}
132
133void GrGpuResource::notifyAllCntsAreZero(CntType lastCntTypeToReachZero) const {
134    if (this->wasDestroyed()) {
135        // We've already been removed from the cache. Goodbye cruel world!
136        delete this;
137        return;
138    }
139
140    // We should have already handled this fully in notifyRefCntIsZero().
141    SkASSERT(kRef_CntType != lastCntTypeToReachZero);
142
143    GrGpuResource* mutableThis = const_cast<GrGpuResource*>(this);
144    static const uint32_t kFlag =
145        GrResourceCache::ResourceAccess::kAllCntsReachedZero_RefNotificationFlag;
146    get_resource_cache(fGpu)->resourceAccess().notifyCntReachedZero(mutableThis, kFlag);
147}
148
149bool GrGpuResource::notifyRefCountIsZero() const {
150    if (this->wasDestroyed()) {
151        // handle this in notifyAllCntsAreZero().
152        return true;
153    }
154
155    GrGpuResource* mutableThis = const_cast<GrGpuResource*>(this);
156    uint32_t flags =
157        GrResourceCache::ResourceAccess::kRefCntReachedZero_RefNotificationFlag;
158    if (!this->internalHasPendingIO()) {
159        flags |= GrResourceCache::ResourceAccess::kAllCntsReachedZero_RefNotificationFlag;
160    }
161    get_resource_cache(fGpu)->resourceAccess().notifyCntReachedZero(mutableThis, flags);
162
163    // There is no need to call our notifyAllCntsAreZero function at this point since we already
164    // told the cache about the state of cnts.
165    return false;
166}
167
168void GrGpuResource::setScratchKey(const GrScratchKey& scratchKey) {
169    SkASSERT(!fScratchKey.isValid());
170    SkASSERT(scratchKey.isValid());
171    // Wrapped resources can never have a scratch key.
172    if (this->cacheAccess().isExternal()) {
173        return;
174    }
175    fScratchKey = scratchKey;
176}
177
178void GrGpuResource::removeScratchKey() {
179    if (!this->wasDestroyed() && fScratchKey.isValid()) {
180        get_resource_cache(fGpu)->resourceAccess().willRemoveScratchKey(this);
181        fScratchKey.reset();
182    }
183}
184
185void GrGpuResource::makeBudgeted() {
186    if (!this->wasDestroyed() && GrGpuResource::kUncached_LifeCycle == fLifeCycle) {
187        fLifeCycle = kCached_LifeCycle;
188        get_resource_cache(fGpu)->resourceAccess().didChangeBudgetStatus(this);
189    }
190}
191
192void GrGpuResource::makeUnbudgeted() {
193    if (!this->wasDestroyed() && GrGpuResource::kCached_LifeCycle == fLifeCycle &&
194        !fUniqueKey.isValid()) {
195        fLifeCycle = kUncached_LifeCycle;
196        get_resource_cache(fGpu)->resourceAccess().didChangeBudgetStatus(this);
197    }
198}
199
200uint32_t GrGpuResource::CreateUniqueID() {
201    static int32_t gUniqueID = SK_InvalidUniqueID;
202    uint32_t id;
203    do {
204        id = static_cast<uint32_t>(sk_atomic_inc(&gUniqueID) + 1);
205    } while (id == SK_InvalidUniqueID);
206    return id;
207}
208