Commit 0f80ed86 by Jamie Madill Committed by Commit Bot

Improve speed of iterating dirty textures.

We had a performance regression in the Textures benchmark. What the test was doing was iterating over all possible texture state, ensuring the active texture was dirty every frame. This is an attempt to improve on the speed by not doing as much resetting work in State::syncProgramTextures. It introduces an active textures mask to speed iteration over the active texture set. Also makes a refactoring change to Context to make it easier to limit caps to an implementation maxium. The number of active textures is limited to 64 so they easily fit in the bitset mask, with a limit of 32 per shader stage. No mask is currenly kept for compute shaders. With the fix the performance should be about the same as before (which is good, as the test always sets the textures dirty). Test: TexturesBenchmark.Run/gl_8_textures_5_rebind_3_state_8_mips BUG=chromium:765363 BUG=angleproject:1387 Change-Id: I8bcf95be3671195373573f89f406edaba40aa1be Reviewed-on: https://chromium-review.googlesource.com/670279Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarFrank Henigman <fjhenigman@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 8b2142e3
......@@ -47,7 +47,11 @@ enum
IMPLEMENTATION_MAX_3D_TEXTURE_SIZE = 2048,
IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS = 2048,
IMPLEMENTATION_MAX_TEXTURE_LEVELS = 15 // 1+log2 of MAX_TEXTURE_SIZE
// 1+log2 of max of MAX_*_TEXTURE_SIZE
IMPLEMENTATION_MAX_TEXTURE_LEVELS = 15,
// Limit active textures so we can use fast bitsets.
IMPLEMENTATION_MAX_ACTIVE_TEXTURES = 64,
};
}
......
......@@ -240,6 +240,12 @@ void GetObjectLabelBase(const std::string &objectLabel,
}
}
template <typename CapT, typename MaxT>
void LimitCap(CapT *cap, MaxT maximum)
{
*cap = std::min(*cap, static_cast<CapT>(maximum));
}
} // anonymous namespace
namespace gl
......@@ -2672,19 +2678,25 @@ void Context::initCaps(const egl::DisplayExtensions &displayExtensions)
mExtensions.programCacheControl = true;
// Apply implementation limits
mCaps.maxVertexAttributes = std::min<GLuint>(mCaps.maxVertexAttributes, MAX_VERTEX_ATTRIBS);
mCaps.maxVertexAttribBindings =
getClientVersion() < ES_3_1
? mCaps.maxVertexAttributes
: std::min<GLuint>(mCaps.maxVertexAttribBindings, MAX_VERTEX_ATTRIB_BINDINGS);
mCaps.maxVertexUniformBlocks = std::min<GLuint>(
mCaps.maxVertexUniformBlocks, IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS);
mCaps.maxVertexOutputComponents =
std::min<GLuint>(mCaps.maxVertexOutputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4);
mCaps.maxFragmentInputComponents =
std::min<GLuint>(mCaps.maxFragmentInputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4);
LimitCap(&mCaps.maxVertexAttributes, MAX_VERTEX_ATTRIBS);
if (getClientVersion() < ES_3_1)
{
mCaps.maxVertexAttribBindings = mCaps.maxVertexAttributes;
}
else
{
LimitCap(&mCaps.maxVertexAttribBindings, MAX_VERTEX_ATTRIB_BINDINGS);
}
LimitCap(&mCaps.maxVertexUniformBlocks, IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS);
LimitCap(&mCaps.maxVertexOutputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4);
LimitCap(&mCaps.maxFragmentInputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4);
// Limit textures as well, so we can use fast bitsets with texture bindings.
LimitCap(&mCaps.maxCombinedTextureImageUnits, IMPLEMENTATION_MAX_ACTIVE_TEXTURES);
LimitCap(&mCaps.maxVertexTextureImageUnits, IMPLEMENTATION_MAX_ACTIVE_TEXTURES / 2);
LimitCap(&mCaps.maxTextureImageUnits, IMPLEMENTATION_MAX_ACTIVE_TEXTURES / 2);
// WebGL compatibility
mExtensions.webglCompatibility = mWebGLContext;
......
......@@ -2206,12 +2206,6 @@ void State::syncDirtyObjects(const Context *context, const DirtyObjects &bitset)
void State::syncProgramTextures(const Context *context)
{
std::fill(mCompleteTextureCache.begin(), mCompleteTextureCache.end(), nullptr);
for (auto &binding : mCompleteTextureBindings)
{
binding.reset();
}
// TODO(jmadill): Fine-grained updates.
if (!mProgram)
{
......@@ -2221,6 +2215,8 @@ void State::syncProgramTextures(const Context *context)
ASSERT(mDirtyObjects[DIRTY_OBJECT_PROGRAM_TEXTURES]);
mDirtyBits.set(DIRTY_BIT_TEXTURE_BINDINGS);
ActiveTextureMask newActiveTextures;
for (const SamplerBinding &samplerBinding : mProgram->getSamplerBindings())
{
if (samplerBinding.unreferenced)
......@@ -2231,6 +2227,8 @@ void State::syncProgramTextures(const Context *context)
{
Texture *texture = getSamplerTexture(textureUnitIndex, textureType);
Sampler *sampler = getSampler(textureUnitIndex);
ASSERT(static_cast<size_t>(textureUnitIndex) < mCompleteTextureCache.size());
ASSERT(static_cast<size_t>(textureUnitIndex) < newActiveTextures.size());
if (texture != nullptr)
{
......@@ -2239,14 +2237,17 @@ void State::syncProgramTextures(const Context *context)
if (texture->isSamplerComplete(context, sampler))
{
texture->syncState();
ASSERT(static_cast<size_t>(textureUnitIndex) < mCompleteTextureCache.size());
ASSERT(mCompleteTextureCache[textureUnitIndex] == nullptr ||
mCompleteTextureCache[textureUnitIndex] == texture);
mCompleteTextureCache[textureUnitIndex] = texture;
}
else
{
mCompleteTextureCache[textureUnitIndex] = nullptr;
}
// Bind the texture unconditionally, to recieve completeness change notifications.
mCompleteTextureBindings[textureUnitIndex].bind(texture->getDirtyChannel());
newActiveTextures.set(textureUnitIndex);
mCompleteTexturesMask.set(textureUnitIndex);
}
if (sampler != nullptr)
......@@ -2255,6 +2256,18 @@ void State::syncProgramTextures(const Context *context)
}
}
}
// Unset now missing textures.
ActiveTextureMask negativeMask = mCompleteTexturesMask & ~newActiveTextures;
if (negativeMask.any())
{
for (auto textureIndex : negativeMask)
{
mCompleteTextureBindings[textureIndex].reset();
mCompleteTextureCache[textureIndex] = nullptr;
mCompleteTexturesMask.reset(textureIndex);
}
}
}
void State::syncDirtyObject(const Context *context, GLenum target)
......
......@@ -559,6 +559,8 @@ class State : public OnAttachmentDirtyReceiver, angle::NonCopyable
// Also stores a notification channel to the texture itself to handle texture change events.
std::vector<Texture *> mCompleteTextureCache;
std::vector<OnAttachmentDirtyBinding> mCompleteTextureBindings;
using ActiveTextureMask = angle::BitSet<IMPLEMENTATION_MAX_ACTIVE_TEXTURES>;
ActiveTextureMask mCompleteTexturesMask;
typedef std::vector<BindingPointer<Sampler>> SamplerBindingVector;
SamplerBindingVector mSamplers;
......
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