Commit 4f7edbe1 by Jamie Madill Committed by Commit Bot

State: Add dirty object for active textures.

Checking sampler completeness after every sampler related state change is inefficient. Defer sampler completeness check to draw time. Based on a CL by hckim.kim@samsung.com. Bug: angleproject:4765 Tests: angle_perftests.exe --gtest_filter=TexturesBenchmark.* Change-Id: I7e971371e40b3044ca3d5ca39bfe7fc600620c3e Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2268577 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 24c2f0e7
...@@ -481,6 +481,7 @@ void Context::initialize() ...@@ -481,6 +481,7 @@ void Context::initialize()
// Initialize dirty bit masks // Initialize dirty bit masks
mAllDirtyBits.set(); mAllDirtyBits.set();
mDrawDirtyObjects.set(State::DIRTY_OBJECT_ACTIVE_TEXTURES);
mDrawDirtyObjects.set(State::DIRTY_OBJECT_DRAW_FRAMEBUFFER); mDrawDirtyObjects.set(State::DIRTY_OBJECT_DRAW_FRAMEBUFFER);
mDrawDirtyObjects.set(State::DIRTY_OBJECT_VERTEX_ARRAY); mDrawDirtyObjects.set(State::DIRTY_OBJECT_VERTEX_ARRAY);
mDrawDirtyObjects.set(State::DIRTY_OBJECT_TEXTURES); mDrawDirtyObjects.set(State::DIRTY_OBJECT_TEXTURES);
...@@ -532,6 +533,7 @@ void Context::initialize() ...@@ -532,6 +533,7 @@ void Context::initialize()
mComputeDirtyBits.set(State::DIRTY_BIT_SAMPLER_BINDINGS); mComputeDirtyBits.set(State::DIRTY_BIT_SAMPLER_BINDINGS);
mComputeDirtyBits.set(State::DIRTY_BIT_IMAGE_BINDINGS); mComputeDirtyBits.set(State::DIRTY_BIT_IMAGE_BINDINGS);
mComputeDirtyBits.set(State::DIRTY_BIT_DISPATCH_INDIRECT_BUFFER_BINDING); mComputeDirtyBits.set(State::DIRTY_BIT_DISPATCH_INDIRECT_BUFFER_BINDING);
mComputeDirtyObjects.set(State::DIRTY_OBJECT_ACTIVE_TEXTURES);
mComputeDirtyObjects.set(State::DIRTY_OBJECT_TEXTURES); mComputeDirtyObjects.set(State::DIRTY_OBJECT_TEXTURES);
mComputeDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM); mComputeDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM);
mComputeDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM_PIPELINE); mComputeDirtyObjects.set(State::DIRTY_OBJECT_PROGRAM_PIPELINE);
......
...@@ -504,13 +504,15 @@ void State::initialize(Context *context) ...@@ -504,13 +504,15 @@ void State::initialize(Context *context)
void State::reset(const Context *context) void State::reset(const Context *context)
{ {
// Force a sync so clear doesn't end up deferencing stale pointers.
(void)syncActiveTextures(context, Command::Other);
mActiveTexturesCache.clear(); mActiveTexturesCache.clear();
for (auto &bindingVec : mSamplerTextures) for (TextureBindingVector &bindingVec : mSamplerTextures)
{ {
for (size_t textureIdx = 0; textureIdx < bindingVec.size(); textureIdx++) for (BindingPointer<Texture> &texBinding : bindingVec)
{ {
bindingVec[textureIdx].set(context, nullptr); texBinding.set(context, nullptr);
} }
} }
for (size_t samplerIdx = 0; samplerIdx < mSamplers.size(); samplerIdx++) for (size_t samplerIdx = 0; samplerIdx < mSamplers.size(); samplerIdx++)
...@@ -518,7 +520,7 @@ void State::reset(const Context *context) ...@@ -518,7 +520,7 @@ void State::reset(const Context *context)
mSamplers[samplerIdx].set(context, nullptr); mSamplers[samplerIdx].set(context, nullptr);
} }
for (auto &imageUnit : mImageUnits) for (ImageUnit &imageUnit : mImageUnits)
{ {
imageUnit.texture.set(context, nullptr); imageUnit.texture.set(context, nullptr);
imageUnit.level = 0; imageUnit.level = 0;
...@@ -530,7 +532,7 @@ void State::reset(const Context *context) ...@@ -530,7 +532,7 @@ void State::reset(const Context *context)
mRenderbuffer.set(context, nullptr); mRenderbuffer.set(context, nullptr);
for (auto type : angle::AllEnums<BufferBinding>()) for (BufferBinding type : angle::AllEnums<BufferBinding>())
{ {
UpdateBufferBinding(context, &mBoundBuffers[type], nullptr, type); UpdateBufferBinding(context, &mBoundBuffers[type], nullptr, type);
} }
...@@ -554,17 +556,17 @@ void State::reset(const Context *context) ...@@ -554,17 +556,17 @@ void State::reset(const Context *context)
mActiveQueries[type].set(context, nullptr); mActiveQueries[type].set(context, nullptr);
} }
for (auto &buf : mUniformBuffers) for (OffsetBindingPointer<Buffer> &buf : mUniformBuffers)
{ {
UpdateIndexedBufferBinding(context, &buf, nullptr, BufferBinding::Uniform, 0, 0); UpdateIndexedBufferBinding(context, &buf, nullptr, BufferBinding::Uniform, 0, 0);
} }
for (auto &buf : mAtomicCounterBuffers) for (OffsetBindingPointer<Buffer> &buf : mAtomicCounterBuffers)
{ {
UpdateIndexedBufferBinding(context, &buf, nullptr, BufferBinding::AtomicCounter, 0, 0); UpdateIndexedBufferBinding(context, &buf, nullptr, BufferBinding::AtomicCounter, 0, 0);
} }
for (auto &buf : mShaderStorageBuffers) for (OffsetBindingPointer<Buffer> &buf : mShaderStorageBuffers)
{ {
UpdateIndexedBufferBinding(context, &buf, nullptr, BufferBinding::ShaderStorage, 0, 0); UpdateIndexedBufferBinding(context, &buf, nullptr, BufferBinding::ShaderStorage, 0, 0);
} }
...@@ -584,10 +586,10 @@ ANGLE_INLINE void State::unsetActiveTextures(ActiveTextureMask textureMask) ...@@ -584,10 +586,10 @@ ANGLE_INLINE void State::unsetActiveTextures(ActiveTextureMask textureMask)
} }
} }
ANGLE_INLINE void State::updateActiveTextureState(const Context *context, ANGLE_INLINE void State::updateActiveTextureStateOnSync(const Context *context,
size_t textureIndex, size_t textureIndex,
const Sampler *sampler, const Sampler *sampler,
Texture *texture) Texture *texture)
{ {
if (!texture || !texture->isSamplerComplete(context, sampler)) if (!texture || !texture->isSamplerComplete(context, sampler))
{ {
...@@ -596,20 +598,36 @@ ANGLE_INLINE void State::updateActiveTextureState(const Context *context, ...@@ -596,20 +598,36 @@ ANGLE_INLINE void State::updateActiveTextureState(const Context *context,
else else
{ {
mActiveTexturesCache.set(textureIndex, texture); mActiveTexturesCache.set(textureIndex, texture);
}
if (texture->hasAnyDirtyBit()) mDirtyBits.set(DIRTY_BIT_TEXTURE_BINDINGS);
{ }
setTextureDirty(textureIndex);
}
if (mRobustResourceInit && texture->initState() == InitState::MayNeedInit) ANGLE_INLINE void State::setActiveTextureDirty(size_t textureIndex, Texture *texture)
{ {
mDirtyObjects.set(DIRTY_OBJECT_TEXTURES_INIT); mDirtyObjects.set(DIRTY_OBJECT_ACTIVE_TEXTURES);
} mDirtyActiveTextures.set(textureIndex);
if (!texture)
{
return;
}
if (texture->hasAnyDirtyBit())
{
setTextureDirty(textureIndex);
} }
if (mRobustResourceInit && texture->initState() == InitState::MayNeedInit)
{
mDirtyObjects.set(DIRTY_OBJECT_TEXTURES_INIT);
}
// This cache is updated immediately because we use the cache in the validation layer.
// If we defer the update until syncState it's too late and we've already passed validation.
if (texture && mExecutable) if (texture && mExecutable)
{ {
const Sampler *sampler = mSamplers[textureIndex].get();
const SamplerState &samplerState = const SamplerState &samplerState =
sampler ? sampler->getSamplerState() : texture->getSamplerState(); sampler ? sampler->getSamplerState() : texture->getSamplerState();
mTexturesIncompatibleWithSamplers[textureIndex] = mTexturesIncompatibleWithSamplers[textureIndex] =
...@@ -620,26 +638,15 @@ ANGLE_INLINE void State::updateActiveTextureState(const Context *context, ...@@ -620,26 +638,15 @@ ANGLE_INLINE void State::updateActiveTextureState(const Context *context,
{ {
mTexturesIncompatibleWithSamplers[textureIndex] = false; mTexturesIncompatibleWithSamplers[textureIndex] = false;
} }
mDirtyBits.set(DIRTY_BIT_TEXTURE_BINDINGS);
} }
ANGLE_INLINE void State::updateActiveTexture(const Context *context, ANGLE_INLINE void State::updateTextureBinding(const Context *context,
size_t textureIndex, size_t textureIndex,
Texture *texture) Texture *texture)
{ {
const Sampler *sampler = mSamplers[textureIndex].get();
mCompleteTextureBindings[textureIndex].bind(texture); mCompleteTextureBindings[textureIndex].bind(texture);
mActiveTexturesCache.reset(textureIndex);
if (!texture) setActiveTextureDirty(textureIndex, texture);
{
mActiveTexturesCache.reset(textureIndex);
mDirtyBits.set(DIRTY_BIT_TEXTURE_BINDINGS);
return;
}
updateActiveTextureState(context, textureIndex, sampler, texture);
} }
ANGLE_INLINE bool State::hasConstantColor(GLenum sourceRGB, GLenum destRGB) const ANGLE_INLINE bool State::hasConstantColor(GLenum sourceRGB, GLenum destRGB) const
...@@ -1465,7 +1472,7 @@ void State::setSamplerTexture(const Context *context, TextureType type, Texture ...@@ -1465,7 +1472,7 @@ void State::setSamplerTexture(const Context *context, TextureType type, Texture
if (mExecutable && mExecutable->getActiveSamplersMask()[mActiveSampler] && if (mExecutable && mExecutable->getActiveSamplersMask()[mActiveSampler] &&
IsTextureCompatibleWithSampler(type, mExecutable->getActiveSamplerTypes()[mActiveSampler])) IsTextureCompatibleWithSampler(type, mExecutable->getActiveSamplerTypes()[mActiveSampler]))
{ {
updateActiveTexture(context, mActiveSampler, texture); updateTextureBinding(context, mActiveSampler, texture);
} }
mSamplerTextures[type][mActiveSampler].set(context, texture); mSamplerTextures[type][mActiveSampler].set(context, texture);
...@@ -1509,7 +1516,7 @@ void State::detachTexture(const Context *context, const TextureMap &zeroTextures ...@@ -1509,7 +1516,7 @@ void State::detachTexture(const Context *context, const TextureMap &zeroTextures
ASSERT(zeroTexture != nullptr); ASSERT(zeroTexture != nullptr);
if (mCompleteTextureBindings[bindingIndex].getSubject() == binding.get()) if (mCompleteTextureBindings[bindingIndex].getSubject() == binding.get())
{ {
updateActiveTexture(context, bindingIndex, zeroTexture); updateTextureBinding(context, bindingIndex, zeroTexture);
} }
binding.set(context, zeroTexture); binding.set(context, zeroTexture);
} }
...@@ -1573,7 +1580,6 @@ void State::setSamplerBinding(const Context *context, GLuint textureUnit, Sample ...@@ -1573,7 +1580,6 @@ void State::setSamplerBinding(const Context *context, GLuint textureUnit, Sample
// This is overly conservative as it assumes the sampler has never been bound. // This is overly conservative as it assumes the sampler has never been bound.
setSamplerDirty(textureUnit); setSamplerDirty(textureUnit);
onActiveTextureChange(context, textureUnit); onActiveTextureChange(context, textureUnit);
onActiveTextureStateChange(context, textureUnit);
} }
void State::detachSampler(const Context *context, SamplerID sampler) void State::detachSampler(const Context *context, SamplerID sampler)
...@@ -3044,6 +3050,31 @@ Texture *State::getTextureForActiveSampler(TextureType type, size_t index) ...@@ -3044,6 +3050,31 @@ Texture *State::getTextureForActiveSampler(TextureType type, size_t index)
return mSamplerTextures[type][index].get(); return mSamplerTextures[type][index].get();
} }
angle::Result State::syncActiveTextures(const Context *context, Command command)
{
if (mDirtyActiveTextures.none())
{
return angle::Result::Continue;
}
for (size_t textureUnit : mDirtyActiveTextures)
{
if (mExecutable)
{
TextureType type = mExecutable->getActiveSamplerTypes()[textureUnit];
Texture *activeTexture = (type != TextureType::InvalidEnum)
? getTextureForActiveSampler(type, textureUnit)
: nullptr;
const Sampler *sampler = mSamplers[textureUnit].get();
updateActiveTextureStateOnSync(context, textureUnit, sampler, activeTexture);
}
}
mDirtyActiveTextures.reset();
return angle::Result::Continue;
}
angle::Result State::syncTexturesInit(const Context *context, Command command) angle::Result State::syncTexturesInit(const Context *context, Command command)
{ {
ASSERT(mRobustResourceInit); ASSERT(mRobustResourceInit);
...@@ -3276,7 +3307,7 @@ angle::Result State::onProgramExecutableChange(const Context *context, Program * ...@@ -3276,7 +3307,7 @@ angle::Result State::onProgramExecutableChange(const Context *context, Program *
continue; continue;
Texture *texture = getTextureForActiveSampler(type, textureIndex); Texture *texture = getTextureForActiveSampler(type, textureIndex);
updateActiveTexture(context, textureIndex, texture); updateTextureBinding(context, textureIndex, texture);
} }
for (size_t imageUnitIndex : executable.getActiveImagesMask()) for (size_t imageUnitIndex : executable.getActiveImagesMask())
...@@ -3321,7 +3352,7 @@ angle::Result State::onProgramPipelineExecutableChange(const Context *context, ...@@ -3321,7 +3352,7 @@ angle::Result State::onProgramPipelineExecutableChange(const Context *context,
continue; continue;
Texture *texture = getTextureForActiveSampler(type, textureIndex); Texture *texture = getTextureForActiveSampler(type, textureIndex);
updateActiveTexture(context, textureIndex, texture); updateTextureBinding(context, textureIndex, texture);
} }
for (size_t imageUnitIndex : programPipeline->getExecutable().getActiveImagesMask()) for (size_t imageUnitIndex : programPipeline->getExecutable().getActiveImagesMask())
...@@ -3391,7 +3422,7 @@ void State::onActiveTextureChange(const Context *context, size_t textureUnit) ...@@ -3391,7 +3422,7 @@ void State::onActiveTextureChange(const Context *context, size_t textureUnit)
Texture *activeTexture = (type != TextureType::InvalidEnum) Texture *activeTexture = (type != TextureType::InvalidEnum)
? getTextureForActiveSampler(type, textureUnit) ? getTextureForActiveSampler(type, textureUnit)
: nullptr; : nullptr;
updateActiveTexture(context, textureUnit, activeTexture); updateTextureBinding(context, textureUnit, activeTexture);
mExecutable->onStateChange(angle::SubjectMessage::SubjectChanged); mExecutable->onStateChange(angle::SubjectMessage::SubjectChanged);
} }
...@@ -3405,8 +3436,7 @@ void State::onActiveTextureStateChange(const Context *context, size_t textureUni ...@@ -3405,8 +3436,7 @@ void State::onActiveTextureStateChange(const Context *context, size_t textureUni
Texture *activeTexture = (type != TextureType::InvalidEnum) Texture *activeTexture = (type != TextureType::InvalidEnum)
? getTextureForActiveSampler(type, textureUnit) ? getTextureForActiveSampler(type, textureUnit)
: nullptr; : nullptr;
const Sampler *sampler = mSamplers[textureUnit].get(); setActiveTextureDirty(textureUnit, activeTexture);
updateActiveTextureState(context, textureUnit, sampler, activeTexture);
} }
} }
......
...@@ -646,6 +646,7 @@ class State : angle::NonCopyable ...@@ -646,6 +646,7 @@ class State : angle::NonCopyable
// TODO(jmadill): Consider storing dirty objects in a list instead of by binding. // TODO(jmadill): Consider storing dirty objects in a list instead of by binding.
enum DirtyObjectType enum DirtyObjectType
{ {
DIRTY_OBJECT_ACTIVE_TEXTURES, // Top-level dirty bit. Also see mDirtyActiveTextures.
DIRTY_OBJECT_TEXTURES_INIT, DIRTY_OBJECT_TEXTURES_INIT,
DIRTY_OBJECT_IMAGES_INIT, DIRTY_OBJECT_IMAGES_INIT,
DIRTY_OBJECT_READ_ATTACHMENTS, DIRTY_OBJECT_READ_ATTACHMENTS,
...@@ -720,7 +721,7 @@ class State : angle::NonCopyable ...@@ -720,7 +721,7 @@ class State : angle::NonCopyable
// "onActiveTextureChange" is called when a texture binding changes. // "onActiveTextureChange" is called when a texture binding changes.
void onActiveTextureChange(const Context *context, size_t textureUnit); void onActiveTextureChange(const Context *context, size_t textureUnit);
// "onActiveTextureStateChange" calls when the Texture itself changed but the binding did not. // "onActiveTextureStateChange" is called when the Texture changed but the binding did not.
void onActiveTextureStateChange(const Context *context, size_t textureUnit); void onActiveTextureStateChange(const Context *context, size_t textureUnit);
void onImageStateChange(const Context *context, size_t unit); void onImageStateChange(const Context *context, size_t unit);
...@@ -855,17 +856,19 @@ class State : angle::NonCopyable ...@@ -855,17 +856,19 @@ class State : angle::NonCopyable
friend class Context; friend class Context;
void unsetActiveTextures(ActiveTextureMask textureMask); void unsetActiveTextures(ActiveTextureMask textureMask);
void updateActiveTexture(const Context *context, size_t textureIndex, Texture *texture); void setActiveTextureDirty(size_t textureIndex, Texture *texture);
void updateActiveTextureState(const Context *context, void updateTextureBinding(const Context *context, size_t textureIndex, Texture *texture);
size_t textureIndex, void updateActiveTextureStateOnSync(const Context *context,
const Sampler *sampler, size_t textureIndex,
Texture *texture); const Sampler *sampler,
Texture *texture);
Texture *getTextureForActiveSampler(TextureType type, size_t index); Texture *getTextureForActiveSampler(TextureType type, size_t index);
bool hasConstantColor(GLenum sourceRGB, GLenum destRGB) const; bool hasConstantColor(GLenum sourceRGB, GLenum destRGB) const;
bool hasConstantAlpha(GLenum sourceRGB, GLenum destRGB) const; bool hasConstantAlpha(GLenum sourceRGB, GLenum destRGB) const;
// Functions to synchronize dirty states // Functions to synchronize dirty states
angle::Result syncActiveTextures(const Context *context, Command command);
angle::Result syncTexturesInit(const Context *context, Command command); angle::Result syncTexturesInit(const Context *context, Command command);
angle::Result syncImagesInit(const Context *context, Command command); angle::Result syncImagesInit(const Context *context, Command command);
angle::Result syncReadAttachments(const Context *context, Command command); angle::Result syncReadAttachments(const Context *context, Command command);
...@@ -881,30 +884,33 @@ class State : angle::NonCopyable ...@@ -881,30 +884,33 @@ class State : angle::NonCopyable
using DirtyObjectHandler = angle::Result (State::*)(const Context *context, Command command); using DirtyObjectHandler = angle::Result (State::*)(const Context *context, Command command);
static constexpr DirtyObjectHandler kDirtyObjectHandlers[DIRTY_OBJECT_MAX] = { static constexpr DirtyObjectHandler kDirtyObjectHandlers[DIRTY_OBJECT_MAX] = {
&State::syncTexturesInit, &State::syncImagesInit, &State::syncReadAttachments, &State::syncActiveTextures, &State::syncTexturesInit, &State::syncImagesInit,
&State::syncDrawAttachments, &State::syncReadFramebuffer, &State::syncDrawFramebuffer, &State::syncReadAttachments, &State::syncDrawAttachments, &State::syncReadFramebuffer,
&State::syncVertexArray, &State::syncTextures, &State::syncImages, &State::syncDrawFramebuffer, &State::syncVertexArray, &State::syncTextures,
&State::syncSamplers, &State::syncProgram, &State::syncProgramPipeline, &State::syncImages, &State::syncSamplers, &State::syncProgram,
&State::syncProgramPipeline,
}; };
// Robust init must happen before Framebuffer init for the Vulkan back-end. // Robust init must happen before Framebuffer init for the Vulkan back-end.
static_assert(DIRTY_OBJECT_ACTIVE_TEXTURES < DIRTY_OBJECT_TEXTURES_INIT, "init order");
static_assert(DIRTY_OBJECT_TEXTURES_INIT < DIRTY_OBJECT_DRAW_FRAMEBUFFER, "init order"); static_assert(DIRTY_OBJECT_TEXTURES_INIT < DIRTY_OBJECT_DRAW_FRAMEBUFFER, "init order");
static_assert(DIRTY_OBJECT_IMAGES_INIT < DIRTY_OBJECT_DRAW_FRAMEBUFFER, "init order"); static_assert(DIRTY_OBJECT_IMAGES_INIT < DIRTY_OBJECT_DRAW_FRAMEBUFFER, "init order");
static_assert(DIRTY_OBJECT_DRAW_ATTACHMENTS < DIRTY_OBJECT_DRAW_FRAMEBUFFER, "init order"); static_assert(DIRTY_OBJECT_DRAW_ATTACHMENTS < DIRTY_OBJECT_DRAW_FRAMEBUFFER, "init order");
static_assert(DIRTY_OBJECT_READ_ATTACHMENTS < DIRTY_OBJECT_READ_FRAMEBUFFER, "init order"); static_assert(DIRTY_OBJECT_READ_ATTACHMENTS < DIRTY_OBJECT_READ_FRAMEBUFFER, "init order");
static_assert(DIRTY_OBJECT_TEXTURES_INIT == 0, "check DIRTY_OBJECT_TEXTURES_INIT index"); static_assert(DIRTY_OBJECT_ACTIVE_TEXTURES == 0, "check DIRTY_OBJECT_ACTIVE_TEXTURES index");
static_assert(DIRTY_OBJECT_IMAGES_INIT == 1, "check DIRTY_OBJECT_IMAGES_INIT index"); static_assert(DIRTY_OBJECT_TEXTURES_INIT == 1, "check DIRTY_OBJECT_TEXTURES_INIT index");
static_assert(DIRTY_OBJECT_READ_ATTACHMENTS == 2, "check DIRTY_OBJECT_READ_ATTACHMENTS index"); static_assert(DIRTY_OBJECT_IMAGES_INIT == 2, "check DIRTY_OBJECT_IMAGES_INIT index");
static_assert(DIRTY_OBJECT_DRAW_ATTACHMENTS == 3, "check DIRTY_OBJECT_DRAW_ATTACHMENTS index"); static_assert(DIRTY_OBJECT_READ_ATTACHMENTS == 3, "check DIRTY_OBJECT_READ_ATTACHMENTS index");
static_assert(DIRTY_OBJECT_READ_FRAMEBUFFER == 4, "check DIRTY_OBJECT_READ_FRAMEBUFFER index"); static_assert(DIRTY_OBJECT_DRAW_ATTACHMENTS == 4, "check DIRTY_OBJECT_DRAW_ATTACHMENTS index");
static_assert(DIRTY_OBJECT_DRAW_FRAMEBUFFER == 5, "check DIRTY_OBJECT_DRAW_FRAMEBUFFER index"); static_assert(DIRTY_OBJECT_READ_FRAMEBUFFER == 5, "check DIRTY_OBJECT_READ_FRAMEBUFFER index");
static_assert(DIRTY_OBJECT_VERTEX_ARRAY == 6, "check DIRTY_OBJECT_VERTEX_ARRAY index"); static_assert(DIRTY_OBJECT_DRAW_FRAMEBUFFER == 6, "check DIRTY_OBJECT_DRAW_FRAMEBUFFER index");
static_assert(DIRTY_OBJECT_TEXTURES == 7, "check DIRTY_OBJECT_TEXTURES index"); static_assert(DIRTY_OBJECT_VERTEX_ARRAY == 7, "check DIRTY_OBJECT_VERTEX_ARRAY index");
static_assert(DIRTY_OBJECT_IMAGES == 8, "check DIRTY_OBJECT_IMAGES index"); static_assert(DIRTY_OBJECT_TEXTURES == 8, "check DIRTY_OBJECT_TEXTURES index");
static_assert(DIRTY_OBJECT_SAMPLERS == 9, "check DIRTY_OBJECT_SAMPLERS index"); static_assert(DIRTY_OBJECT_IMAGES == 9, "check DIRTY_OBJECT_IMAGES index");
static_assert(DIRTY_OBJECT_PROGRAM == 10, "check DIRTY_OBJECT_PROGRAM index"); static_assert(DIRTY_OBJECT_SAMPLERS == 10, "check DIRTY_OBJECT_SAMPLERS index");
static_assert(DIRTY_OBJECT_PROGRAM_PIPELINE == 11, "check DIRTY_OBJECT_PROGRAM_PIPELINE index"); static_assert(DIRTY_OBJECT_PROGRAM == 11, "check DIRTY_OBJECT_PROGRAM index");
static_assert(DIRTY_OBJECT_PROGRAM_PIPELINE == 12, "check DIRTY_OBJECT_PROGRAM_PIPELINE index");
// Dispatch table for buffer update functions. // Dispatch table for buffer update functions.
static const angle::PackedEnumMap<BufferBinding, BufferBindingSetter> kBufferSetters; static const angle::PackedEnumMap<BufferBinding, BufferBindingSetter> kBufferSetters;
...@@ -995,20 +1001,15 @@ class State : angle::NonCopyable ...@@ -995,20 +1001,15 @@ class State : angle::NonCopyable
TextureBindingMap mSamplerTextures; TextureBindingMap mSamplerTextures;
// Texture Completeness Caching // Active Textures Cache
// ---------------------------- // ---------------------
// The texture completeness cache uses dirty bits to avoid having to scan the list of textures // The active textures cache gives ANGLE components access to a complete array of textures
// each draw call. This gl::State class implements angle::Observer interface. When subject // on a draw call. gl::State implements angle::Observer and watches gl::Texture for state
// Textures have state changes, messages reach 'State' (also any observing Framebuffers) via the // changes via the onSubjectStateChange method above. We update the cache before draws.
// onSubjectStateChange method (above). This then invalidates the completeness cache. // See Observer.h and the design doc linked there for more info on Subject/Observer events.
// //
// Note this requires that we also invalidate the completeness cache manually on events like // On state change events (re-binding textures, samplers, programs etc) we clear the cache
// re-binding textures/samplers or a change in the program. For more information see the // and flag dirty bits. nullptr indicates unbound or incomplete.
// Observer.h header and the design doc linked there.
// A cache of complete textures. nullptr indicates unbound or incomplete.
// Don't use BindingPointer because this cache is only valid within a draw call.
// Also stores a notification channel to the texture itself to handle texture change events.
ActiveTexturesCache mActiveTexturesCache; ActiveTexturesCache mActiveTexturesCache;
std::vector<angle::ObserverBinding> mCompleteTextureBindings; std::vector<angle::ObserverBinding> mCompleteTextureBindings;
...@@ -1068,6 +1069,7 @@ class State : angle::NonCopyable ...@@ -1068,6 +1069,7 @@ class State : angle::NonCopyable
DirtyBits mDirtyBits; DirtyBits mDirtyBits;
DirtyObjects mDirtyObjects; DirtyObjects mDirtyObjects;
mutable AttributesMask mDirtyCurrentValues; mutable AttributesMask mDirtyCurrentValues;
ActiveTextureMask mDirtyActiveTextures;
ActiveTextureMask mDirtyTextures; ActiveTextureMask mDirtyTextures;
ActiveTextureMask mDirtySamplers; ActiveTextureMask mDirtySamplers;
ImageUnitMask mDirtyImages; ImageUnitMask mDirtyImages;
......
...@@ -467,6 +467,11 @@ bool ValidateVertexShaderAttributeTypeMatch(const Context *context) ...@@ -467,6 +467,11 @@ bool ValidateVertexShaderAttributeTypeMatch(const Context *context)
const Program *program = context->getActiveLinkedProgram(); const Program *program = context->getActiveLinkedProgram();
const VertexArray *vao = context->getState().getVertexArray(); const VertexArray *vao = context->getState().getVertexArray();
if (!program)
{
return false;
}
unsigned long stateCurrentValuesTypeBits = glState.getCurrentValuesTypeMask().to_ulong(); unsigned long stateCurrentValuesTypeBits = glState.getCurrentValuesTypeMask().to_ulong();
unsigned long vaoAttribTypeBits = vao->getAttributesTypeMask().to_ulong(); unsigned long vaoAttribTypeBits = vao->getAttributesTypeMask().to_ulong();
unsigned long vaoAttribEnabledMask = vao->getAttributesMask().to_ulong(); unsigned long vaoAttribEnabledMask = vao->getAttributesMask().to_ulong();
...@@ -475,10 +480,10 @@ bool ValidateVertexShaderAttributeTypeMatch(const Context *context) ...@@ -475,10 +480,10 @@ bool ValidateVertexShaderAttributeTypeMatch(const Context *context)
vaoAttribTypeBits = (vaoAttribEnabledMask & vaoAttribTypeBits); vaoAttribTypeBits = (vaoAttribEnabledMask & vaoAttribTypeBits);
vaoAttribTypeBits |= (~vaoAttribEnabledMask & stateCurrentValuesTypeBits); vaoAttribTypeBits |= (~vaoAttribEnabledMask & stateCurrentValuesTypeBits);
return program && const ProgramExecutable &executable = program->getExecutable();
ValidateComponentTypeMasks( return ValidateComponentTypeMasks(executable.getAttributesTypeMask().to_ulong(),
program->getExecutable().getAttributesTypeMask().to_ulong(), vaoAttribTypeBits, vaoAttribTypeBits, executable.getAttributesMask().to_ulong(),
program->getExecutable().getAttributesMask().to_ulong(), 0xFFFF); 0xFFFF);
} }
bool IsCompatibleDrawModeWithGeometryShader(PrimitiveMode drawMode, bool IsCompatibleDrawModeWithGeometryShader(PrimitiveMode drawMode,
......
...@@ -273,27 +273,42 @@ void TexturesBenchmark::drawBenchmark() ...@@ -273,27 +273,42 @@ void TexturesBenchmark::drawBenchmark()
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
} }
TexturesParams D3D11Params(bool webglCompat) TexturesParams D3D11Params(bool webglCompat, bool frequentUpdate)
{ {
TexturesParams params; TexturesParams params;
params.eglParameters = egl_platform::D3D11_NULL(); params.eglParameters = egl_platform::D3D11_NULL();
params.webgl = webglCompat; params.webgl = webglCompat;
if (frequentUpdate)
{
params.textureRebindFrequency = 1;
params.textureStateUpdateFrequency = 1;
}
return params; return params;
} }
TexturesParams OpenGLOrGLESParams(bool webglCompat) TexturesParams OpenGLOrGLESParams(bool webglCompat, bool frequentUpdate)
{ {
TexturesParams params; TexturesParams params;
params.eglParameters = egl_platform::OPENGL_OR_GLES_NULL(); params.eglParameters = egl_platform::OPENGL_OR_GLES_NULL();
params.webgl = webglCompat; params.webgl = webglCompat;
if (frequentUpdate)
{
params.textureRebindFrequency = 1;
params.textureStateUpdateFrequency = 1;
}
return params; return params;
} }
TexturesParams VulkanParams(bool webglCompat) TexturesParams VulkanParams(bool webglCompat, bool frequentUpdate)
{ {
TexturesParams params; TexturesParams params;
params.eglParameters = egl_platform::VULKAN_NULL(); params.eglParameters = egl_platform::VULKAN_NULL();
params.webgl = webglCompat; params.webgl = webglCompat;
if (frequentUpdate)
{
params.textureRebindFrequency = 1;
params.textureStateUpdateFrequency = 1;
}
return params; return params;
} }
...@@ -303,10 +318,16 @@ TEST_P(TexturesBenchmark, Run) ...@@ -303,10 +318,16 @@ TEST_P(TexturesBenchmark, Run)
} }
ANGLE_INSTANTIATE_TEST(TexturesBenchmark, ANGLE_INSTANTIATE_TEST(TexturesBenchmark,
D3D11Params(false), D3D11Params(false, false),
D3D11Params(true), D3D11Params(true, false),
OpenGLOrGLESParams(false), D3D11Params(false, true),
OpenGLOrGLESParams(true), D3D11Params(true, true),
VulkanParams(false), OpenGLOrGLESParams(false, false),
VulkanParams(true)); OpenGLOrGLESParams(true, false),
OpenGLOrGLESParams(false, true),
OpenGLOrGLESParams(true, true),
VulkanParams(false, false),
VulkanParams(true, false),
VulkanParams(false, true),
VulkanParams(true, true));
} // namespace angle } // namespace angle
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