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