xref: /aosp_15_r20/external/angle/src/libANGLE/Program.h (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2002 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 
7 // Program.h: Defines the gl::Program class. Implements GL program objects
8 // and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
9 
10 #ifndef LIBANGLE_PROGRAM_H_
11 #define LIBANGLE_PROGRAM_H_
12 
13 #include <GLES2/gl2.h>
14 #include <GLSLANG/ShaderVars.h>
15 
16 #include <array>
17 #include <map>
18 #include <memory>
19 #include <set>
20 #include <sstream>
21 #include <string>
22 #include <vector>
23 
24 #include "common/Optional.h"
25 #include "common/SimpleMutex.h"
26 #include "common/angleutils.h"
27 #include "common/hash_containers.h"
28 #include "common/mathutil.h"
29 #include "common/utilities.h"
30 
31 #include "libANGLE/Constants.h"
32 #include "libANGLE/Debug.h"
33 #include "libANGLE/Error.h"
34 #include "libANGLE/InfoLog.h"
35 #include "libANGLE/ProgramExecutable.h"
36 #include "libANGLE/ProgramLinkedResources.h"
37 #include "libANGLE/RefCountObject.h"
38 #include "libANGLE/Shader.h"
39 #include "libANGLE/Uniform.h"
40 #include "libANGLE/angletypes.h"
41 
42 namespace rx
43 {
44 class GLImplFactory;
45 class ProgramImpl;
46 class LinkSubTask;
47 struct TranslatedAttribute;
48 }  // namespace rx
49 
50 namespace gl
51 {
52 class Buffer;
53 class BinaryInputStream;
54 class BinaryOutputStream;
55 struct Caps;
56 class Context;
57 struct Extensions;
58 class Framebuffer;
59 class ProgramExecutable;
60 class ShaderProgramManager;
61 class State;
62 struct UnusedUniform;
63 struct Version;
64 
65 extern const char *const g_fakepath;
66 
67 enum class LinkMismatchError
68 {
69     // Shared
70     NO_MISMATCH,
71     TYPE_MISMATCH,
72     ARRAYNESS_MISMATCH,
73     ARRAY_SIZE_MISMATCH,
74     PRECISION_MISMATCH,
75     STRUCT_NAME_MISMATCH,
76     FIELD_NUMBER_MISMATCH,
77     FIELD_NAME_MISMATCH,
78 
79     // Varying specific
80     INTERPOLATION_TYPE_MISMATCH,
81     INVARIANCE_MISMATCH,
82 
83     // Uniform specific
84     BINDING_MISMATCH,
85     LOCATION_MISMATCH,
86     OFFSET_MISMATCH,
87     INSTANCE_NAME_MISMATCH,
88     FORMAT_MISMATCH,
89 
90     // Interface block specific
91     LAYOUT_QUALIFIER_MISMATCH,
92     MATRIX_PACKING_MISMATCH,
93 
94     // I/O block specific
95     FIELD_LOCATION_MISMATCH,
96     FIELD_STRUCT_NAME_MISMATCH,
97 };
98 
99 void LogLinkMismatch(InfoLog &infoLog,
100                      const std::string &variableName,
101                      const char *variableType,
102                      LinkMismatchError linkError,
103                      const std::string &mismatchedStructOrBlockFieldName,
104                      ShaderType shaderType1,
105                      ShaderType shaderType2);
106 
107 bool IsActiveInterfaceBlock(const sh::InterfaceBlock &interfaceBlock);
108 
109 // Struct used for correlating uniforms/elements of uniform arrays to handles
110 ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
111 struct VariableLocation
112 {
113     static constexpr unsigned int kUnused = GL_INVALID_INDEX;
114 
115     VariableLocation();
116     VariableLocation(unsigned int arrayIndex, unsigned int index);
117 
118     // If used is false, it means this location is only used to fill an empty space in an array,
119     // and there is no corresponding uniform variable for this location. It can also mean the
120     // uniform was optimized out by the implementation.
usedVariableLocation121     bool used() const { return (index != kUnused); }
markUnusedVariableLocation122     void markUnused() { index = kUnused; }
markIgnoredVariableLocation123     void markIgnored() { ignored = true; }
124 
125     bool operator==(const VariableLocation &other) const
126     {
127         return arrayIndex == other.arrayIndex && index == other.index;
128     }
129 
130     // "index" is an index of the variable. The variable contains the indices for other than the
131     // innermost GLSL arrays.
132     uint32_t index;
133 
134     // "arrayIndex" stores the index of the innermost GLSL array. It's zero for non-arrays.
135     uint32_t arrayIndex : 31;
136     // If this location was bound to an unreferenced uniform.  Setting data on this uniform is a
137     // no-op.
138     uint32_t ignored : 1;
139 };
140 ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
141 
142 // Information about a variable binding.
143 // Currently used by CHROMIUM_path_rendering
144 struct BindingInfo
145 {
146     // The type of binding, for example GL_FLOAT_VEC3.
147     // This can be GL_NONE if the variable is optimized away.
148     GLenum type;
149 
150     // This is the name of the variable in
151     // the translated shader program. Note that
152     // this can be empty in the case where the
153     // variable has been optimized away.
154     std::string name;
155 
156     // True if the binding is valid, otherwise false.
157     bool valid;
158 };
159 
160 struct ProgramBinding
161 {
ProgramBindingProgramBinding162     ProgramBinding() : location(GL_INVALID_INDEX), aliased(false) {}
ProgramBindingProgramBinding163     ProgramBinding(GLuint index) : location(index), aliased(false) {}
164 
165     GLuint location;
166     // Whether another binding was set that may potentially alias this.
167     bool aliased;
168 };
169 
170 class ProgramBindings final : angle::NonCopyable
171 {
172   public:
173     ProgramBindings();
174     ~ProgramBindings();
175 
176     void bindLocation(GLuint index, const std::string &name);
177     int getBindingByName(const std::string &name) const;
178     template <typename T>
179     int getBinding(const T &variable) const;
180 
181     using const_iterator = angle::HashMap<std::string, GLuint>::const_iterator;
182     const_iterator begin() const;
183     const_iterator end() const;
184 
185     std::map<std::string, GLuint> getStableIterationMap() const;
186 
187   private:
188     angle::HashMap<std::string, GLuint> mBindings;
189 };
190 
191 // Uniforms and Fragment Outputs require special treatment due to array notation (e.g., "[0]")
192 class ProgramAliasedBindings final : angle::NonCopyable
193 {
194   public:
195     ProgramAliasedBindings();
196     ~ProgramAliasedBindings();
197 
198     void bindLocation(GLuint index, const std::string &name);
199     int getBindingByName(const std::string &name) const;
200     int getBindingByLocation(GLuint location) const;
201     template <typename T>
202     int getBinding(const T &variable) const;
203 
204     using const_iterator = angle::HashMap<std::string, ProgramBinding>::const_iterator;
205     const_iterator begin() const;
206     const_iterator end() const;
207 
208     std::map<std::string, ProgramBinding> getStableIterationMap() const;
209 
210   private:
211     angle::HashMap<std::string, ProgramBinding> mBindings;
212 };
213 
214 class ProgramState final : angle::NonCopyable
215 {
216   public:
217     ProgramState(rx::GLImplFactory *factory);
218     ~ProgramState();
219 
220     const std::string &getLabel();
221 
222     SharedCompiledShaderState getAttachedShader(ShaderType shaderType) const;
getAttachedShaders()223     const ShaderMap<SharedCompiledShaderState> &getAttachedShaders() const
224     {
225         return mAttachedShaders;
226     }
getTransformFeedbackVaryingNames()227     const std::vector<std::string> &getTransformFeedbackVaryingNames() const
228     {
229         return mTransformFeedbackVaryingNames;
230     }
getTransformFeedbackBufferMode()231     GLint getTransformFeedbackBufferMode() const { return mTransformFeedbackBufferMode; }
232 
233     bool hasAnyAttachedShader() const;
234 
getAttributeBindings()235     const ProgramBindings &getAttributeBindings() const { return mAttributeBindings; }
getUniformLocationBindings()236     const ProgramAliasedBindings &getUniformLocationBindings() const
237     {
238         return mUniformLocationBindings;
239     }
getFragmentOutputLocations()240     const ProgramAliasedBindings &getFragmentOutputLocations() const
241     {
242         return mFragmentOutputLocations;
243     }
getFragmentOutputIndexes()244     const ProgramAliasedBindings &getFragmentOutputIndexes() const
245     {
246         return mFragmentOutputIndexes;
247     }
248 
getExecutable()249     const ProgramExecutable &getExecutable() const
250     {
251         ASSERT(mExecutable);
252         return *mExecutable;
253     }
getExecutable()254     ProgramExecutable &getExecutable()
255     {
256         ASSERT(mExecutable);
257         return *mExecutable;
258     }
259 
getSharedExecutable()260     const SharedProgramExecutable &getSharedExecutable() const
261     {
262         ASSERT(mExecutable);
263         return mExecutable;
264     }
265 
getLabel()266     const std::string &getLabel() const { return mLabel; }
267 
hasBinaryRetrieveableHint()268     bool hasBinaryRetrieveableHint() const { return mBinaryRetrieveableHint; }
269 
isSeparable()270     bool isSeparable() const { return mSeparable; }
271 
272     ShaderType getAttachedTransformFeedbackStage() const;
273 
274   private:
275     friend class MemoryProgramCache;
276     friend class Program;
277 
278     void updateActiveSamplers();
279     void updateProgramInterfaceInputs();
280     void updateProgramInterfaceOutputs();
281 
282     // Scans the sampler bindings for type conflicts with sampler 'textureUnitIndex'.
283     void setSamplerUniformTextureTypeAndFormat(size_t textureUnitIndex);
284 
285     std::string mLabel;
286 
287     ShaderMap<SharedCompileJob> mShaderCompileJobs;
288     ShaderMap<SharedCompiledShaderState> mAttachedShaders;
289 
290     std::vector<std::string> mTransformFeedbackVaryingNames;
291     GLenum mTransformFeedbackBufferMode;
292 
293     bool mBinaryRetrieveableHint;
294     bool mSeparable;
295 
296     ProgramBindings mAttributeBindings;
297 
298     // Note that this has nothing to do with binding layout qualifiers that can be set for some
299     // uniforms in GLES3.1+. It is used to pre-set the location of uniforms.
300     ProgramAliasedBindings mUniformLocationBindings;
301 
302     // EXT_blend_func_extended
303     ProgramAliasedBindings mFragmentOutputLocations;
304     ProgramAliasedBindings mFragmentOutputIndexes;
305 
306     InfoLog mInfoLog;
307 
308     // The result of the link.  State that is not the link output should remain in ProgramState,
309     // while the link output should be placed in ProgramExecutable.
310     //
311     // This is a shared_ptr because it can be "installed" in the context as part of the rendering
312     // context.  Similarly, it can be installed in a program pipeline.  Once the executable is
313     // installed, the actual Program should not be referenced; it may have been unsuccessfully
314     // relinked and its executable in an unusable state.
315     SharedProgramExecutable mExecutable;
316 };
317 
318 struct ProgramVaryingRef
319 {
getProgramVaryingRef320     const sh::ShaderVariable *get(ShaderType stage) const
321     {
322         ASSERT(stage == frontShaderStage || stage == backShaderStage);
323         const sh::ShaderVariable *ref = stage == frontShaderStage ? frontShader : backShader;
324         ASSERT(ref);
325         return ref;
326     }
327 
328     const sh::ShaderVariable *frontShader = nullptr;
329     const sh::ShaderVariable *backShader  = nullptr;
330     ShaderType frontShaderStage           = ShaderType::InvalidEnum;
331     ShaderType backShaderStage            = ShaderType::InvalidEnum;
332 };
333 
334 using ProgramMergedVaryings = std::vector<ProgramVaryingRef>;
335 
336 class Program final : public LabeledObject, public angle::Subject
337 {
338   public:
339     Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, ShaderProgramID handle);
340     void onDestroy(const Context *context);
341 
342     ShaderProgramID id() const;
343 
344     angle::Result setLabel(const Context *context, const std::string &label) override;
345     const std::string &getLabel() const override;
346 
getImplementation()347     ANGLE_INLINE rx::ProgramImpl *getImplementation() const
348     {
349         ASSERT(!mLinkingState);
350         return mProgram;
351     }
352 
353     void attachShader(const Context *context, Shader *shader);
354     void detachShader(const Context *context, Shader *shader);
355     int getAttachedShadersCount() const;
356 
357     Shader *getAttachedShader(ShaderType shaderType) const;
358 
359     void bindAttributeLocation(const Context *context, GLuint index, const char *name);
360     void bindUniformLocation(const Context *context, UniformLocation location, const char *name);
361 
362     // EXT_blend_func_extended
363     void bindFragmentOutputLocation(const Context *context, GLuint index, const char *name);
364     void bindFragmentOutputIndex(const Context *context, GLuint index, const char *name);
365 
366     // KHR_parallel_shader_compile
367     // Try to link the program asynchronously. As a result, background threads may be launched to
368     // execute the linking tasks concurrently.
369     angle::Result link(const Context *context, angle::JobResultExpectancy resultExpectancy);
370 
371     // Peek whether there is any running linking tasks.
372     bool isLinking() const;
hasLinkingState()373     bool hasLinkingState() const { return mLinkingState != nullptr; }
374 
isLinked()375     bool isLinked() const
376     {
377         ASSERT(!mLinkingState);
378         return mLinked;
379     }
380     bool isBinaryReady(const Context *context);
cacheProgramBinaryIfNecessary(const Context * context)381     ANGLE_INLINE void cacheProgramBinaryIfNecessary(const Context *context)
382     {
383         // This function helps ensure the program binary is cached, even if the backend waits for
384         // post-link tasks without the knowledge of the front-end.
385         if (!mIsBinaryCached && !mState.mBinaryRetrieveableHint &&
386             mState.mExecutable->mPostLinkSubTasks.empty())
387         {
388             cacheProgramBinaryIfNotAlready(context);
389         }
390     }
391 
392     angle::Result setBinary(const Context *context,
393                             GLenum binaryFormat,
394                             const void *binary,
395                             GLsizei length);
396     angle::Result getBinary(Context *context,
397                             GLenum *binaryFormat,
398                             void *binary,
399                             GLsizei bufSize,
400                             GLsizei *length);
401     GLint getBinaryLength(Context *context);
402     void setBinaryRetrievableHint(bool retrievable);
403     bool getBinaryRetrievableHint() const;
404 
405     angle::Result loadBinary(const Context *context,
406                              const void *binary,
407                              GLsizei length,
408                              egl::CacheGetResult *resultOut);
409 
getInfoLog()410     InfoLog &getInfoLog() { return mState.mInfoLog; }
411     int getInfoLogLength() const;
412     void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const;
413 
414     void setSeparable(const Context *context, bool separable);
isSeparable()415     bool isSeparable() const { return mState.mSeparable; }
416 
417     void getAttachedShaders(GLsizei maxCount, GLsizei *count, ShaderProgramID *shaders) const;
418 
419     void bindUniformBlock(UniformBlockIndex uniformBlockIndex, GLuint uniformBlockBinding);
420 
421     void setTransformFeedbackVaryings(const Context *context,
422                                       GLsizei count,
423                                       const GLchar *const *varyings,
424                                       GLenum bufferMode);
getTransformFeedbackBufferMode()425     GLenum getTransformFeedbackBufferMode() const { return mState.mTransformFeedbackBufferMode; }
426 
addRef()427     ANGLE_INLINE void addRef() { mRefCount++; }
428 
release(const Context * context)429     ANGLE_INLINE void release(const Context *context)
430     {
431         mRefCount--;
432 
433         if (mRefCount == 0 && mDeleteStatus)
434         {
435             deleteSelf(context);
436         }
437     }
438 
439     unsigned int getRefCount() const;
isInUse()440     bool isInUse() const { return getRefCount() != 0; }
441     void flagForDeletion();
442     bool isFlaggedForDeletion() const;
443 
444     void validate(const Caps &caps);
445     bool isValidated() const;
446 
getState()447     const ProgramState &getState() const { return mState; }
448 
getAttributeBindings()449     const ProgramBindings &getAttributeBindings() const { return mState.getAttributeBindings(); }
getUniformLocationBindings()450     const ProgramAliasedBindings &getUniformLocationBindings() const
451     {
452         return mState.getUniformLocationBindings();
453     }
getFragmentOutputLocations()454     const ProgramAliasedBindings &getFragmentOutputLocations() const
455     {
456         return mState.getFragmentOutputLocations();
457     }
getFragmentOutputIndexes()458     const ProgramAliasedBindings &getFragmentOutputIndexes() const
459     {
460         return mState.getFragmentOutputIndexes();
461     }
462 
463     // Try to resolve linking. Inlined to make sure its overhead is as low as possible.
resolveLink(const Context * context)464     void resolveLink(const Context *context)
465     {
466         if (mLinkingState)
467         {
468             resolveLinkImpl(context);
469         }
470     }
471 
472     // Writes a program's binary to |mBinary|.
473     angle::Result serialize(const Context *context);
getSerializedBinary()474     const angle::MemoryBuffer &getSerializedBinary() const { return mBinary; }
475 
serial()476     rx::UniqueSerial serial() const { return mSerial; }
477 
getExecutable()478     const ProgramExecutable &getExecutable() const { return mState.getExecutable(); }
getExecutable()479     ProgramExecutable &getExecutable() { return mState.getExecutable(); }
getSharedExecutable()480     const SharedProgramExecutable &getSharedExecutable() const
481     {
482         return mState.getSharedExecutable();
483     }
484 
485   private:
486     class MainLinkLoadTask;
487     class MainLoadTask;
488     class MainLinkTask;
489     class MainLinkLoadEvent;
490 
491     friend class ProgramPipeline;
492     friend class MainLinkLoadTask;
493     friend class MainLoadTask;
494     friend class MainLinkTask;
495 
496     struct LinkingState;
497     ~Program() override;
498 
499     // Loads program state according to the specified binary blob.  Returns true on success.
500     bool deserialize(const Context *context, BinaryInputStream &stream);
501 
502     void unlink();
503     void setupExecutableForLink(const Context *context);
504     void deleteSelf(const Context *context);
505 
506     angle::Result linkJobImpl(const Caps &caps,
507                               const Limitations &limitations,
508                               const Version &clientVersion,
509                               bool isWebGL,
510                               LinkingVariables *linkingVariables,
511                               ProgramLinkedResources *resources,
512                               ProgramMergedVaryings *mergedVaryingsOut);
513 
514     void makeNewExecutable(const Context *context);
515 
516     bool linkValidateShaders();
517     void linkShaders();
518     bool linkAttributes(const Caps &caps, const Limitations &limitations, bool webglCompatibility);
519     bool linkVaryings();
520 
521     bool linkUniforms(const Caps &caps,
522                       const Version &clientVersion,
523                       std::vector<UnusedUniform> *unusedUniformsOutOrNull,
524                       GLuint *combinedImageUniformsOut);
525 
526     void updateLinkedShaderStages();
527 
528     // Block until linking is finished and resolve it.
529     void resolveLinkImpl(const Context *context);
530     // Block until post-link tasks are finished.
531     void waitForPostLinkTasks(const Context *context);
532 
533     void postResolveLink(const Context *context);
534     void cacheProgramBinaryIfNotAlready(const Context *context);
535 
536     void dumpProgramInfo(const Context *context) const;
537 
538     rx::UniqueSerial mSerial;
539     ProgramState mState;
540     rx::ProgramImpl *mProgram;
541 
542     bool mValidated;
543     // Flag to indicate that the program can be deleted when no longer in use
544     bool mDeleteStatus;
545     // Whether the program binary is implicitly cached yet.  This is usually done in
546     // |resolveLinkImpl|, but may be deferred in the presence of post-link tasks.  In that case,
547     // |waitForPostLinkTasks| would cache the binary.  However, if the wait on the tasks is done by
548     // the backend itself, this caching will not be done.  This flag is used to make sure the binary
549     // is eventually cached at some point in the future.
550     bool mIsBinaryCached;
551 
552     bool mLinked;
553     std::unique_ptr<LinkingState> mLinkingState;
554 
555     egl::BlobCache::Key mProgramHash;
556 
557     unsigned int mRefCount;
558 
559     ShaderProgramManager *mResourceManager;
560     const ShaderProgramID mHandle;
561 
562     // ProgramState::mAttachedShaders holds a reference to shaders' compiled state, which is all the
563     // program and the backends require after link.  The actual shaders linked to the program are
564     // stored here to support shader attach/detach and link without providing access to them in the
565     // backends.
566     ShaderMap<Shader *> mAttachedShaders;
567 
568     // A cache of the program binary, prepared by |serialize()|.  OpenGL requires the application to
569     // query the length of the binary first (requiring a call to |serialize()|), and then get the
570     // actual binary.  This cache ensures the second call does not need to call |serialize()| again.
571     angle::MemoryBuffer mBinary;
572 
573     angle::SimpleMutex mHistogramMutex;
574 };
575 }  // namespace gl
576 
577 #endif  // LIBANGLE_PROGRAM_H_
578