blob: a7c6dc1d9a85d7ea6da25c0bc317d5dd8805fd05 [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>
13
14#include "common/version.h"
15#include "libANGLE/BinaryStream.h"
16#include "libANGLE/Context.h"
17#include "libANGLE/Uniform.h"
18#include "libANGLE/renderer/ProgramImpl.h"
19
20namespace gl
21{
22
23namespace
24{
25
26void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var)
27{
28 stream->writeInt(var.type);
29 stream->writeInt(var.precision);
30 stream->writeString(var.name);
31 stream->writeString(var.mappedName);
32 stream->writeInt(var.arraySize);
33 stream->writeInt(var.staticUse);
34 stream->writeString(var.structName);
35 ASSERT(var.fields.empty());
36}
37
38void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var)
39{
40 var->type = stream->readInt<GLenum>();
41 var->precision = stream->readInt<GLenum>();
42 var->name = stream->readString();
43 var->mappedName = stream->readString();
44 var->arraySize = stream->readInt<unsigned int>();
45 var->staticUse = stream->readBool();
46 var->structName = stream->readString();
47}
48
49} // anonymous namespace
50
51// static
52LinkResult MemoryProgramCache::Deserialize(const Context *context,
53 const Program *program,
54 ProgramState *state,
55 const uint8_t *binary,
56 size_t length,
57 InfoLog &infoLog)
58{
59 BinaryInputStream stream(binary, length);
60
61 unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
62 stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
63 if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) !=
64 0)
65 {
66 infoLog << "Invalid program binary version.";
67 return false;
68 }
69
70 int majorVersion = stream.readInt<int>();
71 int minorVersion = stream.readInt<int>();
72 if (majorVersion != context->getClientMajorVersion() ||
73 minorVersion != context->getClientMinorVersion())
74 {
75 infoLog << "Cannot load program binaries across different ES context versions.";
76 return false;
77 }
78
79 state->mComputeShaderLocalSize[0] = stream.readInt<int>();
80 state->mComputeShaderLocalSize[1] = stream.readInt<int>();
81 state->mComputeShaderLocalSize[2] = stream.readInt<int>();
82
83 static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
84 "Too many vertex attribs for mask");
85 state->mActiveAttribLocationsMask = stream.readInt<unsigned long>();
86
87 unsigned int attribCount = stream.readInt<unsigned int>();
88 ASSERT(state->mAttributes.empty());
89 for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
90 {
91 sh::Attribute attrib;
92 LoadShaderVar(&stream, &attrib);
93 attrib.location = stream.readInt<int>();
94 state->mAttributes.push_back(attrib);
95 }
96
97 unsigned int uniformCount = stream.readInt<unsigned int>();
98 ASSERT(state->mUniforms.empty());
99 for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
100 {
101 LinkedUniform uniform;
102 LoadShaderVar(&stream, &uniform);
103
104 uniform.blockIndex = stream.readInt<int>();
105 uniform.blockInfo.offset = stream.readInt<int>();
106 uniform.blockInfo.arrayStride = stream.readInt<int>();
107 uniform.blockInfo.matrixStride = stream.readInt<int>();
108 uniform.blockInfo.isRowMajorMatrix = stream.readBool();
109
110 state->mUniforms.push_back(uniform);
111 }
112
113 const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
114 ASSERT(state->mUniformLocations.empty());
115 for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount;
116 uniformIndexIndex++)
117 {
118 VariableLocation variable;
119 stream.readString(&variable.name);
120 stream.readInt(&variable.element);
121 stream.readInt(&variable.index);
122 stream.readBool(&variable.used);
123 stream.readBool(&variable.ignored);
124
125 state->mUniformLocations.push_back(variable);
126 }
127
128 unsigned int uniformBlockCount = stream.readInt<unsigned int>();
129 ASSERT(state->mUniformBlocks.empty());
130 for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
131 ++uniformBlockIndex)
132 {
133 UniformBlock uniformBlock;
134 stream.readString(&uniformBlock.name);
135 stream.readBool(&uniformBlock.isArray);
136 stream.readInt(&uniformBlock.arrayElement);
137 stream.readInt(&uniformBlock.binding);
138 stream.readInt(&uniformBlock.dataSize);
139 stream.readBool(&uniformBlock.vertexStaticUse);
140 stream.readBool(&uniformBlock.fragmentStaticUse);
141
142 unsigned int numMembers = stream.readInt<unsigned int>();
143 for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
144 {
145 uniformBlock.memberUniformIndexes.push_back(stream.readInt<unsigned int>());
146 }
147
148 state->mUniformBlocks.push_back(uniformBlock);
Jamie Madill4f86d052017-06-05 12:59:26 -0400149
jchen107a20b972017-06-13 14:25:26 +0800150 state->mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlock.binding != 0);
Jamie Madill4f86d052017-06-05 12:59:26 -0400151 }
152
153 unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
154 ASSERT(state->mLinkedTransformFeedbackVaryings.empty());
155 for (unsigned int transformFeedbackVaryingIndex = 0;
156 transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
157 ++transformFeedbackVaryingIndex)
158 {
159 sh::Varying varying;
160 stream.readInt(&varying.arraySize);
161 stream.readInt(&varying.type);
162 stream.readString(&varying.name);
163
164 GLuint arrayIndex = stream.readInt<GLuint>();
165
166 state->mLinkedTransformFeedbackVaryings.emplace_back(varying, arrayIndex);
167 }
168
169 stream.readInt(&state->mTransformFeedbackBufferMode);
170
171 unsigned int outputCount = stream.readInt<unsigned int>();
172 ASSERT(state->mOutputVariables.empty());
173 for (unsigned int outputIndex = 0; outputIndex < outputCount; ++outputIndex)
174 {
175 sh::OutputVariable output;
176 LoadShaderVar(&stream, &output);
177 output.location = stream.readInt<int>();
178 state->mOutputVariables.push_back(output);
179 }
180
181 unsigned int outputVarCount = stream.readInt<unsigned int>();
182 for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
183 {
184 int locationIndex = stream.readInt<int>();
185 VariableLocation locationData;
186 stream.readInt(&locationData.element);
187 stream.readInt(&locationData.index);
188 stream.readString(&locationData.name);
189 state->mOutputLocations[locationIndex] = locationData;
190 }
191
192 unsigned int outputTypeCount = stream.readInt<unsigned int>();
193 for (unsigned int outputIndex = 0; outputIndex < outputTypeCount; ++outputIndex)
194 {
195 state->mOutputVariableTypes.push_back(stream.readInt<GLenum>());
196 }
197 static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS < 8 * sizeof(uint32_t),
198 "All bits of DrawBufferMask can be contained in an uint32_t");
199 state->mActiveOutputVariables = stream.readInt<uint32_t>();
200
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800201 unsigned int samplerRangeLow = stream.readInt<unsigned int>();
202 unsigned int samplerRangeHigh = stream.readInt<unsigned int>();
203 state->mSamplerUniformRange = RangeUI(samplerRangeLow, samplerRangeHigh);
Jamie Madill4f86d052017-06-05 12:59:26 -0400204 unsigned int samplerCount = stream.readInt<unsigned int>();
205 for (unsigned int samplerIndex = 0; samplerIndex < samplerCount; ++samplerIndex)
206 {
207 GLenum textureType = stream.readInt<GLenum>();
208 size_t bindingCount = stream.readInt<size_t>();
209 state->mSamplerBindings.emplace_back(SamplerBinding(textureType, bindingCount));
210 }
211
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800212 unsigned int imageRangeLow = stream.readInt<unsigned int>();
213 unsigned int imageRangeHigh = stream.readInt<unsigned int>();
214 state->mImageUniformRange = RangeUI(imageRangeLow, imageRangeHigh);
215 unsigned int imageCount = stream.readInt<unsigned int>();
216 for (unsigned int imageIndex = 0; imageIndex < imageCount; ++imageIndex)
217 {
218 GLuint boundImageUnit = stream.readInt<unsigned int>();
219 size_t elementCount = stream.readInt<size_t>();
220 state->mImageBindings.emplace_back(ImageBinding(boundImageUnit, elementCount));
221 }
222
Jamie Madill4f86d052017-06-05 12:59:26 -0400223 return program->getImplementation()->load(context, infoLog, &stream);
224}
225
226// static
227void MemoryProgramCache::Serialize(const Context *context,
228 const gl::Program *program,
229 angle::MemoryBuffer *binaryOut)
230{
231 BinaryOutputStream stream;
232
233 stream.writeBytes(reinterpret_cast<const unsigned char *>(ANGLE_COMMIT_HASH),
234 ANGLE_COMMIT_HASH_SIZE);
235
236 // nullptr context is supported when computing binary length.
237 if (context)
238 {
239 stream.writeInt(context->getClientVersion().major);
240 stream.writeInt(context->getClientVersion().minor);
241 }
242 else
243 {
244 stream.writeInt(2);
245 stream.writeInt(0);
246 }
247
248 const auto &state = program->getState();
249
250 const auto &computeLocalSize = state.getComputeShaderLocalSize();
251
252 stream.writeInt(computeLocalSize[0]);
253 stream.writeInt(computeLocalSize[1]);
254 stream.writeInt(computeLocalSize[2]);
255
256 stream.writeInt(state.getActiveAttribLocationsMask().to_ulong());
257
258 stream.writeInt(state.getAttributes().size());
259 for (const sh::Attribute &attrib : state.getAttributes())
260 {
261 WriteShaderVar(&stream, attrib);
262 stream.writeInt(attrib.location);
263 }
264
265 stream.writeInt(state.getUniforms().size());
266 for (const LinkedUniform &uniform : state.getUniforms())
267 {
268 WriteShaderVar(&stream, uniform);
269
270 // FIXME: referenced
271
272 stream.writeInt(uniform.blockIndex);
273 stream.writeInt(uniform.blockInfo.offset);
274 stream.writeInt(uniform.blockInfo.arrayStride);
275 stream.writeInt(uniform.blockInfo.matrixStride);
276 stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
277 }
278
279 stream.writeInt(state.getUniformLocations().size());
280 for (const auto &variable : state.getUniformLocations())
281 {
282 stream.writeString(variable.name);
283 stream.writeInt(variable.element);
284 stream.writeInt(variable.index);
285 stream.writeInt(variable.used);
286 stream.writeInt(variable.ignored);
287 }
288
289 stream.writeInt(state.getUniformBlocks().size());
290 for (const UniformBlock &uniformBlock : state.getUniformBlocks())
291 {
292 stream.writeString(uniformBlock.name);
293 stream.writeInt(uniformBlock.isArray);
294 stream.writeInt(uniformBlock.arrayElement);
295 stream.writeInt(uniformBlock.binding);
296 stream.writeInt(uniformBlock.dataSize);
297
298 stream.writeInt(uniformBlock.vertexStaticUse);
299 stream.writeInt(uniformBlock.fragmentStaticUse);
300
301 stream.writeInt(uniformBlock.memberUniformIndexes.size());
302 for (unsigned int memberUniformIndex : uniformBlock.memberUniformIndexes)
303 {
304 stream.writeInt(memberUniformIndex);
305 }
306 }
307
Jamie Madill4f86d052017-06-05 12:59:26 -0400308 stream.writeInt(state.getLinkedTransformFeedbackVaryings().size());
309 for (const auto &var : state.getLinkedTransformFeedbackVaryings())
310 {
311 stream.writeInt(var.arraySize);
312 stream.writeInt(var.type);
313 stream.writeString(var.name);
314
315 stream.writeIntOrNegOne(var.arrayIndex);
316 }
317
318 stream.writeInt(state.getTransformFeedbackBufferMode());
319
320 stream.writeInt(state.getOutputVariables().size());
321 for (const sh::OutputVariable &output : state.getOutputVariables())
322 {
323 WriteShaderVar(&stream, output);
324 stream.writeInt(output.location);
325 }
326
327 stream.writeInt(state.getOutputLocations().size());
328 for (const auto &outputPair : state.getOutputLocations())
329 {
330 stream.writeInt(outputPair.first);
331 stream.writeIntOrNegOne(outputPair.second.element);
332 stream.writeInt(outputPair.second.index);
333 stream.writeString(outputPair.second.name);
334 }
335
336 stream.writeInt(state.mOutputVariableTypes.size());
337 for (const auto &outputVariableType : state.mOutputVariableTypes)
338 {
339 stream.writeInt(outputVariableType);
340 }
341
342 static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS < 8 * sizeof(uint32_t),
343 "All bits of DrawBufferMask can be contained in an uint32_t");
344 stream.writeInt(static_cast<uint32_t>(state.mActiveOutputVariables.to_ulong()));
345
346 stream.writeInt(state.getSamplerUniformRange().low());
347 stream.writeInt(state.getSamplerUniformRange().high());
348
349 stream.writeInt(state.getSamplerBindings().size());
350 for (const auto &samplerBinding : state.getSamplerBindings())
351 {
352 stream.writeInt(samplerBinding.textureType);
353 stream.writeInt(samplerBinding.boundTextureUnits.size());
354 }
355
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800356 stream.writeInt(state.getImageUniformRange().low());
357 stream.writeInt(state.getImageUniformRange().high());
358
359 stream.writeInt(state.getImageBindings().size());
360 for (const auto &imageBinding : state.getImageBindings())
361 {
362 stream.writeInt(imageBinding.boundImageUnit);
363 stream.writeInt(imageBinding.elementCount);
364 }
365
Jamie Madill4f86d052017-06-05 12:59:26 -0400366 program->getImplementation()->save(&stream);
367
368 ASSERT(binaryOut);
369 binaryOut->resize(stream.length());
370 memcpy(binaryOut->data(), stream.data(), stream.length());
371}
372
373} // namespace gl