• 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 {
29     mActiveSamplerTypes.fill(TextureType::InvalidEnum);
30     mActiveSamplerFormats.fill(SamplerFormat::InvalidEnum);
31 }
32 
33 ProgramExecutable::~ProgramExecutable() = default;
34 
reset()35 void ProgramExecutable::reset()
36 {
37     resetInfoLog();
38     mActiveAttribLocationsMask.reset();
39     mAttributesTypeMask.reset();
40     mAttributesMask.reset();
41     mMaxActiveAttribLocation = 0;
42 
43     mActiveSamplersMask.reset();
44     mActiveSamplerRefCounts = {};
45     mActiveSamplerTypes.fill(TextureType::InvalidEnum);
46     mActiveSamplerFormats.fill(SamplerFormat::InvalidEnum);
47 
48     mActiveImagesMask.reset();
49 }
50 
getProgramState(ShaderType shaderType) const51 const ProgramState *ProgramExecutable::getProgramState(ShaderType shaderType) const
52 {
53     if (mProgramState &&
54         (hasLinkedShaderStage(shaderType) || mProgramState->getAttachedShader(shaderType)))
55     {
56         return mProgramState;
57     }
58     else if (mProgramPipelineState && (hasLinkedShaderStage(shaderType) ||
59                                        mProgramPipelineState->getShaderProgram(shaderType)))
60     {
61         return &mProgramPipelineState->getShaderProgram(shaderType)->getState();
62     }
63 
64     return nullptr;
65 }
66 
getInfoLogLength() const67 int ProgramExecutable::getInfoLogLength() const
68 {
69     return static_cast<int>(mInfoLog.getLength());
70 }
71 
getInfoLog(GLsizei bufSize,GLsizei * length,char * infoLog) const72 void ProgramExecutable::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const
73 {
74     return mInfoLog.getLog(bufSize, length, infoLog);
75 }
76 
getInfoLogString() const77 std::string ProgramExecutable::getInfoLogString() const
78 {
79     return mInfoLog.str();
80 }
81 
isAttribLocationActive(size_t attribLocation) const82 bool ProgramExecutable::isAttribLocationActive(size_t attribLocation) const
83 {
84     // TODO(timvp): http://anglebug.com/3570: Enable this assert here somehow.
85     //    ASSERT(mLinkResolved);
86     ASSERT(attribLocation < mActiveAttribLocationsMask.size());
87     return mActiveAttribLocationsMask[attribLocation];
88 }
89 
getAttributesMask() const90 AttributesMask ProgramExecutable::getAttributesMask() const
91 {
92     // TODO(timvp): http://anglebug.com/3570: Enable this assert here somehow.
93     //    ASSERT(mLinkResolved);
94     return mAttributesMask;
95 }
96 
hasDefaultUniforms() const97 bool ProgramExecutable::hasDefaultUniforms() const
98 {
99     ASSERT(mProgramState || mProgramPipelineState);
100     if (mProgramState)
101     {
102         return mProgramState->hasDefaultUniforms();
103     }
104 
105     return mProgramPipelineState->hasDefaultUniforms();
106 }
107 
hasTextures() const108 bool ProgramExecutable::hasTextures() const
109 {
110     ASSERT(mProgramState || mProgramPipelineState);
111     if (mProgramState)
112     {
113         return mProgramState->hasTextures();
114     }
115 
116     return mProgramPipelineState->hasTextures();
117 }
118 
hasUniformBuffers() const119 bool ProgramExecutable::hasUniformBuffers() const
120 {
121     ASSERT(mProgramState || mProgramPipelineState);
122     if (mProgramState)
123     {
124         return mProgramState->hasUniformBuffers();
125     }
126 
127     return mProgramPipelineState->hasUniformBuffers();
128 }
129 
hasStorageBuffers() const130 bool ProgramExecutable::hasStorageBuffers() const
131 {
132     ASSERT(mProgramState || mProgramPipelineState);
133     if (mProgramState)
134     {
135         return mProgramState->hasStorageBuffers();
136     }
137 
138     return mProgramPipelineState->hasStorageBuffers();
139 }
140 
hasAtomicCounterBuffers() const141 bool ProgramExecutable::hasAtomicCounterBuffers() const
142 {
143     ASSERT(mProgramState || mProgramPipelineState);
144     if (mProgramState)
145     {
146         return mProgramState->hasAtomicCounterBuffers();
147     }
148 
149     return mProgramPipelineState->hasAtomicCounterBuffers();
150 }
151 
hasImages() const152 bool ProgramExecutable::hasImages() const
153 {
154     ASSERT(mProgramState || mProgramPipelineState);
155     if (mProgramState)
156     {
157         return mProgramState->hasImages();
158     }
159 
160     return mProgramPipelineState->hasImages();
161 }
162 
hasTransformFeedbackOutput() const163 bool ProgramExecutable::hasTransformFeedbackOutput() const
164 {
165     ASSERT(mProgramState || mProgramPipelineState);
166     if (mProgramState)
167     {
168         return mProgramState->hasTransformFeedbackOutput();
169     }
170 
171     return mProgramPipelineState->hasTransformFeedbackOutput();
172 }
173 
getTransformFeedbackBufferCount(const gl::State & glState) const174 size_t ProgramExecutable::getTransformFeedbackBufferCount(const gl::State &glState) const
175 {
176     ASSERT(mProgramState || mProgramPipelineState);
177     if (mProgramState)
178     {
179         return mProgramState->getTransformFeedbackBufferCount();
180     }
181 
182     // TODO(timvp): http://anglebug.com/3570: Support program pipelines
183 
184     return 0;
185 }
186 
updateActiveSamplers(const ProgramState & programState)187 void ProgramExecutable::updateActiveSamplers(const ProgramState &programState)
188 {
189     const std::vector<SamplerBinding> &samplerBindings = programState.getSamplerBindings();
190 
191     for (uint32_t samplerIndex = 0; samplerIndex < samplerBindings.size(); ++samplerIndex)
192     {
193         const SamplerBinding &samplerBinding = samplerBindings[samplerIndex];
194         if (samplerBinding.unreferenced)
195             continue;
196 
197         uint32_t uniformIndex = programState.getUniformIndexFromSamplerIndex(samplerIndex);
198         const gl::LinkedUniform &samplerUniform = programState.getUniforms()[uniformIndex];
199 
200         for (GLint textureUnit : samplerBinding.boundTextureUnits)
201         {
202             if (++mActiveSamplerRefCounts[textureUnit] == 1)
203             {
204                 mActiveSamplerTypes[textureUnit]      = samplerBinding.textureType;
205                 mActiveSamplerFormats[textureUnit]    = samplerBinding.format;
206                 mActiveSamplerShaderBits[textureUnit] = samplerUniform.activeShaders();
207             }
208             else
209             {
210                 if (mActiveSamplerTypes[textureUnit] != samplerBinding.textureType)
211                 {
212                     mActiveSamplerTypes[textureUnit] = TextureType::InvalidEnum;
213                 }
214                 if (mActiveSamplerFormats[textureUnit] != samplerBinding.format)
215                 {
216                     mActiveSamplerFormats[textureUnit] = SamplerFormat::InvalidEnum;
217                 }
218             }
219             mActiveSamplersMask.set(textureUnit);
220         }
221     }
222 }
223 
updateActiveImages(std::vector<ImageBinding> & imageBindings)224 void ProgramExecutable::updateActiveImages(std::vector<ImageBinding> &imageBindings)
225 {
226     const bool compute = isCompute() ? true : false;
227     for (uint32_t imageIndex = 0; imageIndex < imageBindings.size(); ++imageIndex)
228     {
229         const gl::ImageBinding &imageBinding = imageBindings[imageIndex];
230         if (imageBinding.unreferenced)
231             continue;
232 
233         uint32_t uniformIndex = mProgramState->getUniformIndexFromImageIndex(imageIndex);
234         const gl::LinkedUniform &imageUniform = mProgramState->getUniforms()[uniformIndex];
235         const ShaderBitSet shaderBits         = imageUniform.activeShaders();
236         for (GLint imageUnit : imageBinding.boundImageUnits)
237         {
238             mActiveImagesMask.set(imageUnit);
239             if (compute)
240                 mActiveImageShaderBits[imageUnit].set(gl::ShaderType::Compute);
241             else
242                 mActiveImageShaderBits[imageUnit] = shaderBits;
243         }
244     }
245 }
246 
setSamplerUniformTextureTypeAndFormat(size_t textureUnitIndex,std::vector<SamplerBinding> & samplerBindings)247 void ProgramExecutable::setSamplerUniformTextureTypeAndFormat(
248     size_t textureUnitIndex,
249     std::vector<SamplerBinding> &samplerBindings)
250 {
251     bool foundBinding         = false;
252     TextureType foundType     = TextureType::InvalidEnum;
253     SamplerFormat foundFormat = SamplerFormat::InvalidEnum;
254 
255     for (const SamplerBinding &binding : samplerBindings)
256     {
257         if (binding.unreferenced)
258             continue;
259 
260         // A conflict exists if samplers of different types are sourced by the same texture unit.
261         // We need to check all bound textures to detect this error case.
262         for (GLuint textureUnit : binding.boundTextureUnits)
263         {
264             if (textureUnit == textureUnitIndex)
265             {
266                 if (!foundBinding)
267                 {
268                     foundBinding = true;
269                     foundType    = binding.textureType;
270                     foundFormat  = binding.format;
271                 }
272                 else
273                 {
274                     if (foundType != binding.textureType)
275                     {
276                         foundType = TextureType::InvalidEnum;
277                     }
278                     if (foundFormat != binding.format)
279                     {
280                         foundFormat = SamplerFormat::InvalidEnum;
281                     }
282                 }
283             }
284         }
285     }
286 
287     mActiveSamplerTypes[textureUnitIndex]   = foundType;
288     mActiveSamplerFormats[textureUnitIndex] = foundFormat;
289 }
290 
linkValidateGlobalNames(InfoLog & infoLog) const291 bool ProgramExecutable::linkValidateGlobalNames(InfoLog &infoLog) const
292 {
293     std::unordered_map<std::string, const sh::ShaderVariable *> uniformMap;
294     using BlockAndFieldPair = std::pair<const sh::InterfaceBlock *, const sh::ShaderVariable *>;
295     std::unordered_map<std::string, std::vector<BlockAndFieldPair>> uniformBlockFieldMap;
296 
297     for (ShaderType shaderType : kAllGraphicsShaderTypes)
298     {
299         const ProgramState *programState = getProgramState(shaderType);
300         if (!programState)
301         {
302             continue;
303         }
304         Shader *shader = programState->getAttachedShader(shaderType);
305         if (!shader)
306         {
307             continue;
308         }
309 
310         // Build a map of Uniforms
311         const std::vector<sh::ShaderVariable> uniforms = shader->getUniforms();
312         for (const auto &uniform : uniforms)
313         {
314             uniformMap[uniform.name] = &uniform;
315         }
316 
317         // Build a map of Uniform Blocks
318         // This will also detect any field name conflicts between Uniform Blocks without instance
319         // names
320         const std::vector<sh::InterfaceBlock> &uniformBlocks = shader->getUniformBlocks();
321         for (const auto &uniformBlock : uniformBlocks)
322         {
323             // Only uniform blocks without an instance name can create a conflict with their field
324             // names
325             if (!uniformBlock.instanceName.empty())
326             {
327                 continue;
328             }
329 
330             for (const auto &field : uniformBlock.fields)
331             {
332                 if (!uniformBlockFieldMap.count(field.name))
333                 {
334                     // First time we've seen this uniform block field name, so add the
335                     // (Uniform Block, Field) pair immediately since there can't be a conflict yet
336                     BlockAndFieldPair blockAndFieldPair(&uniformBlock, &field);
337                     std::vector<BlockAndFieldPair> newUniformBlockList;
338                     newUniformBlockList.push_back(blockAndFieldPair);
339                     uniformBlockFieldMap[field.name] = newUniformBlockList;
340                     continue;
341                 }
342 
343                 // We've seen this name before.
344                 // We need to check each of the uniform blocks that contain a field with this name
345                 // to see if there's a conflict or not.
346                 std::vector<BlockAndFieldPair> prevBlockFieldPairs =
347                     uniformBlockFieldMap[field.name];
348                 for (const auto &prevBlockFieldPair : prevBlockFieldPairs)
349                 {
350                     const sh::InterfaceBlock *prevUniformBlock      = prevBlockFieldPair.first;
351                     const sh::ShaderVariable *prevUniformBlockField = prevBlockFieldPair.second;
352 
353                     if (uniformBlock.isSameInterfaceBlockAtLinkTime(*prevUniformBlock))
354                     {
355                         // The same uniform block should, by definition, contain the same field name
356                         continue;
357                     }
358 
359                     // The uniform blocks don't match, so check if the necessary field properties
360                     // also match
361                     if ((field.name == prevUniformBlockField->name) &&
362                         (field.type == prevUniformBlockField->type) &&
363                         (field.precision == prevUniformBlockField->precision))
364                     {
365                         infoLog << "Name conflicts between uniform block field names: "
366                                 << field.name;
367                         return false;
368                     }
369                 }
370 
371                 // No conflict, so record this pair
372                 BlockAndFieldPair blockAndFieldPair(&uniformBlock, &field);
373                 uniformBlockFieldMap[field.name].push_back(blockAndFieldPair);
374             }
375         }
376     }
377 
378     // Validate no uniform names conflict with attribute names
379     const ProgramState *programState = getProgramState(ShaderType::Vertex);
380     if (programState)
381     {
382         Shader *vertexShader = programState->getAttachedShader(ShaderType::Vertex);
383         if (vertexShader)
384         {
385             for (const auto &attrib : vertexShader->getActiveAttributes())
386             {
387                 if (uniformMap.count(attrib.name))
388                 {
389                     infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
390                     return false;
391                 }
392             }
393         }
394     }
395 
396     // Validate no Uniform Block fields conflict with other Uniforms
397     for (const auto &uniformBlockField : uniformBlockFieldMap)
398     {
399         const std::string &fieldName = uniformBlockField.first;
400         if (uniformMap.count(fieldName))
401         {
402             infoLog << "Name conflicts between a uniform and a uniform block field: " << fieldName;
403             return false;
404         }
405     }
406 
407     return true;
408 }
409 
410 }  // namespace gl
411