blob: 7853a00b8b1ac4cd62cfb3d1eeb2018105fdc0df [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
Jamie Madill97ee6542017-06-07 17:06:05 -0400201 unsigned int low = stream.readInt<unsigned int>();
202 unsigned int high = stream.readInt<unsigned int>();
Jamie Madill4f86d052017-06-05 12:59:26 -0400203 state->mSamplerUniformRange = RangeUI(low, high);
204
205 unsigned int samplerCount = stream.readInt<unsigned int>();
206 for (unsigned int samplerIndex = 0; samplerIndex < samplerCount; ++samplerIndex)
207 {
208 GLenum textureType = stream.readInt<GLenum>();
209 size_t bindingCount = stream.readInt<size_t>();
210 state->mSamplerBindings.emplace_back(SamplerBinding(textureType, bindingCount));
211 }
212
213 return program->getImplementation()->load(context, infoLog, &stream);
214}
215
216// static
217void MemoryProgramCache::Serialize(const Context *context,
218 const gl::Program *program,
219 angle::MemoryBuffer *binaryOut)
220{
221 BinaryOutputStream stream;
222
223 stream.writeBytes(reinterpret_cast<const unsigned char *>(ANGLE_COMMIT_HASH),
224 ANGLE_COMMIT_HASH_SIZE);
225
226 // nullptr context is supported when computing binary length.
227 if (context)
228 {
229 stream.writeInt(context->getClientVersion().major);
230 stream.writeInt(context->getClientVersion().minor);
231 }
232 else
233 {
234 stream.writeInt(2);
235 stream.writeInt(0);
236 }
237
238 const auto &state = program->getState();
239
240 const auto &computeLocalSize = state.getComputeShaderLocalSize();
241
242 stream.writeInt(computeLocalSize[0]);
243 stream.writeInt(computeLocalSize[1]);
244 stream.writeInt(computeLocalSize[2]);
245
246 stream.writeInt(state.getActiveAttribLocationsMask().to_ulong());
247
248 stream.writeInt(state.getAttributes().size());
249 for (const sh::Attribute &attrib : state.getAttributes())
250 {
251 WriteShaderVar(&stream, attrib);
252 stream.writeInt(attrib.location);
253 }
254
255 stream.writeInt(state.getUniforms().size());
256 for (const LinkedUniform &uniform : state.getUniforms())
257 {
258 WriteShaderVar(&stream, uniform);
259
260 // FIXME: referenced
261
262 stream.writeInt(uniform.blockIndex);
263 stream.writeInt(uniform.blockInfo.offset);
264 stream.writeInt(uniform.blockInfo.arrayStride);
265 stream.writeInt(uniform.blockInfo.matrixStride);
266 stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
267 }
268
269 stream.writeInt(state.getUniformLocations().size());
270 for (const auto &variable : state.getUniformLocations())
271 {
272 stream.writeString(variable.name);
273 stream.writeInt(variable.element);
274 stream.writeInt(variable.index);
275 stream.writeInt(variable.used);
276 stream.writeInt(variable.ignored);
277 }
278
279 stream.writeInt(state.getUniformBlocks().size());
280 for (const UniformBlock &uniformBlock : state.getUniformBlocks())
281 {
282 stream.writeString(uniformBlock.name);
283 stream.writeInt(uniformBlock.isArray);
284 stream.writeInt(uniformBlock.arrayElement);
285 stream.writeInt(uniformBlock.binding);
286 stream.writeInt(uniformBlock.dataSize);
287
288 stream.writeInt(uniformBlock.vertexStaticUse);
289 stream.writeInt(uniformBlock.fragmentStaticUse);
290
291 stream.writeInt(uniformBlock.memberUniformIndexes.size());
292 for (unsigned int memberUniformIndex : uniformBlock.memberUniformIndexes)
293 {
294 stream.writeInt(memberUniformIndex);
295 }
296 }
297
Jamie Madill4f86d052017-06-05 12:59:26 -0400298 stream.writeInt(state.getLinkedTransformFeedbackVaryings().size());
299 for (const auto &var : state.getLinkedTransformFeedbackVaryings())
300 {
301 stream.writeInt(var.arraySize);
302 stream.writeInt(var.type);
303 stream.writeString(var.name);
304
305 stream.writeIntOrNegOne(var.arrayIndex);
306 }
307
308 stream.writeInt(state.getTransformFeedbackBufferMode());
309
310 stream.writeInt(state.getOutputVariables().size());
311 for (const sh::OutputVariable &output : state.getOutputVariables())
312 {
313 WriteShaderVar(&stream, output);
314 stream.writeInt(output.location);
315 }
316
317 stream.writeInt(state.getOutputLocations().size());
318 for (const auto &outputPair : state.getOutputLocations())
319 {
320 stream.writeInt(outputPair.first);
321 stream.writeIntOrNegOne(outputPair.second.element);
322 stream.writeInt(outputPair.second.index);
323 stream.writeString(outputPair.second.name);
324 }
325
326 stream.writeInt(state.mOutputVariableTypes.size());
327 for (const auto &outputVariableType : state.mOutputVariableTypes)
328 {
329 stream.writeInt(outputVariableType);
330 }
331
332 static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS < 8 * sizeof(uint32_t),
333 "All bits of DrawBufferMask can be contained in an uint32_t");
334 stream.writeInt(static_cast<uint32_t>(state.mActiveOutputVariables.to_ulong()));
335
336 stream.writeInt(state.getSamplerUniformRange().low());
337 stream.writeInt(state.getSamplerUniformRange().high());
338
339 stream.writeInt(state.getSamplerBindings().size());
340 for (const auto &samplerBinding : state.getSamplerBindings())
341 {
342 stream.writeInt(samplerBinding.textureType);
343 stream.writeInt(samplerBinding.boundTextureUnits.size());
344 }
345
346 program->getImplementation()->save(&stream);
347
348 ASSERT(binaryOut);
349 binaryOut->resize(stream.length());
350 memcpy(binaryOut->data(), stream.data(), stream.length());
351}
352
353} // namespace gl