Commit e858cb1d by Jamie Madill Committed by Commit Bot

Split VAO dirty bits to speed iteration.

Using > 64 bits (we had over 90) would use a much slower dirty bit iteration. Speed this up by splitting the dirty bits into two levels. The first top level only has a single dirty bit per attrib, per binding, and one bit for the element array buffer. The next level has separate dirty bits for attribs and bindings. The D3D11 back-end doesn't actually care about individual dirty bits of attribs or bindings, since it resets entire attributes at a time, but the GL back-end only refreshes the necessary info. Improves the score of a simple state change microbenchmark by 15% on the D3D11 and GL back-ends with a no-op driver. Real-world impact will be smaller. Also includes a test suppression for an NVIDIA bug that surfaced when we changed the order of that GL commands were sent to the driver. BUG=angleproject:2389 Change-Id: If8d5e5eb0b27e2a77e20535e33626183d372d311 Reviewed-on: https://chromium-review.googlesource.com/556799Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarYuly Novikov <ynovikov@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent a0ccea1e
...@@ -111,7 +111,19 @@ size_t VertexArray::GetVertexIndexFromDirtyBit(size_t dirtyBit) ...@@ -111,7 +111,19 @@ size_t VertexArray::GetVertexIndexFromDirtyBit(size_t dirtyBit)
static_assert(gl::MAX_VERTEX_ATTRIBS == gl::MAX_VERTEX_ATTRIB_BINDINGS, static_assert(gl::MAX_VERTEX_ATTRIBS == gl::MAX_VERTEX_ATTRIB_BINDINGS,
"The stride of vertex attributes should equal to that of vertex bindings."); "The stride of vertex attributes should equal to that of vertex bindings.");
ASSERT(dirtyBit > DIRTY_BIT_ELEMENT_ARRAY_BUFFER); ASSERT(dirtyBit > DIRTY_BIT_ELEMENT_ARRAY_BUFFER);
return (dirtyBit - DIRTY_BIT_ATTRIB_0_ENABLED) % gl::MAX_VERTEX_ATTRIBS; return (dirtyBit - DIRTY_BIT_ATTRIB_0) % gl::MAX_VERTEX_ATTRIBS;
}
void VertexArray::setDirtyAttribBit(size_t attribIndex, DirtyAttribBitType dirtyAttribBit)
{
mDirtyBits.set(DIRTY_BIT_ATTRIB_0 + attribIndex);
mDirtyAttribBits[attribIndex].set(dirtyAttribBit);
}
void VertexArray::setDirtyBindingBit(size_t bindingIndex, DirtyBindingBitType dirtyBindingBit)
{
mDirtyBits.set(DIRTY_BIT_BINDING_0 + bindingIndex);
mDirtyBindingBits[bindingIndex].set(dirtyBindingBit);
} }
void VertexArray::bindVertexBufferImpl(const Context *context, void VertexArray::bindVertexBufferImpl(const Context *context,
...@@ -137,8 +149,7 @@ void VertexArray::bindVertexBuffer(const Context *context, ...@@ -137,8 +149,7 @@ void VertexArray::bindVertexBuffer(const Context *context,
GLsizei stride) GLsizei stride)
{ {
bindVertexBufferImpl(context, bindingIndex, boundBuffer, offset, stride); bindVertexBufferImpl(context, bindingIndex, boundBuffer, offset, stride);
setDirtyBindingBit(bindingIndex, DIRTY_BINDING_BUFFER);
mDirtyBits.set(DIRTY_BIT_BINDING_0_BUFFER + bindingIndex);
} }
void VertexArray::setVertexAttribBinding(const Context *context, void VertexArray::setVertexAttribBinding(const Context *context,
...@@ -153,8 +164,9 @@ void VertexArray::setVertexAttribBinding(const Context *context, ...@@ -153,8 +164,9 @@ void VertexArray::setVertexAttribBinding(const Context *context,
ASSERT(context->getClientVersion() >= ES_3_1); ASSERT(context->getClientVersion() >= ES_3_1);
mState.mVertexAttributes[attribIndex].bindingIndex = bindingIndex; mState.mVertexAttributes[attribIndex].bindingIndex = bindingIndex;
mDirtyBits.set(DIRTY_BIT_ATTRIB_0_BINDING + attribIndex); setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_BINDING);
} }
mState.mVertexAttributes[attribIndex].bindingIndex = static_cast<GLuint>(bindingIndex);
} }
void VertexArray::setVertexBindingDivisor(size_t bindingIndex, GLuint divisor) void VertexArray::setVertexBindingDivisor(size_t bindingIndex, GLuint divisor)
...@@ -162,8 +174,7 @@ void VertexArray::setVertexBindingDivisor(size_t bindingIndex, GLuint divisor) ...@@ -162,8 +174,7 @@ void VertexArray::setVertexBindingDivisor(size_t bindingIndex, GLuint divisor)
ASSERT(bindingIndex < getMaxBindings()); ASSERT(bindingIndex < getMaxBindings());
mState.mVertexBindings[bindingIndex].setDivisor(divisor); mState.mVertexBindings[bindingIndex].setDivisor(divisor);
setDirtyBindingBit(bindingIndex, DIRTY_BINDING_DIVISOR);
mDirtyBits.set(DIRTY_BIT_BINDING_0_DIVISOR + bindingIndex);
} }
void VertexArray::setVertexAttribFormatImpl(size_t attribIndex, void VertexArray::setVertexAttribFormatImpl(size_t attribIndex,
...@@ -194,8 +205,7 @@ void VertexArray::setVertexAttribFormat(size_t attribIndex, ...@@ -194,8 +205,7 @@ void VertexArray::setVertexAttribFormat(size_t attribIndex,
GLuint relativeOffset) GLuint relativeOffset)
{ {
setVertexAttribFormatImpl(attribIndex, size, type, normalized, pureInteger, relativeOffset); setVertexAttribFormatImpl(attribIndex, size, type, normalized, pureInteger, relativeOffset);
setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_FORMAT);
mDirtyBits.set(DIRTY_BIT_ATTRIB_0_FORMAT + attribIndex);
} }
void VertexArray::setVertexAttribDivisor(const Context *context, size_t attribIndex, GLuint divisor) void VertexArray::setVertexAttribDivisor(const Context *context, size_t attribIndex, GLuint divisor)
...@@ -214,7 +224,7 @@ void VertexArray::enableAttribute(size_t attribIndex, bool enabledState) ...@@ -214,7 +224,7 @@ void VertexArray::enableAttribute(size_t attribIndex, bool enabledState)
mState.mVertexAttributesTypeMask.setIndex( mState.mVertexAttributesTypeMask.setIndex(
GetVertexAttributeBaseType(mState.mVertexAttributes[attribIndex]), attribIndex); GetVertexAttributeBaseType(mState.mVertexAttributes[attribIndex]), attribIndex);
mDirtyBits.set(DIRTY_BIT_ATTRIB_0_ENABLED + attribIndex); setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_ENABLED);
// Update state cache // Update state cache
mState.mEnabledAttributesMask.set(attribIndex, enabledState); mState.mEnabledAttributesMask.set(attribIndex, enabledState);
...@@ -246,7 +256,7 @@ void VertexArray::setVertexAttribPointer(const Context *context, ...@@ -246,7 +256,7 @@ void VertexArray::setVertexAttribPointer(const Context *context,
bindVertexBufferImpl(context, attribIndex, boundBuffer, offset, effectiveStride); bindVertexBufferImpl(context, attribIndex, boundBuffer, offset, effectiveStride);
mDirtyBits.set(DIRTY_BIT_ATTRIB_0_POINTER + attribIndex); setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_POINTER);
} }
void VertexArray::setElementArrayBuffer(const Context *context, Buffer *buffer) void VertexArray::setElementArrayBuffer(const Context *context, Buffer *buffer)
...@@ -264,8 +274,15 @@ void VertexArray::syncState(const Context *context) ...@@ -264,8 +274,15 @@ void VertexArray::syncState(const Context *context)
{ {
if (mDirtyBits.any()) if (mDirtyBits.any())
{ {
mVertexArray->syncState(context, mDirtyBits); mVertexArray->syncState(context, mDirtyBits, mDirtyAttribBits, mDirtyBindingBits);
mDirtyBits.reset(); mDirtyBits.reset();
// This is a bit of an implementation hack - but since we know the implementation
// details of the dirty bit class it should always have the same effect as iterating
// individual attribs. We could also look into schemes where iterating the dirty
// bit set also resets it as you pass through it.
memset(&mDirtyAttribBits, 0, sizeof(mDirtyAttribBits));
memset(&mDirtyBindingBits, 0, sizeof(mDirtyBindingBits));
} }
} }
......
...@@ -153,40 +153,54 @@ class VertexArray final : public LabeledObject ...@@ -153,40 +153,54 @@ class VertexArray final : public LabeledObject
return mState.getEnabledAttributesMask(); return mState.getEnabledAttributesMask();
} }
// Dirty bits for VertexArrays use a heirarchical design. At the top level, each attribute
// has a single dirty bit. Then an array of MAX_ATTRIBS dirty bits each has a dirty bit for
// enabled/pointer/format/binding. Bindings are handled similarly. Note that because the
// total number of dirty bits is 33, it will not be as fast on a 32-bit machine, which
// can't support the advanced 64-bit scanning intrinsics. We could consider packing the
// binding and attribute bits together if this becomes a problem.
enum DirtyBitType enum DirtyBitType
{ {
DIRTY_BIT_ELEMENT_ARRAY_BUFFER, DIRTY_BIT_ELEMENT_ARRAY_BUFFER,
// Reserve bits for enabled flags // Dirty bits for attributes.
DIRTY_BIT_ATTRIB_0_ENABLED, DIRTY_BIT_ATTRIB_0,
DIRTY_BIT_ATTRIB_MAX_ENABLED = DIRTY_BIT_ATTRIB_0_ENABLED + gl::MAX_VERTEX_ATTRIBS, DIRTY_BIT_ATTRIB_MAX = DIRTY_BIT_ATTRIB_0 + gl::MAX_VERTEX_ATTRIBS,
// Reserve bits for attrib pointers // Dirty bits for bindings.
DIRTY_BIT_ATTRIB_0_POINTER = DIRTY_BIT_ATTRIB_MAX_ENABLED, DIRTY_BIT_BINDING_0 = DIRTY_BIT_ATTRIB_MAX,
DIRTY_BIT_ATTRIB_MAX_POINTER = DIRTY_BIT_ATTRIB_0_POINTER + gl::MAX_VERTEX_ATTRIBS, DIRTY_BIT_BINDING_MAX = DIRTY_BIT_BINDING_0 + gl::MAX_VERTEX_ATTRIB_BINDINGS,
// Reserve bits for changes to VertexAttribFormat DIRTY_BIT_UNKNOWN = DIRTY_BIT_BINDING_MAX,
DIRTY_BIT_ATTRIB_0_FORMAT = DIRTY_BIT_ATTRIB_MAX_POINTER, DIRTY_BIT_MAX = DIRTY_BIT_UNKNOWN,
DIRTY_BIT_ATTRIB_MAX_FORMAT = DIRTY_BIT_ATTRIB_0_FORMAT + gl::MAX_VERTEX_ATTRIBS, };
// Reserve bits for changes to VertexAttribBinding
DIRTY_BIT_ATTRIB_0_BINDING = DIRTY_BIT_ATTRIB_MAX_FORMAT,
DIRTY_BIT_ATTRIB_MAX_BINDING = DIRTY_BIT_ATTRIB_0_BINDING + gl::MAX_VERTEX_ATTRIBS,
// Reserve bits for changes to BindVertexBuffer // We want to keep the number of dirty bits within 64 to keep iteration times fast.
DIRTY_BIT_BINDING_0_BUFFER = DIRTY_BIT_ATTRIB_MAX_BINDING, static_assert(DIRTY_BIT_MAX <= 64, "Too many vertex array dirty bits.");
DIRTY_BIT_BINDING_MAX_BUFFER = DIRTY_BIT_BINDING_0_BUFFER + gl::MAX_VERTEX_ATTRIB_BINDINGS,
// Reserve bits for binding divisors enum DirtyAttribBitType
DIRTY_BIT_BINDING_0_DIVISOR = DIRTY_BIT_BINDING_MAX_BUFFER, {
DIRTY_BIT_BINDING_MAX_DIVISOR = DIRTY_ATTRIB_ENABLED,
DIRTY_BIT_BINDING_0_DIVISOR + gl::MAX_VERTEX_ATTRIB_BINDINGS, DIRTY_ATTRIB_POINTER,
DIRTY_ATTRIB_FORMAT,
DIRTY_ATTRIB_BINDING,
DIRTY_ATTRIB_UNKNOWN,
DIRTY_ATTRIB_MAX = DIRTY_ATTRIB_UNKNOWN,
};
DIRTY_BIT_UNKNOWN = DIRTY_BIT_BINDING_MAX_DIVISOR, enum DirtyBindingBitType
DIRTY_BIT_MAX = DIRTY_BIT_UNKNOWN, {
DIRTY_BINDING_BUFFER,
DIRTY_BINDING_DIVISOR,
DIRTY_BINDING_UNKNOWN,
DIRTY_BINDING_MAX = DIRTY_BINDING_UNKNOWN,
}; };
using DirtyBits = angle::BitSet<DIRTY_BIT_MAX>; using DirtyBits = angle::BitSet<DIRTY_BIT_MAX>;
using DirtyAttribBits = angle::BitSet<DIRTY_ATTRIB_MAX>;
using DirtyBindingBits = angle::BitSet<DIRTY_BINDING_MAX>;
using DirtyAttribBitsArray = std::array<DirtyAttribBits, gl::MAX_VERTEX_ATTRIBS>;
using DirtyBindingBitsArray = std::array<DirtyBindingBits, gl::MAX_VERTEX_ATTRIB_BINDINGS>;
static size_t GetVertexIndexFromDirtyBit(size_t dirtyBit); static size_t GetVertexIndexFromDirtyBit(size_t dirtyBit);
...@@ -201,10 +215,15 @@ class VertexArray final : public LabeledObject ...@@ -201,10 +215,15 @@ class VertexArray final : public LabeledObject
private: private:
~VertexArray() override; ~VertexArray() override;
void setDirtyAttribBit(size_t attribIndex, DirtyAttribBitType dirtyAttribBit);
void setDirtyBindingBit(size_t bindingIndex, DirtyBindingBitType dirtyBindingBit);
GLuint mId; GLuint mId;
VertexArrayState mState; VertexArrayState mState;
DirtyBits mDirtyBits; DirtyBits mDirtyBits;
DirtyAttribBitsArray mDirtyAttribBits;
DirtyBindingBitsArray mDirtyBindingBits;
rx::VertexArrayImpl *mVertexArray; rx::VertexArrayImpl *mVertexArray;
}; };
......
...@@ -19,7 +19,7 @@ using namespace gl; ...@@ -19,7 +19,7 @@ using namespace gl;
TEST(VertexArrayTest, VerifyGetIndexFromDirtyBit) TEST(VertexArrayTest, VerifyGetIndexFromDirtyBit)
{ {
VertexArray::DirtyBits dirtyBits; VertexArray::DirtyBits dirtyBits;
constexpr size_t bits[] = {1, 4, 9, 16, 25, 36, 49, 64, 81, 92}; constexpr size_t bits[] = {1, 4, 9, 16, 25};
constexpr GLint count = sizeof(bits) / sizeof(size_t); constexpr GLint count = sizeof(bits) / sizeof(size_t);
for (GLint i = 0; i < count; i++) for (GLint i = 0; i < count; i++)
{ {
...@@ -29,29 +29,13 @@ TEST(VertexArrayTest, VerifyGetIndexFromDirtyBit) ...@@ -29,29 +29,13 @@ TEST(VertexArrayTest, VerifyGetIndexFromDirtyBit)
for (size_t dirtyBit : dirtyBits) for (size_t dirtyBit : dirtyBits)
{ {
const size_t index = VertexArray::GetVertexIndexFromDirtyBit(dirtyBit); const size_t index = VertexArray::GetVertexIndexFromDirtyBit(dirtyBit);
if (dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_ENABLED) if (dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX)
{ {
EXPECT_EQ(dirtyBit - VertexArray::DIRTY_BIT_ATTRIB_0_ENABLED, index); EXPECT_EQ(dirtyBit - VertexArray::DIRTY_BIT_ATTRIB_0, index);
} }
else if (dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_POINTER) else if (dirtyBit < VertexArray::DIRTY_BIT_BINDING_MAX)
{ {
EXPECT_EQ(dirtyBit - VertexArray::DIRTY_BIT_ATTRIB_0_POINTER, index); EXPECT_EQ(dirtyBit - VertexArray::DIRTY_BIT_BINDING_0, index);
}
else if (dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_FORMAT)
{
EXPECT_EQ(dirtyBit - VertexArray::DIRTY_BIT_ATTRIB_0_FORMAT, index);
}
else if (dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_BINDING)
{
EXPECT_EQ(dirtyBit - VertexArray::DIRTY_BIT_ATTRIB_0_BINDING, index);
}
else if (dirtyBit < VertexArray::DIRTY_BIT_BINDING_MAX_BUFFER)
{
EXPECT_EQ(dirtyBit - VertexArray::DIRTY_BIT_BINDING_0_BUFFER, index);
}
else if (dirtyBit < VertexArray::DIRTY_BIT_BINDING_MAX_DIVISOR)
{
EXPECT_EQ(dirtyBit - VertexArray::DIRTY_BIT_BINDING_0_DIVISOR, index);
} }
else else
ASSERT_TRUE(false); ASSERT_TRUE(false);
......
...@@ -21,7 +21,10 @@ class VertexArrayImpl : angle::NonCopyable ...@@ -21,7 +21,10 @@ class VertexArrayImpl : angle::NonCopyable
{ {
public: public:
VertexArrayImpl(const gl::VertexArrayState &state) : mState(state) {} VertexArrayImpl(const gl::VertexArrayState &state) : mState(state) {}
virtual void syncState(const gl::Context *context, const gl::VertexArray::DirtyBits &dirtyBits) virtual void syncState(const gl::Context *context,
const gl::VertexArray::DirtyBits &dirtyBits,
const gl::VertexArray::DirtyAttribBitsArray &attribBits,
const gl::VertexArray::DirtyBindingBitsArray &bindingBits)
{ {
} }
...@@ -32,6 +35,6 @@ class VertexArrayImpl : angle::NonCopyable ...@@ -32,6 +35,6 @@ class VertexArrayImpl : angle::NonCopyable
const gl::VertexArrayState &mState; const gl::VertexArrayState &mState;
}; };
} } // namespace rx
#endif // LIBANGLE_RENDERER_VERTEXARRAYIMPL_H_ #endif // LIBANGLE_RENDERER_VERTEXARRAYIMPL_H_
...@@ -57,7 +57,9 @@ void VertexArray11::destroy(const gl::Context *context) ...@@ -57,7 +57,9 @@ void VertexArray11::destroy(const gl::Context *context)
} }
void VertexArray11::syncState(const gl::Context *context, void VertexArray11::syncState(const gl::Context *context,
const gl::VertexArray::DirtyBits &dirtyBits) const gl::VertexArray::DirtyBits &dirtyBits,
const gl::VertexArray::DirtyAttribBitsArray &attribBits,
const gl::VertexArray::DirtyBindingBitsArray &bindingBits)
{ {
ASSERT(dirtyBits.any()); ASSERT(dirtyBits.any());
......
...@@ -27,7 +27,9 @@ class VertexArray11 : public angle::ObserverInterface, public VertexArrayImpl ...@@ -27,7 +27,9 @@ class VertexArray11 : public angle::ObserverInterface, public VertexArrayImpl
void destroy(const gl::Context *context) override; void destroy(const gl::Context *context) override;
void syncState(const gl::Context *context, void syncState(const gl::Context *context,
const gl::VertexArray::DirtyBits &dirtyBits) override; const gl::VertexArray::DirtyBits &dirtyBits,
const gl::VertexArray::DirtyAttribBitsArray &attribBits,
const gl::VertexArray::DirtyBindingBitsArray &bindingBits) override;
// This will flush any pending attrib updates and then check the dynamic attribs mask. // This will flush any pending attrib updates and then check the dynamic attribs mask.
bool hasActiveDynamicAttrib(const gl::Context *context); bool hasActiveDynamicAttrib(const gl::Context *context);
gl::Error updateDirtyAndDynamicAttribs(const gl::Context *context, gl::Error updateDirtyAndDynamicAttribs(const gl::Context *context,
......
...@@ -24,7 +24,9 @@ class VertexArray9 : public VertexArrayImpl ...@@ -24,7 +24,9 @@ class VertexArray9 : public VertexArrayImpl
VertexArray9(const gl::VertexArrayState &data) : VertexArrayImpl(data) {} VertexArray9(const gl::VertexArrayState &data) : VertexArrayImpl(data) {}
void syncState(const gl::Context *context, void syncState(const gl::Context *context,
const gl::VertexArray::DirtyBits &dirtyBits) override; const gl::VertexArray::DirtyBits &dirtyBits,
const gl::VertexArray::DirtyAttribBitsArray &attribBits,
const gl::VertexArray::DirtyBindingBitsArray &bindingBits) override;
~VertexArray9() override {} ~VertexArray9() override {}
...@@ -35,12 +37,14 @@ class VertexArray9 : public VertexArrayImpl ...@@ -35,12 +37,14 @@ class VertexArray9 : public VertexArrayImpl
}; };
inline void VertexArray9::syncState(const gl::Context *context, inline void VertexArray9::syncState(const gl::Context *context,
const gl::VertexArray::DirtyBits &dirtyBits) const gl::VertexArray::DirtyBits &dirtyBits,
const gl::VertexArray::DirtyAttribBitsArray &attribBits,
const gl::VertexArray::DirtyBindingBitsArray &bindingBits)
{ {
ASSERT(dirtyBits.any()); ASSERT(dirtyBits.any());
Renderer9 *renderer = GetImplAs<Context9>(context)->getRenderer(); Renderer9 *renderer = GetImplAs<Context9>(context)->getRenderer();
mCurrentStateSerial = renderer->generateSerial(); mCurrentStateSerial = renderer->generateSerial();
} }
} } // namespace rx
#endif // LIBANGLE_RENDERER_D3D_D3D9_VERTEXARRAY9_H_ #endif // LIBANGLE_RENDERER_D3D_D3D9_VERTEXARRAY9_H_
...@@ -640,56 +640,99 @@ void VertexArrayGL::updateBindingDivisor(size_t bindingIndex) ...@@ -640,56 +640,99 @@ void VertexArrayGL::updateBindingDivisor(size_t bindingIndex)
mAppliedBindings[bindingIndex].setDivisor(adjustedDivisor); mAppliedBindings[bindingIndex].setDivisor(adjustedDivisor);
} }
void VertexArrayGL::syncState(const gl::Context *context, const VertexArray::DirtyBits &dirtyBits) void VertexArrayGL::syncDirtyAttrib(const gl::Context *context,
size_t attribIndex,
const gl::VertexArray::DirtyAttribBits &dirtyAttribBits)
{ {
mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID()); ASSERT(dirtyAttribBits.any());
for (size_t dirtyBit : dirtyBits) for (size_t dirtyBit : dirtyAttribBits)
{ {
if (dirtyBit == VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER) switch (dirtyBit)
{ {
updateElementArrayBufferBinding(context); case VertexArray::DIRTY_ATTRIB_ENABLED:
continue; updateAttribEnabled(attribIndex);
break;
case VertexArray::DIRTY_ATTRIB_POINTER:
updateAttribPointer(context, attribIndex);
break;
case VertexArray::DIRTY_ATTRIB_FORMAT:
ASSERT(supportVertexAttribBinding());
updateAttribFormat(attribIndex);
break;
case VertexArray::DIRTY_ATTRIB_BINDING:
ASSERT(supportVertexAttribBinding());
updateAttribBinding(attribIndex);
break;
default:
UNREACHABLE();
break;
} }
}
}
size_t index = VertexArray::GetVertexIndexFromDirtyBit(dirtyBit); void VertexArrayGL::syncDirtyBinding(const gl::Context *context,
if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_ENABLED && size_t bindingIndex,
dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_ENABLED) const gl::VertexArray::DirtyBindingBits &dirtyBindingBits)
{ {
updateAttribEnabled(index); ASSERT(dirtyBindingBits.any());
}
else if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_POINTER &&
dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_POINTER)
{
updateAttribPointer(context, index);
}
else if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_FORMAT && for (size_t dirtyBit : dirtyBindingBits)
dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_FORMAT) {
{ switch (dirtyBit)
ASSERT(supportVertexAttribBinding());
updateAttribFormat(index);
}
else if (dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0_BINDING &&
dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_BINDING)
{
ASSERT(supportVertexAttribBinding());
updateAttribBinding(index);
}
else if (dirtyBit >= VertexArray::DIRTY_BIT_BINDING_0_BUFFER &&
dirtyBit < VertexArray::DIRTY_BIT_BINDING_MAX_BUFFER)
{ {
ASSERT(supportVertexAttribBinding()); case VertexArray::DIRTY_BINDING_BUFFER:
updateBindingBuffer(context, index); ASSERT(supportVertexAttribBinding());
updateBindingBuffer(context, bindingIndex);
break;
case VertexArray::DIRTY_BINDING_DIVISOR:
updateBindingDivisor(bindingIndex);
break;
default:
UNREACHABLE();
break;
} }
}
}
void VertexArrayGL::syncState(const gl::Context *context,
const VertexArray::DirtyBits &dirtyBits,
const gl::VertexArray::DirtyAttribBitsArray &attribBits,
const gl::VertexArray::DirtyBindingBitsArray &bindingBits)
{
mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
else if (dirtyBit >= VertexArray::DIRTY_BIT_BINDING_0_DIVISOR && for (size_t dirtyBit : dirtyBits)
dirtyBit < VertexArray::DIRTY_BIT_BINDING_MAX_DIVISOR) {
switch (dirtyBit)
{ {
updateBindingDivisor(index); case VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER:
updateElementArrayBufferBinding(context);
break;
default:
{
ASSERT(dirtyBit >= VertexArray::DIRTY_BIT_ATTRIB_0);
size_t index = VertexArray::GetVertexIndexFromDirtyBit(dirtyBit);
if (dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX)
{
syncDirtyAttrib(context, index, attribBits[index]);
}
else
{
ASSERT(dirtyBit >= VertexArray::DIRTY_BIT_BINDING_0 &&
dirtyBit < VertexArray::DIRTY_BIT_BINDING_MAX);
syncDirtyBinding(context, index, bindingBits[index]);
}
break;
}
} }
else
UNREACHABLE();
} }
} }
......
...@@ -45,7 +45,10 @@ class VertexArrayGL : public VertexArrayImpl ...@@ -45,7 +45,10 @@ class VertexArrayGL : public VertexArrayImpl
GLuint getAppliedElementArrayBufferID() const; GLuint getAppliedElementArrayBufferID() const;
void syncState(const gl::Context *context, void syncState(const gl::Context *context,
const gl::VertexArray::DirtyBits &dirtyBits) override; const gl::VertexArray::DirtyBits &dirtyBits,
const gl::VertexArray::DirtyAttribBitsArray &attribBits,
const gl::VertexArray::DirtyBindingBitsArray &bindingBits) override;
void applyNumViewsToDivisor(int numViews); void applyNumViewsToDivisor(int numViews);
private: private:
...@@ -81,6 +84,12 @@ class VertexArrayGL : public VertexArrayImpl ...@@ -81,6 +84,12 @@ class VertexArrayGL : public VertexArrayImpl
gl::Error streamAttributes(const gl::AttributesMask &activeAttributesMask, gl::Error streamAttributes(const gl::AttributesMask &activeAttributesMask,
GLsizei instanceCount, GLsizei instanceCount,
const gl::IndexRange &indexRange) const; const gl::IndexRange &indexRange) const;
void syncDirtyAttrib(const gl::Context *context,
size_t attribIndex,
const gl::VertexArray::DirtyAttribBits &dirtyAttribBits);
void syncDirtyBinding(const gl::Context *context,
size_t bindingIndex,
const gl::VertexArray::DirtyBindingBits &dirtyBindingBits);
void updateNeedsStreaming(size_t attribIndex); void updateNeedsStreaming(size_t attribIndex);
void updateAttribEnabled(size_t attribIndex); void updateAttribEnabled(size_t attribIndex);
......
...@@ -94,7 +94,9 @@ gl::Error VertexArrayVk::streamVertexData(ContextVk *context, ...@@ -94,7 +94,9 @@ gl::Error VertexArrayVk::streamVertexData(ContextVk *context,
} }
void VertexArrayVk::syncState(const gl::Context *context, void VertexArrayVk::syncState(const gl::Context *context,
const gl::VertexArray::DirtyBits &dirtyBits) const gl::VertexArray::DirtyBits &dirtyBits,
const gl::VertexArray::DirtyAttribBitsArray &attribBits,
const gl::VertexArray::DirtyBindingBitsArray &bindingBits)
{ {
ASSERT(dirtyBits.any()); ASSERT(dirtyBits.any());
......
...@@ -32,7 +32,9 @@ class VertexArrayVk : public VertexArrayImpl ...@@ -32,7 +32,9 @@ class VertexArrayVk : public VertexArrayImpl
size_t firstVertex, size_t firstVertex,
size_t lastVertex); size_t lastVertex);
void syncState(const gl::Context *context, void syncState(const gl::Context *context,
const gl::VertexArray::DirtyBits &dirtyBits) override; const gl::VertexArray::DirtyBits &dirtyBits,
const gl::VertexArray::DirtyAttribBitsArray &attribBits,
const gl::VertexArray::DirtyBindingBitsArray &bindingBits) override;
const gl::AttribArray<VkBuffer> &getCurrentArrayBufferHandles() const; const gl::AttribArray<VkBuffer> &getCurrentArrayBufferHandles() const;
const gl::AttribArray<VkDeviceSize> &getCurrentArrayBufferOffsets() const; const gl::AttribArray<VkDeviceSize> &getCurrentArrayBufferOffsets() const;
......
...@@ -1603,6 +1603,9 @@ ...@@ -1603,6 +1603,9 @@
2272 WIN NVIDIA OPENGL : dEQP-GLES31.functional.ssbo.layout.random.nested_structs* = FAIL 2272 WIN NVIDIA OPENGL : dEQP-GLES31.functional.ssbo.layout.random.nested_structs* = FAIL
2272 WIN NVIDIA OPENGL : dEQP-GLES31.functional.ssbo.layout.random.all* = FAIL 2272 WIN NVIDIA OPENGL : dEQP-GLES31.functional.ssbo.layout.random.all* = FAIL
// An NVIDIA bug seems to occur when sending GL commands in a certain order to the driver
2432 NVIDIA OPENGL : dEQP-GLES31.functional.vertex_attribute_binding.usage.mixed_usage.mixed_api_change_binding_point = SKIP
// OpenGL and D3D11 Failing Tests // OpenGL and D3D11 Failing Tests
1442 OPENGL D3D11 : dEQP-GLES31.functional.shaders.opaque_type_indexing.* = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.shaders.opaque_type_indexing.* = FAIL
1442 OPENGL D3D11 : dEQP-GLES31.functional.shaders.helper_invocation.* = FAIL 1442 OPENGL D3D11 : dEQP-GLES31.functional.shaders.helper_invocation.* = FAIL
......
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