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