blob: 80d25fefcad75296814bcfa8ec8597ce52931764 [file] [log] [blame]
//
// 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_