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