blob: e34a18a328b6e25d8a98c70fc054e929490f6be2 [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"
19#include "libANGLE/renderer/ProgramImpl.h"
Jamie Madill360daee2017-06-29 10:36:19 -040020#include "platform/Platform.h"
Jamie Madill4f86d052017-06-05 12:59:26 -040021
22namespace gl
23{
24
25namespace
26{
Jamie Madill32447362017-06-28 14:53:52 -040027constexpr unsigned int kWarningLimit = 3;
Jamie Madill4f86d052017-06-05 12:59:26 -040028
29void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var)
30{
31 stream->writeInt(var.type);
32 stream->writeInt(var.precision);
33 stream->writeString(var.name);
34 stream->writeString(var.mappedName);
35 stream->writeInt(var.arraySize);
36 stream->writeInt(var.staticUse);
37 stream->writeString(var.structName);
38 ASSERT(var.fields.empty());
39}
40
41void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var)
42{
43 var->type = stream->readInt<GLenum>();
44 var->precision = stream->readInt<GLenum>();
45 var->name = stream->readString();
46 var->mappedName = stream->readString();
47 var->arraySize = stream->readInt<unsigned int>();
48 var->staticUse = stream->readBool();
49 var->structName = stream->readString();
50}
51
jchen10eaef1e52017-06-13 10:44:11 +080052void WriteShaderVariableBuffer(BinaryOutputStream *stream, const ShaderVariableBuffer &var)
53{
54 stream->writeInt(var.binding);
55 stream->writeInt(var.dataSize);
56
57 stream->writeInt(var.vertexStaticUse);
58 stream->writeInt(var.fragmentStaticUse);
59 stream->writeInt(var.computeStaticUse);
60
61 stream->writeInt(var.memberIndexes.size());
62 for (unsigned int memberCounterIndex : var.memberIndexes)
63 {
64 stream->writeInt(memberCounterIndex);
65 }
66}
67
68void LoadShaderVariableBuffer(BinaryInputStream *stream, ShaderVariableBuffer *var)
69{
70 var->binding = stream->readInt<int>();
71 var->dataSize = stream->readInt<unsigned int>();
72 var->vertexStaticUse = stream->readBool();
73 var->fragmentStaticUse = stream->readBool();
74 var->computeStaticUse = stream->readBool();
75
76 unsigned int numMembers = stream->readInt<unsigned int>();
77 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
78 {
79 var->memberIndexes.push_back(stream->readInt<unsigned int>());
80 }
81}
82
Jamie Madill32447362017-06-28 14:53:52 -040083class HashStream final : angle::NonCopyable
84{
85 public:
86 std::string str() { return mStringStream.str(); }
87
88 template <typename T>
89 HashStream &operator<<(T value)
90 {
91 mStringStream << value << kSeparator;
92 return *this;
93 }
94
95 private:
96 static constexpr char kSeparator = ':';
97 std::ostringstream mStringStream;
98};
99
100HashStream &operator<<(HashStream &stream, const Shader *shader)
101{
102 if (shader)
103 {
104 stream << shader->getSourceString().c_str() << shader->getSourceString().length()
105 << shader->getCompilerResourcesString().c_str();
106 }
107 return stream;
108}
109
110HashStream &operator<<(HashStream &stream, const Program::Bindings &bindings)
111{
112 for (const auto &binding : bindings)
113 {
114 stream << binding.first << binding.second;
115 }
116 return stream;
117}
118
119HashStream &operator<<(HashStream &stream, const std::vector<std::string> &strings)
120{
121 for (const auto &str : strings)
122 {
123 stream << str;
124 }
125 return stream;
126}
127
Jamie Madill4f86d052017-06-05 12:59:26 -0400128} // anonymous namespace
129
Jamie Madill32447362017-06-28 14:53:52 -0400130MemoryProgramCache::MemoryProgramCache(size_t maxCacheSizeBytes)
131 : mProgramBinaryCache(maxCacheSizeBytes), mIssuedWarnings(0)
132{
133}
134
135MemoryProgramCache::~MemoryProgramCache()
136{
137}
138
Jamie Madill4f86d052017-06-05 12:59:26 -0400139// static
140LinkResult MemoryProgramCache::Deserialize(const Context *context,
141 const Program *program,
142 ProgramState *state,
143 const uint8_t *binary,
144 size_t length,
145 InfoLog &infoLog)
146{
147 BinaryInputStream stream(binary, length);
148
149 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
150 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
151 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) !=
152 0)
153 {
154 infoLog << "Invalid program binary version.";
155 return false;
156 }
157
158 int majorVersion = stream.readInt<int>();
159 int minorVersion = stream.readInt<int>();
160 if (majorVersion != context->getClientMajorVersion() ||
161 minorVersion != context->getClientMinorVersion())
162 {
163 infoLog << "Cannot load program binaries across different ES context versions.";
164 return false;
165 }
166
167 state->mComputeShaderLocalSize[0] = stream.readInt<int>();
168 state->mComputeShaderLocalSize[1] = stream.readInt<int>();
169 state->mComputeShaderLocalSize[2] = stream.readInt<int>();
170
171 static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
172 "Too many vertex attribs for mask");
173 state->mActiveAttribLocationsMask = stream.readInt<unsigned long>();
174
175 unsigned int attribCount = stream.readInt<unsigned int>();
176 ASSERT(state->mAttributes.empty());
177 for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
178 {
179 sh::Attribute attrib;
180 LoadShaderVar(&stream, &attrib);
181 attrib.location = stream.readInt<int>();
182 state->mAttributes.push_back(attrib);
183 }
184
185 unsigned int uniformCount = stream.readInt<unsigned int>();
186 ASSERT(state->mUniforms.empty());
187 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
188 {
189 LinkedUniform uniform;
190 LoadShaderVar(&stream, &uniform);
191
jchen10eaef1e52017-06-13 10:44:11 +0800192 uniform.bufferIndex = stream.readInt<int>();
Jamie Madill4f86d052017-06-05 12:59:26 -0400193 uniform.blockInfo.offset = stream.readInt<int>();
194 uniform.blockInfo.arrayStride = stream.readInt<int>();
195 uniform.blockInfo.matrixStride = stream.readInt<int>();
196 uniform.blockInfo.isRowMajorMatrix = stream.readBool();
197
198 state->mUniforms.push_back(uniform);
199 }
200
201 const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
202 ASSERT(state->mUniformLocations.empty());
203 for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount;
204 uniformIndexIndex++)
205 {
206 VariableLocation variable;
207 stream.readString(&variable.name);
208 stream.readInt(&variable.element);
209 stream.readInt(&variable.index);
210 stream.readBool(&variable.used);
211 stream.readBool(&variable.ignored);
212
213 state->mUniformLocations.push_back(variable);
214 }
215
216 unsigned int uniformBlockCount = stream.readInt<unsigned int>();
217 ASSERT(state->mUniformBlocks.empty());
218 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
219 ++uniformBlockIndex)
220 {
221 UniformBlock uniformBlock;
222 stream.readString(&uniformBlock.name);
223 stream.readBool(&uniformBlock.isArray);
224 stream.readInt(&uniformBlock.arrayElement);
Jamie Madill4f86d052017-06-05 12:59:26 -0400225
jchen10eaef1e52017-06-13 10:44:11 +0800226 LoadShaderVariableBuffer(&stream, &uniformBlock);
Jamie Madill4f86d052017-06-05 12:59:26 -0400227
228 state->mUniformBlocks.push_back(uniformBlock);
Jamie Madill4f86d052017-06-05 12:59:26 -0400229
jchen107a20b972017-06-13 14:25:26 +0800230 state->mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlock.binding != 0);
Jamie Madill4f86d052017-06-05 12:59:26 -0400231 }
jchen10eaef1e52017-06-13 10:44:11 +0800232 unsigned int atomicCounterBufferCount = stream.readInt<unsigned int>();
233 ASSERT(state->mAtomicCounterBuffers.empty());
234 for (unsigned int bufferIndex = 0; bufferIndex < atomicCounterBufferCount; ++bufferIndex)
235 {
236 AtomicCounterBuffer atomicCounterBuffer;
237 LoadShaderVariableBuffer(&stream, &atomicCounterBuffer);
238
239 state->mAtomicCounterBuffers.push_back(atomicCounterBuffer);
240 }
Jamie Madill4f86d052017-06-05 12:59:26 -0400241
242 unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
Jamie Madillffe00c02017-06-27 16:26:55 -0400243
244 // Reject programs that use transform feedback varyings if the hardware cannot support them.
245 if (transformFeedbackVaryingCount > 0 &&
246 context->getWorkarounds().disableProgramCachingForTransformFeedback)
247 {
248 infoLog << "Current driver does not support transform feedback in binary programs.";
249 return false;
250 }
251
Jamie Madill4f86d052017-06-05 12:59:26 -0400252 ASSERT(state->mLinkedTransformFeedbackVaryings.empty());
253 for (unsigned int transformFeedbackVaryingIndex = 0;
254 transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
255 ++transformFeedbackVaryingIndex)
256 {
257 sh::Varying varying;
258 stream.readInt(&varying.arraySize);
259 stream.readInt(&varying.type);
260 stream.readString(&varying.name);
261
262 GLuint arrayIndex = stream.readInt<GLuint>();
263
264 state->mLinkedTransformFeedbackVaryings.emplace_back(varying, arrayIndex);
265 }
266
267 stream.readInt(&state->mTransformFeedbackBufferMode);
268
269 unsigned int outputCount = stream.readInt<unsigned int>();
270 ASSERT(state->mOutputVariables.empty());
271 for (unsigned int outputIndex = 0; outputIndex < outputCount; ++outputIndex)
272 {
273 sh::OutputVariable output;
274 LoadShaderVar(&stream, &output);
275 output.location = stream.readInt<int>();
276 state->mOutputVariables.push_back(output);
277 }
278
279 unsigned int outputVarCount = stream.readInt<unsigned int>();
280 for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
281 {
282 int locationIndex = stream.readInt<int>();
283 VariableLocation locationData;
284 stream.readInt(&locationData.element);
285 stream.readInt(&locationData.index);
286 stream.readString(&locationData.name);
287 state->mOutputLocations[locationIndex] = locationData;
288 }
289
290 unsigned int outputTypeCount = stream.readInt<unsigned int>();
291 for (unsigned int outputIndex = 0; outputIndex < outputTypeCount; ++outputIndex)
292 {
293 state->mOutputVariableTypes.push_back(stream.readInt<GLenum>());
294 }
295 static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS < 8 * sizeof(uint32_t),
296 "All bits of DrawBufferMask can be contained in an uint32_t");
297 state->mActiveOutputVariables = stream.readInt<uint32_t>();
298
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800299 unsigned int samplerRangeLow = stream.readInt<unsigned int>();
300 unsigned int samplerRangeHigh = stream.readInt<unsigned int>();
301 state->mSamplerUniformRange = RangeUI(samplerRangeLow, samplerRangeHigh);
Jamie Madill4f86d052017-06-05 12:59:26 -0400302 unsigned int samplerCount = stream.readInt<unsigned int>();
303 for (unsigned int samplerIndex = 0; samplerIndex < samplerCount; ++samplerIndex)
304 {
305 GLenum textureType = stream.readInt<GLenum>();
306 size_t bindingCount = stream.readInt<size_t>();
307 state->mSamplerBindings.emplace_back(SamplerBinding(textureType, bindingCount));
308 }
309
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800310 unsigned int imageRangeLow = stream.readInt<unsigned int>();
311 unsigned int imageRangeHigh = stream.readInt<unsigned int>();
312 state->mImageUniformRange = RangeUI(imageRangeLow, imageRangeHigh);
313 unsigned int imageCount = stream.readInt<unsigned int>();
314 for (unsigned int imageIndex = 0; imageIndex < imageCount; ++imageIndex)
315 {
316 GLuint boundImageUnit = stream.readInt<unsigned int>();
317 size_t elementCount = stream.readInt<size_t>();
318 state->mImageBindings.emplace_back(ImageBinding(boundImageUnit, elementCount));
319 }
320
jchen10eaef1e52017-06-13 10:44:11 +0800321 unsigned int atomicCounterRangeLow = stream.readInt<unsigned int>();
322 unsigned int atomicCounterRangeHigh = stream.readInt<unsigned int>();
323 state->mAtomicCounterUniformRange = RangeUI(atomicCounterRangeLow, atomicCounterRangeHigh);
324
Jamie Madill4f86d052017-06-05 12:59:26 -0400325 return program->getImplementation()->load(context, infoLog, &stream);
326}
327
328// static
329void MemoryProgramCache::Serialize(const Context *context,
330 const gl::Program *program,
331 angle::MemoryBuffer *binaryOut)
332{
333 BinaryOutputStream stream;
334
335 stream.writeBytes(reinterpret_cast<const unsigned char *>(ANGLE_COMMIT_HASH),
336 ANGLE_COMMIT_HASH_SIZE);
337
338 // nullptr context is supported when computing binary length.
339 if (context)
340 {
341 stream.writeInt(context->getClientVersion().major);
342 stream.writeInt(context->getClientVersion().minor);
343 }
344 else
345 {
346 stream.writeInt(2);
347 stream.writeInt(0);
348 }
349
350 const auto &state = program->getState();
351
352 const auto &computeLocalSize = state.getComputeShaderLocalSize();
353
354 stream.writeInt(computeLocalSize[0]);
355 stream.writeInt(computeLocalSize[1]);
356 stream.writeInt(computeLocalSize[2]);
357
358 stream.writeInt(state.getActiveAttribLocationsMask().to_ulong());
359
360 stream.writeInt(state.getAttributes().size());
361 for (const sh::Attribute &attrib : state.getAttributes())
362 {
363 WriteShaderVar(&stream, attrib);
364 stream.writeInt(attrib.location);
365 }
366
367 stream.writeInt(state.getUniforms().size());
368 for (const LinkedUniform &uniform : state.getUniforms())
369 {
370 WriteShaderVar(&stream, uniform);
371
372 // FIXME: referenced
373
jchen10eaef1e52017-06-13 10:44:11 +0800374 stream.writeInt(uniform.bufferIndex);
Jamie Madill4f86d052017-06-05 12:59:26 -0400375 stream.writeInt(uniform.blockInfo.offset);
376 stream.writeInt(uniform.blockInfo.arrayStride);
377 stream.writeInt(uniform.blockInfo.matrixStride);
378 stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
379 }
380
381 stream.writeInt(state.getUniformLocations().size());
382 for (const auto &variable : state.getUniformLocations())
383 {
384 stream.writeString(variable.name);
385 stream.writeInt(variable.element);
386 stream.writeInt(variable.index);
387 stream.writeInt(variable.used);
388 stream.writeInt(variable.ignored);
389 }
390
391 stream.writeInt(state.getUniformBlocks().size());
392 for (const UniformBlock &uniformBlock : state.getUniformBlocks())
393 {
394 stream.writeString(uniformBlock.name);
395 stream.writeInt(uniformBlock.isArray);
396 stream.writeInt(uniformBlock.arrayElement);
Jamie Madill4f86d052017-06-05 12:59:26 -0400397
jchen10eaef1e52017-06-13 10:44:11 +0800398 WriteShaderVariableBuffer(&stream, uniformBlock);
399 }
Jamie Madill4f86d052017-06-05 12:59:26 -0400400
jchen10eaef1e52017-06-13 10:44:11 +0800401 stream.writeInt(state.mAtomicCounterBuffers.size());
402 for (const auto &atomicCounterBuffer : state.mAtomicCounterBuffers)
403 {
404 WriteShaderVariableBuffer(&stream, atomicCounterBuffer);
Jamie Madill4f86d052017-06-05 12:59:26 -0400405 }
406
Jamie Madillffe00c02017-06-27 16:26:55 -0400407 // Warn the app layer if saving a binary with unsupported transform feedback.
408 if (!state.getLinkedTransformFeedbackVaryings().empty() &&
409 context->getWorkarounds().disableProgramCachingForTransformFeedback)
410 {
411 WARN() << "Saving program binary with transform feedback, which is not supported on this "
412 "driver.";
413 }
414
Jamie Madill4f86d052017-06-05 12:59:26 -0400415 stream.writeInt(state.getLinkedTransformFeedbackVaryings().size());
416 for (const auto &var : state.getLinkedTransformFeedbackVaryings())
417 {
418 stream.writeInt(var.arraySize);
419 stream.writeInt(var.type);
420 stream.writeString(var.name);
421
422 stream.writeIntOrNegOne(var.arrayIndex);
423 }
424
425 stream.writeInt(state.getTransformFeedbackBufferMode());
426
427 stream.writeInt(state.getOutputVariables().size());
428 for (const sh::OutputVariable &output : state.getOutputVariables())
429 {
430 WriteShaderVar(&stream, output);
431 stream.writeInt(output.location);
432 }
433
434 stream.writeInt(state.getOutputLocations().size());
435 for (const auto &outputPair : state.getOutputLocations())
436 {
437 stream.writeInt(outputPair.first);
438 stream.writeIntOrNegOne(outputPair.second.element);
439 stream.writeInt(outputPair.second.index);
440 stream.writeString(outputPair.second.name);
441 }
442
443 stream.writeInt(state.mOutputVariableTypes.size());
444 for (const auto &outputVariableType : state.mOutputVariableTypes)
445 {
446 stream.writeInt(outputVariableType);
447 }
448
449 static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS < 8 * sizeof(uint32_t),
450 "All bits of DrawBufferMask can be contained in an uint32_t");
451 stream.writeInt(static_cast<uint32_t>(state.mActiveOutputVariables.to_ulong()));
452
453 stream.writeInt(state.getSamplerUniformRange().low());
454 stream.writeInt(state.getSamplerUniformRange().high());
455
456 stream.writeInt(state.getSamplerBindings().size());
457 for (const auto &samplerBinding : state.getSamplerBindings())
458 {
459 stream.writeInt(samplerBinding.textureType);
460 stream.writeInt(samplerBinding.boundTextureUnits.size());
461 }
462
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800463 stream.writeInt(state.getImageUniformRange().low());
464 stream.writeInt(state.getImageUniformRange().high());
465
466 stream.writeInt(state.getImageBindings().size());
467 for (const auto &imageBinding : state.getImageBindings())
468 {
469 stream.writeInt(imageBinding.boundImageUnit);
470 stream.writeInt(imageBinding.elementCount);
471 }
472
jchen10eaef1e52017-06-13 10:44:11 +0800473 stream.writeInt(state.getAtomicCounterUniformRange().low());
474 stream.writeInt(state.getAtomicCounterUniformRange().high());
475
Jamie Madill27a60632017-06-30 15:12:01 -0400476 program->getImplementation()->save(context, &stream);
Jamie Madill4f86d052017-06-05 12:59:26 -0400477
478 ASSERT(binaryOut);
479 binaryOut->resize(stream.length());
480 memcpy(binaryOut->data(), stream.data(), stream.length());
481}
482
Jamie Madill32447362017-06-28 14:53:52 -0400483// static
484void MemoryProgramCache::ComputeHash(const Context *context,
485 const Program *program,
486 ProgramHash *hashOut)
487{
488 auto vertexShader = program->getAttachedVertexShader();
489 auto fragmentShader = program->getAttachedFragmentShader();
490 auto computeShader = program->getAttachedComputeShader();
491
492 // Compute the program hash. Start with the shader hashes and resource strings.
493 HashStream hashStream;
494 hashStream << vertexShader << fragmentShader << computeShader;
495
496 // Add some ANGLE metadata and Context properties, such as version and back-end.
497 hashStream << ANGLE_COMMIT_HASH << context->getClientMajorVersion()
498 << context->getClientMinorVersion() << context->getString(GL_RENDERER);
499
500 // Hash pre-link program properties.
501 hashStream << program->getAttributeBindings() << program->getUniformLocationBindings()
502 << program->getFragmentInputBindings()
503 << program->getState().getTransformFeedbackVaryingNames()
504 << program->getState().getTransformFeedbackBufferMode();
505
506 // Call the secure SHA hashing function.
507 const std::string &programKey = hashStream.str();
508 angle::base::SHA1HashBytes(reinterpret_cast<const unsigned char *>(programKey.c_str()),
509 programKey.length(), hashOut->data());
510}
511
512LinkResult MemoryProgramCache::getProgram(const Context *context,
513 const Program *program,
514 ProgramState *state,
515 ProgramHash *hashOut)
516{
517 ComputeHash(context, program, hashOut);
518 const angle::MemoryBuffer *binaryProgram = nullptr;
519 LinkResult result(false);
520 if (get(*hashOut, &binaryProgram))
521 {
522 InfoLog infoLog;
523 ANGLE_TRY_RESULT(Deserialize(context, program, state, binaryProgram->data(),
524 binaryProgram->size(), infoLog),
525 result);
526 if (!result.getResult())
527 {
528 // Cache load failed, evict.
529 if (mIssuedWarnings++ < kWarningLimit)
530 {
531 WARN() << "Failed to load binary from cache: " << infoLog.str();
532
533 if (mIssuedWarnings == kWarningLimit)
534 {
535 WARN() << "Reaching warning limit for cache load failures, silencing "
536 "subsequent warnings.";
537 }
538 }
539 remove(*hashOut);
540 }
541 }
542 return result;
543}
544
545bool MemoryProgramCache::get(const ProgramHash &programHash, const angle::MemoryBuffer **programOut)
546{
547 return mProgramBinaryCache.get(programHash, programOut);
548}
549
Jamie Madillc43be722017-07-13 16:22:14 -0400550bool MemoryProgramCache::getAt(size_t index,
551 ProgramHash *hashOut,
552 const angle::MemoryBuffer **programOut)
553{
554 return mProgramBinaryCache.getAt(index, hashOut, programOut);
555}
556
Jamie Madill32447362017-06-28 14:53:52 -0400557void MemoryProgramCache::remove(const ProgramHash &programHash)
558{
559 bool result = mProgramBinaryCache.eraseByKey(programHash);
560 ASSERT(result);
561}
562
Jamie Madill360daee2017-06-29 10:36:19 -0400563void MemoryProgramCache::put(const ProgramHash &program,
Jamie Madill360daee2017-06-29 10:36:19 -0400564 angle::MemoryBuffer &&binaryProgram)
Jamie Madill32447362017-06-28 14:53:52 -0400565{
Jamie Madill360daee2017-06-29 10:36:19 -0400566 const angle::MemoryBuffer *result =
567 mProgramBinaryCache.put(program, std::move(binaryProgram), binaryProgram.size());
568 if (!result)
Jamie Madill32447362017-06-28 14:53:52 -0400569 {
570 ERR() << "Failed to store binary program in memory cache, program is too large.";
571 }
Jamie Madill360daee2017-06-29 10:36:19 -0400572 else
573 {
574 auto *platform = ANGLEPlatformCurrent();
575 platform->cacheProgram(platform, program, result->size(), result->data());
576 }
Jamie Madill32447362017-06-28 14:53:52 -0400577}
578
579void MemoryProgramCache::putProgram(const ProgramHash &programHash,
580 const Context *context,
581 const Program *program)
582{
583 angle::MemoryBuffer binaryProgram;
584 Serialize(context, program, &binaryProgram);
Jamie Madillc43be722017-07-13 16:22:14 -0400585 put(programHash, std::move(binaryProgram));
Jamie Madill32447362017-06-28 14:53:52 -0400586}
587
Jamie Madill4c19a8a2017-07-24 11:46:06 -0400588void MemoryProgramCache::updateProgram(const Context *context, const Program *program)
589{
590 gl::ProgramHash programHash;
591 ComputeHash(context, program, &programHash);
592 putProgram(programHash, context, program);
593}
594
Jamie Madillc43be722017-07-13 16:22:14 -0400595void MemoryProgramCache::putBinary(const ProgramHash &programHash,
Jamie Madill32447362017-06-28 14:53:52 -0400596 const uint8_t *binary,
597 size_t length)
598{
599 // Copy the binary.
600 angle::MemoryBuffer binaryProgram;
601 binaryProgram.resize(length);
602 memcpy(binaryProgram.data(), binary, length);
603
Jamie Madill32447362017-06-28 14:53:52 -0400604 // Store the binary.
Jamie Madillc43be722017-07-13 16:22:14 -0400605 const angle::MemoryBuffer *result =
606 mProgramBinaryCache.put(programHash, std::move(binaryProgram), binaryProgram.size());
607 if (!result)
608 {
609 ERR() << "Failed to store binary program in memory cache, program is too large.";
610 }
Jamie Madill32447362017-06-28 14:53:52 -0400611}
612
613void MemoryProgramCache::clear()
614{
615 mProgramBinaryCache.clear();
616 mIssuedWarnings = 0;
617}
618
Jamie Madillc43be722017-07-13 16:22:14 -0400619void MemoryProgramCache::resize(size_t maxCacheSizeBytes)
620{
621 mProgramBinaryCache.resize(maxCacheSizeBytes);
622}
623
624size_t MemoryProgramCache::entryCount() const
625{
626 return mProgramBinaryCache.entryCount();
627}
628
629size_t MemoryProgramCache::trim(size_t limit)
630{
631 return mProgramBinaryCache.shrinkToSize(limit);
632}
633
634size_t MemoryProgramCache::size() const
635{
636 return mProgramBinaryCache.size();
637}
638
639size_t MemoryProgramCache::maxSize() const
640{
641 return mProgramBinaryCache.maxSize();
642}
643
Jamie Madill4f86d052017-06-05 12:59:26 -0400644} // namespace gl