// // 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 #include #include #include #include #include #include #include #include "common/Optional.h" #include "common/angleutils.h" #include "common/mathutil.h" #include "common/utilities.h" #include "libANGLE/Constants.h" #include "libANGLE/Debug.h" #include "libANGLE/Error.h" #include "libANGLE/RefCountObject.h" #include "libANGLE/Uniform.h" #include "libANGLE/angletypes.h" namespace rx { class GLImplFactory; class ProgramImpl; struct TranslatedAttribute; } // namespace rx namespace gl { class Buffer; class BinaryInputStream; class BinaryOutputStream; struct Caps; class Context; struct Extensions; class Framebuffer; class 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, INSTANCE_NAME_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 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 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 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); void WriteBlockMemberInfo(BinaryOutputStream *stream, const sh::BlockMemberInfo &var); void LoadBlockMemberInfo(BinaryInputStream *stream, sh::BlockMemberInfo *var); // Struct used for correlating uniforms/elements of uniform arrays to handles struct VariableLocation { static constexpr unsigned int kUnused = GL_INVALID_INDEX; VariableLocation(); VariableLocation(unsigned int arrayIndex, unsigned int index); // If used is false, it means this location is only used to fill an empty space in an array, // and there is no corresponding uniform variable for this location. It can also mean the // uniform was optimized out by the implementation. bool used() const { return (index != kUnused); } void markUnused() { index = kUnused; } void markIgnored() { ignored = true; } bool operator==(const VariableLocation &other) const { return arrayIndex == other.arrayIndex && index == other.index; } // "arrayIndex" stores the index of the innermost GLSL array. It's zero for non-arrays. unsigned int arrayIndex; // "index" is an index of the variable. The variable contains the indices for other than the // innermost GLSL arrays. unsigned int index; // If this location was bound to an unreferenced uniform. Setting data on this uniform is a // no-op. bool ignored; }; // Information about a variable binding. // Currently used by CHROMIUM_path_rendering struct BindingInfo { // The type of binding, for example GL_FLOAT_VEC3. // This can be GL_NONE if the variable is optimized away. GLenum type; // This is the name of the variable in // the translated shader program. Note that // this can be empty in the case where the // variable has been optimized away. std::string name; // True if the binding is valid, otherwise false. bool valid; }; // 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 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 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 &getAttachedShaders() const { return mAttachedShaders; } const std::vector &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 &getAttributes() const { return mAttributes; } const AttributesMask &getActiveAttribLocationsMask() const { return mActiveAttribLocationsMask; } const AttributesMask &getNonBuiltinAttribLocationsMask() const { return mAttributesMask; } unsigned int getMaxActiveAttribLocation() const { return mMaxActiveAttribLocation; } DrawBufferMask getActiveOutputVariables() const { return mActiveOutputVariables; } const std::vector &getOutputVariables() const { return mOutputVariables; } const std::vector &getOutputLocations() const { return mOutputLocations; } const std::vector &getSecondaryOutputLocations() const { return mSecondaryOutputLocations; } const std::vector &getUniforms() const { return mUniforms; } const std::vector &getUniformLocations() const { return mUniformLocations; } const std::vector &getUniformBlocks() const { return mUniformBlocks; } const std::vector &getShaderStorageBlocks() const { return mShaderStorageBlocks; } const std::vector &getBufferVariables() const { return mBufferVariables; } const std::vector &getSamplerBindings() const { return mSamplerBindings; } const std::vector &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 ComponentTypeMask &getAttributesTypeMask() const { return mAttributesTypeMask; } const std::vector &getLinkedTransformFeedbackVaryings() const { return mLinkedTransformFeedbackVaryings; } const std::vector &getTransformFeedbackStrides() const { return mTransformFeedbackStrides; } size_t getTransformFeedbackBufferCount() const { return mTransformFeedbackStrides.size(); } const std::vector &getAtomicCounterBuffers() const { return mAtomicCounterBuffers; } // Count the number of uniform and storage buffer declarations, counting arrays as one. size_t getUniqueUniformBlockCount() const; size_t getUniqueStorageBlockCount() const; GLuint getUniformIndexFromName(const std::string &name) const; GLuint getUniformIndexFromLocation(GLint location) const; Optional getSamplerIndex(GLint location) const; bool isSamplerUniformIndex(GLuint index) const; GLuint getSamplerIndexFromUniformIndex(GLuint uniformIndex) const; GLuint getUniformIndexFromSamplerIndex(GLuint samplerIndex) const; bool isImageUniformIndex(GLuint index) const; GLuint getImageIndexFromUniformIndex(GLuint uniformIndex) const; GLuint getUniformIndexFromImageIndex(GLuint imageIndex) 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 hasLinkedShaderStage(ShaderType shaderType) const { return mLinkedShaderStages[shaderType]; } size_t getLinkedShaderStageCount() const { return mLinkedShaderStages.count(); } bool isCompute() const { return hasLinkedShaderStage(ShaderType::Compute); } 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 mAttachedShaders; std::vector mTransformFeedbackVaryingNames; std::vector mLinkedTransformFeedbackVaryings; GLenum mTransformFeedbackBufferMode; // For faster iteration on the blocks currently being bound. UniformBlockBindingMask mActiveUniformBlockBindings; std::vector mAttributes; angle::BitSet 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 mUniforms; std::vector mUniformLocations; std::vector mUniformBlocks; std::vector mBufferVariables; std::vector mShaderStorageBlocks; std::vector mAtomicCounterBuffers; RangeUI mSamplerUniformRange; RangeUI mImageUniformRange; RangeUI mAtomicCounterUniformRange; // An array of the samplers that are used by the program std::vector mSamplerBindings; // An array of the images that are used by the program std::vector mImageBindings; // Names and mapped names of output variables that are arrays include [0] in the end, similarly // to uniforms. std::vector mOutputVariables; std::vector mOutputLocations; // EXT_blend_func_extended secondary outputs (ones with index 1) in ESSL 3.00 shaders. std::vector mSecondaryOutputLocations; DrawBufferMask mActiveOutputVariables; // Fragment output variable base types: FLOAT, INT, or UINT. Ordered by location. std::vector 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 mTransformFeedbackStrides; // Cached mask of active samplers and sampler types. ActiveTextureMask mActiveSamplersMask; ActiveTextureArray mActiveSamplerRefCounts; ActiveTextureArray mActiveSamplerTypes; ActiveTextureArray 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::const_iterator; const_iterator begin() const; const_iterator end() const; private: std::unordered_map 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; 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.hasLinkedShaderStage(shaderType); } bool isCompute() const { return mState.isCompute(); } 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 &getAttributes() const; GLint getFragDataLocation(const std::string &name) const; size_t getOutputResourceCount() const; const std::vector &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 &getUniformLocations() const { ASSERT(mLinkResolved); return mState.mUniformLocations; } const LinkedUniform &getUniformByIndex(GLuint index) const { ASSERT(mLinkResolved); ASSERT(index < static_cast(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(mState.mUniformBlocks.size()); } ANGLE_INLINE GLuint getActiveAtomicCounterBufferCount() const { ASSERT(mLinkResolved); return static_cast(mState.mAtomicCounterBuffers.size()); } ANGLE_INLINE GLuint getActiveShaderStorageBlockCount() const { ASSERT(mLinkResolved); return static_cast(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 &getSamplerBindings() const; const std::vector &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 &getTransformFeedbackStrides() const; const ActiveTextureMask &getActiveSamplersMask() const { return mState.mActiveSamplersMask; } const ActiveTextureMask &getActiveImagesMask() const { return mState.mActiveImagesMask; } const ActiveTextureArray &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; 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 *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 GLsizei clampUniformCount(const VariableLocation &locationInfo, GLsizei count, int vectorSize, const T *v); template GLsizei clampMatrixUniformCount(GLint location, GLsizei count, GLboolean transpose, const T *v); void updateSamplerUniform(Context *context, const VariableLocation &locationInfo, GLsizei clampedCount, const GLint *v); template void getUniformInternal(const Context *context, DestT *dataOut, GLint location, GLenum nativeType, int components) const; template void getResourceName(GLuint index, const std::vector &resources, GLsizei bufSize, GLsizei *length, GLchar *name) const; template GLint getActiveInterfaceBlockMaxNameLength(const std::vector &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 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 mCachedValidateSamplersResult; DirtyBits mDirtyBits; }; } // namespace gl #endif // LIBANGLE_PROGRAM_H_