• 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/ProgramPipeline.h"
14 #include "libANGLE/Shader.h"
15 
16 namespace gl
17 {
18 
ProgramExecutable()19 ProgramExecutable::ProgramExecutable()
20     : mProgramState(nullptr),
21       mProgramPipelineState(nullptr),
22       mMaxActiveAttribLocation(0),
23       mAttributesTypeMask(0),
24       mAttributesMask(0),
25       mActiveSamplersMask(0),
26       mActiveSamplerRefCounts{},
27       mActiveImagesMask(0),
28       mCanDrawWith(false),
29       mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
30       mSamplerUniformRange(0, 0),
31       mImageUniformRange(0, 0),
32       mPipelineHasGraphicsUniformBuffers(false),
33       mPipelineHasComputeUniformBuffers(false),
34       mPipelineHasGraphicsStorageBuffers(false),
35       mPipelineHasComputeStorageBuffers(false),
36       mPipelineHasGraphicsAtomicCounterBuffers(false),
37       mPipelineHasComputeAtomicCounterBuffers(false)
38 {
39     reset();
40 }
41 
ProgramExecutable(const ProgramExecutable & other)42 ProgramExecutable::ProgramExecutable(const ProgramExecutable &other)
43     : mProgramState(other.mProgramState),
44       mProgramPipelineState(other.mProgramPipelineState),
45       mLinkedGraphicsShaderStages(other.mLinkedGraphicsShaderStages),
46       mLinkedComputeShaderStages(other.mLinkedComputeShaderStages),
47       mActiveAttribLocationsMask(other.mActiveAttribLocationsMask),
48       mMaxActiveAttribLocation(other.mMaxActiveAttribLocation),
49       mAttributesTypeMask(other.mAttributesTypeMask),
50       mAttributesMask(other.mAttributesMask),
51       mActiveSamplersMask(other.mActiveSamplersMask),
52       mActiveSamplerRefCounts(other.mActiveSamplerRefCounts),
53       mActiveSamplerTypes(other.mActiveSamplerTypes),
54       mActiveSamplerFormats(other.mActiveSamplerFormats),
55       mActiveSamplerShaderBits(other.mActiveSamplerShaderBits),
56       mActiveImagesMask(other.mActiveImagesMask),
57       mActiveImageShaderBits(other.mActiveImageShaderBits),
58       mCanDrawWith(other.mCanDrawWith),
59       mOutputVariables(other.mOutputVariables),
60       mOutputLocations(other.mOutputLocations),
61       mProgramInputs(other.mProgramInputs),
62       mLinkedTransformFeedbackVaryings(other.mLinkedTransformFeedbackVaryings),
63       mTransformFeedbackStrides(other.mTransformFeedbackStrides),
64       mTransformFeedbackBufferMode(other.mTransformFeedbackBufferMode),
65       mUniforms(other.mUniforms),
66       mSamplerUniformRange(other.mSamplerUniformRange),
67       mUniformBlocks(other.mUniformBlocks),
68       mAtomicCounterBuffers(other.mAtomicCounterBuffers),
69       mImageUniformRange(other.mImageUniformRange),
70       mShaderStorageBlocks(other.mShaderStorageBlocks),
71       mPipelineHasGraphicsUniformBuffers(other.mPipelineHasGraphicsUniformBuffers),
72       mPipelineHasComputeUniformBuffers(other.mPipelineHasComputeUniformBuffers),
73       mPipelineHasGraphicsStorageBuffers(other.mPipelineHasGraphicsStorageBuffers),
74       mPipelineHasComputeStorageBuffers(other.mPipelineHasComputeStorageBuffers),
75       mPipelineHasGraphicsAtomicCounterBuffers(other.mPipelineHasGraphicsAtomicCounterBuffers),
76       mPipelineHasComputeAtomicCounterBuffers(other.mPipelineHasComputeAtomicCounterBuffers)
77 {
78     reset();
79 }
80 
81 ProgramExecutable::~ProgramExecutable() = default;
82 
reset()83 void ProgramExecutable::reset()
84 {
85     resetInfoLog();
86     mActiveAttribLocationsMask.reset();
87     mAttributesTypeMask.reset();
88     mAttributesMask.reset();
89     mMaxActiveAttribLocation = 0;
90 
91     mActiveSamplersMask.reset();
92     mActiveSamplerRefCounts = {};
93     mActiveSamplerTypes.fill(TextureType::InvalidEnum);
94     mActiveSamplerFormats.fill(SamplerFormat::InvalidEnum);
95 
96     mActiveImagesMask.reset();
97 
98     mProgramInputs.clear();
99     mLinkedTransformFeedbackVaryings.clear();
100     mUniforms.clear();
101     mUniformBlocks.clear();
102     mShaderStorageBlocks.clear();
103     mAtomicCounterBuffers.clear();
104     mOutputVariables.clear();
105     mOutputLocations.clear();
106 
107     mPipelineHasGraphicsUniformBuffers       = false;
108     mPipelineHasComputeUniformBuffers        = false;
109     mPipelineHasGraphicsStorageBuffers       = false;
110     mPipelineHasComputeStorageBuffers        = false;
111     mPipelineHasGraphicsAtomicCounterBuffers = false;
112     mPipelineHasComputeAtomicCounterBuffers  = false;
113 }
114 
load(gl::BinaryInputStream * stream)115 void ProgramExecutable::load(gl::BinaryInputStream *stream)
116 {
117     static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
118                   "Too many vertex attribs for mask: All bits of mAttributesTypeMask types and "
119                   "mask fit into 32 bits each");
120     mAttributesTypeMask        = gl::ComponentTypeMask(stream->readInt<uint32_t>());
121     mAttributesMask            = stream->readInt<gl::AttributesMask>();
122     mActiveAttribLocationsMask = stream->readInt<gl::AttributesMask>();
123     mMaxActiveAttribLocation   = stream->readInt<unsigned int>();
124 
125     mLinkedGraphicsShaderStages = ShaderBitSet(stream->readInt<uint8_t>());
126     mLinkedComputeShaderStages  = ShaderBitSet(stream->readInt<uint8_t>());
127 
128     mPipelineHasGraphicsUniformBuffers       = stream->readBool();
129     mPipelineHasComputeUniformBuffers        = stream->readBool();
130     mPipelineHasGraphicsStorageBuffers       = stream->readBool();
131     mPipelineHasComputeStorageBuffers        = stream->readBool();
132     mPipelineHasGraphicsAtomicCounterBuffers = stream->readBool();
133     mPipelineHasComputeAtomicCounterBuffers  = stream->readBool();
134 }
135 
save(gl::BinaryOutputStream * stream) const136 void ProgramExecutable::save(gl::BinaryOutputStream *stream) const
137 {
138     static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
139                   "All bits of mAttributesTypeMask types and mask fit into 32 bits each");
140     stream->writeInt(static_cast<int>(mAttributesTypeMask.to_ulong()));
141     stream->writeInt(static_cast<int>(mAttributesMask.to_ulong()));
142     stream->writeInt(mActiveAttribLocationsMask.to_ulong());
143     stream->writeInt(mMaxActiveAttribLocation);
144 
145     stream->writeInt(mLinkedGraphicsShaderStages.bits());
146     stream->writeInt(mLinkedComputeShaderStages.bits());
147 
148     stream->writeInt(static_cast<bool>(mPipelineHasGraphicsUniformBuffers));
149     stream->writeInt(static_cast<bool>(mPipelineHasComputeUniformBuffers));
150     stream->writeInt(static_cast<bool>(mPipelineHasGraphicsStorageBuffers));
151     stream->writeInt(static_cast<bool>(mPipelineHasComputeStorageBuffers));
152     stream->writeInt(static_cast<bool>(mPipelineHasGraphicsAtomicCounterBuffers));
153     stream->writeInt(static_cast<bool>(mPipelineHasComputeAtomicCounterBuffers));
154 }
155 
getProgramState(ShaderType shaderType) const156 const ProgramState *ProgramExecutable::getProgramState(ShaderType shaderType) const
157 {
158     if (mProgramState &&
159         (hasLinkedShaderStage(shaderType) || mProgramState->getAttachedShader(shaderType)))
160     {
161         return mProgramState;
162     }
163     else if (mProgramPipelineState && (hasLinkedShaderStage(shaderType) ||
164                                        mProgramPipelineState->getShaderProgram(shaderType)))
165     {
166         return &mProgramPipelineState->getShaderProgram(shaderType)->getState();
167     }
168 
169     return nullptr;
170 }
171 
isCompute() const172 bool ProgramExecutable::isCompute() const
173 {
174     ASSERT(mProgramState || mProgramPipelineState);
175 
176     if (mProgramState)
177     {
178         return mProgramState->isCompute();
179     }
180 
181     return mProgramPipelineState->isCompute();
182 }
183 
setIsCompute(bool isComputeIn)184 void ProgramExecutable::setIsCompute(bool isComputeIn)
185 {
186     // A Program can only either be graphics or compute, but never both, so it can answer
187     // isCompute() based on which shaders it has. However, a PPO can have both graphics and compute
188     // programs attached, so we don't know if the PPO is a 'graphics' or 'compute' PPO until the
189     // actual draw/dispatch call, which is why only PPOs need to record the type of call here.
190     if (mProgramPipelineState)
191     {
192         mProgramPipelineState->setIsCompute(isComputeIn);
193     }
194 }
195 
getInfoLogLength() const196 int ProgramExecutable::getInfoLogLength() const
197 {
198     return static_cast<int>(mInfoLog.getLength());
199 }
200 
getInfoLog(GLsizei bufSize,GLsizei * length,char * infoLog) const201 void ProgramExecutable::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
202 {
203     return mInfoLog.getLog(bufSize, length, infoLog);
204 }
205 
getInfoLogString() const206 std::string ProgramExecutable::getInfoLogString() const
207 {
208     return mInfoLog.str();
209 }
210 
isAttribLocationActive(size_t attribLocation) const211 bool ProgramExecutable::isAttribLocationActive(size_t attribLocation) const
212 {
213     // TODO(timvp): http://anglebug.com/3570: Enable this assert here somehow.
214     //    ASSERT(!mLinkingState);
215     ASSERT(attribLocation < mActiveAttribLocationsMask.size());
216     return mActiveAttribLocationsMask[attribLocation];
217 }
218 
getAttributesMask() const219 AttributesMask ProgramExecutable::getAttributesMask() const
220 {
221     // TODO(timvp): http://anglebug.com/3570: Enable this assert here somehow.
222     //    ASSERT(!mLinkingState);
223     return mAttributesMask;
224 }
225 
226 // TODO: http://anglebug.com/4520: Needs  mDefaultUniformRange moved to ProgramExecutable
hasDefaultUniforms() const227 bool ProgramExecutable::hasDefaultUniforms() const
228 {
229     ASSERT(mProgramState || mProgramPipelineState);
230     if (mProgramState)
231     {
232         return mProgramState->hasDefaultUniforms();
233     }
234 
235     return mProgramPipelineState->hasDefaultUniforms();
236 }
237 
238 // TODO: http://anglebug.com/4520: Needs  mSamplerBindings moved to ProgramExecutable
hasTextures() const239 bool ProgramExecutable::hasTextures() const
240 {
241     ASSERT(mProgramState || mProgramPipelineState);
242     if (mProgramState)
243     {
244         return mProgramState->hasTextures();
245     }
246 
247     return mProgramPipelineState->hasTextures();
248 }
249 
250 // TODO: http://anglebug.com/3570: Remove mHas*UniformBuffers once PPO's have valid data in
251 // mUniformBlocks
hasUniformBuffers() const252 bool ProgramExecutable::hasUniformBuffers() const
253 {
254     return !getUniformBlocks().empty() ||
255            (isCompute() ? mPipelineHasComputeUniformBuffers : mPipelineHasGraphicsUniformBuffers);
256 }
257 
hasStorageBuffers() const258 bool ProgramExecutable::hasStorageBuffers() const
259 {
260     return !getShaderStorageBlocks().empty() ||
261            (isCompute() ? mPipelineHasComputeStorageBuffers : mPipelineHasGraphicsStorageBuffers);
262 }
263 
hasAtomicCounterBuffers() const264 bool ProgramExecutable::hasAtomicCounterBuffers() const
265 {
266     return !getAtomicCounterBuffers().empty() ||
267            (isCompute() ? mPipelineHasComputeAtomicCounterBuffers
268                         : mPipelineHasGraphicsAtomicCounterBuffers);
269 }
270 
271 // TODO: http://anglebug.com/4520: Needs  mImageBindings moved to ProgramExecutable
hasImages() const272 bool ProgramExecutable::hasImages() const
273 {
274     ASSERT(mProgramState || mProgramPipelineState);
275     if (mProgramState)
276     {
277         return mProgramState->hasImages();
278     }
279 
280     return mProgramPipelineState->hasImages();
281 }
282 
updateActiveSamplers(const ProgramState & programState)283 void ProgramExecutable::updateActiveSamplers(const ProgramState &programState)
284 {
285     const std::vector<SamplerBinding> &samplerBindings = programState.getSamplerBindings();
286 
287     for (uint32_t samplerIndex = 0; samplerIndex < samplerBindings.size(); ++samplerIndex)
288     {
289         const SamplerBinding &samplerBinding = samplerBindings[samplerIndex];
290         if (samplerBinding.unreferenced)
291             continue;
292 
293         uint32_t uniformIndex = programState.getUniformIndexFromSamplerIndex(samplerIndex);
294         const gl::LinkedUniform &samplerUniform = programState.getUniforms()[uniformIndex];
295 
296         for (GLint textureUnit : samplerBinding.boundTextureUnits)
297         {
298             if (++mActiveSamplerRefCounts[textureUnit] == 1)
299             {
300                 mActiveSamplerTypes[textureUnit]      = samplerBinding.textureType;
301                 mActiveSamplerFormats[textureUnit]    = samplerBinding.format;
302                 mActiveSamplerShaderBits[textureUnit] = samplerUniform.activeShaders();
303             }
304             else
305             {
306                 if (mActiveSamplerTypes[textureUnit] != samplerBinding.textureType)
307                 {
308                     mActiveSamplerTypes[textureUnit] = TextureType::InvalidEnum;
309                 }
310                 if (mActiveSamplerFormats[textureUnit] != samplerBinding.format)
311                 {
312                     mActiveSamplerFormats[textureUnit] = SamplerFormat::InvalidEnum;
313                 }
314             }
315             mActiveSamplersMask.set(textureUnit);
316         }
317     }
318 }
319 
updateActiveImages(std::vector<ImageBinding> & imageBindings)320 void ProgramExecutable::updateActiveImages(std::vector<ImageBinding> &imageBindings)
321 {
322     const bool compute = isCompute() ? true : false;
323     for (uint32_t imageIndex = 0; imageIndex < imageBindings.size(); ++imageIndex)
324     {
325         const gl::ImageBinding &imageBinding = imageBindings[imageIndex];
326         if (imageBinding.unreferenced)
327             continue;
328 
329         uint32_t uniformIndex = mProgramState->getUniformIndexFromImageIndex(imageIndex);
330         const gl::LinkedUniform &imageUniform = mProgramState->getUniforms()[uniformIndex];
331         const ShaderBitSet shaderBits         = imageUniform.activeShaders();
332         for (GLint imageUnit : imageBinding.boundImageUnits)
333         {
334             mActiveImagesMask.set(imageUnit);
335             if (compute)
336                 mActiveImageShaderBits[imageUnit].set(gl::ShaderType::Compute);
337             else
338                 mActiveImageShaderBits[imageUnit] = shaderBits;
339         }
340     }
341 }
342 
setSamplerUniformTextureTypeAndFormat(size_t textureUnitIndex,std::vector<SamplerBinding> & samplerBindings)343 void ProgramExecutable::setSamplerUniformTextureTypeAndFormat(
344     size_t textureUnitIndex,
345     std::vector<SamplerBinding> &samplerBindings)
346 {
347     bool foundBinding         = false;
348     TextureType foundType     = TextureType::InvalidEnum;
349     SamplerFormat foundFormat = SamplerFormat::InvalidEnum;
350 
351     for (const SamplerBinding &binding : samplerBindings)
352     {
353         if (binding.unreferenced)
354             continue;
355 
356         // A conflict exists if samplers of different types are sourced by the same texture unit.
357         // We need to check all bound textures to detect this error case.
358         for (GLuint textureUnit : binding.boundTextureUnits)
359         {
360             if (textureUnit == textureUnitIndex)
361             {
362                 if (!foundBinding)
363                 {
364                     foundBinding = true;
365                     foundType    = binding.textureType;
366                     foundFormat  = binding.format;
367                 }
368                 else
369                 {
370                     if (foundType != binding.textureType)
371                     {
372                         foundType = TextureType::InvalidEnum;
373                     }
374                     if (foundFormat != binding.format)
375                     {
376                         foundFormat = SamplerFormat::InvalidEnum;
377                     }
378                 }
379             }
380         }
381     }
382 
383     mActiveSamplerTypes[textureUnitIndex]   = foundType;
384     mActiveSamplerFormats[textureUnitIndex] = foundFormat;
385 }
386 
linkValidateGlobalNames(InfoLog & infoLog) const387 bool ProgramExecutable::linkValidateGlobalNames(InfoLog &infoLog) const
388 {
389     std::unordered_map<std::string, const sh::ShaderVariable *> uniformMap;
390     using BlockAndFieldPair = std::pair<const sh::InterfaceBlock *, const sh::ShaderVariable *>;
391     std::unordered_map<std::string, std::vector<BlockAndFieldPair>> uniformBlockFieldMap;
392 
393     for (ShaderType shaderType : kAllGraphicsShaderTypes)
394     {
395         const ProgramState *programState = getProgramState(shaderType);
396         if (!programState)
397         {
398             continue;
399         }
400         Shader *shader = programState->getAttachedShader(shaderType);
401         if (!shader)
402         {
403             continue;
404         }
405 
406         // Build a map of Uniforms
407         const std::vector<sh::ShaderVariable> uniforms = shader->getUniforms();
408         for (const auto &uniform : uniforms)
409         {
410             uniformMap[uniform.name] = &uniform;
411         }
412 
413         // Build a map of Uniform Blocks
414         // This will also detect any field name conflicts between Uniform Blocks without instance
415         // names
416         const std::vector<sh::InterfaceBlock> &uniformBlocks = shader->getUniformBlocks();
417         for (const auto &uniformBlock : uniformBlocks)
418         {
419             // Only uniform blocks without an instance name can create a conflict with their field
420             // names
421             if (!uniformBlock.instanceName.empty())
422             {
423                 continue;
424             }
425 
426             for (const auto &field : uniformBlock.fields)
427             {
428                 if (!uniformBlockFieldMap.count(field.name))
429                 {
430                     // First time we've seen this uniform block field name, so add the
431                     // (Uniform Block, Field) pair immediately since there can't be a conflict yet
432                     BlockAndFieldPair blockAndFieldPair(&uniformBlock, &field);
433                     std::vector<BlockAndFieldPair> newUniformBlockList;
434                     newUniformBlockList.push_back(blockAndFieldPair);
435                     uniformBlockFieldMap[field.name] = newUniformBlockList;
436                     continue;
437                 }
438 
439                 // We've seen this name before.
440                 // We need to check each of the uniform blocks that contain a field with this name
441                 // to see if there's a conflict or not.
442                 std::vector<BlockAndFieldPair> prevBlockFieldPairs =
443                     uniformBlockFieldMap[field.name];
444                 for (const auto &prevBlockFieldPair : prevBlockFieldPairs)
445                 {
446                     const sh::InterfaceBlock *prevUniformBlock      = prevBlockFieldPair.first;
447                     const sh::ShaderVariable *prevUniformBlockField = prevBlockFieldPair.second;
448 
449                     if (uniformBlock.isSameInterfaceBlockAtLinkTime(*prevUniformBlock))
450                     {
451                         // The same uniform block should, by definition, contain the same field name
452                         continue;
453                     }
454 
455                     // The uniform blocks don't match, so check if the necessary field properties
456                     // also match
457                     if ((field.name == prevUniformBlockField->name) &&
458                         (field.type == prevUniformBlockField->type) &&
459                         (field.precision == prevUniformBlockField->precision))
460                     {
461                         infoLog << "Name conflicts between uniform block field names: "
462                                 << field.name;
463                         return false;
464                     }
465                 }
466 
467                 // No conflict, so record this pair
468                 BlockAndFieldPair blockAndFieldPair(&uniformBlock, &field);
469                 uniformBlockFieldMap[field.name].push_back(blockAndFieldPair);
470             }
471         }
472     }
473 
474     // Validate no uniform names conflict with attribute names
475     const ProgramState *programState = getProgramState(ShaderType::Vertex);
476     if (programState)
477     {
478         Shader *vertexShader = programState->getAttachedShader(ShaderType::Vertex);
479         if (vertexShader)
480         {
481             for (const auto &attrib : vertexShader->getActiveAttributes())
482             {
483                 if (uniformMap.count(attrib.name))
484                 {
485                     infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
486                     return false;
487                 }
488             }
489         }
490     }
491 
492     // Validate no Uniform Block fields conflict with other Uniforms
493     for (const auto &uniformBlockField : uniformBlockFieldMap)
494     {
495         const std::string &fieldName = uniformBlockField.first;
496         if (uniformMap.count(fieldName))
497         {
498             infoLog << "Name conflicts between a uniform and a uniform block field: " << fieldName;
499             return false;
500         }
501     }
502 
503     return true;
504 }
505 
updateCanDrawWith()506 void ProgramExecutable::updateCanDrawWith()
507 {
508     mCanDrawWith =
509         (hasLinkedShaderStage(ShaderType::Vertex) && hasLinkedShaderStage(ShaderType::Fragment));
510 }
511 
saveLinkedStateInfo()512 void ProgramExecutable::saveLinkedStateInfo()
513 {
514     // Only a Program's linked data needs to be saved, not a ProgramPipeline's
515     ASSERT(mProgramState);
516 
517     for (ShaderType shaderType : getLinkedShaderStages())
518     {
519         Shader *shader = mProgramState->getAttachedShader(shaderType);
520         ASSERT(shader);
521         mLinkedOutputVaryings[shaderType] = shader->getOutputVaryings();
522         mLinkedInputVaryings[shaderType]  = shader->getInputVaryings();
523         mLinkedShaderVersions[shaderType] = shader->getShaderVersion();
524     }
525 }
526 
527 }  // namespace gl
528