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