blob: c8d92e50cad7829b6b85bac0900aaf40abcd7499 [file] [log] [blame]
Jamie Madill4f86d052017-06-05 12:59:26 -04001//
2// Copyright 2017 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// MemoryProgramCache: Stores compiled and linked programs in memory so they don't
7// always have to be re-compiled. Can be used in conjunction with the platform
8// layer to warm up the cache from disk.
9
10#include "libANGLE/MemoryProgramCache.h"
11
12#include <GLSLANG/ShaderVars.h>
Jamie Madill32447362017-06-28 14:53:52 -040013#include <anglebase/sha1.h>
Jamie Madill4f86d052017-06-05 12:59:26 -040014
15#include "common/version.h"
16#include "libANGLE/BinaryStream.h"
17#include "libANGLE/Context.h"
18#include "libANGLE/Uniform.h"
Jamie Madill6c58b062017-08-01 13:44:25 -040019#include "libANGLE/histogram_macros.h"
Jamie Madill4f86d052017-06-05 12:59:26 -040020#include "libANGLE/renderer/ProgramImpl.h"
Jamie Madill360daee2017-06-29 10:36:19 -040021#include "platform/Platform.h"
Jamie Madill4f86d052017-06-05 12:59:26 -040022
23namespace gl
24{
25
26namespace
27{
Jamie Madill6c58b062017-08-01 13:44:25 -040028enum CacheResult
29{
30 kCacheMiss,
31 kCacheHitMemory,
32 kCacheHitDisk,
33 kCacheResultMax,
34};
35
Jamie Madill32447362017-06-28 14:53:52 -040036constexpr unsigned int kWarningLimit = 3;
Jamie Madill4f86d052017-06-05 12:59:26 -040037
38void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var)
39{
40 stream->writeInt(var.type);
41 stream->writeInt(var.precision);
42 stream->writeString(var.name);
43 stream->writeString(var.mappedName);
44 stream->writeInt(var.arraySize);
45 stream->writeInt(var.staticUse);
46 stream->writeString(var.structName);
47 ASSERT(var.fields.empty());
48}
49
50void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var)
51{
52 var->type = stream->readInt<GLenum>();
53 var->precision = stream->readInt<GLenum>();
54 var->name = stream->readString();
55 var->mappedName = stream->readString();
56 var->arraySize = stream->readInt<unsigned int>();
57 var->staticUse = stream->readBool();
58 var->structName = stream->readString();
59}
60
jchen10eaef1e52017-06-13 10:44:11 +080061void WriteShaderVariableBuffer(BinaryOutputStream *stream, const ShaderVariableBuffer &var)
62{
63 stream->writeInt(var.binding);
64 stream->writeInt(var.dataSize);
65
66 stream->writeInt(var.vertexStaticUse);
67 stream->writeInt(var.fragmentStaticUse);
68 stream->writeInt(var.computeStaticUse);
69
70 stream->writeInt(var.memberIndexes.size());
71 for (unsigned int memberCounterIndex : var.memberIndexes)
72 {
73 stream->writeInt(memberCounterIndex);
74 }
75}
76
77void LoadShaderVariableBuffer(BinaryInputStream *stream, ShaderVariableBuffer *var)
78{
79 var->binding = stream->readInt<int>();
80 var->dataSize = stream->readInt<unsigned int>();
81 var->vertexStaticUse = stream->readBool();
82 var->fragmentStaticUse = stream->readBool();
83 var->computeStaticUse = stream->readBool();
84
85 unsigned int numMembers = stream->readInt<unsigned int>();
86 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
87 {
88 var->memberIndexes.push_back(stream->readInt<unsigned int>());
89 }
90}
91
Jamie Madill32447362017-06-28 14:53:52 -040092class HashStream final : angle::NonCopyable
93{
94 public:
95 std::string str() { return mStringStream.str(); }
96
97 template <typename T>
98 HashStream &operator<<(T value)
99 {
100 mStringStream << value << kSeparator;
101 return *this;
102 }
103
104 private:
105 static constexpr char kSeparator = ':';
106 std::ostringstream mStringStream;
107};
108
109HashStream &operator<<(HashStream &stream, const Shader *shader)
110{
111 if (shader)
112 {
113 stream << shader->getSourceString().c_str() << shader->getSourceString().length()
114 << shader->getCompilerResourcesString().c_str();
115 }
116 return stream;
117}
118
119HashStream &operator<<(HashStream &stream, const Program::Bindings &bindings)
120{
121 for (const auto &binding : bindings)
122 {
123 stream << binding.first << binding.second;
124 }
125 return stream;
126}
127
128HashStream &operator<<(HashStream &stream, const std::vector<std::string> &strings)
129{
130 for (const auto &str : strings)
131 {
132 stream << str;
133 }
134 return stream;
135}
136
Jamie Madill4f86d052017-06-05 12:59:26 -0400137} // anonymous namespace
138
Jamie Madill32447362017-06-28 14:53:52 -0400139MemoryProgramCache::MemoryProgramCache(size_t maxCacheSizeBytes)
140 : mProgramBinaryCache(maxCacheSizeBytes), mIssuedWarnings(0)
141{
142}
143
144MemoryProgramCache::~MemoryProgramCache()
145{
146}
147
Jamie Madill4f86d052017-06-05 12:59:26 -0400148// static
149LinkResult MemoryProgramCache::Deserialize(const Context *context,
150 const Program *program,
151 ProgramState *state,
152 const uint8_t *binary,
153 size_t length,
154 InfoLog &infoLog)
155{
156 BinaryInputStream stream(binary, length);
157
158 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
159 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
160 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) !=
161 0)
162 {
163 infoLog << "Invalid program binary version.";
164 return false;
165 }
166
167 int majorVersion = stream.readInt<int>();
168 int minorVersion = stream.readInt<int>();
169 if (majorVersion != context->getClientMajorVersion() ||
170 minorVersion != context->getClientMinorVersion())
171 {
172 infoLog << "Cannot load program binaries across different ES context versions.";
173 return false;
174 }
175
176 state->mComputeShaderLocalSize[0] = stream.readInt<int>();
177 state->mComputeShaderLocalSize[1] = stream.readInt<int>();
178 state->mComputeShaderLocalSize[2] = stream.readInt<int>();
179
Martin Radev7cf61662017-07-26 17:10:53 +0300180 state->mNumViews = stream.readInt<int>();
181
Jamie Madill4f86d052017-06-05 12:59:26 -0400182 static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
183 "Too many vertex attribs for mask");
184 state->mActiveAttribLocationsMask = stream.readInt<unsigned long>();
185
186 unsigned int attribCount = stream.readInt<unsigned int>();
187 ASSERT(state->mAttributes.empty());
188 for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
189 {
190 sh::Attribute attrib;
191 LoadShaderVar(&stream, &attrib);
192 attrib.location = stream.readInt<int>();
193 state->mAttributes.push_back(attrib);
194 }
195
196 unsigned int uniformCount = stream.readInt<unsigned int>();
197 ASSERT(state->mUniforms.empty());
198 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
199 {
200 LinkedUniform uniform;
201 LoadShaderVar(&stream, &uniform);
202
jchen10eaef1e52017-06-13 10:44:11 +0800203 uniform.bufferIndex = stream.readInt<int>();
Jamie Madill4f86d052017-06-05 12:59:26 -0400204 uniform.blockInfo.offset = stream.readInt<int>();
205 uniform.blockInfo.arrayStride = stream.readInt<int>();
206 uniform.blockInfo.matrixStride = stream.readInt<int>();
207 uniform.blockInfo.isRowMajorMatrix = stream.readBool();
208
209 state->mUniforms.push_back(uniform);
210 }
211
212 const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
213 ASSERT(state->mUniformLocations.empty());
214 for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount;
215 uniformIndexIndex++)
216 {
217 VariableLocation variable;
218 stream.readString(&variable.name);
219 stream.readInt(&variable.element);
220 stream.readInt(&variable.index);
221 stream.readBool(&variable.used);
222 stream.readBool(&variable.ignored);
223
224 state->mUniformLocations.push_back(variable);
225 }
226
227 unsigned int uniformBlockCount = stream.readInt<unsigned int>();
228 ASSERT(state->mUniformBlocks.empty());
229 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
230 ++uniformBlockIndex)
231 {
232 UniformBlock uniformBlock;
233 stream.readString(&uniformBlock.name);
234 stream.readBool(&uniformBlock.isArray);
235 stream.readInt(&uniformBlock.arrayElement);
Jamie Madill4f86d052017-06-05 12:59:26 -0400236
jchen10eaef1e52017-06-13 10:44:11 +0800237 LoadShaderVariableBuffer(&stream, &uniformBlock);
Jamie Madill4f86d052017-06-05 12:59:26 -0400238
239 state->mUniformBlocks.push_back(uniformBlock);
Jamie Madill4f86d052017-06-05 12:59:26 -0400240
jchen107a20b972017-06-13 14:25:26 +0800241 state->mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlock.binding != 0);
Jamie Madill4f86d052017-06-05 12:59:26 -0400242 }
jchen10eaef1e52017-06-13 10:44:11 +0800243 unsigned int atomicCounterBufferCount = stream.readInt<unsigned int>();
244 ASSERT(state->mAtomicCounterBuffers.empty());
245 for (unsigned int bufferIndex = 0; bufferIndex < atomicCounterBufferCount; ++bufferIndex)
246 {
247 AtomicCounterBuffer atomicCounterBuffer;
248 LoadShaderVariableBuffer(&stream, &atomicCounterBuffer);
249
250 state->mAtomicCounterBuffers.push_back(atomicCounterBuffer);
251 }
Jamie Madill4f86d052017-06-05 12:59:26 -0400252
253 unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
Jamie Madillffe00c02017-06-27 16:26:55 -0400254
255 // Reject programs that use transform feedback varyings if the hardware cannot support them.
256 if (transformFeedbackVaryingCount > 0 &&
257 context->getWorkarounds().disableProgramCachingForTransformFeedback)
258 {
259 infoLog << "Current driver does not support transform feedback in binary programs.";
260 return false;
261 }
262
Jamie Madill4f86d052017-06-05 12:59:26 -0400263 ASSERT(state->mLinkedTransformFeedbackVaryings.empty());
264 for (unsigned int transformFeedbackVaryingIndex = 0;
265 transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
266 ++transformFeedbackVaryingIndex)
267 {
268 sh::Varying varying;
269 stream.readInt(&varying.arraySize);
270 stream.readInt(&varying.type);
271 stream.readString(&varying.name);
272
273 GLuint arrayIndex = stream.readInt<GLuint>();
274
275 state->mLinkedTransformFeedbackVaryings.emplace_back(varying, arrayIndex);
276 }
277
278 stream.readInt(&state->mTransformFeedbackBufferMode);
279
280 unsigned int outputCount = stream.readInt<unsigned int>();
281 ASSERT(state->mOutputVariables.empty());
282 for (unsigned int outputIndex = 0; outputIndex < outputCount; ++outputIndex)
283 {
284 sh::OutputVariable output;
285 LoadShaderVar(&stream, &output);
286 output.location = stream.readInt<int>();
287 state->mOutputVariables.push_back(output);
288 }
289
290 unsigned int outputVarCount = stream.readInt<unsigned int>();
291 for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
292 {
293 int locationIndex = stream.readInt<int>();
294 VariableLocation locationData;
295 stream.readInt(&locationData.element);
296 stream.readInt(&locationData.index);
297 stream.readString(&locationData.name);
298 state->mOutputLocations[locationIndex] = locationData;
299 }
300
301 unsigned int outputTypeCount = stream.readInt<unsigned int>();
302 for (unsigned int outputIndex = 0; outputIndex < outputTypeCount; ++outputIndex)
303 {
304 state->mOutputVariableTypes.push_back(stream.readInt<GLenum>());
305 }
306 static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS < 8 * sizeof(uint32_t),
307 "All bits of DrawBufferMask can be contained in an uint32_t");
308 state->mActiveOutputVariables = stream.readInt<uint32_t>();
309
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800310 unsigned int samplerRangeLow = stream.readInt<unsigned int>();
311 unsigned int samplerRangeHigh = stream.readInt<unsigned int>();
312 state->mSamplerUniformRange = RangeUI(samplerRangeLow, samplerRangeHigh);
Jamie Madill4f86d052017-06-05 12:59:26 -0400313 unsigned int samplerCount = stream.readInt<unsigned int>();
314 for (unsigned int samplerIndex = 0; samplerIndex < samplerCount; ++samplerIndex)
315 {
316 GLenum textureType = stream.readInt<GLenum>();
317 size_t bindingCount = stream.readInt<size_t>();
318 state->mSamplerBindings.emplace_back(SamplerBinding(textureType, bindingCount));
319 }
320
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800321 unsigned int imageRangeLow = stream.readInt<unsigned int>();
322 unsigned int imageRangeHigh = stream.readInt<unsigned int>();
323 state->mImageUniformRange = RangeUI(imageRangeLow, imageRangeHigh);
Xinghua Cao0328b572017-06-26 15:51:36 +0800324 unsigned int imageBindingCount = stream.readInt<unsigned int>();
325 for (unsigned int imageIndex = 0; imageIndex < imageBindingCount; ++imageIndex)
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800326 {
Xinghua Cao0328b572017-06-26 15:51:36 +0800327 unsigned int elementCount = stream.readInt<unsigned int>();
328 ImageBinding imageBinding(elementCount);
329 for (unsigned int i = 0; i < elementCount; ++i)
330 {
331 imageBinding.boundImageUnits[i] = stream.readInt<unsigned int>();
332 }
333 state->mImageBindings.emplace_back(imageBinding);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800334 }
335
jchen10eaef1e52017-06-13 10:44:11 +0800336 unsigned int atomicCounterRangeLow = stream.readInt<unsigned int>();
337 unsigned int atomicCounterRangeHigh = stream.readInt<unsigned int>();
338 state->mAtomicCounterUniformRange = RangeUI(atomicCounterRangeLow, atomicCounterRangeHigh);
339
Jamie Madill4f86d052017-06-05 12:59:26 -0400340 return program->getImplementation()->load(context, infoLog, &stream);
341}
342
343// static
344void MemoryProgramCache::Serialize(const Context *context,
345 const gl::Program *program,
346 angle::MemoryBuffer *binaryOut)
347{
348 BinaryOutputStream stream;
349
350 stream.writeBytes(reinterpret_cast<const unsigned char *>(ANGLE_COMMIT_HASH),
351 ANGLE_COMMIT_HASH_SIZE);
352
353 // nullptr context is supported when computing binary length.
354 if (context)
355 {
356 stream.writeInt(context->getClientVersion().major);
357 stream.writeInt(context->getClientVersion().minor);
358 }
359 else
360 {
361 stream.writeInt(2);
362 stream.writeInt(0);
363 }
364
365 const auto &state = program->getState();
366
367 const auto &computeLocalSize = state.getComputeShaderLocalSize();
368
369 stream.writeInt(computeLocalSize[0]);
370 stream.writeInt(computeLocalSize[1]);
371 stream.writeInt(computeLocalSize[2]);
372
Martin Radev7cf61662017-07-26 17:10:53 +0300373 stream.writeInt(state.mNumViews);
374
Jamie Madill4f86d052017-06-05 12:59:26 -0400375 stream.writeInt(state.getActiveAttribLocationsMask().to_ulong());
376
377 stream.writeInt(state.getAttributes().size());
378 for (const sh::Attribute &attrib : state.getAttributes())
379 {
380 WriteShaderVar(&stream, attrib);
381 stream.writeInt(attrib.location);
382 }
383
384 stream.writeInt(state.getUniforms().size());
385 for (const LinkedUniform &uniform : state.getUniforms())
386 {
387 WriteShaderVar(&stream, uniform);
388
389 // FIXME: referenced
390
jchen10eaef1e52017-06-13 10:44:11 +0800391 stream.writeInt(uniform.bufferIndex);
Jamie Madill4f86d052017-06-05 12:59:26 -0400392 stream.writeInt(uniform.blockInfo.offset);
393 stream.writeInt(uniform.blockInfo.arrayStride);
394 stream.writeInt(uniform.blockInfo.matrixStride);
395 stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
396 }
397
398 stream.writeInt(state.getUniformLocations().size());
399 for (const auto &variable : state.getUniformLocations())
400 {
401 stream.writeString(variable.name);
402 stream.writeInt(variable.element);
403 stream.writeInt(variable.index);
404 stream.writeInt(variable.used);
405 stream.writeInt(variable.ignored);
406 }
407
408 stream.writeInt(state.getUniformBlocks().size());
409 for (const UniformBlock &uniformBlock : state.getUniformBlocks())
410 {
411 stream.writeString(uniformBlock.name);
412 stream.writeInt(uniformBlock.isArray);
413 stream.writeInt(uniformBlock.arrayElement);
Jamie Madill4f86d052017-06-05 12:59:26 -0400414
jchen10eaef1e52017-06-13 10:44:11 +0800415 WriteShaderVariableBuffer(&stream, uniformBlock);
416 }
Jamie Madill4f86d052017-06-05 12:59:26 -0400417
jchen10eaef1e52017-06-13 10:44:11 +0800418 stream.writeInt(state.mAtomicCounterBuffers.size());
419 for (const auto &atomicCounterBuffer : state.mAtomicCounterBuffers)
420 {
421 WriteShaderVariableBuffer(&stream, atomicCounterBuffer);
Jamie Madill4f86d052017-06-05 12:59:26 -0400422 }
423
Jamie Madillffe00c02017-06-27 16:26:55 -0400424 // Warn the app layer if saving a binary with unsupported transform feedback.
425 if (!state.getLinkedTransformFeedbackVaryings().empty() &&
426 context->getWorkarounds().disableProgramCachingForTransformFeedback)
427 {
428 WARN() << "Saving program binary with transform feedback, which is not supported on this "
429 "driver.";
430 }
431
Jamie Madill4f86d052017-06-05 12:59:26 -0400432 stream.writeInt(state.getLinkedTransformFeedbackVaryings().size());
433 for (const auto &var : state.getLinkedTransformFeedbackVaryings())
434 {
435 stream.writeInt(var.arraySize);
436 stream.writeInt(var.type);
437 stream.writeString(var.name);
438
439 stream.writeIntOrNegOne(var.arrayIndex);
440 }
441
442 stream.writeInt(state.getTransformFeedbackBufferMode());
443
444 stream.writeInt(state.getOutputVariables().size());
445 for (const sh::OutputVariable &output : state.getOutputVariables())
446 {
447 WriteShaderVar(&stream, output);
448 stream.writeInt(output.location);
449 }
450
451 stream.writeInt(state.getOutputLocations().size());
452 for (const auto &outputPair : state.getOutputLocations())
453 {
454 stream.writeInt(outputPair.first);
455 stream.writeIntOrNegOne(outputPair.second.element);
456 stream.writeInt(outputPair.second.index);
457 stream.writeString(outputPair.second.name);
458 }
459
460 stream.writeInt(state.mOutputVariableTypes.size());
461 for (const auto &outputVariableType : state.mOutputVariableTypes)
462 {
463 stream.writeInt(outputVariableType);
464 }
465
466 static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS < 8 * sizeof(uint32_t),
467 "All bits of DrawBufferMask can be contained in an uint32_t");
468 stream.writeInt(static_cast<uint32_t>(state.mActiveOutputVariables.to_ulong()));
469
470 stream.writeInt(state.getSamplerUniformRange().low());
471 stream.writeInt(state.getSamplerUniformRange().high());
472
473 stream.writeInt(state.getSamplerBindings().size());
474 for (const auto &samplerBinding : state.getSamplerBindings())
475 {
476 stream.writeInt(samplerBinding.textureType);
477 stream.writeInt(samplerBinding.boundTextureUnits.size());
478 }
479
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800480 stream.writeInt(state.getImageUniformRange().low());
481 stream.writeInt(state.getImageUniformRange().high());
482
483 stream.writeInt(state.getImageBindings().size());
484 for (const auto &imageBinding : state.getImageBindings())
485 {
Xinghua Cao0328b572017-06-26 15:51:36 +0800486 stream.writeInt(imageBinding.boundImageUnits.size());
487 for (size_t i = 0; i < imageBinding.boundImageUnits.size(); ++i)
488 {
489 stream.writeInt(imageBinding.boundImageUnits[i]);
490 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800491 }
492
jchen10eaef1e52017-06-13 10:44:11 +0800493 stream.writeInt(state.getAtomicCounterUniformRange().low());
494 stream.writeInt(state.getAtomicCounterUniformRange().high());
495
Jamie Madill27a60632017-06-30 15:12:01 -0400496 program->getImplementation()->save(context, &stream);
Jamie Madill4f86d052017-06-05 12:59:26 -0400497
498 ASSERT(binaryOut);
499 binaryOut->resize(stream.length());
500 memcpy(binaryOut->data(), stream.data(), stream.length());
501}
502
Jamie Madill32447362017-06-28 14:53:52 -0400503// static
504void MemoryProgramCache::ComputeHash(const Context *context,
505 const Program *program,
506 ProgramHash *hashOut)
507{
508 auto vertexShader = program->getAttachedVertexShader();
509 auto fragmentShader = program->getAttachedFragmentShader();
510 auto computeShader = program->getAttachedComputeShader();
511
512 // Compute the program hash. Start with the shader hashes and resource strings.
513 HashStream hashStream;
514 hashStream << vertexShader << fragmentShader << computeShader;
515
516 // Add some ANGLE metadata and Context properties, such as version and back-end.
517 hashStream << ANGLE_COMMIT_HASH << context->getClientMajorVersion()
518 << context->getClientMinorVersion() << context->getString(GL_RENDERER);
519
520 // Hash pre-link program properties.
521 hashStream << program->getAttributeBindings() << program->getUniformLocationBindings()
522 << program->getFragmentInputBindings()
523 << program->getState().getTransformFeedbackVaryingNames()
524 << program->getState().getTransformFeedbackBufferMode();
525
526 // Call the secure SHA hashing function.
527 const std::string &programKey = hashStream.str();
528 angle::base::SHA1HashBytes(reinterpret_cast<const unsigned char *>(programKey.c_str()),
529 programKey.length(), hashOut->data());
530}
531
532LinkResult MemoryProgramCache::getProgram(const Context *context,
533 const Program *program,
534 ProgramState *state,
535 ProgramHash *hashOut)
536{
537 ComputeHash(context, program, hashOut);
538 const angle::MemoryBuffer *binaryProgram = nullptr;
539 LinkResult result(false);
540 if (get(*hashOut, &binaryProgram))
541 {
542 InfoLog infoLog;
543 ANGLE_TRY_RESULT(Deserialize(context, program, state, binaryProgram->data(),
544 binaryProgram->size(), infoLog),
545 result);
Jamie Madill6c58b062017-08-01 13:44:25 -0400546 ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ProgramCache.LoadBinarySuccess", result.getResult());
Jamie Madill32447362017-06-28 14:53:52 -0400547 if (!result.getResult())
548 {
549 // Cache load failed, evict.
550 if (mIssuedWarnings++ < kWarningLimit)
551 {
552 WARN() << "Failed to load binary from cache: " << infoLog.str();
553
554 if (mIssuedWarnings == kWarningLimit)
555 {
556 WARN() << "Reaching warning limit for cache load failures, silencing "
557 "subsequent warnings.";
558 }
559 }
560 remove(*hashOut);
561 }
562 }
563 return result;
564}
565
566bool MemoryProgramCache::get(const ProgramHash &programHash, const angle::MemoryBuffer **programOut)
567{
Jamie Madill6c58b062017-08-01 13:44:25 -0400568 const CacheEntry *entry = nullptr;
569 if (!mProgramBinaryCache.get(programHash, &entry))
570 {
571 ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.ProgramCache.CacheResult", kCacheMiss,
572 kCacheResultMax);
573 return false;
574 }
575
576 if (entry->second == CacheSource::PutProgram)
577 {
578 ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.ProgramCache.CacheResult", kCacheHitMemory,
579 kCacheResultMax);
580 }
581 else
582 {
583 ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.ProgramCache.CacheResult", kCacheHitDisk,
584 kCacheResultMax);
585 }
586
587 *programOut = &entry->first;
588 return true;
Jamie Madill32447362017-06-28 14:53:52 -0400589}
590
Jamie Madillc43be722017-07-13 16:22:14 -0400591bool MemoryProgramCache::getAt(size_t index,
592 ProgramHash *hashOut,
593 const angle::MemoryBuffer **programOut)
594{
Jamie Madill6c58b062017-08-01 13:44:25 -0400595 const CacheEntry *entry = nullptr;
596 if (!mProgramBinaryCache.getAt(index, hashOut, &entry))
597 {
598 return false;
599 }
600
601 *programOut = &entry->first;
602 return true;
Jamie Madillc43be722017-07-13 16:22:14 -0400603}
604
Jamie Madill32447362017-06-28 14:53:52 -0400605void MemoryProgramCache::remove(const ProgramHash &programHash)
606{
607 bool result = mProgramBinaryCache.eraseByKey(programHash);
608 ASSERT(result);
609}
610
Jamie Madill6c58b062017-08-01 13:44:25 -0400611void MemoryProgramCache::putProgram(const ProgramHash &programHash,
612 const Context *context,
613 const Program *program)
Jamie Madill32447362017-06-28 14:53:52 -0400614{
Jamie Madill6c58b062017-08-01 13:44:25 -0400615 CacheEntry newEntry;
616 Serialize(context, program, &newEntry.first);
617 newEntry.second = CacheSource::PutProgram;
618
619 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramBinarySizeBytes",
620 static_cast<int>(newEntry.first.size()));
621
622 const CacheEntry *result =
623 mProgramBinaryCache.put(programHash, std::move(newEntry), newEntry.first.size());
Jamie Madill360daee2017-06-29 10:36:19 -0400624 if (!result)
Jamie Madill32447362017-06-28 14:53:52 -0400625 {
626 ERR() << "Failed to store binary program in memory cache, program is too large.";
627 }
Jamie Madill360daee2017-06-29 10:36:19 -0400628 else
629 {
630 auto *platform = ANGLEPlatformCurrent();
Jamie Madill6c58b062017-08-01 13:44:25 -0400631 platform->cacheProgram(platform, programHash, result->first.size(), result->first.data());
Jamie Madill360daee2017-06-29 10:36:19 -0400632 }
Jamie Madill32447362017-06-28 14:53:52 -0400633}
634
Jamie Madill4c19a8a2017-07-24 11:46:06 -0400635void MemoryProgramCache::updateProgram(const Context *context, const Program *program)
636{
637 gl::ProgramHash programHash;
638 ComputeHash(context, program, &programHash);
639 putProgram(programHash, context, program);
640}
641
Jamie Madillc43be722017-07-13 16:22:14 -0400642void MemoryProgramCache::putBinary(const ProgramHash &programHash,
Jamie Madill32447362017-06-28 14:53:52 -0400643 const uint8_t *binary,
644 size_t length)
645{
646 // Copy the binary.
Jamie Madill6c58b062017-08-01 13:44:25 -0400647 CacheEntry newEntry;
648 newEntry.first.resize(length);
649 memcpy(newEntry.first.data(), binary, length);
650 newEntry.second = CacheSource::PutBinary;
Jamie Madill32447362017-06-28 14:53:52 -0400651
Jamie Madill32447362017-06-28 14:53:52 -0400652 // Store the binary.
Jamie Madill6c58b062017-08-01 13:44:25 -0400653 const CacheEntry *result = mProgramBinaryCache.put(programHash, std::move(newEntry), length);
Jamie Madillc43be722017-07-13 16:22:14 -0400654 if (!result)
655 {
656 ERR() << "Failed to store binary program in memory cache, program is too large.";
657 }
Jamie Madill32447362017-06-28 14:53:52 -0400658}
659
660void MemoryProgramCache::clear()
661{
662 mProgramBinaryCache.clear();
663 mIssuedWarnings = 0;
664}
665
Jamie Madillc43be722017-07-13 16:22:14 -0400666void MemoryProgramCache::resize(size_t maxCacheSizeBytes)
667{
668 mProgramBinaryCache.resize(maxCacheSizeBytes);
669}
670
671size_t MemoryProgramCache::entryCount() const
672{
673 return mProgramBinaryCache.entryCount();
674}
675
676size_t MemoryProgramCache::trim(size_t limit)
677{
678 return mProgramBinaryCache.shrinkToSize(limit);
679}
680
681size_t MemoryProgramCache::size() const
682{
683 return mProgramBinaryCache.size();
684}
685
686size_t MemoryProgramCache::maxSize() const
687{
688 return mProgramBinaryCache.maxSize();
689}
690
Jamie Madill4f86d052017-06-05 12:59:26 -0400691} // namespace gl