// // Copyright 2002 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // Program.h: Defines the gl::Program class. Implements GL program objects // and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28. #ifndef LIBANGLE_PROGRAM_H_ #define LIBANGLE_PROGRAM_H_ #include #include #include #include #include #include #include #include #include "common/Optional.h" #include "common/angleutils.h" #include "common/mathutil.h" #include "common/utilities.h" #include "libANGLE/Constants.h" #include "libANGLE/Debug.h" #include "libANGLE/Error.h" #include "libANGLE/InfoLog.h" #include "libANGLE/ProgramExecutable.h" #include "libANGLE/ProgramLinkedResources.h" #include "libANGLE/RefCountObject.h" #include "libANGLE/Uniform.h" #include "libANGLE/angletypes.h" namespace rx { class GLImplFactory; class ProgramImpl; struct TranslatedAttribute; } // namespace rx namespace gl { class Buffer; class BinaryInputStream; class BinaryOutputStream; struct Caps; class Context; struct Extensions; class Framebuffer; class ProgramExecutable; class Shader; class ShaderProgramManager; class State; struct UnusedUniform; struct Version; extern const char *const g_fakepath; enum class LinkMismatchError { // Shared NO_MISMATCH, TYPE_MISMATCH, ARRAYNESS_MISMATCH, ARRAY_SIZE_MISMATCH, PRECISION_MISMATCH, STRUCT_NAME_MISMATCH, FIELD_NUMBER_MISMATCH, FIELD_NAME_MISMATCH, // Varying specific INTERPOLATION_TYPE_MISMATCH, INVARIANCE_MISMATCH, // Uniform specific BINDING_MISMATCH, LOCATION_MISMATCH, OFFSET_MISMATCH, INSTANCE_NAME_MISMATCH, FORMAT_MISMATCH, // Interface block specific LAYOUT_QUALIFIER_MISMATCH, MATRIX_PACKING_MISMATCH, // I/O block specific FIELD_LOCATION_MISMATCH, FIELD_STRUCT_NAME_MISMATCH, }; void LogLinkMismatch(InfoLog &infoLog, const std::string &variableName, const char *variableType, LinkMismatchError linkError, const std::string &mismatchedStructOrBlockFieldName, ShaderType shaderType1, ShaderType shaderType2); bool IsActiveInterfaceBlock(const sh::InterfaceBlock &interfaceBlock); void WriteBlockMemberInfo(BinaryOutputStream *stream, const sh::BlockMemberInfo &var); void LoadBlockMemberInfo(BinaryInputStream *stream, sh::BlockMemberInfo *var); void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var); void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var); void WriteInterfaceBlock(BinaryOutputStream *stream, const InterfaceBlock &block); void LoadInterfaceBlock(BinaryInputStream *stream, InterfaceBlock *block); void WriteShaderVariableBuffer(BinaryOutputStream *stream, const ShaderVariableBuffer &var); void LoadShaderVariableBuffer(BinaryInputStream *stream, ShaderVariableBuffer *var); // Struct used for correlating uniforms/elements of uniform arrays to handles struct VariableLocation { static constexpr unsigned int kUnused = GL_INVALID_INDEX; VariableLocation(); VariableLocation(unsigned int arrayIndex, unsigned int index); // If used is false, it means this location is only used to fill an empty space in an array, // and there is no corresponding uniform variable for this location. It can also mean the // uniform was optimized out by the implementation. bool used() const { return (index != kUnused); } void markUnused() { index = kUnused; } void markIgnored() { ignored = true; } bool operator==(const VariableLocation &other) const { return arrayIndex == other.arrayIndex && index == other.index; } // "arrayIndex" stores the index of the innermost GLSL array. It's zero for non-arrays. unsigned int arrayIndex; // "index" is an index of the variable. The variable contains the indices for other than the // innermost GLSL arrays. unsigned int index; // If this location was bound to an unreferenced uniform. Setting data on this uniform is a // no-op. bool ignored; }; // Information about a variable binding. // Currently used by CHROMIUM_path_rendering struct BindingInfo { // The type of binding, for example GL_FLOAT_VEC3. // This can be GL_NONE if the variable is optimized away. GLenum type; // This is the name of the variable in // the translated shader program. Note that // this can be empty in the case where the // variable has been optimized away. std::string name; // True if the binding is valid, otherwise false. bool valid; }; struct ProgramBinding { ProgramBinding() : location(GL_INVALID_INDEX), aliased(false) {} ProgramBinding(GLuint index) : location(index), aliased(false) {} GLuint location; // Whether another binding was set that may potentially alias this. bool aliased; }; class ProgramBindings final : angle::NonCopyable { public: ProgramBindings(); ~ProgramBindings(); void bindLocation(GLuint index, const std::string &name); int getBindingByName(const std::string &name) const; int getBinding(const sh::ShaderVariable &variable) const; using const_iterator = angle::HashMap::const_iterator; const_iterator begin() const; const_iterator end() const; std::map getStableIterationMap() const; private: angle::HashMap mBindings; }; // Uniforms and Fragment Outputs require special treatment due to array notation (e.g., "[0]") class ProgramAliasedBindings final : angle::NonCopyable { public: ProgramAliasedBindings(); ~ProgramAliasedBindings(); void bindLocation(GLuint index, const std::string &name); int getBindingByName(const std::string &name) const; int getBindingByLocation(GLuint location) const; int getBinding(const sh::ShaderVariable &variable) const; using const_iterator = angle::HashMap::const_iterator; const_iterator begin() const; const_iterator end() const; std::map getStableIterationMap() const; private: angle::HashMap mBindings; }; class ProgramState final : angle::NonCopyable { public: ProgramState(); ~ProgramState(); const std::string &getLabel(); Shader *getAttachedShader(ShaderType shaderType) const; const gl::ShaderMap &getAttachedShaders() const { return mAttachedShaders; } const std::vector &getTransformFeedbackVaryingNames() const { return mTransformFeedbackVaryingNames; } GLint getTransformFeedbackBufferMode() const { return mExecutable->getTransformFeedbackBufferMode(); } GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const { return mExecutable->getUniformBlockBinding(uniformBlockIndex); } GLuint getShaderStorageBlockBinding(GLuint blockIndex) const { return mExecutable->getShaderStorageBlockBinding(blockIndex); } const UniformBlockBindingMask &getActiveUniformBlockBindingsMask() const { return mExecutable->getActiveUniformBlockBindings(); } const std::vector &getProgramInputs() const { return mExecutable->getProgramInputs(); } DrawBufferMask getActiveOutputVariables() const { return mActiveOutputVariables; } const std::vector &getOutputVariables() const { return mExecutable->getOutputVariables(); } const std::vector &getOutputLocations() const { return mExecutable->getOutputLocations(); } const std::vector &getSecondaryOutputLocations() const { return mExecutable->getSecondaryOutputLocations(); } const std::vector &getUniforms() const { return mExecutable->getUniforms(); } const std::vector &getUniformLocations() const { return mUniformLocations; } const std::vector &getUniformBlocks() const { return mExecutable->getUniformBlocks(); } const std::vector &getShaderStorageBlocks() const { return mExecutable->getShaderStorageBlocks(); } const std::vector &getBufferVariables() const { return mBufferVariables; } const std::vector &getSamplerBindings() const { return mExecutable->getSamplerBindings(); } const std::vector &getImageBindings() const { return getExecutable().getImageBindings(); } const sh::WorkGroupSize &getComputeShaderLocalSize() const { return mComputeShaderLocalSize; } const RangeUI &getDefaultUniformRange() const { return mExecutable->getDefaultUniformRange(); } const RangeUI &getSamplerUniformRange() const { return mExecutable->getSamplerUniformRange(); } const RangeUI &getImageUniformRange() const { return mExecutable->getImageUniformRange(); } const RangeUI &getAtomicCounterUniformRange() const { return mAtomicCounterUniformRange; } const RangeUI &getFragmentInoutRange() const { return mExecutable->getFragmentInoutRange(); } const std::vector &getLinkedTransformFeedbackVaryings() const { return mExecutable->getLinkedTransformFeedbackVaryings(); } const std::vector &getTransformFeedbackStrides() const { return mExecutable->getTransformFeedbackStrides(); } const std::vector &getAtomicCounterBuffers() const { return mExecutable->getAtomicCounterBuffers(); } GLuint getUniformIndexFromName(const std::string &name) const; GLuint getUniformIndexFromLocation(UniformLocation location) const; Optional getSamplerIndex(UniformLocation location) const; bool isSamplerUniformIndex(GLuint index) const; GLuint getSamplerIndexFromUniformIndex(GLuint uniformIndex) const; GLuint getUniformIndexFromSamplerIndex(GLuint samplerIndex) const; bool isImageUniformIndex(GLuint index) const; GLuint getImageIndexFromUniformIndex(GLuint uniformIndex) const; GLuint getAttributeLocation(const std::string &name) const; GLuint getBufferVariableIndexFromName(const std::string &name) const; int getNumViews() const { return mNumViews; } bool usesMultiview() const { return mNumViews != -1; } bool hasAttachedShader() const; ShaderType getFirstAttachedShaderStageType() const; ShaderType getLastAttachedShaderStageType() const; const ProgramAliasedBindings &getUniformLocationBindings() const { return mUniformLocationBindings; } const ProgramExecutable &getExecutable() const { ASSERT(mExecutable); return *mExecutable; } ProgramExecutable &getExecutable() { ASSERT(mExecutable); return *mExecutable; } bool hasImages() const { return !getImageBindings().empty(); } bool hasEarlyFragmentTestsOptimization() const { return mEarlyFramentTestsOptimization; } rx::SpecConstUsageBits getSpecConstUsageBits() const { return mSpecConstUsageBits; } // A Program can only either be graphics or compute, but never both, so it // can answer isCompute() based on which shaders it has. bool isCompute() const { return mExecutable->hasLinkedShaderStage(ShaderType::Compute); } const std::string &getLabel() const { return mLabel; } uint32_t getLocationsUsedForXfbExtension() const { return mLocationsUsedForXfbExtension; } const std::vector &getOutputVariableTypes() const { return mOutputVariableTypes; } ComponentTypeMask getDrawBufferTypeMask() const { return mDrawBufferTypeMask; } bool isYUVOutput() const { return mYUVOutput; } bool hasBinaryRetrieveableHint() const { return mBinaryRetrieveableHint; } bool isSeparable() const { return mSeparable; } int getDrawIDLocation() const { return mDrawIDLocation; } int getBaseVertexLocation() const { return mBaseVertexLocation; } int getBaseInstanceLocation() const { return mBaseInstanceLocation; } ShaderType getAttachedTransformFeedbackStage() const; private: friend class MemoryProgramCache; friend class Program; void updateActiveSamplers(); void updateProgramInterfaceInputs(); void updateProgramInterfaceOutputs(); // Scans the sampler bindings for type conflicts with sampler 'textureUnitIndex'. void setSamplerUniformTextureTypeAndFormat(size_t textureUnitIndex); std::string mLabel; sh::WorkGroupSize mComputeShaderLocalSize; ShaderMap mAttachedShaders; uint32_t mLocationsUsedForXfbExtension; std::vector mTransformFeedbackVaryingNames; std::vector mUniformLocations; std::vector mBufferVariables; RangeUI mAtomicCounterUniformRange; DrawBufferMask mActiveOutputVariables; // Fragment output variable base types: FLOAT, INT, or UINT. Ordered by location. std::vector mOutputVariableTypes; ComponentTypeMask mDrawBufferTypeMask; // GL_EXT_YUV_target. YUV output shaders can only have one ouput and can only write to YUV // framebuffers. bool mYUVOutput; bool mBinaryRetrieveableHint; bool mSeparable; bool mEarlyFramentTestsOptimization; rx::SpecConstUsageBits mSpecConstUsageBits; // ANGLE_multiview. int mNumViews; // GL_ANGLE_multi_draw int mDrawIDLocation; // GL_ANGLE_base_vertex_base_instance int mBaseVertexLocation; int mBaseInstanceLocation; // Cached value of base vertex and base instance // need to reset them to zero if using non base vertex or base instance draw calls. GLint mCachedBaseVertex; GLuint mCachedBaseInstance; // Note that this has nothing to do with binding layout qualifiers that can be set for some // uniforms in GLES3.1+. It is used to pre-set the location of uniforms. ProgramAliasedBindings mUniformLocationBindings; std::shared_ptr mExecutable; }; struct ProgramVaryingRef { const sh::ShaderVariable *get(ShaderType stage) const { ASSERT(stage == frontShaderStage || stage == backShaderStage); const sh::ShaderVariable *ref = stage == frontShaderStage ? frontShader : backShader; ASSERT(ref); return ref; } const sh::ShaderVariable *frontShader = nullptr; const sh::ShaderVariable *backShader = nullptr; ShaderType frontShaderStage = ShaderType::InvalidEnum; ShaderType backShaderStage = ShaderType::InvalidEnum; }; using ProgramMergedVaryings = std::vector; // TODO: Copy necessary shader state into Program. http://anglebug.com/5506 class HasAttachedShaders { public: virtual Shader *getAttachedShader(ShaderType shaderType) const = 0; ShaderType getTransformFeedbackStage() const; protected: virtual ~HasAttachedShaders() {} }; class Program final : public LabeledObject, public angle::Subject, public HasAttachedShaders { public: Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, ShaderProgramID handle); void onDestroy(const Context *context); ShaderProgramID id() const; void setLabel(const Context *context, const std::string &label) override; const std::string &getLabel() const override; ANGLE_INLINE rx::ProgramImpl *getImplementation() const { ASSERT(!mLinkingState); return mProgram; } void attachShader(Shader *shader); void detachShader(const Context *context, Shader *shader); int getAttachedShadersCount() const; // HasAttachedShaders implementation Shader *getAttachedShader(ShaderType shaderType) const override; void bindAttributeLocation(GLuint index, const char *name); void bindUniformLocation(UniformLocation location, const char *name); // EXT_blend_func_extended void bindFragmentOutputLocation(GLuint index, const char *name); void bindFragmentOutputIndex(GLuint index, const char *name); // KHR_parallel_shader_compile // Try to link the program asynchrously. As a result, background threads may be launched to // execute the linking tasks concurrently. angle::Result link(const Context *context); // Peek whether there is any running linking tasks. bool isLinking() const; bool hasLinkingState() const { return mLinkingState != nullptr; } bool isLinked() const { ASSERT(!mLinkingState); return mLinked; } angle::Result loadBinary(const Context *context, GLenum binaryFormat, const void *binary, GLsizei length); angle::Result saveBinary(Context *context, GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) const; GLint getBinaryLength(Context *context) const; void setBinaryRetrievableHint(bool retrievable); bool getBinaryRetrievableHint() const; void setSeparable(bool separable); bool isSeparable() const; void getAttachedShaders(GLsizei maxCount, GLsizei *count, ShaderProgramID *shaders) const; GLuint getAttributeLocation(const std::string &name) const; void getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const; GLint getActiveAttributeCount() const; GLint getActiveAttributeMaxLength() const; const std::vector &getAttributes() const; GLint getFragDataLocation(const std::string &name) const; size_t getOutputResourceCount() const; const std::vector &getOutputVariableTypes() const; DrawBufferMask getActiveOutputVariables() const { ASSERT(!mLinkingState); return mState.mActiveOutputVariables; } // EXT_blend_func_extended GLint getFragDataIndex(const std::string &name) const; void getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const; GLint getActiveUniformCount() const; size_t getActiveBufferVariableCount() const; GLint getActiveUniformMaxLength() const; bool isValidUniformLocation(UniformLocation location) const; const LinkedUniform &getUniformByLocation(UniformLocation location) const; const VariableLocation &getUniformLocation(UniformLocation location) const; const std::vector &getUniformLocations() const { ASSERT(!mLinkingState); return mState.mUniformLocations; } const LinkedUniform &getUniformByIndex(GLuint index) const { ASSERT(!mLinkingState); return mState.mExecutable->getUniformByIndex(index); } const BufferVariable &getBufferVariableByIndex(GLuint index) const; enum SetUniformResult { SamplerChanged, NoSamplerChange, }; UniformLocation getUniformLocation(const std::string &name) const; GLuint getUniformIndex(const std::string &name) const; void setUniform1fv(UniformLocation location, GLsizei count, const GLfloat *v); void setUniform2fv(UniformLocation location, GLsizei count, const GLfloat *v); void setUniform3fv(UniformLocation location, GLsizei count, const GLfloat *v); void setUniform4fv(UniformLocation location, GLsizei count, const GLfloat *v); void setUniform1iv(Context *context, UniformLocation location, GLsizei count, const GLint *v); void setUniform2iv(UniformLocation location, GLsizei count, const GLint *v); void setUniform3iv(UniformLocation location, GLsizei count, const GLint *v); void setUniform4iv(UniformLocation location, GLsizei count, const GLint *v); void setUniform1uiv(UniformLocation location, GLsizei count, const GLuint *v); void setUniform2uiv(UniformLocation location, GLsizei count, const GLuint *v); void setUniform3uiv(UniformLocation location, GLsizei count, const GLuint *v); void setUniform4uiv(UniformLocation location, GLsizei count, const GLuint *v); void setUniformMatrix2fv(UniformLocation location, GLsizei count, GLboolean transpose, const GLfloat *value); void setUniformMatrix3fv(UniformLocation location, GLsizei count, GLboolean transpose, const GLfloat *value); void setUniformMatrix4fv(UniformLocation location, GLsizei count, GLboolean transpose, const GLfloat *value); void setUniformMatrix2x3fv(UniformLocation location, GLsizei count, GLboolean transpose, const GLfloat *value); void setUniformMatrix3x2fv(UniformLocation location, GLsizei count, GLboolean transpose, const GLfloat *value); void setUniformMatrix2x4fv(UniformLocation location, GLsizei count, GLboolean transpose, const GLfloat *value); void setUniformMatrix4x2fv(UniformLocation location, GLsizei count, GLboolean transpose, const GLfloat *value); void setUniformMatrix3x4fv(UniformLocation location, GLsizei count, GLboolean transpose, const GLfloat *value); void setUniformMatrix4x3fv(UniformLocation location, GLsizei count, GLboolean transpose, const GLfloat *value); void getUniformfv(const Context *context, UniformLocation location, GLfloat *params) const; void getUniformiv(const Context *context, UniformLocation location, GLint *params) const; void getUniformuiv(const Context *context, UniformLocation location, GLuint *params) const; void getActiveUniformBlockName(const UniformBlockIndex blockIndex, GLsizei bufSize, GLsizei *length, GLchar *blockName) const; void getActiveShaderStorageBlockName(const GLuint blockIndex, GLsizei bufSize, GLsizei *length, GLchar *blockName) const; ANGLE_INLINE GLuint getActiveUniformBlockCount() const { ASSERT(!mLinkingState); return static_cast(mState.mExecutable->getActiveUniformBlockCount()); } ANGLE_INLINE GLuint getActiveAtomicCounterBufferCount() const { ASSERT(!mLinkingState); return static_cast(mState.mExecutable->getActiveAtomicCounterBufferCount()); } ANGLE_INLINE GLuint getActiveShaderStorageBlockCount() const { ASSERT(!mLinkingState); return static_cast(mState.mExecutable->getActiveShaderStorageBlockCount()); } GLint getActiveUniformBlockMaxNameLength() const; GLint getActiveShaderStorageBlockMaxNameLength() const; GLuint getUniformBlockIndex(const std::string &name) const; GLuint getShaderStorageBlockIndex(const std::string &name) const; void bindUniformBlock(UniformBlockIndex uniformBlockIndex, GLuint uniformBlockBinding); GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const; GLuint getShaderStorageBlockBinding(GLuint shaderStorageBlockIndex) const; const InterfaceBlock &getUniformBlockByIndex(GLuint index) const; const InterfaceBlock &getShaderStorageBlockByIndex(GLuint index) const; void setTransformFeedbackVaryings(GLsizei count, const GLchar *const *varyings, GLenum bufferMode); void getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const; GLsizei getTransformFeedbackVaryingCount() const; GLsizei getTransformFeedbackVaryingMaxLength() const; GLenum getTransformFeedbackBufferMode() const; GLuint getTransformFeedbackVaryingResourceIndex(const GLchar *name) const; const TransformFeedbackVarying &getTransformFeedbackVaryingResource(GLuint index) const; bool hasDrawIDUniform() const; void setDrawIDUniform(GLint drawid); bool hasBaseVertexUniform() const; void setBaseVertexUniform(GLint baseVertex); bool hasBaseInstanceUniform() const; void setBaseInstanceUniform(GLuint baseInstance); ANGLE_INLINE void addRef() { ASSERT(!mLinkingState); mRefCount++; } ANGLE_INLINE void release(const Context *context) { ASSERT(!mLinkingState); mRefCount--; if (mRefCount == 0 && mDeleteStatus) { deleteSelf(context); } } unsigned int getRefCount() const; bool isInUse() const { return getRefCount() != 0; } void flagForDeletion(); bool isFlaggedForDeletion() const; void validate(const Caps &caps); bool isValidated() const; const std::vector &getImageBindings() const { ASSERT(!mLinkingState); return getExecutable().getImageBindings(); } const sh::WorkGroupSize &getComputeShaderLocalSize() const; PrimitiveMode getGeometryShaderInputPrimitiveType() const; PrimitiveMode getGeometryShaderOutputPrimitiveType() const; GLint getGeometryShaderInvocations() const; GLint getGeometryShaderMaxVertices() const; GLint getTessControlShaderVertices() const; GLenum getTessGenMode() const; GLenum getTessGenPointMode() const; GLenum getTessGenSpacing() const; GLenum getTessGenVertexOrder() const; const ProgramState &getState() const { ASSERT(!mLinkingState); return mState; } GLuint getInputResourceIndex(const GLchar *name) const; GLuint getOutputResourceIndex(const GLchar *name) const; void getInputResourceName(GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) const; void getOutputResourceName(GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) const; void getUniformResourceName(GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) const; void getBufferVariableResourceName(GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) const; const sh::ShaderVariable &getInputResource(size_t index) const; GLuint getResourceMaxNameSize(const sh::ShaderVariable &resource, GLint max) const; GLuint getInputResourceMaxNameSize() const; GLuint getOutputResourceMaxNameSize() const; GLuint getResourceLocation(const GLchar *name, const sh::ShaderVariable &variable) const; GLuint getInputResourceLocation(const GLchar *name) const; GLuint getOutputResourceLocation(const GLchar *name) const; const std::string getResourceName(const sh::ShaderVariable &resource) const; const std::string getInputResourceName(GLuint index) const; const std::string getOutputResourceName(GLuint index) const; const sh::ShaderVariable &getOutputResource(size_t index) const; const ProgramBindings &getAttributeBindings() const; const ProgramAliasedBindings &getUniformLocationBindings() const; const ProgramAliasedBindings &getFragmentOutputLocations() const; const ProgramAliasedBindings &getFragmentOutputIndexes() const; int getNumViews() const { ASSERT(!mLinkingState); return mState.getNumViews(); } bool usesMultiview() const { return mState.usesMultiview(); } ComponentTypeMask getDrawBufferTypeMask() const; bool isYUVOutput() const { ASSERT(!mLinkingState); return mState.isYUVOutput(); } const std::vector &getTransformFeedbackStrides() const; // Program dirty bits. enum DirtyBitType { DIRTY_BIT_UNIFORM_BLOCK_BINDING_0, DIRTY_BIT_UNIFORM_BLOCK_BINDING_MAX = DIRTY_BIT_UNIFORM_BLOCK_BINDING_0 + IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS, DIRTY_BIT_COUNT = DIRTY_BIT_UNIFORM_BLOCK_BINDING_MAX, }; using DirtyBits = angle::BitSet; angle::Result syncState(const Context *context); // Try to resolve linking. Inlined to make sure its overhead is as low as possible. void resolveLink(const Context *context) { if (mLinkingState) { resolveLinkImpl(context); } } ANGLE_INLINE bool hasAnyDirtyBit() const { return mDirtyBits.any(); } // Writes a program's binary to the output memory buffer. angle::Result serialize(const Context *context, angle::MemoryBuffer *binaryOut) const; rx::Serial serial() const { return mSerial; } const ProgramExecutable &getExecutable() const { return mState.getExecutable(); } ProgramExecutable &getExecutable() { return mState.getExecutable(); } private: struct LinkingState; ~Program() override; // Loads program state according to the specified binary blob. angle::Result deserialize(const Context *context, BinaryInputStream &stream, InfoLog &infoLog); void unlink(); void deleteSelf(const Context *context); angle::Result linkImpl(const Context *context); bool linkValidateShaders(InfoLog &infoLog); bool linkAttributes(const Context *context, InfoLog &infoLog); bool linkInterfaceBlocks(const Caps &caps, const Version &version, bool webglCompatibility, InfoLog &infoLog, GLuint *combinedShaderStorageBlocksCount); bool linkVaryings(InfoLog &infoLog) const; bool linkUniforms(const Caps &caps, const Version &version, InfoLog &infoLog, const ProgramAliasedBindings &uniformLocationBindings, GLuint *combinedImageUniformsCount, std::vector *unusedUniforms); void linkSamplerAndImageBindings(GLuint *combinedImageUniformsCount); bool linkAtomicCounterBuffers(); void updateLinkedShaderStages(); int getOutputLocationForLink(const sh::ShaderVariable &outputVariable) const; bool isOutputSecondaryForLink(const sh::ShaderVariable &outputVariable) const; bool linkOutputVariables(const Caps &caps, const Extensions &extensions, const Version &version, GLuint combinedImageUniformsCount, GLuint combinedShaderStorageBlocksCount); void setUniformValuesFromBindingQualifiers(); bool shouldIgnoreUniform(UniformLocation location) const; void initInterfaceBlockBindings(); // Both these function update the cached uniform values and return a modified "count" // so that the uniform update doesn't overflow the uniform. template GLsizei clampUniformCount(const VariableLocation &locationInfo, GLsizei count, int vectorSize, const T *v); template GLsizei clampMatrixUniformCount(UniformLocation location, GLsizei count, GLboolean transpose, const T *v); void updateSamplerUniform(Context *context, const VariableLocation &locationInfo, GLsizei clampedCount, const GLint *v); template void getUniformInternal(const Context *context, DestT *dataOut, UniformLocation location, GLenum nativeType, int components) const; void getResourceName(const std::string name, GLsizei bufSize, GLsizei *length, GLchar *dest) const; template GLint getActiveInterfaceBlockMaxNameLength(const std::vector &resources) const; GLuint getSamplerUniformBinding(const VariableLocation &uniformLocation) const; GLuint getImageUniformBinding(const VariableLocation &uniformLocation) const; // Block until linking is finished and resolve it. void resolveLinkImpl(const gl::Context *context); void postResolveLink(const gl::Context *context); rx::Serial mSerial; ProgramState mState; rx::ProgramImpl *mProgram; bool mValidated; ProgramBindings mAttributeBindings; // EXT_blend_func_extended ProgramAliasedBindings mFragmentOutputLocations; ProgramAliasedBindings mFragmentOutputIndexes; bool mLinked; std::unique_ptr mLinkingState; bool mDeleteStatus; // Flag to indicate that the program can be deleted when no longer in use unsigned int mRefCount; ShaderProgramManager *mResourceManager; const ShaderProgramID mHandle; DirtyBits mDirtyBits; }; } // namespace gl #endif // LIBANGLE_PROGRAM_H_