• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef GrGpuResourceCacheAccess_DEFINED
9 #define GrGpuResourceCacheAccess_DEFINED
10 
11 #include "src/gpu/GrGpuResource.h"
12 #include "src/gpu/GrGpuResourcePriv.h"
13 
14 namespace skiatest {
15     class Reporter;
16 }  // namespace skiatest
17 
IsValidAddress(GrGpuResource * ptr)18 static inline bool IsValidAddress(GrGpuResource* ptr)
19 {
20 #if defined(__aarch64__)
21     static constexpr uint64_t HWASAN_HEADER = 0xFF00000000000000u;
22     static constexpr uint64_t HIGH_BOUND = 0x8000000000u;
23     static constexpr uint64_t LOW_BOUND = 0x1000u;
24     uint64_t memory = reinterpret_cast<uint64_t>(ptr);
25     uint64_t real = (memory & ~HWASAN_HEADER);
26     return (LOW_BOUND < real) && (real < HIGH_BOUND) && ptr->checkMagic();
27 #else
28     return true;
29 #endif
30 }
31 
32 /**
33  * This class allows GrResourceCache increased privileged access to GrGpuResource objects.
34  */
35 class GrGpuResource::CacheAccess {
36 private:
37     /** The cache is allowed to go from no refs to 1 ref. */
ref()38     void ref()
39     {
40         if (IsValidAddress(fResource)) fResource->addInitialRef();
41     }
42 
43     /**
44      * Is the resource currently cached as scratch? This means it is cached, has a valid scratch
45      * key, and does not have a unique key.
46      */
isScratch()47     bool isScratch() const {
48         return IsValidAddress(fResource) && !fResource->getUniqueKey().isValid() && fResource->fScratchKey.isValid() &&
49                GrBudgetedType::kBudgeted == fResource->resourcePriv().budgetedType();
50     }
51 
isUsableAsScratch()52     bool isUsableAsScratch() const {
53         return this->isScratch() && !fResource->internalHasRef();
54     }
55 
56     /**
57      * Called by the cache to delete the resource under normal circumstances.
58      */
release()59     void release() {
60         if (!IsValidAddress(fResource)) {
61             return;
62         }
63         fResource->release();
64         if (!fResource->hasRef() && fResource->hasNoCommandBufferUsages()) {
65             if (!IsValidAddress(fResource)) {
66                 return;
67             }
68             delete fResource;
69             fResource = nullptr;
70         }
71     }
72 
73     /**
74      * Called by the cache to delete the resource when the backend 3D context is no longer valid.
75      */
abandon()76     void abandon() {
77         if (!IsValidAddress(fResource)) {
78             return;
79         }
80         fResource->abandon();
81         if (!fResource->hasRef() && fResource->hasNoCommandBufferUsages()) {
82             if (!IsValidAddress(fResource)) {
83                 return;
84             }
85             delete fResource;
86         }
87     }
88 
89     /** Called by the cache to assign a new unique key. */
setUniqueKey(const GrUniqueKey & key)90     void setUniqueKey(const GrUniqueKey& key)
91     {
92         if (IsValidAddress(fResource)) fResource->fUniqueKey = key;
93     }
94 
95     /** Is the resource ref'ed */
hasRef()96     bool hasRef() const { return IsValidAddress(fResource) && fResource->hasRef(); }
hasRefOrCommandBufferUsage()97     bool hasRefOrCommandBufferUsage() const {
98         return this->hasRef() || (IsValidAddress(fResource) && !fResource->hasNoCommandBufferUsages());
99     }
100 
101     /** Called by the cache to make the unique key invalid. */
removeUniqueKey()102     void removeUniqueKey()
103     {
104         if (IsValidAddress(fResource)) fResource->fUniqueKey.reset();
105     }
106 
timestamp()107     uint32_t timestamp() const { return IsValidAddress(fResource) ? fResource->fTimestamp : 0; }
setTimestamp(uint32_t ts)108     void setTimestamp(uint32_t ts)
109     {
110         if (IsValidAddress(fResource)) fResource->fTimestamp = ts;
111     }
112 
setTimeWhenResourceBecomePurgeable()113     void setTimeWhenResourceBecomePurgeable() {
114         SkASSERT(fResource->isPurgeable());
115         if (IsValidAddress(fResource)) {
116             fResource->fTimeWhenBecamePurgeable = GrStdSteadyClock::now();
117         }
118     }
119     /**
120      * Called by the cache to determine whether this resource should be purged based on the length
121      * of time it has been available for purging.
122      */
timeWhenResourceBecamePurgeable()123     GrStdSteadyClock::time_point timeWhenResourceBecamePurgeable() {
124         SkASSERT(fResource->isPurgeable());
125         return IsValidAddress(fResource) ? fResource->fTimeWhenBecamePurgeable : GrStdSteadyClock::now();
126     }
127 
accessCacheIndex()128     int* accessCacheIndex() const
129     {
130         thread_local int IN_VALID_INDEX = 0;
131         return IsValidAddress(fResource) ? &fResource->fCacheArrayIndex : &IN_VALID_INDEX;
132     }
133 
CacheAccess(GrGpuResource * resource)134     CacheAccess(GrGpuResource* resource) : fResource(resource) {}
CacheAccess(const CacheAccess & that)135     CacheAccess(const CacheAccess& that) : fResource(that.fResource) {}
136     CacheAccess& operator=(const CacheAccess&) = delete;
137 
138     // No taking addresses of this type.
139     const CacheAccess* operator&() const = delete;
140     CacheAccess* operator&() = delete;
141 
142     GrGpuResource* fResource;
143 
144     friend class GrGpuResource; // to construct/copy this type.
145     friend class GrResourceCache; // to use this type
146     friend void test_unbudgeted_to_scratch(skiatest::Reporter* reporter); // for unit testing
147 };
148 
cacheAccess()149 inline GrGpuResource::CacheAccess GrGpuResource::cacheAccess() { return CacheAccess(this); }
150 
cacheAccess()151 inline const GrGpuResource::CacheAccess GrGpuResource::cacheAccess() const {  // NOLINT(readability-const-return-type)
152     return CacheAccess(const_cast<GrGpuResource*>(this));
153 }
154 
155 #endif
156