blob: f1eac54eb724d10a7ceec415e38fa57d70d94529 [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);
149 }
150
151 for (GLuint bindingIndex = 0; bindingIndex < state->mUniformBlockBindings.size();
152 ++bindingIndex)
153 {
154 stream.readInt(&state->mUniformBlockBindings[bindingIndex]);
155 state->mActiveUniformBlockBindings.set(bindingIndex,
156 state->mUniformBlockBindings[bindingIndex] != 0);
157 }
158
159 unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
160 ASSERT(state->mLinkedTransformFeedbackVaryings.empty());
161 for (unsigned int transformFeedbackVaryingIndex = 0;
162 transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
163 ++transformFeedbackVaryingIndex)
164 {
165 sh::Varying varying;
166 stream.readInt(&varying.arraySize);
167 stream.readInt(&varying.type);
168 stream.readString(&varying.name);
169
170 GLuint arrayIndex = stream.readInt<GLuint>();
171
172 state->mLinkedTransformFeedbackVaryings.emplace_back(varying, arrayIndex);
173 }
174
175 stream.readInt(&state->mTransformFeedbackBufferMode);
176
177 unsigned int outputCount = stream.readInt<unsigned int>();
178 ASSERT(state->mOutputVariables.empty());
179 for (unsigned int outputIndex = 0; outputIndex < outputCount; ++outputIndex)
180 {
181 sh::OutputVariable output;
182 LoadShaderVar(&stream, &output);
183 output.location = stream.readInt<int>();
184 state->mOutputVariables.push_back(output);
185 }
186
187 unsigned int outputVarCount = stream.readInt<unsigned int>();
188 for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
189 {
190 int locationIndex = stream.readInt<int>();
191 VariableLocation locationData;
192 stream.readInt(&locationData.element);
193 stream.readInt(&locationData.index);
194 stream.readString(&locationData.name);
195 state->mOutputLocations[locationIndex] = locationData;
196 }
197
198 unsigned int outputTypeCount = stream.readInt<unsigned int>();
199 for (unsigned int outputIndex = 0; outputIndex < outputTypeCount; ++outputIndex)
200 {
201 state->mOutputVariableTypes.push_back(stream.readInt<GLenum>());
202 }
203 static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS < 8 * sizeof(uint32_t),
204 "All bits of DrawBufferMask can be contained in an uint32_t");
205 state->mActiveOutputVariables = stream.readInt<uint32_t>();
206
207 unsigned int low = stream.readInt<unsigned int>();
208 unsigned int high = stream.readInt<unsigned int>();
209 state->mSamplerUniformRange = RangeUI(low, high);
210
211 unsigned int samplerCount = stream.readInt<unsigned int>();
212 for (unsigned int samplerIndex = 0; samplerIndex < samplerCount; ++samplerIndex)
213 {
214 GLenum textureType = stream.readInt<GLenum>();
215 size_t bindingCount = stream.readInt<size_t>();
216 state->mSamplerBindings.emplace_back(SamplerBinding(textureType, bindingCount));
217 }
218
219 return program->getImplementation()->load(context, infoLog, &stream);
220}
221
222// static
223void MemoryProgramCache::Serialize(const Context *context,
224 const gl::Program *program,
225 angle::MemoryBuffer *binaryOut)
226{
227 BinaryOutputStream stream;
228
229 stream.writeBytes(reinterpret_cast<const unsigned char *>(ANGLE_COMMIT_HASH),
230 ANGLE_COMMIT_HASH_SIZE);
231
232 // nullptr context is supported when computing binary length.
233 if (context)
234 {
235 stream.writeInt(context->getClientVersion().major);
236 stream.writeInt(context->getClientVersion().minor);
237 }
238 else
239 {
240 stream.writeInt(2);
241 stream.writeInt(0);
242 }
243
244 const auto &state = program->getState();
245
246 const auto &computeLocalSize = state.getComputeShaderLocalSize();
247
248 stream.writeInt(computeLocalSize[0]);
249 stream.writeInt(computeLocalSize[1]);
250 stream.writeInt(computeLocalSize[2]);
251
252 stream.writeInt(state.getActiveAttribLocationsMask().to_ulong());
253
254 stream.writeInt(state.getAttributes().size());
255 for (const sh::Attribute &attrib : state.getAttributes())
256 {
257 WriteShaderVar(&stream, attrib);
258 stream.writeInt(attrib.location);
259 }
260
261 stream.writeInt(state.getUniforms().size());
262 for (const LinkedUniform &uniform : state.getUniforms())
263 {
264 WriteShaderVar(&stream, uniform);
265
266 // FIXME: referenced
267
268 stream.writeInt(uniform.blockIndex);
269 stream.writeInt(uniform.blockInfo.offset);
270 stream.writeInt(uniform.blockInfo.arrayStride);
271 stream.writeInt(uniform.blockInfo.matrixStride);
272 stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
273 }
274
275 stream.writeInt(state.getUniformLocations().size());
276 for (const auto &variable : state.getUniformLocations())
277 {
278 stream.writeString(variable.name);
279 stream.writeInt(variable.element);
280 stream.writeInt(variable.index);
281 stream.writeInt(variable.used);
282 stream.writeInt(variable.ignored);
283 }
284
285 stream.writeInt(state.getUniformBlocks().size());
286 for (const UniformBlock &uniformBlock : state.getUniformBlocks())
287 {
288 stream.writeString(uniformBlock.name);
289 stream.writeInt(uniformBlock.isArray);
290 stream.writeInt(uniformBlock.arrayElement);
291 stream.writeInt(uniformBlock.binding);
292 stream.writeInt(uniformBlock.dataSize);
293
294 stream.writeInt(uniformBlock.vertexStaticUse);
295 stream.writeInt(uniformBlock.fragmentStaticUse);
296
297 stream.writeInt(uniformBlock.memberUniformIndexes.size());
298 for (unsigned int memberUniformIndex : uniformBlock.memberUniformIndexes)
299 {
300 stream.writeInt(memberUniformIndex);
301 }
302 }
303
304 for (GLuint binding : state.getUniformBlockBindings())
305 {
306 stream.writeInt(binding);
307 }
308
309 stream.writeInt(state.getLinkedTransformFeedbackVaryings().size());
310 for (const auto &var : state.getLinkedTransformFeedbackVaryings())
311 {
312 stream.writeInt(var.arraySize);
313 stream.writeInt(var.type);
314 stream.writeString(var.name);
315
316 stream.writeIntOrNegOne(var.arrayIndex);
317 }
318
319 stream.writeInt(state.getTransformFeedbackBufferMode());
320
321 stream.writeInt(state.getOutputVariables().size());
322 for (const sh::OutputVariable &output : state.getOutputVariables())
323 {
324 WriteShaderVar(&stream, output);
325 stream.writeInt(output.location);
326 }
327
328 stream.writeInt(state.getOutputLocations().size());
329 for (const auto &outputPair : state.getOutputLocations())
330 {
331 stream.writeInt(outputPair.first);
332 stream.writeIntOrNegOne(outputPair.second.element);
333 stream.writeInt(outputPair.second.index);
334 stream.writeString(outputPair.second.name);
335 }
336
337 stream.writeInt(state.mOutputVariableTypes.size());
338 for (const auto &outputVariableType : state.mOutputVariableTypes)
339 {
340 stream.writeInt(outputVariableType);
341 }
342
343 static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS < 8 * sizeof(uint32_t),
344 "All bits of DrawBufferMask can be contained in an uint32_t");
345 stream.writeInt(static_cast<uint32_t>(state.mActiveOutputVariables.to_ulong()));
346
347 stream.writeInt(state.getSamplerUniformRange().low());
348 stream.writeInt(state.getSamplerUniformRange().high());
349
350 stream.writeInt(state.getSamplerBindings().size());
351 for (const auto &samplerBinding : state.getSamplerBindings())
352 {
353 stream.writeInt(samplerBinding.textureType);
354 stream.writeInt(samplerBinding.boundTextureUnits.size());
355 }
356
357 program->getImplementation()->save(&stream);
358
359 ASSERT(binaryOut);
360 binaryOut->resize(stream.length());
361 memcpy(binaryOut->data(), stream.data(), stream.length());
362}
363
364} // namespace gl