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