blob: edb2e7b477cf9424952411a83f098a25d7238683 [file] [log] [blame]
//
// Copyright 2002 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Program.h: Defines the gl::Program class. Implements GL program objects
// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
#ifndef LIBANGLE_PROGRAM_H_
#define LIBANGLE_PROGRAM_H_
#include <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/InfoLog.h"
#include "libANGLE/ProgramExecutable.h"
#include "libANGLE/ProgramLinkedResources.h"
#include "libANGLE/RefCountObject.h"
#include "libANGLE/Uniform.h"
#include "libANGLE/angletypes.h"
namespace rx
{
class GLImplFactory;
class ProgramImpl;
struct TranslatedAttribute;
} // namespace rx
namespace gl
{
class Buffer;
class BinaryInputStream;
class BinaryOutputStream;
struct Caps;
class Context;
struct Extensions;
class Framebuffer;
class ProgramExecutable;
class Shader;
class ShaderProgramManager;
class State;
struct UnusedUniform;
struct Version;
extern const char *const g_fakepath;
enum class LinkMismatchError
{
// Shared
NO_MISMATCH,
TYPE_MISMATCH,
ARRAY_SIZE_MISMATCH,
PRECISION_MISMATCH,
STRUCT_NAME_MISMATCH,
FIELD_NUMBER_MISMATCH,
FIELD_NAME_MISMATCH,
// Varying specific
INTERPOLATION_TYPE_MISMATCH,
INVARIANCE_MISMATCH,
// Uniform specific
BINDING_MISMATCH,
LOCATION_MISMATCH,
OFFSET_MISMATCH,
INSTANCE_NAME_MISMATCH,
FORMAT_MISMATCH,
// Interface block specific
LAYOUT_QUALIFIER_MISMATCH,
MATRIX_PACKING_MISMATCH,
};
void LogLinkMismatch(InfoLog &infoLog,
const std::string &variableName,
const char *variableType,
LinkMismatchError linkError,
const std::string &mismatchedStructOrBlockFieldName,
ShaderType shaderType1,
ShaderType shaderType2);
bool IsActiveInterfaceBlock(const sh::InterfaceBlock &interfaceBlock);
void WriteBlockMemberInfo(BinaryOutputStream *stream, const sh::BlockMemberInfo &var);
void LoadBlockMemberInfo(BinaryInputStream *stream, sh::BlockMemberInfo *var);
void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var);
void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var);
// Struct used for correlating uniforms/elements of uniform arrays to handles
struct VariableLocation
{
static constexpr unsigned int kUnused = GL_INVALID_INDEX;
VariableLocation();
VariableLocation(unsigned int arrayIndex, unsigned int index);
// If used is false, it means this location is only used to fill an empty space in an array,
// and there is no corresponding uniform variable for this location. It can also mean the
// uniform was optimized out by the implementation.
bool used() const { return (index != kUnused); }
void markUnused() { index = kUnused; }
void markIgnored() { ignored = true; }
bool operator==(const VariableLocation &other) const
{
return arrayIndex == other.arrayIndex && index == other.index;
}
// "arrayIndex" stores the index of the innermost GLSL array. It's zero for non-arrays.
unsigned int arrayIndex;
// "index" is an index of the variable. The variable contains the indices for other than the
// innermost GLSL arrays.
unsigned int index;
// If this location was bound to an unreferenced uniform. Setting data on this uniform is a
// no-op.
bool ignored;
};
// Information about a variable binding.
// Currently used by CHROMIUM_path_rendering
struct BindingInfo
{
// The type of binding, for example GL_FLOAT_VEC3.
// This can be GL_NONE if the variable is optimized away.
GLenum type;
// This is the name of the variable in
// the translated shader program. Note that
// this can be empty in the case where the
// variable has been optimized away.
std::string name;
// True if the binding is valid, otherwise false.
bool valid;
};
struct ProgramBinding
{
ProgramBinding() : location(GL_INVALID_INDEX), aliased(false) {}
ProgramBinding(GLuint index) : location(index), aliased(false) {}
GLuint location;
// Whether another binding was set that may potentially alias this.
bool aliased;
};
class ProgramBindings final : angle::NonCopyable
{
public:
ProgramBindings();
~ProgramBindings();
void bindLocation(GLuint index, const std::string &name);
int getBindingByName(const std::string &name) const;
int getBinding(const sh::ShaderVariable &variable) const;
using const_iterator = std::unordered_map<std::string, GLuint>::const_iterator;
const_iterator begin() const;
const_iterator end() const;
private:
std::unordered_map<std::string, GLuint> mBindings;
};
// Uniforms and Fragment Outputs require special treatment due to array notation (e.g., "[0]")
class ProgramAliasedBindings final : angle::NonCopyable
{
public:
ProgramAliasedBindings();
~ProgramAliasedBindings();
void bindLocation(GLuint index, const std::string &name);
int getBindingByName(const std::string &name) const;
int getBindingByLocation(GLuint location) const;
int getBinding(const sh::ShaderVariable &variable) const;
using const_iterator = std::unordered_map<std::string, ProgramBinding>::const_iterator;
const_iterator begin() const;
const_iterator end() const;
private:
std::unordered_map<std::string, ProgramBinding> mBindings;
};
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 mExecutable->getTransformFeedbackBufferMode();
}
GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const
{
return mExecutable->getUniformBlockBinding(uniformBlockIndex);
}
GLuint getShaderStorageBlockBinding(GLuint blockIndex) const
{
return mExecutable->getShaderStorageBlockBinding(blockIndex);
}
const UniformBlockBindingMask &getActiveUniformBlockBindingsMask() const
{
return mActiveUniformBlockBindings;
}
const std::vector<sh::ShaderVariable> &getProgramInputs() const
{
return mExecutable->getProgramInputs();
}
DrawBufferMask getActiveOutputVariables() const { return mActiveOutputVariables; }
const std::vector<sh::ShaderVariable> &getOutputVariables() const
{
return mExecutable->getOutputVariables();
}
const std::vector<VariableLocation> &getOutputLocations() const
{
return mExecutable->getOutputLocations();
}
const std::vector<VariableLocation> &getSecondaryOutputLocations() const
{
return mSecondaryOutputLocations;
}
const std::vector<LinkedUniform> &getUniforms() const { return mExecutable->getUniforms(); }
const std::vector<VariableLocation> &getUniformLocations() const { return mUniformLocations; }
const std::vector<InterfaceBlock> &getUniformBlocks() const
{
return mExecutable->getUniformBlocks();
}
const std::vector<InterfaceBlock> &getShaderStorageBlocks() const
{
return mExecutable->getShaderStorageBlocks();
}
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 &getDefaultUniformRange() const { return mDefaultUniformRange; }
const RangeUI &getSamplerUniformRange() const { return mExecutable->getSamplerUniformRange(); }
const RangeUI &getImageUniformRange() const { return mExecutable->getImageUniformRange(); }
const RangeUI &getAtomicCounterUniformRange() const { return mAtomicCounterUniformRange; }
const std::vector<TransformFeedbackVarying> &getLinkedTransformFeedbackVaryings() const
{
return mExecutable->getLinkedTransformFeedbackVaryings();
}
const std::vector<GLsizei> &getTransformFeedbackStrides() const
{
return mExecutable->getTransformFeedbackStrides();
}
const std::vector<AtomicCounterBuffer> &getAtomicCounterBuffers() const
{
return mExecutable->getAtomicCounterBuffers();
}
// Count the number of uniform and storage buffer declarations, counting arrays as one.
size_t getTransformFeedbackBufferCount() const;
GLuint getUniformIndexFromName(const std::string &name) const;
GLuint getUniformIndexFromLocation(UniformLocation location) const;
Optional<GLuint> getSamplerIndex(UniformLocation location) const;
bool isSamplerUniformIndex(GLuint index) const;
GLuint getSamplerIndexFromUniformIndex(GLuint uniformIndex) const;
GLuint getUniformIndexFromSamplerIndex(GLuint samplerIndex) const;
bool isImageUniformIndex(GLuint index) const;
GLuint getImageIndexFromUniformIndex(GLuint uniformIndex) const;
GLuint 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; }
bool hasAttachedShader() const;
ShaderType getFirstAttachedShaderStageType() const;
ShaderType getLastAttachedShaderStageType() const;
const ProgramAliasedBindings &getUniformLocationBindings() const
{
return mUniformLocationBindings;
}
const ProgramExecutable &getExecutable() const
{
ASSERT(mExecutable);
return *mExecutable;
}
ProgramExecutable &getExecutable()
{
ASSERT(mExecutable);
return *mExecutable;
}
bool hasDefaultUniforms() const { return !getDefaultUniformRange().empty(); }
bool hasTextures() const { return !getSamplerBindings().empty(); }
bool hasUniformBuffers() const { return !getUniformBlocks().empty(); }
bool hasStorageBuffers() const { return !getShaderStorageBlocks().empty(); }
bool hasAtomicCounterBuffers() const { return !getAtomicCounterBuffers().empty(); }
bool hasImages() const { return !getImageBindings().empty(); }
bool hasTransformFeedbackOutput() const
{
return !getLinkedTransformFeedbackVaryings().empty();
}
bool hasEarlyFragmentTestsOptimization() const { return mEarlyFramentTestsOptimization; }
bool isShaderMarkedForDetach(gl::ShaderType shaderType) const
{
return mAttachedShadersMarkedForDetach[shaderType];
}
// A Program can only either be graphics or compute, but never both, so it
// can answer isCompute() based on which shaders it has.
bool isCompute() const { return mExecutable->hasLinkedShaderStage(ShaderType::Compute); }
private:
friend class MemoryProgramCache;
friend class Program;
void updateTransformFeedbackStrides();
void updateActiveSamplers();
void updateActiveImages();
void updateProgramInterfaceInputs();
void updateProgramInterfaceOutputs();
// Scans the sampler bindings for type conflicts with sampler 'textureUnitIndex'.
void setSamplerUniformTextureTypeAndFormat(size_t textureUnitIndex);
std::string mLabel;
sh::WorkGroupSize mComputeShaderLocalSize;
ShaderMap<Shader *> mAttachedShaders;
ShaderMap<bool> mAttachedShadersMarkedForDetach;
uint32_t mLocationsUsedForXfbExtension;
std::vector<std::string> mTransformFeedbackVaryingNames;
// For faster iteration on the blocks currently being bound.
UniformBlockBindingMask mActiveUniformBlockBindings;
std::vector<VariableLocation> mUniformLocations;
std::vector<BufferVariable> mBufferVariables;
RangeUI mDefaultUniformRange;
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;
// 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;
bool mEarlyFramentTestsOptimization;
// ANGLE_multiview.
int mNumViews;
// GL_EXT_geometry_shader.
PrimitiveMode mGeometryShaderInputPrimitiveType;
PrimitiveMode mGeometryShaderOutputPrimitiveType;
int mGeometryShaderInvocations;
int mGeometryShaderMaxVertices;
// GL_ANGLE_multi_draw
int mDrawIDLocation;
// GL_ANGLE_base_vertex_base_instance
int mBaseVertexLocation;
int mBaseInstanceLocation;
// Cached value of base vertex and base instance
// need to reset them to zero if using non base vertex or base instance draw calls.
GLint mCachedBaseVertex;
GLuint mCachedBaseInstance;
// Note that this has nothing to do with binding layout qualifiers that can be set for some
// uniforms in GLES3.1+. It is used to pre-set the location of uniforms.
ProgramAliasedBindings mUniformLocationBindings;
std::shared_ptr<ProgramExecutable> mExecutable;
};
struct ProgramVaryingRef
{
const sh::ShaderVariable *get(ShaderType stage) const
{
ASSERT(stage == frontShaderStage || stage == backShaderStage);
const sh::ShaderVariable *ref = stage == frontShaderStage ? frontShader : backShader;
ASSERT(ref);
return ref;
}
const sh::ShaderVariable *frontShader = nullptr;
const sh::ShaderVariable *backShader = nullptr;
ShaderType frontShaderStage = ShaderType::InvalidEnum;
ShaderType backShaderStage = ShaderType::InvalidEnum;
};
using ProgramMergedVaryings = std::vector<ProgramVaryingRef>;
class Program final : angle::NonCopyable, public LabeledObject
{
public:
Program(rx::GLImplFactory *factory, ShaderProgramManager *manager, ShaderProgramID handle);
void onDestroy(const Context *context);
ShaderProgramID id() const;
void setLabel(const Context *context, const std::string &label) override;
const std::string &getLabel() const override;
ANGLE_INLINE rx::ProgramImpl *getImplementation() const
{
ASSERT(!mLinkingState);
return mProgram;
}
void attachShader(const Context *context, 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(UniformLocation location, const char *name);
// EXT_blend_func_extended
void bindFragmentOutputLocation(GLuint index, const char *name);
void bindFragmentOutputIndex(GLuint index, const char *name);
angle::Result linkMergedVaryings(const Context *context,
const ProgramExecutable &executable,
const ProgramMergedVaryings &mergedVaryings);
// 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(!mLinkingState);
return mLinked;
}
angle::Result loadBinary(const Context *context,
GLenum binaryFormat,
const void *binary,
GLsizei length);
angle::Result saveBinary(Context *context,
GLenum *binaryFormat,
void *binary,
GLsizei bufSize,
GLsizei *length) const;
GLint getBinaryLength(Context *context) const;
void setBinaryRetrievableHint(bool retrievable);
bool getBinaryRetrievableHint() const;
void setSeparable(bool separable);
bool isSeparable() const;
void getAttachedShaders(GLsizei maxCount, GLsizei *count, ShaderProgramID *shaders) const;
GLuint getAttributeLocation(const std::string &name) const;
void getActiveAttribute(GLuint index,
GLsizei bufsize,
GLsizei *length,
GLint *size,
GLenum *type,
GLchar *name) const;
GLint getActiveAttributeCount() const;
GLint getActiveAttributeMaxLength() const;
const std::vector<sh::ShaderVariable> &getAttributes() const;
GLint getFragDataLocation(const std::string &name) const;
size_t getOutputResourceCount() const;
const std::vector<GLenum> &getOutputVariableTypes() const;
DrawBufferMask getActiveOutputVariables() const
{
ASSERT(!mLinkingState);
return mState.mActiveOutputVariables;
}
// EXT_blend_func_extended
GLint getFragDataIndex(const std::string &name) const;
void getActiveUniform(GLuint index,
GLsizei bufsize,
GLsizei *length,
GLint *size,
GLenum *type,
GLchar *name) const;
GLint getActiveUniformCount() const;
size_t getActiveBufferVariableCount() const;
GLint getActiveUniformMaxLength() const;
bool isValidUniformLocation(UniformLocation location) const;
const LinkedUniform &getUniformByLocation(UniformLocation location) const;
const VariableLocation &getUniformLocation(UniformLocation location) const;
const std::vector<VariableLocation> &getUniformLocations() const
{
ASSERT(!mLinkingState);
return mState.mUniformLocations;
}
const LinkedUniform &getUniformByIndex(GLuint index) const
{
ASSERT(!mLinkingState);
return mState.mExecutable->getUniformByIndex(index);
}
const BufferVariable &getBufferVariableByIndex(GLuint index) const;
enum SetUniformResult
{
SamplerChanged,
NoSamplerChange,
};
UniformLocation getUniformLocation(const std::string &name) const;
GLuint getUniformIndex(const std::string &name) const;
void setUniform1fv(UniformLocation location, GLsizei count, const GLfloat *v);
void setUniform2fv(UniformLocation location, GLsizei count, const GLfloat *v);
void setUniform3fv(UniformLocation location, GLsizei count, const GLfloat *v);
void setUniform4fv(UniformLocation location, GLsizei count, const GLfloat *v);
void setUniform1iv(Context *context, UniformLocation location, GLsizei count, const GLint *v);
void setUniform2iv(UniformLocation location, GLsizei count, const GLint *v);
void setUniform3iv(UniformLocation location, GLsizei count, const GLint *v);
void setUniform4iv(UniformLocation location, GLsizei count, const GLint *v);
void setUniform1uiv(UniformLocation location, GLsizei count, const GLuint *v);
void setUniform2uiv(UniformLocation location, GLsizei count, const GLuint *v);
void setUniform3uiv(UniformLocation location, GLsizei count, const GLuint *v);
void setUniform4uiv(UniformLocation location, GLsizei count, const GLuint *v);
void setUniformMatrix2fv(UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value);
void setUniformMatrix3fv(UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value);
void setUniformMatrix4fv(UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value);
void setUniformMatrix2x3fv(UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value);
void setUniformMatrix3x2fv(UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value);
void setUniformMatrix2x4fv(UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value);
void setUniformMatrix4x2fv(UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value);
void setUniformMatrix3x4fv(UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value);
void setUniformMatrix4x3fv(UniformLocation location,
GLsizei count,
GLboolean transpose,
const GLfloat *value);
void getUniformfv(const Context *context, UniformLocation location, GLfloat *params) const;
void getUniformiv(const Context *context, UniformLocation location, GLint *params) const;
void getUniformuiv(const Context *context, UniformLocation location, GLuint *params) const;
void getActiveUniformBlockName(const 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(!mLinkingState);
return static_cast<GLuint>(mState.mExecutable->getActiveUniformBlockCount());
}
ANGLE_INLINE GLuint getActiveAtomicCounterBufferCount() const
{
ASSERT(!mLinkingState);
return static_cast<GLuint>(mState.mExecutable->getActiveAtomicCounterBufferCount());
}
ANGLE_INLINE GLuint getActiveShaderStorageBlockCount() const
{
ASSERT(!mLinkingState);
return static_cast<GLuint>(mState.mExecutable->getActiveShaderStorageBlockCount());
}
GLint getActiveUniformBlockMaxNameLength() const;
GLint getActiveShaderStorageBlockMaxNameLength() const;
GLuint getUniformBlockIndex(const std::string &name) const;
GLuint getShaderStorageBlockIndex(const std::string &name) const;
void bindUniformBlock(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);
bool hasBaseVertexUniform() const;
void setBaseVertexUniform(GLint baseVertex);
bool hasBaseInstanceUniform() const;
void setBaseInstanceUniform(GLuint baseInstance);
ANGLE_INLINE void addRef()
{
ASSERT(!mLinkingState);
mRefCount++;
}
ANGLE_INLINE void release(const Context *context)
{
ASSERT(!mLinkingState);
mRefCount--;
if (mRefCount == 0 && mDeleteStatus)
{
deleteSelf(context);
}
}
unsigned int getRefCount() const;
bool isInUse() const { return getRefCount() != 0; }
void flagForDeletion();
bool isFlaggedForDeletion() const;
void validate(const Caps &caps);
bool 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;
Optional<bool> getCachedValidateSamplersResult() { return mCachedValidateSamplersResult; }
void setCachedValidateSamplersResult(bool result) { mCachedValidateSamplersResult = result; }
const std::vector<SamplerBinding> &getSamplerBindings() const;
const std::vector<ImageBinding> &getImageBindings() const
{
ASSERT(!mLinkingState);
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(!mLinkingState);
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::ShaderVariable &getInputResource(size_t index) const;
GLuint getResourceMaxNameSize(const sh::ShaderVariable &resource, GLint max) const;
GLuint getInputResourceMaxNameSize() const;
GLuint getOutputResourceMaxNameSize() const;
GLuint getResourceLocation(const GLchar *name, const sh::ShaderVariable &variable) const;
GLuint getInputResourceLocation(const GLchar *name) const;
GLuint getOutputResourceLocation(const GLchar *name) const;
const std::string getResourceName(const sh::ShaderVariable &resource) const;
const std::string getInputResourceName(GLuint index) const;
const std::string getOutputResourceName(GLuint index) const;
const sh::ShaderVariable &getOutputResource(size_t index) const;
const ProgramBindings &getAttributeBindings() const;
const ProgramAliasedBindings &getUniformLocationBindings() const;
const ProgramAliasedBindings &getFragmentOutputLocations() const;
const ProgramAliasedBindings &getFragmentOutputIndexes() const;
int getNumViews() const
{
ASSERT(!mLinkingState);
return mState.getNumViews();
}
bool usesMultiview() const { return mState.usesMultiview(); }
ComponentTypeMask getDrawBufferTypeMask() const;
const std::vector<GLsizei> &getTransformFeedbackStrides() const;
// Program dirty bits.
enum DirtyBitType
{
DIRTY_BIT_UNIFORM_BLOCK_BINDING_0,
DIRTY_BIT_UNIFORM_BLOCK_BINDING_MAX =
DIRTY_BIT_UNIFORM_BLOCK_BINDING_0 + IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS,
DIRTY_BIT_COUNT = DIRTY_BIT_UNIFORM_BLOCK_BINDING_MAX,
};
using DirtyBits = angle::BitSet<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 (mLinkingState)
{
resolveLinkImpl(context);
}
}
ANGLE_INLINE bool hasAnyDirtyBit() const { return mDirtyBits.any(); }
// Writes a program's binary to the output memory buffer.
angle::Result serialize(const Context *context, angle::MemoryBuffer *binaryOut) const;
rx::Serial serial() const { return mSerial; }
const ProgramExecutable &getExecutable() const { return mState.getExecutable(); }
ProgramExecutable &getExecutable() { return mState.getExecutable(); }
const char *validateDrawStates(const State &state, const gl::Extensions &extensions) const;
static void getFilteredVaryings(const std::vector<sh::ShaderVariable> &varyings,
std::vector<const sh::ShaderVariable *> *filteredVaryingsOut);
static bool doShaderVariablesMatch(int outputShaderVersion,
ShaderType outputShaderType,
ShaderType inputShaderType,
const sh::ShaderVariable &input,
const sh::ShaderVariable &output,
bool validateGeometryShaderInputs,
bool isSeparable,
gl::InfoLog &infoLog);
static bool linkValidateShaderInterfaceMatching(
const std::vector<sh::ShaderVariable> &outputVaryings,
const std::vector<sh::ShaderVariable> &inputVaryings,
ShaderType outputShaderType,
ShaderType inputShaderType,
int outputShaderVersion,
int inputShaderVersion,
bool isSeparable,
InfoLog &infoLog);
static bool linkValidateBuiltInVaryings(const std::vector<sh::ShaderVariable> &vertexVaryings,
const std::vector<sh::ShaderVariable> &fragmentVaryings,
int vertexShaderVersion,
InfoLog &infoLog);
private:
struct LinkingState;
~Program() override;
// Loads program state according to the specified binary blob.
angle::Result deserialize(const Context *context, BinaryInputStream &stream, InfoLog &infoLog);
void unlink();
void deleteSelf(const Context *context);
angle::Result linkImpl(const Context *context);
bool linkValidateShaders(InfoLog &infoLog);
bool linkAttributes(const Context *context, InfoLog &infoLog);
bool linkInterfaceBlocks(const Caps &caps,
const Version &version,
bool webglCompatibility,
InfoLog &infoLog,
GLuint *combinedShaderStorageBlocksCount);
bool linkVaryings(InfoLog &infoLog) const;
bool linkUniforms(const Caps &caps,
const Version &version,
InfoLog &infoLog,
const ProgramAliasedBindings &uniformLocationBindings,
GLuint *combinedImageUniformsCount,
std::vector<UnusedUniform> *unusedUniforms);
void linkSamplerAndImageBindings(GLuint *combinedImageUniformsCount);
bool linkAtomicCounterBuffers();
void updateLinkedShaderStages();
static LinkMismatchError LinkValidateVaryings(const sh::ShaderVariable &outputVarying,
const sh::ShaderVariable &inputVarying,
int shaderVersion,
bool validateGeometryShaderInputVarying,
bool isSeparable,
std::string *mismatchedStructFieldName);
bool linkValidateTransformFeedback(const Version &version,
InfoLog &infoLog,
const ProgramMergedVaryings &linkedVaryings,
ShaderType stage,
const Caps &caps) const;
void gatherTransformFeedbackVaryings(const ProgramMergedVaryings &varyings, ShaderType stage);
ProgramMergedVaryings getMergedVaryings() const;
int getOutputLocationForLink(const sh::ShaderVariable &outputVariable) const;
bool isOutputSecondaryForLink(const sh::ShaderVariable &outputVariable) const;
bool linkOutputVariables(const Caps &caps,
const Extensions &extensions,
const Version &version,
GLuint combinedImageUniformsCount,
GLuint combinedShaderStorageBlocksCount);
void setUniformValuesFromBindingQualifiers();
bool shouldIgnoreUniform(UniformLocation location) const;
void initInterfaceBlockBindings();
// Both these function update the cached uniform values and return a modified "count"
// so that the uniform update doesn't overflow the uniform.
template <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(UniformLocation 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,
UniformLocation location,
GLenum nativeType,
int components) const;
void getResourceName(const std::string name,
GLsizei bufSize,
GLsizei *length,
GLchar *dest) const;
template <typename T>
GLint getActiveInterfaceBlockMaxNameLength(const std::vector<T> &resources) const;
GLuint getSamplerUniformBinding(const VariableLocation &uniformLocation) const;
GLuint getImageUniformBinding(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);
rx::Serial mSerial;
ProgramState mState;
rx::ProgramImpl *mProgram;
bool mValidated;
ProgramBindings mAttributeBindings;
// EXT_blend_func_extended
ProgramAliasedBindings mFragmentOutputLocations;
ProgramAliasedBindings mFragmentOutputIndexes;
bool mLinked;
std::unique_ptr<LinkingState> mLinkingState;
bool mDeleteStatus; // Flag to indicate that the program can be deleted when no longer in use
unsigned int mRefCount;
ShaderProgramManager *mResourceManager;
const ShaderProgramID mHandle;
// Cache for sampler validation
Optional<bool> mCachedValidateSamplersResult;
DirtyBits mDirtyBits;
};
} // namespace gl
#endif // LIBANGLE_PROGRAM_H_