Edit

kc3-lang/angle/src/libANGLE/Program.h

Branch :

  • Show log

    Commit

  • Author : Shahbaz Youssefi
    Date : 2019-06-03 10:40:10
    Hash : 0bfa5504
    Message : Vulkan: Emulate Transform Feedback with vertex shader output In ES 3.0 and 3.1, only non-indexed GL_POINTS, GL_LINES and GL_TRIANGLES is supported for transform feedback. Without tessellation and geometry shaders, we can calculate the exact location where each vertex transform output should be written on the CPU, and have each vertex shader invocation write its data separately to the appropriate location in the buffer. This depends on the vertexPipelineStoresAndAtomics Vulkan feature. Bug: angleproject:3205 Change-Id: I68ccbb80aece597cf20c557a0aee842360fea593 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1645678 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org>

  • src/libANGLE/Program.h
  • //
    // Copyright (c) 2002-2014 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 <GLES2/gl2.h>
    #include <GLSLANG/ShaderVars.h>
    
    #include <array>
    #include <map>
    #include <set>
    #include <sstream>
    #include <string>
    #include <vector>
    
    #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/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;
    struct Caps;
    class Context;
    struct Extensions;
    class Framebuffer;
    class InfoLog;
    class Shader;
    class ShaderProgramManager;
    class State;
    struct UnusedUniform;
    struct Version;
    
    extern const char *const g_fakepath;
    
    enum class LinkMismatchError
    {
        // Shared
        NO_MISMATCH,
        TYPE_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,
    
        // Interface block specific
        LAYOUT_QUALIFIER_MISMATCH,
        MATRIX_PACKING_MISMATCH
    };
    
    class InfoLog : angle::NonCopyable
    {
      public:
        InfoLog();
        ~InfoLog();
    
        size_t getLength() const;
        void getLog(GLsizei bufSize, GLsizei *length, char *infoLog) const;
    
        void appendSanitized(const char *message);
        void reset();
    
        // This helper class ensures we append a newline after writing a line.
        class StreamHelper : angle::NonCopyable
        {
          public:
            StreamHelper(StreamHelper &&rhs) : mStream(rhs.mStream) { rhs.mStream = nullptr; }
    
            StreamHelper &operator=(StreamHelper &&rhs)
            {
                std::swap(mStream, rhs.mStream);
                return *this;
            }
    
            ~StreamHelper()
            {
                // Write newline when destroyed on the stack
                if (mStream)
                {
                    (*mStream) << std::endl;
                }
            }
    
            template <typename T>
            StreamHelper &operator<<(const T &value)
            {
                (*mStream) << value;
                return *this;
            }
    
          private:
            friend class InfoLog;
    
            StreamHelper(std::stringstream *stream) : mStream(stream) { ASSERT(stream); }
    
            std::stringstream *mStream;
        };
    
        template <typename T>
        StreamHelper operator<<(const T &value)
        {
            ensureInitialized();
            StreamHelper helper(mLazyStream.get());
            helper << value;
            return helper;
        }
    
        std::string str() const { return mLazyStream ? mLazyStream->str() : ""; }
    
        bool empty() const;
    
      private:
        void ensureInitialized()
        {
            if (!mLazyStream)
            {
                mLazyStream.reset(new std::stringstream());
            }
        }
    
        std::unique_ptr<std::stringstream> mLazyStream;
    };
    
    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);
    
    // 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;
    };
    
    // This small structure encapsulates binding sampler uniforms to active GL textures.
    struct SamplerBinding
    {
        SamplerBinding(TextureType textureTypeIn,
                       SamplerFormat formatIn,
                       size_t elementCount,
                       bool unreferenced);
        SamplerBinding(const SamplerBinding &other);
        ~SamplerBinding();
    
        // Necessary for retrieving active textures from the GL state.
        TextureType textureType;
    
        SamplerFormat format;
    
        // List of all textures bound to this sampler, of type textureType.
        std::vector<GLuint> boundTextureUnits;
    
        // A note if this sampler is an unreferenced uniform.
        bool unreferenced;
    };
    
    // A varying with tranform feedback enabled. If it's an array, either the whole array or one of its
    // elements specified by 'arrayIndex' can set to be enabled.
    struct TransformFeedbackVarying : public sh::Varying
    {
        TransformFeedbackVarying(const sh::Varying &varyingIn, GLuint index)
            : sh::Varying(varyingIn), arrayIndex(index)
        {
            ASSERT(!isArrayOfArrays());
        }
    
        TransformFeedbackVarying(const sh::ShaderVariable &field, const sh::Varying &parent)
            : arrayIndex(GL_INVALID_INDEX)
        {
            sh::ShaderVariable *thisVar = this;
            *thisVar                    = field;
            interpolation               = parent.interpolation;
            isInvariant                 = parent.isInvariant;
            name                        = parent.name + "." + name;
            mappedName                  = parent.mappedName + "." + mappedName;
        }
    
        std::string nameWithArrayIndex() const
        {
            std::stringstream fullNameStr;
            fullNameStr << name;
            if (arrayIndex != GL_INVALID_INDEX)
            {
                fullNameStr << "[" << arrayIndex << "]";
            }
            return fullNameStr.str();
        }
        GLsizei size() const
        {
            return (isArray() && arrayIndex == GL_INVALID_INDEX ? getOutermostArraySize() : 1);
        }
    
        GLuint arrayIndex;
    };
    
    struct ImageBinding
    {
        ImageBinding(size_t count);
        ImageBinding(GLuint imageUnit, size_t count, bool unreferenced);
        ImageBinding(const ImageBinding &other);
        ~ImageBinding();
    
        std::vector<GLuint> boundImageUnits;
    
        // A note if this image unit is an unreferenced uniform.
        bool unreferenced;
    };
    
    class ProgramState final : angle::NonCopyable
    {
      public:
        ProgramState();
        ~ProgramState();
    
        const std::string &getLabel();
    
        Shader *getAttachedShader(ShaderType shaderType) const;
        const gl::ShaderMap<Shader *> &getAttachedShaders() const { return mAttachedShaders; }
        const std::vector<std::string> &getTransformFeedbackVaryingNames() const
        {
            return mTransformFeedbackVaryingNames;
        }
        GLint getTransformFeedbackBufferMode() const { return mTransformFeedbackBufferMode; }
        GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const
        {
            ASSERT(uniformBlockIndex < mUniformBlocks.size());
            return mUniformBlocks[uniformBlockIndex].binding;
        }
        GLuint getShaderStorageBlockBinding(GLuint blockIndex) const
        {
            ASSERT(blockIndex < mShaderStorageBlocks.size());
            return mShaderStorageBlocks[blockIndex].binding;
        }
        const UniformBlockBindingMask &getActiveUniformBlockBindingsMask() const
        {
            return mActiveUniformBlockBindings;
        }
        const std::vector<sh::Attribute> &getAttributes() const { return mAttributes; }
        const AttributesMask &getActiveAttribLocationsMask() const
        {
            return mActiveAttribLocationsMask;
        }
        unsigned int getMaxActiveAttribLocation() const { return mMaxActiveAttribLocation; }
        DrawBufferMask getActiveOutputVariables() const { return mActiveOutputVariables; }
        const std::vector<sh::OutputVariable> &getOutputVariables() const { return mOutputVariables; }
        const std::vector<VariableLocation> &getOutputLocations() const { return mOutputLocations; }
        const std::vector<VariableLocation> &getSecondaryOutputLocations() const
        {
            return mSecondaryOutputLocations;
        }
        const std::vector<LinkedUniform> &getUniforms() const { return mUniforms; }
        const std::vector<VariableLocation> &getUniformLocations() const { return mUniformLocations; }
        const std::vector<InterfaceBlock> &getUniformBlocks() const { return mUniformBlocks; }
        const std::vector<InterfaceBlock> &getShaderStorageBlocks() const
        {
            return mShaderStorageBlocks;
        }
        const std::vector<BufferVariable> &getBufferVariables() const { return mBufferVariables; }
        const std::vector<SamplerBinding> &getSamplerBindings() const { return mSamplerBindings; }
        const std::vector<ImageBinding> &getImageBindings() const { return mImageBindings; }
        const sh::WorkGroupSize &getComputeShaderLocalSize() const { return mComputeShaderLocalSize; }
        const RangeUI &getSamplerUniformRange() const { return mSamplerUniformRange; }
        const RangeUI &getImageUniformRange() const { return mImageUniformRange; }
        const RangeUI &getAtomicCounterUniformRange() const { return mAtomicCounterUniformRange; }
    
        const std::vector<TransformFeedbackVarying> &getLinkedTransformFeedbackVaryings() const
        {
            return mLinkedTransformFeedbackVaryings;
        }
        const std::vector<GLsizei> &getTransformFeedbackStrides() const
        {
            return mTransformFeedbackStrides;
        }
        size_t getTransformFeedbackBufferCount() const { return mTransformFeedbackStrides.size(); }
        const std::vector<AtomicCounterBuffer> &getAtomicCounterBuffers() const
        {
            return mAtomicCounterBuffers;
        }
    
        GLuint getUniformIndexFromName(const std::string &name) const;
        GLuint getUniformIndexFromLocation(GLint location) const;
        Optional<GLuint> getSamplerIndex(GLint location) const;
        bool isSamplerUniformIndex(GLuint index) const;
        GLuint getSamplerIndexFromUniformIndex(GLuint uniformIndex) 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; }
    
        const ShaderBitSet &getLinkedShaderStages() const { return mLinkedShaderStages; }
    
        bool hasAttachedShader() const;
    
        const ActiveTextureMask &getActiveSamplersMask() const { return mActiveSamplersMask; }
        SamplerFormat getSamplerFormatForTextureUnitIndex(size_t textureUnitIndex) const
        {
            return mActiveSamplerFormats[textureUnitIndex];
        }
    
      private:
        friend class MemoryProgramCache;
        friend class Program;
    
        void updateTransformFeedbackStrides();
        void updateActiveSamplers();
        void updateActiveImages();
    
        // Scans the sampler bindings for type conflicts with sampler 'textureUnitIndex'.
        void setSamplerUniformTextureTypeAndFormat(size_t textureUnitIndex);
    
        std::string mLabel;
    
        sh::WorkGroupSize mComputeShaderLocalSize;
    
        ShaderMap<Shader *> mAttachedShaders;
    
        std::vector<std::string> mTransformFeedbackVaryingNames;
        std::vector<TransformFeedbackVarying> mLinkedTransformFeedbackVaryings;
        GLenum mTransformFeedbackBufferMode;
    
        // For faster iteration on the blocks currently being bound.
        UniformBlockBindingMask mActiveUniformBlockBindings;
    
        std::vector<sh::Attribute> mAttributes;
        angle::BitSet<MAX_VERTEX_ATTRIBS> mActiveAttribLocationsMask;
        unsigned int mMaxActiveAttribLocation;
        ComponentTypeMask mAttributesTypeMask;
        // mAttributesMask is identical to mActiveAttribLocationsMask with built-in attributes removed.
        AttributesMask mAttributesMask;
    
        // Uniforms are sorted in order:
        //  1. Non-opaque uniforms
        //  2. Sampler uniforms
        //  3. Image uniforms
        //  4. Atomic counter uniforms
        //  5. Uniform block uniforms
        // This makes opaque uniform validation easier, since we don't need a separate list.
        // For generating the entries and naming them we follow the spec: GLES 3.1 November 2016 section
        // 7.3.1.1 Naming Active Resources. There's a separate entry for each struct member and each
        // inner array of an array of arrays. Names and mapped names of uniforms that are arrays include
        // [0] in the end. This makes implementation of queries simpler.
        std::vector<LinkedUniform> mUniforms;
    
        std::vector<VariableLocation> mUniformLocations;
        std::vector<InterfaceBlock> mUniformBlocks;
        std::vector<BufferVariable> mBufferVariables;
        std::vector<InterfaceBlock> mShaderStorageBlocks;
        std::vector<AtomicCounterBuffer> mAtomicCounterBuffers;
        RangeUI mSamplerUniformRange;
        RangeUI mImageUniformRange;
        RangeUI mAtomicCounterUniformRange;
    
        // An array of the samplers that are used by the program
        std::vector<SamplerBinding> mSamplerBindings;
    
        // An array of the images that are used by the program
        std::vector<ImageBinding> mImageBindings;
    
        // Names and mapped names of output variables that are arrays include [0] in the end, similarly
        // to uniforms.
        std::vector<sh::OutputVariable> mOutputVariables;
        std::vector<VariableLocation> mOutputLocations;
    
        // EXT_blend_func_extended secondary outputs (ones with index 1) in ESSL 3.00 shaders.
        std::vector<VariableLocation> mSecondaryOutputLocations;
    
        DrawBufferMask mActiveOutputVariables;
    
        // Fragment output variable base types: FLOAT, INT, or UINT.  Ordered by location.
        std::vector<GLenum> mOutputVariableTypes;
        ComponentTypeMask mDrawBufferTypeMask;
    
        bool mBinaryRetrieveableHint;
        bool mSeparable;
        ShaderBitSet mLinkedShaderStages;
    
        // ANGLE_multiview.
        int mNumViews;
    
        // GL_EXT_geometry_shader.
        PrimitiveMode mGeometryShaderInputPrimitiveType;
        PrimitiveMode mGeometryShaderOutputPrimitiveType;
        int mGeometryShaderInvocations;
        int mGeometryShaderMaxVertices;
    
        // GL_ANGLE_multi_draw
        int mDrawIDLocation;
    
        // The size of the data written to each transform feedback buffer per vertex.
        std::vector<GLsizei> mTransformFeedbackStrides;
    
        // Cached mask of active samplers and sampler types.
        ActiveTextureMask mActiveSamplersMask;
        ActiveTextureArray<uint32_t> mActiveSamplerRefCounts;
        ActiveTextureArray<TextureType> mActiveSamplerTypes;
        ActiveTextureArray<SamplerFormat> mActiveSamplerFormats;
    
        // Cached mask of active images.
        ActiveTextureMask mActiveImagesMask;
    };
    
    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::VariableWithLocation &variable) const;
    
        using const_iterator = std::unordered_map<std::string, ProgramBinding>::const_iterator;
        const_iterator begin() const;
        const_iterator end() const;
    
      private:
        std::unordered_map<std::string, ProgramBinding> mBindings;
    };
    
    struct ProgramVaryingRef
    {
        const sh::Varying *get() const { return vertex ? vertex : fragment; }
    
        const sh::Varying *vertex   = nullptr;
        const sh::Varying *fragment = nullptr;
    };
    
    using ProgramMergedVaryings = std::map<std::string, ProgramVaryingRef>;
    
    class Program final : angle::NonCopyable, public LabeledObject
    {
      public:
        Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, GLuint handle);
        void onDestroy(const Context *context);
    
        GLuint 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(mLinkResolved);
            return mProgram;
        }
    
        void attachShader(Shader *shader);
        void detachShader(const Context *context, Shader *shader);
        int getAttachedShadersCount() const;
    
        const Shader *getAttachedShader(ShaderType shaderType) const;
    
        void bindAttributeLocation(GLuint index, const char *name);
        void bindUniformLocation(GLuint index, const char *name);
    
        // CHROMIUM_path_rendering
        BindingInfo getFragmentInputBindingInfo(GLint index) const;
        void bindFragmentInputLocation(GLint index, const char *name);
        void pathFragmentInputGen(GLint index, GLenum genMode, GLint components, const GLfloat *coeffs);
    
        // 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 isLinked() const
        {
            ASSERT(mLinkResolved);
            return mLinked;
        }
    
        bool hasLinkedShaderStage(ShaderType shaderType) const
        {
            ASSERT(shaderType != ShaderType::InvalidEnum);
            return mState.mLinkedShaderStages[shaderType];
        }
    
        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;
    
        int getInfoLogLength() const;
        void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const;
        void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders) const;
    
        GLuint getAttributeLocation(const std::string &name) const;
        bool isAttribLocationActive(size_t attribLocation) 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<sh::Attribute> &getAttributes() const;
    
        GLint getFragDataLocation(const std::string &name) const;
        size_t getOutputResourceCount() const;
        const std::vector<GLenum> &getOutputVariableTypes() const;
        DrawBufferMask getActiveOutputVariables() const
        {
            ASSERT(mLinkResolved);
            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(GLint location) const;
        const LinkedUniform &getUniformByLocation(GLint location) const;
        const VariableLocation &getUniformLocation(GLint location) const;
    
        const std::vector<VariableLocation> &getUniformLocations() const
        {
            ASSERT(mLinkResolved);
            return mState.mUniformLocations;
        }
    
        const LinkedUniform &getUniformByIndex(GLuint index) const
        {
            ASSERT(mLinkResolved);
            ASSERT(index < static_cast<size_t>(mState.mUniforms.size()));
            return mState.mUniforms[index];
        }
    
        const BufferVariable &getBufferVariableByIndex(GLuint index) const;
    
        enum SetUniformResult
        {
            SamplerChanged,
            NoSamplerChange,
        };
    
        GLint getUniformLocation(const std::string &name) const;
        GLuint getUniformIndex(const std::string &name) const;
        void setUniform1fv(GLint location, GLsizei count, const GLfloat *v);
        void setUniform2fv(GLint location, GLsizei count, const GLfloat *v);
        void setUniform3fv(GLint location, GLsizei count, const GLfloat *v);
        void setUniform4fv(GLint location, GLsizei count, const GLfloat *v);
        void setUniform1iv(Context *context, GLint location, GLsizei count, const GLint *v);
        void setUniform2iv(GLint location, GLsizei count, const GLint *v);
        void setUniform3iv(GLint location, GLsizei count, const GLint *v);
        void setUniform4iv(GLint location, GLsizei count, const GLint *v);
        void setUniform1uiv(GLint location, GLsizei count, const GLuint *v);
        void setUniform2uiv(GLint location, GLsizei count, const GLuint *v);
        void setUniform3uiv(GLint location, GLsizei count, const GLuint *v);
        void setUniform4uiv(GLint location, GLsizei count, const GLuint *v);
        void setUniformMatrix2fv(GLint location,
                                 GLsizei count,
                                 GLboolean transpose,
                                 const GLfloat *value);
        void setUniformMatrix3fv(GLint location,
                                 GLsizei count,
                                 GLboolean transpose,
                                 const GLfloat *value);
        void setUniformMatrix4fv(GLint location,
                                 GLsizei count,
                                 GLboolean transpose,
                                 const GLfloat *value);
        void setUniformMatrix2x3fv(GLint location,
                                   GLsizei count,
                                   GLboolean transpose,
                                   const GLfloat *value);
        void setUniformMatrix3x2fv(GLint location,
                                   GLsizei count,
                                   GLboolean transpose,
                                   const GLfloat *value);
        void setUniformMatrix2x4fv(GLint location,
                                   GLsizei count,
                                   GLboolean transpose,
                                   const GLfloat *value);
        void setUniformMatrix4x2fv(GLint location,
                                   GLsizei count,
                                   GLboolean transpose,
                                   const GLfloat *value);
        void setUniformMatrix3x4fv(GLint location,
                                   GLsizei count,
                                   GLboolean transpose,
                                   const GLfloat *value);
        void setUniformMatrix4x3fv(GLint location,
                                   GLsizei count,
                                   GLboolean transpose,
                                   const GLfloat *value);
    
        void getUniformfv(const Context *context, GLint location, GLfloat *params) const;
        void getUniformiv(const Context *context, GLint location, GLint *params) const;
        void getUniformuiv(const Context *context, GLint location, GLuint *params) const;
    
        void getActiveUniformBlockName(const GLuint 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(mLinkResolved);
            return static_cast<GLuint>(mState.mUniformBlocks.size());
        }
    
        ANGLE_INLINE GLuint getActiveAtomicCounterBufferCount() const
        {
            ASSERT(mLinkResolved);
            return static_cast<GLuint>(mState.mAtomicCounterBuffers.size());
        }
    
        ANGLE_INLINE GLuint getActiveShaderStorageBlockCount() const
        {
            ASSERT(mLinkResolved);
            return static_cast<GLuint>(mState.mShaderStorageBlocks.size());
        }
    
        GLint getActiveUniformBlockMaxNameLength() const;
        GLint getActiveShaderStorageBlockMaxNameLength() const;
    
        GLuint getUniformBlockIndex(const std::string &name) const;
        GLuint getShaderStorageBlockIndex(const std::string &name) const;
    
        void bindUniformBlock(GLuint 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);
    
        ANGLE_INLINE void addRef()
        {
            ASSERT(mLinkResolved);
            mRefCount++;
        }
    
        ANGLE_INLINE void release(const Context *context)
        {
            ASSERT(mLinkResolved);
            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 validateSamplers(InfoLog *infoLog, const Caps &caps)
        {
            // Skip cache if we're using an infolog, so we get the full error.
            // Also skip the cache if the sample mapping has changed, or if we haven't ever validated.
            if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
            {
                return mCachedValidateSamplersResult.value();
            }
    
            return validateSamplersImpl(infoLog, caps);
        }
    
        bool isValidated() const;
    
        const AttributesMask &getActiveAttribLocationsMask() const
        {
            ASSERT(mLinkResolved);
            return mState.mActiveAttribLocationsMask;
        }
    
        const std::vector<SamplerBinding> &getSamplerBindings() const;
        const std::vector<ImageBinding> &getImageBindings() const
        {
            ASSERT(mLinkResolved);
            return mState.mImageBindings;
        }
        const sh::WorkGroupSize &getComputeShaderLocalSize() const;
        PrimitiveMode getGeometryShaderInputPrimitiveType() const;
        PrimitiveMode getGeometryShaderOutputPrimitiveType() const;
        GLint getGeometryShaderInvocations() const;
        GLint getGeometryShaderMaxVertices() const;
    
        const ProgramState &getState() const
        {
            ASSERT(mLinkResolved);
            return mState;
        }
    
        static LinkMismatchError LinkValidateVariablesBase(
            const sh::ShaderVariable &variable1,
            const sh::ShaderVariable &variable2,
            bool validatePrecision,
            bool validateArraySize,
            std::string *mismatchedStructOrBlockMemberName);
    
        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::Attribute &getInputResource(GLuint index) const;
        const sh::OutputVariable &getOutputResource(GLuint index) const;
    
        const ProgramBindings &getAttributeBindings() const;
        const ProgramBindings &getUniformLocationBindings() const;
        const ProgramBindings &getFragmentInputBindings() const;
    
        int getNumViews() const
        {
            ASSERT(mLinkResolved);
            return mState.getNumViews();
        }
    
        bool usesMultiview() const { return mState.usesMultiview(); }
    
        ComponentTypeMask getDrawBufferTypeMask() const;
        ComponentTypeMask getAttributesTypeMask() const;
        AttributesMask getAttributesMask() const;
    
        const std::vector<GLsizei> &getTransformFeedbackStrides() const;
    
        const ActiveTextureMask &getActiveSamplersMask() const { return mState.mActiveSamplersMask; }
        const ActiveTextureMask &getActiveImagesMask() const { return mState.mActiveImagesMask; }
    
        const ActiveTextureArray<TextureType> &getActiveSamplerTypes() const
        {
            return mState.mActiveSamplerTypes;
        }
    
        // 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<DIRTY_BIT_COUNT>;
    
        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 (!mLinkResolved)
            {
                resolveLinkImpl(context);
            }
        }
    
        ANGLE_INLINE bool hasAnyDirtyBit() const { return mDirtyBits.any(); }
    
        // Writes a program's binary to the output memory buffer.
        void serialize(const Context *context, angle::MemoryBuffer *binaryOut) const;
    
      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);
    
        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,
                          InfoLog &infoLog,
                          const ProgramBindings &uniformLocationBindings,
                          GLuint *combinedImageUniformsCount,
                          std::vector<UnusedUniform> *unusedUniforms);
        void linkSamplerAndImageBindings(GLuint *combinedImageUniformsCount);
        bool linkAtomicCounterBuffers();
    
        void updateLinkedShaderStages();
    
        static LinkMismatchError LinkValidateVaryings(const sh::Varying &outputVarying,
                                                      const sh::Varying &inputVarying,
                                                      int shaderVersion,
                                                      bool validateGeometryShaderInputVarying,
                                                      std::string *mismatchedStructFieldName);
    
        bool linkValidateShaderInterfaceMatching(Shader *generatingShader,
                                                 Shader *consumingShader,
                                                 InfoLog &infoLog) const;
    
        // Check for aliased path rendering input bindings (if any).
        // If more than one binding refer statically to the same location the link must fail.
        bool linkValidateFragmentInputBindings(InfoLog &infoLog) const;
    
        bool linkValidateBuiltInVaryings(InfoLog &infoLog) const;
        bool linkValidateTransformFeedback(const Version &version,
                                           InfoLog &infoLog,
                                           const ProgramMergedVaryings &linkedVaryings,
                                           const Caps &caps) const;
        bool linkValidateGlobalNames(InfoLog &infoLog) const;
    
        void gatherTransformFeedbackVaryings(const ProgramMergedVaryings &varyings);
    
        ProgramMergedVaryings getMergedVaryings() const;
        int getOutputLocationForLink(const sh::OutputVariable &outputVariable) const;
        bool isOutputSecondaryForLink(const sh::OutputVariable &outputVariable) const;
        bool linkOutputVariables(const Caps &caps,
                                 const Extensions &extensions,
                                 const Version &version,
                                 GLuint combinedImageUniformsCount,
                                 GLuint combinedShaderStorageBlocksCount);
    
        void setUniformValuesFromBindingQualifiers();
    
        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 <typename T>
        GLsizei clampUniformCount(const VariableLocation &locationInfo,
                                  GLsizei count,
                                  int vectorSize,
                                  const T *v);
        template <size_t cols, size_t rows, typename T>
        GLsizei clampMatrixUniformCount(GLint location, GLsizei count, GLboolean transpose, const T *v);
    
        void updateSamplerUniform(Context *context,
                                  const VariableLocation &locationInfo,
                                  GLsizei clampedCount,
                                  const GLint *v);
    
        template <typename DestT>
        void getUniformInternal(const Context *context,
                                DestT *dataOut,
                                GLint location,
                                GLenum nativeType,
                                int components) const;
    
        template <typename T>
        void getResourceName(GLuint index,
                             const std::vector<T> &resources,
                             GLsizei bufSize,
                             GLsizei *length,
                             GLchar *name) const;
    
        template <typename T>
        GLint getActiveInterfaceBlockMaxNameLength(const std::vector<T> &resources) const;
    
        GLuint getSamplerUniformBinding(const VariableLocation &uniformLocation) const;
    
        bool validateSamplersImpl(InfoLog *infoLog, const Caps &caps);
    
        // Block until linking is finished and resolve it.
        void resolveLinkImpl(const gl::Context *context);
    
        void postResolveLink(const gl::Context *context);
    
        ProgramState mState;
        rx::ProgramImpl *mProgram;
    
        bool mValidated;
    
        ProgramBindings mAttributeBindings;
    
        // 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.
        ProgramBindings mUniformLocationBindings;
    
        // CHROMIUM_path_rendering
        ProgramBindings mFragmentInputBindings;
    
        // EXT_blend_func_extended
        ProgramBindings mFragmentOutputLocations;
        ProgramBindings mFragmentOutputIndexes;
    
        bool mLinked;
        bool mLinkResolved;
        std::unique_ptr<LinkingState> mLinkingState;
        bool mDeleteStatus;  // Flag to indicate that the program can be deleted when no longer in use
    
        unsigned int mRefCount;
    
        ShaderProgramManager *mResourceManager;
        const GLuint mHandle;
    
        InfoLog mInfoLog;
    
        // Cache for sampler validation
        Optional<bool> mCachedValidateSamplersResult;
    
        DirtyBits mDirtyBits;
    };
    }  // namespace gl
    
    #endif  // LIBANGLE_PROGRAM_H_