blob: 809edcaed97ef542318b6b73002f1bc9dfb45b45 [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
Jamie Madillf00f7ff2017-08-31 14:39:15 -040015#include "common/utilities.h"
Jamie Madill4f86d052017-06-05 12:59:26 -040016#include "common/version.h"
17#include "libANGLE/BinaryStream.h"
18#include "libANGLE/Context.h"
19#include "libANGLE/Uniform.h"
Jamie Madill6c58b062017-08-01 13:44:25 -040020#include "libANGLE/histogram_macros.h"
Jamie Madill4f86d052017-06-05 12:59:26 -040021#include "libANGLE/renderer/ProgramImpl.h"
Jamie Madill360daee2017-06-29 10:36:19 -040022#include "platform/Platform.h"
Jamie Madill4f86d052017-06-05 12:59:26 -040023
24namespace gl
25{
26
27namespace
28{
Jamie Madill6c58b062017-08-01 13:44:25 -040029enum CacheResult
30{
31 kCacheMiss,
32 kCacheHitMemory,
33 kCacheHitDisk,
34 kCacheResultMax,
35};
36
Jamie Madill32447362017-06-28 14:53:52 -040037constexpr unsigned int kWarningLimit = 3;
Jamie Madill4f86d052017-06-05 12:59:26 -040038
39void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var)
40{
41 stream->writeInt(var.type);
42 stream->writeInt(var.precision);
43 stream->writeString(var.name);
44 stream->writeString(var.mappedName);
Olli Etuaho465835d2017-09-26 13:34:10 +030045 stream->writeIntVector(var.arraySizes);
Jamie Madill4f86d052017-06-05 12:59:26 -040046 stream->writeInt(var.staticUse);
Olli Etuaho107c7242018-03-20 15:45:35 +020047 stream->writeInt(var.active);
Jamie Madill4f86d052017-06-05 12:59:26 -040048 stream->writeString(var.structName);
49 ASSERT(var.fields.empty());
50}
51
52void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var)
53{
54 var->type = stream->readInt<GLenum>();
55 var->precision = stream->readInt<GLenum>();
56 var->name = stream->readString();
57 var->mappedName = stream->readString();
Olli Etuaho465835d2017-09-26 13:34:10 +030058 stream->readIntVector<unsigned int>(&var->arraySizes);
Jamie Madill4f86d052017-06-05 12:59:26 -040059 var->staticUse = stream->readBool();
Olli Etuaho107c7242018-03-20 15:45:35 +020060 var->active = stream->readBool();
Jamie Madill4f86d052017-06-05 12:59:26 -040061 var->structName = stream->readString();
62}
63
jchen10eaef1e52017-06-13 10:44:11 +080064void WriteShaderVariableBuffer(BinaryOutputStream *stream, const ShaderVariableBuffer &var)
65{
66 stream->writeInt(var.binding);
67 stream->writeInt(var.dataSize);
68
Olli Etuaho107c7242018-03-20 15:45:35 +020069 stream->writeInt(var.vertexActive);
70 stream->writeInt(var.fragmentActive);
71 stream->writeInt(var.computeActive);
72 stream->writeInt(var.geometryActive);
jchen10eaef1e52017-06-13 10:44:11 +080073
74 stream->writeInt(var.memberIndexes.size());
75 for (unsigned int memberCounterIndex : var.memberIndexes)
76 {
77 stream->writeInt(memberCounterIndex);
78 }
79}
80
81void LoadShaderVariableBuffer(BinaryInputStream *stream, ShaderVariableBuffer *var)
82{
83 var->binding = stream->readInt<int>();
84 var->dataSize = stream->readInt<unsigned int>();
Olli Etuaho107c7242018-03-20 15:45:35 +020085 var->vertexActive = stream->readBool();
86 var->fragmentActive = stream->readBool();
87 var->computeActive = stream->readBool();
88 var->geometryActive = stream->readBool();
jchen10eaef1e52017-06-13 10:44:11 +080089
90 unsigned int numMembers = stream->readInt<unsigned int>();
91 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
92 {
93 var->memberIndexes.push_back(stream->readInt<unsigned int>());
94 }
95}
96
Jiajia Qin3a9090f2017-09-27 14:37:04 +080097void WriteBufferVariable(BinaryOutputStream *stream, const BufferVariable &var)
98{
99 WriteShaderVar(stream, var);
100
101 stream->writeInt(var.bufferIndex);
102 stream->writeInt(var.blockInfo.offset);
103 stream->writeInt(var.blockInfo.arrayStride);
104 stream->writeInt(var.blockInfo.matrixStride);
105 stream->writeInt(var.blockInfo.isRowMajorMatrix);
106 stream->writeInt(var.blockInfo.topLevelArrayStride);
107 stream->writeInt(var.topLevelArraySize);
Olli Etuaho107c7242018-03-20 15:45:35 +0200108 stream->writeInt(var.vertexActive);
109 stream->writeInt(var.fragmentActive);
110 stream->writeInt(var.computeActive);
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800111}
112
113void LoadBufferVariable(BinaryInputStream *stream, BufferVariable *var)
114{
115 LoadShaderVar(stream, var);
116
117 var->bufferIndex = stream->readInt<int>();
118 var->blockInfo.offset = stream->readInt<int>();
119 var->blockInfo.arrayStride = stream->readInt<int>();
120 var->blockInfo.matrixStride = stream->readInt<int>();
121 var->blockInfo.isRowMajorMatrix = stream->readBool();
122 var->blockInfo.topLevelArrayStride = stream->readInt<int>();
123 var->topLevelArraySize = stream->readInt<int>();
Olli Etuaho107c7242018-03-20 15:45:35 +0200124 var->vertexActive = stream->readBool();
125 var->fragmentActive = stream->readBool();
126 var->computeActive = stream->readBool();
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800127}
128
Jiajia Qin729b2c62017-08-14 09:36:11 +0800129void WriteInterfaceBlock(BinaryOutputStream *stream, const InterfaceBlock &block)
130{
131 stream->writeString(block.name);
132 stream->writeString(block.mappedName);
133 stream->writeInt(block.isArray);
134 stream->writeInt(block.arrayElement);
135
136 WriteShaderVariableBuffer(stream, block);
137}
138
139void LoadInterfaceBlock(BinaryInputStream *stream, InterfaceBlock *block)
140{
141 block->name = stream->readString();
142 block->mappedName = stream->readString();
143 block->isArray = stream->readBool();
144 block->arrayElement = stream->readInt<unsigned int>();
145
146 LoadShaderVariableBuffer(stream, block);
147}
148
Jamie Madill32447362017-06-28 14:53:52 -0400149class HashStream final : angle::NonCopyable
150{
151 public:
152 std::string str() { return mStringStream.str(); }
153
154 template <typename T>
155 HashStream &operator<<(T value)
156 {
157 mStringStream << value << kSeparator;
158 return *this;
159 }
160
161 private:
162 static constexpr char kSeparator = ':';
163 std::ostringstream mStringStream;
164};
165
166HashStream &operator<<(HashStream &stream, const Shader *shader)
167{
168 if (shader)
169 {
170 stream << shader->getSourceString().c_str() << shader->getSourceString().length()
171 << shader->getCompilerResourcesString().c_str();
172 }
173 return stream;
174}
175
Jamie Madill3c1da042017-11-27 18:33:40 -0500176HashStream &operator<<(HashStream &stream, const ProgramBindings &bindings)
Jamie Madill32447362017-06-28 14:53:52 -0400177{
178 for (const auto &binding : bindings)
179 {
180 stream << binding.first << binding.second;
181 }
182 return stream;
183}
184
185HashStream &operator<<(HashStream &stream, const std::vector<std::string> &strings)
186{
187 for (const auto &str : strings)
188 {
189 stream << str;
190 }
191 return stream;
192}
193
Jamie Madill4f86d052017-06-05 12:59:26 -0400194} // anonymous namespace
195
Jamie Madill32447362017-06-28 14:53:52 -0400196MemoryProgramCache::MemoryProgramCache(size_t maxCacheSizeBytes)
197 : mProgramBinaryCache(maxCacheSizeBytes), mIssuedWarnings(0)
198{
199}
200
201MemoryProgramCache::~MemoryProgramCache()
202{
203}
204
Jamie Madill4f86d052017-06-05 12:59:26 -0400205// static
206LinkResult MemoryProgramCache::Deserialize(const Context *context,
207 const Program *program,
208 ProgramState *state,
209 const uint8_t *binary,
210 size_t length,
211 InfoLog &infoLog)
212{
213 BinaryInputStream stream(binary, length);
214
215 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
216 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
217 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) !=
218 0)
219 {
220 infoLog << "Invalid program binary version.";
221 return false;
222 }
223
224 int majorVersion = stream.readInt<int>();
225 int minorVersion = stream.readInt<int>();
226 if (majorVersion != context->getClientMajorVersion() ||
227 minorVersion != context->getClientMinorVersion())
228 {
229 infoLog << "Cannot load program binaries across different ES context versions.";
230 return false;
231 }
232
233 state->mComputeShaderLocalSize[0] = stream.readInt<int>();
234 state->mComputeShaderLocalSize[1] = stream.readInt<int>();
235 state->mComputeShaderLocalSize[2] = stream.readInt<int>();
236
Jiawei Shao4ed05da2018-02-02 14:26:15 +0800237 state->mGeometryShaderInputPrimitiveType = stream.readInt<GLenum>();
238 state->mGeometryShaderOutputPrimitiveType = stream.readInt<GLenum>();
239 state->mGeometryShaderInvocations = stream.readInt<int>();
240 state->mGeometryShaderMaxVertices = stream.readInt<int>();
241
Martin Radev7cf61662017-07-26 17:10:53 +0300242 state->mNumViews = stream.readInt<int>();
243
Brandon Jonesc405ae72017-12-06 14:15:03 -0800244 static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
245 "All bits of mAttributesTypeMask types and mask fit into 32 bits each");
246 state->mAttributesTypeMask.from_ulong(stream.readInt<uint32_t>());
Jamie Madill09463932018-04-04 05:26:59 -0400247 state->mAttributesMask = stream.readInt<gl::AttributesMask>();
Brandon Jonesc405ae72017-12-06 14:15:03 -0800248
Jamie Madill4f86d052017-06-05 12:59:26 -0400249 static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
250 "Too many vertex attribs for mask");
Jamie Madill09463932018-04-04 05:26:59 -0400251 state->mActiveAttribLocationsMask = stream.readInt<gl::AttributesMask>();
Jamie Madill4f86d052017-06-05 12:59:26 -0400252
253 unsigned int attribCount = stream.readInt<unsigned int>();
254 ASSERT(state->mAttributes.empty());
255 for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
256 {
257 sh::Attribute attrib;
258 LoadShaderVar(&stream, &attrib);
259 attrib.location = stream.readInt<int>();
260 state->mAttributes.push_back(attrib);
261 }
262
263 unsigned int uniformCount = stream.readInt<unsigned int>();
264 ASSERT(state->mUniforms.empty());
265 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
266 {
267 LinkedUniform uniform;
268 LoadShaderVar(&stream, &uniform);
269
jchen10eaef1e52017-06-13 10:44:11 +0800270 uniform.bufferIndex = stream.readInt<int>();
Jamie Madill4f86d052017-06-05 12:59:26 -0400271 uniform.blockInfo.offset = stream.readInt<int>();
272 uniform.blockInfo.arrayStride = stream.readInt<int>();
273 uniform.blockInfo.matrixStride = stream.readInt<int>();
274 uniform.blockInfo.isRowMajorMatrix = stream.readBool();
275
Jamie Madillf00f7ff2017-08-31 14:39:15 -0400276 uniform.typeInfo = &GetUniformTypeInfo(uniform.type);
277
Jamie Madill4f86d052017-06-05 12:59:26 -0400278 state->mUniforms.push_back(uniform);
279 }
280
281 const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
282 ASSERT(state->mUniformLocations.empty());
283 for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount;
284 uniformIndexIndex++)
285 {
286 VariableLocation variable;
Olli Etuaho1734e172017-10-27 15:30:27 +0300287 stream.readInt(&variable.arrayIndex);
Jamie Madill4f86d052017-06-05 12:59:26 -0400288 stream.readInt(&variable.index);
Jamie Madill4f86d052017-06-05 12:59:26 -0400289 stream.readBool(&variable.ignored);
290
291 state->mUniformLocations.push_back(variable);
292 }
293
294 unsigned int uniformBlockCount = stream.readInt<unsigned int>();
295 ASSERT(state->mUniformBlocks.empty());
296 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
297 ++uniformBlockIndex)
298 {
Jiajia Qin729b2c62017-08-14 09:36:11 +0800299 InterfaceBlock uniformBlock;
300 LoadInterfaceBlock(&stream, &uniformBlock);
Jamie Madill4f86d052017-06-05 12:59:26 -0400301 state->mUniformBlocks.push_back(uniformBlock);
Jamie Madill4f86d052017-06-05 12:59:26 -0400302
jchen107a20b972017-06-13 14:25:26 +0800303 state->mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlock.binding != 0);
Jamie Madill4f86d052017-06-05 12:59:26 -0400304 }
Jiajia Qin729b2c62017-08-14 09:36:11 +0800305
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800306 unsigned int bufferVariableCount = stream.readInt<unsigned int>();
307 ASSERT(state->mBufferVariables.empty());
308 for (unsigned int index = 0; index < bufferVariableCount; ++index)
309 {
310 BufferVariable bufferVariable;
311 LoadBufferVariable(&stream, &bufferVariable);
312 state->mBufferVariables.push_back(bufferVariable);
313 }
314
Jiajia Qin729b2c62017-08-14 09:36:11 +0800315 unsigned int shaderStorageBlockCount = stream.readInt<unsigned int>();
316 ASSERT(state->mShaderStorageBlocks.empty());
317 for (unsigned int shaderStorageBlockIndex = 0;
318 shaderStorageBlockIndex < shaderStorageBlockCount; ++shaderStorageBlockIndex)
319 {
320 InterfaceBlock shaderStorageBlock;
321 LoadInterfaceBlock(&stream, &shaderStorageBlock);
322 state->mShaderStorageBlocks.push_back(shaderStorageBlock);
323 }
324
jchen10eaef1e52017-06-13 10:44:11 +0800325 unsigned int atomicCounterBufferCount = stream.readInt<unsigned int>();
326 ASSERT(state->mAtomicCounterBuffers.empty());
327 for (unsigned int bufferIndex = 0; bufferIndex < atomicCounterBufferCount; ++bufferIndex)
328 {
329 AtomicCounterBuffer atomicCounterBuffer;
330 LoadShaderVariableBuffer(&stream, &atomicCounterBuffer);
331
332 state->mAtomicCounterBuffers.push_back(atomicCounterBuffer);
333 }
Jamie Madill4f86d052017-06-05 12:59:26 -0400334
335 unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
Jamie Madillffe00c02017-06-27 16:26:55 -0400336
337 // Reject programs that use transform feedback varyings if the hardware cannot support them.
338 if (transformFeedbackVaryingCount > 0 &&
339 context->getWorkarounds().disableProgramCachingForTransformFeedback)
340 {
341 infoLog << "Current driver does not support transform feedback in binary programs.";
342 return false;
343 }
344
Jamie Madill4f86d052017-06-05 12:59:26 -0400345 ASSERT(state->mLinkedTransformFeedbackVaryings.empty());
346 for (unsigned int transformFeedbackVaryingIndex = 0;
347 transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
348 ++transformFeedbackVaryingIndex)
349 {
350 sh::Varying varying;
Olli Etuaho465835d2017-09-26 13:34:10 +0300351 stream.readIntVector<unsigned int>(&varying.arraySizes);
Jamie Madill4f86d052017-06-05 12:59:26 -0400352 stream.readInt(&varying.type);
353 stream.readString(&varying.name);
354
355 GLuint arrayIndex = stream.readInt<GLuint>();
356
357 state->mLinkedTransformFeedbackVaryings.emplace_back(varying, arrayIndex);
358 }
359
360 stream.readInt(&state->mTransformFeedbackBufferMode);
361
362 unsigned int outputCount = stream.readInt<unsigned int>();
363 ASSERT(state->mOutputVariables.empty());
364 for (unsigned int outputIndex = 0; outputIndex < outputCount; ++outputIndex)
365 {
366 sh::OutputVariable output;
367 LoadShaderVar(&stream, &output);
368 output.location = stream.readInt<int>();
369 state->mOutputVariables.push_back(output);
370 }
371
372 unsigned int outputVarCount = stream.readInt<unsigned int>();
Olli Etuahod2551232017-10-26 20:03:33 +0300373 ASSERT(state->mOutputLocations.empty());
Jamie Madill4f86d052017-06-05 12:59:26 -0400374 for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
375 {
Jamie Madill4f86d052017-06-05 12:59:26 -0400376 VariableLocation locationData;
Olli Etuaho1734e172017-10-27 15:30:27 +0300377 stream.readInt(&locationData.arrayIndex);
Jamie Madill4f86d052017-06-05 12:59:26 -0400378 stream.readInt(&locationData.index);
Jamie Madillfb997ec2017-09-20 15:44:27 -0400379 stream.readBool(&locationData.ignored);
Olli Etuahod2551232017-10-26 20:03:33 +0300380 state->mOutputLocations.push_back(locationData);
Jamie Madill4f86d052017-06-05 12:59:26 -0400381 }
382
383 unsigned int outputTypeCount = stream.readInt<unsigned int>();
384 for (unsigned int outputIndex = 0; outputIndex < outputTypeCount; ++outputIndex)
385 {
386 state->mOutputVariableTypes.push_back(stream.readInt<GLenum>());
387 }
Brandon Jones76746f92017-11-22 11:44:41 -0800388
Brandon Jonesc405ae72017-12-06 14:15:03 -0800389 static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS * 2 <= 8 * sizeof(uint32_t),
390 "All bits of mDrawBufferTypeMask and mActiveOutputVariables types and mask fit "
391 "into 32 bits each");
392 state->mDrawBufferTypeMask.from_ulong(stream.readInt<uint32_t>());
Jamie Madill09463932018-04-04 05:26:59 -0400393 state->mActiveOutputVariables = stream.readInt<gl::DrawBufferMask>();
Jamie Madill4f86d052017-06-05 12:59:26 -0400394
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800395 unsigned int samplerRangeLow = stream.readInt<unsigned int>();
396 unsigned int samplerRangeHigh = stream.readInt<unsigned int>();
397 state->mSamplerUniformRange = RangeUI(samplerRangeLow, samplerRangeHigh);
Jamie Madill4f86d052017-06-05 12:59:26 -0400398 unsigned int samplerCount = stream.readInt<unsigned int>();
399 for (unsigned int samplerIndex = 0; samplerIndex < samplerCount; ++samplerIndex)
400 {
Corentin Wallezf0e89be2017-11-08 14:00:32 -0800401 TextureType textureType = stream.readEnum<TextureType>();
Jamie Madill4f86d052017-06-05 12:59:26 -0400402 size_t bindingCount = stream.readInt<size_t>();
Jamie Madill54164b02017-08-28 15:17:37 -0400403 bool unreferenced = stream.readBool();
404 state->mSamplerBindings.emplace_back(
405 SamplerBinding(textureType, bindingCount, unreferenced));
Jamie Madill4f86d052017-06-05 12:59:26 -0400406 }
407
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800408 unsigned int imageRangeLow = stream.readInt<unsigned int>();
409 unsigned int imageRangeHigh = stream.readInt<unsigned int>();
410 state->mImageUniformRange = RangeUI(imageRangeLow, imageRangeHigh);
Xinghua Cao0328b572017-06-26 15:51:36 +0800411 unsigned int imageBindingCount = stream.readInt<unsigned int>();
412 for (unsigned int imageIndex = 0; imageIndex < imageBindingCount; ++imageIndex)
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800413 {
Xinghua Cao0328b572017-06-26 15:51:36 +0800414 unsigned int elementCount = stream.readInt<unsigned int>();
415 ImageBinding imageBinding(elementCount);
416 for (unsigned int i = 0; i < elementCount; ++i)
417 {
418 imageBinding.boundImageUnits[i] = stream.readInt<unsigned int>();
419 }
420 state->mImageBindings.emplace_back(imageBinding);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800421 }
422
jchen10eaef1e52017-06-13 10:44:11 +0800423 unsigned int atomicCounterRangeLow = stream.readInt<unsigned int>();
424 unsigned int atomicCounterRangeHigh = stream.readInt<unsigned int>();
425 state->mAtomicCounterUniformRange = RangeUI(atomicCounterRangeLow, atomicCounterRangeHigh);
426
Jiawei Shao385b3e02018-03-21 09:43:28 +0800427 static_assert(static_cast<unsigned long>(ShaderType::EnumCount) <= sizeof(unsigned long) * 8,
428 "Too many shader types");
Jamie Madill09463932018-04-04 05:26:59 -0400429 state->mLinkedShaderStages = stream.readInt<gl::ShaderStagesMask>();
Yunchao He85072e82017-11-14 15:43:28 +0800430
James Darpinian30b604d2018-03-12 17:26:57 -0700431 state->updateTransformFeedbackStrides();
432
Jamie Madill4f86d052017-06-05 12:59:26 -0400433 return program->getImplementation()->load(context, infoLog, &stream);
434}
435
436// static
437void MemoryProgramCache::Serialize(const Context *context,
438 const gl::Program *program,
439 angle::MemoryBuffer *binaryOut)
440{
441 BinaryOutputStream stream;
442
443 stream.writeBytes(reinterpret_cast<const unsigned char *>(ANGLE_COMMIT_HASH),
444 ANGLE_COMMIT_HASH_SIZE);
445
446 // nullptr context is supported when computing binary length.
447 if (context)
448 {
449 stream.writeInt(context->getClientVersion().major);
450 stream.writeInt(context->getClientVersion().minor);
451 }
452 else
453 {
454 stream.writeInt(2);
455 stream.writeInt(0);
456 }
457
458 const auto &state = program->getState();
459
460 const auto &computeLocalSize = state.getComputeShaderLocalSize();
461
462 stream.writeInt(computeLocalSize[0]);
463 stream.writeInt(computeLocalSize[1]);
464 stream.writeInt(computeLocalSize[2]);
465
Jiawei Shao4ed05da2018-02-02 14:26:15 +0800466 ASSERT(state.mGeometryShaderInvocations >= 1 && state.mGeometryShaderMaxVertices >= 0);
467 stream.writeInt(state.mGeometryShaderInputPrimitiveType);
468 stream.writeInt(state.mGeometryShaderOutputPrimitiveType);
469 stream.writeInt(state.mGeometryShaderInvocations);
470 stream.writeInt(state.mGeometryShaderMaxVertices);
471
Martin Radev7cf61662017-07-26 17:10:53 +0300472 stream.writeInt(state.mNumViews);
473
Brandon Jonesc405ae72017-12-06 14:15:03 -0800474 static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
475 "All bits of mAttributesTypeMask types and mask fit into 32 bits each");
476 stream.writeInt(static_cast<int>(state.mAttributesTypeMask.to_ulong()));
477 stream.writeInt(static_cast<int>(state.mAttributesMask.to_ulong()));
478
Jamie Madill4f86d052017-06-05 12:59:26 -0400479 stream.writeInt(state.getActiveAttribLocationsMask().to_ulong());
480
481 stream.writeInt(state.getAttributes().size());
482 for (const sh::Attribute &attrib : state.getAttributes())
483 {
484 WriteShaderVar(&stream, attrib);
485 stream.writeInt(attrib.location);
486 }
487
488 stream.writeInt(state.getUniforms().size());
489 for (const LinkedUniform &uniform : state.getUniforms())
490 {
491 WriteShaderVar(&stream, uniform);
492
493 // FIXME: referenced
494
jchen10eaef1e52017-06-13 10:44:11 +0800495 stream.writeInt(uniform.bufferIndex);
Jamie Madill4f86d052017-06-05 12:59:26 -0400496 stream.writeInt(uniform.blockInfo.offset);
497 stream.writeInt(uniform.blockInfo.arrayStride);
498 stream.writeInt(uniform.blockInfo.matrixStride);
499 stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
500 }
501
502 stream.writeInt(state.getUniformLocations().size());
503 for (const auto &variable : state.getUniformLocations())
504 {
Olli Etuaho1734e172017-10-27 15:30:27 +0300505 stream.writeInt(variable.arrayIndex);
Jamie Madillfb997ec2017-09-20 15:44:27 -0400506 stream.writeIntOrNegOne(variable.index);
Jamie Madill4f86d052017-06-05 12:59:26 -0400507 stream.writeInt(variable.ignored);
508 }
509
510 stream.writeInt(state.getUniformBlocks().size());
Jiajia Qin729b2c62017-08-14 09:36:11 +0800511 for (const InterfaceBlock &uniformBlock : state.getUniformBlocks())
Jamie Madill4f86d052017-06-05 12:59:26 -0400512 {
Jiajia Qin729b2c62017-08-14 09:36:11 +0800513 WriteInterfaceBlock(&stream, uniformBlock);
514 }
Jamie Madill4f86d052017-06-05 12:59:26 -0400515
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800516 stream.writeInt(state.getBufferVariables().size());
517 for (const BufferVariable &bufferVariable : state.getBufferVariables())
518 {
519 WriteBufferVariable(&stream, bufferVariable);
520 }
521
Jiajia Qin729b2c62017-08-14 09:36:11 +0800522 stream.writeInt(state.getShaderStorageBlocks().size());
523 for (const InterfaceBlock &shaderStorageBlock : state.getShaderStorageBlocks())
524 {
525 WriteInterfaceBlock(&stream, shaderStorageBlock);
jchen10eaef1e52017-06-13 10:44:11 +0800526 }
Jamie Madill4f86d052017-06-05 12:59:26 -0400527
jchen10eaef1e52017-06-13 10:44:11 +0800528 stream.writeInt(state.mAtomicCounterBuffers.size());
529 for (const auto &atomicCounterBuffer : state.mAtomicCounterBuffers)
530 {
531 WriteShaderVariableBuffer(&stream, atomicCounterBuffer);
Jamie Madill4f86d052017-06-05 12:59:26 -0400532 }
533
Jamie Madillffe00c02017-06-27 16:26:55 -0400534 // Warn the app layer if saving a binary with unsupported transform feedback.
535 if (!state.getLinkedTransformFeedbackVaryings().empty() &&
536 context->getWorkarounds().disableProgramCachingForTransformFeedback)
537 {
538 WARN() << "Saving program binary with transform feedback, which is not supported on this "
539 "driver.";
540 }
541
Jamie Madill4f86d052017-06-05 12:59:26 -0400542 stream.writeInt(state.getLinkedTransformFeedbackVaryings().size());
543 for (const auto &var : state.getLinkedTransformFeedbackVaryings())
544 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300545 stream.writeIntVector(var.arraySizes);
Jamie Madill4f86d052017-06-05 12:59:26 -0400546 stream.writeInt(var.type);
547 stream.writeString(var.name);
548
549 stream.writeIntOrNegOne(var.arrayIndex);
550 }
551
552 stream.writeInt(state.getTransformFeedbackBufferMode());
553
554 stream.writeInt(state.getOutputVariables().size());
555 for (const sh::OutputVariable &output : state.getOutputVariables())
556 {
557 WriteShaderVar(&stream, output);
558 stream.writeInt(output.location);
559 }
560
561 stream.writeInt(state.getOutputLocations().size());
Olli Etuahod2551232017-10-26 20:03:33 +0300562 for (const auto &outputVar : state.getOutputLocations())
Jamie Madill4f86d052017-06-05 12:59:26 -0400563 {
Olli Etuaho1734e172017-10-27 15:30:27 +0300564 stream.writeInt(outputVar.arrayIndex);
Olli Etuahod2551232017-10-26 20:03:33 +0300565 stream.writeIntOrNegOne(outputVar.index);
Olli Etuahod2551232017-10-26 20:03:33 +0300566 stream.writeInt(outputVar.ignored);
Jamie Madill4f86d052017-06-05 12:59:26 -0400567 }
568
569 stream.writeInt(state.mOutputVariableTypes.size());
570 for (const auto &outputVariableType : state.mOutputVariableTypes)
571 {
572 stream.writeInt(outputVariableType);
573 }
574
Brandon Jonesc405ae72017-12-06 14:15:03 -0800575 static_assert(
576 IMPLEMENTATION_MAX_DRAW_BUFFERS * 2 <= 8 * sizeof(uint32_t),
577 "All bits of mDrawBufferTypeMask and mActiveOutputVariables can be contained in 32 bits");
578 stream.writeInt(static_cast<int>(state.mDrawBufferTypeMask.to_ulong()));
579 stream.writeInt(static_cast<int>(state.mActiveOutputVariables.to_ulong()));
Jamie Madill4f86d052017-06-05 12:59:26 -0400580
581 stream.writeInt(state.getSamplerUniformRange().low());
582 stream.writeInt(state.getSamplerUniformRange().high());
583
584 stream.writeInt(state.getSamplerBindings().size());
585 for (const auto &samplerBinding : state.getSamplerBindings())
586 {
Corentin Wallezf0e89be2017-11-08 14:00:32 -0800587 stream.writeEnum(samplerBinding.textureType);
Jamie Madill4f86d052017-06-05 12:59:26 -0400588 stream.writeInt(samplerBinding.boundTextureUnits.size());
Jamie Madill54164b02017-08-28 15:17:37 -0400589 stream.writeInt(samplerBinding.unreferenced);
Jamie Madill4f86d052017-06-05 12:59:26 -0400590 }
591
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800592 stream.writeInt(state.getImageUniformRange().low());
593 stream.writeInt(state.getImageUniformRange().high());
594
595 stream.writeInt(state.getImageBindings().size());
596 for (const auto &imageBinding : state.getImageBindings())
597 {
Xinghua Cao0328b572017-06-26 15:51:36 +0800598 stream.writeInt(imageBinding.boundImageUnits.size());
599 for (size_t i = 0; i < imageBinding.boundImageUnits.size(); ++i)
600 {
601 stream.writeInt(imageBinding.boundImageUnits[i]);
602 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800603 }
604
jchen10eaef1e52017-06-13 10:44:11 +0800605 stream.writeInt(state.getAtomicCounterUniformRange().low());
606 stream.writeInt(state.getAtomicCounterUniformRange().high());
607
Yunchao He85072e82017-11-14 15:43:28 +0800608 stream.writeInt(state.getLinkedShaderStages().to_ulong());
609
Jamie Madill27a60632017-06-30 15:12:01 -0400610 program->getImplementation()->save(context, &stream);
Jamie Madill4f86d052017-06-05 12:59:26 -0400611
612 ASSERT(binaryOut);
613 binaryOut->resize(stream.length());
614 memcpy(binaryOut->data(), stream.data(), stream.length());
615}
616
Jamie Madill32447362017-06-28 14:53:52 -0400617// static
618void MemoryProgramCache::ComputeHash(const Context *context,
619 const Program *program,
620 ProgramHash *hashOut)
621{
Jamie Madill32447362017-06-28 14:53:52 -0400622 // Compute the program hash. Start with the shader hashes and resource strings.
623 HashStream hashStream;
Jiawei Shao385b3e02018-03-21 09:43:28 +0800624 for (ShaderType shaderType : AllShaderTypes())
625 {
626 hashStream << program->getAttachedShader(shaderType);
627 }
Jamie Madill32447362017-06-28 14:53:52 -0400628
629 // Add some ANGLE metadata and Context properties, such as version and back-end.
630 hashStream << ANGLE_COMMIT_HASH << context->getClientMajorVersion()
631 << context->getClientMinorVersion() << context->getString(GL_RENDERER);
632
633 // Hash pre-link program properties.
634 hashStream << program->getAttributeBindings() << program->getUniformLocationBindings()
635 << program->getFragmentInputBindings()
636 << program->getState().getTransformFeedbackVaryingNames()
637 << program->getState().getTransformFeedbackBufferMode();
638
639 // Call the secure SHA hashing function.
640 const std::string &programKey = hashStream.str();
641 angle::base::SHA1HashBytes(reinterpret_cast<const unsigned char *>(programKey.c_str()),
642 programKey.length(), hashOut->data());
643}
644
645LinkResult MemoryProgramCache::getProgram(const Context *context,
646 const Program *program,
647 ProgramState *state,
648 ProgramHash *hashOut)
649{
650 ComputeHash(context, program, hashOut);
651 const angle::MemoryBuffer *binaryProgram = nullptr;
652 LinkResult result(false);
653 if (get(*hashOut, &binaryProgram))
654 {
655 InfoLog infoLog;
656 ANGLE_TRY_RESULT(Deserialize(context, program, state, binaryProgram->data(),
657 binaryProgram->size(), infoLog),
658 result);
Jamie Madill6c58b062017-08-01 13:44:25 -0400659 ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ProgramCache.LoadBinarySuccess", result.getResult());
Jamie Madill32447362017-06-28 14:53:52 -0400660 if (!result.getResult())
661 {
662 // Cache load failed, evict.
663 if (mIssuedWarnings++ < kWarningLimit)
664 {
665 WARN() << "Failed to load binary from cache: " << infoLog.str();
666
667 if (mIssuedWarnings == kWarningLimit)
668 {
669 WARN() << "Reaching warning limit for cache load failures, silencing "
670 "subsequent warnings.";
671 }
672 }
673 remove(*hashOut);
674 }
675 }
676 return result;
677}
678
679bool MemoryProgramCache::get(const ProgramHash &programHash, const angle::MemoryBuffer **programOut)
680{
Jamie Madill6c58b062017-08-01 13:44:25 -0400681 const CacheEntry *entry = nullptr;
682 if (!mProgramBinaryCache.get(programHash, &entry))
683 {
684 ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.ProgramCache.CacheResult", kCacheMiss,
685 kCacheResultMax);
686 return false;
687 }
688
689 if (entry->second == CacheSource::PutProgram)
690 {
691 ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.ProgramCache.CacheResult", kCacheHitMemory,
692 kCacheResultMax);
693 }
694 else
695 {
696 ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.ProgramCache.CacheResult", kCacheHitDisk,
697 kCacheResultMax);
698 }
699
700 *programOut = &entry->first;
701 return true;
Jamie Madill32447362017-06-28 14:53:52 -0400702}
703
Jamie Madillc43be722017-07-13 16:22:14 -0400704bool MemoryProgramCache::getAt(size_t index,
705 ProgramHash *hashOut,
706 const angle::MemoryBuffer **programOut)
707{
Jamie Madill6c58b062017-08-01 13:44:25 -0400708 const CacheEntry *entry = nullptr;
709 if (!mProgramBinaryCache.getAt(index, hashOut, &entry))
710 {
711 return false;
712 }
713
714 *programOut = &entry->first;
715 return true;
Jamie Madillc43be722017-07-13 16:22:14 -0400716}
717
Jamie Madill32447362017-06-28 14:53:52 -0400718void MemoryProgramCache::remove(const ProgramHash &programHash)
719{
720 bool result = mProgramBinaryCache.eraseByKey(programHash);
721 ASSERT(result);
722}
723
Jamie Madill6c58b062017-08-01 13:44:25 -0400724void MemoryProgramCache::putProgram(const ProgramHash &programHash,
725 const Context *context,
726 const Program *program)
Jamie Madill32447362017-06-28 14:53:52 -0400727{
Jamie Madill6c58b062017-08-01 13:44:25 -0400728 CacheEntry newEntry;
729 Serialize(context, program, &newEntry.first);
730 newEntry.second = CacheSource::PutProgram;
731
732 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramBinarySizeBytes",
733 static_cast<int>(newEntry.first.size()));
734
735 const CacheEntry *result =
736 mProgramBinaryCache.put(programHash, std::move(newEntry), newEntry.first.size());
Jamie Madill360daee2017-06-29 10:36:19 -0400737 if (!result)
Jamie Madill32447362017-06-28 14:53:52 -0400738 {
739 ERR() << "Failed to store binary program in memory cache, program is too large.";
740 }
Jamie Madill360daee2017-06-29 10:36:19 -0400741 else
742 {
743 auto *platform = ANGLEPlatformCurrent();
Jamie Madill6c58b062017-08-01 13:44:25 -0400744 platform->cacheProgram(platform, programHash, result->first.size(), result->first.data());
Jamie Madill360daee2017-06-29 10:36:19 -0400745 }
Jamie Madill32447362017-06-28 14:53:52 -0400746}
747
Jamie Madill4c19a8a2017-07-24 11:46:06 -0400748void MemoryProgramCache::updateProgram(const Context *context, const Program *program)
749{
750 gl::ProgramHash programHash;
751 ComputeHash(context, program, &programHash);
752 putProgram(programHash, context, program);
753}
754
Jamie Madillc43be722017-07-13 16:22:14 -0400755void MemoryProgramCache::putBinary(const ProgramHash &programHash,
Jamie Madill32447362017-06-28 14:53:52 -0400756 const uint8_t *binary,
757 size_t length)
758{
759 // Copy the binary.
Jamie Madill6c58b062017-08-01 13:44:25 -0400760 CacheEntry newEntry;
761 newEntry.first.resize(length);
762 memcpy(newEntry.first.data(), binary, length);
763 newEntry.second = CacheSource::PutBinary;
Jamie Madill32447362017-06-28 14:53:52 -0400764
Jamie Madill32447362017-06-28 14:53:52 -0400765 // Store the binary.
Jamie Madill6c58b062017-08-01 13:44:25 -0400766 const CacheEntry *result = mProgramBinaryCache.put(programHash, std::move(newEntry), length);
Jamie Madillc43be722017-07-13 16:22:14 -0400767 if (!result)
768 {
769 ERR() << "Failed to store binary program in memory cache, program is too large.";
770 }
Jamie Madill32447362017-06-28 14:53:52 -0400771}
772
773void MemoryProgramCache::clear()
774{
775 mProgramBinaryCache.clear();
776 mIssuedWarnings = 0;
777}
778
Jamie Madillc43be722017-07-13 16:22:14 -0400779void MemoryProgramCache::resize(size_t maxCacheSizeBytes)
780{
781 mProgramBinaryCache.resize(maxCacheSizeBytes);
782}
783
784size_t MemoryProgramCache::entryCount() const
785{
786 return mProgramBinaryCache.entryCount();
787}
788
789size_t MemoryProgramCache::trim(size_t limit)
790{
791 return mProgramBinaryCache.shrinkToSize(limit);
792}
793
794size_t MemoryProgramCache::size() const
795{
796 return mProgramBinaryCache.size();
797}
798
799size_t MemoryProgramCache::maxSize() const
800{
801 return mProgramBinaryCache.maxSize();
802}
803
Jamie Madill4f86d052017-06-05 12:59:26 -0400804} // namespace gl