blob: 48f3bd21754084796d98d5282dda6e5b4fa86933 [file] [log] [blame]
//
// Copyright 2020 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.
//
// ProgramExecutable.h: Collects the information and interfaces common to both Programs and
// ProgramPipelines in order to execute/draw with either.
#ifndef LIBANGLE_PROGRAMEXECUTABLE_H_
#define LIBANGLE_PROGRAMEXECUTABLE_H_
#include "BinaryStream.h"
#include "libANGLE/Caps.h"
#include "libANGLE/InfoLog.h"
#include "libANGLE/ProgramLinkedResources.h"
#include "libANGLE/Shader.h"
#include "libANGLE/Uniform.h"
#include "libANGLE/VaryingPacking.h"
#include "libANGLE/angletypes.h"
namespace gl
{
// This small structure encapsulates binding sampler uniforms to active GL textures.
struct SamplerBinding
{
SamplerBinding(TextureType textureTypeIn, SamplerFormat formatIn, size_t elementCount);
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.
// Cropped by the amount of unused elements reported by the driver.
std::vector<GLuint> boundTextureUnits;
};
struct ImageBinding
{
ImageBinding(size_t count);
ImageBinding(GLuint imageUnit, size_t count);
ImageBinding(const ImageBinding &other);
~ImageBinding();
// List of all textures bound.
// Cropped by the amount of unused elements reported by the driver.
std::vector<GLuint> boundImageUnits;
};
// A varying with transform 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::ShaderVariable
{
TransformFeedbackVarying(const sh::ShaderVariable &varyingIn, GLuint arrayIndexIn)
: sh::ShaderVariable(varyingIn), arrayIndex(arrayIndexIn)
{
ASSERT(!isArrayOfArrays());
}
TransformFeedbackVarying(const sh::ShaderVariable &field, const sh::ShaderVariable &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;
};
class ProgramState;
class ProgramPipelineState;
class ProgramExecutable final : public angle::Subject
{
public:
ProgramExecutable();
ProgramExecutable(const ProgramExecutable &other);
~ProgramExecutable() override;
void reset();
void save(gl::BinaryOutputStream *stream) const;
void load(gl::BinaryInputStream *stream);
int getInfoLogLength() const;
InfoLog &getInfoLog() { return mInfoLog; }
void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const;
std::string getInfoLogString() const;
void resetInfoLog() { mInfoLog.reset(); }
void resetLinkedShaderStages()
{
mLinkedComputeShaderStages.reset();
mLinkedGraphicsShaderStages.reset();
}
const ShaderBitSet &getLinkedShaderStages() const
{
return isCompute() ? mLinkedComputeShaderStages : mLinkedGraphicsShaderStages;
}
void setLinkedShaderStages(ShaderType shaderType)
{
if (shaderType == ShaderType::Compute)
{
mLinkedComputeShaderStages.set(ShaderType::Compute);
}
else
{
mLinkedGraphicsShaderStages.set(shaderType);
}
updateCanDrawWith();
}
bool hasLinkedShaderStage(ShaderType shaderType) const
{
ASSERT(shaderType != ShaderType::InvalidEnum);
return (shaderType == ShaderType::Compute) ? mLinkedComputeShaderStages[shaderType]
: mLinkedGraphicsShaderStages[shaderType];
}
size_t getLinkedShaderStageCount() const
{
return isCompute() ? mLinkedComputeShaderStages.count()
: mLinkedGraphicsShaderStages.count();
}
// A PPO can have both graphics and compute programs attached, so
// we don't know if the PPO is a 'graphics' or 'compute' PPO until the
// actual draw/dispatch call.
bool isCompute() const { return mIsCompute; }
void setIsCompute(bool isCompute) { mIsCompute = isCompute; }
const AttributesMask &getActiveAttribLocationsMask() const
{
return mActiveAttribLocationsMask;
}
bool isAttribLocationActive(size_t attribLocation) const;
const AttributesMask &getNonBuiltinAttribLocationsMask() const { return mAttributesMask; }
unsigned int getMaxActiveAttribLocation() const { return mMaxActiveAttribLocation; }
const ComponentTypeMask &getAttributesTypeMask() const { return mAttributesTypeMask; }
AttributesMask getAttributesMask() const;
const ActiveTextureMask &getActiveSamplersMask() const { return mActiveSamplersMask; }
void setActiveTextureMask(ActiveTextureMask mask) { mActiveSamplersMask = mask; }
SamplerFormat getSamplerFormatForTextureUnitIndex(size_t textureUnitIndex) const
{
return mActiveSamplerFormats[textureUnitIndex];
}
const ShaderBitSet getSamplerShaderBitsForTextureUnitIndex(size_t textureUnitIndex) const
{
return mActiveSamplerShaderBits[textureUnitIndex];
}
const ActiveTextureMask &getActiveImagesMask() const { return mActiveImagesMask; }
void setActiveImagesMask(ActiveTextureMask mask) { mActiveImagesMask = mask; }
const ActiveTextureArray<ShaderBitSet> &getActiveImageShaderBits() const
{
return mActiveImageShaderBits;
}
const ActiveTextureArray<TextureType> &getActiveSamplerTypes() const
{
return mActiveSamplerTypes;
}
void updateActiveSamplers(const ProgramState &programState);
bool hasDefaultUniforms() const;
bool hasTextures() const;
bool hasUniformBuffers() const;
bool hasStorageBuffers() const;
bool hasGraphicsStorageBuffers() const;
bool hasComputeStorageBuffers() const;
bool hasAtomicCounterBuffers() const;
bool hasImages() const;
bool hasGraphicsImages() const;
bool hasComputeImages() const;
bool hasTransformFeedbackOutput() const
{
return !getLinkedTransformFeedbackVaryings().empty();
}
// Count the number of uniform and storage buffer declarations, counting arrays as one.
size_t getTransformFeedbackBufferCount() const { return mTransformFeedbackStrides.size(); }
bool linkValidateGlobalNames(InfoLog &infoLog,
const ShaderMap<const ProgramState *> &programStates) const;
void updateCanDrawWith();
bool hasVertexAndFragmentShader() const { return mCanDrawWith; }
const std::vector<sh::ShaderVariable> &getProgramInputs() const { return mProgramInputs; }
const std::vector<sh::ShaderVariable> &getOutputVariables() const { return mOutputVariables; }
const std::vector<VariableLocation> &getOutputLocations() const { return mOutputLocations; }
const std::vector<LinkedUniform> &getUniforms() const { return mUniforms; }
const std::vector<InterfaceBlock> &getUniformBlocks() const { return mUniformBlocks; }
const std::vector<SamplerBinding> &getSamplerBindings() const { return mSamplerBindings; }
const std::vector<ImageBinding> &getImageBindings() const
{
return isCompute() ? mComputeImageBindings : mGraphicsImageBindings;
}
std::vector<ImageBinding> *getImageBindings()
{
return isCompute() ? &mComputeImageBindings : &mGraphicsImageBindings;
}
const RangeUI &getDefaultUniformRange() const { return mDefaultUniformRange; }
const RangeUI &getSamplerUniformRange() const { return mSamplerUniformRange; }
const RangeUI &getImageUniformRange() const { return mImageUniformRange; }
const std::vector<TransformFeedbackVarying> &getLinkedTransformFeedbackVaryings() const
{
return mLinkedTransformFeedbackVaryings;
}
void setLinkedTransformFeedbackVaryings(
const std::vector<TransformFeedbackVarying> _mLinkedTransformFeedbackVaryings)
{
mLinkedTransformFeedbackVaryings = _mLinkedTransformFeedbackVaryings;
}
GLint getTransformFeedbackBufferMode() const { return mTransformFeedbackBufferMode; }
GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const
{
ASSERT(uniformBlockIndex < mUniformBlocks.size());
return mUniformBlocks[uniformBlockIndex].binding;
}
GLuint getShaderStorageBlockBinding(GLuint blockIndex) const
{
ASSERT((isCompute() && (blockIndex < mComputeShaderStorageBlocks.size())) ||
(!isCompute() && (blockIndex < mGraphicsShaderStorageBlocks.size())));
return isCompute() ? mComputeShaderStorageBlocks[blockIndex].binding
: mGraphicsShaderStorageBlocks[blockIndex].binding;
}
const std::vector<GLsizei> &getTransformFeedbackStrides() const
{
return mTransformFeedbackStrides;
}
const std::vector<AtomicCounterBuffer> &getAtomicCounterBuffers() const
{
return mAtomicCounterBuffers;
}
const std::vector<InterfaceBlock> &getShaderStorageBlocks() const
{
return isCompute() ? mComputeShaderStorageBlocks : mGraphicsShaderStorageBlocks;
}
const LinkedUniform &getUniformByIndex(GLuint index) const
{
ASSERT(index < static_cast<size_t>(mUniforms.size()));
return mUniforms[index];
}
ANGLE_INLINE GLuint getActiveUniformBlockCount() const
{
return static_cast<GLuint>(mUniformBlocks.size());
}
ANGLE_INLINE GLuint getActiveAtomicCounterBufferCount() const
{
return static_cast<GLuint>(mAtomicCounterBuffers.size());
}
ANGLE_INLINE GLuint getActiveShaderStorageBlockCount() const
{
size_t shaderStorageBlocksSize =
isCompute() ? mComputeShaderStorageBlocks.size() : mGraphicsShaderStorageBlocks.size();
return static_cast<GLuint>(shaderStorageBlocksSize);
}
GLuint getUniformIndexFromImageIndex(GLuint imageIndex) const;
gl::ProgramLinkedResources &getResources() const
{
ASSERT(mResources);
return *mResources;
}
void saveLinkedStateInfo(const ProgramState &state);
std::vector<sh::ShaderVariable> getLinkedOutputVaryings(ShaderType shaderType)
{
return mLinkedOutputVaryings[shaderType];
}
std::vector<sh::ShaderVariable> getLinkedInputVaryings(ShaderType shaderType)
{
return mLinkedInputVaryings[shaderType];
}
int getLinkedShaderVersion(ShaderType shaderType) { return mLinkedShaderVersions[shaderType]; }
private:
// TODO(timvp): http://anglebug.com/3570: Investigate removing these friend
// class declarations and accessing the necessary members with getters/setters.
friend class Program;
friend class ProgramPipeline;
friend class ProgramState;
void updateActiveImages(const ProgramExecutable &executable);
// Scans the sampler bindings for type conflicts with sampler 'textureUnitIndex'.
void setSamplerUniformTextureTypeAndFormat(size_t textureUnitIndex,
std::vector<SamplerBinding> &samplerBindings);
InfoLog mInfoLog;
ShaderBitSet mLinkedGraphicsShaderStages;
ShaderBitSet mLinkedComputeShaderStages;
angle::BitSet<MAX_VERTEX_ATTRIBS> mActiveAttribLocationsMask;
unsigned int mMaxActiveAttribLocation;
ComponentTypeMask mAttributesTypeMask;
// mAttributesMask is identical to mActiveAttribLocationsMask with built-in attributes removed.
AttributesMask mAttributesMask;
// Cached mask of active samplers and sampler types.
ActiveTextureMask mActiveSamplersMask;
ActiveTextureArray<uint32_t> mActiveSamplerRefCounts;
ActiveTextureArray<TextureType> mActiveSamplerTypes;
ActiveTextureArray<SamplerFormat> mActiveSamplerFormats;
ActiveTextureArray<ShaderBitSet> mActiveSamplerShaderBits;
// Cached mask of active images.
ActiveTextureMask mActiveImagesMask;
ActiveTextureArray<ShaderBitSet> mActiveImageShaderBits;
bool mCanDrawWith;
// Names and mapped names of output variables that are arrays include [0] in the end, similarly
// to uniforms.
std::vector<sh::ShaderVariable> mOutputVariables;
std::vector<VariableLocation> mOutputLocations;
// Vertex attributes, Fragment input varyings, etc.
std::vector<sh::ShaderVariable> mProgramInputs;
std::vector<TransformFeedbackVarying> mLinkedTransformFeedbackVaryings;
// The size of the data written to each transform feedback buffer per vertex.
std::vector<GLsizei> mTransformFeedbackStrides;
GLenum mTransformFeedbackBufferMode;
// 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;
RangeUI mDefaultUniformRange;
RangeUI mSamplerUniformRange;
std::vector<InterfaceBlock> mUniformBlocks;
std::vector<AtomicCounterBuffer> mAtomicCounterBuffers;
RangeUI mImageUniformRange;
std::vector<InterfaceBlock> mComputeShaderStorageBlocks;
std::vector<InterfaceBlock> mGraphicsShaderStorageBlocks;
// 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> mComputeImageBindings;
std::vector<ImageBinding> mGraphicsImageBindings;
// TODO: http://anglebug.com/3570: Remove mPipelineHas*UniformBuffers once PPO's have valid data
// in mUniformBlocks
bool mPipelineHasGraphicsUniformBuffers;
bool mPipelineHasComputeUniformBuffers;
bool mPipelineHasGraphicsStorageBuffers;
bool mPipelineHasComputeStorageBuffers;
bool mPipelineHasGraphicsAtomicCounterBuffers;
bool mPipelineHasComputeAtomicCounterBuffers;
bool mPipelineHasGraphicsDefaultUniforms;
bool mPipelineHasComputeDefaultUniforms;
bool mPipelineHasGraphicsTextures;
bool mPipelineHasComputeTextures;
bool mPipelineHasGraphicsImages;
bool mPipelineHasComputeImages;
bool mIsCompute;
ShaderMap<std::vector<sh::ShaderVariable>> mLinkedOutputVaryings;
ShaderMap<std::vector<sh::ShaderVariable>> mLinkedInputVaryings;
ShaderMap<int> mLinkedShaderVersions;
// TODO: http://anglebug.com/4514: Remove
std::unique_ptr<gl::ProgramLinkedResources> mResources;
};
} // namespace gl
#endif // LIBANGLE_PROGRAMEXECUTABLE_H_