Commit c759b8b4 by Jamie Madill Committed by Commit Bot

Vulkan: More Vertex Array optimizations.

Inlines a number of Vulkan vertex array methods. Also changes the way vertex buffers are bound. Note that Vulkan doesn't support NULL buffer bindings. Thus we create an emulated NULL buffer to work around the problem of having gaps in the bound vertex buffers. This allows us to use a single bind call for ranges of vertex buffers even when there are gaps. Also changes how vertex array dirty bits are reset. Instead of calling memset to clear the affected buffers we pass a mutable pointer to the Vertex Array sync state. This allows us to only reset the dirty bits that we sync. This saves on the memory clearing time. Improves perf by about 10% in the Vulkan VBO state change test. Bug: angleproject:3014 Change-Id: Ib7b742dff7897fc891606a652ea0b64255a24c86 Reviewed-on: https://chromium-review.googlesource.com/c/1390360 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 633d5e69
...@@ -252,22 +252,6 @@ GLint64 Buffer::getMemorySize() const ...@@ -252,22 +252,6 @@ GLint64 Buffer::getMemorySize() const
return implSize > 0 ? implSize : mState.mSize; return implSize > 0 ? implSize : mState.mSize;
} }
bool Buffer::isBound() const
{
return mState.mBindingCount;
}
bool Buffer::isBoundForTransformFeedbackAndOtherUse() const
{
// The transform feedback generic binding point is not an indexed binding point but it also does
// not count as a non-transform-feedback use of the buffer, so we subtract it from the binding
// count when checking if the buffer is bound to a non-transform-feedback location. See
// https://crbug.com/853978
return mState.mTransformFeedbackIndexedBindingCount > 0 &&
mState.mTransformFeedbackIndexedBindingCount !=
mState.mBindingCount - mState.mTransformFeedbackGenericBindingCount;
}
bool Buffer::isDoubleBoundForTransformFeedback() const bool Buffer::isDoubleBoundForTransformFeedback() const
{ {
return mState.mTransformFeedbackIndexedBindingCount > 1; return mState.mTransformFeedbackIndexedBindingCount > 1;
......
...@@ -121,8 +121,19 @@ class Buffer final : public RefCountObject, ...@@ -121,8 +121,19 @@ class Buffer final : public RefCountObject,
rx::BufferImpl *getImplementation() const { return mImpl; } rx::BufferImpl *getImplementation() const { return mImpl; }
bool isBound() const; ANGLE_INLINE bool isBound() const { return mState.mBindingCount > 0; }
bool isBoundForTransformFeedbackAndOtherUse() const;
ANGLE_INLINE bool isBoundForTransformFeedbackAndOtherUse() const
{
// The transform feedback generic binding point is not an indexed binding point but it also
// does not count as a non-transform-feedback use of the buffer, so we subtract it from the
// binding count when checking if the buffer is bound to a non-transform-feedback location.
// See https://crbug.com/853978
return mState.mTransformFeedbackIndexedBindingCount > 0 &&
mState.mTransformFeedbackIndexedBindingCount !=
mState.mBindingCount - mState.mTransformFeedbackGenericBindingCount;
}
bool isDoubleBoundForTransformFeedback() const; bool isDoubleBoundForTransformFeedback() const;
void onTFBindingChanged(const Context *context, bool bound, bool indexed); void onTFBindingChanged(const Context *context, bool bound, bool indexed);
void onNonTFBindingChanged(int incr) { mState.mBindingCount += incr; } void onNonTFBindingChanged(int incr) { mState.mBindingCount += incr; }
......
...@@ -8143,7 +8143,6 @@ void StateCache::updateVertexElementLimits(Context *context) ...@@ -8143,7 +8143,6 @@ void StateCache::updateVertexElementLimits(Context *context)
for (size_t attributeIndex : mCachedActiveBufferedAttribsMask) for (size_t attributeIndex : mCachedActiveBufferedAttribsMask)
{ {
const VertexAttribute &attrib = vertexAttribs[attributeIndex]; const VertexAttribute &attrib = vertexAttribs[attributeIndex];
ASSERT(attrib.enabled);
const VertexBinding &binding = vertexBindings[attrib.bindingIndex]; const VertexBinding &binding = vertexBindings[attrib.bindingIndex];
ASSERT(context->isGLES1() || ASSERT(context->isGLES1() ||
......
...@@ -122,11 +122,6 @@ VertexArray::~VertexArray() ...@@ -122,11 +122,6 @@ VertexArray::~VertexArray()
ASSERT(!mVertexArray); ASSERT(!mVertexArray);
} }
GLuint VertexArray::id() const
{
return mId;
}
void VertexArray::setLabel(const Context *context, const std::string &label) void VertexArray::setLabel(const Context *context, const std::string &label)
{ {
mState.mLabel = label; mState.mLabel = label;
...@@ -176,18 +171,51 @@ size_t VertexArray::GetVertexIndexFromDirtyBit(size_t dirtyBit) ...@@ -176,18 +171,51 @@ size_t VertexArray::GetVertexIndexFromDirtyBit(size_t dirtyBit)
return (dirtyBit - DIRTY_BIT_ATTRIB_0) % gl::MAX_VERTEX_ATTRIBS; return (dirtyBit - DIRTY_BIT_ATTRIB_0) % gl::MAX_VERTEX_ATTRIBS;
} }
void VertexArray::setDirtyAttribBit(size_t attribIndex, DirtyAttribBitType dirtyAttribBit) ANGLE_INLINE void VertexArray::setDirtyAttribBit(size_t attribIndex,
DirtyAttribBitType dirtyAttribBit)
{ {
mDirtyBits.set(DIRTY_BIT_ATTRIB_0 + attribIndex); mDirtyBits.set(DIRTY_BIT_ATTRIB_0 + attribIndex);
mDirtyAttribBits[attribIndex].set(dirtyAttribBit); mDirtyAttribBits[attribIndex].set(dirtyAttribBit);
} }
void VertexArray::setDirtyBindingBit(size_t bindingIndex, DirtyBindingBitType dirtyBindingBit) ANGLE_INLINE void VertexArray::setDirtyBindingBit(size_t bindingIndex,
DirtyBindingBitType dirtyBindingBit)
{ {
mDirtyBits.set(DIRTY_BIT_BINDING_0 + bindingIndex); mDirtyBits.set(DIRTY_BIT_BINDING_0 + bindingIndex);
mDirtyBindingBits[bindingIndex].set(dirtyBindingBit); mDirtyBindingBits[bindingIndex].set(dirtyBindingBit);
} }
ANGLE_INLINE void VertexArray::updateCachedBufferBindingSize(VertexBinding *binding)
{
for (size_t boundAttribute : binding->getBoundAttributesMask())
{
mState.mVertexAttributes[boundAttribute].updateCachedElementLimit(*binding);
}
}
ANGLE_INLINE void VertexArray::updateCachedMappedArrayBuffers(VertexBinding *binding)
{
Buffer *buffer = binding->getBuffer().get();
if (buffer && buffer->isMapped())
{
mState.mCachedMappedArrayBuffers |= binding->getBoundAttributesMask();
}
else
{
mState.mCachedMappedArrayBuffers &= ~binding->getBoundAttributesMask();
}
mState.mCachedEnabledMappedArrayBuffers =
mState.mCachedMappedArrayBuffers & mState.mEnabledAttributesMask;
}
ANGLE_INLINE void VertexArray::updateCachedTransformFeedbackBindingValidation(size_t bindingIndex,
const Buffer *buffer)
{
const bool hasConflict = buffer && buffer->isBoundForTransformFeedbackAndOtherUse();
mCachedTransformFeedbackConflictedBindingsMask.set(bindingIndex, hasConflict);
}
void VertexArray::bindVertexBufferImpl(const Context *context, void VertexArray::bindVertexBufferImpl(const Context *context,
size_t bindingIndex, size_t bindingIndex,
Buffer *boundBuffer, Buffer *boundBuffer,
...@@ -266,12 +294,12 @@ void VertexArray::setVertexBindingDivisor(size_t bindingIndex, GLuint divisor) ...@@ -266,12 +294,12 @@ void VertexArray::setVertexBindingDivisor(size_t bindingIndex, GLuint divisor)
} }
} }
void VertexArray::setVertexAttribFormatImpl(size_t attribIndex, ANGLE_INLINE void VertexArray::setVertexAttribFormatImpl(size_t attribIndex,
GLint size, GLint size,
GLenum type, GLenum type,
bool normalized, bool normalized,
bool pureInteger, bool pureInteger,
GLuint relativeOffset) GLuint relativeOffset)
{ {
ASSERT(attribIndex < getMaxAttribs()); ASSERT(attribIndex < getMaxAttribs());
...@@ -366,16 +394,13 @@ angle::Result VertexArray::syncState(const Context *context) ...@@ -366,16 +394,13 @@ angle::Result VertexArray::syncState(const Context *context)
{ {
mDirtyBitsGuard = mDirtyBits; mDirtyBitsGuard = mDirtyBits;
ANGLE_TRY( ANGLE_TRY(
mVertexArray->syncState(context, mDirtyBits, mDirtyAttribBits, mDirtyBindingBits)); mVertexArray->syncState(context, mDirtyBits, &mDirtyAttribBits, &mDirtyBindingBits));
mDirtyBits.reset(); mDirtyBits.reset();
mDirtyBitsGuard.reset(); mDirtyBitsGuard.reset();
// This is a bit of an implementation hack - but since we know the implementation // The dirty bits should be reset in the back-end. To simplify ASSERTs only check attrib 0.
// details of the dirty bit class it should always have the same effect as iterating ASSERT(mDirtyAttribBits[0].none());
// individual attribs. We could also look into schemes where iterating the dirty ASSERT(mDirtyBindingBits[0].none());
// bit set also resets it as you pass through it.
memset(&mDirtyAttribBits, 0, sizeof(mDirtyAttribBits));
memset(&mDirtyBindingBits, 0, sizeof(mDirtyBindingBits));
} }
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -474,21 +499,6 @@ void VertexArray::updateObserverBinding(size_t bindingIndex) ...@@ -474,21 +499,6 @@ void VertexArray::updateObserverBinding(size_t bindingIndex)
mArrayBufferObserverBindings[bindingIndex].bind(boundBuffer); mArrayBufferObserverBindings[bindingIndex].bind(boundBuffer);
} }
void VertexArray::updateCachedBufferBindingSize(VertexBinding *binding)
{
for (size_t boundAttribute : binding->getBoundAttributesMask())
{
mState.mVertexAttributes[boundAttribute].updateCachedElementLimit(*binding);
}
}
void VertexArray::updateCachedTransformFeedbackBindingValidation(size_t bindingIndex,
const Buffer *buffer)
{
const bool hasConflict = buffer && buffer->isBoundForTransformFeedbackAndOtherUse();
mCachedTransformFeedbackConflictedBindingsMask.set(bindingIndex, hasConflict);
}
bool VertexArray::hasTransformFeedbackBindingConflict(const gl::Context *context) const bool VertexArray::hasTransformFeedbackBindingConflict(const gl::Context *context) const
{ {
// Fast check first. // Fast check first.
...@@ -512,22 +522,6 @@ bool VertexArray::hasTransformFeedbackBindingConflict(const gl::Context *context ...@@ -512,22 +522,6 @@ bool VertexArray::hasTransformFeedbackBindingConflict(const gl::Context *context
return false; return false;
} }
void VertexArray::updateCachedMappedArrayBuffers(VertexBinding *binding)
{
Buffer *buffer = binding->getBuffer().get();
if (buffer && buffer->isMapped())
{
mState.mCachedMappedArrayBuffers |= binding->getBoundAttributesMask();
}
else
{
mState.mCachedMappedArrayBuffers &= ~binding->getBoundAttributesMask();
}
mState.mCachedEnabledMappedArrayBuffers =
mState.mCachedMappedArrayBuffers & mState.mEnabledAttributesMask;
}
angle::Result VertexArray::getIndexRangeImpl(const Context *context, angle::Result VertexArray::getIndexRangeImpl(const Context *context,
DrawElementsType type, DrawElementsType type,
GLsizei indexCount, GLsizei indexCount,
......
...@@ -104,7 +104,7 @@ class VertexArray final : public angle::ObserverInterface, ...@@ -104,7 +104,7 @@ class VertexArray final : public angle::ObserverInterface,
void onDestroy(const Context *context); void onDestroy(const Context *context);
GLuint id() const; GLuint id() const { return mId; }
void setLabel(const Context *context, const std::string &label) override; void setLabel(const Context *context, const std::string &label) override;
const std::string &getLabel() const override; const std::string &getLabel() const override;
......
...@@ -40,18 +40,6 @@ VertexBinding &VertexBinding::operator=(VertexBinding &&binding) ...@@ -40,18 +40,6 @@ VertexBinding &VertexBinding::operator=(VertexBinding &&binding)
return *this; return *this;
} }
void VertexBinding::setBuffer(const gl::Context *context, Buffer *bufferIn, bool containerIsBound)
{
if (containerIsBound)
{
if (mBuffer.get())
mBuffer->onNonTFBindingChanged(-1);
if (bufferIn)
bufferIn->onNonTFBindingChanged(1);
}
mBuffer.set(context, bufferIn);
}
void VertexBinding::onContainerBindingChanged(const Context *context, int incr) const void VertexBinding::onContainerBindingChanged(const Context *context, int incr) const
{ {
if (mBuffer.get()) if (mBuffer.get())
......
...@@ -39,7 +39,18 @@ class VertexBinding final : angle::NonCopyable ...@@ -39,7 +39,18 @@ class VertexBinding final : angle::NonCopyable
void setOffset(GLintptr offsetIn) { mOffset = offsetIn; } void setOffset(GLintptr offsetIn) { mOffset = offsetIn; }
const BindingPointer<Buffer> &getBuffer() const { return mBuffer; } const BindingPointer<Buffer> &getBuffer() const { return mBuffer; }
void setBuffer(const gl::Context *context, Buffer *bufferIn, bool containerIsBound);
ANGLE_INLINE void setBuffer(const gl::Context *context, Buffer *bufferIn, bool containerIsBound)
{
if (containerIsBound)
{
if (mBuffer.get())
mBuffer->onNonTFBindingChanged(-1);
if (bufferIn)
bufferIn->onNonTFBindingChanged(1);
}
mBuffer.set(context, bufferIn);
}
void onContainerBindingChanged(const Context *context, int incr) const; void onContainerBindingChanged(const Context *context, int incr) const;
......
...@@ -32,10 +32,13 @@ class VertexArrayImpl : angle::NonCopyable ...@@ -32,10 +32,13 @@ class VertexArrayImpl : angle::NonCopyable
{ {
public: public:
VertexArrayImpl(const gl::VertexArrayState &state) : mState(state) {} VertexArrayImpl(const gl::VertexArrayState &state) : mState(state) {}
// It's up to the implementation to reset the attrib and binding dirty bits.
// This is faster than the front-end having to clear all the bits after they have been scanned.
virtual angle::Result syncState(const gl::Context *context, virtual angle::Result syncState(const gl::Context *context,
const gl::VertexArray::DirtyBits &dirtyBits, const gl::VertexArray::DirtyBits &dirtyBits,
const gl::VertexArray::DirtyAttribBitsArray &attribBits, gl::VertexArray::DirtyAttribBitsArray *attribBits,
const gl::VertexArray::DirtyBindingBitsArray &bindingBits) gl::VertexArray::DirtyBindingBitsArray *bindingBits)
{ {
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -34,23 +34,25 @@ void VertexArray11::destroy(const gl::Context *context) {} ...@@ -34,23 +34,25 @@ void VertexArray11::destroy(const gl::Context *context) {}
// As VertexAttribPointer can modify both attribute and binding, we should also set other attributes // As VertexAttribPointer can modify both attribute and binding, we should also set other attributes
// that are also using this binding dirty. // that are also using this binding dirty.
#define ANGLE_VERTEX_DIRTY_ATTRIB_FUNC(INDEX) \ #define ANGLE_VERTEX_DIRTY_ATTRIB_FUNC(INDEX) \
case gl::VertexArray::DIRTY_BIT_ATTRIB_0 + INDEX: \ case gl::VertexArray::DIRTY_BIT_ATTRIB_0 + INDEX: \
if (attribBits[INDEX][gl::VertexArray::DirtyAttribBitType::DIRTY_ATTRIB_POINTER]) \ if ((*attribBits)[INDEX][gl::VertexArray::DirtyAttribBitType::DIRTY_ATTRIB_POINTER]) \
{ \ { \
attributesToUpdate |= mState.getBindingToAttributesMask(INDEX); \ attributesToUpdate |= mState.getBindingToAttributesMask(INDEX); \
} \ } \
else \ else \
{ \ { \
attributesToUpdate.set(INDEX); \ attributesToUpdate.set(INDEX); \
} \ } \
invalidateVertexBuffer = true; \ invalidateVertexBuffer = true; \
(*attribBits)[INDEX].reset(); \
break; break;
#define ANGLE_VERTEX_DIRTY_BINDING_FUNC(INDEX) \ #define ANGLE_VERTEX_DIRTY_BINDING_FUNC(INDEX) \
case gl::VertexArray::DIRTY_BIT_BINDING_0 + INDEX: \ case gl::VertexArray::DIRTY_BIT_BINDING_0 + INDEX: \
attributesToUpdate |= mState.getBindingToAttributesMask(INDEX); \ attributesToUpdate |= mState.getBindingToAttributesMask(INDEX); \
invalidateVertexBuffer = true; \ invalidateVertexBuffer = true; \
(*bindingBits)[INDEX].reset(); \
break; break;
#define ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC(INDEX) \ #define ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC(INDEX) \
...@@ -64,8 +66,8 @@ void VertexArray11::destroy(const gl::Context *context) {} ...@@ -64,8 +66,8 @@ void VertexArray11::destroy(const gl::Context *context) {}
angle::Result VertexArray11::syncState(const gl::Context *context, angle::Result VertexArray11::syncState(const gl::Context *context,
const gl::VertexArray::DirtyBits &dirtyBits, const gl::VertexArray::DirtyBits &dirtyBits,
const gl::VertexArray::DirtyAttribBitsArray &attribBits, gl::VertexArray::DirtyAttribBitsArray *attribBits,
const gl::VertexArray::DirtyBindingBitsArray &bindingBits) gl::VertexArray::DirtyBindingBitsArray *bindingBits)
{ {
ASSERT(dirtyBits.any()); ASSERT(dirtyBits.any());
......
...@@ -29,8 +29,8 @@ class VertexArray11 : public VertexArrayImpl ...@@ -29,8 +29,8 @@ class VertexArray11 : public VertexArrayImpl
// the draw call parameters. // the draw call parameters.
angle::Result syncState(const gl::Context *context, angle::Result syncState(const gl::Context *context,
const gl::VertexArray::DirtyBits &dirtyBits, const gl::VertexArray::DirtyBits &dirtyBits,
const gl::VertexArray::DirtyAttribBitsArray &attribBits, gl::VertexArray::DirtyAttribBitsArray *attribBits,
const gl::VertexArray::DirtyBindingBitsArray &bindingBits) override; gl::VertexArray::DirtyBindingBitsArray *bindingBits) override;
// Applied buffer pointers are updated here. // Applied buffer pointers are updated here.
angle::Result syncStateForDraw(const gl::Context *context, angle::Result syncStateForDraw(const gl::Context *context,
......
...@@ -25,8 +25,8 @@ class VertexArray9 : public VertexArrayImpl ...@@ -25,8 +25,8 @@ class VertexArray9 : public VertexArrayImpl
angle::Result syncState(const gl::Context *context, angle::Result syncState(const gl::Context *context,
const gl::VertexArray::DirtyBits &dirtyBits, const gl::VertexArray::DirtyBits &dirtyBits,
const gl::VertexArray::DirtyAttribBitsArray &attribBits, gl::VertexArray::DirtyAttribBitsArray *attribBits,
const gl::VertexArray::DirtyBindingBitsArray &bindingBits) override; gl::VertexArray::DirtyBindingBitsArray *bindingBits) override;
~VertexArray9() override {} ~VertexArray9() override {}
...@@ -36,15 +36,20 @@ class VertexArray9 : public VertexArrayImpl ...@@ -36,15 +36,20 @@ class VertexArray9 : public VertexArrayImpl
Serial mCurrentStateSerial; Serial mCurrentStateSerial;
}; };
inline angle::Result VertexArray9::syncState( inline angle::Result VertexArray9::syncState(const gl::Context *context,
const gl::Context *context, const gl::VertexArray::DirtyBits &dirtyBits,
const gl::VertexArray::DirtyBits &dirtyBits, gl::VertexArray::DirtyAttribBitsArray *attribBits,
const gl::VertexArray::DirtyAttribBitsArray &attribBits, gl::VertexArray::DirtyBindingBitsArray *bindingBits)
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();
// Clear the dirty bits in the back-end here.
memset(attribBits, 0, sizeof(gl::VertexArray::DirtyAttribBitsArray));
memset(bindingBits, 0, sizeof(gl::VertexArray::DirtyBindingBitsArray));
return angle::Result::Continue; return angle::Result::Continue;
} }
} // namespace rx } // namespace rx
......
...@@ -654,14 +654,16 @@ void VertexArrayGL::syncDirtyBinding(const gl::Context *context, ...@@ -654,14 +654,16 @@ void VertexArrayGL::syncDirtyBinding(const gl::Context *context,
} }
} }
#define ANGLE_DIRTY_ATTRIB_FUNC(INDEX) \ #define ANGLE_DIRTY_ATTRIB_FUNC(INDEX) \
case VertexArray::DIRTY_BIT_ATTRIB_0 + INDEX: \ case VertexArray::DIRTY_BIT_ATTRIB_0 + INDEX: \
syncDirtyAttrib(context, INDEX, attribBits[INDEX]); \ syncDirtyAttrib(context, INDEX, (*attribBits)[INDEX]); \
(*attribBits)[INDEX].reset(); \
break; break;
#define ANGLE_DIRTY_BINDING_FUNC(INDEX) \ #define ANGLE_DIRTY_BINDING_FUNC(INDEX) \
case VertexArray::DIRTY_BIT_BINDING_0 + INDEX: \ case VertexArray::DIRTY_BIT_BINDING_0 + INDEX: \
syncDirtyBinding(context, INDEX, bindingBits[INDEX]); \ syncDirtyBinding(context, INDEX, (*bindingBits)[INDEX]); \
(*bindingBits)[INDEX].reset(); \
break; break;
#define ANGLE_DIRTY_BUFFER_DATA_FUNC(INDEX) \ #define ANGLE_DIRTY_BUFFER_DATA_FUNC(INDEX) \
...@@ -670,8 +672,8 @@ void VertexArrayGL::syncDirtyBinding(const gl::Context *context, ...@@ -670,8 +672,8 @@ void VertexArrayGL::syncDirtyBinding(const gl::Context *context,
angle::Result VertexArrayGL::syncState(const gl::Context *context, angle::Result VertexArrayGL::syncState(const gl::Context *context,
const gl::VertexArray::DirtyBits &dirtyBits, const gl::VertexArray::DirtyBits &dirtyBits,
const gl::VertexArray::DirtyAttribBitsArray &attribBits, gl::VertexArray::DirtyAttribBitsArray *attribBits,
const gl::VertexArray::DirtyBindingBitsArray &bindingBits) gl::VertexArray::DirtyBindingBitsArray *bindingBits)
{ {
mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID()); mStateManager->bindVertexArray(mVertexArrayID, getAppliedElementArrayBufferID());
......
...@@ -50,8 +50,8 @@ class VertexArrayGL : public VertexArrayImpl ...@@ -50,8 +50,8 @@ class VertexArrayGL : public VertexArrayImpl
angle::Result syncState(const gl::Context *context, angle::Result syncState(const gl::Context *context,
const gl::VertexArray::DirtyBits &dirtyBits, const gl::VertexArray::DirtyBits &dirtyBits,
const gl::VertexArray::DirtyAttribBitsArray &attribBits, gl::VertexArray::DirtyAttribBitsArray *attribBits,
const gl::VertexArray::DirtyBindingBitsArray &bindingBits) override; gl::VertexArray::DirtyBindingBitsArray *bindingBits) override;
void applyNumViewsToDivisor(int numViews); void applyNumViewsToDivisor(int numViews);
void applyActiveAttribLocationsMask(const gl::AttributesMask &activeMask); void applyActiveAttribLocationsMask(const gl::AttributesMask &activeMask);
......
...@@ -99,11 +99,6 @@ bool CommandGraphResource::hasPendingWork(RendererVk *renderer) const ...@@ -99,11 +99,6 @@ bool CommandGraphResource::hasPendingWork(RendererVk *renderer) const
return mStoredQueueSerial == renderer->getCurrentQueueSerial(); return mStoredQueueSerial == renderer->getCurrentQueueSerial();
} }
Serial CommandGraphResource::getStoredQueueSerial() const
{
return mStoredQueueSerial;
}
// RecordableGraphResource implementation. // RecordableGraphResource implementation.
RecordableGraphResource::RecordableGraphResource(CommandGraphResourceType resourceType) RecordableGraphResource::RecordableGraphResource(CommandGraphResourceType resourceType)
: CommandGraphResource(resourceType) : CommandGraphResource(resourceType)
...@@ -111,18 +106,6 @@ RecordableGraphResource::RecordableGraphResource(CommandGraphResourceType resour ...@@ -111,18 +106,6 @@ RecordableGraphResource::RecordableGraphResource(CommandGraphResourceType resour
RecordableGraphResource::~RecordableGraphResource() = default; RecordableGraphResource::~RecordableGraphResource() = default;
void RecordableGraphResource::updateQueueSerial(Serial queueSerial)
{
ASSERT(queueSerial >= mStoredQueueSerial);
if (queueSerial > mStoredQueueSerial)
{
mCurrentWritingNode = nullptr;
mCurrentReadingNodes.clear();
mStoredQueueSerial = queueSerial;
}
}
angle::Result RecordableGraphResource::recordCommands(Context *context, angle::Result RecordableGraphResource::recordCommands(Context *context,
CommandBuffer **commandBufferOut) CommandBuffer **commandBufferOut)
{ {
...@@ -149,21 +132,6 @@ angle::Result RecordableGraphResource::recordCommands(Context *context, ...@@ -149,21 +132,6 @@ angle::Result RecordableGraphResource::recordCommands(Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
bool RecordableGraphResource::appendToStartedRenderPass(RendererVk *renderer,
CommandBuffer **commandBufferOut)
{
updateQueueSerial(renderer->getCurrentQueueSerial());
if (hasStartedRenderPass())
{
*commandBufferOut = mCurrentWritingNode->getInsideRenderPassCommands();
return true;
}
else
{
return false;
}
}
const gl::Rectangle &RecordableGraphResource::getRenderPassRenderArea() const const gl::Rectangle &RecordableGraphResource::getRenderPassRenderArea() const
{ {
ASSERT(hasStartedRenderPass()); ASSERT(hasStartedRenderPass());
...@@ -377,15 +345,6 @@ void CommandGraphNode::storeRenderPassInfo(const Framebuffer &framebuffer, ...@@ -377,15 +345,6 @@ void CommandGraphNode::storeRenderPassInfo(const Framebuffer &framebuffer,
} }
// static // static
void CommandGraphNode::SetHappensBeforeDependency(CommandGraphNode *beforeNode,
CommandGraphNode *afterNode)
{
ASSERT(beforeNode != afterNode && !beforeNode->isChildOf(afterNode));
afterNode->mParents.emplace_back(beforeNode);
beforeNode->setHasChildren();
}
// static
void CommandGraphNode::SetHappensBeforeDependencies(CommandGraphNode **beforeNodes, void CommandGraphNode::SetHappensBeforeDependencies(CommandGraphNode **beforeNodes,
size_t beforeNodesCount, size_t beforeNodesCount,
CommandGraphNode *afterNode) CommandGraphNode *afterNode)
...@@ -426,17 +385,6 @@ void CommandGraphNode::setQueryPool(const QueryPool *queryPool, uint32_t queryIn ...@@ -426,17 +385,6 @@ void CommandGraphNode::setQueryPool(const QueryPool *queryPool, uint32_t queryIn
mQueryIndex = queryIndex; mQueryIndex = queryIndex;
} }
void CommandGraphNode::addGlobalMemoryBarrier(VkFlags srcAccess, VkFlags dstAccess)
{
mGlobalMemoryBarrierSrcAccess |= srcAccess;
mGlobalMemoryBarrierDstAccess |= dstAccess;
}
void CommandGraphNode::setHasChildren()
{
mHasChildren = true;
}
// Do not call this in anything but testing code, since it's slow. // Do not call this in anything but testing code, since it's slow.
bool CommandGraphNode::isChildOf(CommandGraphNode *parent) bool CommandGraphNode::isChildOf(CommandGraphNode *parent)
{ {
......
...@@ -76,7 +76,13 @@ class CommandGraphNode final : angle::NonCopyable ...@@ -76,7 +76,13 @@ class CommandGraphNode final : angle::NonCopyable
// Once a node has commands that must happen after it, recording is stopped and the node is // Once a node has commands that must happen after it, recording is stopped and the node is
// frozen forever. // frozen forever.
static void SetHappensBeforeDependency(CommandGraphNode *beforeNode, static void SetHappensBeforeDependency(CommandGraphNode *beforeNode,
CommandGraphNode *afterNode); CommandGraphNode *afterNode)
{
ASSERT(beforeNode != afterNode && !beforeNode->isChildOf(afterNode));
afterNode->mParents.emplace_back(beforeNode);
beforeNode->setHasChildren();
}
static void SetHappensBeforeDependencies(CommandGraphNode **beforeNodes, static void SetHappensBeforeDependencies(CommandGraphNode **beforeNodes,
size_t beforeNodesCount, size_t beforeNodesCount,
CommandGraphNode *afterNode); CommandGraphNode *afterNode);
...@@ -107,10 +113,14 @@ class CommandGraphNode final : angle::NonCopyable ...@@ -107,10 +113,14 @@ class CommandGraphNode final : angle::NonCopyable
void setQueryPool(const QueryPool *queryPool, uint32_t queryIndex); void setQueryPool(const QueryPool *queryPool, uint32_t queryIndex);
void addGlobalMemoryBarrier(VkFlags srcAccess, VkFlags dstAccess); ANGLE_INLINE void addGlobalMemoryBarrier(VkFlags srcAccess, VkFlags dstAccess)
{
mGlobalMemoryBarrierSrcAccess |= srcAccess;
mGlobalMemoryBarrierDstAccess |= dstAccess;
}
private: private:
void setHasChildren(); void setHasChildren() { mHasChildren = true; }
// Used for testing only. // Used for testing only.
bool isChildOf(CommandGraphNode *parent); bool isChildOf(CommandGraphNode *parent);
...@@ -169,7 +179,7 @@ class CommandGraphResource : angle::NonCopyable ...@@ -169,7 +179,7 @@ class CommandGraphResource : angle::NonCopyable
// Get the current queue serial for this resource. Used to release resources, and for // Get the current queue serial for this resource. Used to release resources, and for
// queries, to know if the queue they are submitted on has finished execution. // queries, to know if the queue they are submitted on has finished execution.
Serial getStoredQueueSerial() const; Serial getStoredQueueSerial() const { return mStoredQueueSerial; }
protected: protected:
explicit CommandGraphResource(CommandGraphResourceType resourceType); explicit CommandGraphResource(CommandGraphResourceType resourceType);
...@@ -198,7 +208,17 @@ class RecordableGraphResource : public CommandGraphResource ...@@ -198,7 +208,17 @@ class RecordableGraphResource : public CommandGraphResource
// Updates the in-use serial tracked for this resource. Will clear dependencies if the resource // Updates the in-use serial tracked for this resource. Will clear dependencies if the resource
// was not used in this set of command nodes. // was not used in this set of command nodes.
void updateQueueSerial(Serial queueSerial); ANGLE_INLINE void updateQueueSerial(Serial queueSerial)
{
ASSERT(queueSerial >= mStoredQueueSerial);
if (queueSerial > mStoredQueueSerial)
{
mCurrentWritingNode = nullptr;
mCurrentReadingNodes.clear();
mStoredQueueSerial = queueSerial;
}
}
// Allocates a write node via getNewWriteNode and returns a started command buffer. // Allocates a write node via getNewWriteNode and returns a started command buffer.
// The started command buffer will render outside of a RenderPass. // The started command buffer will render outside of a RenderPass.
...@@ -216,7 +236,20 @@ class RecordableGraphResource : public CommandGraphResource ...@@ -216,7 +236,20 @@ class RecordableGraphResource : public CommandGraphResource
// Checks if we're in a RenderPass, returning true if so. Updates serial internally. // Checks if we're in a RenderPass, returning true if so. Updates serial internally.
// Returns the started command buffer in commandBufferOut. // Returns the started command buffer in commandBufferOut.
bool appendToStartedRenderPass(RendererVk *renderer, CommandBuffer **commandBufferOut); ANGLE_INLINE bool appendToStartedRenderPass(Serial currentQueueSerial,
CommandBuffer **commandBufferOut)
{
updateQueueSerial(currentQueueSerial);
if (hasStartedRenderPass())
{
*commandBufferOut = mCurrentWritingNode->getInsideRenderPassCommands();
return true;
}
else
{
return false;
}
}
// Accessor for RenderPass RenderArea. // Accessor for RenderPass RenderArea.
const gl::Rectangle &getRenderPassRenderArea() const; const gl::Rectangle &getRenderPassRenderArea() const;
...@@ -236,7 +269,7 @@ class RecordableGraphResource : public CommandGraphResource ...@@ -236,7 +269,7 @@ class RecordableGraphResource : public CommandGraphResource
private: private:
// Returns true if this node has a current writing node with no children. // Returns true if this node has a current writing node with no children.
bool hasChildlessWritingNode() const ANGLE_INLINE bool hasChildlessWritingNode() const
{ {
// Note: currently, we don't have a resource that can issue both generic and special // Note: currently, we don't have a resource that can issue both generic and special
// commands. We don't create read/write dependencies between mixed generic/special // commands. We don't create read/write dependencies between mixed generic/special
......
...@@ -52,45 +52,6 @@ GLenum DefaultGLErrorCode(VkResult result) ...@@ -52,45 +52,6 @@ GLenum DefaultGLErrorCode(VkResult result)
} }
} }
void BindNonNullVertexBufferRanges(vk::CommandBuffer *commandBuffer,
const gl::AttributesMask &nonNullAttribMask,
uint32_t maxAttrib,
const gl::AttribArray<VkBuffer> &arrayBufferHandles,
const gl::AttribArray<VkDeviceSize> &arrayBufferOffsets)
{
// Vulkan does not allow binding a null vertex buffer but the default state of null buffers is
// valid.
// We can detect if there are no gaps in active attributes by using the mask of the program
// attribs and the max enabled attrib.
ASSERT(maxAttrib > 0);
if (nonNullAttribMask.to_ulong() == (maxAttrib - 1))
{
commandBuffer->bindVertexBuffers(0, maxAttrib, arrayBufferHandles.data(),
arrayBufferOffsets.data());
return;
}
// Find ranges of non-null buffers and bind them all together.
for (uint32_t attribIdx = 0; attribIdx < maxAttrib; attribIdx++)
{
if (arrayBufferHandles[attribIdx] != VK_NULL_HANDLE)
{
// Find the end of this range of non-null handles
uint32_t rangeCount = 1;
while (attribIdx + rangeCount < maxAttrib &&
arrayBufferHandles[attribIdx + rangeCount] != VK_NULL_HANDLE)
{
rangeCount++;
}
commandBuffer->bindVertexBuffers(attribIdx, rangeCount, &arrayBufferHandles[attribIdx],
&arrayBufferOffsets[attribIdx]);
attribIdx += rangeCount;
}
}
}
constexpr VkColorComponentFlags kAllColorChannelsMask = constexpr VkColorComponentFlags kAllColorChannelsMask =
(VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT |
VK_COLOR_COMPONENT_A_BIT); VK_COLOR_COMPONENT_A_BIT);
...@@ -251,7 +212,8 @@ angle::Result ContextVk::setupDraw(const gl::Context *context, ...@@ -251,7 +212,8 @@ angle::Result ContextVk::setupDraw(const gl::Context *context,
mGraphicsPipelineDesc->updateTopology(&mGraphicsPipelineTransition, mCurrentDrawMode); mGraphicsPipelineDesc->updateTopology(&mGraphicsPipelineTransition, mCurrentDrawMode);
} }
if (!mDrawFramebuffer->appendToStartedRenderPass(mRenderer, commandBufferOut)) if (!mDrawFramebuffer->appendToStartedRenderPass(mRenderer->getCurrentQueueSerial(),
commandBufferOut))
{ {
ANGLE_TRY(mDrawFramebuffer->startNewRenderPass(this, commandBufferOut)); ANGLE_TRY(mDrawFramebuffer->startNewRenderPass(this, commandBufferOut));
mDirtyBits |= mNewCommandBufferDirtyBits; mDirtyBits |= mNewCommandBufferDirtyBits;
...@@ -278,10 +240,11 @@ angle::Result ContextVk::setupDraw(const gl::Context *context, ...@@ -278,10 +240,11 @@ angle::Result ContextVk::setupDraw(const gl::Context *context,
// Flush any relevant dirty bits. // Flush any relevant dirty bits.
for (size_t dirtyBit : dirtyBits) for (size_t dirtyBit : dirtyBits)
{ {
mDirtyBits.reset(dirtyBit);
ANGLE_TRY((this->*mDirtyBitHandlers[dirtyBit])(context, *commandBufferOut)); ANGLE_TRY((this->*mDirtyBitHandlers[dirtyBit])(context, *commandBufferOut));
} }
mDirtyBits &= ~dirtyBitMask;
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -410,13 +373,15 @@ angle::Result ContextVk::handleDirtyTextures(const gl::Context *context, ...@@ -410,13 +373,15 @@ angle::Result ContextVk::handleDirtyTextures(const gl::Context *context,
angle::Result ContextVk::handleDirtyVertexBuffers(const gl::Context *context, angle::Result ContextVk::handleDirtyVertexBuffers(const gl::Context *context,
vk::CommandBuffer *commandBuffer) vk::CommandBuffer *commandBuffer)
{ {
BindNonNullVertexBufferRanges( uint32_t maxAttrib = mProgram->getState().getMaxActiveAttribLocation();
commandBuffer, mProgram->getState().getActiveAttribLocationsMask(), const gl::AttribArray<VkBuffer> &bufferHandles = mVertexArray->getCurrentArrayBufferHandles();
mProgram->getState().getMaxActiveAttribLocation(), const gl::AttribArray<VkDeviceSize> &bufferOffsets =
mVertexArray->getCurrentArrayBufferHandles(), mVertexArray->getCurrentArrayBufferOffsets()); mVertexArray->getCurrentArrayBufferOffsets();
const auto &arrayBufferResources = mVertexArray->getCurrentArrayBuffers(); commandBuffer->bindVertexBuffers(0, maxAttrib, bufferHandles.data(), bufferOffsets.data());
const gl::AttribArray<vk::BufferHelper *> &arrayBufferResources =
mVertexArray->getCurrentArrayBuffers();
vk::FramebufferHelper *framebuffer = mDrawFramebuffer->getFramebuffer(); vk::FramebufferHelper *framebuffer = mDrawFramebuffer->getFramebuffer();
for (size_t attribIndex : context->getStateCache().getActiveBufferedAttribsMask()) for (size_t attribIndex : context->getStateCache().getActiveBufferedAttribsMask())
...@@ -1023,7 +988,7 @@ BufferImpl *ContextVk::createBuffer(const gl::BufferState &state) ...@@ -1023,7 +988,7 @@ BufferImpl *ContextVk::createBuffer(const gl::BufferState &state)
VertexArrayImpl *ContextVk::createVertexArray(const gl::VertexArrayState &state) VertexArrayImpl *ContextVk::createVertexArray(const gl::VertexArrayState &state)
{ {
return new VertexArrayVk(state, mRenderer); return new VertexArrayVk(this, state);
} }
QueryImpl *ContextVk::createQuery(gl::QueryType type) QueryImpl *ContextVk::createQuery(gl::QueryType type)
......
...@@ -1030,7 +1030,7 @@ angle::Result FramebufferVk::getCommandBufferForDraw(ContextVk *contextVk, ...@@ -1030,7 +1030,7 @@ angle::Result FramebufferVk::getCommandBufferForDraw(ContextVk *contextVk,
RendererVk *renderer = contextVk->getRenderer(); RendererVk *renderer = contextVk->getRenderer();
// This will clear the current write operation if it is complete. // This will clear the current write operation if it is complete.
if (appendToStartedRenderPass(renderer, commandBufferOut)) if (appendToStartedRenderPass(renderer->getCurrentQueueSerial(), commandBufferOut))
{ {
*modeOut = vk::RecordingMode::Append; *modeOut = vk::RecordingMode::Append;
return angle::Result::Continue; return angle::Result::Continue;
......
...@@ -106,9 +106,9 @@ class FramebufferVk : public FramebufferImpl ...@@ -106,9 +106,9 @@ class FramebufferVk : public FramebufferImpl
RenderTargetVk *getColorReadRenderTarget() const; RenderTargetVk *getColorReadRenderTarget() const;
// This will clear the current write operation if it is complete. // This will clear the current write operation if it is complete.
bool appendToStartedRenderPass(RendererVk *renderer, vk::CommandBuffer **commandBufferOut) bool appendToStartedRenderPass(Serial currentQueueSerial, vk::CommandBuffer **commandBufferOut)
{ {
return mFramebuffer.appendToStartedRenderPass(renderer, commandBufferOut); return mFramebuffer.appendToStartedRenderPass(currentQueueSerial, commandBufferOut);
} }
vk::FramebufferHelper *getFramebuffer() { return &mFramebuffer; } vk::FramebufferHelper *getFramebuffer() { return &mFramebuffer; }
......
...@@ -614,7 +614,7 @@ angle::Result UtilsVk::clearImage(ContextVk *contextVk, ...@@ -614,7 +614,7 @@ angle::Result UtilsVk::clearImage(ContextVk *contextVk,
ANGLE_TRY(ensureImageClearResourcesInitialized(contextVk)); ANGLE_TRY(ensureImageClearResourcesInitialized(contextVk));
vk::CommandBuffer *commandBuffer; vk::CommandBuffer *commandBuffer;
if (!framebuffer->appendToStartedRenderPass(contextVk->getRenderer(), &commandBuffer)) if (!framebuffer->appendToStartedRenderPass(renderer->getCurrentQueueSerial(), &commandBuffer))
{ {
ANGLE_TRY(framebuffer->startNewRenderPass(contextVk, &commandBuffer)) ANGLE_TRY(framebuffer->startNewRenderPass(contextVk, &commandBuffer))
} }
......
...@@ -95,7 +95,7 @@ size_t GetVertexCount(BufferVk *srcBuffer, const gl::VertexBinding &binding, uin ...@@ -95,7 +95,7 @@ size_t GetVertexCount(BufferVk *srcBuffer, const gl::VertexBinding &binding, uin
kVertexBufferUsageFlags, 1024 * 8, true \ kVertexBufferUsageFlags, 1024 * 8, true \
} }
VertexArrayVk::VertexArrayVk(const gl::VertexArrayState &state, RendererVk *renderer) VertexArrayVk::VertexArrayVk(ContextVk *contextVk, const gl::VertexArrayState &state)
: VertexArrayImpl(state), : VertexArrayImpl(state),
mCurrentArrayBufferHandles{}, mCurrentArrayBufferHandles{},
mCurrentArrayBufferOffsets{}, mCurrentArrayBufferOffsets{},
...@@ -126,10 +126,18 @@ VertexArrayVk::VertexArrayVk(const gl::VertexArrayState &state, RendererVk *rend ...@@ -126,10 +126,18 @@ VertexArrayVk::VertexArrayVk(const gl::VertexArrayState &state, RendererVk *rend
mDynamicVertexData(kVertexBufferUsageFlags, kDynamicVertexDataSize, true), mDynamicVertexData(kVertexBufferUsageFlags, kDynamicVertexDataSize, true),
mDynamicIndexData(kIndexBufferUsageFlags, kDynamicIndexDataSize, true), mDynamicIndexData(kIndexBufferUsageFlags, kDynamicIndexDataSize, true),
mTranslatedByteIndexData(kIndexBufferUsageFlags, kDynamicIndexDataSize, true), mTranslatedByteIndexData(kIndexBufferUsageFlags, kDynamicIndexDataSize, true),
mLineLoopHelper(renderer), mLineLoopHelper(contextVk->getRenderer()),
mDirtyLineLoopTranslation(true) mDirtyLineLoopTranslation(true)
{ {
mCurrentArrayBufferHandles.fill(VK_NULL_HANDLE); RendererVk *renderer = contextVk->getRenderer();
VkBufferCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
createInfo.size = 16;
createInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
(void)mTheNullBuffer.init(contextVk, createInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
mCurrentArrayBufferHandles.fill(mTheNullBuffer.getBuffer().getHandle());
mCurrentArrayBufferOffsets.fill(0); mCurrentArrayBufferOffsets.fill(0);
mCurrentArrayBuffers.fill(nullptr); mCurrentArrayBuffers.fill(nullptr);
...@@ -148,6 +156,8 @@ void VertexArrayVk::destroy(const gl::Context *context) ...@@ -148,6 +156,8 @@ void VertexArrayVk::destroy(const gl::Context *context)
{ {
RendererVk *renderer = vk::GetImpl(context)->getRenderer(); RendererVk *renderer = vk::GetImpl(context)->getRenderer();
mTheNullBuffer.release(renderer);
for (vk::DynamicBuffer &buffer : mCurrentArrayBufferConversion) for (vk::DynamicBuffer &buffer : mCurrentArrayBufferConversion)
{ {
buffer.release(renderer); buffer.release(renderer);
...@@ -286,7 +296,7 @@ angle::Result VertexArrayVk::convertVertexBufferCpu(ContextVk *contextVk, ...@@ -286,7 +296,7 @@ angle::Result VertexArrayVk::convertVertexBufferCpu(ContextVk *contextVk,
return angle::Result::Continue; return angle::Result::Continue;
} }
void VertexArrayVk::ensureConversionReleased(RendererVk *renderer, size_t attribIndex) ANGLE_INLINE void VertexArrayVk::ensureConversionReleased(RendererVk *renderer, size_t attribIndex)
{ {
if (mCurrentArrayBufferConversionCanRelease[attribIndex]) if (mCurrentArrayBufferConversionCanRelease[attribIndex])
{ {
...@@ -297,8 +307,8 @@ void VertexArrayVk::ensureConversionReleased(RendererVk *renderer, size_t attrib ...@@ -297,8 +307,8 @@ void VertexArrayVk::ensureConversionReleased(RendererVk *renderer, size_t attrib
angle::Result VertexArrayVk::syncState(const gl::Context *context, angle::Result VertexArrayVk::syncState(const gl::Context *context,
const gl::VertexArray::DirtyBits &dirtyBits, const gl::VertexArray::DirtyBits &dirtyBits,
const gl::VertexArray::DirtyAttribBitsArray &attribBits, gl::VertexArray::DirtyAttribBitsArray *attribBits,
const gl::VertexArray::DirtyBindingBitsArray &bindingBits) gl::VertexArray::DirtyBindingBitsArray *bindingBits)
{ {
ASSERT(dirtyBits.any()); ASSERT(dirtyBits.any());
...@@ -347,6 +357,7 @@ angle::Result VertexArrayVk::syncState(const gl::Context *context, ...@@ -347,6 +357,7 @@ angle::Result VertexArrayVk::syncState(const gl::Context *context,
ANGLE_TRY(syncDirtyAttrib(contextVk, attribs[INDEX], \ ANGLE_TRY(syncDirtyAttrib(contextVk, attribs[INDEX], \
bindings[attribs[INDEX].bindingIndex], INDEX)); \ bindings[attribs[INDEX].bindingIndex], INDEX)); \
invalidateContext = true; \ invalidateContext = true; \
(*attribBits)[INDEX].reset(); \
break; break;
ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_ATTRIB_FUNC); ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_ATTRIB_FUNC);
...@@ -356,6 +367,7 @@ angle::Result VertexArrayVk::syncState(const gl::Context *context, ...@@ -356,6 +367,7 @@ angle::Result VertexArrayVk::syncState(const gl::Context *context,
ANGLE_TRY(syncDirtyAttrib(contextVk, attribs[INDEX], \ ANGLE_TRY(syncDirtyAttrib(contextVk, attribs[INDEX], \
bindings[attribs[INDEX].bindingIndex], INDEX)); \ bindings[attribs[INDEX].bindingIndex], INDEX)); \
invalidateContext = true; \ invalidateContext = true; \
(*bindingBits)[INDEX].reset(); \
break; break;
ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BINDING_FUNC); ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BINDING_FUNC);
...@@ -404,7 +416,6 @@ angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk, ...@@ -404,7 +416,6 @@ angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk,
size_t attribIndex) size_t attribIndex)
{ {
RendererVk *renderer = contextVk->getRenderer(); RendererVk *renderer = contextVk->getRenderer();
bool releaseConversion = true;
bool anyVertexBufferConvertedOnGpu = false; bool anyVertexBufferConvertedOnGpu = false;
if (attrib.enabled) if (attrib.enabled)
...@@ -436,8 +447,6 @@ angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk, ...@@ -436,8 +447,6 @@ angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk,
// http://anglebug.com/3009 // http://anglebug.com/3009
ANGLE_TRY(convertVertexBufferCpu(contextVk, bufferVk, binding, attribIndex)); ANGLE_TRY(convertVertexBufferCpu(contextVk, bufferVk, binding, attribIndex));
} }
releaseConversion = false;
} }
else else
{ {
...@@ -446,15 +455,17 @@ angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk, ...@@ -446,15 +455,17 @@ angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk,
bufferVk->getBuffer().getBuffer().getHandle(); bufferVk->getBuffer().getBuffer().getHandle();
mCurrentArrayBufferOffsets[attribIndex] = binding.getOffset(); mCurrentArrayBufferOffsets[attribIndex] = binding.getOffset();
mCurrentArrayBufferStrides[attribIndex] = binding.getStride(); mCurrentArrayBufferStrides[attribIndex] = binding.getStride();
ensureConversionReleased(renderer, attribIndex);
} }
} }
else else
{ {
mCurrentArrayBuffers[attribIndex] = nullptr; mCurrentArrayBuffers[attribIndex] = nullptr;
mCurrentArrayBufferHandles[attribIndex] = VK_NULL_HANDLE; mCurrentArrayBufferHandles[attribIndex] = mTheNullBuffer.getBuffer().getHandle();
mCurrentArrayBufferOffsets[attribIndex] = 0; mCurrentArrayBufferOffsets[attribIndex] = 0;
mCurrentArrayBufferStrides[attribIndex] = mCurrentArrayBufferStrides[attribIndex] =
mCurrentArrayBufferFormats[attribIndex]->bufferFormat().pixelBytes; mCurrentArrayBufferFormats[attribIndex]->bufferFormat().pixelBytes;
ensureConversionReleased(renderer, attribIndex);
} }
setPackedInputInfo(contextVk, attribIndex, attrib, binding); setPackedInputInfo(contextVk, attribIndex, attrib, binding);
...@@ -465,13 +476,14 @@ angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk, ...@@ -465,13 +476,14 @@ angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk,
// These will be filled out by the ContextVk. // These will be filled out by the ContextVk.
mCurrentArrayBuffers[attribIndex] = nullptr; mCurrentArrayBuffers[attribIndex] = nullptr;
mCurrentArrayBufferHandles[attribIndex] = VK_NULL_HANDLE; mCurrentArrayBufferHandles[attribIndex] = mTheNullBuffer.getBuffer().getHandle();
mCurrentArrayBufferOffsets[attribIndex] = 0; mCurrentArrayBufferOffsets[attribIndex] = 0;
mCurrentArrayBufferStrides[attribIndex] = 0; mCurrentArrayBufferStrides[attribIndex] = 0;
mCurrentArrayBufferFormats[attribIndex] = mCurrentArrayBufferFormats[attribIndex] =
&renderer->getFormat(angle::FormatID::R32G32B32A32_FLOAT); &renderer->getFormat(angle::FormatID::R32G32B32A32_FLOAT);
setDefaultPackedInput(contextVk, attribIndex); setDefaultPackedInput(contextVk, attribIndex);
ensureConversionReleased(renderer, attribIndex);
} }
if (anyVertexBufferConvertedOnGpu && renderer->getFeatures().flushAfterVertexConversion) if (anyVertexBufferConvertedOnGpu && renderer->getFeatures().flushAfterVertexConversion)
...@@ -479,9 +491,6 @@ angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk, ...@@ -479,9 +491,6 @@ angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk,
ANGLE_TRY(renderer->flush(contextVk)); ANGLE_TRY(renderer->flush(contextVk));
} }
if (releaseConversion)
ensureConversionReleased(renderer, attribIndex);
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -26,15 +26,15 @@ class RecordableGraphResource; ...@@ -26,15 +26,15 @@ class RecordableGraphResource;
class VertexArrayVk : public VertexArrayImpl class VertexArrayVk : public VertexArrayImpl
{ {
public: public:
VertexArrayVk(const gl::VertexArrayState &state, RendererVk *renderer); VertexArrayVk(ContextVk *contextVk, const gl::VertexArrayState &state);
~VertexArrayVk() override; ~VertexArrayVk() override;
void destroy(const gl::Context *context) override; void destroy(const gl::Context *context) override;
angle::Result syncState(const gl::Context *context, angle::Result syncState(const gl::Context *context,
const gl::VertexArray::DirtyBits &dirtyBits, const gl::VertexArray::DirtyBits &dirtyBits,
const gl::VertexArray::DirtyAttribBitsArray &attribBits, gl::VertexArray::DirtyAttribBitsArray *attribBits,
const gl::VertexArray::DirtyBindingBitsArray &bindingBits) override; gl::VertexArray::DirtyBindingBitsArray *bindingBits) override;
void updateDefaultAttrib(ContextVk *contextVk, void updateDefaultAttrib(ContextVk *contextVk,
size_t attribIndex, size_t attribIndex,
...@@ -130,6 +130,9 @@ class VertexArrayVk : public VertexArrayImpl ...@@ -130,6 +130,9 @@ class VertexArrayVk : public VertexArrayImpl
Optional<GLint> mLineLoopBufferFirstIndex; Optional<GLint> mLineLoopBufferFirstIndex;
Optional<size_t> mLineLoopBufferLastIndex; Optional<size_t> mLineLoopBufferLastIndex;
bool mDirtyLineLoopTranslation; bool mDirtyLineLoopTranslation;
// Vulkan does not allow binding a null vertex buffer. We use a dummy as a placeholder.
vk::BufferHelper mTheNullBuffer;
}; };
} // namespace rx } // namespace rx
......
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