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.h: Collects the information and interfaces common to both Programs and
7 // ProgramPipelines in order to execute/draw with either.
8 
9 #ifndef LIBANGLE_PROGRAMEXECUTABLE_H_
10 #define LIBANGLE_PROGRAMEXECUTABLE_H_
11 
12 #include "BinaryStream.h"
13 #include "libANGLE/Caps.h"
14 #include "libANGLE/InfoLog.h"
15 #include "libANGLE/ProgramLinkedResources.h"
16 #include "libANGLE/Shader.h"
17 #include "libANGLE/Uniform.h"
18 #include "libANGLE/VaryingPacking.h"
19 #include "libANGLE/angletypes.h"
20 
21 namespace gl
22 {
23 
24 // This small structure encapsulates binding sampler uniforms to active GL textures.
25 struct SamplerBinding
26 {
27     SamplerBinding(TextureType textureTypeIn,
28                    GLenum samplerTypeIn,
29                    SamplerFormat formatIn,
30                    size_t elementCount);
31     SamplerBinding(const SamplerBinding &other);
32     ~SamplerBinding();
33 
34     // Necessary for retrieving active textures from the GL state.
35     TextureType textureType;
36 
37     GLenum samplerType;
38 
39     SamplerFormat format;
40 
41     // List of all textures bound to this sampler, of type textureType.
42     // Cropped by the amount of unused elements reported by the driver.
43     std::vector<GLuint> boundTextureUnits;
44 };
45 
46 struct ImageBinding
47 {
48     ImageBinding(size_t count, TextureType textureTypeIn);
49     ImageBinding(GLuint imageUnit, size_t count, TextureType textureTypeIn);
50     ImageBinding(const ImageBinding &other);
51     ~ImageBinding();
52 
53     // Necessary for distinguishing between textures with images and texture buffers.
54     TextureType textureType;
55 
56     // List of all textures bound.
57     // Cropped by the amount of unused elements reported by the driver.
58     std::vector<GLuint> boundImageUnits;
59 };
60 
61 // A varying with transform feedback enabled. If it's an array, either the whole array or one of its
62 // elements specified by 'arrayIndex' can set to be enabled.
63 struct TransformFeedbackVarying : public sh::ShaderVariable
64 {
TransformFeedbackVaryingTransformFeedbackVarying65     TransformFeedbackVarying(const sh::ShaderVariable &varyingIn, GLuint arrayIndexIn)
66         : sh::ShaderVariable(varyingIn), arrayIndex(arrayIndexIn)
67     {
68         ASSERT(!isArrayOfArrays());
69     }
70 
TransformFeedbackVaryingTransformFeedbackVarying71     TransformFeedbackVarying(const sh::ShaderVariable &field, const sh::ShaderVariable &parent)
72         : arrayIndex(GL_INVALID_INDEX)
73     {
74         sh::ShaderVariable *thisVar = this;
75         *thisVar                    = field;
76         interpolation               = parent.interpolation;
77         isInvariant                 = parent.isInvariant;
78         ASSERT(parent.isShaderIOBlock || !parent.name.empty());
79         if (!parent.name.empty())
80         {
81             name       = parent.name + "." + name;
82             mappedName = parent.mappedName + "." + mappedName;
83         }
84         structOrBlockName       = parent.structOrBlockName;
85         mappedStructOrBlockName = parent.mappedStructOrBlockName;
86     }
87 
nameWithArrayIndexTransformFeedbackVarying88     std::string nameWithArrayIndex() const
89     {
90         std::stringstream fullNameStr;
91         fullNameStr << name;
92         if (arrayIndex != GL_INVALID_INDEX)
93         {
94             fullNameStr << "[" << arrayIndex << "]";
95         }
96         return fullNameStr.str();
97     }
sizeTransformFeedbackVarying98     GLsizei size() const
99     {
100         return (isArray() && arrayIndex == GL_INVALID_INDEX ? getOutermostArraySize() : 1);
101     }
102 
103     GLuint arrayIndex;
104 };
105 
106 class ProgramState;
107 class ProgramPipelineState;
108 
109 class ProgramExecutable final : public angle::Subject
110 {
111   public:
112     ProgramExecutable();
113     ProgramExecutable(const ProgramExecutable &other);
114     ~ProgramExecutable() override;
115 
116     void reset();
117 
118     void save(bool isSeparable, gl::BinaryOutputStream *stream) const;
119     void load(bool isSeparable, gl::BinaryInputStream *stream);
120 
121     int getInfoLogLength() const;
getInfoLog()122     InfoLog &getInfoLog() { return mInfoLog; }
123     void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const;
124     std::string getInfoLogString() const;
resetInfoLog()125     void resetInfoLog() { mInfoLog.reset(); }
126 
resetLinkedShaderStages()127     void resetLinkedShaderStages()
128     {
129         mLinkedComputeShaderStages.reset();
130         mLinkedGraphicsShaderStages.reset();
131     }
getLinkedShaderStages()132     const ShaderBitSet &getLinkedShaderStages() const
133     {
134         return isCompute() ? mLinkedComputeShaderStages : mLinkedGraphicsShaderStages;
135     }
setLinkedShaderStages(ShaderType shaderType)136     void setLinkedShaderStages(ShaderType shaderType)
137     {
138         if (shaderType == ShaderType::Compute)
139         {
140             mLinkedComputeShaderStages.set(ShaderType::Compute);
141         }
142         else
143         {
144             mLinkedGraphicsShaderStages.set(shaderType);
145         }
146 
147         updateCanDrawWith();
148     }
hasLinkedShaderStage(ShaderType shaderType)149     bool hasLinkedShaderStage(ShaderType shaderType) const
150     {
151         ASSERT(shaderType != ShaderType::InvalidEnum);
152         return (shaderType == ShaderType::Compute) ? mLinkedComputeShaderStages[shaderType]
153                                                    : mLinkedGraphicsShaderStages[shaderType];
154     }
getLinkedShaderStageCount()155     size_t getLinkedShaderStageCount() const
156     {
157         return isCompute() ? mLinkedComputeShaderStages.count()
158                            : mLinkedGraphicsShaderStages.count();
159     }
hasLinkedTessellationShader()160     bool hasLinkedTessellationShader() const
161     {
162         return mLinkedGraphicsShaderStages[ShaderType::TessControl] ||
163                mLinkedGraphicsShaderStages[ShaderType::TessEvaluation];
164     }
165 
166     ShaderType getTransformFeedbackStage() const;
167 
168     ShaderType getLinkedTransformFeedbackStage() const;
169 
170     // A PPO can have both graphics and compute programs attached, so
171     // we don't know if the PPO is a 'graphics' or 'compute' PPO until the
172     // actual draw/dispatch call.
isCompute()173     bool isCompute() const { return mIsCompute; }
setIsCompute(bool isCompute)174     void setIsCompute(bool isCompute) { mIsCompute = isCompute; }
175 
getActiveAttribLocationsMask()176     const AttributesMask &getActiveAttribLocationsMask() const
177     {
178         return mActiveAttribLocationsMask;
179     }
180     bool isAttribLocationActive(size_t attribLocation) const;
getNonBuiltinAttribLocationsMask()181     const AttributesMask &getNonBuiltinAttribLocationsMask() const { return mAttributesMask; }
getMaxActiveAttribLocation()182     unsigned int getMaxActiveAttribLocation() const { return mMaxActiveAttribLocation; }
getAttributesTypeMask()183     const ComponentTypeMask &getAttributesTypeMask() const { return mAttributesTypeMask; }
184     AttributesMask getAttributesMask() const;
185 
getActiveSamplersMask()186     const ActiveTextureMask &getActiveSamplersMask() const { return mActiveSamplersMask; }
setActiveTextureMask(ActiveTextureMask mask)187     void setActiveTextureMask(ActiveTextureMask mask) { mActiveSamplersMask = mask; }
getSamplerFormatForTextureUnitIndex(size_t textureUnitIndex)188     SamplerFormat getSamplerFormatForTextureUnitIndex(size_t textureUnitIndex) const
189     {
190         return mActiveSamplerFormats[textureUnitIndex];
191     }
getSamplerShaderBitsForTextureUnitIndex(size_t textureUnitIndex)192     const ShaderBitSet getSamplerShaderBitsForTextureUnitIndex(size_t textureUnitIndex) const
193     {
194         return mActiveSamplerShaderBits[textureUnitIndex];
195     }
getActiveImagesMask()196     const ActiveTextureMask &getActiveImagesMask() const { return mActiveImagesMask; }
setActiveImagesMask(ActiveTextureMask mask)197     void setActiveImagesMask(ActiveTextureMask mask) { mActiveImagesMask = mask; }
getActiveImageShaderBits()198     const ActiveTextureArray<ShaderBitSet> &getActiveImageShaderBits() const
199     {
200         return mActiveImageShaderBits;
201     }
202 
getActiveYUVSamplers()203     const ActiveTextureMask &getActiveYUVSamplers() const { return mActiveSamplerYUV; }
204 
getActiveSamplerTypes()205     const ActiveTextureArray<TextureType> &getActiveSamplerTypes() const
206     {
207         return mActiveSamplerTypes;
208     }
209 
210     void updateActiveSamplers(const ProgramState &programState);
211 
212     bool hasDefaultUniforms() const;
213     bool hasTextures() const;
214     bool hasUniformBuffers() const;
215     bool hasStorageBuffers() const;
216     bool hasGraphicsStorageBuffers() const;
217     bool hasComputeStorageBuffers() const;
218     bool hasAtomicCounterBuffers() const;
219     bool hasImages() const;
220     bool hasGraphicsImages() const;
221     bool hasComputeImages() const;
hasTransformFeedbackOutput()222     bool hasTransformFeedbackOutput() const
223     {
224         return !getLinkedTransformFeedbackVaryings().empty();
225     }
226     bool usesFramebufferFetch() const;
227 
228     // Count the number of uniform and storage buffer declarations, counting arrays as one.
getTransformFeedbackBufferCount()229     size_t getTransformFeedbackBufferCount() const { return mTransformFeedbackStrides.size(); }
230 
231     void updateCanDrawWith();
hasVertexAndFragmentShader()232     bool hasVertexAndFragmentShader() const { return mCanDrawWith; }
233 
getProgramInputs()234     const std::vector<sh::ShaderVariable> &getProgramInputs() const { return mProgramInputs; }
getOutputVariables()235     const std::vector<sh::ShaderVariable> &getOutputVariables() const { return mOutputVariables; }
getOutputLocations()236     const std::vector<VariableLocation> &getOutputLocations() const { return mOutputLocations; }
getSecondaryOutputLocations()237     const std::vector<VariableLocation> &getSecondaryOutputLocations() const
238     {
239         return mSecondaryOutputLocations;
240     }
getUniforms()241     const std::vector<LinkedUniform> &getUniforms() const { return mUniforms; }
getUniformBlocks()242     const std::vector<InterfaceBlock> &getUniformBlocks() const { return mUniformBlocks; }
getActiveUniformBlockBindings()243     const UniformBlockBindingMask &getActiveUniformBlockBindings() const
244     {
245         return mActiveUniformBlockBindings;
246     }
getSamplerBindings()247     const std::vector<SamplerBinding> &getSamplerBindings() const { return mSamplerBindings; }
getImageBindings()248     const std::vector<ImageBinding> &getImageBindings() const
249     {
250         return isCompute() ? mComputeImageBindings : mGraphicsImageBindings;
251     }
getImageBindings()252     std::vector<ImageBinding> *getImageBindings()
253     {
254         return isCompute() ? &mComputeImageBindings : &mGraphicsImageBindings;
255     }
getDefaultUniformRange()256     const RangeUI &getDefaultUniformRange() const { return mDefaultUniformRange; }
getSamplerUniformRange()257     const RangeUI &getSamplerUniformRange() const { return mSamplerUniformRange; }
getImageUniformRange()258     const RangeUI &getImageUniformRange() const { return mImageUniformRange; }
getFragmentInoutRange()259     const RangeUI &getFragmentInoutRange() const { return mFragmentInoutRange; }
getLinkedTransformFeedbackVaryings()260     const std::vector<TransformFeedbackVarying> &getLinkedTransformFeedbackVaryings() const
261     {
262         return mLinkedTransformFeedbackVaryings;
263     }
getTransformFeedbackBufferMode()264     GLint getTransformFeedbackBufferMode() const { return mTransformFeedbackBufferMode; }
getUniformBlockBinding(GLuint uniformBlockIndex)265     GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const
266     {
267         ASSERT(uniformBlockIndex < mUniformBlocks.size());
268         return mUniformBlocks[uniformBlockIndex].binding;
269     }
getShaderStorageBlockBinding(GLuint blockIndex)270     GLuint getShaderStorageBlockBinding(GLuint blockIndex) const
271     {
272         ASSERT((isCompute() && (blockIndex < mComputeShaderStorageBlocks.size())) ||
273                (!isCompute() && (blockIndex < mGraphicsShaderStorageBlocks.size())));
274         return isCompute() ? mComputeShaderStorageBlocks[blockIndex].binding
275                            : mGraphicsShaderStorageBlocks[blockIndex].binding;
276     }
getTransformFeedbackStrides()277     const std::vector<GLsizei> &getTransformFeedbackStrides() const
278     {
279         return mTransformFeedbackStrides;
280     }
getAtomicCounterBuffers()281     const std::vector<AtomicCounterBuffer> &getAtomicCounterBuffers() const
282     {
283         return mAtomicCounterBuffers;
284     }
getShaderStorageBlocks()285     const std::vector<InterfaceBlock> &getShaderStorageBlocks() const
286     {
287         return isCompute() ? mComputeShaderStorageBlocks : mGraphicsShaderStorageBlocks;
288     }
getUniformByIndex(GLuint index)289     const LinkedUniform &getUniformByIndex(GLuint index) const
290     {
291         ASSERT(index < static_cast<size_t>(mUniforms.size()));
292         return mUniforms[index];
293     }
294 
getActiveUniformBlockCount()295     ANGLE_INLINE GLuint getActiveUniformBlockCount() const
296     {
297         return static_cast<GLuint>(mUniformBlocks.size());
298     }
299 
getActiveAtomicCounterBufferCount()300     ANGLE_INLINE GLuint getActiveAtomicCounterBufferCount() const
301     {
302         return static_cast<GLuint>(mAtomicCounterBuffers.size());
303     }
304 
getActiveShaderStorageBlockCount()305     ANGLE_INLINE GLuint getActiveShaderStorageBlockCount() const
306     {
307         size_t shaderStorageBlocksSize =
308             isCompute() ? mComputeShaderStorageBlocks.size() : mGraphicsShaderStorageBlocks.size();
309         return static_cast<GLuint>(shaderStorageBlocksSize);
310     }
311 
312     GLuint getUniformIndexFromImageIndex(GLuint imageIndex) const;
313 
314     void saveLinkedStateInfo(const ProgramState &state);
getLinkedOutputVaryings(ShaderType shaderType)315     const std::vector<sh::ShaderVariable> &getLinkedOutputVaryings(ShaderType shaderType) const
316     {
317         return mLinkedOutputVaryings[shaderType];
318     }
getLinkedInputVaryings(ShaderType shaderType)319     const std::vector<sh::ShaderVariable> &getLinkedInputVaryings(ShaderType shaderType) const
320     {
321         return mLinkedInputVaryings[shaderType];
322     }
323 
getLinkedShaderVersion(ShaderType shaderType)324     int getLinkedShaderVersion(ShaderType shaderType) const
325     {
326         return mLinkedShaderVersions[shaderType];
327     }
328 
329     bool isYUVOutput() const;
330 
getGeometryShaderInputPrimitiveType()331     PrimitiveMode getGeometryShaderInputPrimitiveType() const
332     {
333         return mGeometryShaderInputPrimitiveType;
334     }
335 
getGeometryShaderOutputPrimitiveType()336     PrimitiveMode getGeometryShaderOutputPrimitiveType() const
337     {
338         return mGeometryShaderOutputPrimitiveType;
339     }
340 
getGeometryShaderInvocations()341     int getGeometryShaderInvocations() const { return mGeometryShaderInvocations; }
342 
getGeometryShaderMaxVertices()343     int getGeometryShaderMaxVertices() const { return mGeometryShaderMaxVertices; }
344 
getTessGenMode()345     GLenum getTessGenMode() const { return mTessGenMode; }
346 
resetCachedValidateSamplersResult()347     void resetCachedValidateSamplersResult() { mCachedValidateSamplersResult.reset(); }
validateSamplers(InfoLog * infoLog,const Caps & caps)348     bool validateSamplers(InfoLog *infoLog, const Caps &caps) const
349     {
350         // Use the cache if:
351         // - we aren't using an infolog (which gives the full error).
352         // - The sample mapping hasn't changed and we've already validated.
353         if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
354         {
355             return mCachedValidateSamplersResult.value();
356         }
357 
358         return validateSamplersImpl(infoLog, caps);
359     }
360 
361   private:
362     // TODO(timvp): http://anglebug.com/3570: Investigate removing these friend
363     // class declarations and accessing the necessary members with getters/setters.
364     friend class Program;
365     friend class ProgramPipeline;
366     friend class ProgramState;
367 
368     void updateActiveImages(const ProgramExecutable &executable);
369 
370     // Scans the sampler bindings for type conflicts with sampler 'textureUnitIndex'.
371     void setSamplerUniformTextureTypeAndFormat(size_t textureUnitIndex,
372                                                std::vector<SamplerBinding> &samplerBindings);
373 
374     bool linkMergedVaryings(const Context *context,
375                             const HasAttachedShaders &programOrPipeline,
376                             const ProgramMergedVaryings &mergedVaryings,
377                             const std::vector<std::string> &transformFeedbackVaryingNames,
378                             bool isSeparable,
379                             ProgramVaryingPacking *varyingPacking);
380 
381     bool linkValidateTransformFeedback(
382         const Context *context,
383         const ProgramMergedVaryings &varyings,
384         ShaderType stage,
385         const std::vector<std::string> &transformFeedbackVaryingNames);
386 
387     void gatherTransformFeedbackVaryings(
388         const ProgramMergedVaryings &varyings,
389         ShaderType stage,
390         const std::vector<std::string> &transformFeedbackVaryingNames);
391 
392     void updateTransformFeedbackStrides();
393 
394     bool validateSamplersImpl(InfoLog *infoLog, const Caps &caps) const;
395 
396     InfoLog mInfoLog;
397 
398     ShaderBitSet mLinkedGraphicsShaderStages;
399     ShaderBitSet mLinkedComputeShaderStages;
400 
401     angle::BitSet<MAX_VERTEX_ATTRIBS> mActiveAttribLocationsMask;
402     unsigned int mMaxActiveAttribLocation;
403     ComponentTypeMask mAttributesTypeMask;
404     // mAttributesMask is identical to mActiveAttribLocationsMask with built-in attributes removed.
405     AttributesMask mAttributesMask;
406 
407     // Cached mask of active samplers and sampler types.
408     ActiveTextureMask mActiveSamplersMask;
409     ActiveTextureArray<uint32_t> mActiveSamplerRefCounts;
410     ActiveTextureArray<TextureType> mActiveSamplerTypes;
411     ActiveTextureMask mActiveSamplerYUV;
412     ActiveTextureArray<SamplerFormat> mActiveSamplerFormats;
413     ActiveTextureArray<ShaderBitSet> mActiveSamplerShaderBits;
414 
415     // Cached mask of active images.
416     ActiveTextureMask mActiveImagesMask;
417     ActiveTextureArray<ShaderBitSet> mActiveImageShaderBits;
418 
419     bool mCanDrawWith;
420 
421     // Names and mapped names of output variables that are arrays include [0] in the end, similarly
422     // to uniforms.
423     std::vector<sh::ShaderVariable> mOutputVariables;
424     std::vector<VariableLocation> mOutputLocations;
425     // EXT_blend_func_extended secondary outputs (ones with index 1)
426     std::vector<VariableLocation> mSecondaryOutputLocations;
427     bool mYUVOutput;
428     // Vertex attributes, Fragment input varyings, etc.
429     std::vector<sh::ShaderVariable> mProgramInputs;
430     std::vector<TransformFeedbackVarying> mLinkedTransformFeedbackVaryings;
431     // The size of the data written to each transform feedback buffer per vertex.
432     std::vector<GLsizei> mTransformFeedbackStrides;
433     GLenum mTransformFeedbackBufferMode;
434     // Uniforms are sorted in order:
435     //  1. Non-opaque uniforms
436     //  2. Sampler uniforms
437     //  3. Image uniforms
438     //  4. Atomic counter uniforms
439     //  5. Subpass Input uniforms (Only for Vulkan)
440     //  6. Uniform block uniforms
441     // This makes opaque uniform validation easier, since we don't need a separate list.
442     // For generating the entries and naming them we follow the spec: GLES 3.1 November 2016 section
443     // 7.3.1.1 Naming Active Resources. There's a separate entry for each struct member and each
444     // inner array of an array of arrays. Names and mapped names of uniforms that are arrays include
445     // [0] in the end. This makes implementation of queries simpler.
446     std::vector<LinkedUniform> mUniforms;
447     RangeUI mDefaultUniformRange;
448     RangeUI mSamplerUniformRange;
449     std::vector<InterfaceBlock> mUniformBlocks;
450 
451     // For faster iteration on the blocks currently being bound.
452     UniformBlockBindingMask mActiveUniformBlockBindings;
453 
454     std::vector<AtomicCounterBuffer> mAtomicCounterBuffers;
455     RangeUI mImageUniformRange;
456     std::vector<InterfaceBlock> mComputeShaderStorageBlocks;
457     std::vector<InterfaceBlock> mGraphicsShaderStorageBlocks;
458     RangeUI mFragmentInoutRange;
459 
460     // An array of the samplers that are used by the program
461     std::vector<SamplerBinding> mSamplerBindings;
462 
463     // An array of the images that are used by the program
464     std::vector<ImageBinding> mComputeImageBindings;
465     std::vector<ImageBinding> mGraphicsImageBindings;
466 
467     // TODO: http://anglebug.com/3570: Remove mPipelineHas*UniformBuffers once PPO's have valid data
468     // in mUniformBlocks
469     bool mPipelineHasGraphicsUniformBuffers;
470     bool mPipelineHasComputeUniformBuffers;
471     bool mPipelineHasGraphicsStorageBuffers;
472     bool mPipelineHasComputeStorageBuffers;
473     bool mPipelineHasGraphicsAtomicCounterBuffers;
474     bool mPipelineHasComputeAtomicCounterBuffers;
475     bool mPipelineHasGraphicsDefaultUniforms;
476     bool mPipelineHasComputeDefaultUniforms;
477     bool mPipelineHasGraphicsTextures;
478     bool mPipelineHasComputeTextures;
479     bool mPipelineHasGraphicsImages;
480     bool mPipelineHasComputeImages;
481 
482     bool mIsCompute;
483 
484     ShaderMap<std::vector<sh::ShaderVariable>> mLinkedOutputVaryings;
485     ShaderMap<std::vector<sh::ShaderVariable>> mLinkedInputVaryings;
486     ShaderMap<int> mLinkedShaderVersions;
487 
488     // GL_EXT_geometry_shader.
489     PrimitiveMode mGeometryShaderInputPrimitiveType;
490     PrimitiveMode mGeometryShaderOutputPrimitiveType;
491     int mGeometryShaderInvocations;
492     int mGeometryShaderMaxVertices;
493 
494     // GL_EXT_tessellation_shader
495     int mTessControlShaderVertices;
496     GLenum mTessGenMode;
497     GLenum mTessGenSpacing;
498     GLenum mTessGenVertexOrder;
499     GLenum mTessGenPointMode;
500 
501     // Cache for sampler validation
502     mutable Optional<bool> mCachedValidateSamplersResult;
503 };
504 }  // namespace gl
505 
506 #endif  // LIBANGLE_PROGRAMEXECUTABLE_H_
507