blob: 6bc6947db959b37d87b40838edbdad37315cada7 [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
Martin Radev7cf61662017-07-26 17:10:53 +0300171 state->mNumViews = stream.readInt<int>();
172
Jamie Madill4f86d052017-06-05 12:59:26 -0400173 static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
174 "Too many vertex attribs for mask");
175 state->mActiveAttribLocationsMask = stream.readInt<unsigned long>();
176
177 unsigned int attribCount = stream.readInt<unsigned int>();
178 ASSERT(state->mAttributes.empty());
179 for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
180 {
181 sh::Attribute attrib;
182 LoadShaderVar(&stream, &attrib);
183 attrib.location = stream.readInt<int>();
184 state->mAttributes.push_back(attrib);
185 }
186
187 unsigned int uniformCount = stream.readInt<unsigned int>();
188 ASSERT(state->mUniforms.empty());
189 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
190 {
191 LinkedUniform uniform;
192 LoadShaderVar(&stream, &uniform);
193
jchen10eaef1e52017-06-13 10:44:11 +0800194 uniform.bufferIndex = stream.readInt<int>();
Jamie Madill4f86d052017-06-05 12:59:26 -0400195 uniform.blockInfo.offset = stream.readInt<int>();
196 uniform.blockInfo.arrayStride = stream.readInt<int>();
197 uniform.blockInfo.matrixStride = stream.readInt<int>();
198 uniform.blockInfo.isRowMajorMatrix = stream.readBool();
199
200 state->mUniforms.push_back(uniform);
201 }
202
203 const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
204 ASSERT(state->mUniformLocations.empty());
205 for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount;
206 uniformIndexIndex++)
207 {
208 VariableLocation variable;
209 stream.readString(&variable.name);
210 stream.readInt(&variable.element);
211 stream.readInt(&variable.index);
212 stream.readBool(&variable.used);
213 stream.readBool(&variable.ignored);
214
215 state->mUniformLocations.push_back(variable);
216 }
217
218 unsigned int uniformBlockCount = stream.readInt<unsigned int>();
219 ASSERT(state->mUniformBlocks.empty());
220 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
221 ++uniformBlockIndex)
222 {
223 UniformBlock uniformBlock;
224 stream.readString(&uniformBlock.name);
225 stream.readBool(&uniformBlock.isArray);
226 stream.readInt(&uniformBlock.arrayElement);
Jamie Madill4f86d052017-06-05 12:59:26 -0400227
jchen10eaef1e52017-06-13 10:44:11 +0800228 LoadShaderVariableBuffer(&stream, &uniformBlock);
Jamie Madill4f86d052017-06-05 12:59:26 -0400229
230 state->mUniformBlocks.push_back(uniformBlock);
Jamie Madill4f86d052017-06-05 12:59:26 -0400231
jchen107a20b972017-06-13 14:25:26 +0800232 state->mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlock.binding != 0);
Jamie Madill4f86d052017-06-05 12:59:26 -0400233 }
jchen10eaef1e52017-06-13 10:44:11 +0800234 unsigned int atomicCounterBufferCount = stream.readInt<unsigned int>();
235 ASSERT(state->mAtomicCounterBuffers.empty());
236 for (unsigned int bufferIndex = 0; bufferIndex < atomicCounterBufferCount; ++bufferIndex)
237 {
238 AtomicCounterBuffer atomicCounterBuffer;
239 LoadShaderVariableBuffer(&stream, &atomicCounterBuffer);
240
241 state->mAtomicCounterBuffers.push_back(atomicCounterBuffer);
242 }
Jamie Madill4f86d052017-06-05 12:59:26 -0400243
244 unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
Jamie Madillffe00c02017-06-27 16:26:55 -0400245
246 // Reject programs that use transform feedback varyings if the hardware cannot support them.
247 if (transformFeedbackVaryingCount > 0 &&
248 context->getWorkarounds().disableProgramCachingForTransformFeedback)
249 {
250 infoLog << "Current driver does not support transform feedback in binary programs.";
251 return false;
252 }
253
Jamie Madill4f86d052017-06-05 12:59:26 -0400254 ASSERT(state->mLinkedTransformFeedbackVaryings.empty());
255 for (unsigned int transformFeedbackVaryingIndex = 0;
256 transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
257 ++transformFeedbackVaryingIndex)
258 {
259 sh::Varying varying;
260 stream.readInt(&varying.arraySize);
261 stream.readInt(&varying.type);
262 stream.readString(&varying.name);
263
264 GLuint arrayIndex = stream.readInt<GLuint>();
265
266 state->mLinkedTransformFeedbackVaryings.emplace_back(varying, arrayIndex);
267 }
268
269 stream.readInt(&state->mTransformFeedbackBufferMode);
270
271 unsigned int outputCount = stream.readInt<unsigned int>();
272 ASSERT(state->mOutputVariables.empty());
273 for (unsigned int outputIndex = 0; outputIndex < outputCount; ++outputIndex)
274 {
275 sh::OutputVariable output;
276 LoadShaderVar(&stream, &output);
277 output.location = stream.readInt<int>();
278 state->mOutputVariables.push_back(output);
279 }
280
281 unsigned int outputVarCount = stream.readInt<unsigned int>();
282 for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
283 {
284 int locationIndex = stream.readInt<int>();
285 VariableLocation locationData;
286 stream.readInt(&locationData.element);
287 stream.readInt(&locationData.index);
288 stream.readString(&locationData.name);
289 state->mOutputLocations[locationIndex] = locationData;
290 }
291
292 unsigned int outputTypeCount = stream.readInt<unsigned int>();
293 for (unsigned int outputIndex = 0; outputIndex < outputTypeCount; ++outputIndex)
294 {
295 state->mOutputVariableTypes.push_back(stream.readInt<GLenum>());
296 }
297 static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS < 8 * sizeof(uint32_t),
298 "All bits of DrawBufferMask can be contained in an uint32_t");
299 state->mActiveOutputVariables = stream.readInt<uint32_t>();
300
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800301 unsigned int samplerRangeLow = stream.readInt<unsigned int>();
302 unsigned int samplerRangeHigh = stream.readInt<unsigned int>();
303 state->mSamplerUniformRange = RangeUI(samplerRangeLow, samplerRangeHigh);
Jamie Madill4f86d052017-06-05 12:59:26 -0400304 unsigned int samplerCount = stream.readInt<unsigned int>();
305 for (unsigned int samplerIndex = 0; samplerIndex < samplerCount; ++samplerIndex)
306 {
307 GLenum textureType = stream.readInt<GLenum>();
308 size_t bindingCount = stream.readInt<size_t>();
309 state->mSamplerBindings.emplace_back(SamplerBinding(textureType, bindingCount));
310 }
311
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800312 unsigned int imageRangeLow = stream.readInt<unsigned int>();
313 unsigned int imageRangeHigh = stream.readInt<unsigned int>();
314 state->mImageUniformRange = RangeUI(imageRangeLow, imageRangeHigh);
Xinghua Cao0328b572017-06-26 15:51:36 +0800315 unsigned int imageBindingCount = stream.readInt<unsigned int>();
316 for (unsigned int imageIndex = 0; imageIndex < imageBindingCount; ++imageIndex)
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800317 {
Xinghua Cao0328b572017-06-26 15:51:36 +0800318 unsigned int elementCount = stream.readInt<unsigned int>();
319 ImageBinding imageBinding(elementCount);
320 for (unsigned int i = 0; i < elementCount; ++i)
321 {
322 imageBinding.boundImageUnits[i] = stream.readInt<unsigned int>();
323 }
324 state->mImageBindings.emplace_back(imageBinding);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800325 }
326
jchen10eaef1e52017-06-13 10:44:11 +0800327 unsigned int atomicCounterRangeLow = stream.readInt<unsigned int>();
328 unsigned int atomicCounterRangeHigh = stream.readInt<unsigned int>();
329 state->mAtomicCounterUniformRange = RangeUI(atomicCounterRangeLow, atomicCounterRangeHigh);
330
Jamie Madill4f86d052017-06-05 12:59:26 -0400331 return program->getImplementation()->load(context, infoLog, &stream);
332}
333
334// static
335void MemoryProgramCache::Serialize(const Context *context,
336 const gl::Program *program,
337 angle::MemoryBuffer *binaryOut)
338{
339 BinaryOutputStream stream;
340
341 stream.writeBytes(reinterpret_cast<const unsigned char *>(ANGLE_COMMIT_HASH),
342 ANGLE_COMMIT_HASH_SIZE);
343
344 // nullptr context is supported when computing binary length.
345 if (context)
346 {
347 stream.writeInt(context->getClientVersion().major);
348 stream.writeInt(context->getClientVersion().minor);
349 }
350 else
351 {
352 stream.writeInt(2);
353 stream.writeInt(0);
354 }
355
356 const auto &state = program->getState();
357
358 const auto &computeLocalSize = state.getComputeShaderLocalSize();
359
360 stream.writeInt(computeLocalSize[0]);
361 stream.writeInt(computeLocalSize[1]);
362 stream.writeInt(computeLocalSize[2]);
363
Martin Radev7cf61662017-07-26 17:10:53 +0300364 stream.writeInt(state.mNumViews);
365
Jamie Madill4f86d052017-06-05 12:59:26 -0400366 stream.writeInt(state.getActiveAttribLocationsMask().to_ulong());
367
368 stream.writeInt(state.getAttributes().size());
369 for (const sh::Attribute &attrib : state.getAttributes())
370 {
371 WriteShaderVar(&stream, attrib);
372 stream.writeInt(attrib.location);
373 }
374
375 stream.writeInt(state.getUniforms().size());
376 for (const LinkedUniform &uniform : state.getUniforms())
377 {
378 WriteShaderVar(&stream, uniform);
379
380 // FIXME: referenced
381
jchen10eaef1e52017-06-13 10:44:11 +0800382 stream.writeInt(uniform.bufferIndex);
Jamie Madill4f86d052017-06-05 12:59:26 -0400383 stream.writeInt(uniform.blockInfo.offset);
384 stream.writeInt(uniform.blockInfo.arrayStride);
385 stream.writeInt(uniform.blockInfo.matrixStride);
386 stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
387 }
388
389 stream.writeInt(state.getUniformLocations().size());
390 for (const auto &variable : state.getUniformLocations())
391 {
392 stream.writeString(variable.name);
393 stream.writeInt(variable.element);
394 stream.writeInt(variable.index);
395 stream.writeInt(variable.used);
396 stream.writeInt(variable.ignored);
397 }
398
399 stream.writeInt(state.getUniformBlocks().size());
400 for (const UniformBlock &uniformBlock : state.getUniformBlocks())
401 {
402 stream.writeString(uniformBlock.name);
403 stream.writeInt(uniformBlock.isArray);
404 stream.writeInt(uniformBlock.arrayElement);
Jamie Madill4f86d052017-06-05 12:59:26 -0400405
jchen10eaef1e52017-06-13 10:44:11 +0800406 WriteShaderVariableBuffer(&stream, uniformBlock);
407 }
Jamie Madill4f86d052017-06-05 12:59:26 -0400408
jchen10eaef1e52017-06-13 10:44:11 +0800409 stream.writeInt(state.mAtomicCounterBuffers.size());
410 for (const auto &atomicCounterBuffer : state.mAtomicCounterBuffers)
411 {
412 WriteShaderVariableBuffer(&stream, atomicCounterBuffer);
Jamie Madill4f86d052017-06-05 12:59:26 -0400413 }
414
Jamie Madillffe00c02017-06-27 16:26:55 -0400415 // Warn the app layer if saving a binary with unsupported transform feedback.
416 if (!state.getLinkedTransformFeedbackVaryings().empty() &&
417 context->getWorkarounds().disableProgramCachingForTransformFeedback)
418 {
419 WARN() << "Saving program binary with transform feedback, which is not supported on this "
420 "driver.";
421 }
422
Jamie Madill4f86d052017-06-05 12:59:26 -0400423 stream.writeInt(state.getLinkedTransformFeedbackVaryings().size());
424 for (const auto &var : state.getLinkedTransformFeedbackVaryings())
425 {
426 stream.writeInt(var.arraySize);
427 stream.writeInt(var.type);
428 stream.writeString(var.name);
429
430 stream.writeIntOrNegOne(var.arrayIndex);
431 }
432
433 stream.writeInt(state.getTransformFeedbackBufferMode());
434
435 stream.writeInt(state.getOutputVariables().size());
436 for (const sh::OutputVariable &output : state.getOutputVariables())
437 {
438 WriteShaderVar(&stream, output);
439 stream.writeInt(output.location);
440 }
441
442 stream.writeInt(state.getOutputLocations().size());
443 for (const auto &outputPair : state.getOutputLocations())
444 {
445 stream.writeInt(outputPair.first);
446 stream.writeIntOrNegOne(outputPair.second.element);
447 stream.writeInt(outputPair.second.index);
448 stream.writeString(outputPair.second.name);
449 }
450
451 stream.writeInt(state.mOutputVariableTypes.size());
452 for (const auto &outputVariableType : state.mOutputVariableTypes)
453 {
454 stream.writeInt(outputVariableType);
455 }
456
457 static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS < 8 * sizeof(uint32_t),
458 "All bits of DrawBufferMask can be contained in an uint32_t");
459 stream.writeInt(static_cast<uint32_t>(state.mActiveOutputVariables.to_ulong()));
460
461 stream.writeInt(state.getSamplerUniformRange().low());
462 stream.writeInt(state.getSamplerUniformRange().high());
463
464 stream.writeInt(state.getSamplerBindings().size());
465 for (const auto &samplerBinding : state.getSamplerBindings())
466 {
467 stream.writeInt(samplerBinding.textureType);
468 stream.writeInt(samplerBinding.boundTextureUnits.size());
469 }
470
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800471 stream.writeInt(state.getImageUniformRange().low());
472 stream.writeInt(state.getImageUniformRange().high());
473
474 stream.writeInt(state.getImageBindings().size());
475 for (const auto &imageBinding : state.getImageBindings())
476 {
Xinghua Cao0328b572017-06-26 15:51:36 +0800477 stream.writeInt(imageBinding.boundImageUnits.size());
478 for (size_t i = 0; i < imageBinding.boundImageUnits.size(); ++i)
479 {
480 stream.writeInt(imageBinding.boundImageUnits[i]);
481 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800482 }
483
jchen10eaef1e52017-06-13 10:44:11 +0800484 stream.writeInt(state.getAtomicCounterUniformRange().low());
485 stream.writeInt(state.getAtomicCounterUniformRange().high());
486
Jamie Madill27a60632017-06-30 15:12:01 -0400487 program->getImplementation()->save(context, &stream);
Jamie Madill4f86d052017-06-05 12:59:26 -0400488
489 ASSERT(binaryOut);
490 binaryOut->resize(stream.length());
491 memcpy(binaryOut->data(), stream.data(), stream.length());
492}
493
Jamie Madill32447362017-06-28 14:53:52 -0400494// static
495void MemoryProgramCache::ComputeHash(const Context *context,
496 const Program *program,
497 ProgramHash *hashOut)
498{
499 auto vertexShader = program->getAttachedVertexShader();
500 auto fragmentShader = program->getAttachedFragmentShader();
501 auto computeShader = program->getAttachedComputeShader();
502
503 // Compute the program hash. Start with the shader hashes and resource strings.
504 HashStream hashStream;
505 hashStream << vertexShader << fragmentShader << computeShader;
506
507 // Add some ANGLE metadata and Context properties, such as version and back-end.
508 hashStream << ANGLE_COMMIT_HASH << context->getClientMajorVersion()
509 << context->getClientMinorVersion() << context->getString(GL_RENDERER);
510
511 // Hash pre-link program properties.
512 hashStream << program->getAttributeBindings() << program->getUniformLocationBindings()
513 << program->getFragmentInputBindings()
514 << program->getState().getTransformFeedbackVaryingNames()
515 << program->getState().getTransformFeedbackBufferMode();
516
517 // Call the secure SHA hashing function.
518 const std::string &programKey = hashStream.str();
519 angle::base::SHA1HashBytes(reinterpret_cast<const unsigned char *>(programKey.c_str()),
520 programKey.length(), hashOut->data());
521}
522
523LinkResult MemoryProgramCache::getProgram(const Context *context,
524 const Program *program,
525 ProgramState *state,
526 ProgramHash *hashOut)
527{
528 ComputeHash(context, program, hashOut);
529 const angle::MemoryBuffer *binaryProgram = nullptr;
530 LinkResult result(false);
531 if (get(*hashOut, &binaryProgram))
532 {
533 InfoLog infoLog;
534 ANGLE_TRY_RESULT(Deserialize(context, program, state, binaryProgram->data(),
535 binaryProgram->size(), infoLog),
536 result);
537 if (!result.getResult())
538 {
539 // Cache load failed, evict.
540 if (mIssuedWarnings++ < kWarningLimit)
541 {
542 WARN() << "Failed to load binary from cache: " << infoLog.str();
543
544 if (mIssuedWarnings == kWarningLimit)
545 {
546 WARN() << "Reaching warning limit for cache load failures, silencing "
547 "subsequent warnings.";
548 }
549 }
550 remove(*hashOut);
551 }
552 }
553 return result;
554}
555
556bool MemoryProgramCache::get(const ProgramHash &programHash, const angle::MemoryBuffer **programOut)
557{
558 return mProgramBinaryCache.get(programHash, programOut);
559}
560
Jamie Madillc43be722017-07-13 16:22:14 -0400561bool MemoryProgramCache::getAt(size_t index,
562 ProgramHash *hashOut,
563 const angle::MemoryBuffer **programOut)
564{
565 return mProgramBinaryCache.getAt(index, hashOut, programOut);
566}
567
Jamie Madill32447362017-06-28 14:53:52 -0400568void MemoryProgramCache::remove(const ProgramHash &programHash)
569{
570 bool result = mProgramBinaryCache.eraseByKey(programHash);
571 ASSERT(result);
572}
573
Jamie Madill360daee2017-06-29 10:36:19 -0400574void MemoryProgramCache::put(const ProgramHash &program,
Jamie Madill360daee2017-06-29 10:36:19 -0400575 angle::MemoryBuffer &&binaryProgram)
Jamie Madill32447362017-06-28 14:53:52 -0400576{
Jamie Madill360daee2017-06-29 10:36:19 -0400577 const angle::MemoryBuffer *result =
578 mProgramBinaryCache.put(program, std::move(binaryProgram), binaryProgram.size());
579 if (!result)
Jamie Madill32447362017-06-28 14:53:52 -0400580 {
581 ERR() << "Failed to store binary program in memory cache, program is too large.";
582 }
Jamie Madill360daee2017-06-29 10:36:19 -0400583 else
584 {
585 auto *platform = ANGLEPlatformCurrent();
586 platform->cacheProgram(platform, program, result->size(), result->data());
587 }
Jamie Madill32447362017-06-28 14:53:52 -0400588}
589
590void MemoryProgramCache::putProgram(const ProgramHash &programHash,
591 const Context *context,
592 const Program *program)
593{
594 angle::MemoryBuffer binaryProgram;
595 Serialize(context, program, &binaryProgram);
Jamie Madillc43be722017-07-13 16:22:14 -0400596 put(programHash, std::move(binaryProgram));
Jamie Madill32447362017-06-28 14:53:52 -0400597}
598
Jamie Madill4c19a8a2017-07-24 11:46:06 -0400599void MemoryProgramCache::updateProgram(const Context *context, const Program *program)
600{
601 gl::ProgramHash programHash;
602 ComputeHash(context, program, &programHash);
603 putProgram(programHash, context, program);
604}
605
Jamie Madillc43be722017-07-13 16:22:14 -0400606void MemoryProgramCache::putBinary(const ProgramHash &programHash,
Jamie Madill32447362017-06-28 14:53:52 -0400607 const uint8_t *binary,
608 size_t length)
609{
610 // Copy the binary.
611 angle::MemoryBuffer binaryProgram;
612 binaryProgram.resize(length);
613 memcpy(binaryProgram.data(), binary, length);
614
Jamie Madill32447362017-06-28 14:53:52 -0400615 // Store the binary.
Jamie Madillc43be722017-07-13 16:22:14 -0400616 const angle::MemoryBuffer *result =
617 mProgramBinaryCache.put(programHash, std::move(binaryProgram), binaryProgram.size());
618 if (!result)
619 {
620 ERR() << "Failed to store binary program in memory cache, program is too large.";
621 }
Jamie Madill32447362017-06-28 14:53:52 -0400622}
623
624void MemoryProgramCache::clear()
625{
626 mProgramBinaryCache.clear();
627 mIssuedWarnings = 0;
628}
629
Jamie Madillc43be722017-07-13 16:22:14 -0400630void MemoryProgramCache::resize(size_t maxCacheSizeBytes)
631{
632 mProgramBinaryCache.resize(maxCacheSizeBytes);
633}
634
635size_t MemoryProgramCache::entryCount() const
636{
637 return mProgramBinaryCache.entryCount();
638}
639
640size_t MemoryProgramCache::trim(size_t limit)
641{
642 return mProgramBinaryCache.shrinkToSize(limit);
643}
644
645size_t MemoryProgramCache::size() const
646{
647 return mProgramBinaryCache.size();
648}
649
650size_t MemoryProgramCache::maxSize() const
651{
652 return mProgramBinaryCache.maxSize();
653}
654
Jamie Madill4f86d052017-06-05 12:59:26 -0400655} // namespace gl