| // |
| // 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/angleutils.h" |
| #include "common/mathutil.h" |
| #include "common/Optional.h" |
| |
| #include "libANGLE/angletypes.h" |
| #include "libANGLE/Constants.h" |
| #include "libANGLE/Debug.h" |
| #include "libANGLE/Error.h" |
| #include "libANGLE/RefCountObject.h" |
| |
| namespace rx |
| { |
| class GLImplFactory; |
| class ProgramImpl; |
| struct TranslatedAttribute; |
| } |
| |
| namespace gl |
| { |
| struct Caps; |
| class Context; |
| class ContextState; |
| class Shader; |
| class ShaderProgramManager; |
| class State; |
| class InfoLog; |
| class Buffer; |
| class Framebuffer; |
| struct UniformBlock; |
| struct LinkedUniform; |
| struct PackedVarying; |
| |
| extern const char * const g_fakepath; |
| |
| 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) |
| { |
| StreamHelper helper(&mStream); |
| helper << value; |
| return helper; |
| } |
| |
| std::string str() const { return mStream.str(); } |
| |
| private: |
| std::stringstream mStream; |
| }; |
| |
| // Struct used for correlating uniforms/elements of uniform arrays to handles |
| struct VariableLocation |
| { |
| VariableLocation(); |
| VariableLocation(const std::string &name, unsigned int element, unsigned int index); |
| |
| std::string name; |
| unsigned int element; |
| unsigned int index; |
| |
| // If this is a valid uniform location |
| bool used; |
| |
| // 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(GLenum textureTypeIn, size_t elementCount) |
| : textureType(textureTypeIn), boundTextureUnits(elementCount, 0) |
| { |
| } |
| |
| // Necessary for retrieving active textures from the GL state. |
| GLenum textureType; |
| |
| // List of all textures bound to this sampler, of type textureType. |
| std::vector<GLuint> boundTextureUnits; |
| }; |
| |
| // 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) |
| { |
| } |
| std::string nameWithArrayIndex() const |
| { |
| std::stringstream fullNameStr; |
| fullNameStr << name; |
| if (arrayIndex != GL_INVALID_INDEX) |
| { |
| fullNameStr << "[" << arrayIndex << "]"; |
| } |
| return fullNameStr.str(); |
| } |
| GLsizei size() const { return (arrayIndex == GL_INVALID_INDEX ? elementCount() : 1); } |
| |
| GLuint arrayIndex; |
| }; |
| |
| class ProgramState final : angle::NonCopyable |
| { |
| public: |
| ProgramState(); |
| ~ProgramState(); |
| |
| const std::string &getLabel(); |
| |
| const Shader *getAttachedVertexShader() const { return mAttachedVertexShader; } |
| const Shader *getAttachedFragmentShader() const { return mAttachedFragmentShader; } |
| const Shader *getAttachedComputeShader() const { return mAttachedComputeShader; } |
| const std::vector<std::string> &getTransformFeedbackVaryingNames() const |
| { |
| return mTransformFeedbackVaryingNames; |
| } |
| GLint getTransformFeedbackBufferMode() const { return mTransformFeedbackBufferMode; } |
| GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const |
| { |
| ASSERT(uniformBlockIndex < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS); |
| return mUniformBlockBindings[uniformBlockIndex]; |
| } |
| const UniformBlockBindingMask &getActiveUniformBlockBindingsMask() const |
| { |
| return mActiveUniformBlockBindings; |
| } |
| const std::vector<sh::Attribute> &getAttributes() const { return mAttributes; } |
| const AttributesMask &getActiveAttribLocationsMask() const |
| { |
| return mActiveAttribLocationsMask; |
| } |
| const std::map<int, VariableLocation> &getOutputLocations() const { return mOutputLocations; } |
| const std::vector<LinkedUniform> &getUniforms() const { return mUniforms; } |
| const std::vector<VariableLocation> &getUniformLocations() const { return mUniformLocations; } |
| const std::vector<UniformBlock> &getUniformBlocks() const { return mUniformBlocks; } |
| const std::vector<SamplerBinding> &getSamplerBindings() const { return mSamplerBindings; } |
| |
| GLint getUniformLocation(const std::string &name) const; |
| 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; |
| |
| private: |
| friend class Program; |
| |
| std::string mLabel; |
| |
| sh::WorkGroupSize mComputeShaderLocalSize; |
| |
| Shader *mAttachedFragmentShader; |
| Shader *mAttachedVertexShader; |
| Shader *mAttachedComputeShader; |
| |
| std::vector<std::string> mTransformFeedbackVaryingNames; |
| std::vector<TransformFeedbackVarying> mLinkedTransformFeedbackVaryings; |
| GLenum mTransformFeedbackBufferMode; |
| |
| std::array<GLuint, IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS> mUniformBlockBindings; |
| UniformBlockBindingMask mActiveUniformBlockBindings; |
| |
| std::vector<sh::Attribute> mAttributes; |
| angle::BitSet<MAX_VERTEX_ATTRIBS> mActiveAttribLocationsMask; |
| |
| // Uniforms are sorted in order: |
| // 1. Non-sampler uniforms |
| // 2. Sampler uniforms |
| // 3. Uniform block uniforms |
| // This makes sampler validation easier, since we don't need a separate list. |
| std::vector<LinkedUniform> mUniforms; |
| std::vector<VariableLocation> mUniformLocations; |
| std::vector<UniformBlock> mUniformBlocks; |
| RangeUI mSamplerUniformRange; |
| |
| // An array of the samplers that are used by the program |
| std::vector<gl::SamplerBinding> mSamplerBindings; |
| |
| std::vector<sh::OutputVariable> mOutputVariables; |
| // TODO(jmadill): use unordered/hash map when available |
| std::map<int, VariableLocation> mOutputLocations; |
| |
| bool mBinaryRetrieveableHint; |
| bool mSeparable; |
| }; |
| |
| class Program final : angle::NonCopyable, public LabeledObject |
| { |
| public: |
| Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, GLuint handle); |
| ~Program(); |
| void destroy(const Context *context); |
| |
| GLuint id() const { return mHandle; } |
| |
| void setLabel(const std::string &label) override; |
| const std::string &getLabel() const override; |
| |
| rx::ProgramImpl *getImplementation() const { return mProgram; } |
| |
| void attachShader(Shader *shader); |
| void detachShader(const Context *context, Shader *shader); |
| int getAttachedShadersCount() const; |
| |
| const Shader *getAttachedVertexShader() const { return mState.mAttachedVertexShader; } |
| const Shader *getAttachedFragmentShader() const { return mState.mAttachedFragmentShader; } |
| const Shader *getAttachedComputeShader() const { return mState.mAttachedComputeShader; } |
| |
| 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); |
| |
| Error link(const gl::Context *context); |
| bool isLinked() const; |
| |
| Error loadBinary(const Context *context, |
| GLenum binaryFormat, |
| const void *binary, |
| GLsizei length); |
| Error saveBinary(const Context *context, |
| GLenum *binaryFormat, |
| void *binary, |
| GLsizei bufSize, |
| GLsizei *length) const; |
| GLint getBinaryLength() 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 { return mState.mAttributes; } |
| |
| GLint getFragDataLocation(const std::string &name) const; |
| size_t getOutputResourceCount() const; |
| |
| void getActiveUniform(GLuint index, |
| GLsizei bufsize, |
| GLsizei *length, |
| GLint *size, |
| GLenum *type, |
| GLchar *name) const; |
| GLint getActiveUniformCount() const; |
| GLint getActiveUniformMaxLength() const; |
| GLint getActiveUniformi(GLuint index, GLenum pname) const; |
| bool isValidUniformLocation(GLint location) const; |
| const LinkedUniform &getUniformByLocation(GLint location) const; |
| const VariableLocation &getUniformLocation(GLint location) const; |
| const std::vector<VariableLocation> &getUniformLocations() const; |
| const LinkedUniform &getUniformByIndex(GLuint index) const; |
| |
| 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(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(GLint location, GLfloat *params) const; |
| void getUniformiv(GLint location, GLint *params) const; |
| void getUniformuiv(GLint location, GLuint *params) const; |
| |
| void getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const; |
| GLuint getActiveUniformBlockCount() const; |
| GLint getActiveUniformBlockMaxLength() const; |
| |
| GLuint getUniformBlockIndex(const std::string &name) const; |
| |
| void bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding); |
| GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const; |
| |
| const UniformBlock &getUniformBlockByIndex(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; |
| |
| static bool linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform); |
| |
| void addRef(); |
| void release(const Context *context); |
| unsigned int getRefCount() const; |
| void flagForDeletion(); |
| bool isFlaggedForDeletion() const; |
| |
| void validate(const Caps &caps); |
| bool validateSamplers(InfoLog *infoLog, const Caps &caps); |
| bool isValidated() const; |
| bool samplesFromTexture(const gl::State &state, GLuint textureID) const; |
| |
| const AttributesMask &getActiveAttribLocationsMask() const |
| { |
| return mState.mActiveAttribLocationsMask; |
| } |
| |
| const std::vector<SamplerBinding> &getSamplerBindings() const |
| { |
| return mState.mSamplerBindings; |
| } |
| const ProgramState &getState() const { return mState; } |
| |
| static bool linkValidateVariablesBase(InfoLog &infoLog, |
| const std::string &variableName, |
| const sh::ShaderVariable &vertexVariable, |
| const sh::ShaderVariable &fragmentVariable, |
| bool validatePrecision); |
| |
| 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; |
| |
| class Bindings final : angle::NonCopyable |
| { |
| public: |
| void bindLocation(GLuint index, const std::string &name); |
| int getBinding(const std::string &name) const; |
| |
| typedef std::unordered_map<std::string, GLuint>::const_iterator const_iterator; |
| const_iterator begin() const; |
| const_iterator end() const; |
| |
| private: |
| std::unordered_map<std::string, GLuint> mBindings; |
| }; |
| |
| private: |
| struct VaryingRef |
| { |
| const sh::Varying *get() const { return vertex ? vertex : fragment; } |
| |
| const sh::Varying *vertex = nullptr; |
| const sh::Varying *fragment = nullptr; |
| }; |
| |
| using MergedVaryings = std::map<std::string, VaryingRef>; |
| |
| void unlink(); |
| void resetUniformBlockBindings(); |
| |
| bool linkAttributes(const ContextState &data, InfoLog &infoLog); |
| bool validateUniformBlocksCount(GLuint maxUniformBlocks, |
| const std::vector<sh::InterfaceBlock> &block, |
| const std::string &errorMessage, |
| InfoLog &infoLog) const; |
| bool validateVertexAndFragmentInterfaceBlocks( |
| const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks, |
| const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks, |
| InfoLog &infoLog) const; |
| bool linkUniformBlocks(InfoLog &infoLog, const Caps &caps); |
| bool linkVaryings(InfoLog &infoLog) const; |
| |
| bool linkUniforms(InfoLog &infoLog, const Caps &caps, const Bindings &uniformLocationBindings); |
| void linkSamplerBindings(); |
| |
| bool areMatchingInterfaceBlocks(InfoLog &infoLog, |
| const sh::InterfaceBlock &vertexInterfaceBlock, |
| const sh::InterfaceBlock &fragmentInterfaceBlock) const; |
| |
| static bool linkValidateVaryings(InfoLog &infoLog, |
| const std::string &varyingName, |
| const sh::Varying &vertexVarying, |
| const sh::Varying &fragmentVarying, |
| int shaderVersion); |
| bool linkValidateBuiltInVaryings(InfoLog &infoLog) const; |
| bool linkValidateTransformFeedback(const gl::Context *context, |
| InfoLog &infoLog, |
| const MergedVaryings &linkedVaryings, |
| const Caps &caps) const; |
| |
| void gatherTransformFeedbackVaryings(const MergedVaryings &varyings); |
| |
| MergedVaryings getMergedVaryings() const; |
| std::vector<PackedVarying> getPackedVaryings(const MergedVaryings &mergedVaryings) const; |
| void linkOutputVariables(); |
| |
| void setUniformValuesFromBindingQualifiers(); |
| |
| void gatherInterfaceBlockInfo(); |
| template <typename VarT> |
| void defineUniformBlockMembers(const std::vector<VarT> &fields, |
| const std::string &prefix, |
| int blockIndex); |
| |
| void defineUniformBlock(const sh::InterfaceBlock &interfaceBlock, GLenum shaderType); |
| |
| // 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 setUniformInternal(GLint location, GLsizei count, int vectorSize, const T *v); |
| template <size_t cols, size_t rows, typename T> |
| GLsizei setMatrixUniformInternal(GLint location, |
| GLsizei count, |
| GLboolean transpose, |
| const T *v); |
| template <typename T> |
| void updateSamplerUniform(const VariableLocation &locationInfo, |
| const uint8_t *destPointer, |
| GLsizei clampedCount, |
| const T *v); |
| |
| template <typename DestT> |
| void getUniformInternal(GLint location, DestT *dataOut) const; |
| |
| ProgramState mState; |
| rx::ProgramImpl *mProgram; |
| |
| bool mValidated; |
| |
| Bindings 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. |
| Bindings mUniformLocationBindings; |
| |
| // CHROMIUM_path_rendering |
| Bindings mFragmentInputBindings; |
| |
| bool mLinked; |
| 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; |
| std::vector<GLenum> mTextureUnitTypesCache; |
| }; |
| } // namespace gl |
| |
| #endif // LIBANGLE_PROGRAM_H_ |