blob: e9340c61bb78c3ada226a1d9ced03cd1f2a91be1 [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
Jiawei Shao3dd8d2912018-03-30 09:39:09 +080069 for (ShaderType shaderType : AllShaderTypes())
70 {
71 stream->writeInt(var.isActive(shaderType));
72 }
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>();
Jiawei Shao3dd8d2912018-03-30 09:39:09 +080085
86 for (ShaderType shaderType : AllShaderTypes())
87 {
88 var->setActive(shaderType, stream->readBool());
89 }
jchen10eaef1e52017-06-13 10:44:11 +080090
91 unsigned int numMembers = stream->readInt<unsigned int>();
92 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
93 {
94 var->memberIndexes.push_back(stream->readInt<unsigned int>());
95 }
96}
97
Jiajia Qin3a9090f2017-09-27 14:37:04 +080098void WriteBufferVariable(BinaryOutputStream *stream, const BufferVariable &var)
99{
100 WriteShaderVar(stream, var);
101
102 stream->writeInt(var.bufferIndex);
103 stream->writeInt(var.blockInfo.offset);
104 stream->writeInt(var.blockInfo.arrayStride);
105 stream->writeInt(var.blockInfo.matrixStride);
106 stream->writeInt(var.blockInfo.isRowMajorMatrix);
107 stream->writeInt(var.blockInfo.topLevelArrayStride);
108 stream->writeInt(var.topLevelArraySize);
Jiawei Shao3dd8d2912018-03-30 09:39:09 +0800109
110 for (ShaderType shaderType : AllShaderTypes())
111 {
112 stream->writeInt(var.isActive(shaderType));
113 }
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800114}
115
116void LoadBufferVariable(BinaryInputStream *stream, BufferVariable *var)
117{
118 LoadShaderVar(stream, var);
119
120 var->bufferIndex = stream->readInt<int>();
121 var->blockInfo.offset = stream->readInt<int>();
122 var->blockInfo.arrayStride = stream->readInt<int>();
123 var->blockInfo.matrixStride = stream->readInt<int>();
124 var->blockInfo.isRowMajorMatrix = stream->readBool();
125 var->blockInfo.topLevelArrayStride = stream->readInt<int>();
126 var->topLevelArraySize = stream->readInt<int>();
Jiawei Shao3dd8d2912018-03-30 09:39:09 +0800127
128 for (ShaderType shaderType : AllShaderTypes())
129 {
130 var->setActive(shaderType, stream->readBool());
131 }
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800132}
133
Jiajia Qin729b2c62017-08-14 09:36:11 +0800134void WriteInterfaceBlock(BinaryOutputStream *stream, const InterfaceBlock &block)
135{
136 stream->writeString(block.name);
137 stream->writeString(block.mappedName);
138 stream->writeInt(block.isArray);
139 stream->writeInt(block.arrayElement);
140
141 WriteShaderVariableBuffer(stream, block);
142}
143
144void LoadInterfaceBlock(BinaryInputStream *stream, InterfaceBlock *block)
145{
146 block->name = stream->readString();
147 block->mappedName = stream->readString();
148 block->isArray = stream->readBool();
149 block->arrayElement = stream->readInt<unsigned int>();
150
151 LoadShaderVariableBuffer(stream, block);
152}
153
Jamie Madill32447362017-06-28 14:53:52 -0400154class HashStream final : angle::NonCopyable
155{
156 public:
157 std::string str() { return mStringStream.str(); }
158
159 template <typename T>
160 HashStream &operator<<(T value)
161 {
162 mStringStream << value << kSeparator;
163 return *this;
164 }
165
166 private:
167 static constexpr char kSeparator = ':';
168 std::ostringstream mStringStream;
169};
170
171HashStream &operator<<(HashStream &stream, const Shader *shader)
172{
173 if (shader)
174 {
175 stream << shader->getSourceString().c_str() << shader->getSourceString().length()
176 << shader->getCompilerResourcesString().c_str();
177 }
178 return stream;
179}
180
Jamie Madill3c1da042017-11-27 18:33:40 -0500181HashStream &operator<<(HashStream &stream, const ProgramBindings &bindings)
Jamie Madill32447362017-06-28 14:53:52 -0400182{
183 for (const auto &binding : bindings)
184 {
185 stream << binding.first << binding.second;
186 }
187 return stream;
188}
189
190HashStream &operator<<(HashStream &stream, const std::vector<std::string> &strings)
191{
192 for (const auto &str : strings)
193 {
194 stream << str;
195 }
196 return stream;
197}
198
Jamie Madill4f86d052017-06-05 12:59:26 -0400199} // anonymous namespace
200
Jamie Madill32447362017-06-28 14:53:52 -0400201MemoryProgramCache::MemoryProgramCache(size_t maxCacheSizeBytes)
202 : mProgramBinaryCache(maxCacheSizeBytes), mIssuedWarnings(0)
203{
204}
205
206MemoryProgramCache::~MemoryProgramCache()
207{
208}
209
Jamie Madill4f86d052017-06-05 12:59:26 -0400210// static
211LinkResult MemoryProgramCache::Deserialize(const Context *context,
212 const Program *program,
213 ProgramState *state,
214 const uint8_t *binary,
215 size_t length,
216 InfoLog &infoLog)
217{
218 BinaryInputStream stream(binary, length);
219
220 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
221 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
222 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) !=
223 0)
224 {
225 infoLog << "Invalid program binary version.";
226 return false;
227 }
228
229 int majorVersion = stream.readInt<int>();
230 int minorVersion = stream.readInt<int>();
231 if (majorVersion != context->getClientMajorVersion() ||
232 minorVersion != context->getClientMinorVersion())
233 {
234 infoLog << "Cannot load program binaries across different ES context versions.";
235 return false;
236 }
237
238 state->mComputeShaderLocalSize[0] = stream.readInt<int>();
239 state->mComputeShaderLocalSize[1] = stream.readInt<int>();
240 state->mComputeShaderLocalSize[2] = stream.readInt<int>();
241
Jiawei Shao4ed05da2018-02-02 14:26:15 +0800242 state->mGeometryShaderInputPrimitiveType = stream.readInt<GLenum>();
243 state->mGeometryShaderOutputPrimitiveType = stream.readInt<GLenum>();
244 state->mGeometryShaderInvocations = stream.readInt<int>();
245 state->mGeometryShaderMaxVertices = stream.readInt<int>();
246
Martin Radev7cf61662017-07-26 17:10:53 +0300247 state->mNumViews = stream.readInt<int>();
248
Brandon Jonesc405ae72017-12-06 14:15:03 -0800249 static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
250 "All bits of mAttributesTypeMask types and mask fit into 32 bits each");
251 state->mAttributesTypeMask.from_ulong(stream.readInt<uint32_t>());
Jamie Madill09463932018-04-04 05:26:59 -0400252 state->mAttributesMask = stream.readInt<gl::AttributesMask>();
Brandon Jonesc405ae72017-12-06 14:15:03 -0800253
Jamie Madill4f86d052017-06-05 12:59:26 -0400254 static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
255 "Too many vertex attribs for mask");
Jamie Madill09463932018-04-04 05:26:59 -0400256 state->mActiveAttribLocationsMask = stream.readInt<gl::AttributesMask>();
Jamie Madill4f86d052017-06-05 12:59:26 -0400257
258 unsigned int attribCount = stream.readInt<unsigned int>();
259 ASSERT(state->mAttributes.empty());
260 for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
261 {
262 sh::Attribute attrib;
263 LoadShaderVar(&stream, &attrib);
264 attrib.location = stream.readInt<int>();
265 state->mAttributes.push_back(attrib);
266 }
267
268 unsigned int uniformCount = stream.readInt<unsigned int>();
269 ASSERT(state->mUniforms.empty());
270 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
271 {
272 LinkedUniform uniform;
273 LoadShaderVar(&stream, &uniform);
274
jchen10eaef1e52017-06-13 10:44:11 +0800275 uniform.bufferIndex = stream.readInt<int>();
Jamie Madill4f86d052017-06-05 12:59:26 -0400276 uniform.blockInfo.offset = stream.readInt<int>();
277 uniform.blockInfo.arrayStride = stream.readInt<int>();
278 uniform.blockInfo.matrixStride = stream.readInt<int>();
279 uniform.blockInfo.isRowMajorMatrix = stream.readBool();
280
Jamie Madillf00f7ff2017-08-31 14:39:15 -0400281 uniform.typeInfo = &GetUniformTypeInfo(uniform.type);
282
Jamie Madill4f86d052017-06-05 12:59:26 -0400283 state->mUniforms.push_back(uniform);
284 }
285
286 const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
287 ASSERT(state->mUniformLocations.empty());
288 for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount;
289 uniformIndexIndex++)
290 {
291 VariableLocation variable;
Olli Etuaho1734e172017-10-27 15:30:27 +0300292 stream.readInt(&variable.arrayIndex);
Jamie Madill4f86d052017-06-05 12:59:26 -0400293 stream.readInt(&variable.index);
Jamie Madill4f86d052017-06-05 12:59:26 -0400294 stream.readBool(&variable.ignored);
295
296 state->mUniformLocations.push_back(variable);
297 }
298
299 unsigned int uniformBlockCount = stream.readInt<unsigned int>();
300 ASSERT(state->mUniformBlocks.empty());
301 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
302 ++uniformBlockIndex)
303 {
Jiajia Qin729b2c62017-08-14 09:36:11 +0800304 InterfaceBlock uniformBlock;
305 LoadInterfaceBlock(&stream, &uniformBlock);
Jamie Madill4f86d052017-06-05 12:59:26 -0400306 state->mUniformBlocks.push_back(uniformBlock);
Jamie Madill4f86d052017-06-05 12:59:26 -0400307
jchen107a20b972017-06-13 14:25:26 +0800308 state->mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlock.binding != 0);
Jamie Madill4f86d052017-06-05 12:59:26 -0400309 }
Jiajia Qin729b2c62017-08-14 09:36:11 +0800310
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800311 unsigned int bufferVariableCount = stream.readInt<unsigned int>();
312 ASSERT(state->mBufferVariables.empty());
313 for (unsigned int index = 0; index < bufferVariableCount; ++index)
314 {
315 BufferVariable bufferVariable;
316 LoadBufferVariable(&stream, &bufferVariable);
317 state->mBufferVariables.push_back(bufferVariable);
318 }
319
Jiajia Qin729b2c62017-08-14 09:36:11 +0800320 unsigned int shaderStorageBlockCount = stream.readInt<unsigned int>();
321 ASSERT(state->mShaderStorageBlocks.empty());
322 for (unsigned int shaderStorageBlockIndex = 0;
323 shaderStorageBlockIndex < shaderStorageBlockCount; ++shaderStorageBlockIndex)
324 {
325 InterfaceBlock shaderStorageBlock;
326 LoadInterfaceBlock(&stream, &shaderStorageBlock);
327 state->mShaderStorageBlocks.push_back(shaderStorageBlock);
328 }
329
jchen10eaef1e52017-06-13 10:44:11 +0800330 unsigned int atomicCounterBufferCount = stream.readInt<unsigned int>();
331 ASSERT(state->mAtomicCounterBuffers.empty());
332 for (unsigned int bufferIndex = 0; bufferIndex < atomicCounterBufferCount; ++bufferIndex)
333 {
334 AtomicCounterBuffer atomicCounterBuffer;
335 LoadShaderVariableBuffer(&stream, &atomicCounterBuffer);
336
337 state->mAtomicCounterBuffers.push_back(atomicCounterBuffer);
338 }
Jamie Madill4f86d052017-06-05 12:59:26 -0400339
340 unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
Jamie Madillffe00c02017-06-27 16:26:55 -0400341
342 // Reject programs that use transform feedback varyings if the hardware cannot support them.
343 if (transformFeedbackVaryingCount > 0 &&
344 context->getWorkarounds().disableProgramCachingForTransformFeedback)
345 {
346 infoLog << "Current driver does not support transform feedback in binary programs.";
347 return false;
348 }
349
Jamie Madill4f86d052017-06-05 12:59:26 -0400350 ASSERT(state->mLinkedTransformFeedbackVaryings.empty());
351 for (unsigned int transformFeedbackVaryingIndex = 0;
352 transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
353 ++transformFeedbackVaryingIndex)
354 {
355 sh::Varying varying;
Olli Etuaho465835d2017-09-26 13:34:10 +0300356 stream.readIntVector<unsigned int>(&varying.arraySizes);
Jamie Madill4f86d052017-06-05 12:59:26 -0400357 stream.readInt(&varying.type);
358 stream.readString(&varying.name);
359
360 GLuint arrayIndex = stream.readInt<GLuint>();
361
362 state->mLinkedTransformFeedbackVaryings.emplace_back(varying, arrayIndex);
363 }
364
365 stream.readInt(&state->mTransformFeedbackBufferMode);
366
367 unsigned int outputCount = stream.readInt<unsigned int>();
368 ASSERT(state->mOutputVariables.empty());
369 for (unsigned int outputIndex = 0; outputIndex < outputCount; ++outputIndex)
370 {
371 sh::OutputVariable output;
372 LoadShaderVar(&stream, &output);
373 output.location = stream.readInt<int>();
374 state->mOutputVariables.push_back(output);
375 }
376
377 unsigned int outputVarCount = stream.readInt<unsigned int>();
Olli Etuahod2551232017-10-26 20:03:33 +0300378 ASSERT(state->mOutputLocations.empty());
Jamie Madill4f86d052017-06-05 12:59:26 -0400379 for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
380 {
Jamie Madill4f86d052017-06-05 12:59:26 -0400381 VariableLocation locationData;
Olli Etuaho1734e172017-10-27 15:30:27 +0300382 stream.readInt(&locationData.arrayIndex);
Jamie Madill4f86d052017-06-05 12:59:26 -0400383 stream.readInt(&locationData.index);
Jamie Madillfb997ec2017-09-20 15:44:27 -0400384 stream.readBool(&locationData.ignored);
Olli Etuahod2551232017-10-26 20:03:33 +0300385 state->mOutputLocations.push_back(locationData);
Jamie Madill4f86d052017-06-05 12:59:26 -0400386 }
387
388 unsigned int outputTypeCount = stream.readInt<unsigned int>();
389 for (unsigned int outputIndex = 0; outputIndex < outputTypeCount; ++outputIndex)
390 {
391 state->mOutputVariableTypes.push_back(stream.readInt<GLenum>());
392 }
Brandon Jones76746f92017-11-22 11:44:41 -0800393
Brandon Jonesc405ae72017-12-06 14:15:03 -0800394 static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS * 2 <= 8 * sizeof(uint32_t),
395 "All bits of mDrawBufferTypeMask and mActiveOutputVariables types and mask fit "
396 "into 32 bits each");
397 state->mDrawBufferTypeMask.from_ulong(stream.readInt<uint32_t>());
Jamie Madill09463932018-04-04 05:26:59 -0400398 state->mActiveOutputVariables = stream.readInt<gl::DrawBufferMask>();
Jamie Madill4f86d052017-06-05 12:59:26 -0400399
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800400 unsigned int samplerRangeLow = stream.readInt<unsigned int>();
401 unsigned int samplerRangeHigh = stream.readInt<unsigned int>();
402 state->mSamplerUniformRange = RangeUI(samplerRangeLow, samplerRangeHigh);
Jamie Madill4f86d052017-06-05 12:59:26 -0400403 unsigned int samplerCount = stream.readInt<unsigned int>();
404 for (unsigned int samplerIndex = 0; samplerIndex < samplerCount; ++samplerIndex)
405 {
Corentin Wallezf0e89be2017-11-08 14:00:32 -0800406 TextureType textureType = stream.readEnum<TextureType>();
Jamie Madill4f86d052017-06-05 12:59:26 -0400407 size_t bindingCount = stream.readInt<size_t>();
Jamie Madill54164b02017-08-28 15:17:37 -0400408 bool unreferenced = stream.readBool();
409 state->mSamplerBindings.emplace_back(
410 SamplerBinding(textureType, bindingCount, unreferenced));
Jamie Madill4f86d052017-06-05 12:59:26 -0400411 }
412
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800413 unsigned int imageRangeLow = stream.readInt<unsigned int>();
414 unsigned int imageRangeHigh = stream.readInt<unsigned int>();
415 state->mImageUniformRange = RangeUI(imageRangeLow, imageRangeHigh);
Xinghua Cao0328b572017-06-26 15:51:36 +0800416 unsigned int imageBindingCount = stream.readInt<unsigned int>();
417 for (unsigned int imageIndex = 0; imageIndex < imageBindingCount; ++imageIndex)
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800418 {
Xinghua Cao0328b572017-06-26 15:51:36 +0800419 unsigned int elementCount = stream.readInt<unsigned int>();
420 ImageBinding imageBinding(elementCount);
421 for (unsigned int i = 0; i < elementCount; ++i)
422 {
423 imageBinding.boundImageUnits[i] = stream.readInt<unsigned int>();
424 }
425 state->mImageBindings.emplace_back(imageBinding);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800426 }
427
jchen10eaef1e52017-06-13 10:44:11 +0800428 unsigned int atomicCounterRangeLow = stream.readInt<unsigned int>();
429 unsigned int atomicCounterRangeHigh = stream.readInt<unsigned int>();
430 state->mAtomicCounterUniformRange = RangeUI(atomicCounterRangeLow, atomicCounterRangeHigh);
431
Jiawei Shao385b3e02018-03-21 09:43:28 +0800432 static_assert(static_cast<unsigned long>(ShaderType::EnumCount) <= sizeof(unsigned long) * 8,
433 "Too many shader types");
Jiawei Shao3dd8d2912018-03-30 09:39:09 +0800434 state->mLinkedShaderStages = stream.readInt<gl::ShaderBitSet>();
Yunchao He85072e82017-11-14 15:43:28 +0800435
James Darpinian30b604d2018-03-12 17:26:57 -0700436 state->updateTransformFeedbackStrides();
437
Jamie Madill4f86d052017-06-05 12:59:26 -0400438 return program->getImplementation()->load(context, infoLog, &stream);
439}
440
441// static
442void MemoryProgramCache::Serialize(const Context *context,
443 const gl::Program *program,
444 angle::MemoryBuffer *binaryOut)
445{
446 BinaryOutputStream stream;
447
448 stream.writeBytes(reinterpret_cast<const unsigned char *>(ANGLE_COMMIT_HASH),
449 ANGLE_COMMIT_HASH_SIZE);
450
451 // nullptr context is supported when computing binary length.
452 if (context)
453 {
454 stream.writeInt(context->getClientVersion().major);
455 stream.writeInt(context->getClientVersion().minor);
456 }
457 else
458 {
459 stream.writeInt(2);
460 stream.writeInt(0);
461 }
462
463 const auto &state = program->getState();
464
465 const auto &computeLocalSize = state.getComputeShaderLocalSize();
466
467 stream.writeInt(computeLocalSize[0]);
468 stream.writeInt(computeLocalSize[1]);
469 stream.writeInt(computeLocalSize[2]);
470
Jiawei Shao4ed05da2018-02-02 14:26:15 +0800471 ASSERT(state.mGeometryShaderInvocations >= 1 && state.mGeometryShaderMaxVertices >= 0);
472 stream.writeInt(state.mGeometryShaderInputPrimitiveType);
473 stream.writeInt(state.mGeometryShaderOutputPrimitiveType);
474 stream.writeInt(state.mGeometryShaderInvocations);
475 stream.writeInt(state.mGeometryShaderMaxVertices);
476
Martin Radev7cf61662017-07-26 17:10:53 +0300477 stream.writeInt(state.mNumViews);
478
Brandon Jonesc405ae72017-12-06 14:15:03 -0800479 static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
480 "All bits of mAttributesTypeMask types and mask fit into 32 bits each");
481 stream.writeInt(static_cast<int>(state.mAttributesTypeMask.to_ulong()));
482 stream.writeInt(static_cast<int>(state.mAttributesMask.to_ulong()));
483
Jamie Madill4f86d052017-06-05 12:59:26 -0400484 stream.writeInt(state.getActiveAttribLocationsMask().to_ulong());
485
486 stream.writeInt(state.getAttributes().size());
487 for (const sh::Attribute &attrib : state.getAttributes())
488 {
489 WriteShaderVar(&stream, attrib);
490 stream.writeInt(attrib.location);
491 }
492
493 stream.writeInt(state.getUniforms().size());
494 for (const LinkedUniform &uniform : state.getUniforms())
495 {
496 WriteShaderVar(&stream, uniform);
497
498 // FIXME: referenced
499
jchen10eaef1e52017-06-13 10:44:11 +0800500 stream.writeInt(uniform.bufferIndex);
Jamie Madill4f86d052017-06-05 12:59:26 -0400501 stream.writeInt(uniform.blockInfo.offset);
502 stream.writeInt(uniform.blockInfo.arrayStride);
503 stream.writeInt(uniform.blockInfo.matrixStride);
504 stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
505 }
506
507 stream.writeInt(state.getUniformLocations().size());
508 for (const auto &variable : state.getUniformLocations())
509 {
Olli Etuaho1734e172017-10-27 15:30:27 +0300510 stream.writeInt(variable.arrayIndex);
Jamie Madillfb997ec2017-09-20 15:44:27 -0400511 stream.writeIntOrNegOne(variable.index);
Jamie Madill4f86d052017-06-05 12:59:26 -0400512 stream.writeInt(variable.ignored);
513 }
514
515 stream.writeInt(state.getUniformBlocks().size());
Jiajia Qin729b2c62017-08-14 09:36:11 +0800516 for (const InterfaceBlock &uniformBlock : state.getUniformBlocks())
Jamie Madill4f86d052017-06-05 12:59:26 -0400517 {
Jiajia Qin729b2c62017-08-14 09:36:11 +0800518 WriteInterfaceBlock(&stream, uniformBlock);
519 }
Jamie Madill4f86d052017-06-05 12:59:26 -0400520
Jiajia Qin3a9090f2017-09-27 14:37:04 +0800521 stream.writeInt(state.getBufferVariables().size());
522 for (const BufferVariable &bufferVariable : state.getBufferVariables())
523 {
524 WriteBufferVariable(&stream, bufferVariable);
525 }
526
Jiajia Qin729b2c62017-08-14 09:36:11 +0800527 stream.writeInt(state.getShaderStorageBlocks().size());
528 for (const InterfaceBlock &shaderStorageBlock : state.getShaderStorageBlocks())
529 {
530 WriteInterfaceBlock(&stream, shaderStorageBlock);
jchen10eaef1e52017-06-13 10:44:11 +0800531 }
Jamie Madill4f86d052017-06-05 12:59:26 -0400532
jchen10eaef1e52017-06-13 10:44:11 +0800533 stream.writeInt(state.mAtomicCounterBuffers.size());
534 for (const auto &atomicCounterBuffer : state.mAtomicCounterBuffers)
535 {
536 WriteShaderVariableBuffer(&stream, atomicCounterBuffer);
Jamie Madill4f86d052017-06-05 12:59:26 -0400537 }
538
Jamie Madillffe00c02017-06-27 16:26:55 -0400539 // Warn the app layer if saving a binary with unsupported transform feedback.
540 if (!state.getLinkedTransformFeedbackVaryings().empty() &&
541 context->getWorkarounds().disableProgramCachingForTransformFeedback)
542 {
543 WARN() << "Saving program binary with transform feedback, which is not supported on this "
544 "driver.";
545 }
546
Jamie Madill4f86d052017-06-05 12:59:26 -0400547 stream.writeInt(state.getLinkedTransformFeedbackVaryings().size());
548 for (const auto &var : state.getLinkedTransformFeedbackVaryings())
549 {
Olli Etuaho465835d2017-09-26 13:34:10 +0300550 stream.writeIntVector(var.arraySizes);
Jamie Madill4f86d052017-06-05 12:59:26 -0400551 stream.writeInt(var.type);
552 stream.writeString(var.name);
553
554 stream.writeIntOrNegOne(var.arrayIndex);
555 }
556
557 stream.writeInt(state.getTransformFeedbackBufferMode());
558
559 stream.writeInt(state.getOutputVariables().size());
560 for (const sh::OutputVariable &output : state.getOutputVariables())
561 {
562 WriteShaderVar(&stream, output);
563 stream.writeInt(output.location);
564 }
565
566 stream.writeInt(state.getOutputLocations().size());
Olli Etuahod2551232017-10-26 20:03:33 +0300567 for (const auto &outputVar : state.getOutputLocations())
Jamie Madill4f86d052017-06-05 12:59:26 -0400568 {
Olli Etuaho1734e172017-10-27 15:30:27 +0300569 stream.writeInt(outputVar.arrayIndex);
Olli Etuahod2551232017-10-26 20:03:33 +0300570 stream.writeIntOrNegOne(outputVar.index);
Olli Etuahod2551232017-10-26 20:03:33 +0300571 stream.writeInt(outputVar.ignored);
Jamie Madill4f86d052017-06-05 12:59:26 -0400572 }
573
574 stream.writeInt(state.mOutputVariableTypes.size());
575 for (const auto &outputVariableType : state.mOutputVariableTypes)
576 {
577 stream.writeInt(outputVariableType);
578 }
579
Brandon Jonesc405ae72017-12-06 14:15:03 -0800580 static_assert(
581 IMPLEMENTATION_MAX_DRAW_BUFFERS * 2 <= 8 * sizeof(uint32_t),
582 "All bits of mDrawBufferTypeMask and mActiveOutputVariables can be contained in 32 bits");
583 stream.writeInt(static_cast<int>(state.mDrawBufferTypeMask.to_ulong()));
584 stream.writeInt(static_cast<int>(state.mActiveOutputVariables.to_ulong()));
Jamie Madill4f86d052017-06-05 12:59:26 -0400585
586 stream.writeInt(state.getSamplerUniformRange().low());
587 stream.writeInt(state.getSamplerUniformRange().high());
588
589 stream.writeInt(state.getSamplerBindings().size());
590 for (const auto &samplerBinding : state.getSamplerBindings())
591 {
Corentin Wallezf0e89be2017-11-08 14:00:32 -0800592 stream.writeEnum(samplerBinding.textureType);
Jamie Madill4f86d052017-06-05 12:59:26 -0400593 stream.writeInt(samplerBinding.boundTextureUnits.size());
Jamie Madill54164b02017-08-28 15:17:37 -0400594 stream.writeInt(samplerBinding.unreferenced);
Jamie Madill4f86d052017-06-05 12:59:26 -0400595 }
596
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800597 stream.writeInt(state.getImageUniformRange().low());
598 stream.writeInt(state.getImageUniformRange().high());
599
600 stream.writeInt(state.getImageBindings().size());
601 for (const auto &imageBinding : state.getImageBindings())
602 {
Xinghua Cao0328b572017-06-26 15:51:36 +0800603 stream.writeInt(imageBinding.boundImageUnits.size());
604 for (size_t i = 0; i < imageBinding.boundImageUnits.size(); ++i)
605 {
606 stream.writeInt(imageBinding.boundImageUnits[i]);
607 }
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800608 }
609
jchen10eaef1e52017-06-13 10:44:11 +0800610 stream.writeInt(state.getAtomicCounterUniformRange().low());
611 stream.writeInt(state.getAtomicCounterUniformRange().high());
612
Yunchao He85072e82017-11-14 15:43:28 +0800613 stream.writeInt(state.getLinkedShaderStages().to_ulong());
614
Jamie Madill27a60632017-06-30 15:12:01 -0400615 program->getImplementation()->save(context, &stream);
Jamie Madill4f86d052017-06-05 12:59:26 -0400616
617 ASSERT(binaryOut);
618 binaryOut->resize(stream.length());
619 memcpy(binaryOut->data(), stream.data(), stream.length());
620}
621
Jamie Madill32447362017-06-28 14:53:52 -0400622// static
623void MemoryProgramCache::ComputeHash(const Context *context,
624 const Program *program,
625 ProgramHash *hashOut)
626{
Jamie Madill32447362017-06-28 14:53:52 -0400627 // Compute the program hash. Start with the shader hashes and resource strings.
628 HashStream hashStream;
Jiawei Shao385b3e02018-03-21 09:43:28 +0800629 for (ShaderType shaderType : AllShaderTypes())
630 {
631 hashStream << program->getAttachedShader(shaderType);
632 }
Jamie Madill32447362017-06-28 14:53:52 -0400633
634 // Add some ANGLE metadata and Context properties, such as version and back-end.
635 hashStream << ANGLE_COMMIT_HASH << context->getClientMajorVersion()
636 << context->getClientMinorVersion() << context->getString(GL_RENDERER);
637
638 // Hash pre-link program properties.
639 hashStream << program->getAttributeBindings() << program->getUniformLocationBindings()
640 << program->getFragmentInputBindings()
641 << program->getState().getTransformFeedbackVaryingNames()
642 << program->getState().getTransformFeedbackBufferMode();
643
644 // Call the secure SHA hashing function.
645 const std::string &programKey = hashStream.str();
646 angle::base::SHA1HashBytes(reinterpret_cast<const unsigned char *>(programKey.c_str()),
647 programKey.length(), hashOut->data());
648}
649
650LinkResult MemoryProgramCache::getProgram(const Context *context,
651 const Program *program,
652 ProgramState *state,
653 ProgramHash *hashOut)
654{
655 ComputeHash(context, program, hashOut);
656 const angle::MemoryBuffer *binaryProgram = nullptr;
657 LinkResult result(false);
658 if (get(*hashOut, &binaryProgram))
659 {
660 InfoLog infoLog;
661 ANGLE_TRY_RESULT(Deserialize(context, program, state, binaryProgram->data(),
662 binaryProgram->size(), infoLog),
663 result);
Jamie Madill6c58b062017-08-01 13:44:25 -0400664 ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ProgramCache.LoadBinarySuccess", result.getResult());
Jamie Madill32447362017-06-28 14:53:52 -0400665 if (!result.getResult())
666 {
667 // Cache load failed, evict.
668 if (mIssuedWarnings++ < kWarningLimit)
669 {
670 WARN() << "Failed to load binary from cache: " << infoLog.str();
671
672 if (mIssuedWarnings == kWarningLimit)
673 {
674 WARN() << "Reaching warning limit for cache load failures, silencing "
675 "subsequent warnings.";
676 }
677 }
678 remove(*hashOut);
679 }
680 }
681 return result;
682}
683
684bool MemoryProgramCache::get(const ProgramHash &programHash, const angle::MemoryBuffer **programOut)
685{
Jamie Madill6c58b062017-08-01 13:44:25 -0400686 const CacheEntry *entry = nullptr;
687 if (!mProgramBinaryCache.get(programHash, &entry))
688 {
689 ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.ProgramCache.CacheResult", kCacheMiss,
690 kCacheResultMax);
691 return false;
692 }
693
694 if (entry->second == CacheSource::PutProgram)
695 {
696 ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.ProgramCache.CacheResult", kCacheHitMemory,
697 kCacheResultMax);
698 }
699 else
700 {
701 ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.ProgramCache.CacheResult", kCacheHitDisk,
702 kCacheResultMax);
703 }
704
705 *programOut = &entry->first;
706 return true;
Jamie Madill32447362017-06-28 14:53:52 -0400707}
708
Jamie Madillc43be722017-07-13 16:22:14 -0400709bool MemoryProgramCache::getAt(size_t index,
710 ProgramHash *hashOut,
711 const angle::MemoryBuffer **programOut)
712{
Jamie Madill6c58b062017-08-01 13:44:25 -0400713 const CacheEntry *entry = nullptr;
714 if (!mProgramBinaryCache.getAt(index, hashOut, &entry))
715 {
716 return false;
717 }
718
719 *programOut = &entry->first;
720 return true;
Jamie Madillc43be722017-07-13 16:22:14 -0400721}
722
Jamie Madill32447362017-06-28 14:53:52 -0400723void MemoryProgramCache::remove(const ProgramHash &programHash)
724{
725 bool result = mProgramBinaryCache.eraseByKey(programHash);
726 ASSERT(result);
727}
728
Jamie Madill6c58b062017-08-01 13:44:25 -0400729void MemoryProgramCache::putProgram(const ProgramHash &programHash,
730 const Context *context,
731 const Program *program)
Jamie Madill32447362017-06-28 14:53:52 -0400732{
Jamie Madill6c58b062017-08-01 13:44:25 -0400733 CacheEntry newEntry;
734 Serialize(context, program, &newEntry.first);
735 newEntry.second = CacheSource::PutProgram;
736
737 ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramBinarySizeBytes",
738 static_cast<int>(newEntry.first.size()));
739
740 const CacheEntry *result =
741 mProgramBinaryCache.put(programHash, std::move(newEntry), newEntry.first.size());
Jamie Madill360daee2017-06-29 10:36:19 -0400742 if (!result)
Jamie Madill32447362017-06-28 14:53:52 -0400743 {
744 ERR() << "Failed to store binary program in memory cache, program is too large.";
745 }
Jamie Madill360daee2017-06-29 10:36:19 -0400746 else
747 {
748 auto *platform = ANGLEPlatformCurrent();
Jamie Madill6c58b062017-08-01 13:44:25 -0400749 platform->cacheProgram(platform, programHash, result->first.size(), result->first.data());
Jamie Madill360daee2017-06-29 10:36:19 -0400750 }
Jamie Madill32447362017-06-28 14:53:52 -0400751}
752
Jamie Madill4c19a8a2017-07-24 11:46:06 -0400753void MemoryProgramCache::updateProgram(const Context *context, const Program *program)
754{
755 gl::ProgramHash programHash;
756 ComputeHash(context, program, &programHash);
757 putProgram(programHash, context, program);
758}
759
Jamie Madillc43be722017-07-13 16:22:14 -0400760void MemoryProgramCache::putBinary(const ProgramHash &programHash,
Jamie Madill32447362017-06-28 14:53:52 -0400761 const uint8_t *binary,
762 size_t length)
763{
764 // Copy the binary.
Jamie Madill6c58b062017-08-01 13:44:25 -0400765 CacheEntry newEntry;
766 newEntry.first.resize(length);
767 memcpy(newEntry.first.data(), binary, length);
768 newEntry.second = CacheSource::PutBinary;
Jamie Madill32447362017-06-28 14:53:52 -0400769
Jamie Madill32447362017-06-28 14:53:52 -0400770 // Store the binary.
Jamie Madill6c58b062017-08-01 13:44:25 -0400771 const CacheEntry *result = mProgramBinaryCache.put(programHash, std::move(newEntry), length);
Jamie Madillc43be722017-07-13 16:22:14 -0400772 if (!result)
773 {
774 ERR() << "Failed to store binary program in memory cache, program is too large.";
775 }
Jamie Madill32447362017-06-28 14:53:52 -0400776}
777
778void MemoryProgramCache::clear()
779{
780 mProgramBinaryCache.clear();
781 mIssuedWarnings = 0;
782}
783
Jamie Madillc43be722017-07-13 16:22:14 -0400784void MemoryProgramCache::resize(size_t maxCacheSizeBytes)
785{
786 mProgramBinaryCache.resize(maxCacheSizeBytes);
787}
788
789size_t MemoryProgramCache::entryCount() const
790{
791 return mProgramBinaryCache.entryCount();
792}
793
794size_t MemoryProgramCache::trim(size_t limit)
795{
796 return mProgramBinaryCache.shrinkToSize(limit);
797}
798
799size_t MemoryProgramCache::size() const
800{
801 return mProgramBinaryCache.size();
802}
803
804size_t MemoryProgramCache::maxSize() const
805{
806 return mProgramBinaryCache.maxSize();
807}
808
Jamie Madill4f86d052017-06-05 12:59:26 -0400809} // namespace gl