• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2020 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // ProgramExecutable.cpp: Collects the interfaces common to both Programs and
7 // ProgramPipelines in order to execute/draw with either.
8 
9 #include "libANGLE/ProgramExecutable.h"
10 
11 #include "libANGLE/Context.h"
12 #include "libANGLE/Program.h"
13 #include "libANGLE/Shader.h"
14 
15 namespace gl
16 {
17 namespace
18 {
IncludeSameArrayElement(const std::set<std::string> & nameSet,const std::string & name)19 bool IncludeSameArrayElement(const std::set<std::string> &nameSet, const std::string &name)
20 {
21     std::vector<unsigned int> subscripts;
22     std::string baseName = ParseResourceName(name, &subscripts);
23     for (const std::string &nameInSet : nameSet)
24     {
25         std::vector<unsigned int> arrayIndices;
26         std::string arrayName = ParseResourceName(nameInSet, &arrayIndices);
27         if (baseName == arrayName &&
28             (subscripts.empty() || arrayIndices.empty() || subscripts == arrayIndices))
29         {
30             return true;
31         }
32     }
33     return false;
34 }
35 
36 // Find the matching varying or field by name.
FindOutputVaryingOrField(const ProgramMergedVaryings & varyings,ShaderType stage,const std::string & name)37 const sh::ShaderVariable *FindOutputVaryingOrField(const ProgramMergedVaryings &varyings,
38                                                    ShaderType stage,
39                                                    const std::string &name)
40 {
41     const sh::ShaderVariable *var = nullptr;
42     for (const ProgramVaryingRef &ref : varyings)
43     {
44         if (ref.frontShaderStage != stage)
45         {
46             continue;
47         }
48 
49         const sh::ShaderVariable *varying = ref.get(stage);
50         if (varying->name == name)
51         {
52             var = varying;
53             break;
54         }
55         GLuint fieldIndex = 0;
56         var               = varying->findField(name, &fieldIndex);
57         if (var != nullptr)
58         {
59             break;
60         }
61     }
62     return var;
63 }
64 }  // anonymous namespace
65 
ProgramExecutable()66 ProgramExecutable::ProgramExecutable()
67     : mMaxActiveAttribLocation(0),
68       mAttributesTypeMask(0),
69       mAttributesMask(0),
70       mActiveSamplerRefCounts{},
71       mCanDrawWith(false),
72       mYUVOutput(false),
73       mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
74       mDefaultUniformRange(0, 0),
75       mSamplerUniformRange(0, 0),
76       mImageUniformRange(0, 0),
77       mFragmentInoutRange(0, 0),
78       mPipelineHasGraphicsUniformBuffers(false),
79       mPipelineHasComputeUniformBuffers(false),
80       mPipelineHasGraphicsStorageBuffers(false),
81       mPipelineHasComputeStorageBuffers(false),
82       mPipelineHasGraphicsAtomicCounterBuffers(false),
83       mPipelineHasComputeAtomicCounterBuffers(false),
84       mPipelineHasGraphicsDefaultUniforms(false),
85       mPipelineHasComputeDefaultUniforms(false),
86       mPipelineHasGraphicsTextures(false),
87       mPipelineHasComputeTextures(false),
88       mPipelineHasGraphicsImages(false),
89       mPipelineHasComputeImages(false),
90       mIsCompute(false),
91       // [GL_EXT_geometry_shader] Table 20.22
92       mGeometryShaderInputPrimitiveType(PrimitiveMode::Triangles),
93       mGeometryShaderOutputPrimitiveType(PrimitiveMode::TriangleStrip),
94       mGeometryShaderInvocations(1),
95       mGeometryShaderMaxVertices(0),
96       mTessControlShaderVertices(0),
97       mTessGenMode(GL_NONE),
98       mTessGenSpacing(GL_NONE),
99       mTessGenVertexOrder(GL_NONE),
100       mTessGenPointMode(GL_NONE)
101 {
102     reset();
103 }
104 
ProgramExecutable(const ProgramExecutable & other)105 ProgramExecutable::ProgramExecutable(const ProgramExecutable &other)
106     : mLinkedGraphicsShaderStages(other.mLinkedGraphicsShaderStages),
107       mLinkedComputeShaderStages(other.mLinkedComputeShaderStages),
108       mActiveAttribLocationsMask(other.mActiveAttribLocationsMask),
109       mMaxActiveAttribLocation(other.mMaxActiveAttribLocation),
110       mAttributesTypeMask(other.mAttributesTypeMask),
111       mAttributesMask(other.mAttributesMask),
112       mActiveSamplersMask(other.mActiveSamplersMask),
113       mActiveSamplerRefCounts(other.mActiveSamplerRefCounts),
114       mActiveSamplerTypes(other.mActiveSamplerTypes),
115       mActiveSamplerYUV(other.mActiveSamplerYUV),
116       mActiveSamplerFormats(other.mActiveSamplerFormats),
117       mActiveSamplerShaderBits(other.mActiveSamplerShaderBits),
118       mActiveImagesMask(other.mActiveImagesMask),
119       mActiveImageShaderBits(other.mActiveImageShaderBits),
120       mCanDrawWith(other.mCanDrawWith),
121       mOutputVariables(other.mOutputVariables),
122       mOutputLocations(other.mOutputLocations),
123       mSecondaryOutputLocations(other.mSecondaryOutputLocations),
124       mYUVOutput(other.mYUVOutput),
125       mProgramInputs(other.mProgramInputs),
126       mLinkedTransformFeedbackVaryings(other.mLinkedTransformFeedbackVaryings),
127       mTransformFeedbackStrides(other.mTransformFeedbackStrides),
128       mTransformFeedbackBufferMode(other.mTransformFeedbackBufferMode),
129       mUniforms(other.mUniforms),
130       mDefaultUniformRange(other.mDefaultUniformRange),
131       mSamplerUniformRange(other.mSamplerUniformRange),
132       mUniformBlocks(other.mUniformBlocks),
133       mActiveUniformBlockBindings(other.mActiveUniformBlockBindings),
134       mAtomicCounterBuffers(other.mAtomicCounterBuffers),
135       mImageUniformRange(other.mImageUniformRange),
136       mComputeShaderStorageBlocks(other.mComputeShaderStorageBlocks),
137       mGraphicsShaderStorageBlocks(other.mGraphicsShaderStorageBlocks),
138       mFragmentInoutRange(other.mFragmentInoutRange),
139       mPipelineHasGraphicsUniformBuffers(other.mPipelineHasGraphicsUniformBuffers),
140       mPipelineHasComputeUniformBuffers(other.mPipelineHasComputeUniformBuffers),
141       mPipelineHasGraphicsStorageBuffers(other.mPipelineHasGraphicsStorageBuffers),
142       mPipelineHasComputeStorageBuffers(other.mPipelineHasComputeStorageBuffers),
143       mPipelineHasGraphicsAtomicCounterBuffers(other.mPipelineHasGraphicsAtomicCounterBuffers),
144       mPipelineHasComputeAtomicCounterBuffers(other.mPipelineHasComputeAtomicCounterBuffers),
145       mPipelineHasGraphicsDefaultUniforms(other.mPipelineHasGraphicsDefaultUniforms),
146       mPipelineHasComputeDefaultUniforms(other.mPipelineHasComputeDefaultUniforms),
147       mPipelineHasGraphicsTextures(other.mPipelineHasGraphicsTextures),
148       mPipelineHasComputeTextures(other.mPipelineHasComputeTextures),
149       mPipelineHasGraphicsImages(other.mPipelineHasGraphicsImages),
150       mPipelineHasComputeImages(other.mPipelineHasComputeImages),
151       mIsCompute(other.mIsCompute)
152 {
153     reset();
154 }
155 
156 ProgramExecutable::~ProgramExecutable() = default;
157 
reset()158 void ProgramExecutable::reset()
159 {
160     resetInfoLog();
161     mActiveAttribLocationsMask.reset();
162     mAttributesTypeMask.reset();
163     mAttributesMask.reset();
164     mMaxActiveAttribLocation = 0;
165 
166     mActiveSamplersMask.reset();
167     mActiveSamplerRefCounts = {};
168     mActiveSamplerTypes.fill(TextureType::InvalidEnum);
169     mActiveSamplerYUV.reset();
170     mActiveSamplerFormats.fill(SamplerFormat::InvalidEnum);
171 
172     mActiveImagesMask.reset();
173 
174     mProgramInputs.clear();
175     mLinkedTransformFeedbackVaryings.clear();
176     mTransformFeedbackStrides.clear();
177     mUniforms.clear();
178     mUniformBlocks.clear();
179     mActiveUniformBlockBindings.reset();
180     mComputeShaderStorageBlocks.clear();
181     mGraphicsShaderStorageBlocks.clear();
182     mAtomicCounterBuffers.clear();
183     mOutputVariables.clear();
184     mOutputLocations.clear();
185     mSecondaryOutputLocations.clear();
186     mYUVOutput = false;
187     mSamplerBindings.clear();
188     mComputeImageBindings.clear();
189     mGraphicsImageBindings.clear();
190 
191     mPipelineHasGraphicsUniformBuffers       = false;
192     mPipelineHasComputeUniformBuffers        = false;
193     mPipelineHasGraphicsStorageBuffers       = false;
194     mPipelineHasComputeStorageBuffers        = false;
195     mPipelineHasGraphicsAtomicCounterBuffers = false;
196     mPipelineHasComputeAtomicCounterBuffers  = false;
197     mPipelineHasGraphicsDefaultUniforms      = false;
198     mPipelineHasComputeDefaultUniforms       = false;
199     mPipelineHasGraphicsTextures             = false;
200     mPipelineHasComputeTextures              = false;
201 
202     mGeometryShaderInputPrimitiveType  = PrimitiveMode::Triangles;
203     mGeometryShaderOutputPrimitiveType = PrimitiveMode::TriangleStrip;
204     mGeometryShaderInvocations         = 1;
205     mGeometryShaderMaxVertices         = 0;
206 
207     mTessControlShaderVertices = 0;
208     mTessGenMode               = GL_NONE;
209     mTessGenSpacing            = GL_NONE;
210     mTessGenVertexOrder        = GL_NONE;
211     mTessGenPointMode          = GL_NONE;
212 }
213 
load(bool isSeparable,gl::BinaryInputStream * stream)214 void ProgramExecutable::load(bool isSeparable, gl::BinaryInputStream *stream)
215 {
216     static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
217                   "Too many vertex attribs for mask: All bits of mAttributesTypeMask types and "
218                   "mask fit into 32 bits each");
219     mAttributesTypeMask        = gl::ComponentTypeMask(stream->readInt<uint32_t>());
220     mAttributesMask            = gl::AttributesMask(stream->readInt<uint32_t>());
221     mActiveAttribLocationsMask = gl::AttributesMask(stream->readInt<uint32_t>());
222     mMaxActiveAttribLocation   = stream->readInt<unsigned int>();
223 
224     unsigned int fragmentInoutRangeLow  = stream->readInt<uint32_t>();
225     unsigned int fragmentInoutRangeHigh = stream->readInt<uint32_t>();
226     mFragmentInoutRange                 = RangeUI(fragmentInoutRangeLow, fragmentInoutRangeHigh);
227 
228     mLinkedGraphicsShaderStages = ShaderBitSet(stream->readInt<uint8_t>());
229     mLinkedComputeShaderStages  = ShaderBitSet(stream->readInt<uint8_t>());
230     mIsCompute                  = stream->readBool();
231 
232     mPipelineHasGraphicsUniformBuffers       = stream->readBool();
233     mPipelineHasComputeUniformBuffers        = stream->readBool();
234     mPipelineHasGraphicsStorageBuffers       = stream->readBool();
235     mPipelineHasComputeStorageBuffers        = stream->readBool();
236     mPipelineHasGraphicsAtomicCounterBuffers = stream->readBool();
237     mPipelineHasComputeAtomicCounterBuffers  = stream->readBool();
238     mPipelineHasGraphicsDefaultUniforms      = stream->readBool();
239     mPipelineHasComputeDefaultUniforms       = stream->readBool();
240     mPipelineHasGraphicsTextures             = stream->readBool();
241     mPipelineHasComputeTextures              = stream->readBool();
242 
243     mGeometryShaderInputPrimitiveType  = stream->readEnum<PrimitiveMode>();
244     mGeometryShaderOutputPrimitiveType = stream->readEnum<PrimitiveMode>();
245     mGeometryShaderInvocations         = stream->readInt<int>();
246     mGeometryShaderMaxVertices         = stream->readInt<int>();
247 
248     mTessControlShaderVertices = stream->readInt<int>();
249     mTessGenMode               = stream->readInt<GLenum>();
250     mTessGenSpacing            = stream->readInt<GLenum>();
251     mTessGenVertexOrder        = stream->readInt<GLenum>();
252     mTessGenPointMode          = stream->readInt<GLenum>();
253 
254     size_t attribCount = stream->readInt<size_t>();
255     ASSERT(getProgramInputs().empty());
256     for (size_t attribIndex = 0; attribIndex < attribCount; ++attribIndex)
257     {
258         sh::ShaderVariable attrib;
259         LoadShaderVar(stream, &attrib);
260         attrib.location = stream->readInt<int>();
261         mProgramInputs.push_back(attrib);
262     }
263 
264     size_t uniformCount = stream->readInt<size_t>();
265     ASSERT(getUniforms().empty());
266     for (size_t uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
267     {
268         LinkedUniform uniform;
269         LoadShaderVar(stream, &uniform);
270 
271         uniform.bufferIndex = stream->readInt<int>();
272         LoadBlockMemberInfo(stream, &uniform.blockInfo);
273 
274         stream->readIntVector<unsigned int>(&uniform.outerArraySizes);
275 
276         uniform.typeInfo = &GetUniformTypeInfo(uniform.type);
277 
278         // Active shader info
279         for (ShaderType shaderType : gl::AllShaderTypes())
280         {
281             uniform.setActive(shaderType, stream->readBool());
282         }
283 
284         mUniforms.push_back(uniform);
285     }
286 
287     size_t uniformBlockCount = stream->readInt<size_t>();
288     ASSERT(getUniformBlocks().empty());
289     for (size_t uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex)
290     {
291         InterfaceBlock uniformBlock;
292         LoadInterfaceBlock(stream, &uniformBlock);
293         mUniformBlocks.push_back(uniformBlock);
294 
295         mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlock.binding != 0);
296     }
297 
298     size_t shaderStorageBlockCount = stream->readInt<size_t>();
299     ASSERT(getShaderStorageBlocks().empty());
300     for (size_t shaderStorageBlockIndex = 0; shaderStorageBlockIndex < shaderStorageBlockCount;
301          ++shaderStorageBlockIndex)
302     {
303         InterfaceBlock shaderStorageBlock;
304         LoadInterfaceBlock(stream, &shaderStorageBlock);
305         if (isCompute())
306         {
307             mComputeShaderStorageBlocks.push_back(shaderStorageBlock);
308         }
309         else
310         {
311             mGraphicsShaderStorageBlocks.push_back(shaderStorageBlock);
312         }
313     }
314 
315     size_t atomicCounterBufferCount = stream->readInt<size_t>();
316     ASSERT(getAtomicCounterBuffers().empty());
317     for (size_t bufferIndex = 0; bufferIndex < atomicCounterBufferCount; ++bufferIndex)
318     {
319         AtomicCounterBuffer atomicCounterBuffer;
320         LoadShaderVariableBuffer(stream, &atomicCounterBuffer);
321 
322         mAtomicCounterBuffers.push_back(atomicCounterBuffer);
323     }
324 
325     size_t transformFeedbackVaryingCount = stream->readInt<size_t>();
326     ASSERT(mLinkedTransformFeedbackVaryings.empty());
327     for (size_t transformFeedbackVaryingIndex = 0;
328          transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
329          ++transformFeedbackVaryingIndex)
330     {
331         sh::ShaderVariable varying;
332         stream->readIntVector<unsigned int>(&varying.arraySizes);
333         stream->readInt(&varying.type);
334         stream->readString(&varying.name);
335 
336         GLuint arrayIndex = stream->readInt<GLuint>();
337 
338         mLinkedTransformFeedbackVaryings.emplace_back(varying, arrayIndex);
339     }
340 
341     mTransformFeedbackBufferMode = stream->readInt<GLint>();
342 
343     size_t outputCount = stream->readInt<size_t>();
344     ASSERT(getOutputVariables().empty());
345     for (size_t outputIndex = 0; outputIndex < outputCount; ++outputIndex)
346     {
347         sh::ShaderVariable output;
348         LoadShaderVar(stream, &output);
349         output.location = stream->readInt<int>();
350         output.index    = stream->readInt<int>();
351         mOutputVariables.push_back(output);
352     }
353 
354     size_t outputVarCount = stream->readInt<size_t>();
355     ASSERT(getOutputLocations().empty());
356     for (size_t outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
357     {
358         VariableLocation locationData;
359         stream->readInt(&locationData.arrayIndex);
360         stream->readInt(&locationData.index);
361         stream->readBool(&locationData.ignored);
362         mOutputLocations.push_back(locationData);
363     }
364 
365     size_t secondaryOutputVarCount = stream->readInt<size_t>();
366     ASSERT(getSecondaryOutputLocations().empty());
367     for (size_t outputIndex = 0; outputIndex < secondaryOutputVarCount; ++outputIndex)
368     {
369         VariableLocation locationData;
370         stream->readInt(&locationData.arrayIndex);
371         stream->readInt(&locationData.index);
372         stream->readBool(&locationData.ignored);
373         mSecondaryOutputLocations.push_back(locationData);
374     }
375 
376     unsigned int defaultUniformRangeLow  = stream->readInt<unsigned int>();
377     unsigned int defaultUniformRangeHigh = stream->readInt<unsigned int>();
378     mDefaultUniformRange                 = RangeUI(defaultUniformRangeLow, defaultUniformRangeHigh);
379 
380     unsigned int samplerRangeLow  = stream->readInt<unsigned int>();
381     unsigned int samplerRangeHigh = stream->readInt<unsigned int>();
382     mSamplerUniformRange          = RangeUI(samplerRangeLow, samplerRangeHigh);
383 
384     size_t samplerCount = stream->readInt<size_t>();
385     for (size_t samplerIndex = 0; samplerIndex < samplerCount; ++samplerIndex)
386     {
387         TextureType textureType = stream->readEnum<TextureType>();
388         GLenum samplerType      = stream->readInt<GLenum>();
389         SamplerFormat format    = stream->readEnum<SamplerFormat>();
390         size_t bindingCount     = stream->readInt<size_t>();
391         mSamplerBindings.emplace_back(textureType, samplerType, format, bindingCount);
392     }
393 
394     unsigned int imageRangeLow  = stream->readInt<unsigned int>();
395     unsigned int imageRangeHigh = stream->readInt<unsigned int>();
396     mImageUniformRange          = RangeUI(imageRangeLow, imageRangeHigh);
397 
398     size_t imageBindingCount = stream->readInt<size_t>();
399     for (size_t imageIndex = 0; imageIndex < imageBindingCount; ++imageIndex)
400     {
401         size_t elementCount     = stream->readInt<size_t>();
402         TextureType textureType = static_cast<TextureType>(stream->readInt<unsigned int>());
403         ImageBinding imageBinding(elementCount, textureType);
404         for (size_t elementIndex = 0; elementIndex < elementCount; ++elementIndex)
405         {
406             imageBinding.boundImageUnits[elementIndex] = stream->readInt<unsigned int>();
407         }
408         if (isCompute())
409         {
410             mComputeImageBindings.emplace_back(imageBinding);
411         }
412         else
413         {
414             mGraphicsImageBindings.emplace_back(imageBinding);
415         }
416     }
417 
418     // These values are currently only used by PPOs, so only load them when the program is marked
419     // separable to save memory.
420     if (isSeparable)
421     {
422         for (ShaderType shaderType : mLinkedGraphicsShaderStages)
423         {
424             mLinkedOutputVaryings[shaderType].resize(stream->readInt<size_t>());
425             for (sh::ShaderVariable &variable : mLinkedOutputVaryings[shaderType])
426             {
427                 LoadShaderVar(stream, &variable);
428             }
429             mLinkedInputVaryings[shaderType].resize(stream->readInt<size_t>());
430             for (sh::ShaderVariable &variable : mLinkedInputVaryings[shaderType])
431             {
432                 LoadShaderVar(stream, &variable);
433             }
434             mLinkedShaderVersions[shaderType] = stream->readInt<int>();
435         }
436         for (ShaderType shaderType : mLinkedComputeShaderStages)
437         {
438             mLinkedOutputVaryings[shaderType].resize(stream->readInt<size_t>());
439             for (sh::ShaderVariable &variable : mLinkedOutputVaryings[shaderType])
440             {
441                 LoadShaderVar(stream, &variable);
442             }
443             mLinkedInputVaryings[shaderType].resize(stream->readInt<size_t>());
444             for (sh::ShaderVariable &variable : mLinkedInputVaryings[shaderType])
445             {
446                 LoadShaderVar(stream, &variable);
447             }
448             mLinkedShaderVersions[shaderType] = stream->readInt<int>();
449         }
450     }
451 }
452 
save(bool isSeparable,gl::BinaryOutputStream * stream) const453 void ProgramExecutable::save(bool isSeparable, gl::BinaryOutputStream *stream) const
454 {
455     static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
456                   "All bits of mAttributesTypeMask types and mask fit into 32 bits each");
457     stream->writeInt(static_cast<uint32_t>(mAttributesTypeMask.to_ulong()));
458     stream->writeInt(static_cast<uint32_t>(mAttributesMask.to_ulong()));
459     stream->writeInt(static_cast<uint32_t>(mActiveAttribLocationsMask.to_ulong()));
460     stream->writeInt(mMaxActiveAttribLocation);
461 
462     stream->writeInt(mFragmentInoutRange.low());
463     stream->writeInt(mFragmentInoutRange.high());
464 
465     stream->writeInt(mLinkedGraphicsShaderStages.bits());
466     stream->writeInt(mLinkedComputeShaderStages.bits());
467     stream->writeBool(mIsCompute);
468 
469     stream->writeBool(mPipelineHasGraphicsUniformBuffers);
470     stream->writeBool(mPipelineHasComputeUniformBuffers);
471     stream->writeBool(mPipelineHasGraphicsStorageBuffers);
472     stream->writeBool(mPipelineHasComputeStorageBuffers);
473     stream->writeBool(mPipelineHasGraphicsAtomicCounterBuffers);
474     stream->writeBool(mPipelineHasComputeAtomicCounterBuffers);
475     stream->writeBool(mPipelineHasGraphicsDefaultUniforms);
476     stream->writeBool(mPipelineHasComputeDefaultUniforms);
477     stream->writeBool(mPipelineHasGraphicsTextures);
478     stream->writeBool(mPipelineHasComputeTextures);
479 
480     ASSERT(mGeometryShaderInvocations >= 1 && mGeometryShaderMaxVertices >= 0);
481     stream->writeEnum(mGeometryShaderInputPrimitiveType);
482     stream->writeEnum(mGeometryShaderOutputPrimitiveType);
483     stream->writeInt(mGeometryShaderInvocations);
484     stream->writeInt(mGeometryShaderMaxVertices);
485 
486     stream->writeInt(mTessControlShaderVertices);
487     stream->writeInt(mTessGenMode);
488     stream->writeInt(mTessGenSpacing);
489     stream->writeInt(mTessGenVertexOrder);
490     stream->writeInt(mTessGenPointMode);
491 
492     stream->writeInt(getProgramInputs().size());
493     for (const sh::ShaderVariable &attrib : getProgramInputs())
494     {
495         WriteShaderVar(stream, attrib);
496         stream->writeInt(attrib.location);
497     }
498 
499     stream->writeInt(getUniforms().size());
500     for (const LinkedUniform &uniform : getUniforms())
501     {
502         WriteShaderVar(stream, uniform);
503 
504         stream->writeInt(uniform.bufferIndex);
505         WriteBlockMemberInfo(stream, uniform.blockInfo);
506 
507         stream->writeIntVector(uniform.outerArraySizes);
508 
509         // Active shader info
510         for (ShaderType shaderType : gl::AllShaderTypes())
511         {
512             stream->writeBool(uniform.isActive(shaderType));
513         }
514     }
515 
516     stream->writeInt(getUniformBlocks().size());
517     for (const InterfaceBlock &uniformBlock : getUniformBlocks())
518     {
519         WriteInterfaceBlock(stream, uniformBlock);
520     }
521 
522     stream->writeInt(getShaderStorageBlocks().size());
523     for (const InterfaceBlock &shaderStorageBlock : getShaderStorageBlocks())
524     {
525         WriteInterfaceBlock(stream, shaderStorageBlock);
526     }
527 
528     stream->writeInt(mAtomicCounterBuffers.size());
529     for (const AtomicCounterBuffer &atomicCounterBuffer : getAtomicCounterBuffers())
530     {
531         WriteShaderVariableBuffer(stream, atomicCounterBuffer);
532     }
533 
534     stream->writeInt(getLinkedTransformFeedbackVaryings().size());
535     for (const auto &var : getLinkedTransformFeedbackVaryings())
536     {
537         stream->writeIntVector(var.arraySizes);
538         stream->writeInt(var.type);
539         stream->writeString(var.name);
540 
541         stream->writeIntOrNegOne(var.arrayIndex);
542     }
543 
544     stream->writeInt(getTransformFeedbackBufferMode());
545 
546     stream->writeInt(getOutputVariables().size());
547     for (const sh::ShaderVariable &output : getOutputVariables())
548     {
549         WriteShaderVar(stream, output);
550         stream->writeInt(output.location);
551         stream->writeInt(output.index);
552     }
553 
554     stream->writeInt(getOutputLocations().size());
555     for (const auto &outputVar : getOutputLocations())
556     {
557         stream->writeInt(outputVar.arrayIndex);
558         stream->writeIntOrNegOne(outputVar.index);
559         stream->writeBool(outputVar.ignored);
560     }
561 
562     stream->writeInt(getSecondaryOutputLocations().size());
563     for (const auto &outputVar : getSecondaryOutputLocations())
564     {
565         stream->writeInt(outputVar.arrayIndex);
566         stream->writeIntOrNegOne(outputVar.index);
567         stream->writeBool(outputVar.ignored);
568     }
569 
570     stream->writeInt(getDefaultUniformRange().low());
571     stream->writeInt(getDefaultUniformRange().high());
572 
573     stream->writeInt(getSamplerUniformRange().low());
574     stream->writeInt(getSamplerUniformRange().high());
575 
576     stream->writeInt(getSamplerBindings().size());
577     for (const auto &samplerBinding : getSamplerBindings())
578     {
579         stream->writeEnum(samplerBinding.textureType);
580         stream->writeInt(samplerBinding.samplerType);
581         stream->writeEnum(samplerBinding.format);
582         stream->writeInt(samplerBinding.boundTextureUnits.size());
583     }
584 
585     stream->writeInt(getImageUniformRange().low());
586     stream->writeInt(getImageUniformRange().high());
587 
588     stream->writeInt(getImageBindings().size());
589     for (const auto &imageBinding : getImageBindings())
590     {
591         stream->writeInt(imageBinding.boundImageUnits.size());
592         stream->writeInt(static_cast<unsigned int>(imageBinding.textureType));
593         for (size_t i = 0; i < imageBinding.boundImageUnits.size(); ++i)
594         {
595             stream->writeInt(imageBinding.boundImageUnits[i]);
596         }
597     }
598 
599     // These values are currently only used by PPOs, so only save them when the program is marked
600     // separable to save memory.
601     if (isSeparable)
602     {
603         for (ShaderType shaderType : mLinkedGraphicsShaderStages)
604         {
605             stream->writeInt(mLinkedOutputVaryings[shaderType].size());
606             for (const sh::ShaderVariable &shaderVariable : mLinkedOutputVaryings[shaderType])
607             {
608                 WriteShaderVar(stream, shaderVariable);
609             }
610             stream->writeInt(mLinkedInputVaryings[shaderType].size());
611             for (const sh::ShaderVariable &shaderVariable : mLinkedInputVaryings[shaderType])
612             {
613                 WriteShaderVar(stream, shaderVariable);
614             }
615             stream->writeInt(mLinkedShaderVersions[shaderType]);
616         }
617         for (ShaderType shaderType : mLinkedComputeShaderStages)
618         {
619             stream->writeInt(mLinkedOutputVaryings[shaderType].size());
620             for (const sh::ShaderVariable &shaderVariable : mLinkedOutputVaryings[shaderType])
621             {
622                 WriteShaderVar(stream, shaderVariable);
623             }
624             stream->writeInt(mLinkedInputVaryings[shaderType].size());
625             for (const sh::ShaderVariable &shaderVariable : mLinkedInputVaryings[shaderType])
626             {
627                 WriteShaderVar(stream, shaderVariable);
628             }
629             stream->writeInt(mLinkedShaderVersions[shaderType]);
630         }
631     }
632 }
633 
getInfoLogLength() const634 int ProgramExecutable::getInfoLogLength() const
635 {
636     return static_cast<int>(mInfoLog.getLength());
637 }
638 
getInfoLog(GLsizei bufSize,GLsizei * length,char * infoLog) const639 void ProgramExecutable::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
640 {
641     return mInfoLog.getLog(bufSize, length, infoLog);
642 }
643 
getInfoLogString() const644 std::string ProgramExecutable::getInfoLogString() const
645 {
646     return mInfoLog.str();
647 }
648 
isAttribLocationActive(size_t attribLocation) const649 bool ProgramExecutable::isAttribLocationActive(size_t attribLocation) const
650 {
651     // TODO(timvp): http://anglebug.com/3570: Enable this assert here somehow.
652     //    ASSERT(!mLinkingState);
653     ASSERT(attribLocation < mActiveAttribLocationsMask.size());
654     return mActiveAttribLocationsMask[attribLocation];
655 }
656 
getAttributesMask() const657 AttributesMask ProgramExecutable::getAttributesMask() const
658 {
659     // TODO(timvp): http://anglebug.com/3570: Enable this assert here somehow.
660     //    ASSERT(!mLinkingState);
661     return mAttributesMask;
662 }
663 
hasDefaultUniforms() const664 bool ProgramExecutable::hasDefaultUniforms() const
665 {
666     return !getDefaultUniformRange().empty() ||
667            (isCompute() ? mPipelineHasComputeDefaultUniforms : mPipelineHasGraphicsDefaultUniforms);
668 }
669 
hasTextures() const670 bool ProgramExecutable::hasTextures() const
671 {
672     return !getSamplerBindings().empty() ||
673            (isCompute() ? mPipelineHasComputeTextures : mPipelineHasGraphicsTextures);
674 }
675 
676 // TODO: http://anglebug.com/3570: Remove mHas*UniformBuffers once PPO's have valid data in
677 // mUniformBlocks
hasUniformBuffers() const678 bool ProgramExecutable::hasUniformBuffers() const
679 {
680     return !getUniformBlocks().empty() ||
681            (isCompute() ? mPipelineHasComputeUniformBuffers : mPipelineHasGraphicsUniformBuffers);
682 }
683 
hasStorageBuffers() const684 bool ProgramExecutable::hasStorageBuffers() const
685 {
686     return (isCompute() ? hasComputeStorageBuffers() : hasGraphicsStorageBuffers());
687 }
688 
hasGraphicsStorageBuffers() const689 bool ProgramExecutable::hasGraphicsStorageBuffers() const
690 {
691     return !mGraphicsShaderStorageBlocks.empty() || mPipelineHasGraphicsStorageBuffers;
692 }
693 
hasComputeStorageBuffers() const694 bool ProgramExecutable::hasComputeStorageBuffers() const
695 {
696     return !mComputeShaderStorageBlocks.empty() || mPipelineHasComputeStorageBuffers;
697 }
698 
hasAtomicCounterBuffers() const699 bool ProgramExecutable::hasAtomicCounterBuffers() const
700 {
701     return !getAtomicCounterBuffers().empty() ||
702            (isCompute() ? mPipelineHasComputeAtomicCounterBuffers
703                         : mPipelineHasGraphicsAtomicCounterBuffers);
704 }
705 
hasImages() const706 bool ProgramExecutable::hasImages() const
707 {
708     return (isCompute() ? hasComputeImages() : hasGraphicsImages());
709 }
710 
hasGraphicsImages() const711 bool ProgramExecutable::hasGraphicsImages() const
712 {
713     return !mGraphicsImageBindings.empty() || mPipelineHasGraphicsImages;
714 }
715 
hasComputeImages() const716 bool ProgramExecutable::hasComputeImages() const
717 {
718     return !mComputeImageBindings.empty() || mPipelineHasComputeImages;
719 }
720 
usesFramebufferFetch() const721 bool ProgramExecutable::usesFramebufferFetch() const
722 {
723     return (mFragmentInoutRange.length() > 0);
724 }
725 
getUniformIndexFromImageIndex(GLuint imageIndex) const726 GLuint ProgramExecutable::getUniformIndexFromImageIndex(GLuint imageIndex) const
727 {
728     ASSERT(imageIndex < mImageUniformRange.length());
729     return imageIndex + mImageUniformRange.low();
730 }
731 
updateActiveSamplers(const ProgramState & programState)732 void ProgramExecutable::updateActiveSamplers(const ProgramState &programState)
733 {
734     const std::vector<SamplerBinding> &samplerBindings = programState.getSamplerBindings();
735 
736     for (uint32_t samplerIndex = 0; samplerIndex < samplerBindings.size(); ++samplerIndex)
737     {
738         const SamplerBinding &samplerBinding = samplerBindings[samplerIndex];
739         uint32_t uniformIndex = programState.getUniformIndexFromSamplerIndex(samplerIndex);
740         const gl::LinkedUniform &samplerUniform = programState.getUniforms()[uniformIndex];
741 
742         for (GLint textureUnit : samplerBinding.boundTextureUnits)
743         {
744             if (++mActiveSamplerRefCounts[textureUnit] == 1)
745             {
746                 mActiveSamplerTypes[textureUnit]   = samplerBinding.textureType;
747                 mActiveSamplerYUV[textureUnit]     = IsSamplerYUVType(samplerBinding.samplerType);
748                 mActiveSamplerFormats[textureUnit] = samplerBinding.format;
749                 mActiveSamplerShaderBits[textureUnit] = samplerUniform.activeShaders();
750             }
751             else
752             {
753                 if (mActiveSamplerTypes[textureUnit] != samplerBinding.textureType)
754                 {
755                     // Conflicts are marked with InvalidEnum
756                     mActiveSamplerTypes[textureUnit] = TextureType::InvalidEnum;
757                 }
758                 if (mActiveSamplerYUV.test(textureUnit) !=
759                     IsSamplerYUVType(samplerBinding.samplerType))
760                 {
761                     mActiveSamplerYUV[textureUnit] = false;
762                 }
763                 if (mActiveSamplerFormats[textureUnit] != samplerBinding.format)
764                 {
765                     mActiveSamplerFormats[textureUnit] = SamplerFormat::InvalidEnum;
766                 }
767             }
768             mActiveSamplersMask.set(textureUnit);
769         }
770     }
771 }
772 
updateActiveImages(const ProgramExecutable & executable)773 void ProgramExecutable::updateActiveImages(const ProgramExecutable &executable)
774 {
775     const std::vector<ImageBinding> *imageBindings = getImageBindings();
776     for (uint32_t imageIndex = 0; imageIndex < imageBindings->size(); ++imageIndex)
777     {
778         const gl::ImageBinding &imageBinding = imageBindings->at(imageIndex);
779 
780         uint32_t uniformIndex = executable.getUniformIndexFromImageIndex(imageIndex);
781         const gl::LinkedUniform &imageUniform = executable.getUniforms()[uniformIndex];
782         const ShaderBitSet shaderBits         = imageUniform.activeShaders();
783         for (GLint imageUnit : imageBinding.boundImageUnits)
784         {
785             mActiveImagesMask.set(imageUnit);
786             if (isCompute())
787             {
788                 mActiveImageShaderBits[imageUnit].set(gl::ShaderType::Compute);
789             }
790             else
791             {
792                 mActiveImageShaderBits[imageUnit] |= shaderBits;
793             }
794         }
795     }
796 }
797 
setSamplerUniformTextureTypeAndFormat(size_t textureUnitIndex,std::vector<SamplerBinding> & samplerBindings)798 void ProgramExecutable::setSamplerUniformTextureTypeAndFormat(
799     size_t textureUnitIndex,
800     std::vector<SamplerBinding> &samplerBindings)
801 {
802     bool foundBinding         = false;
803     TextureType foundType     = TextureType::InvalidEnum;
804     bool foundYUV             = false;
805     SamplerFormat foundFormat = SamplerFormat::InvalidEnum;
806 
807     for (const SamplerBinding &binding : samplerBindings)
808     {
809         // A conflict exists if samplers of different types are sourced by the same texture unit.
810         // We need to check all bound textures to detect this error case.
811         for (GLuint textureUnit : binding.boundTextureUnits)
812         {
813             if (textureUnit == textureUnitIndex)
814             {
815                 if (!foundBinding)
816                 {
817                     foundBinding = true;
818                     foundType    = binding.textureType;
819                     foundYUV     = IsSamplerYUVType(binding.samplerType);
820                     foundFormat  = binding.format;
821                 }
822                 else
823                 {
824                     if (foundType != binding.textureType)
825                     {
826                         foundType = TextureType::InvalidEnum;
827                     }
828                     if (foundYUV != IsSamplerYUVType(binding.samplerType))
829                     {
830                         foundYUV = false;
831                     }
832                     if (foundFormat != binding.format)
833                     {
834                         foundFormat = SamplerFormat::InvalidEnum;
835                     }
836                 }
837             }
838         }
839     }
840 
841     mActiveSamplerTypes[textureUnitIndex]   = foundType;
842     mActiveSamplerYUV[textureUnitIndex]     = foundYUV;
843     mActiveSamplerFormats[textureUnitIndex] = foundFormat;
844 }
845 
updateCanDrawWith()846 void ProgramExecutable::updateCanDrawWith()
847 {
848     mCanDrawWith =
849         (hasLinkedShaderStage(ShaderType::Vertex) && hasLinkedShaderStage(ShaderType::Fragment));
850 }
851 
saveLinkedStateInfo(const ProgramState & state)852 void ProgramExecutable::saveLinkedStateInfo(const ProgramState &state)
853 {
854     for (ShaderType shaderType : getLinkedShaderStages())
855     {
856         Shader *shader = state.getAttachedShader(shaderType);
857         ASSERT(shader);
858         mLinkedOutputVaryings[shaderType] = shader->getOutputVaryings();
859         mLinkedInputVaryings[shaderType]  = shader->getInputVaryings();
860         mLinkedShaderVersions[shaderType] = shader->getShaderVersion();
861     }
862 }
863 
isYUVOutput() const864 bool ProgramExecutable::isYUVOutput() const
865 {
866     return !isCompute() && mYUVOutput;
867 }
868 
getLinkedTransformFeedbackStage() const869 ShaderType ProgramExecutable::getLinkedTransformFeedbackStage() const
870 {
871     return GetLastPreFragmentStage(mLinkedGraphicsShaderStages);
872 }
873 
linkMergedVaryings(const Context * context,const HasAttachedShaders & programOrPipeline,const ProgramMergedVaryings & mergedVaryings,const std::vector<std::string> & transformFeedbackVaryingNames,bool isSeparable,ProgramVaryingPacking * varyingPacking)874 bool ProgramExecutable::linkMergedVaryings(
875     const Context *context,
876     const HasAttachedShaders &programOrPipeline,
877     const ProgramMergedVaryings &mergedVaryings,
878     const std::vector<std::string> &transformFeedbackVaryingNames,
879     bool isSeparable,
880     ProgramVaryingPacking *varyingPacking)
881 {
882     ShaderType tfStage = programOrPipeline.getTransformFeedbackStage();
883 
884     if (!linkValidateTransformFeedback(context, mergedVaryings, tfStage,
885                                        transformFeedbackVaryingNames))
886     {
887         return false;
888     }
889 
890     // Map the varyings to the register file
891     // In WebGL, we use a slightly different handling for packing variables.
892     gl::PackMode packMode = PackMode::ANGLE_RELAXED;
893     if (context->getLimitations().noFlexibleVaryingPacking)
894     {
895         // D3D9 pack mode is strictly more strict than WebGL, so takes priority.
896         packMode = PackMode::ANGLE_NON_CONFORMANT_D3D9;
897     }
898     else if (context->getExtensions().webglCompatibility)
899     {
900         packMode = PackMode::WEBGL_STRICT;
901     }
902 
903     // Build active shader stage map.
904     ShaderBitSet activeShadersMask;
905     for (ShaderType shaderType : kAllGraphicsShaderTypes)
906     {
907         // - Check for attached shaders to handle the case of a Program linking the currently
908         // attached shaders.
909         // - Check for linked shaders to handle the case of a PPO linking separable programs before
910         // drawing.
911         if (programOrPipeline.getAttachedShader(shaderType) ||
912             getLinkedShaderStages().test(shaderType))
913         {
914             activeShadersMask[shaderType] = true;
915         }
916     }
917 
918     if (!varyingPacking->collectAndPackUserVaryings(mInfoLog, context->getCaps(), packMode,
919                                                     activeShadersMask, mergedVaryings,
920                                                     transformFeedbackVaryingNames, isSeparable))
921     {
922         return false;
923     }
924 
925     gatherTransformFeedbackVaryings(mergedVaryings, tfStage, transformFeedbackVaryingNames);
926     updateTransformFeedbackStrides();
927 
928     return true;
929 }
930 
linkValidateTransformFeedback(const Context * context,const ProgramMergedVaryings & varyings,ShaderType stage,const std::vector<std::string> & transformFeedbackVaryingNames)931 bool ProgramExecutable::linkValidateTransformFeedback(
932     const Context *context,
933     const ProgramMergedVaryings &varyings,
934     ShaderType stage,
935     const std::vector<std::string> &transformFeedbackVaryingNames)
936 {
937     const Version &version = context->getClientVersion();
938 
939     // Validate the tf names regardless of the actual program varyings.
940     std::set<std::string> uniqueNames;
941     for (const std::string &tfVaryingName : transformFeedbackVaryingNames)
942     {
943         if (version < Version(3, 1) && tfVaryingName.find('[') != std::string::npos)
944         {
945             mInfoLog << "Capture of array elements is undefined and not supported.";
946             return false;
947         }
948         if (version >= Version(3, 1))
949         {
950             if (IncludeSameArrayElement(uniqueNames, tfVaryingName))
951             {
952                 mInfoLog << "Two transform feedback varyings include the same array element ("
953                          << tfVaryingName << ").";
954                 return false;
955             }
956         }
957         else
958         {
959             if (uniqueNames.count(tfVaryingName) > 0)
960             {
961                 mInfoLog << "Two transform feedback varyings specify the same output variable ("
962                          << tfVaryingName << ").";
963                 return false;
964             }
965         }
966         uniqueNames.insert(tfVaryingName);
967     }
968 
969     // Validate against program varyings.
970     size_t totalComponents = 0;
971     for (const std::string &tfVaryingName : transformFeedbackVaryingNames)
972     {
973         std::vector<unsigned int> subscripts;
974         std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
975 
976         const sh::ShaderVariable *var = FindOutputVaryingOrField(varyings, stage, baseName);
977         if (var == nullptr)
978         {
979             mInfoLog << "Transform feedback varying " << tfVaryingName
980                      << " does not exist in the vertex shader.";
981             return false;
982         }
983 
984         // Validate the matching variable.
985         if (var->isStruct())
986         {
987             mInfoLog << "Struct cannot be captured directly (" << baseName << ").";
988             return false;
989         }
990 
991         size_t elementCount   = 0;
992         size_t componentCount = 0;
993 
994         if (var->isArray())
995         {
996             if (version < Version(3, 1))
997             {
998                 mInfoLog << "Capture of arrays is undefined and not supported.";
999                 return false;
1000             }
1001 
1002             // GLSL ES 3.10 section 4.3.6: A vertex output can't be an array of arrays.
1003             ASSERT(!var->isArrayOfArrays());
1004 
1005             if (!subscripts.empty() && subscripts[0] >= var->getOutermostArraySize())
1006             {
1007                 mInfoLog << "Cannot capture outbound array element '" << tfVaryingName << "'.";
1008                 return false;
1009             }
1010             elementCount = (subscripts.empty() ? var->getOutermostArraySize() : 1);
1011         }
1012         else
1013         {
1014             if (!subscripts.empty())
1015             {
1016                 mInfoLog << "Varying '" << baseName
1017                          << "' is not an array to be captured by element.";
1018                 return false;
1019             }
1020             elementCount = 1;
1021         }
1022 
1023         const Caps &caps = context->getCaps();
1024 
1025         // TODO(jmadill): Investigate implementation limits on D3D11
1026         componentCount = VariableComponentCount(var->type) * elementCount;
1027         if (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
1028             componentCount > static_cast<GLuint>(caps.maxTransformFeedbackSeparateComponents))
1029         {
1030             mInfoLog << "Transform feedback varying " << tfVaryingName << " components ("
1031                      << componentCount << ") exceed the maximum separate components ("
1032                      << caps.maxTransformFeedbackSeparateComponents << ").";
1033             return false;
1034         }
1035 
1036         totalComponents += componentCount;
1037         if (mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS &&
1038             totalComponents > static_cast<GLuint>(caps.maxTransformFeedbackInterleavedComponents))
1039         {
1040             mInfoLog << "Transform feedback varying total components (" << totalComponents
1041                      << ") exceed the maximum interleaved components ("
1042                      << caps.maxTransformFeedbackInterleavedComponents << ").";
1043             return false;
1044         }
1045     }
1046     return true;
1047 }
1048 
gatherTransformFeedbackVaryings(const ProgramMergedVaryings & varyings,ShaderType stage,const std::vector<std::string> & transformFeedbackVaryingNames)1049 void ProgramExecutable::gatherTransformFeedbackVaryings(
1050     const ProgramMergedVaryings &varyings,
1051     ShaderType stage,
1052     const std::vector<std::string> &transformFeedbackVaryingNames)
1053 {
1054     // Gather the linked varyings that are used for transform feedback, they should all exist.
1055     mLinkedTransformFeedbackVaryings.clear();
1056     for (const std::string &tfVaryingName : transformFeedbackVaryingNames)
1057     {
1058         std::vector<unsigned int> subscripts;
1059         std::string baseName = ParseResourceName(tfVaryingName, &subscripts);
1060         size_t subscript     = GL_INVALID_INDEX;
1061         if (!subscripts.empty())
1062         {
1063             subscript = subscripts.back();
1064         }
1065         for (const ProgramVaryingRef &ref : varyings)
1066         {
1067             if (ref.frontShaderStage != stage)
1068             {
1069                 continue;
1070             }
1071 
1072             const sh::ShaderVariable *varying = ref.get(stage);
1073             if (baseName == varying->name)
1074             {
1075                 mLinkedTransformFeedbackVaryings.emplace_back(*varying,
1076                                                               static_cast<GLuint>(subscript));
1077                 break;
1078             }
1079             else if (varying->isStruct())
1080             {
1081                 GLuint fieldIndex = 0;
1082                 const auto *field = varying->findField(tfVaryingName, &fieldIndex);
1083                 if (field != nullptr)
1084                 {
1085                     mLinkedTransformFeedbackVaryings.emplace_back(*field, *varying);
1086                     break;
1087                 }
1088             }
1089         }
1090     }
1091 }
1092 
updateTransformFeedbackStrides()1093 void ProgramExecutable::updateTransformFeedbackStrides()
1094 {
1095     if (mTransformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS)
1096     {
1097         mTransformFeedbackStrides.resize(1);
1098         size_t totalSize = 0;
1099         for (const TransformFeedbackVarying &varying : mLinkedTransformFeedbackVaryings)
1100         {
1101             totalSize += varying.size() * VariableExternalSize(varying.type);
1102         }
1103         mTransformFeedbackStrides[0] = static_cast<GLsizei>(totalSize);
1104     }
1105     else
1106     {
1107         mTransformFeedbackStrides.resize(mLinkedTransformFeedbackVaryings.size());
1108         for (size_t i = 0; i < mLinkedTransformFeedbackVaryings.size(); i++)
1109         {
1110             TransformFeedbackVarying &varying = mLinkedTransformFeedbackVaryings[i];
1111             mTransformFeedbackStrides[i] =
1112                 static_cast<GLsizei>(varying.size() * VariableExternalSize(varying.type));
1113         }
1114     }
1115 }
1116 
validateSamplersImpl(InfoLog * infoLog,const Caps & caps) const1117 bool ProgramExecutable::validateSamplersImpl(InfoLog *infoLog, const Caps &caps) const
1118 {
1119     // if any two active samplers in a program are of different types, but refer to the same
1120     // texture image unit, and this is the current program, then ValidateProgram will fail, and
1121     // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
1122     for (size_t textureUnit : mActiveSamplersMask)
1123     {
1124         if (mActiveSamplerTypes[textureUnit] == TextureType::InvalidEnum)
1125         {
1126             if (infoLog)
1127             {
1128                 (*infoLog) << "Samplers of conflicting types refer to the same texture "
1129                               "image unit ("
1130                            << textureUnit << ").";
1131             }
1132 
1133             mCachedValidateSamplersResult = false;
1134             return false;
1135         }
1136     }
1137 
1138     mCachedValidateSamplersResult = true;
1139     return true;
1140 }
1141 
1142 }  // namespace gl
1143