| // |
| // 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; } |
| |
| // "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; |
| } |
| |
| 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<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; |
| }; |
| |
| class ProgramBindings final : angle::NonCopyable |
| { |
| public: |
| ProgramBindings(); |
| ~ProgramBindings(); |
| |
| void bindLocation(GLuint index, const std::string &name); |
| int getBinding(const std::string &name) const; |
| |
| using const_iterator = std::unordered_map<std::string, GLuint>::const_iterator; |
| const_iterator begin() const; |
| const_iterator end() const; |
| |
| private: |
| std::unordered_map<std::string, GLuint> 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 Caps &caps, 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_ |