Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/angle
Path: blob/main_old/src/libANGLE/BlobCache.cpp
1693 views
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 "libANGLE/Context.h"
13
#include "libANGLE/Display.h"
14
#include "libANGLE/histogram_macros.h"
15
#include "platform/PlatformMethods.h"
16
17
#define USE_SYSTEM_ZLIB
18
#include "compression_utils_portable.h"
19
20
namespace egl
21
{
22
23
namespace
24
{
25
enum CacheResult
26
{
27
kCacheMiss,
28
kCacheHitMemory,
29
kCacheHitDisk,
30
kCacheResultMax,
31
};
32
33
} // anonymous namespace
34
35
// In oder to store more cache in blob cache, compress cacheData to compressedData
36
// before being stored.
37
bool CompressBlobCacheData(const size_t cacheSize,
38
const uint8_t *cacheData,
39
angle::MemoryBuffer *compressedData)
40
{
41
uLong uncompressedSize = static_cast<uLong>(cacheSize);
42
uLong expectedCompressedSize = zlib_internal::GzipExpectedCompressedSize(uncompressedSize);
43
44
// Allocate memory.
45
if (!compressedData->resize(expectedCompressedSize))
46
{
47
ERR() << "Failed to allocate memory for compression";
48
return false;
49
}
50
51
int zResult = zlib_internal::GzipCompressHelper(compressedData->data(), &expectedCompressedSize,
52
cacheData, uncompressedSize, nullptr, nullptr);
53
54
if (zResult != Z_OK)
55
{
56
ERR() << "Failed to compress cache data: " << zResult;
57
return false;
58
}
59
60
// Resize it to expected size.
61
if (!compressedData->resize(expectedCompressedSize))
62
{
63
return false;
64
}
65
66
return true;
67
}
68
69
bool DecompressBlobCacheData(const uint8_t *compressedData,
70
const size_t compressedSize,
71
angle::MemoryBuffer *uncompressedData)
72
{
73
// Call zlib function to decompress.
74
uint32_t uncompressedSize =
75
zlib_internal::GetGzipUncompressedSize(compressedData, compressedSize);
76
77
// Allocate enough memory.
78
if (!uncompressedData->resize(uncompressedSize))
79
{
80
ERR() << "Failed to allocate memory for decompression";
81
return false;
82
}
83
84
uLong destLen = uncompressedSize;
85
int zResult = zlib_internal::GzipUncompressHelper(
86
uncompressedData->data(), &destLen, compressedData, static_cast<uLong>(compressedSize));
87
88
if (zResult != Z_OK)
89
{
90
ERR() << "Failed to decompress data: " << zResult << "\n";
91
return false;
92
}
93
94
// Resize it to expected size.
95
if (!uncompressedData->resize(destLen))
96
{
97
return false;
98
}
99
100
return true;
101
}
102
103
BlobCache::BlobCache(size_t maxCacheSizeBytes)
104
: mBlobCache(maxCacheSizeBytes), mSetBlobFunc(nullptr), mGetBlobFunc(nullptr)
105
{}
106
107
BlobCache::~BlobCache() {}
108
109
void BlobCache::put(const BlobCache::Key &key, angle::MemoryBuffer &&value)
110
{
111
if (areBlobCacheFuncsSet())
112
{
113
// Store the result in the application's cache
114
mSetBlobFunc(key.data(), key.size(), value.data(), value.size());
115
}
116
else
117
{
118
populate(key, std::move(value), CacheSource::Memory);
119
}
120
}
121
122
void BlobCache::putApplication(const BlobCache::Key &key, const angle::MemoryBuffer &value)
123
{
124
std::lock_guard<std::mutex> lock(mBlobCacheMutex);
125
if (areBlobCacheFuncsSet())
126
{
127
mSetBlobFunc(key.data(), key.size(), value.data(), value.size());
128
}
129
}
130
131
void BlobCache::populate(const BlobCache::Key &key, angle::MemoryBuffer &&value, CacheSource source)
132
{
133
CacheEntry newEntry;
134
newEntry.first = std::move(value);
135
newEntry.second = source;
136
137
// Cache it inside blob cache only if caching inside the application is not possible.
138
mBlobCache.put(key, std::move(newEntry), newEntry.first.size());
139
}
140
141
bool BlobCache::get(angle::ScratchBuffer *scratchBuffer,
142
const BlobCache::Key &key,
143
BlobCache::Value *valueOut,
144
size_t *bufferSizeOut)
145
{
146
// Look into the application's cache, if there is such a cache
147
if (areBlobCacheFuncsSet())
148
{
149
EGLsizeiANDROID valueSize = mGetBlobFunc(key.data(), key.size(), nullptr, 0);
150
if (valueSize <= 0)
151
{
152
return false;
153
}
154
155
angle::MemoryBuffer *scratchMemory;
156
bool result = scratchBuffer->get(valueSize, &scratchMemory);
157
if (!result)
158
{
159
ERR() << "Failed to allocate memory for binary blob";
160
return false;
161
}
162
163
EGLsizeiANDROID originalValueSize = valueSize;
164
valueSize = mGetBlobFunc(key.data(), key.size(), scratchMemory->data(), valueSize);
165
166
// Make sure the key/value pair still exists/is unchanged after the second call
167
// (modifications to the application cache by another thread are a possibility)
168
if (valueSize != originalValueSize)
169
{
170
// This warning serves to find issues with the application cache, none of which are
171
// currently known to be thread-safe. If such a use ever arises, this WARN can be
172
// removed.
173
WARN() << "Binary blob no longer available in cache (removed by a thread?)";
174
return false;
175
}
176
177
*valueOut = BlobCache::Value(scratchMemory->data(), scratchMemory->size());
178
*bufferSizeOut = valueSize;
179
return true;
180
}
181
182
// Otherwise we are doing caching internally, so try to find it there
183
const CacheEntry *entry;
184
bool result = mBlobCache.get(key, &entry);
185
186
if (result)
187
{
188
if (entry->second == CacheSource::Memory)
189
{
190
ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.ProgramCache.CacheResult", kCacheHitMemory,
191
kCacheResultMax);
192
}
193
else
194
{
195
ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.ProgramCache.CacheResult", kCacheHitDisk,
196
kCacheResultMax);
197
}
198
199
*valueOut = BlobCache::Value(entry->first.data(), entry->first.size());
200
*bufferSizeOut = entry->first.size();
201
}
202
else
203
{
204
ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.ProgramCache.CacheResult", kCacheMiss,
205
kCacheResultMax);
206
}
207
208
return result;
209
}
210
211
bool BlobCache::getAt(size_t index, const BlobCache::Key **keyOut, BlobCache::Value *valueOut)
212
{
213
const CacheEntry *valueBuf;
214
bool result = mBlobCache.getAt(index, keyOut, &valueBuf);
215
if (result)
216
{
217
*valueOut = BlobCache::Value(valueBuf->first.data(), valueBuf->first.size());
218
}
219
return result;
220
}
221
222
void BlobCache::remove(const BlobCache::Key &key)
223
{
224
mBlobCache.eraseByKey(key);
225
}
226
227
void BlobCache::setBlobCacheFuncs(EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get)
228
{
229
mSetBlobFunc = set;
230
mGetBlobFunc = get;
231
}
232
233
bool BlobCache::areBlobCacheFuncsSet() const
234
{
235
// Either none or both of the callbacks should be set.
236
ASSERT((mSetBlobFunc != nullptr) == (mGetBlobFunc != nullptr));
237
238
return mSetBlobFunc != nullptr && mGetBlobFunc != nullptr;
239
}
240
241
} // namespace egl
242
243