• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2018 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // BlobCache: Stores keyed blobs in memory to support EGL_ANDROID_blob_cache.
7 // Can be used in conjunction with the platform layer to warm up the cache from
8 // disk.  MemoryProgramCache uses this to handle caching of compiled programs.
9 
10 #include "libANGLE/BlobCache.h"
11 #include "common/utilities.h"
12 #include "common/version.h"
13 #include "libANGLE/Context.h"
14 #include "libANGLE/Display.h"
15 #include "libANGLE/histogram_macros.h"
16 #include "platform/PlatformMethods.h"
17 
18 namespace egl
19 {
20 
21 namespace
22 {
23 enum CacheResult
24 {
25     kCacheMiss,
26     kCacheHitMemory,
27     kCacheHitDisk,
28     kCacheResultMax,
29 };
30 
31 }  // anonymous namespace
32 
BlobCache(size_t maxCacheSizeBytes)33 BlobCache::BlobCache(size_t maxCacheSizeBytes)
34     : mBlobCache(maxCacheSizeBytes), mSetBlobFunc(nullptr), mGetBlobFunc(nullptr)
35 {}
36 
~BlobCache()37 BlobCache::~BlobCache() {}
38 
put(const BlobCache::Key & key,angle::MemoryBuffer && value)39 void BlobCache::put(const BlobCache::Key &key, angle::MemoryBuffer &&value)
40 {
41     if (areBlobCacheFuncsSet())
42     {
43         // Store the result in the application's cache
44         mSetBlobFunc(key.data(), key.size(), value.data(), value.size());
45     }
46     else
47     {
48         populate(key, std::move(value), CacheSource::Memory);
49     }
50 }
51 
putApplication(const BlobCache::Key & key,const angle::MemoryBuffer & value)52 void BlobCache::putApplication(const BlobCache::Key &key, const angle::MemoryBuffer &value)
53 {
54     if (areBlobCacheFuncsSet())
55     {
56         mSetBlobFunc(key.data(), key.size(), value.data(), value.size());
57     }
58 }
59 
populate(const BlobCache::Key & key,angle::MemoryBuffer && value,CacheSource source)60 void BlobCache::populate(const BlobCache::Key &key, angle::MemoryBuffer &&value, CacheSource source)
61 {
62     CacheEntry newEntry;
63     newEntry.first  = std::move(value);
64     newEntry.second = source;
65 
66     // Cache it inside blob cache only if caching inside the application is not possible.
67     mBlobCache.put(key, std::move(newEntry), newEntry.first.size());
68 }
69 
get(angle::ScratchBuffer * scratchBuffer,const BlobCache::Key & key,BlobCache::Value * valueOut)70 bool BlobCache::get(angle::ScratchBuffer *scratchBuffer,
71                     const BlobCache::Key &key,
72                     BlobCache::Value *valueOut)
73 {
74     // Look into the application's cache, if there is such a cache
75     if (areBlobCacheFuncsSet())
76     {
77         EGLsizeiANDROID valueSize = mGetBlobFunc(key.data(), key.size(), nullptr, 0);
78         if (valueSize <= 0)
79         {
80             return false;
81         }
82 
83         angle::MemoryBuffer *scratchMemory;
84         bool result = scratchBuffer->get(valueSize, &scratchMemory);
85         if (!result)
86         {
87             ERR() << "Failed to allocate memory for binary blob";
88             return false;
89         }
90 
91         EGLsizeiANDROID originalValueSize = valueSize;
92         valueSize = mGetBlobFunc(key.data(), key.size(), scratchMemory->data(), valueSize);
93 
94         // Make sure the key/value pair still exists/is unchanged after the second call
95         // (modifications to the application cache by another thread are a possibility)
96         if (valueSize != originalValueSize)
97         {
98             // This warning serves to find issues with the application cache, none of which are
99             // currently known to be thread-safe.  If such a use ever arises, this WARN can be
100             // removed.
101             WARN() << "Binary blob no longer available in cache (removed by a thread?)";
102             return false;
103         }
104 
105         *valueOut = BlobCache::Value(scratchMemory->data(), scratchMemory->size());
106         return true;
107     }
108 
109     // Otherwise we are doing caching internally, so try to find it there
110     const CacheEntry *entry;
111     bool result = mBlobCache.get(key, &entry);
112 
113     if (result)
114     {
115         if (entry->second == CacheSource::Memory)
116         {
117             ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.ProgramCache.CacheResult", kCacheHitMemory,
118                                         kCacheResultMax);
119         }
120         else
121         {
122             ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.ProgramCache.CacheResult", kCacheHitDisk,
123                                         kCacheResultMax);
124         }
125 
126         *valueOut = BlobCache::Value(entry->first.data(), entry->first.size());
127     }
128     else
129     {
130         ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.ProgramCache.CacheResult", kCacheMiss,
131                                     kCacheResultMax);
132     }
133 
134     return result;
135 }
136 
getAt(size_t index,const BlobCache::Key ** keyOut,BlobCache::Value * valueOut)137 bool BlobCache::getAt(size_t index, const BlobCache::Key **keyOut, BlobCache::Value *valueOut)
138 {
139     const CacheEntry *valueBuf;
140     bool result = mBlobCache.getAt(index, keyOut, &valueBuf);
141     if (result)
142     {
143         *valueOut = BlobCache::Value(valueBuf->first.data(), valueBuf->first.size());
144     }
145     return result;
146 }
147 
remove(const BlobCache::Key & key)148 void BlobCache::remove(const BlobCache::Key &key)
149 {
150     mBlobCache.eraseByKey(key);
151 }
152 
setBlobCacheFuncs(EGLSetBlobFuncANDROID set,EGLGetBlobFuncANDROID get)153 void BlobCache::setBlobCacheFuncs(EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get)
154 {
155     mSetBlobFunc = set;
156     mGetBlobFunc = get;
157 }
158 
areBlobCacheFuncsSet() const159 bool BlobCache::areBlobCacheFuncsSet() const
160 {
161     // Either none or both of the callbacks should be set.
162     ASSERT((mSetBlobFunc != nullptr) == (mGetBlobFunc != nullptr));
163 
164     return mSetBlobFunc != nullptr && mGetBlobFunc != nullptr;
165 }
166 
167 }  // namespace egl
168