1 //
2 // Copyright 2020 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 // ProgramExecutable.cpp: Collects the interfaces common to both Programs and
7 // ProgramPipelines in order to execute/draw with either.
8
9 #include "libANGLE/ProgramExecutable.h"
10
11 #include "common/string_utils.h"
12 #include "libANGLE/Context.h"
13 #include "libANGLE/Program.h"
14 #include "libANGLE/Shader.h"
15 #include "libANGLE/queryconversions.h"
16 #include "libANGLE/renderer/GLImplFactory.h"
17 #include "libANGLE/renderer/ProgramExecutableImpl.h"
18 #include "libANGLE/renderer/ProgramImpl.h"
19
20 namespace gl
21 {
22 namespace
23 {
24 ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
25 // A placeholder struct just to ensure sh::BlockMemberInfo is tightly packed since vulkan backend
26 // uses it and memcpy the entire vector which requires it tightly packed to make msan happy.
27 struct BlockMemberInfoPaddingTest
28 {
29 sh::BlockMemberInfo blockMemberInfo;
30 };
31 ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
32
IncludeSameArrayElement(const std::set<std::string> & nameSet,const std::string & name)33 bool IncludeSameArrayElement(const std::set<std::string> &nameSet, const std::string &name)
34 {
35 std::vector<unsigned int> subscripts;
36 std::string baseName = ParseResourceName(name, &subscripts);
37 for (const std::string &nameInSet : nameSet)
38 {
39 std::vector<unsigned int> arrayIndices;
40 std::string arrayName = ParseResourceName(nameInSet, &arrayIndices);
41 if (baseName == arrayName &&
42 (subscripts.empty() || arrayIndices.empty() || subscripts == arrayIndices))
43 {
44 return true;
45 }
46 }
47 return false;
48 }
49
50 // Find the matching varying or field by name.
FindOutputVaryingOrField(const ProgramMergedVaryings & varyings,ShaderType stage,const std::string & name)51 const sh::ShaderVariable *FindOutputVaryingOrField(const ProgramMergedVaryings &varyings,
52 ShaderType stage,
53 const std::string &name)
54 {
55 const sh::ShaderVariable *var = nullptr;
56 for (const ProgramVaryingRef &ref : varyings)
57 {
58 if (ref.frontShaderStage != stage)
59 {
60 continue;
61 }
62
63 const sh::ShaderVariable *varying = ref.get(stage);
64 if (varying->name == name)
65 {
66 var = varying;
67 break;
68 }
69 GLuint fieldIndex = 0;
70 var = varying->findField(name, &fieldIndex);
71 if (var != nullptr)
72 {
73 break;
74 }
75 }
76 return var;
77 }
78
FindUsedOutputLocation(std::vector<VariableLocation> & outputLocations,unsigned int baseLocation,unsigned int elementCount,const std::vector<VariableLocation> & reservedLocations,unsigned int variableIndex)79 bool FindUsedOutputLocation(std::vector<VariableLocation> &outputLocations,
80 unsigned int baseLocation,
81 unsigned int elementCount,
82 const std::vector<VariableLocation> &reservedLocations,
83 unsigned int variableIndex)
84 {
85 if (baseLocation + elementCount > outputLocations.size())
86 {
87 elementCount = baseLocation < outputLocations.size()
88 ? static_cast<unsigned int>(outputLocations.size() - baseLocation)
89 : 0;
90 }
91 for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
92 {
93 const unsigned int location = baseLocation + elementIndex;
94 if (outputLocations[location].used())
95 {
96 VariableLocation locationInfo(elementIndex, variableIndex);
97 if (std::find(reservedLocations.begin(), reservedLocations.end(), locationInfo) ==
98 reservedLocations.end())
99 {
100 return true;
101 }
102 }
103 }
104 return false;
105 }
106
AssignOutputLocations(std::vector<VariableLocation> & outputLocations,unsigned int baseLocation,unsigned int elementCount,const std::vector<VariableLocation> & reservedLocations,unsigned int variableIndex,bool locationAssignedByApi,ProgramOutput & outputVariable)107 void AssignOutputLocations(std::vector<VariableLocation> &outputLocations,
108 unsigned int baseLocation,
109 unsigned int elementCount,
110 const std::vector<VariableLocation> &reservedLocations,
111 unsigned int variableIndex,
112 bool locationAssignedByApi,
113 ProgramOutput &outputVariable)
114 {
115 if (baseLocation + elementCount > outputLocations.size())
116 {
117 outputLocations.resize(baseLocation + elementCount);
118 }
119 for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
120 {
121 VariableLocation locationInfo(elementIndex, variableIndex);
122 if (std::find(reservedLocations.begin(), reservedLocations.end(), locationInfo) ==
123 reservedLocations.end())
124 {
125 outputVariable.pod.location = baseLocation;
126 const unsigned int location = baseLocation + elementIndex;
127 outputLocations[location] = locationInfo;
128 }
129 }
130 outputVariable.pod.hasApiAssignedLocation = locationAssignedByApi;
131 }
132
GetOutputLocationForLink(const ProgramAliasedBindings & fragmentOutputLocations,const ProgramOutput & outputVariable)133 int GetOutputLocationForLink(const ProgramAliasedBindings &fragmentOutputLocations,
134 const ProgramOutput &outputVariable)
135 {
136 if (outputVariable.pod.location != -1)
137 {
138 return outputVariable.pod.location;
139 }
140 int apiLocation = fragmentOutputLocations.getBinding(outputVariable);
141 if (apiLocation != -1)
142 {
143 return apiLocation;
144 }
145 return -1;
146 }
147
AssignOutputIndex(const ProgramAliasedBindings & fragmentOutputIndexes,ProgramOutput & outputVariable)148 void AssignOutputIndex(const ProgramAliasedBindings &fragmentOutputIndexes,
149 ProgramOutput &outputVariable)
150 {
151 if (outputVariable.pod.hasShaderAssignedLocation)
152 {
153 // Already assigned through a layout qualifier
154 ASSERT(outputVariable.pod.index == 0 || outputVariable.pod.index == 1);
155 return;
156 }
157
158 int apiIndex = fragmentOutputIndexes.getBinding(outputVariable);
159 if (apiIndex != -1)
160 {
161 // Index layout qualifier from the shader takes precedence, so the index from the API is
162 // checked only if the index was not set in the shader. This is not specified in the EXT
163 // spec, but is specified in desktop OpenGL specs.
164 ASSERT(apiIndex == 0 || apiIndex == 1);
165 outputVariable.pod.index = apiIndex;
166 return;
167 }
168
169 // EXT_blend_func_extended: Outputs get index 0 by default.
170 outputVariable.pod.index = 0;
171 }
172
AddUniforms(const ShaderMap<SharedProgramExecutable> & executables,ShaderBitSet activeShaders,std::vector<LinkedUniform> * outputUniforms,std::vector<std::string> * outputUniformNames,std::vector<std::string> * outputUniformMappedNames,const std::function<RangeUI (const ProgramExecutable &)> & getRange)173 RangeUI AddUniforms(const ShaderMap<SharedProgramExecutable> &executables,
174 ShaderBitSet activeShaders,
175 std::vector<LinkedUniform> *outputUniforms,
176 std::vector<std::string> *outputUniformNames,
177 std::vector<std::string> *outputUniformMappedNames,
178 const std::function<RangeUI(const ProgramExecutable &)> &getRange)
179 {
180 unsigned int startRange = static_cast<unsigned int>(outputUniforms->size());
181 for (ShaderType shaderType : activeShaders)
182 {
183 const ProgramExecutable &executable = *executables[shaderType];
184 const RangeUI uniformRange = getRange(executable);
185
186 const std::vector<LinkedUniform> &programUniforms = executable.getUniforms();
187 outputUniforms->insert(outputUniforms->end(), programUniforms.begin() + uniformRange.low(),
188 programUniforms.begin() + uniformRange.high());
189
190 const std::vector<std::string> &uniformNames = executable.getUniformNames();
191 outputUniformNames->insert(outputUniformNames->end(),
192 uniformNames.begin() + uniformRange.low(),
193 uniformNames.begin() + uniformRange.high());
194
195 const std::vector<std::string> &uniformMappedNames = executable.getUniformMappedNames();
196 outputUniformMappedNames->insert(outputUniformMappedNames->end(),
197 uniformMappedNames.begin() + uniformRange.low(),
198 uniformMappedNames.begin() + uniformRange.high());
199 }
200 return RangeUI(startRange, static_cast<unsigned int>(outputUniforms->size()));
201 }
202
203 template <typename BlockT>
AppendActiveBlocks(ShaderType shaderType,const std::vector<BlockT> & blocksIn,std::vector<BlockT> & blocksOut,ProgramUniformBlockArray<GLuint> * ppoBlockMap)204 void AppendActiveBlocks(ShaderType shaderType,
205 const std::vector<BlockT> &blocksIn,
206 std::vector<BlockT> &blocksOut,
207 ProgramUniformBlockArray<GLuint> *ppoBlockMap)
208 {
209 for (size_t index = 0; index < blocksIn.size(); ++index)
210 {
211 const BlockT &block = blocksIn[index];
212 if (block.isActive(shaderType))
213 {
214 // Have a way for the PPO to know how to map the program's UBO index into its own UBO
215 // array. This is used to propagate changes to the program's UBOs to the PPO's UBO
216 // list.
217 if (ppoBlockMap != nullptr)
218 {
219 (*ppoBlockMap)[static_cast<uint32_t>(index)] =
220 static_cast<uint32_t>(blocksOut.size());
221 }
222
223 blocksOut.push_back(block);
224 }
225 }
226 }
227
SaveProgramInputs(BinaryOutputStream * stream,const std::vector<ProgramInput> & programInputs)228 void SaveProgramInputs(BinaryOutputStream *stream, const std::vector<ProgramInput> &programInputs)
229 {
230 stream->writeInt(programInputs.size());
231 for (const ProgramInput &attrib : programInputs)
232 {
233 stream->writeString(attrib.name);
234 stream->writeString(attrib.mappedName);
235 stream->writeStruct(attrib.pod);
236 }
237 }
LoadProgramInputs(BinaryInputStream * stream,std::vector<ProgramInput> * programInputs)238 void LoadProgramInputs(BinaryInputStream *stream, std::vector<ProgramInput> *programInputs)
239 {
240 size_t attribCount = stream->readInt<size_t>();
241 ASSERT(programInputs->empty());
242 if (attribCount > 0)
243 {
244 programInputs->resize(attribCount);
245 for (size_t attribIndex = 0; attribIndex < attribCount; ++attribIndex)
246 {
247 ProgramInput &attrib = (*programInputs)[attribIndex];
248 stream->readString(&attrib.name);
249 stream->readString(&attrib.mappedName);
250 stream->readStruct(&attrib.pod);
251 }
252 }
253 }
254
SaveUniforms(BinaryOutputStream * stream,const std::vector<LinkedUniform> & uniforms,const std::vector<std::string> & uniformNames,const std::vector<std::string> & uniformMappedNames,const std::vector<VariableLocation> & uniformLocations)255 void SaveUniforms(BinaryOutputStream *stream,
256 const std::vector<LinkedUniform> &uniforms,
257 const std::vector<std::string> &uniformNames,
258 const std::vector<std::string> &uniformMappedNames,
259 const std::vector<VariableLocation> &uniformLocations)
260 {
261 stream->writeVector(uniforms);
262 ASSERT(uniforms.size() == uniformNames.size());
263 ASSERT(uniforms.size() == uniformMappedNames.size());
264 for (const std::string &name : uniformNames)
265 {
266 stream->writeString(name);
267 }
268 for (const std::string &name : uniformMappedNames)
269 {
270 stream->writeString(name);
271 }
272 stream->writeVector(uniformLocations);
273 }
LoadUniforms(BinaryInputStream * stream,std::vector<LinkedUniform> * uniforms,std::vector<std::string> * uniformNames,std::vector<std::string> * uniformMappedNames,std::vector<VariableLocation> * uniformLocations)274 void LoadUniforms(BinaryInputStream *stream,
275 std::vector<LinkedUniform> *uniforms,
276 std::vector<std::string> *uniformNames,
277 std::vector<std::string> *uniformMappedNames,
278 std::vector<VariableLocation> *uniformLocations)
279 {
280 stream->readVector(uniforms);
281 if (!uniforms->empty())
282 {
283 uniformNames->resize(uniforms->size());
284 for (size_t uniformIndex = 0; uniformIndex < uniforms->size(); ++uniformIndex)
285 {
286 stream->readString(&(*uniformNames)[uniformIndex]);
287 }
288 uniformMappedNames->resize(uniforms->size());
289 for (size_t uniformIndex = 0; uniformIndex < uniforms->size(); ++uniformIndex)
290 {
291 stream->readString(&(*uniformMappedNames)[uniformIndex]);
292 }
293 }
294 stream->readVector(uniformLocations);
295 }
296
SaveSamplerBindings(BinaryOutputStream * stream,const std::vector<SamplerBinding> & samplerBindings,const std::vector<GLuint> & samplerBoundTextureUnits)297 void SaveSamplerBindings(BinaryOutputStream *stream,
298 const std::vector<SamplerBinding> &samplerBindings,
299 const std::vector<GLuint> &samplerBoundTextureUnits)
300 {
301 stream->writeVector(samplerBindings);
302 stream->writeInt(samplerBoundTextureUnits.size());
303 }
LoadSamplerBindings(BinaryInputStream * stream,std::vector<SamplerBinding> * samplerBindings,std::vector<GLuint> * samplerBoundTextureUnits)304 void LoadSamplerBindings(BinaryInputStream *stream,
305 std::vector<SamplerBinding> *samplerBindings,
306 std::vector<GLuint> *samplerBoundTextureUnits)
307 {
308 stream->readVector(samplerBindings);
309 ASSERT(samplerBoundTextureUnits->empty());
310 size_t boundTextureUnitsCount = stream->readInt<size_t>();
311 samplerBoundTextureUnits->resize(boundTextureUnitsCount, 0);
312 }
313
WriteBufferVariable(BinaryOutputStream * stream,const BufferVariable & var)314 void WriteBufferVariable(BinaryOutputStream *stream, const BufferVariable &var)
315 {
316 stream->writeString(var.name);
317 stream->writeString(var.mappedName);
318 stream->writeStruct(var.pod);
319 }
320
LoadBufferVariable(BinaryInputStream * stream,BufferVariable * var)321 void LoadBufferVariable(BinaryInputStream *stream, BufferVariable *var)
322 {
323 var->name = stream->readString();
324 var->mappedName = stream->readString();
325 stream->readStruct(&var->pod);
326 }
327
WriteAtomicCounterBuffer(BinaryOutputStream * stream,const AtomicCounterBuffer & var)328 void WriteAtomicCounterBuffer(BinaryOutputStream *stream, const AtomicCounterBuffer &var)
329 {
330 stream->writeVector(var.memberIndexes);
331 stream->writeStruct(var.pod);
332 }
333
LoadAtomicCounterBuffer(BinaryInputStream * stream,AtomicCounterBuffer * var)334 void LoadAtomicCounterBuffer(BinaryInputStream *stream, AtomicCounterBuffer *var)
335 {
336 stream->readVector(&var->memberIndexes);
337 stream->readStruct(&var->pod);
338 }
339
WriteInterfaceBlock(BinaryOutputStream * stream,const InterfaceBlock & block)340 void WriteInterfaceBlock(BinaryOutputStream *stream, const InterfaceBlock &block)
341 {
342 stream->writeString(block.name);
343 stream->writeString(block.mappedName);
344 stream->writeVector(block.memberIndexes);
345 stream->writeStruct(block.pod);
346 }
347
LoadInterfaceBlock(BinaryInputStream * stream,InterfaceBlock * block)348 void LoadInterfaceBlock(BinaryInputStream *stream, InterfaceBlock *block)
349 {
350 block->name = stream->readString();
351 block->mappedName = stream->readString();
352 stream->readVector(&block->memberIndexes);
353 stream->readStruct(&block->pod);
354 }
355
CopyStringToBuffer(GLchar * buffer,const std::string & string,GLsizei bufSize,GLsizei * lengthOut)356 void CopyStringToBuffer(GLchar *buffer,
357 const std::string &string,
358 GLsizei bufSize,
359 GLsizei *lengthOut)
360 {
361 ASSERT(bufSize > 0);
362 size_t length = std::min<size_t>(bufSize - 1, string.length());
363 memcpy(buffer, string.c_str(), length);
364 buffer[length] = '\0';
365
366 if (lengthOut)
367 {
368 *lengthOut = static_cast<GLsizei>(length);
369 }
370 }
371
372 template <typename T>
GetResourceMaxNameSize(const T & resource,GLint max)373 GLuint GetResourceMaxNameSize(const T &resource, GLint max)
374 {
375 if (resource.isArray())
376 {
377 return std::max(max, clampCast<GLint>((resource.name + "[0]").size()));
378 }
379 else
380 {
381 return std::max(max, clampCast<GLint>((resource.name).size()));
382 }
383 }
384
385 template <typename T>
GetResourceLocation(const GLchar * name,const T & variable,GLint location)386 GLuint GetResourceLocation(const GLchar *name, const T &variable, GLint location)
387 {
388 if (variable.isBuiltIn())
389 {
390 return GL_INVALID_INDEX;
391 }
392
393 if (variable.isArray())
394 {
395 size_t nameLengthWithoutArrayIndexOut;
396 size_t arrayIndex = ParseArrayIndex(name, &nameLengthWithoutArrayIndexOut);
397 // The 'name' string may not contain the array notation "[0]"
398 if (arrayIndex != GL_INVALID_INDEX)
399 {
400 location += arrayIndex;
401 }
402 }
403
404 return location;
405 }
406
407 template <typename T>
GetResourceName(const T & resource)408 const std::string GetResourceName(const T &resource)
409 {
410 std::string resourceName = resource.name;
411
412 if (resource.isArray())
413 {
414 resourceName += "[0]";
415 }
416
417 return resourceName;
418 }
419
GetVariableLocation(const std::vector<gl::ProgramOutput> & list,const std::vector<VariableLocation> & locationList,const std::string & name)420 GLint GetVariableLocation(const std::vector<gl::ProgramOutput> &list,
421 const std::vector<VariableLocation> &locationList,
422 const std::string &name)
423 {
424 size_t nameLengthWithoutArrayIndex;
425 unsigned int arrayIndex = ParseArrayIndex(name, &nameLengthWithoutArrayIndex);
426
427 for (size_t location = 0u; location < locationList.size(); ++location)
428 {
429 const VariableLocation &variableLocation = locationList[location];
430 if (!variableLocation.used())
431 {
432 continue;
433 }
434
435 const gl::ProgramOutput &variable = list[variableLocation.index];
436
437 // Array output variables may be bound out of order, so we need to ensure we only pick the
438 // first element if given the base name.
439 if ((variable.name == name) && (variableLocation.arrayIndex == 0))
440 {
441 return static_cast<GLint>(location);
442 }
443 if (variable.isArray() && variableLocation.arrayIndex == arrayIndex &&
444 angle::BeginsWith(variable.name, name, nameLengthWithoutArrayIndex))
445 {
446 return static_cast<GLint>(location);
447 }
448 }
449
450 return -1;
451 }
452
453 template <typename VarT>
GetResourceIndexFromName(const std::vector<VarT> & list,const std::string & name)454 GLuint GetResourceIndexFromName(const std::vector<VarT> &list, const std::string &name)
455 {
456 std::string nameAsArrayName = name + "[0]";
457 for (size_t index = 0; index < list.size(); index++)
458 {
459 const VarT &resource = list[index];
460 if (resource.name == name || (resource.isArray() && resource.name == nameAsArrayName))
461 {
462 return static_cast<GLuint>(index);
463 }
464 }
465
466 return GL_INVALID_INDEX;
467 }
468
GetUniformIndexFromName(const std::vector<LinkedUniform> & uniformList,const std::vector<std::string> & nameList,const std::string & name)469 GLuint GetUniformIndexFromName(const std::vector<LinkedUniform> &uniformList,
470 const std::vector<std::string> &nameList,
471 const std::string &name)
472 {
473 std::string nameAsArrayName = name + "[0]";
474 for (size_t index = 0; index < nameList.size(); index++)
475 {
476 const std::string &uniformName = nameList[index];
477 if (uniformName == name || (uniformList[index].isArray() && uniformName == nameAsArrayName))
478 {
479 return static_cast<GLuint>(index);
480 }
481 }
482
483 return GL_INVALID_INDEX;
484 }
485
GetUniformLocation(const std::vector<LinkedUniform> & uniformList,const std::vector<std::string> & nameList,const std::vector<VariableLocation> & locationList,const std::string & name)486 GLint GetUniformLocation(const std::vector<LinkedUniform> &uniformList,
487 const std::vector<std::string> &nameList,
488 const std::vector<VariableLocation> &locationList,
489 const std::string &name)
490 {
491 size_t nameLengthWithoutArrayIndex;
492 unsigned int arrayIndex = ParseArrayIndex(name, &nameLengthWithoutArrayIndex);
493
494 for (size_t location = 0u; location < locationList.size(); ++location)
495 {
496 const VariableLocation &variableLocation = locationList[location];
497 if (!variableLocation.used())
498 {
499 continue;
500 }
501
502 const LinkedUniform &variable = uniformList[variableLocation.index];
503 const std::string &uniformName = nameList[variableLocation.index];
504
505 // Array output variables may be bound out of order, so we need to ensure we only pick the
506 // first element if given the base name. Uniforms don't allow this behavior and some code
507 // seemingly depends on the opposite behavior, so only enable it for output variables.
508 if (angle::BeginsWith(uniformName, name) && (variableLocation.arrayIndex == 0))
509 {
510 if (name.length() == uniformName.length())
511 {
512 ASSERT(name == uniformName);
513 // GLES 3.1 November 2016 page 87.
514 // The string exactly matches the name of the active variable.
515 return static_cast<GLint>(location);
516 }
517 if (name.length() + 3u == uniformName.length() && variable.isArray())
518 {
519 ASSERT(name + "[0]" == uniformName);
520 // The string identifies the base name of an active array, where the string would
521 // exactly match the name of the variable if the suffix "[0]" were appended to the
522 // string.
523 return static_cast<GLint>(location);
524 }
525 }
526 if (variable.isArray() && variableLocation.arrayIndex == arrayIndex &&
527 nameLengthWithoutArrayIndex + 3u == uniformName.length() &&
528 angle::BeginsWith(uniformName, name, nameLengthWithoutArrayIndex))
529 {
530 ASSERT(name.substr(0u, nameLengthWithoutArrayIndex) + "[0]" == uniformName);
531 // The string identifies an active element of the array, where the string ends with the
532 // concatenation of the "[" character, an integer (with no "+" sign, extra leading
533 // zeroes, or whitespace) identifying an array element, and the "]" character, the
534 // integer is less than the number of active elements of the array variable, and where
535 // the string would exactly match the enumerated name of the array if the decimal
536 // integer were replaced with zero.
537 return static_cast<GLint>(location);
538 }
539 }
540
541 return -1;
542 }
543
GetInterfaceBlockIndex(const std::vector<InterfaceBlock> & list,const std::string & name)544 GLuint GetInterfaceBlockIndex(const std::vector<InterfaceBlock> &list, const std::string &name)
545 {
546 std::vector<unsigned int> subscripts;
547 std::string baseName = ParseResourceName(name, &subscripts);
548
549 unsigned int numBlocks = static_cast<unsigned int>(list.size());
550 for (unsigned int blockIndex = 0; blockIndex < numBlocks; blockIndex++)
551 {
552 const auto &block = list[blockIndex];
553 if (block.name == baseName)
554 {
555 const bool arrayElementZero =
556 (subscripts.empty() && (!block.pod.isArray || block.pod.arrayElement == 0));
557 const bool arrayElementMatches =
558 (subscripts.size() == 1 && subscripts[0] == block.pod.arrayElement);
559 if (arrayElementMatches || arrayElementZero)
560 {
561 return blockIndex;
562 }
563 }
564 }
565
566 return GL_INVALID_INDEX;
567 }
568
GetInterfaceBlockName(const UniformBlockIndex index,const std::vector<InterfaceBlock> & list,GLsizei bufSize,GLsizei * length,GLchar * name)569 void GetInterfaceBlockName(const UniformBlockIndex index,
570 const std::vector<InterfaceBlock> &list,
571 GLsizei bufSize,
572 GLsizei *length,
573 GLchar *name)
574 {
575 ASSERT(index.value < list.size());
576
577 const auto &block = list[index.value];
578
579 if (bufSize > 0)
580 {
581 std::string blockName = block.name;
582
583 if (block.pod.isArray)
584 {
585 blockName += ArrayString(block.pod.arrayElement);
586 }
587 CopyStringToBuffer(name, blockName, bufSize, length);
588 }
589 }
590
591 template <typename T>
GetActiveInterfaceBlockMaxNameLength(const std::vector<T> & resources)592 GLint GetActiveInterfaceBlockMaxNameLength(const std::vector<T> &resources)
593 {
594 int maxLength = 0;
595
596 for (const T &resource : resources)
597 {
598 if (!resource.name.empty())
599 {
600 int length = static_cast<int>(resource.nameWithArrayIndex().length());
601 maxLength = std::max(length + 1, maxLength);
602 }
603 }
604
605 return maxLength;
606 }
607
608 // This simplified cast function doesn't need to worry about advanced concepts like
609 // depth range values, or casting to bool.
610 template <typename DestT, typename SrcT>
611 DestT UniformStateQueryCast(SrcT value);
612
613 // From-Float-To-Integer Casts
614 template <>
UniformStateQueryCast(GLfloat value)615 GLint UniformStateQueryCast(GLfloat value)
616 {
617 return clampCast<GLint>(roundf(value));
618 }
619
620 template <>
UniformStateQueryCast(GLfloat value)621 GLuint UniformStateQueryCast(GLfloat value)
622 {
623 return clampCast<GLuint>(roundf(value));
624 }
625
626 // From-Integer-to-Integer Casts
627 template <>
UniformStateQueryCast(GLuint value)628 GLint UniformStateQueryCast(GLuint value)
629 {
630 return clampCast<GLint>(value);
631 }
632
633 template <>
UniformStateQueryCast(GLint value)634 GLuint UniformStateQueryCast(GLint value)
635 {
636 return clampCast<GLuint>(value);
637 }
638
639 // From-Boolean-to-Anything Casts
640 template <>
UniformStateQueryCast(GLboolean value)641 GLfloat UniformStateQueryCast(GLboolean value)
642 {
643 return (ConvertToBool(value) ? 1.0f : 0.0f);
644 }
645
646 template <>
UniformStateQueryCast(GLboolean value)647 GLint UniformStateQueryCast(GLboolean value)
648 {
649 return (ConvertToBool(value) ? 1 : 0);
650 }
651
652 template <>
UniformStateQueryCast(GLboolean value)653 GLuint UniformStateQueryCast(GLboolean value)
654 {
655 return (ConvertToBool(value) ? 1u : 0u);
656 }
657
658 // Default to static_cast
659 template <typename DestT, typename SrcT>
UniformStateQueryCast(SrcT value)660 DestT UniformStateQueryCast(SrcT value)
661 {
662 return static_cast<DestT>(value);
663 }
664
665 template <typename SrcT, typename DestT>
UniformStateQueryCastLoop(DestT * dataOut,const uint8_t * srcPointer,int components)666 void UniformStateQueryCastLoop(DestT *dataOut, const uint8_t *srcPointer, int components)
667 {
668 for (int comp = 0; comp < components; ++comp)
669 {
670 // We only work with strides of 4 bytes for uniform components. (GLfloat/GLint)
671 // Don't use SrcT stride directly since GLboolean has a stride of 1 byte.
672 size_t offset = comp * 4;
673 const SrcT *typedSrcPointer = reinterpret_cast<const SrcT *>(&srcPointer[offset]);
674 dataOut[comp] = UniformStateQueryCast<DestT>(*typedSrcPointer);
675 }
676 }
677 } // anonymous namespace
678
679 // ImageBinding implementation.
ImageBinding(GLuint imageUnit,size_t count,TextureType textureTypeIn)680 ImageBinding::ImageBinding(GLuint imageUnit, size_t count, TextureType textureTypeIn)
681 : textureType(textureTypeIn)
682 {
683 for (size_t index = 0; index < count; ++index)
684 {
685 boundImageUnits.push_back(imageUnit + static_cast<GLuint>(index));
686 }
687 }
688
689 // ProgramInput implementation.
ProgramInput(const sh::ShaderVariable & var)690 ProgramInput::ProgramInput(const sh::ShaderVariable &var)
691 {
692 ASSERT(!var.isStruct());
693
694 name = var.name;
695 mappedName = var.mappedName;
696
697 SetBitField(pod.type, var.type);
698 pod.location = var.hasImplicitLocation ? -1 : var.location;
699 SetBitField(pod.interpolation, var.interpolation);
700 pod.flagBitsAsUByte = 0;
701 pod.flagBits.active = var.active;
702 pod.flagBits.isPatch = var.isPatch;
703 pod.flagBits.hasImplicitLocation = var.hasImplicitLocation;
704 pod.flagBits.isArray = var.isArray();
705 pod.flagBits.isBuiltIn = IsBuiltInName(var.name);
706 SetBitField(pod.basicTypeElementCount, var.getBasicTypeElementCount());
707 pod.id = var.id;
708 SetBitField(pod.arraySizeProduct, var.getArraySizeProduct());
709 }
710
711 // ProgramOutput implementation.
ProgramOutput(const sh::ShaderVariable & var)712 ProgramOutput::ProgramOutput(const sh::ShaderVariable &var)
713 {
714 name = var.name;
715 mappedName = var.mappedName;
716
717 pod.type = var.type;
718 pod.location = var.location;
719 pod.index = var.index;
720 pod.id = var.id;
721
722 SetBitField(pod.outermostArraySize, var.getOutermostArraySize());
723 SetBitField(pod.basicTypeElementCount, var.getBasicTypeElementCount());
724
725 SetBitField(pod.isPatch, var.isPatch);
726 SetBitField(pod.yuv, var.yuv);
727 SetBitField(pod.isBuiltIn, IsBuiltInName(var.name));
728 SetBitField(pod.isArray, var.isArray());
729 SetBitField(pod.hasImplicitLocation, var.hasImplicitLocation);
730 SetBitField(pod.hasShaderAssignedLocation, var.location != -1);
731 SetBitField(pod.hasApiAssignedLocation, false);
732 SetBitField(pod.pad, 0);
733
734 if (pod.hasShaderAssignedLocation && pod.index == -1)
735 {
736 // Location was assigned but index was not. Equivalent to setting index to 0.
737 pod.index = 0;
738 }
739 }
740
741 // ProgramExecutable implementation.
ProgramExecutable(rx::GLImplFactory * factory,InfoLog * infoLog)742 ProgramExecutable::ProgramExecutable(rx::GLImplFactory *factory, InfoLog *infoLog)
743 : mImplementation(factory->createProgramExecutable(this)),
744 mInfoLog(infoLog),
745 mCachedBaseVertex(0),
746 mCachedBaseInstance(0),
747 mIsPPO(false)
748 {
749 memset(&mPod, 0, sizeof(mPod));
750 reset();
751 }
752
~ProgramExecutable()753 ProgramExecutable::~ProgramExecutable()
754 {
755 ASSERT(mPostLinkSubTasks.empty());
756 ASSERT(mPostLinkSubTaskWaitableEvents.empty());
757 ASSERT(mImplementation == nullptr);
758 }
759
destroy(const Context * context)760 void ProgramExecutable::destroy(const Context *context)
761 {
762 ASSERT(mImplementation != nullptr);
763
764 for (SharedProgramExecutable &executable : mPPOProgramExecutables)
765 {
766 if (executable)
767 {
768 UninstallExecutable(context, &executable);
769 }
770 }
771
772 mImplementation->destroy(context);
773 SafeDelete(mImplementation);
774 }
775
reset()776 void ProgramExecutable::reset()
777 {
778 mPod.activeAttribLocationsMask.reset();
779 mPod.attributesTypeMask.reset();
780 mPod.attributesMask.reset();
781 mPod.maxActiveAttribLocation = 0;
782 mPod.activeOutputVariablesMask.reset();
783 mPod.activeSecondaryOutputVariablesMask.reset();
784
785 mPod.defaultUniformRange = RangeUI(0, 0);
786 mPod.samplerUniformRange = RangeUI(0, 0);
787 mPod.imageUniformRange = RangeUI(0, 0);
788 mPod.atomicCounterUniformRange = RangeUI(0, 0);
789
790 mPod.fragmentInoutIndices.reset();
791
792 mPod.hasClipDistance = false;
793 mPod.hasDiscard = false;
794 mPod.enablesPerSampleShading = false;
795 mPod.hasYUVOutput = false;
796 mPod.hasDepthInputAttachment = false;
797 mPod.hasStencilInputAttachment = false;
798
799 mPod.advancedBlendEquations.reset();
800
801 mPod.geometryShaderInputPrimitiveType = PrimitiveMode::Triangles;
802 mPod.geometryShaderOutputPrimitiveType = PrimitiveMode::TriangleStrip;
803 mPod.geometryShaderInvocations = 1;
804 mPod.geometryShaderMaxVertices = 0;
805
806 mPod.transformFeedbackBufferMode = GL_INTERLEAVED_ATTRIBS;
807
808 mPod.numViews = -1;
809
810 mPod.drawIDLocation = -1;
811
812 mPod.baseVertexLocation = -1;
813 mPod.baseInstanceLocation = -1;
814
815 mPod.tessControlShaderVertices = 0;
816 mPod.tessGenMode = GL_NONE;
817 mPod.tessGenSpacing = GL_NONE;
818 mPod.tessGenVertexOrder = GL_NONE;
819 mPod.tessGenPointMode = GL_NONE;
820 mPod.drawBufferTypeMask.reset();
821 mPod.computeShaderLocalSize.fill(1);
822
823 mPod.specConstUsageBits.reset();
824
825 mActiveSamplersMask.reset();
826 mActiveSamplerRefCounts = {};
827 mActiveSamplerTypes.fill(TextureType::InvalidEnum);
828 mActiveSamplerYUV.reset();
829 mActiveSamplerFormats.fill(SamplerFormat::InvalidEnum);
830
831 mActiveImagesMask.reset();
832
833 mUniformBlockIndexToBufferBinding = {};
834
835 mProgramInputs.clear();
836 mLinkedTransformFeedbackVaryings.clear();
837 mTransformFeedbackStrides.clear();
838 mUniforms.clear();
839 mUniformNames.clear();
840 mUniformMappedNames.clear();
841 mUniformBlocks.clear();
842 mUniformLocations.clear();
843 mShaderStorageBlocks.clear();
844 mAtomicCounterBuffers.clear();
845 mBufferVariables.clear();
846 mOutputVariables.clear();
847 mOutputLocations.clear();
848 mSecondaryOutputLocations.clear();
849 mSamplerBindings.clear();
850 mSamplerBoundTextureUnits.clear();
851 mImageBindings.clear();
852 mPixelLocalStorageFormats.clear();
853
854 mPostLinkSubTasks.clear();
855 mPostLinkSubTaskWaitableEvents.clear();
856 }
857
load(gl::BinaryInputStream * stream)858 void ProgramExecutable::load(gl::BinaryInputStream *stream)
859 {
860 static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
861 "Too many vertex attribs for mask: All bits of mAttributesTypeMask types and "
862 "mask fit into 32 bits each");
863 static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS * 2 <= 8 * sizeof(uint32_t),
864 "All bits of mDrawBufferTypeMask and mActiveOutputVariables types and mask fit "
865 "into 32 bits each");
866
867 stream->readStruct(&mPod);
868
869 LoadProgramInputs(stream, &mProgramInputs);
870 LoadUniforms(stream, &mUniforms, &mUniformNames, &mUniformMappedNames, &mUniformLocations);
871
872 size_t uniformBlockCount = stream->readInt<size_t>();
873 ASSERT(getUniformBlocks().empty());
874 mUniformBlocks.resize(uniformBlockCount);
875 for (size_t uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex)
876 {
877 InterfaceBlock &uniformBlock = mUniformBlocks[uniformBlockIndex];
878 LoadInterfaceBlock(stream, &uniformBlock);
879 }
880
881 size_t shaderStorageBlockCount = stream->readInt<size_t>();
882 ASSERT(getShaderStorageBlocks().empty());
883 mShaderStorageBlocks.resize(shaderStorageBlockCount);
884 for (size_t shaderStorageBlockIndex = 0; shaderStorageBlockIndex < shaderStorageBlockCount;
885 ++shaderStorageBlockIndex)
886 {
887 InterfaceBlock &shaderStorageBlock = mShaderStorageBlocks[shaderStorageBlockIndex];
888 LoadInterfaceBlock(stream, &shaderStorageBlock);
889 }
890
891 size_t atomicCounterBufferCount = stream->readInt<size_t>();
892 ASSERT(getAtomicCounterBuffers().empty());
893 mAtomicCounterBuffers.resize(atomicCounterBufferCount);
894 for (size_t bufferIndex = 0; bufferIndex < atomicCounterBufferCount; ++bufferIndex)
895 {
896 AtomicCounterBuffer &atomicCounterBuffer = mAtomicCounterBuffers[bufferIndex];
897 LoadAtomicCounterBuffer(stream, &atomicCounterBuffer);
898 }
899
900 size_t bufferVariableCount = stream->readInt<size_t>();
901 ASSERT(getBufferVariables().empty());
902 mBufferVariables.resize(bufferVariableCount);
903 for (size_t bufferVarIndex = 0; bufferVarIndex < bufferVariableCount; ++bufferVarIndex)
904 {
905 LoadBufferVariable(stream, &mBufferVariables[bufferVarIndex]);
906 }
907
908 size_t transformFeedbackVaryingCount = stream->readInt<size_t>();
909 ASSERT(mLinkedTransformFeedbackVaryings.empty());
910 mLinkedTransformFeedbackVaryings.resize(transformFeedbackVaryingCount);
911 for (size_t transformFeedbackVaryingIndex = 0;
912 transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
913 ++transformFeedbackVaryingIndex)
914 {
915 TransformFeedbackVarying &varying =
916 mLinkedTransformFeedbackVaryings[transformFeedbackVaryingIndex];
917 stream->readVector(&varying.arraySizes);
918 stream->readInt(&varying.type);
919 stream->readString(&varying.name);
920 varying.arrayIndex = stream->readInt<GLuint>();
921 }
922
923 size_t outputCount = stream->readInt<size_t>();
924 ASSERT(getOutputVariables().empty());
925 mOutputVariables.resize(outputCount);
926 for (size_t outputIndex = 0; outputIndex < outputCount; ++outputIndex)
927 {
928 ProgramOutput &output = mOutputVariables[outputIndex];
929 stream->readString(&output.name);
930 stream->readString(&output.mappedName);
931 stream->readStruct(&output.pod);
932 }
933
934 stream->readVector(&mOutputLocations);
935 stream->readVector(&mSecondaryOutputLocations);
936 LoadSamplerBindings(stream, &mSamplerBindings, &mSamplerBoundTextureUnits);
937
938 size_t imageBindingCount = stream->readInt<size_t>();
939 ASSERT(mImageBindings.empty());
940 mImageBindings.resize(imageBindingCount);
941 for (size_t imageIndex = 0; imageIndex < imageBindingCount; ++imageIndex)
942 {
943 ImageBinding &imageBinding = mImageBindings[imageIndex];
944 size_t elementCount = stream->readInt<size_t>();
945 imageBinding.textureType = static_cast<TextureType>(stream->readInt<unsigned int>());
946 imageBinding.boundImageUnits.resize(elementCount);
947 for (size_t elementIndex = 0; elementIndex < elementCount; ++elementIndex)
948 {
949 imageBinding.boundImageUnits[elementIndex] = stream->readInt<unsigned int>();
950 }
951 }
952
953 // ANGLE_shader_pixel_local_storage.
954 size_t plsCount = stream->readInt<size_t>();
955 ASSERT(mPixelLocalStorageFormats.empty());
956 mPixelLocalStorageFormats.resize(plsCount);
957 stream->readBytes(reinterpret_cast<uint8_t *>(mPixelLocalStorageFormats.data()), plsCount);
958
959 // These values are currently only used by PPOs, so only load them when the program is marked
960 // separable to save memory.
961 if (mPod.isSeparable)
962 {
963 for (ShaderType shaderType : getLinkedShaderStages())
964 {
965 mLinkedOutputVaryings[shaderType].resize(stream->readInt<size_t>());
966 for (sh::ShaderVariable &variable : mLinkedOutputVaryings[shaderType])
967 {
968 LoadShaderVar(stream, &variable);
969 }
970 mLinkedInputVaryings[shaderType].resize(stream->readInt<size_t>());
971 for (sh::ShaderVariable &variable : mLinkedInputVaryings[shaderType])
972 {
973 LoadShaderVar(stream, &variable);
974 }
975 mLinkedUniforms[shaderType].resize(stream->readInt<size_t>());
976 for (sh::ShaderVariable &variable : mLinkedUniforms[shaderType])
977 {
978 LoadShaderVar(stream, &variable);
979 }
980 mLinkedUniformBlocks[shaderType].resize(stream->readInt<size_t>());
981 for (sh::InterfaceBlock &shaderStorageBlock : mLinkedUniformBlocks[shaderType])
982 {
983 LoadShInterfaceBlock(stream, &shaderStorageBlock);
984 }
985 }
986 }
987 }
988
save(gl::BinaryOutputStream * stream) const989 void ProgramExecutable::save(gl::BinaryOutputStream *stream) const
990 {
991 static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
992 "All bits of mAttributesTypeMask types and mask fit into 32 bits each");
993 static_assert(
994 IMPLEMENTATION_MAX_DRAW_BUFFERS * 2 <= 8 * sizeof(uint32_t),
995 "All bits of mDrawBufferTypeMask and mActiveOutputVariables can be contained in 32 bits");
996
997 ASSERT(mPod.geometryShaderInvocations >= 1 && mPod.geometryShaderMaxVertices >= 0);
998 stream->writeStruct(mPod);
999
1000 SaveProgramInputs(stream, mProgramInputs);
1001 SaveUniforms(stream, mUniforms, mUniformNames, mUniformMappedNames, mUniformLocations);
1002
1003 stream->writeInt(getUniformBlocks().size());
1004 for (const InterfaceBlock &uniformBlock : getUniformBlocks())
1005 {
1006 WriteInterfaceBlock(stream, uniformBlock);
1007 }
1008
1009 stream->writeInt(getShaderStorageBlocks().size());
1010 for (const InterfaceBlock &shaderStorageBlock : getShaderStorageBlocks())
1011 {
1012 WriteInterfaceBlock(stream, shaderStorageBlock);
1013 }
1014
1015 stream->writeInt(mAtomicCounterBuffers.size());
1016 for (const AtomicCounterBuffer &atomicCounterBuffer : getAtomicCounterBuffers())
1017 {
1018 WriteAtomicCounterBuffer(stream, atomicCounterBuffer);
1019 }
1020
1021 stream->writeInt(getBufferVariables().size());
1022 for (const BufferVariable &bufferVariable : getBufferVariables())
1023 {
1024 WriteBufferVariable(stream, bufferVariable);
1025 }
1026
1027 stream->writeInt(getLinkedTransformFeedbackVaryings().size());
1028 for (const auto &var : getLinkedTransformFeedbackVaryings())
1029 {
1030 stream->writeVector(var.arraySizes);
1031 stream->writeInt(var.type);
1032 stream->writeString(var.name);
1033
1034 stream->writeIntOrNegOne(var.arrayIndex);
1035 }
1036
1037 stream->writeInt(getOutputVariables().size());
1038 for (const ProgramOutput &output : getOutputVariables())
1039 {
1040 stream->writeString(output.name);
1041 stream->writeString(output.mappedName);
1042 stream->writeStruct(output.pod);
1043 }
1044
1045 stream->writeVector(mOutputLocations);
1046 stream->writeVector(mSecondaryOutputLocations);
1047 SaveSamplerBindings(stream, mSamplerBindings, mSamplerBoundTextureUnits);
1048
1049 stream->writeInt(getImageBindings().size());
1050 for (const auto &imageBinding : getImageBindings())
1051 {
1052 stream->writeInt(imageBinding.boundImageUnits.size());
1053 stream->writeInt(static_cast<unsigned int>(imageBinding.textureType));
1054 for (size_t i = 0; i < imageBinding.boundImageUnits.size(); ++i)
1055 {
1056 stream->writeInt(imageBinding.boundImageUnits[i]);
1057 }
1058 }
1059
1060 // ANGLE_shader_pixel_local_storage.
1061 stream->writeInt<size_t>(mPixelLocalStorageFormats.size());
1062 stream->writeBytes(reinterpret_cast<const uint8_t *>(mPixelLocalStorageFormats.data()),
1063 mPixelLocalStorageFormats.size());
1064
1065 // These values are currently only used by PPOs, so only save them when the program is marked
1066 // separable to save memory.
1067 if (mPod.isSeparable)
1068 {
1069 for (ShaderType shaderType : getLinkedShaderStages())
1070 {
1071 stream->writeInt(mLinkedOutputVaryings[shaderType].size());
1072 for (const sh::ShaderVariable &shaderVariable : mLinkedOutputVaryings[shaderType])
1073 {
1074 WriteShaderVar(stream, shaderVariable);
1075 }
1076 stream->writeInt(mLinkedInputVaryings[shaderType].size());
1077 for (const sh::ShaderVariable &shaderVariable : mLinkedInputVaryings[shaderType])
1078 {
1079 WriteShaderVar(stream, shaderVariable);
1080 }
1081 stream->writeInt(mLinkedUniforms[shaderType].size());
1082 for (const sh::ShaderVariable &shaderVariable : mLinkedUniforms[shaderType])
1083 {
1084 WriteShaderVar(stream, shaderVariable);
1085 }
1086 stream->writeInt(mLinkedUniformBlocks[shaderType].size());
1087 for (const sh::InterfaceBlock &shaderStorageBlock : mLinkedUniformBlocks[shaderType])
1088 {
1089 WriteShInterfaceBlock(stream, shaderStorageBlock);
1090 }
1091 }
1092 }
1093 }
1094
getInfoLogString() const1095 std::string ProgramExecutable::getInfoLogString() const
1096 {
1097 return mInfoLog->str();
1098 }
1099
getFirstLinkedShaderStageType() const1100 ShaderType ProgramExecutable::getFirstLinkedShaderStageType() const
1101 {
1102 const ShaderBitSet linkedStages = mPod.linkedShaderStages;
1103 if (linkedStages.none())
1104 {
1105 return ShaderType::InvalidEnum;
1106 }
1107
1108 return linkedStages.first();
1109 }
1110
getLastLinkedShaderStageType() const1111 ShaderType ProgramExecutable::getLastLinkedShaderStageType() const
1112 {
1113 const ShaderBitSet linkedStages = mPod.linkedShaderStages;
1114 if (linkedStages.none())
1115 {
1116 return ShaderType::InvalidEnum;
1117 }
1118
1119 return linkedStages.last();
1120 }
1121
setActive(size_t textureUnit,const SamplerBinding & samplerBinding,const gl::LinkedUniform & samplerUniform)1122 void ProgramExecutable::setActive(size_t textureUnit,
1123 const SamplerBinding &samplerBinding,
1124 const gl::LinkedUniform &samplerUniform)
1125 {
1126 mActiveSamplersMask.set(textureUnit);
1127 mActiveSamplerTypes[textureUnit] = samplerBinding.textureType;
1128 mActiveSamplerYUV[textureUnit] = IsSamplerYUVType(samplerBinding.samplerType);
1129 mActiveSamplerFormats[textureUnit] = samplerBinding.format;
1130 mActiveSamplerShaderBits[textureUnit] = samplerUniform.activeShaders();
1131 }
1132
setInactive(size_t textureUnit)1133 void ProgramExecutable::setInactive(size_t textureUnit)
1134 {
1135 mActiveSamplersMask.reset(textureUnit);
1136 mActiveSamplerTypes[textureUnit] = TextureType::InvalidEnum;
1137 mActiveSamplerYUV.reset(textureUnit);
1138 mActiveSamplerFormats[textureUnit] = SamplerFormat::InvalidEnum;
1139 mActiveSamplerShaderBits[textureUnit].reset();
1140 }
1141
hasSamplerTypeConflict(size_t textureUnit)1142 void ProgramExecutable::hasSamplerTypeConflict(size_t textureUnit)
1143 {
1144 // Conflicts are marked with InvalidEnum
1145 mActiveSamplerYUV.reset(textureUnit);
1146 mActiveSamplerTypes[textureUnit] = TextureType::InvalidEnum;
1147 }
1148
hasSamplerFormatConflict(size_t textureUnit)1149 void ProgramExecutable::hasSamplerFormatConflict(size_t textureUnit)
1150 {
1151 // Conflicts are marked with InvalidEnum
1152 mActiveSamplerFormats[textureUnit] = SamplerFormat::InvalidEnum;
1153 }
1154
updateActiveSamplers(const ProgramExecutable & executable)1155 void ProgramExecutable::updateActiveSamplers(const ProgramExecutable &executable)
1156 {
1157 const std::vector<SamplerBinding> &samplerBindings = executable.getSamplerBindings();
1158 const std::vector<GLuint> &boundTextureUnits = executable.getSamplerBoundTextureUnits();
1159
1160 for (uint32_t samplerIndex = 0; samplerIndex < samplerBindings.size(); ++samplerIndex)
1161 {
1162 const SamplerBinding &samplerBinding = samplerBindings[samplerIndex];
1163
1164 for (uint16_t index = 0; index < samplerBinding.textureUnitsCount; index++)
1165 {
1166 GLint textureUnit = samplerBinding.getTextureUnit(boundTextureUnits, index);
1167 if (++mActiveSamplerRefCounts[textureUnit] == 1)
1168 {
1169 uint32_t uniformIndex = executable.getUniformIndexFromSamplerIndex(samplerIndex);
1170 setActive(textureUnit, samplerBinding, executable.getUniforms()[uniformIndex]);
1171 }
1172 else
1173 {
1174 if (mActiveSamplerTypes[textureUnit] != samplerBinding.textureType ||
1175 mActiveSamplerYUV.test(textureUnit) !=
1176 IsSamplerYUVType(samplerBinding.samplerType))
1177 {
1178 hasSamplerTypeConflict(textureUnit);
1179 }
1180
1181 if (mActiveSamplerFormats[textureUnit] != samplerBinding.format)
1182 {
1183 hasSamplerFormatConflict(textureUnit);
1184 }
1185 }
1186 mActiveSamplersMask.set(textureUnit);
1187 }
1188 }
1189
1190 // Invalidate the validation cache.
1191 resetCachedValidateSamplersResult();
1192 }
1193
updateActiveImages(const ProgramExecutable & executable)1194 void ProgramExecutable::updateActiveImages(const ProgramExecutable &executable)
1195 {
1196 const std::vector<ImageBinding> &imageBindings = executable.getImageBindings();
1197 for (uint32_t imageIndex = 0; imageIndex < imageBindings.size(); ++imageIndex)
1198 {
1199 const gl::ImageBinding &imageBinding = imageBindings.at(imageIndex);
1200
1201 uint32_t uniformIndex = executable.getUniformIndexFromImageIndex(imageIndex);
1202 const gl::LinkedUniform &imageUniform = executable.getUniforms()[uniformIndex];
1203 const ShaderBitSet shaderBits = imageUniform.activeShaders();
1204 for (GLint imageUnit : imageBinding.boundImageUnits)
1205 {
1206 mActiveImagesMask.set(imageUnit);
1207 mActiveImageShaderBits[imageUnit] |= shaderBits;
1208 }
1209 }
1210 }
1211
setSamplerUniformTextureTypeAndFormat(size_t textureUnitIndex)1212 void ProgramExecutable::setSamplerUniformTextureTypeAndFormat(size_t textureUnitIndex)
1213 {
1214 bool foundBinding = false;
1215 TextureType foundType = TextureType::InvalidEnum;
1216 bool foundYUV = false;
1217 SamplerFormat foundFormat = SamplerFormat::InvalidEnum;
1218
1219 for (uint32_t samplerIndex = 0; samplerIndex < mSamplerBindings.size(); ++samplerIndex)
1220 {
1221 const SamplerBinding &binding = mSamplerBindings[samplerIndex];
1222
1223 // A conflict exists if samplers of different types are sourced by the same texture unit.
1224 // We need to check all bound textures to detect this error case.
1225 for (uint16_t index = 0; index < binding.textureUnitsCount; index++)
1226 {
1227 GLuint textureUnit = binding.getTextureUnit(mSamplerBoundTextureUnits, index);
1228 if (textureUnit != textureUnitIndex)
1229 {
1230 continue;
1231 }
1232
1233 if (!foundBinding)
1234 {
1235 foundBinding = true;
1236 foundType = binding.textureType;
1237 foundYUV = IsSamplerYUVType(binding.samplerType);
1238 foundFormat = binding.format;
1239 uint32_t uniformIndex = getUniformIndexFromSamplerIndex(samplerIndex);
1240 setActive(textureUnit, binding, mUniforms[uniformIndex]);
1241 }
1242 else
1243 {
1244 if (foundType != binding.textureType ||
1245 foundYUV != IsSamplerYUVType(binding.samplerType))
1246 {
1247 hasSamplerTypeConflict(textureUnit);
1248 }
1249
1250 if (foundFormat != binding.format)
1251 {
1252 hasSamplerFormatConflict(textureUnit);
1253 }
1254 }
1255 }
1256 }
1257 }
1258
saveLinkedStateInfo(const ProgramState & state)1259 void ProgramExecutable::saveLinkedStateInfo(const ProgramState &state)
1260 {
1261 for (ShaderType shaderType : getLinkedShaderStages())
1262 {
1263 const SharedCompiledShaderState &shader = state.getAttachedShader(shaderType);
1264 ASSERT(shader);
1265 mPod.linkedShaderVersions[shaderType] = shader->shaderVersion;
1266 mLinkedOutputVaryings[shaderType] = shader->outputVaryings;
1267 mLinkedInputVaryings[shaderType] = shader->inputVaryings;
1268 mLinkedUniforms[shaderType] = shader->uniforms;
1269 mLinkedUniformBlocks[shaderType] = shader->uniformBlocks;
1270 }
1271 }
1272
linkMergedVaryings(const Caps & caps,const Limitations & limitations,const Version & clientVersion,bool webglCompatibility,const ProgramMergedVaryings & mergedVaryings,const LinkingVariables & linkingVariables,ProgramVaryingPacking * varyingPacking)1273 bool ProgramExecutable::linkMergedVaryings(const Caps &caps,
1274 const Limitations &limitations,
1275 const Version &clientVersion,
1276 bool webglCompatibility,
1277 const ProgramMergedVaryings &mergedVaryings,
1278 const LinkingVariables &linkingVariables,
1279 ProgramVaryingPacking *varyingPacking)
1280 {
1281 ShaderType tfStage = GetLastPreFragmentStage(linkingVariables.isShaderStageUsedBitset);
1282
1283 if (!linkValidateTransformFeedback(caps, clientVersion, mergedVaryings, tfStage))
1284 {
1285 return false;
1286 }
1287
1288 // Map the varyings to the register file
1289 // In WebGL, we use a slightly different handling for packing variables.
1290 gl::PackMode packMode = PackMode::ANGLE_RELAXED;
1291 if (limitations.noFlexibleVaryingPacking)
1292 {
1293 // D3D9 pack mode is strictly more strict than WebGL, so takes priority.
1294 packMode = PackMode::ANGLE_NON_CONFORMANT_D3D9;
1295 }
1296 else if (webglCompatibility)
1297 {
1298 packMode = PackMode::WEBGL_STRICT;
1299 }
1300
1301 // Build active shader stage map.
1302 ShaderBitSet activeShadersMask;
1303 for (ShaderType shaderType : kAllGraphicsShaderTypes)
1304 {
1305 // - Check for attached shaders to handle the case of a Program linking the currently
1306 // attached shaders.
1307 // - Check for linked shaders to handle the case of a PPO linking separable programs before
1308 // drawing.
1309 if (linkingVariables.isShaderStageUsedBitset[shaderType] ||
1310 getLinkedShaderStages().test(shaderType))
1311 {
1312 activeShadersMask[shaderType] = true;
1313 }
1314 }
1315
1316 if (!varyingPacking->collectAndPackUserVaryings(*mInfoLog, caps, packMode, activeShadersMask,
1317 mergedVaryings, mTransformFeedbackVaryingNames,
1318 mPod.isSeparable))
1319 {
1320 return false;
1321 }
1322
1323 gatherTransformFeedbackVaryings(mergedVaryings, tfStage);
1324 updateTransformFeedbackStrides();
1325
1326 return true;
1327 }
1328
linkValidateTransformFeedback(const Caps & caps,const Version & clientVersion,const ProgramMergedVaryings & varyings,ShaderType stage)1329 bool ProgramExecutable::linkValidateTransformFeedback(const Caps &caps,
1330 const Version &clientVersion,
1331 const ProgramMergedVaryings &varyings,
1332 ShaderType stage)
1333 {
1334 // Validate the tf names regardless of the actual program varyings.
1335 std::set<std::string> uniqueNames;
1336 for (const std::string &tfVaryingName : mTransformFeedbackVaryingNames)
1337 {
1338 if (clientVersion < Version(3, 1) && tfVaryingName.find('[') != std::string::npos)
1339 {
1340 *mInfoLog << "Capture of array elements is undefined and not supported.";
1341 return false;
1342 }
1343 if (clientVersion >= Version(3, 1))
1344 {
1345 if (IncludeSameArrayElement(uniqueNames, tfVaryingName))
1346 {
1347 *mInfoLog << "Two transform feedback varyings include the same array element ("
1348 << tfVaryingName << ").";
1349 return false;
1350 }
1351 }
1352 else
1353 {
1354 if (uniqueNames.count(tfVaryingName) > 0)
1355 {
1356 *mInfoLog << "Two transform feedback varyings specify the same output variable ("
1357 << tfVaryingName << ").";
1358 return false;
1359 }
1360 }
1361 uniqueNames.insert(tfVaryingName);
1362 }
1363
1364 // From OpneGLES spec. 11.1.2.1: A program will fail to link if:
1365 // the count specified by TransformFeedbackVaryings is non-zero, but the
1366 // program object has no vertex, tessellation evaluation, or geometry shader
1367 if (mTransformFeedbackVaryingNames.size() > 0 &&
1368 !gl::ShaderTypeSupportsTransformFeedback(getLinkedTransformFeedbackStage()))
1369 {
1370 *mInfoLog << "Linked transform feedback stage " << getLinkedTransformFeedbackStage()
1371 << " does not support transform feedback varying.";
1372 return false;
1373 }
1374
1375 // Validate against program varyings.
1376 size_t totalComponents = 0;
1377 for (const std::string &tfVaryingName : mTransformFeedbackVaryingNames)
1378 {
1379 std::vector<unsigned int> subscripts;
1380 std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
1381
1382 const sh::ShaderVariable *var = FindOutputVaryingOrField(varyings, stage, baseName);
1383 if (var == nullptr)
1384 {
1385 *mInfoLog << "Transform feedback varying " << tfVaryingName
1386 << " does not exist in the vertex shader.";
1387 return false;
1388 }
1389
1390 // Validate the matching variable.
1391 if (var->isStruct())
1392 {
1393 *mInfoLog << "Struct cannot be captured directly (" << baseName << ").";
1394 return false;
1395 }
1396
1397 size_t elementCount = 0;
1398 size_t componentCount = 0;
1399
1400 if (var->isArray())
1401 {
1402 if (clientVersion < Version(3, 1))
1403 {
1404 *mInfoLog << "Capture of arrays is undefined and not supported.";
1405 return false;
1406 }
1407
1408 // GLSL ES 3.10 section 4.3.6: A vertex output can't be an array of arrays.
1409 ASSERT(!var->isArrayOfArrays());
1410
1411 if (!subscripts.empty() && subscripts[0] >= var->getOutermostArraySize())
1412 {
1413 *mInfoLog << "Cannot capture outbound array element '" << tfVaryingName << "'.";
1414 return false;
1415 }
1416 elementCount = (subscripts.empty() ? var->getOutermostArraySize() : 1);
1417 }
1418 else
1419 {
1420 if (!subscripts.empty())
1421 {
1422 *mInfoLog << "Varying '" << baseName
1423 << "' is not an array to be captured by element.";
1424 return false;
1425 }
1426 elementCount = 1;
1427 }
1428
1429 componentCount = VariableComponentCount(var->type) * elementCount;
1430 if (mPod.transformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
1431 componentCount > static_cast<GLuint>(caps.maxTransformFeedbackSeparateComponents))
1432 {
1433 *mInfoLog << "Transform feedback varying " << tfVaryingName << " components ("
1434 << componentCount << ") exceed the maximum separate components ("
1435 << caps.maxTransformFeedbackSeparateComponents << ").";
1436 return false;
1437 }
1438
1439 totalComponents += componentCount;
1440 if (mPod.transformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
1441 totalComponents > static_cast<GLuint>(caps.maxTransformFeedbackInterleavedComponents))
1442 {
1443 *mInfoLog << "Transform feedback varying total components (" << totalComponents
1444 << ") exceed the maximum interleaved components ("
1445 << caps.maxTransformFeedbackInterleavedComponents << ").";
1446 return false;
1447 }
1448 }
1449 return true;
1450 }
1451
gatherTransformFeedbackVaryings(const ProgramMergedVaryings & varyings,ShaderType stage)1452 void ProgramExecutable::gatherTransformFeedbackVaryings(const ProgramMergedVaryings &varyings,
1453 ShaderType stage)
1454 {
1455 // Gather the linked varyings that are used for transform feedback, they should all exist.
1456 mLinkedTransformFeedbackVaryings.clear();
1457 for (const std::string &tfVaryingName : mTransformFeedbackVaryingNames)
1458 {
1459 std::vector<unsigned int> subscripts;
1460 std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
1461 size_t subscript = GL_INVALID_INDEX;
1462 if (!subscripts.empty())
1463 {
1464 subscript = subscripts.back();
1465 }
1466 for (const ProgramVaryingRef &ref : varyings)
1467 {
1468 if (ref.frontShaderStage != stage)
1469 {
1470 continue;
1471 }
1472
1473 const sh::ShaderVariable *varying = ref.get(stage);
1474 if (baseName == varying->name)
1475 {
1476 mLinkedTransformFeedbackVaryings.emplace_back(*varying,
1477 static_cast<GLuint>(subscript));
1478 break;
1479 }
1480 else if (varying->isStruct())
1481 {
1482 GLuint fieldIndex = 0;
1483 const auto *field = varying->findField(tfVaryingName, &fieldIndex);
1484 if (field != nullptr)
1485 {
1486 mLinkedTransformFeedbackVaryings.emplace_back(*field, *varying);
1487 break;
1488 }
1489 }
1490 }
1491 }
1492 }
1493
updateTransformFeedbackStrides()1494 void ProgramExecutable::updateTransformFeedbackStrides()
1495 {
1496 if (mLinkedTransformFeedbackVaryings.empty())
1497 {
1498 return;
1499 }
1500
1501 if (mPod.transformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS)
1502 {
1503 mTransformFeedbackStrides.resize(1);
1504 size_t totalSize = 0;
1505 for (const TransformFeedbackVarying &varying : mLinkedTransformFeedbackVaryings)
1506 {
1507 totalSize += varying.size() * VariableExternalSize(varying.type);
1508 }
1509 mTransformFeedbackStrides[0] = static_cast<GLsizei>(totalSize);
1510 }
1511 else
1512 {
1513 mTransformFeedbackStrides.resize(mLinkedTransformFeedbackVaryings.size());
1514 for (size_t i = 0; i < mLinkedTransformFeedbackVaryings.size(); i++)
1515 {
1516 TransformFeedbackVarying &varying = mLinkedTransformFeedbackVaryings[i];
1517 mTransformFeedbackStrides[i] =
1518 static_cast<GLsizei>(varying.size() * VariableExternalSize(varying.type));
1519 }
1520 }
1521 }
1522
validateSamplersImpl(const Caps & caps) const1523 bool ProgramExecutable::validateSamplersImpl(const Caps &caps) const
1524 {
1525 // if any two active samplers in a program are of different types, but refer to the same
1526 // texture image unit, and this is the current program, then ValidateProgram will fail, and
1527 // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
1528 for (size_t textureUnit : mActiveSamplersMask)
1529 {
1530 if (mActiveSamplerTypes[textureUnit] == TextureType::InvalidEnum)
1531 {
1532 mCachedValidateSamplersResult = false;
1533 return false;
1534 }
1535
1536 if (mActiveSamplerFormats[textureUnit] == SamplerFormat::InvalidEnum)
1537 {
1538 mCachedValidateSamplersResult = false;
1539 return false;
1540 }
1541 }
1542
1543 mCachedValidateSamplersResult = true;
1544 return true;
1545 }
1546
linkValidateOutputVariables(const Caps & caps,const Version & version,GLuint combinedImageUniformsCount,GLuint combinedShaderStorageBlocksCount,int fragmentShaderVersion,const ProgramAliasedBindings & fragmentOutputLocations,const ProgramAliasedBindings & fragmentOutputIndices)1547 bool ProgramExecutable::linkValidateOutputVariables(
1548 const Caps &caps,
1549 const Version &version,
1550 GLuint combinedImageUniformsCount,
1551 GLuint combinedShaderStorageBlocksCount,
1552 int fragmentShaderVersion,
1553 const ProgramAliasedBindings &fragmentOutputLocations,
1554 const ProgramAliasedBindings &fragmentOutputIndices)
1555 {
1556 ASSERT(mPod.activeOutputVariablesMask.none());
1557 ASSERT(mPod.activeSecondaryOutputVariablesMask.none());
1558 ASSERT(mPod.drawBufferTypeMask.none());
1559 ASSERT(!mPod.hasYUVOutput);
1560
1561 if (fragmentShaderVersion == 100)
1562 {
1563 return gatherOutputTypes();
1564 }
1565
1566 // EXT_blend_func_extended doesn't specify anything related to binding specific elements of an
1567 // output array in explicit terms.
1568 //
1569 // Assuming fragData is an output array, you can defend the position that:
1570 // P1) you must support binding "fragData" because it's specified
1571 // P2) you must support querying "fragData[x]" because it's specified
1572 // P3) you must support binding "fragData[0]" because it's a frequently used pattern
1573 //
1574 // Then you can make the leap of faith:
1575 // P4) you must support binding "fragData[x]" because you support "fragData[0]"
1576 // P5) you must support binding "fragData[x]" because you support querying "fragData[x]"
1577 //
1578 // The spec brings in the "world of arrays" when it mentions binding the arrays and the
1579 // automatic binding. Thus it must be interpreted that the thing is not undefined, rather you
1580 // must infer the only possible interpretation (?). Note again: this need of interpretation
1581 // might be completely off of what GL spec logic is.
1582 //
1583 // The other complexity is that unless you implement this feature, it's hard to understand what
1584 // should happen when the client invokes the feature. You cannot add an additional error as it
1585 // is not specified. One can ignore it, but obviously it creates the discrepancies...
1586
1587 std::vector<VariableLocation> reservedLocations;
1588
1589 // Process any output API bindings for arrays that don't alias to the first element.
1590 for (const auto &bindingPair : fragmentOutputLocations)
1591 {
1592 const std::string &name = bindingPair.first;
1593 const ProgramBinding &binding = bindingPair.second;
1594
1595 size_t nameLengthWithoutArrayIndex;
1596 unsigned int arrayIndex = ParseArrayIndex(name, &nameLengthWithoutArrayIndex);
1597 if (arrayIndex == 0 || arrayIndex == GL_INVALID_INDEX)
1598 {
1599 continue;
1600 }
1601 for (unsigned int outputVariableIndex = 0; outputVariableIndex < mOutputVariables.size();
1602 outputVariableIndex++)
1603 {
1604 const ProgramOutput &outputVariable = mOutputVariables[outputVariableIndex];
1605 // Check that the binding corresponds to an output array and its array index fits.
1606 if (outputVariable.isBuiltIn() || !outputVariable.isArray() ||
1607 !angle::BeginsWith(outputVariable.name, name, nameLengthWithoutArrayIndex) ||
1608 arrayIndex >= outputVariable.getOutermostArraySize())
1609 {
1610 continue;
1611 }
1612
1613 // Get the API index that corresponds to this exact binding.
1614 // This index may differ from the index used for the array's base.
1615 std::vector<VariableLocation> &outputLocations =
1616 fragmentOutputIndices.getBindingByName(name) == 1 ? mSecondaryOutputLocations
1617 : mOutputLocations;
1618 unsigned int location = binding.location;
1619 VariableLocation locationInfo(arrayIndex, outputVariableIndex);
1620 if (location >= outputLocations.size())
1621 {
1622 outputLocations.resize(location + 1);
1623 }
1624 if (outputLocations[location].used())
1625 {
1626 *mInfoLog << "Location of variable " << outputVariable.name
1627 << " conflicts with another variable.";
1628 return false;
1629 }
1630 outputLocations[location] = locationInfo;
1631
1632 // Note the array binding location so that it can be skipped later.
1633 reservedLocations.push_back(locationInfo);
1634 }
1635 }
1636
1637 // Reserve locations for output variables whose location is fixed in the shader or through the
1638 // API. Otherwise, the remaining unallocated outputs will be processed later.
1639 for (unsigned int outputVariableIndex = 0; outputVariableIndex < mOutputVariables.size();
1640 outputVariableIndex++)
1641 {
1642 ProgramOutput &outputVariable = mOutputVariables[outputVariableIndex];
1643
1644 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
1645 if (outputVariable.isBuiltIn())
1646 continue;
1647
1648 int fixedLocation = GetOutputLocationForLink(fragmentOutputLocations, outputVariable);
1649 if (fixedLocation == -1)
1650 {
1651 // Here we're only reserving locations for variables whose location is fixed.
1652 continue;
1653 }
1654 unsigned int baseLocation = static_cast<unsigned int>(fixedLocation);
1655
1656 AssignOutputIndex(fragmentOutputIndices, outputVariable);
1657 ASSERT(outputVariable.pod.index == 0 || outputVariable.pod.index == 1);
1658 std::vector<VariableLocation> &outputLocations =
1659 outputVariable.pod.index == 0 ? mOutputLocations : mSecondaryOutputLocations;
1660
1661 // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of
1662 // structures, so we may use getBasicTypeElementCount().
1663 unsigned int elementCount = outputVariable.pod.basicTypeElementCount;
1664 if (FindUsedOutputLocation(outputLocations, baseLocation, elementCount, reservedLocations,
1665 outputVariableIndex))
1666 {
1667 *mInfoLog << "Location of variable " << outputVariable.name
1668 << " conflicts with another variable.";
1669 return false;
1670 }
1671 bool hasApiAssignedLocation = !outputVariable.pod.hasShaderAssignedLocation &&
1672 (fragmentOutputLocations.getBinding(outputVariable) != -1);
1673 AssignOutputLocations(outputLocations, baseLocation, elementCount, reservedLocations,
1674 outputVariableIndex, hasApiAssignedLocation, outputVariable);
1675 }
1676
1677 // Here we assign locations for the output variables that don't yet have them. Note that we're
1678 // not necessarily able to fit the variables optimally, since then we might have to try
1679 // different arrangements of output arrays. Now we just assign the locations in the order that
1680 // we got the output variables. The spec isn't clear on what kind of algorithm is required for
1681 // finding locations for the output variables, so this should be acceptable at least for now.
1682 GLuint maxLocation = static_cast<GLuint>(caps.maxDrawBuffers);
1683 if (!mSecondaryOutputLocations.empty())
1684 {
1685 // EXT_blend_func_extended: Program outputs will be validated against
1686 // MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT if there's even one output with index one.
1687 maxLocation = caps.maxDualSourceDrawBuffers;
1688 }
1689
1690 for (unsigned int outputVariableIndex = 0; outputVariableIndex < mOutputVariables.size();
1691 outputVariableIndex++)
1692 {
1693 ProgramOutput &outputVariable = mOutputVariables[outputVariableIndex];
1694
1695 // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
1696 if (outputVariable.isBuiltIn())
1697 continue;
1698
1699 AssignOutputIndex(fragmentOutputIndices, outputVariable);
1700 ASSERT(outputVariable.pod.index == 0 || outputVariable.pod.index == 1);
1701 std::vector<VariableLocation> &outputLocations =
1702 outputVariable.pod.index == 0 ? mOutputLocations : mSecondaryOutputLocations;
1703
1704 int fixedLocation = GetOutputLocationForLink(fragmentOutputLocations, outputVariable);
1705 unsigned int baseLocation = 0;
1706 unsigned int elementCount = outputVariable.pod.basicTypeElementCount;
1707 if (fixedLocation != -1)
1708 {
1709 // Secondary inputs might have caused the max location to drop below what has already
1710 // been explicitly assigned locations. Check for any fixed locations above the max
1711 // that should cause linking to fail.
1712 baseLocation = static_cast<unsigned int>(fixedLocation);
1713 }
1714 else
1715 {
1716 // No fixed location, so try to fit the output in unassigned locations.
1717 // Try baseLocations starting from 0 one at a time and see if the variable fits.
1718 while (FindUsedOutputLocation(outputLocations, baseLocation, elementCount,
1719 reservedLocations, outputVariableIndex))
1720 {
1721 baseLocation++;
1722 }
1723 AssignOutputLocations(outputLocations, baseLocation, elementCount, reservedLocations,
1724 outputVariableIndex, false, outputVariable);
1725 }
1726
1727 // Check for any elements assigned above the max location that are actually used.
1728 if (baseLocation + elementCount > maxLocation &&
1729 (baseLocation >= maxLocation ||
1730 FindUsedOutputLocation(outputLocations, maxLocation,
1731 baseLocation + elementCount - maxLocation, reservedLocations,
1732 outputVariableIndex)))
1733 {
1734 // EXT_blend_func_extended: Linking can fail:
1735 // "if the explicit binding assignments do not leave enough space for the linker to
1736 // automatically assign a location for a varying out array, which requires multiple
1737 // contiguous locations."
1738 *mInfoLog << "Could not fit output variable into available locations: "
1739 << outputVariable.name;
1740 return false;
1741 }
1742 }
1743
1744 if (!gatherOutputTypes())
1745 {
1746 return false;
1747 }
1748
1749 if (version >= ES_3_1)
1750 {
1751 // [OpenGL ES 3.1] Chapter 8.22 Page 203:
1752 // A link error will be generated if the sum of the number of active image uniforms used in
1753 // all shaders, the number of active shader storage blocks, and the number of active
1754 // fragment shader outputs exceeds the implementation-dependent value of
1755 // MAX_COMBINED_SHADER_OUTPUT_RESOURCES.
1756 if (combinedImageUniformsCount + combinedShaderStorageBlocksCount +
1757 mPod.activeOutputVariablesMask.count() >
1758 static_cast<GLuint>(caps.maxCombinedShaderOutputResources))
1759 {
1760 *mInfoLog
1761 << "The sum of the number of active image uniforms, active shader storage blocks "
1762 "and active fragment shader outputs exceeds "
1763 "MAX_COMBINED_SHADER_OUTPUT_RESOURCES ("
1764 << caps.maxCombinedShaderOutputResources << ")";
1765 return false;
1766 }
1767 }
1768
1769 return true;
1770 }
1771
gatherOutputTypes()1772 bool ProgramExecutable::gatherOutputTypes()
1773 {
1774 for (const ProgramOutput &outputVariable : mOutputVariables)
1775 {
1776 if (outputVariable.isBuiltIn() && outputVariable.name != "gl_FragColor" &&
1777 outputVariable.name != "gl_FragData" &&
1778 outputVariable.name != "gl_SecondaryFragColorEXT" &&
1779 outputVariable.name != "gl_SecondaryFragDataEXT")
1780 {
1781 continue;
1782 }
1783
1784 unsigned int baseLocation = (outputVariable.pod.location == -1
1785 ? 0u
1786 : static_cast<unsigned int>(outputVariable.pod.location));
1787
1788 const bool secondary =
1789 outputVariable.pod.index == 1 || (outputVariable.name == "gl_SecondaryFragColorEXT" ||
1790 outputVariable.name == "gl_SecondaryFragDataEXT");
1791
1792 const ComponentType componentType =
1793 GLenumToComponentType(VariableComponentType(outputVariable.pod.type));
1794
1795 // GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of
1796 // structures, so we may use getBasicTypeElementCount().
1797 unsigned int elementCount = outputVariable.pod.basicTypeElementCount;
1798 for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
1799 {
1800 const unsigned int location = baseLocation + elementIndex;
1801 ASSERT(location < mPod.activeOutputVariablesMask.size());
1802 ASSERT(location < mPod.activeSecondaryOutputVariablesMask.size());
1803 if (secondary)
1804 {
1805 mPod.activeSecondaryOutputVariablesMask.set(location);
1806 }
1807 else
1808 {
1809 mPod.activeOutputVariablesMask.set(location);
1810 }
1811 const ComponentType storedComponentType =
1812 gl::GetComponentTypeMask(mPod.drawBufferTypeMask, location);
1813 if (storedComponentType == ComponentType::InvalidEnum)
1814 {
1815 SetComponentTypeMask(componentType, location, &mPod.drawBufferTypeMask);
1816 }
1817 else if (storedComponentType != componentType)
1818 {
1819 *mInfoLog << "Inconsistent component types for fragment outputs at location "
1820 << location;
1821 return false;
1822 }
1823 }
1824
1825 if (outputVariable.pod.yuv)
1826 {
1827 ASSERT(mOutputVariables.size() == 1);
1828 mPod.hasYUVOutput = true;
1829 }
1830 }
1831
1832 return true;
1833 }
1834
linkUniforms(const Caps & caps,const ShaderMap<std::vector<sh::ShaderVariable>> & shaderUniforms,const ProgramAliasedBindings & uniformLocationBindings,GLuint * combinedImageUniformsCountOut,std::vector<UnusedUniform> * unusedUniformsOutOrNull)1835 bool ProgramExecutable::linkUniforms(
1836 const Caps &caps,
1837 const ShaderMap<std::vector<sh::ShaderVariable>> &shaderUniforms,
1838 const ProgramAliasedBindings &uniformLocationBindings,
1839 GLuint *combinedImageUniformsCountOut,
1840 std::vector<UnusedUniform> *unusedUniformsOutOrNull)
1841 {
1842 UniformLinker linker(mPod.linkedShaderStages, shaderUniforms);
1843 if (!linker.link(caps, *mInfoLog, uniformLocationBindings))
1844 {
1845 return false;
1846 }
1847
1848 linker.getResults(&mUniforms, &mUniformNames, &mUniformMappedNames, unusedUniformsOutOrNull,
1849 &mUniformLocations);
1850
1851 linkSamplerAndImageBindings(combinedImageUniformsCountOut);
1852
1853 if (!linkAtomicCounterBuffers(caps))
1854 {
1855 return false;
1856 }
1857
1858 return true;
1859 }
1860
linkSamplerAndImageBindings(GLuint * combinedImageUniforms)1861 void ProgramExecutable::linkSamplerAndImageBindings(GLuint *combinedImageUniforms)
1862 {
1863 ASSERT(combinedImageUniforms);
1864
1865 // Iterate over mExecutable->mUniforms from the back, and find the range of subpass inputs,
1866 // atomic counters, images and samplers in that order.
1867 auto highIter = mUniforms.rbegin();
1868 auto lowIter = highIter;
1869
1870 unsigned int high = static_cast<unsigned int>(mUniforms.size());
1871 unsigned int low = high;
1872
1873 // Note that uniform block uniforms are not yet appended to this list.
1874 ASSERT(mUniforms.empty() || highIter->isAtomicCounter() || highIter->isImage() ||
1875 highIter->isSampler() || highIter->isInDefaultBlock());
1876
1877 for (; lowIter != mUniforms.rend() && lowIter->isAtomicCounter(); ++lowIter)
1878 {
1879 --low;
1880 }
1881
1882 mPod.atomicCounterUniformRange = RangeUI(low, high);
1883
1884 highIter = lowIter;
1885 high = low;
1886
1887 for (; lowIter != mUniforms.rend() && lowIter->isImage(); ++lowIter)
1888 {
1889 --low;
1890 }
1891
1892 mPod.imageUniformRange = RangeUI(low, high);
1893 *combinedImageUniforms = 0u;
1894 // If uniform is a image type, insert it into the mImageBindings array.
1895 for (unsigned int imageIndex : mPod.imageUniformRange)
1896 {
1897 // ES3.1 (section 7.6.1) and GLSL ES3.1 (section 4.4.5), Uniform*i{v} commands
1898 // cannot load values into a uniform defined as an image. if declare without a
1899 // binding qualifier, any uniform image variable (include all elements of
1900 // unbound image array) should be bound to unit zero.
1901 auto &imageUniform = mUniforms[imageIndex];
1902 TextureType textureType = ImageTypeToTextureType(imageUniform.getType());
1903 const GLuint arraySize = imageUniform.getBasicTypeElementCount();
1904
1905 if (imageUniform.getBinding() == -1)
1906 {
1907 mImageBindings.emplace_back(
1908 ImageBinding(imageUniform.getBasicTypeElementCount(), textureType));
1909 }
1910 else
1911 {
1912 // The arrays of arrays are flattened to arrays, it needs to record the array offset for
1913 // the correct binding image unit.
1914 mImageBindings.emplace_back(ImageBinding(
1915 imageUniform.getBinding() + imageUniform.pod.parentArrayIndex * arraySize,
1916 imageUniform.getBasicTypeElementCount(), textureType));
1917 }
1918
1919 *combinedImageUniforms += imageUniform.activeShaderCount() * arraySize;
1920 }
1921
1922 highIter = lowIter;
1923 high = low;
1924
1925 for (; lowIter != mUniforms.rend() && lowIter->isSampler(); ++lowIter)
1926 {
1927 --low;
1928 }
1929
1930 mPod.samplerUniformRange = RangeUI(low, high);
1931
1932 // If uniform is a sampler type, insert it into the mSamplerBindings array.
1933 uint16_t totalCount = 0;
1934 for (unsigned int samplerIndex : mPod.samplerUniformRange)
1935 {
1936 const auto &samplerUniform = mUniforms[samplerIndex];
1937 TextureType textureType = SamplerTypeToTextureType(samplerUniform.getType());
1938 GLenum samplerType = samplerUniform.getType();
1939 uint16_t elementCount = samplerUniform.getBasicTypeElementCount();
1940 SamplerFormat format = GetUniformTypeInfo(samplerType).samplerFormat;
1941 mSamplerBindings.emplace_back(textureType, samplerType, format, totalCount, elementCount);
1942 totalCount += elementCount;
1943 }
1944 mSamplerBoundTextureUnits.resize(totalCount, 0);
1945
1946 // Whatever is left constitutes the default uniforms.
1947 mPod.defaultUniformRange = RangeUI(0, low);
1948 }
1949
linkAtomicCounterBuffers(const Caps & caps)1950 bool ProgramExecutable::linkAtomicCounterBuffers(const Caps &caps)
1951 {
1952 for (unsigned int index : mPod.atomicCounterUniformRange)
1953 {
1954 auto &uniform = mUniforms[index];
1955
1956 uniform.pod.blockOffset = uniform.getOffset();
1957 uniform.pod.blockArrayStride = uniform.isArray() ? 4 : 0;
1958 uniform.pod.blockMatrixStride = 0;
1959 uniform.pod.flagBits.blockIsRowMajorMatrix = false;
1960 uniform.pod.flagBits.isBlock = true;
1961
1962 bool found = false;
1963 for (size_t bufferIndex = 0; bufferIndex < mAtomicCounterBuffers.size(); ++bufferIndex)
1964 {
1965 AtomicCounterBuffer &buffer = mAtomicCounterBuffers[bufferIndex];
1966 if (buffer.pod.inShaderBinding == uniform.getBinding())
1967 {
1968 buffer.memberIndexes.push_back(index);
1969 SetBitField(uniform.pod.bufferIndex, bufferIndex);
1970 found = true;
1971 buffer.unionReferencesWith(uniform);
1972 break;
1973 }
1974 }
1975 if (!found)
1976 {
1977 AtomicCounterBuffer atomicCounterBuffer;
1978 atomicCounterBuffer.pod.inShaderBinding = uniform.getBinding();
1979 atomicCounterBuffer.memberIndexes.push_back(index);
1980 atomicCounterBuffer.unionReferencesWith(uniform);
1981 mAtomicCounterBuffers.push_back(atomicCounterBuffer);
1982 SetBitField(uniform.pod.bufferIndex, mAtomicCounterBuffers.size() - 1);
1983 }
1984 }
1985
1986 // Count each atomic counter buffer to validate against
1987 // per-stage and combined gl_Max*AtomicCounterBuffers.
1988 GLint combinedShaderACBCount = 0;
1989 gl::ShaderMap<GLint> perShaderACBCount = {};
1990 for (size_t bufferIndex = 0; bufferIndex < mAtomicCounterBuffers.size(); ++bufferIndex)
1991 {
1992 AtomicCounterBuffer &acb = mAtomicCounterBuffers[bufferIndex];
1993 const ShaderBitSet shaderStages = acb.activeShaders();
1994 for (gl::ShaderType shaderType : shaderStages)
1995 {
1996 ++perShaderACBCount[shaderType];
1997 }
1998 ++combinedShaderACBCount;
1999 }
2000 if (combinedShaderACBCount > caps.maxCombinedAtomicCounterBuffers)
2001 {
2002 *mInfoLog << " combined AtomicCounterBuffers count exceeds limit";
2003 return false;
2004 }
2005 for (gl::ShaderType stage : gl::AllShaderTypes())
2006 {
2007 if (perShaderACBCount[stage] > caps.maxShaderAtomicCounterBuffers[stage])
2008 {
2009 *mInfoLog << GetShaderTypeString(stage)
2010 << " shader AtomicCounterBuffers count exceeds limit";
2011 return false;
2012 }
2013 }
2014 return true;
2015 }
2016
copyInputsFromProgram(const ProgramExecutable & executable)2017 void ProgramExecutable::copyInputsFromProgram(const ProgramExecutable &executable)
2018 {
2019 mProgramInputs = executable.getProgramInputs();
2020 }
2021
copyUniformBuffersFromProgram(const ProgramExecutable & executable,ShaderType shaderType,ProgramUniformBlockArray<GLuint> * ppoUniformBlockMap)2022 void ProgramExecutable::copyUniformBuffersFromProgram(
2023 const ProgramExecutable &executable,
2024 ShaderType shaderType,
2025 ProgramUniformBlockArray<GLuint> *ppoUniformBlockMap)
2026 {
2027 AppendActiveBlocks(shaderType, executable.getUniformBlocks(), mUniformBlocks,
2028 ppoUniformBlockMap);
2029
2030 const std::vector<InterfaceBlock> &blocks = executable.getUniformBlocks();
2031 for (size_t blockIndex = 0; blockIndex < blocks.size(); ++blockIndex)
2032 {
2033 if (!blocks[blockIndex].isActive(shaderType))
2034 {
2035 continue;
2036 }
2037 const uint32_t blockIndexInPPO = (*ppoUniformBlockMap)[static_cast<uint32_t>(blockIndex)];
2038 ASSERT(blockIndexInPPO < mUniformBlocks.size());
2039
2040 // Set the block buffer binding in the PPO to the same binding as the program's.
2041 remapUniformBlockBinding({blockIndexInPPO}, executable.getUniformBlockBinding(blockIndex));
2042 }
2043 }
2044
copyStorageBuffersFromProgram(const ProgramExecutable & executable,ShaderType shaderType)2045 void ProgramExecutable::copyStorageBuffersFromProgram(const ProgramExecutable &executable,
2046 ShaderType shaderType)
2047 {
2048 AppendActiveBlocks(shaderType, executable.getShaderStorageBlocks(), mShaderStorageBlocks,
2049 nullptr);
2050 AppendActiveBlocks(shaderType, executable.getAtomicCounterBuffers(), mAtomicCounterBuffers,
2051 nullptr);
2052
2053 // Buffer variable info is queried through the program, and program pipelines don't access it.
2054 ASSERT(mBufferVariables.empty());
2055 }
2056
clearSamplerBindings()2057 void ProgramExecutable::clearSamplerBindings()
2058 {
2059 mSamplerBindings.clear();
2060 mSamplerBoundTextureUnits.clear();
2061 }
2062
copySamplerBindingsFromProgram(const ProgramExecutable & executable)2063 void ProgramExecutable::copySamplerBindingsFromProgram(const ProgramExecutable &executable)
2064 {
2065 const std::vector<SamplerBinding> &bindings = executable.getSamplerBindings();
2066 const std::vector<GLuint> &textureUnits = executable.getSamplerBoundTextureUnits();
2067 uint16_t adjustedStartIndex = mSamplerBoundTextureUnits.size();
2068 mSamplerBoundTextureUnits.insert(mSamplerBoundTextureUnits.end(), textureUnits.begin(),
2069 textureUnits.end());
2070 for (const SamplerBinding &binding : bindings)
2071 {
2072 mSamplerBindings.push_back(binding);
2073 mSamplerBindings.back().textureUnitsStartIndex += adjustedStartIndex;
2074 }
2075 }
2076
copyImageBindingsFromProgram(const ProgramExecutable & executable)2077 void ProgramExecutable::copyImageBindingsFromProgram(const ProgramExecutable &executable)
2078 {
2079 const std::vector<ImageBinding> &bindings = executable.getImageBindings();
2080 mImageBindings.insert(mImageBindings.end(), bindings.begin(), bindings.end());
2081 }
2082
copyOutputsFromProgram(const ProgramExecutable & executable)2083 void ProgramExecutable::copyOutputsFromProgram(const ProgramExecutable &executable)
2084 {
2085 mOutputVariables = executable.getOutputVariables();
2086 mOutputLocations = executable.getOutputLocations();
2087 mSecondaryOutputLocations = executable.getSecondaryOutputLocations();
2088 }
2089
copyUniformsFromProgramMap(const ShaderMap<SharedProgramExecutable> & executables)2090 void ProgramExecutable::copyUniformsFromProgramMap(
2091 const ShaderMap<SharedProgramExecutable> &executables)
2092 {
2093 // Merge default uniforms.
2094 auto getDefaultRange = [](const ProgramExecutable &state) {
2095 return state.getDefaultUniformRange();
2096 };
2097 mPod.defaultUniformRange = AddUniforms(executables, mPod.linkedShaderStages, &mUniforms,
2098 &mUniformNames, &mUniformMappedNames, getDefaultRange);
2099
2100 // Merge sampler uniforms.
2101 auto getSamplerRange = [](const ProgramExecutable &state) {
2102 return state.getSamplerUniformRange();
2103 };
2104 mPod.samplerUniformRange = AddUniforms(executables, mPod.linkedShaderStages, &mUniforms,
2105 &mUniformNames, &mUniformMappedNames, getSamplerRange);
2106
2107 // Merge image uniforms.
2108 auto getImageRange = [](const ProgramExecutable &state) {
2109 return state.getImageUniformRange();
2110 };
2111 mPod.imageUniformRange = AddUniforms(executables, mPod.linkedShaderStages, &mUniforms,
2112 &mUniformNames, &mUniformMappedNames, getImageRange);
2113
2114 // Merge atomic counter uniforms.
2115 auto getAtomicRange = [](const ProgramExecutable &state) {
2116 return state.getAtomicCounterUniformRange();
2117 };
2118 mPod.atomicCounterUniformRange =
2119 AddUniforms(executables, mPod.linkedShaderStages, &mUniforms, &mUniformNames,
2120 &mUniformMappedNames, getAtomicRange);
2121
2122 // Note: uniforms are set through the program, and the program pipeline never needs it.
2123 ASSERT(mUniformLocations.empty());
2124 }
2125
getResourceName(const std::string name,GLsizei bufSize,GLsizei * length,GLchar * dest) const2126 void ProgramExecutable::getResourceName(const std::string name,
2127 GLsizei bufSize,
2128 GLsizei *length,
2129 GLchar *dest) const
2130 {
2131 if (length)
2132 {
2133 *length = 0;
2134 }
2135
2136 if (bufSize > 0)
2137 {
2138 CopyStringToBuffer(dest, name, bufSize, length);
2139 }
2140 }
2141
getInputResourceIndex(const GLchar * name) const2142 GLuint ProgramExecutable::getInputResourceIndex(const GLchar *name) const
2143 {
2144 const std::string nameString = StripLastArrayIndex(name);
2145
2146 for (size_t index = 0; index < mProgramInputs.size(); index++)
2147 {
2148 if (mProgramInputs[index].name == nameString)
2149 {
2150 return static_cast<GLuint>(index);
2151 }
2152 }
2153
2154 return GL_INVALID_INDEX;
2155 }
2156
getInputResourceMaxNameSize() const2157 GLuint ProgramExecutable::getInputResourceMaxNameSize() const
2158 {
2159 GLint max = 0;
2160
2161 for (const ProgramInput &resource : mProgramInputs)
2162 {
2163 max = GetResourceMaxNameSize(resource, max);
2164 }
2165
2166 return max;
2167 }
2168
getOutputResourceMaxNameSize() const2169 GLuint ProgramExecutable::getOutputResourceMaxNameSize() const
2170 {
2171 GLint max = 0;
2172
2173 for (const gl::ProgramOutput &resource : mOutputVariables)
2174 {
2175 max = GetResourceMaxNameSize(resource, max);
2176 }
2177
2178 return max;
2179 }
2180
getInputResourceLocation(const GLchar * name) const2181 GLuint ProgramExecutable::getInputResourceLocation(const GLchar *name) const
2182 {
2183 const GLuint index = getInputResourceIndex(name);
2184 if (index == GL_INVALID_INDEX)
2185 {
2186 return index;
2187 }
2188
2189 const ProgramInput &variable = getInputResource(index);
2190
2191 return GetResourceLocation(name, variable, variable.getLocation());
2192 }
2193
getOutputResourceLocation(const GLchar * name) const2194 GLuint ProgramExecutable::getOutputResourceLocation(const GLchar *name) const
2195 {
2196 const GLuint index = getOutputResourceIndex(name);
2197 if (index == GL_INVALID_INDEX)
2198 {
2199 return index;
2200 }
2201
2202 const gl::ProgramOutput &variable = getOutputResource(index);
2203
2204 return GetResourceLocation(name, variable, variable.pod.location);
2205 }
2206
getOutputResourceIndex(const GLchar * name) const2207 GLuint ProgramExecutable::getOutputResourceIndex(const GLchar *name) const
2208 {
2209 const std::string nameString = StripLastArrayIndex(name);
2210
2211 for (size_t index = 0; index < mOutputVariables.size(); index++)
2212 {
2213 if (mOutputVariables[index].name == nameString)
2214 {
2215 return static_cast<GLuint>(index);
2216 }
2217 }
2218
2219 return GL_INVALID_INDEX;
2220 }
2221
getInputResourceName(GLuint index,GLsizei bufSize,GLsizei * length,GLchar * name) const2222 void ProgramExecutable::getInputResourceName(GLuint index,
2223 GLsizei bufSize,
2224 GLsizei *length,
2225 GLchar *name) const
2226 {
2227 getResourceName(getInputResourceName(index), bufSize, length, name);
2228 }
2229
getOutputResourceName(GLuint index,GLsizei bufSize,GLsizei * length,GLchar * name) const2230 void ProgramExecutable::getOutputResourceName(GLuint index,
2231 GLsizei bufSize,
2232 GLsizei *length,
2233 GLchar *name) const
2234 {
2235 getResourceName(getOutputResourceName(index), bufSize, length, name);
2236 }
2237
getUniformResourceName(GLuint index,GLsizei bufSize,GLsizei * length,GLchar * name) const2238 void ProgramExecutable::getUniformResourceName(GLuint index,
2239 GLsizei bufSize,
2240 GLsizei *length,
2241 GLchar *name) const
2242 {
2243 getResourceName(getUniformNameByIndex(index), bufSize, length, name);
2244 }
2245
getBufferVariableResourceName(GLuint index,GLsizei bufSize,GLsizei * length,GLchar * name) const2246 void ProgramExecutable::getBufferVariableResourceName(GLuint index,
2247 GLsizei bufSize,
2248 GLsizei *length,
2249 GLchar *name) const
2250 {
2251 ASSERT(index < mBufferVariables.size());
2252 getResourceName(mBufferVariables[index].name, bufSize, length, name);
2253 }
2254
getInputResourceName(GLuint index) const2255 const std::string ProgramExecutable::getInputResourceName(GLuint index) const
2256 {
2257 return GetResourceName(getInputResource(index));
2258 }
2259
getOutputResourceName(GLuint index) const2260 const std::string ProgramExecutable::getOutputResourceName(GLuint index) const
2261 {
2262 return GetResourceName(getOutputResource(index));
2263 }
2264
getFragDataLocation(const std::string & name) const2265 GLint ProgramExecutable::getFragDataLocation(const std::string &name) const
2266 {
2267 const GLint primaryLocation = GetVariableLocation(mOutputVariables, mOutputLocations, name);
2268 if (primaryLocation != -1)
2269 {
2270 return primaryLocation;
2271 }
2272 return GetVariableLocation(mOutputVariables, mSecondaryOutputLocations, name);
2273 }
2274
getFragDataIndex(const std::string & name) const2275 GLint ProgramExecutable::getFragDataIndex(const std::string &name) const
2276 {
2277 if (GetVariableLocation(mOutputVariables, mOutputLocations, name) != -1)
2278 {
2279 return 0;
2280 }
2281 if (GetVariableLocation(mOutputVariables, mSecondaryOutputLocations, name) != -1)
2282 {
2283 return 1;
2284 }
2285 return -1;
2286 }
2287
getTransformFeedbackVaryingMaxLength() const2288 GLsizei ProgramExecutable::getTransformFeedbackVaryingMaxLength() const
2289 {
2290 GLsizei maxSize = 0;
2291 for (const TransformFeedbackVarying &var : mLinkedTransformFeedbackVaryings)
2292 {
2293 maxSize = std::max(maxSize, static_cast<GLsizei>(var.nameWithArrayIndex().length() + 1));
2294 }
2295
2296 return maxSize;
2297 }
2298
getTransformFeedbackVaryingResourceIndex(const GLchar * name) const2299 GLuint ProgramExecutable::getTransformFeedbackVaryingResourceIndex(const GLchar *name) const
2300 {
2301 for (GLuint tfIndex = 0; tfIndex < mLinkedTransformFeedbackVaryings.size(); ++tfIndex)
2302 {
2303 if (mLinkedTransformFeedbackVaryings[tfIndex].nameWithArrayIndex() == name)
2304 {
2305 return tfIndex;
2306 }
2307 }
2308 return GL_INVALID_INDEX;
2309 }
2310
getTransformFeedbackVaryingResource(GLuint index) const2311 const TransformFeedbackVarying &ProgramExecutable::getTransformFeedbackVaryingResource(
2312 GLuint index) const
2313 {
2314 ASSERT(index < mLinkedTransformFeedbackVaryings.size());
2315 return mLinkedTransformFeedbackVaryings[index];
2316 }
2317
getTransformFeedbackVarying(GLuint index,GLsizei bufSize,GLsizei * length,GLsizei * size,GLenum * type,GLchar * name) const2318 void ProgramExecutable::getTransformFeedbackVarying(GLuint index,
2319 GLsizei bufSize,
2320 GLsizei *length,
2321 GLsizei *size,
2322 GLenum *type,
2323 GLchar *name) const
2324 {
2325 if (mLinkedTransformFeedbackVaryings.empty())
2326 {
2327 // Program is not successfully linked
2328 return;
2329 }
2330
2331 ASSERT(index < mLinkedTransformFeedbackVaryings.size());
2332 const auto &var = mLinkedTransformFeedbackVaryings[index];
2333 std::string varName = var.nameWithArrayIndex();
2334 GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varName.length()));
2335 if (length)
2336 {
2337 *length = lastNameIdx;
2338 }
2339 if (size)
2340 {
2341 *size = var.size();
2342 }
2343 if (type)
2344 {
2345 *type = var.type;
2346 }
2347 if (name)
2348 {
2349 memcpy(name, varName.c_str(), lastNameIdx);
2350 name[lastNameIdx] = '\0';
2351 }
2352 }
2353
getActiveAttribute(GLuint index,GLsizei bufsize,GLsizei * length,GLint * size,GLenum * type,GLchar * name) const2354 void ProgramExecutable::getActiveAttribute(GLuint index,
2355 GLsizei bufsize,
2356 GLsizei *length,
2357 GLint *size,
2358 GLenum *type,
2359 GLchar *name) const
2360 {
2361 if (mProgramInputs.empty())
2362 {
2363 // Program is not successfully linked
2364 if (bufsize > 0)
2365 {
2366 name[0] = '\0';
2367 }
2368
2369 if (length)
2370 {
2371 *length = 0;
2372 }
2373
2374 *type = GL_NONE;
2375 *size = 1;
2376 return;
2377 }
2378
2379 ASSERT(index < mProgramInputs.size());
2380 const ProgramInput &attrib = mProgramInputs[index];
2381
2382 if (bufsize > 0)
2383 {
2384 CopyStringToBuffer(name, attrib.name, bufsize, length);
2385 }
2386
2387 // Always a single 'type' instance
2388 *size = 1;
2389 *type = attrib.getType();
2390 }
2391
getActiveAttributeMaxLength() const2392 GLint ProgramExecutable::getActiveAttributeMaxLength() const
2393 {
2394 size_t maxLength = 0;
2395
2396 for (const ProgramInput &attrib : mProgramInputs)
2397 {
2398 maxLength = std::max(attrib.name.length() + 1, maxLength);
2399 }
2400
2401 return static_cast<GLint>(maxLength);
2402 }
2403
getAttributeLocation(const std::string & name) const2404 GLuint ProgramExecutable::getAttributeLocation(const std::string &name) const
2405 {
2406 for (const ProgramInput &attribute : mProgramInputs)
2407 {
2408 if (attribute.name == name)
2409 {
2410 return attribute.getLocation();
2411 }
2412 }
2413
2414 return static_cast<GLuint>(-1);
2415 }
2416
getActiveUniform(GLuint index,GLsizei bufsize,GLsizei * length,GLint * size,GLenum * type,GLchar * name) const2417 void ProgramExecutable::getActiveUniform(GLuint index,
2418 GLsizei bufsize,
2419 GLsizei *length,
2420 GLint *size,
2421 GLenum *type,
2422 GLchar *name) const
2423 {
2424 if (mUniforms.empty())
2425 {
2426 // Program is not successfully linked
2427 if (bufsize > 0)
2428 {
2429 name[0] = '\0';
2430 }
2431
2432 if (length)
2433 {
2434 *length = 0;
2435 }
2436
2437 *size = 0;
2438 *type = GL_NONE;
2439 }
2440
2441 ASSERT(index < mUniforms.size());
2442 const LinkedUniform &uniform = mUniforms[index];
2443
2444 if (bufsize > 0)
2445 {
2446 const std::string &string = getUniformNameByIndex(index);
2447 CopyStringToBuffer(name, string, bufsize, length);
2448 }
2449
2450 *size = clampCast<GLint>(uniform.getBasicTypeElementCount());
2451 *type = uniform.getType();
2452 }
2453
getActiveUniformMaxLength() const2454 GLint ProgramExecutable::getActiveUniformMaxLength() const
2455 {
2456 size_t maxLength = 0;
2457
2458 for (GLuint index = 0; index < static_cast<size_t>(mUniformNames.size()); index++)
2459 {
2460 const std::string &uniformName = getUniformNameByIndex(index);
2461 if (!uniformName.empty())
2462 {
2463 size_t length = uniformName.length() + 1u;
2464 if (getUniformByIndex(index).isArray())
2465 {
2466 length += 3; // Counting in "[0]".
2467 }
2468 maxLength = std::max(length, maxLength);
2469 }
2470 }
2471
2472 return static_cast<GLint>(maxLength);
2473 }
2474
isValidUniformLocation(UniformLocation location) const2475 bool ProgramExecutable::isValidUniformLocation(UniformLocation location) const
2476 {
2477 ASSERT(angle::IsValueInRangeForNumericType<GLint>(mUniformLocations.size()));
2478 return location.value >= 0 && static_cast<size_t>(location.value) < mUniformLocations.size() &&
2479 mUniformLocations[location.value].used();
2480 }
2481
getUniformByLocation(UniformLocation location) const2482 const LinkedUniform &ProgramExecutable::getUniformByLocation(UniformLocation location) const
2483 {
2484 ASSERT(location.value >= 0 && static_cast<size_t>(location.value) < mUniformLocations.size());
2485 return mUniforms[getUniformIndexFromLocation(location)];
2486 }
2487
getUniformLocation(UniformLocation location) const2488 const VariableLocation &ProgramExecutable::getUniformLocation(UniformLocation location) const
2489 {
2490 ASSERT(location.value >= 0 && static_cast<size_t>(location.value) < mUniformLocations.size());
2491 return mUniformLocations[location.value];
2492 }
2493
getUniformLocation(const std::string & name) const2494 UniformLocation ProgramExecutable::getUniformLocation(const std::string &name) const
2495 {
2496 return {GetUniformLocation(mUniforms, mUniformNames, mUniformLocations, name)};
2497 }
2498
getUniformIndex(const std::string & name) const2499 GLuint ProgramExecutable::getUniformIndex(const std::string &name) const
2500 {
2501 return getUniformIndexFromName(name);
2502 }
2503
shouldIgnoreUniform(UniformLocation location) const2504 bool ProgramExecutable::shouldIgnoreUniform(UniformLocation location) const
2505 {
2506 // Casting to size_t will convert negative values to large positive avoiding double check.
2507 // Adding ERR() log to report out of bound location harms performance on Android.
2508 return ANGLE_UNLIKELY(static_cast<size_t>(location.value) >= mUniformLocations.size() ||
2509 mUniformLocations[location.value].ignored);
2510 }
2511
getUniformIndexFromName(const std::string & name) const2512 GLuint ProgramExecutable::getUniformIndexFromName(const std::string &name) const
2513 {
2514 return GetUniformIndexFromName(mUniforms, mUniformNames, name);
2515 }
2516
getBufferVariableIndexFromName(const std::string & name) const2517 GLuint ProgramExecutable::getBufferVariableIndexFromName(const std::string &name) const
2518 {
2519 return GetResourceIndexFromName(mBufferVariables, name);
2520 }
2521
getUniformIndexFromLocation(UniformLocation location) const2522 GLuint ProgramExecutable::getUniformIndexFromLocation(UniformLocation location) const
2523 {
2524 ASSERT(location.value >= 0 && static_cast<size_t>(location.value) < mUniformLocations.size());
2525 return mUniformLocations[location.value].index;
2526 }
2527
getSamplerIndex(UniformLocation location) const2528 Optional<GLuint> ProgramExecutable::getSamplerIndex(UniformLocation location) const
2529 {
2530 GLuint index = getUniformIndexFromLocation(location);
2531 if (!isSamplerUniformIndex(index))
2532 {
2533 return Optional<GLuint>::Invalid();
2534 }
2535
2536 return getSamplerIndexFromUniformIndex(index);
2537 }
2538
isSamplerUniformIndex(GLuint index) const2539 bool ProgramExecutable::isSamplerUniformIndex(GLuint index) const
2540 {
2541 return mPod.samplerUniformRange.contains(index);
2542 }
2543
getSamplerIndexFromUniformIndex(GLuint uniformIndex) const2544 GLuint ProgramExecutable::getSamplerIndexFromUniformIndex(GLuint uniformIndex) const
2545 {
2546 ASSERT(isSamplerUniformIndex(uniformIndex));
2547 return uniformIndex - mPod.samplerUniformRange.low();
2548 }
2549
isImageUniformIndex(GLuint index) const2550 bool ProgramExecutable::isImageUniformIndex(GLuint index) const
2551 {
2552 return mPod.imageUniformRange.contains(index);
2553 }
2554
getImageIndexFromUniformIndex(GLuint uniformIndex) const2555 GLuint ProgramExecutable::getImageIndexFromUniformIndex(GLuint uniformIndex) const
2556 {
2557 ASSERT(isImageUniformIndex(uniformIndex));
2558 return uniformIndex - mPod.imageUniformRange.low();
2559 }
2560
getActiveUniformBlockName(const Context * context,const UniformBlockIndex blockIndex,GLsizei bufSize,GLsizei * length,GLchar * blockName) const2561 void ProgramExecutable::getActiveUniformBlockName(const Context *context,
2562 const UniformBlockIndex blockIndex,
2563 GLsizei bufSize,
2564 GLsizei *length,
2565 GLchar *blockName) const
2566 {
2567 GetInterfaceBlockName(blockIndex, mUniformBlocks, bufSize, length, blockName);
2568 }
2569
getActiveShaderStorageBlockName(const GLuint blockIndex,GLsizei bufSize,GLsizei * length,GLchar * blockName) const2570 void ProgramExecutable::getActiveShaderStorageBlockName(const GLuint blockIndex,
2571 GLsizei bufSize,
2572 GLsizei *length,
2573 GLchar *blockName) const
2574 {
2575 GetInterfaceBlockName({blockIndex}, mShaderStorageBlocks, bufSize, length, blockName);
2576 }
2577
getActiveUniformBlockMaxNameLength() const2578 GLint ProgramExecutable::getActiveUniformBlockMaxNameLength() const
2579 {
2580 return GetActiveInterfaceBlockMaxNameLength(mUniformBlocks);
2581 }
2582
getActiveShaderStorageBlockMaxNameLength() const2583 GLint ProgramExecutable::getActiveShaderStorageBlockMaxNameLength() const
2584 {
2585 return GetActiveInterfaceBlockMaxNameLength(mShaderStorageBlocks);
2586 }
2587
getUniformBlockIndex(const std::string & name) const2588 GLuint ProgramExecutable::getUniformBlockIndex(const std::string &name) const
2589 {
2590 return GetInterfaceBlockIndex(mUniformBlocks, name);
2591 }
2592
getShaderStorageBlockIndex(const std::string & name) const2593 GLuint ProgramExecutable::getShaderStorageBlockIndex(const std::string &name) const
2594 {
2595 return GetInterfaceBlockIndex(mShaderStorageBlocks, name);
2596 }
2597
getSamplerUniformBinding(const VariableLocation & uniformLocation) const2598 GLuint ProgramExecutable::getSamplerUniformBinding(const VariableLocation &uniformLocation) const
2599 {
2600 GLuint samplerIndex = getSamplerIndexFromUniformIndex(uniformLocation.index);
2601 const SamplerBinding &samplerBinding = mSamplerBindings[samplerIndex];
2602 if (uniformLocation.arrayIndex >= samplerBinding.textureUnitsCount)
2603 {
2604 return 0;
2605 }
2606
2607 const std::vector<GLuint> &boundTextureUnits = mSamplerBoundTextureUnits;
2608 return samplerBinding.getTextureUnit(boundTextureUnits, uniformLocation.arrayIndex);
2609 }
2610
getImageUniformBinding(const VariableLocation & uniformLocation) const2611 GLuint ProgramExecutable::getImageUniformBinding(const VariableLocation &uniformLocation) const
2612 {
2613 GLuint imageIndex = getImageIndexFromUniformIndex(uniformLocation.index);
2614
2615 const std::vector<GLuint> &boundImageUnits = mImageBindings[imageIndex].boundImageUnits;
2616 return boundImageUnits[uniformLocation.arrayIndex];
2617 }
2618
2619 template <typename UniformT,
2620 GLint UniformSize,
2621 void (rx::ProgramExecutableImpl::*SetUniformFunc)(GLint, GLsizei, const UniformT *)>
setUniformGeneric(UniformLocation location,GLsizei count,const UniformT * v)2622 void ProgramExecutable::setUniformGeneric(UniformLocation location,
2623 GLsizei count,
2624 const UniformT *v)
2625 {
2626 if (shouldIgnoreUniform(location))
2627 {
2628 return;
2629 }
2630
2631 const VariableLocation &locationInfo = mUniformLocations[location.value];
2632 GLsizei clampedCount = clampUniformCount(locationInfo, count, UniformSize, v);
2633 (mImplementation->*SetUniformFunc)(location.value, clampedCount, v);
2634 }
2635
setUniform1fv(UniformLocation location,GLsizei count,const GLfloat * v)2636 void ProgramExecutable::setUniform1fv(UniformLocation location, GLsizei count, const GLfloat *v)
2637 {
2638 setUniformGeneric<GLfloat, 1, &rx::ProgramExecutableImpl::setUniform1fv>(location, count, v);
2639 }
2640
setUniform2fv(UniformLocation location,GLsizei count,const GLfloat * v)2641 void ProgramExecutable::setUniform2fv(UniformLocation location, GLsizei count, const GLfloat *v)
2642 {
2643 setUniformGeneric<GLfloat, 2, &rx::ProgramExecutableImpl::setUniform2fv>(location, count, v);
2644 }
2645
setUniform3fv(UniformLocation location,GLsizei count,const GLfloat * v)2646 void ProgramExecutable::setUniform3fv(UniformLocation location, GLsizei count, const GLfloat *v)
2647 {
2648 setUniformGeneric<GLfloat, 3, &rx::ProgramExecutableImpl::setUniform3fv>(location, count, v);
2649 }
2650
setUniform4fv(UniformLocation location,GLsizei count,const GLfloat * v)2651 void ProgramExecutable::setUniform4fv(UniformLocation location, GLsizei count, const GLfloat *v)
2652 {
2653 setUniformGeneric<GLfloat, 4, &rx::ProgramExecutableImpl::setUniform4fv>(location, count, v);
2654 }
2655
setUniform1iv(Context * context,UniformLocation location,GLsizei count,const GLint * v)2656 void ProgramExecutable::setUniform1iv(Context *context,
2657 UniformLocation location,
2658 GLsizei count,
2659 const GLint *v)
2660 {
2661 if (shouldIgnoreUniform(location))
2662 {
2663 return;
2664 }
2665
2666 const VariableLocation &locationInfo = mUniformLocations[location.value];
2667 GLsizei clampedCount = clampUniformCount(locationInfo, count, 1, v);
2668
2669 mImplementation->setUniform1iv(location.value, clampedCount, v);
2670
2671 if (isSamplerUniformIndex(locationInfo.index))
2672 {
2673 updateSamplerUniform(context, locationInfo, clampedCount, v);
2674 }
2675 }
2676
setUniform2iv(UniformLocation location,GLsizei count,const GLint * v)2677 void ProgramExecutable::setUniform2iv(UniformLocation location, GLsizei count, const GLint *v)
2678 {
2679 setUniformGeneric<GLint, 2, &rx::ProgramExecutableImpl::setUniform2iv>(location, count, v);
2680 }
2681
setUniform3iv(UniformLocation location,GLsizei count,const GLint * v)2682 void ProgramExecutable::setUniform3iv(UniformLocation location, GLsizei count, const GLint *v)
2683 {
2684 setUniformGeneric<GLint, 3, &rx::ProgramExecutableImpl::setUniform3iv>(location, count, v);
2685 }
2686
setUniform4iv(UniformLocation location,GLsizei count,const GLint * v)2687 void ProgramExecutable::setUniform4iv(UniformLocation location, GLsizei count, const GLint *v)
2688 {
2689 setUniformGeneric<GLint, 4, &rx::ProgramExecutableImpl::setUniform4iv>(location, count, v);
2690 }
2691
setUniform1uiv(UniformLocation location,GLsizei count,const GLuint * v)2692 void ProgramExecutable::setUniform1uiv(UniformLocation location, GLsizei count, const GLuint *v)
2693 {
2694 setUniformGeneric<GLuint, 1, &rx::ProgramExecutableImpl::setUniform1uiv>(location, count, v);
2695 }
2696
setUniform2uiv(UniformLocation location,GLsizei count,const GLuint * v)2697 void ProgramExecutable::setUniform2uiv(UniformLocation location, GLsizei count, const GLuint *v)
2698 {
2699 setUniformGeneric<GLuint, 2, &rx::ProgramExecutableImpl::setUniform2uiv>(location, count, v);
2700 }
2701
setUniform3uiv(UniformLocation location,GLsizei count,const GLuint * v)2702 void ProgramExecutable::setUniform3uiv(UniformLocation location, GLsizei count, const GLuint *v)
2703 {
2704 setUniformGeneric<GLuint, 3, &rx::ProgramExecutableImpl::setUniform3uiv>(location, count, v);
2705 }
2706
setUniform4uiv(UniformLocation location,GLsizei count,const GLuint * v)2707 void ProgramExecutable::setUniform4uiv(UniformLocation location, GLsizei count, const GLuint *v)
2708 {
2709 setUniformGeneric<GLuint, 4, &rx::ProgramExecutableImpl::setUniform4uiv>(location, count, v);
2710 }
2711
2712 template <typename UniformT,
2713 GLint MatrixC,
2714 GLint MatrixR,
2715 void (rx::ProgramExecutableImpl::*
2716 SetUniformMatrixFunc)(GLint, GLsizei, GLboolean, const UniformT *)>
setUniformMatrixGeneric(UniformLocation location,GLsizei count,GLboolean transpose,const UniformT * v)2717 void ProgramExecutable::setUniformMatrixGeneric(UniformLocation location,
2718 GLsizei count,
2719 GLboolean transpose,
2720 const UniformT *v)
2721 {
2722 if (shouldIgnoreUniform(location))
2723 {
2724 return;
2725 }
2726
2727 GLsizei clampedCount = clampMatrixUniformCount<MatrixC, MatrixR>(location, count, transpose, v);
2728 (mImplementation->*SetUniformMatrixFunc)(location.value, clampedCount, transpose, v);
2729 }
2730
setUniformMatrix2fv(UniformLocation location,GLsizei count,GLboolean transpose,const GLfloat * v)2731 void ProgramExecutable::setUniformMatrix2fv(UniformLocation location,
2732 GLsizei count,
2733 GLboolean transpose,
2734 const GLfloat *v)
2735 {
2736 setUniformMatrixGeneric<GLfloat, 2, 2, &rx::ProgramExecutableImpl::setUniformMatrix2fv>(
2737 location, count, transpose, v);
2738 }
2739
setUniformMatrix3fv(UniformLocation location,GLsizei count,GLboolean transpose,const GLfloat * v)2740 void ProgramExecutable::setUniformMatrix3fv(UniformLocation location,
2741 GLsizei count,
2742 GLboolean transpose,
2743 const GLfloat *v)
2744 {
2745 setUniformMatrixGeneric<GLfloat, 3, 3, &rx::ProgramExecutableImpl::setUniformMatrix3fv>(
2746 location, count, transpose, v);
2747 }
2748
setUniformMatrix4fv(UniformLocation location,GLsizei count,GLboolean transpose,const GLfloat * v)2749 void ProgramExecutable::setUniformMatrix4fv(UniformLocation location,
2750 GLsizei count,
2751 GLboolean transpose,
2752 const GLfloat *v)
2753 {
2754 setUniformMatrixGeneric<GLfloat, 4, 4, &rx::ProgramExecutableImpl::setUniformMatrix4fv>(
2755 location, count, transpose, v);
2756 }
2757
setUniformMatrix2x3fv(UniformLocation location,GLsizei count,GLboolean transpose,const GLfloat * v)2758 void ProgramExecutable::setUniformMatrix2x3fv(UniformLocation location,
2759 GLsizei count,
2760 GLboolean transpose,
2761 const GLfloat *v)
2762 {
2763 setUniformMatrixGeneric<GLfloat, 2, 3, &rx::ProgramExecutableImpl::setUniformMatrix2x3fv>(
2764 location, count, transpose, v);
2765 }
2766
setUniformMatrix2x4fv(UniformLocation location,GLsizei count,GLboolean transpose,const GLfloat * v)2767 void ProgramExecutable::setUniformMatrix2x4fv(UniformLocation location,
2768 GLsizei count,
2769 GLboolean transpose,
2770 const GLfloat *v)
2771 {
2772 setUniformMatrixGeneric<GLfloat, 2, 4, &rx::ProgramExecutableImpl::setUniformMatrix2x4fv>(
2773 location, count, transpose, v);
2774 }
2775
setUniformMatrix3x2fv(UniformLocation location,GLsizei count,GLboolean transpose,const GLfloat * v)2776 void ProgramExecutable::setUniformMatrix3x2fv(UniformLocation location,
2777 GLsizei count,
2778 GLboolean transpose,
2779 const GLfloat *v)
2780 {
2781 setUniformMatrixGeneric<GLfloat, 3, 2, &rx::ProgramExecutableImpl::setUniformMatrix3x2fv>(
2782 location, count, transpose, v);
2783 }
2784
setUniformMatrix3x4fv(UniformLocation location,GLsizei count,GLboolean transpose,const GLfloat * v)2785 void ProgramExecutable::setUniformMatrix3x4fv(UniformLocation location,
2786 GLsizei count,
2787 GLboolean transpose,
2788 const GLfloat *v)
2789 {
2790 setUniformMatrixGeneric<GLfloat, 3, 4, &rx::ProgramExecutableImpl::setUniformMatrix3x4fv>(
2791 location, count, transpose, v);
2792 }
2793
setUniformMatrix4x2fv(UniformLocation location,GLsizei count,GLboolean transpose,const GLfloat * v)2794 void ProgramExecutable::setUniformMatrix4x2fv(UniformLocation location,
2795 GLsizei count,
2796 GLboolean transpose,
2797 const GLfloat *v)
2798 {
2799 setUniformMatrixGeneric<GLfloat, 4, 2, &rx::ProgramExecutableImpl::setUniformMatrix4x2fv>(
2800 location, count, transpose, v);
2801 }
2802
setUniformMatrix4x3fv(UniformLocation location,GLsizei count,GLboolean transpose,const GLfloat * v)2803 void ProgramExecutable::setUniformMatrix4x3fv(UniformLocation location,
2804 GLsizei count,
2805 GLboolean transpose,
2806 const GLfloat *v)
2807 {
2808 setUniformMatrixGeneric<GLfloat, 4, 3, &rx::ProgramExecutableImpl::setUniformMatrix4x3fv>(
2809 location, count, transpose, v);
2810 }
2811
getUniformfv(const Context * context,UniformLocation location,GLfloat * v) const2812 void ProgramExecutable::getUniformfv(const Context *context,
2813 UniformLocation location,
2814 GLfloat *v) const
2815 {
2816 const VariableLocation &uniformLocation = mUniformLocations[location.value];
2817 const LinkedUniform &uniform = mUniforms[uniformLocation.index];
2818
2819 if (uniform.isSampler())
2820 {
2821 *v = static_cast<GLfloat>(getSamplerUniformBinding(uniformLocation));
2822 return;
2823 }
2824 else if (uniform.isImage())
2825 {
2826 *v = static_cast<GLfloat>(getImageUniformBinding(uniformLocation));
2827 return;
2828 }
2829
2830 const GLenum nativeType = VariableComponentType(uniform.getType());
2831 if (nativeType == GL_FLOAT)
2832 {
2833 mImplementation->getUniformfv(context, location.value, v);
2834 }
2835 else
2836 {
2837 getUniformInternal(context, v, location, nativeType,
2838 VariableComponentCount(uniform.getType()));
2839 }
2840 }
2841
getUniformiv(const Context * context,UniformLocation location,GLint * v) const2842 void ProgramExecutable::getUniformiv(const Context *context,
2843 UniformLocation location,
2844 GLint *v) const
2845 {
2846 const VariableLocation &uniformLocation = mUniformLocations[location.value];
2847 const LinkedUniform &uniform = mUniforms[uniformLocation.index];
2848
2849 if (uniform.isSampler())
2850 {
2851 *v = static_cast<GLint>(getSamplerUniformBinding(uniformLocation));
2852 return;
2853 }
2854 else if (uniform.isImage())
2855 {
2856 *v = static_cast<GLint>(getImageUniformBinding(uniformLocation));
2857 return;
2858 }
2859
2860 const GLenum nativeType = VariableComponentType(uniform.getType());
2861 if (nativeType == GL_INT || nativeType == GL_BOOL)
2862 {
2863 mImplementation->getUniformiv(context, location.value, v);
2864 }
2865 else
2866 {
2867 getUniformInternal(context, v, location, nativeType,
2868 VariableComponentCount(uniform.getType()));
2869 }
2870 }
2871
getUniformuiv(const Context * context,UniformLocation location,GLuint * v) const2872 void ProgramExecutable::getUniformuiv(const Context *context,
2873 UniformLocation location,
2874 GLuint *v) const
2875 {
2876 const VariableLocation &uniformLocation = mUniformLocations[location.value];
2877 const LinkedUniform &uniform = mUniforms[uniformLocation.index];
2878
2879 if (uniform.isSampler())
2880 {
2881 *v = getSamplerUniformBinding(uniformLocation);
2882 return;
2883 }
2884 else if (uniform.isImage())
2885 {
2886 *v = getImageUniformBinding(uniformLocation);
2887 return;
2888 }
2889
2890 const GLenum nativeType = VariableComponentType(uniform.getType());
2891 if (nativeType == GL_UNSIGNED_INT)
2892 {
2893 mImplementation->getUniformuiv(context, location.value, v);
2894 }
2895 else
2896 {
2897 getUniformInternal(context, v, location, nativeType,
2898 VariableComponentCount(uniform.getType()));
2899 }
2900 }
2901
initInterfaceBlockBindings()2902 void ProgramExecutable::initInterfaceBlockBindings()
2903 {
2904 // Set initial bindings from shader.
2905 for (size_t blockIndex = 0; blockIndex < mUniformBlocks.size(); blockIndex++)
2906 {
2907 InterfaceBlock &uniformBlock = mUniformBlocks[blockIndex];
2908 // All interface blocks either have |binding| defined, or default to binding 0.
2909 ASSERT(uniformBlock.pod.inShaderBinding >= 0);
2910 remapUniformBlockBinding({static_cast<uint32_t>(blockIndex)},
2911 uniformBlock.pod.inShaderBinding);
2912
2913 // This is called on program link/binary, which means the executable has changed. There is
2914 // no need to send any additional notifications to the contexts (where the program may be
2915 // current) or program pipeline objects (that have this program attached), because they
2916 // already assume all blocks are dirty.
2917 }
2918 }
2919
remapUniformBlockBinding(UniformBlockIndex uniformBlockIndex,GLuint uniformBlockBinding)2920 void ProgramExecutable::remapUniformBlockBinding(UniformBlockIndex uniformBlockIndex,
2921 GLuint uniformBlockBinding)
2922 {
2923 // Remove previous binding
2924 const GLuint previousBinding = mUniformBlockIndexToBufferBinding[uniformBlockIndex.value];
2925 mUniformBufferBindingToUniformBlocks[previousBinding].reset(uniformBlockIndex.value);
2926
2927 // Set new binding
2928 mUniformBlockIndexToBufferBinding[uniformBlockIndex.value] = uniformBlockBinding;
2929 mUniformBufferBindingToUniformBlocks[uniformBlockBinding].set(uniformBlockIndex.value);
2930 }
2931
setUniformValuesFromBindingQualifiers()2932 void ProgramExecutable::setUniformValuesFromBindingQualifiers()
2933 {
2934 for (unsigned int samplerIndex : mPod.samplerUniformRange)
2935 {
2936 const auto &samplerUniform = mUniforms[samplerIndex];
2937 if (samplerUniform.getBinding() != -1)
2938 {
2939 const std::string &uniformName = getUniformNameByIndex(samplerIndex);
2940 UniformLocation location = getUniformLocation(uniformName);
2941 ASSERT(location.value != -1);
2942 std::vector<GLint> boundTextureUnits;
2943 for (unsigned int elementIndex = 0;
2944 elementIndex < samplerUniform.getBasicTypeElementCount(); ++elementIndex)
2945 {
2946 boundTextureUnits.push_back(samplerUniform.getBinding() + elementIndex);
2947 }
2948
2949 // Here we pass nullptr to avoid a large chain of calls that need a non-const Context.
2950 // We know it's safe not to notify the Context because this is only called after link.
2951 setUniform1iv(nullptr, location, static_cast<GLsizei>(boundTextureUnits.size()),
2952 boundTextureUnits.data());
2953 }
2954 }
2955 }
2956
2957 template <typename T>
clampUniformCount(const VariableLocation & locationInfo,GLsizei count,int vectorSize,const T * v)2958 GLsizei ProgramExecutable::clampUniformCount(const VariableLocation &locationInfo,
2959 GLsizei count,
2960 int vectorSize,
2961 const T *v)
2962 {
2963 if (count == 1)
2964 return 1;
2965
2966 const LinkedUniform &linkedUniform = mUniforms[locationInfo.index];
2967
2968 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
2969 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
2970 unsigned int remainingElements =
2971 linkedUniform.getBasicTypeElementCount() - locationInfo.arrayIndex;
2972 GLsizei maxElementCount =
2973 static_cast<GLsizei>(remainingElements * linkedUniform.getElementComponents());
2974
2975 if (count * vectorSize > maxElementCount)
2976 {
2977 return maxElementCount / vectorSize;
2978 }
2979
2980 return count;
2981 }
2982
2983 template <size_t cols, size_t rows, typename T>
clampMatrixUniformCount(UniformLocation location,GLsizei count,GLboolean transpose,const T * v)2984 GLsizei ProgramExecutable::clampMatrixUniformCount(UniformLocation location,
2985 GLsizei count,
2986 GLboolean transpose,
2987 const T *v)
2988 {
2989 const VariableLocation &locationInfo = mUniformLocations[location.value];
2990
2991 if (!transpose)
2992 {
2993 return clampUniformCount(locationInfo, count, cols * rows, v);
2994 }
2995
2996 const LinkedUniform &linkedUniform = mUniforms[locationInfo.index];
2997
2998 // OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
2999 // element index used, as reported by GetActiveUniform, will be ignored by the GL."
3000 unsigned int remainingElements =
3001 linkedUniform.getBasicTypeElementCount() - locationInfo.arrayIndex;
3002 return std::min(count, static_cast<GLsizei>(remainingElements));
3003 }
3004
updateSamplerUniform(Context * context,const VariableLocation & locationInfo,GLsizei clampedCount,const GLint * v)3005 void ProgramExecutable::updateSamplerUniform(Context *context,
3006 const VariableLocation &locationInfo,
3007 GLsizei clampedCount,
3008 const GLint *v)
3009 {
3010 ASSERT(isSamplerUniformIndex(locationInfo.index));
3011 GLuint samplerIndex = getSamplerIndexFromUniformIndex(locationInfo.index);
3012 const SamplerBinding &samplerBinding = mSamplerBindings[samplerIndex];
3013 std::vector<GLuint> &boundTextureUnits = mSamplerBoundTextureUnits;
3014
3015 if (locationInfo.arrayIndex >= samplerBinding.textureUnitsCount)
3016 {
3017 return;
3018 }
3019 GLsizei safeUniformCount =
3020 std::min(clampedCount,
3021 static_cast<GLsizei>(samplerBinding.textureUnitsCount - locationInfo.arrayIndex));
3022
3023 // Update the sampler uniforms.
3024 for (uint16_t arrayIndex = 0; arrayIndex < safeUniformCount; ++arrayIndex)
3025 {
3026 GLint oldTextureUnit =
3027 samplerBinding.getTextureUnit(boundTextureUnits, arrayIndex + locationInfo.arrayIndex);
3028 GLint newTextureUnit = v[arrayIndex];
3029
3030 if (oldTextureUnit == newTextureUnit)
3031 {
3032 continue;
3033 }
3034
3035 // Update sampler's bound textureUnit
3036 boundTextureUnits[samplerBinding.textureUnitsStartIndex + arrayIndex +
3037 locationInfo.arrayIndex] = newTextureUnit;
3038
3039 // Update the reference counts.
3040 uint32_t &oldRefCount = mActiveSamplerRefCounts[oldTextureUnit];
3041 uint32_t &newRefCount = mActiveSamplerRefCounts[newTextureUnit];
3042 ASSERT(oldRefCount > 0);
3043 ASSERT(newRefCount < std::numeric_limits<uint32_t>::max());
3044 oldRefCount--;
3045 newRefCount++;
3046
3047 // Check for binding type change.
3048 TextureType newSamplerType = mActiveSamplerTypes[newTextureUnit];
3049 TextureType oldSamplerType = mActiveSamplerTypes[oldTextureUnit];
3050 SamplerFormat newSamplerFormat = mActiveSamplerFormats[newTextureUnit];
3051 SamplerFormat oldSamplerFormat = mActiveSamplerFormats[oldTextureUnit];
3052 bool newSamplerYUV = mActiveSamplerYUV.test(newTextureUnit);
3053
3054 if (newRefCount == 1)
3055 {
3056 setActive(newTextureUnit, samplerBinding, mUniforms[locationInfo.index]);
3057 }
3058 else
3059 {
3060 if (newSamplerType != samplerBinding.textureType ||
3061 newSamplerYUV != IsSamplerYUVType(samplerBinding.samplerType))
3062 {
3063 hasSamplerTypeConflict(newTextureUnit);
3064 }
3065
3066 if (newSamplerFormat != samplerBinding.format)
3067 {
3068 hasSamplerFormatConflict(newTextureUnit);
3069 }
3070 }
3071
3072 // Unset previously active sampler.
3073 if (oldRefCount == 0)
3074 {
3075 setInactive(oldTextureUnit);
3076 }
3077 else
3078 {
3079 if (oldSamplerType == TextureType::InvalidEnum ||
3080 oldSamplerFormat == SamplerFormat::InvalidEnum)
3081 {
3082 // Previous conflict. Check if this new change fixed the conflict.
3083 setSamplerUniformTextureTypeAndFormat(oldTextureUnit);
3084 }
3085 }
3086
3087 // Update the observing PPO's executable, if any.
3088 // Do this before any of the Context work, since that uses the current ProgramExecutable,
3089 // which will be the PPO's if this Program is bound to it, rather than this Program's.
3090 if (mPod.isSeparable)
3091 {
3092 onStateChange(angle::SubjectMessage::ProgramTextureOrImageBindingChanged);
3093 }
3094
3095 // Notify context.
3096 if (context)
3097 {
3098 context->onSamplerUniformChange(newTextureUnit);
3099 context->onSamplerUniformChange(oldTextureUnit);
3100 }
3101 }
3102
3103 // Invalidate the validation cache.
3104 resetCachedValidateSamplersResult();
3105 // Inform any PPOs this Program may be bound to.
3106 onStateChange(angle::SubjectMessage::SamplerUniformsUpdated);
3107 }
3108
3109 // Driver differences mean that doing the uniform value cast ourselves gives consistent results.
3110 // EG: on NVIDIA drivers, it was observed that getUniformi for MAX_INT+1 returned MIN_INT.
3111 template <typename DestT>
getUniformInternal(const Context * context,DestT * dataOut,UniformLocation location,GLenum nativeType,int components) const3112 void ProgramExecutable::getUniformInternal(const Context *context,
3113 DestT *dataOut,
3114 UniformLocation location,
3115 GLenum nativeType,
3116 int components) const
3117 {
3118 switch (nativeType)
3119 {
3120 case GL_BOOL:
3121 {
3122 GLint tempValue[16] = {0};
3123 mImplementation->getUniformiv(context, location.value, tempValue);
3124 UniformStateQueryCastLoop<GLboolean>(
3125 dataOut, reinterpret_cast<const uint8_t *>(tempValue), components);
3126 break;
3127 }
3128 case GL_INT:
3129 {
3130 GLint tempValue[16] = {0};
3131 mImplementation->getUniformiv(context, location.value, tempValue);
3132 UniformStateQueryCastLoop<GLint>(dataOut, reinterpret_cast<const uint8_t *>(tempValue),
3133 components);
3134 break;
3135 }
3136 case GL_UNSIGNED_INT:
3137 {
3138 GLuint tempValue[16] = {0};
3139 mImplementation->getUniformuiv(context, location.value, tempValue);
3140 UniformStateQueryCastLoop<GLuint>(dataOut, reinterpret_cast<const uint8_t *>(tempValue),
3141 components);
3142 break;
3143 }
3144 case GL_FLOAT:
3145 {
3146 GLfloat tempValue[16] = {0};
3147 mImplementation->getUniformfv(context, location.value, tempValue);
3148 UniformStateQueryCastLoop<GLfloat>(
3149 dataOut, reinterpret_cast<const uint8_t *>(tempValue), components);
3150 break;
3151 }
3152 default:
3153 UNREACHABLE();
3154 break;
3155 }
3156 }
3157
setDrawIDUniform(GLint drawid)3158 void ProgramExecutable::setDrawIDUniform(GLint drawid)
3159 {
3160 ASSERT(hasDrawIDUniform());
3161 mImplementation->setUniform1iv(mPod.drawIDLocation, 1, &drawid);
3162 }
3163
setBaseVertexUniform(GLint baseVertex)3164 void ProgramExecutable::setBaseVertexUniform(GLint baseVertex)
3165 {
3166 ASSERT(hasBaseVertexUniform());
3167 if (baseVertex == mCachedBaseVertex)
3168 {
3169 return;
3170 }
3171 mCachedBaseVertex = baseVertex;
3172 mImplementation->setUniform1iv(mPod.baseVertexLocation, 1, &baseVertex);
3173 }
3174
setBaseInstanceUniform(GLuint baseInstance)3175 void ProgramExecutable::setBaseInstanceUniform(GLuint baseInstance)
3176 {
3177 ASSERT(hasBaseInstanceUniform());
3178 if (baseInstance == mCachedBaseInstance)
3179 {
3180 return;
3181 }
3182 mCachedBaseInstance = baseInstance;
3183 GLint baseInstanceInt = baseInstance;
3184 mImplementation->setUniform1iv(mPod.baseInstanceLocation, 1, &baseInstanceInt);
3185 }
3186
waitForPostLinkTasks(const Context * context)3187 void ProgramExecutable::waitForPostLinkTasks(const Context *context)
3188 {
3189 if (mPostLinkSubTasks.empty())
3190 {
3191 return;
3192 }
3193
3194 mImplementation->waitForPostLinkTasks(context);
3195
3196 // Implementation is expected to call |onPostLinkTasksComplete|.
3197 ASSERT(mPostLinkSubTasks.empty());
3198 }
3199
InstallExecutable(const Context * context,const SharedProgramExecutable & toInstall,SharedProgramExecutable * executable)3200 void InstallExecutable(const Context *context,
3201 const SharedProgramExecutable &toInstall,
3202 SharedProgramExecutable *executable)
3203 {
3204 // There should never be a need to re-install the same executable.
3205 ASSERT(toInstall.get() != executable->get());
3206
3207 // Destroy the old executable before it gets deleted.
3208 UninstallExecutable(context, executable);
3209
3210 // Install the new executable.
3211 *executable = toInstall;
3212 }
3213
UninstallExecutable(const Context * context,SharedProgramExecutable * executable)3214 void UninstallExecutable(const Context *context, SharedProgramExecutable *executable)
3215 {
3216 if (executable->use_count() == 1)
3217 {
3218 (*executable)->destroy(context);
3219 }
3220
3221 executable->reset();
3222 }
3223
3224 } // namespace gl
3225