Commit 7e4eff11 by Jamie Madill Committed by Commit Bot

Program: Add cache samplers and type masks.

This mask cleans up some of the iteration logic in State::syncProgramTextures. It will make it easier to optimize this function in the future. This will also make it easier to recompute the sampler type validation. Leads to a 5% improvement in State::syncProgramTextures. Bug: angleproject:2747 Bug: angleproject:2763 Change-Id: Ic9a555df843ad23b4c562e6e4a2d425bee58a856 Reviewed-on: https://chromium-review.googlesource.com/1164306 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 46848420
......@@ -5612,22 +5612,22 @@ void Context::uniform1fv(GLint location, GLsizei count, const GLfloat *v)
program->setUniform1fv(location, count, v);
}
void Context::uniform1i(GLint location, GLint x)
void Context::setUniform1iImpl(Program *program, GLint location, GLsizei count, const GLint *v)
{
Program *program = mGLState.getProgram();
if (program->setUniform1iv(location, 1, &x) == Program::SetUniformResult::SamplerChanged)
if (program->setUniform1iv(location, count, v) == Program::SetUniformResult::SamplerChanged)
{
mGLState.setObjectDirty(GL_PROGRAM);
}
}
void Context::uniform1i(GLint location, GLint x)
{
setUniform1iImpl(mGLState.getProgram(), location, 1, &x);
}
void Context::uniform1iv(GLint location, GLsizei count, const GLint *v)
{
Program *program = mGLState.getProgram();
if (program->setUniform1iv(location, count, v) == Program::SetUniformResult::SamplerChanged)
{
mGLState.setObjectDirty(GL_PROGRAM);
}
setUniform1iImpl(mGLState.getProgram(), location, count, v);
}
void Context::uniform2f(GLint location, GLfloat x, GLfloat y)
......@@ -6341,11 +6341,7 @@ void Context::programUniform1iv(GLuint program, GLint location, GLsizei count, c
{
Program *programObject = getProgram(program);
ASSERT(programObject);
if (programObject->setUniform1iv(location, count, value) ==
Program::SetUniformResult::SamplerChanged)
{
mGLState.setObjectDirty(GL_PROGRAM);
}
setUniform1iImpl(programObject, location, count, value);
}
void Context::programUniform2iv(GLuint program, GLint location, GLsizei count, const GLint *value)
......
......@@ -1587,6 +1587,8 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl
gl::LabeledObject *getLabeledObject(GLenum identifier, GLuint name) const;
gl::LabeledObject *getLabeledObjectFromPtr(const void *ptr) const;
void setUniform1iImpl(Program *program, GLint location, GLsizei count, const GLint *v);
ContextState mState;
bool mSkipValidation;
bool mDisplayTextureShareGroup;
......
......@@ -434,6 +434,7 @@ LinkResult MemoryProgramCache::Deserialize(const Context *context,
state->mLinkedShaderStages = ShaderBitSet(stream.readInt<uint8_t>());
state->updateTransformFeedbackStrides();
state->updateActiveSamplers();
return program->getImplementation()->load(context, infoLog, &stream);
}
......
......@@ -794,9 +794,11 @@ ProgramState::ProgramState()
mGeometryShaderInputPrimitiveType(PrimitiveMode::Triangles),
mGeometryShaderOutputPrimitiveType(PrimitiveMode::TriangleStrip),
mGeometryShaderInvocations(1),
mGeometryShaderMaxVertices(0)
mGeometryShaderMaxVertices(0),
mActiveSamplerRefCounts{}
{
mComputeShaderLocalSize.fill(1);
mActiveSamplerTypes.fill(TextureType::InvalidEnum);
}
ProgramState::~ProgramState()
......@@ -1226,8 +1228,6 @@ Error Program::link(const gl::Context *context)
initInterfaceBlockBindings();
setUniformValuesFromBindingQualifiers();
// According to GLES 3.0/3.1 spec for LinkProgram and UseProgram,
// Only successfully linked program can replace the executables.
ASSERT(mLinked);
......@@ -1236,6 +1236,11 @@ Error Program::link(const gl::Context *context)
// Mark implementation-specific unreferenced uniforms as ignored.
mProgram->markUnusedUniformLocations(&mState.mUniformLocations, &mState.mSamplerBindings);
// Must be called after markUnusedUniformLocations.
mState.updateActiveSamplers();
setUniformValuesFromBindingQualifiers();
// Save to the program cache.
if (cache && (mState.mLinkedTransformFeedbackVaryings.empty() ||
!context->getWorkarounds().disableProgramCachingForTransformFeedback))
......@@ -1287,6 +1292,22 @@ void ProgramState::updateTransformFeedbackStrides()
}
}
void ProgramState::updateActiveSamplers()
{
for (SamplerBinding &samplerBinding : mSamplerBindings)
{
if (samplerBinding.unreferenced)
continue;
for (GLint textureUnit : samplerBinding.boundTextureUnits)
{
mActiveSamplerRefCounts[textureUnit]++;
mActiveSamplerTypes[textureUnit] = getSamplerUniformTextureType(textureUnit);
mActiveSamplersMask.set(textureUnit);
}
}
}
// Returns the program object to an unlinked state, before re-linking, or at destruction
void Program::unlink()
{
......@@ -2046,44 +2067,12 @@ void Program::validate(const Caps &caps)
bool Program::validateSamplersImpl(InfoLog *infoLog, const Caps &caps)
{
if (mTextureUnitTypesCache.empty())
{
mTextureUnitTypesCache.resize(caps.maxCombinedTextureImageUnits, TextureType::InvalidEnum);
}
else
{
std::fill(mTextureUnitTypesCache.begin(), mTextureUnitTypesCache.end(),
TextureType::InvalidEnum);
}
// if any two active samplers in a program are of different types, but refer to the same
// texture image unit, and this is the current program, then ValidateProgram will fail, and
// DrawArrays and DrawElements will issue the INVALID_OPERATION error.
for (const auto &samplerBinding : mState.mSamplerBindings)
{
if (samplerBinding.unreferenced)
continue;
TextureType textureType = samplerBinding.textureType;
for (GLuint textureUnit : samplerBinding.boundTextureUnits)
for (size_t textureUnit : mState.mActiveSamplersMask)
{
if (textureUnit >= caps.maxCombinedTextureImageUnits)
{
if (infoLog)
{
(*infoLog) << "Sampler uniform (" << textureUnit
<< ") exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS ("
<< caps.maxCombinedTextureImageUnits << ")";
}
mCachedValidateSamplersResult = false;
return false;
}
if (mTextureUnitTypesCache[textureUnit] != TextureType::InvalidEnum)
{
if (textureType != mTextureUnitTypesCache[textureUnit])
if (mState.mActiveSamplerTypes[textureUnit] == TextureType::InvalidEnum)
{
if (infoLog)
{
......@@ -2096,12 +2085,6 @@ bool Program::validateSamplersImpl(InfoLog *infoLog, const Caps &caps)
return false;
}
}
else
{
mTextureUnitTypesCache[textureUnit] = textureType;
}
}
}
mCachedValidateSamplersResult = true;
return true;
......@@ -2651,8 +2634,8 @@ void Program::linkSamplerAndImageBindings(GLuint *combinedImageUniforms)
{
const auto &samplerUniform = mState.mUniforms[samplerIndex];
TextureType textureType = SamplerTypeToTextureType(samplerUniform.type);
mState.mSamplerBindings.emplace_back(
SamplerBinding(textureType, samplerUniform.getBasicTypeElementCount(), false));
unsigned int elementCount = samplerUniform.getBasicTypeElementCount();
mState.mSamplerBindings.emplace_back(textureType, elementCount, false);
}
}
......@@ -3469,15 +3452,93 @@ void Program::updateSamplerUniform(const VariableLocation &locationInfo,
{
ASSERT(mState.isSamplerUniformIndex(locationInfo.index));
GLuint samplerIndex = mState.getSamplerIndexFromUniformIndex(locationInfo.index);
std::vector<GLuint> *boundTextureUnits =
&mState.mSamplerBindings[samplerIndex].boundTextureUnits;
SamplerBinding &samplerBinding = mState.mSamplerBindings[samplerIndex];
std::vector<GLuint> &boundTextureUnits = samplerBinding.boundTextureUnits;
if (samplerBinding.unreferenced)
return;
// Update the sampler uniforms.
for (GLsizei arrayIndex = 0; arrayIndex < clampedCount; ++arrayIndex)
{
GLint oldSamplerIndex = boundTextureUnits[arrayIndex + locationInfo.arrayIndex];
GLint newSamplerIndex = v[arrayIndex];
if (oldSamplerIndex == newSamplerIndex)
continue;
boundTextureUnits[arrayIndex + locationInfo.arrayIndex] = newSamplerIndex;
std::copy(v, v + clampedCount, boundTextureUnits->begin() + locationInfo.arrayIndex);
// Update the reference counts.
uint32_t &oldRefCount = mState.mActiveSamplerRefCounts[oldSamplerIndex];
uint32_t &newRefCount = mState.mActiveSamplerRefCounts[newSamplerIndex];
ASSERT(oldRefCount > 0);
ASSERT(newRefCount < std::numeric_limits<uint32_t>::max());
oldRefCount--;
newRefCount++;
// Check for binding type change.
TextureType &newSamplerType = mState.mActiveSamplerTypes[newSamplerIndex];
TextureType &oldSamplerType = mState.mActiveSamplerTypes[oldSamplerIndex];
if (newRefCount == 1)
{
newSamplerType = samplerBinding.textureType;
mState.mActiveSamplersMask.set(newSamplerIndex);
}
else if (newSamplerType != samplerBinding.textureType)
{
// Conflict detected. Ensure we reset it properly.
newSamplerType = TextureType::InvalidEnum;
}
// Unset previously active sampler.
if (oldRefCount == 0)
{
oldSamplerType = TextureType::InvalidEnum;
mState.mActiveSamplersMask.reset(oldSamplerIndex);
}
else if (oldSamplerType == TextureType::InvalidEnum)
{
// Previous conflict. Check if this new change fixed the conflict.
oldSamplerType = mState.getSamplerUniformTextureType(oldSamplerIndex);
}
}
// Invalidate the validation cache.
mCachedValidateSamplersResult.reset();
}
TextureType ProgramState::getSamplerUniformTextureType(size_t textureUnitIndex) const
{
TextureType foundType = TextureType::InvalidEnum;
for (const SamplerBinding &binding : mSamplerBindings)
{
if (binding.unreferenced)
continue;
// A conflict exists if samplers of different types are sourced by the same texture unit.
// We need to check all bound textures to detect this error case.
for (GLuint textureUnit : binding.boundTextureUnits)
{
if (textureUnit == textureUnitIndex)
{
if (foundType == TextureType::InvalidEnum)
{
foundType = binding.textureType;
}
else if (foundType != binding.textureType)
{
return TextureType::InvalidEnum;
}
}
}
}
return foundType;
}
template <typename T>
GLsizei Program::clampUniformCount(const VariableLocation &locationInfo,
GLsizei count,
......
......@@ -353,6 +353,10 @@ class ProgramState final : angle::NonCopyable
friend class Program;
void updateTransformFeedbackStrides();
void updateActiveSamplers();
// Scans the sampler bindings for type conflicts with sampler 'textureUnitIndex'.
TextureType getSamplerUniformTextureType(size_t textureUnitIndex) const;
std::string mLabel;
......@@ -427,6 +431,11 @@ class ProgramState final : angle::NonCopyable
// 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;
};
class ProgramBindings final : angle::NonCopyable
......@@ -752,6 +761,13 @@ class Program final : angle::NonCopyable, public LabeledObject
return mState.mTransformFeedbackStrides;
}
const ActiveTextureMask &getActiveSamplersMask() const { return mState.mActiveSamplersMask; }
const ActiveTextureArray<TextureType> &getActiveSamplerTypes() const
{
return mState.mActiveSamplerTypes;
}
private:
~Program() override;
......@@ -868,7 +884,6 @@ class Program final : angle::NonCopyable, public LabeledObject
// Cache for sampler validation
Optional<bool> mCachedValidateSamplersResult;
std::vector<TextureType> mTextureUnitTypesCache;
};
} // namespace gl
......
......@@ -2653,14 +2653,13 @@ Error State::syncProgramTextures(const Context *context)
// initialized.
mCachedTexturesInitState = InitState::Initialized;
for (const SamplerBinding &samplerBinding : mProgram->getSamplerBindings())
{
if (samplerBinding.unreferenced)
continue;
const ActiveTextureMask &activeTextures = mProgram->getActiveSamplersMask();
const ActiveTextureArray<TextureType> &textureTypes = mProgram->getActiveSamplerTypes();
TextureType textureType = samplerBinding.textureType;
for (GLuint textureUnitIndex : samplerBinding.boundTextureUnits)
for (size_t textureUnitIndex : activeTextures)
{
TextureType textureType = textureTypes[textureUnitIndex];
Texture *texture = getSamplerTexture(textureUnitIndex, textureType);
Sampler *sampler = getSampler(textureUnitIndex);
ASSERT(static_cast<size_t>(textureUnitIndex) < mCompleteTextureCache.size());
......@@ -2683,7 +2682,6 @@ Error State::syncProgramTextures(const Context *context)
// Bind the texture unconditionally, to recieve completeness change notifications.
mCompleteTextureBindings[textureUnitIndex].bind(texture->getSubject());
mActiveTexturesMask.set(textureUnitIndex);
newActiveTextures.set(textureUnitIndex);
if (sampler != nullptr)
......@@ -2696,17 +2694,15 @@ Error State::syncProgramTextures(const Context *context)
mCachedTexturesInitState = InitState::MayNeedInit;
}
}
}
// Unset now missing textures.
ActiveTextureMask negativeMask = mActiveTexturesMask & ~newActiveTextures;
ActiveTextureMask negativeMask = activeTextures & ~newActiveTextures;
if (negativeMask.any())
{
for (auto textureIndex : negativeMask)
{
mCompleteTextureBindings[textureIndex].reset();
mCompleteTextureCache[textureIndex] = nullptr;
mActiveTexturesMask.reset(textureIndex);
}
}
......@@ -2830,7 +2826,10 @@ Error State::clearUnclearedActiveTextures(const Context *context)
ASSERT(!mDirtyObjects[DIRTY_OBJECT_PROGRAM_TEXTURES]);
for (auto textureIndex : mActiveTexturesMask)
if (!mProgram)
return NoError();
for (auto textureIndex : mProgram->getActiveSamplersMask())
{
Texture *texture = mCompleteTextureCache[textureIndex];
if (texture)
......
......@@ -467,7 +467,6 @@ class State : public angle::ObserverInterface, angle::NonCopyable
GLenum format);
const ImageUnit &getImageUnit(GLuint unit) const;
const ActiveTextureMask &getActiveTexturesMask() const { return mActiveTexturesMask; }
const std::vector<Texture *> &getCompleteTextureCache() const { return mCompleteTextureCache; }
ComponentTypeMask getCurrentValuesTypeMask() const { return mCurrentValuesTypeMask; }
......@@ -559,7 +558,6 @@ class State : public angle::ObserverInterface, angle::NonCopyable
std::vector<Texture *> mCompleteTextureCache;
std::vector<angle::ObserverBinding> mCompleteTextureBindings;
InitState mCachedTexturesInitState;
ActiveTextureMask mActiveTexturesMask;
using SamplerBindingVector = std::vector<BindingPointer<Sampler>>;
SamplerBindingVector mSamplers;
......
......@@ -251,7 +251,7 @@ gl::Error ContextVk::setupDraw(const gl::Context *context,
mTexturesDirty = false;
// TODO(jmadill): Should probably merge this for loop with programVk's descriptor update.
for (size_t textureIndex : state.getActiveTexturesMask())
for (size_t textureIndex : programGL->getActiveSamplersMask())
{
TextureVk *textureVk = mActiveTextures[textureIndex];
ANGLE_TRY(textureVk->ensureImageInitialized(this));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment