Commit 0136ac37 by Jiacheng Lu Committed by Commit Bot

Separate dirty bit for attrib's binding VBO change

Make a separate dirty bit DIRTY_ATTRIB_POINTER_BUFFER for vertex attrib's binding buffer change. So in handling glVertexAttribPointer, ANGLE will only modify a vulkan graphics pipeline when attrib.format, attrib.stride or attrib.divisor change. If only the VBO pointer changes, then Vulkan can update the state via "vkCmdBindVertexBuffers()" without triggering a pipeline update. Bug: angleproject:3256 Change-Id: I01e02adde3708963b496a20050a5723e8eb57ab2 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1707614Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Jiacheng Lu <lujc@google.com>
parent 6aca71d7
......@@ -457,8 +457,6 @@ ANGLE_INLINE void VertexArray::setVertexAttribPointerImpl(const Context *context
{
ASSERT(attribIndex < getMaxAttribs());
GLintptr offset = boundBuffer ? reinterpret_cast<GLintptr>(pointer) : 0;
VertexAttribute &attrib = mState.mVertexAttributes[attribIndex];
SetComponentTypeMask(componentType, attribIndex, &mState.mVertexAttributesTypeMask);
......@@ -473,28 +471,35 @@ ANGLE_INLINE void VertexArray::setVertexAttribPointerImpl(const Context *context
GLsizei effectiveStride =
stride != 0 ? stride : static_cast<GLsizei>(ComputeVertexAttributeTypeSize(attrib));
if (pointer != attrib.pointer || attrib.vertexAttribArrayStride != static_cast<GLuint>(stride))
if (attrib.vertexAttribArrayStride != static_cast<GLuint>(stride))
{
attribDirty = true;
}
attrib.pointer = pointer;
attrib.vertexAttribArrayStride = stride;
// "Pointer buffer" dirty bit disabled because of a bug. http://anglebug.com/3256
bindVertexBufferImpl(context, attribIndex, boundBuffer, offset, effectiveStride);
setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_POINTER);
ANGLE_UNUSED_VARIABLE(attribDirty);
// if (bindVertexBufferImpl(context, attribIndex, boundBuffer, offset, effectiveStride) &&
// !attribDirty)
//{
// setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_POINTER_BUFFER);
//}
// else if (attribDirty)
//{
// setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_POINTER);
//}
// If we switch from an array buffer to a client pointer(or vice-versa), we set the whole
// attribute dirty. This notifies the Vulkan back-end to update all its caches.
const VertexBinding &binding = mState.mVertexBindings[attribIndex];
if ((boundBuffer == nullptr) != (binding.getBuffer().get() == nullptr))
{
attribDirty = true;
}
// Change of attrib.pointer is not part of attribDirty. Pointer is actually the buffer offset
// which is handled within bindVertexBufferImpl and reflected in bufferDirty.
attrib.pointer = pointer;
GLintptr offset = boundBuffer ? reinterpret_cast<GLintptr>(pointer) : 0;
const bool bufferDirty =
bindVertexBufferImpl(context, attribIndex, boundBuffer, offset, effectiveStride);
if (attribDirty)
{
setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_POINTER);
}
else if (bufferDirty)
{
setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_POINTER_BUFFER);
}
mState.mNullPointerClientMemoryAttribsMask.set(attribIndex,
boundBuffer == nullptr && pointer == nullptr);
......
......@@ -359,39 +359,36 @@ angle::Result VertexArrayVk::syncState(const gl::Context *context,
mDirtyLineLoopTranslation = true;
break;
#define ANGLE_VERTEX_DIRTY_ATTRIB_FUNC(INDEX) \
case gl::VertexArray::DIRTY_BIT_ATTRIB_0 + INDEX: \
if ((*attribBits)[INDEX].to_ulong() == \
angle::Bit<unsigned long>(gl::VertexArray::DIRTY_ATTRIB_POINTER_BUFFER)) \
{ \
syncDirtyBuffer(contextVk, bindings[INDEX], INDEX); \
} \
else \
{ \
ANGLE_TRY(syncDirtyAttrib(contextVk, attribs[INDEX], \
bindings[attribs[INDEX].bindingIndex], INDEX)); \
} \
(*attribBits)[INDEX].reset(); \
break;
#define ANGLE_VERTEX_DIRTY_ATTRIB_FUNC(INDEX) \
case gl::VertexArray::DIRTY_BIT_ATTRIB_0 + INDEX: \
{ \
const bool bufferOnly = \
(*attribBits)[INDEX].to_ulong() == \
angle::Bit<unsigned long>(gl::VertexArray::DIRTY_ATTRIB_POINTER_BUFFER); \
ANGLE_TRY(syncDirtyAttrib(contextVk, attribs[INDEX], \
bindings[attribs[INDEX].bindingIndex], INDEX, bufferOnly)); \
(*attribBits)[INDEX].reset(); \
break; \
}
ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_ATTRIB_FUNC)
#define ANGLE_VERTEX_DIRTY_BINDING_FUNC(INDEX) \
case gl::VertexArray::DIRTY_BIT_BINDING_0 + INDEX: \
for (size_t attribIndex : bindings[INDEX].getBoundAttributesMask()) \
{ \
ANGLE_TRY( \
syncDirtyAttrib(contextVk, attribs[attribIndex], bindings[INDEX], attribIndex)); \
} \
(*bindingBits)[INDEX].reset(); \
#define ANGLE_VERTEX_DIRTY_BINDING_FUNC(INDEX) \
case gl::VertexArray::DIRTY_BIT_BINDING_0 + INDEX: \
for (size_t attribIndex : bindings[INDEX].getBoundAttributesMask()) \
{ \
ANGLE_TRY(syncDirtyAttrib(contextVk, attribs[attribIndex], bindings[INDEX], \
attribIndex, false)); \
} \
(*bindingBits)[INDEX].reset(); \
break;
ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BINDING_FUNC)
#define ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC(INDEX) \
case gl::VertexArray::DIRTY_BIT_BUFFER_DATA_0 + INDEX: \
ANGLE_TRY(syncDirtyAttrib(contextVk, attribs[INDEX], \
bindings[attribs[INDEX].bindingIndex], INDEX)); \
#define ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC(INDEX) \
case gl::VertexArray::DIRTY_BIT_BUFFER_DATA_0 + INDEX: \
ANGLE_TRY(syncDirtyAttrib(contextVk, attribs[INDEX], \
bindings[attribs[INDEX].bindingIndex], INDEX, false)); \
break;
ANGLE_VERTEX_INDEX_CASES(ANGLE_VERTEX_DIRTY_BUFFER_DATA_FUNC)
......@@ -423,17 +420,17 @@ ANGLE_INLINE void VertexArrayVk::setDefaultPackedInput(ContextVk *contextVk, siz
angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk,
const gl::VertexAttribute &attrib,
const gl::VertexBinding &binding,
size_t attribIndex)
size_t attribIndex,
bool bufferOnly)
{
RendererVk *renderer = contextVk->getRenderer();
bool anyVertexBufferConvertedOnGpu = false;
if (attrib.enabled)
{
gl::Buffer *bufferGL = binding.getBuffer().get();
RendererVk *renderer = contextVk->getRenderer();
const vk::Format &vertexFormat = renderer->getFormat(attrib.format->id);
GLuint stride;
GLuint stride;
bool anyVertexBufferConvertedOnGpu = false;
gl::Buffer *bufferGL = binding.getBuffer().get();
if (bufferGL)
{
BufferVk *bufferVk = vk::GetImpl(bufferGL);
......@@ -443,8 +440,6 @@ angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk,
if (vertexFormat.vertexLoadRequiresConversion || !bindingIsAligned)
{
stride = vertexFormat.bufferFormat().pixelBytes;
ConversionBuffer *conversion = bufferVk->getVertexConversionBuffer(
renderer, angleFormat.id, binding.getStride(),
binding.getOffset() + attrib.relativeOffset);
......@@ -463,13 +458,21 @@ angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk,
vertexFormat, conversion,
attrib.relativeOffset));
}
// If conversion happens, the destination buffer stride may be changed,
// therefore an attribute change needs to be called. Note that it may trigger
// unnecessary vulkan PSO update when the destination buffer stride does not
// change, but for simplity just make it conservative
bufferOnly = false;
}
mCurrentArrayBuffers[attribIndex] = conversion->data.getCurrentBuffer();
mCurrentArrayBufferHandles[attribIndex] =
mCurrentArrayBuffers[attribIndex]->getBuffer().getHandle();
mCurrentArrayBufferOffsets[attribIndex] =
conversion->lastAllocationOffset - attrib.relativeOffset;
vk::BufferHelper *bufferHelper = conversion->data.getCurrentBuffer();
mCurrentArrayBuffers[attribIndex] = bufferHelper;
mCurrentArrayBufferHandles[attribIndex] = bufferHelper->getBuffer().getHandle();
mCurrentArrayBufferOffsets[attribIndex] = conversion->lastAllocationOffset;
// Converted buffer is tightly packed
stride = vertexFormat.bufferFormat().pixelBytes;
}
else
{
......@@ -484,7 +487,6 @@ angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk,
else
{
vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
mCurrentArrayBuffers[attribIndex] = &bufferHelper;
mCurrentArrayBufferHandles[attribIndex] = bufferHelper.getBuffer().getHandle();
mCurrentArrayBufferOffsets[attribIndex] = binding.getOffset();
......@@ -497,11 +499,25 @@ angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk,
mCurrentArrayBuffers[attribIndex] = &mTheNullBuffer;
mCurrentArrayBufferHandles[attribIndex] = mTheNullBuffer.getBuffer().getHandle();
mCurrentArrayBufferOffsets[attribIndex] = 0;
stride = vertexFormat.bufferFormat().pixelBytes;
// Client side buffer will be transfered to a tightly packed buffer later
stride = vertexFormat.bufferFormat().pixelBytes;
}
if (bufferOnly)
{
contextVk->invalidateVertexBuffers();
}
else
{
contextVk->onVertexAttributeChange(attribIndex, stride, binding.getDivisor(),
attrib.format->id, attrib.relativeOffset);
}
contextVk->onVertexAttributeChange(attribIndex, stride, binding.getDivisor(),
attrib.format->id, attrib.relativeOffset);
if (anyVertexBufferConvertedOnGpu &&
renderer->getFeatures().flushAfterVertexConversion.enabled)
{
ANGLE_TRY(contextVk->flushImpl(nullptr));
}
}
else
{
......@@ -515,38 +531,9 @@ angle::Result VertexArrayVk::syncDirtyAttrib(ContextVk *contextVk,
setDefaultPackedInput(contextVk, attribIndex);
}
if (anyVertexBufferConvertedOnGpu && renderer->getFeatures().flushAfterVertexConversion.enabled)
{
ANGLE_TRY(contextVk->flushImpl(nullptr));
}
return angle::Result::Continue;
}
void VertexArrayVk::syncDirtyBuffer(ContextVk *contextVk,
const gl::VertexBinding &binding,
size_t bindingIndex)
{
gl::Buffer *bufferGL = binding.getBuffer().get();
if (bufferGL)
{
BufferVk *bufferVk = vk::GetImpl(bufferGL);
vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
mCurrentArrayBuffers[bindingIndex] = &bufferHelper;
mCurrentArrayBufferHandles[bindingIndex] = bufferHelper.getBuffer().getHandle();
mCurrentArrayBufferOffsets[bindingIndex] = binding.getOffset();
}
else
{
mCurrentArrayBuffers[bindingIndex] = &mTheNullBuffer;
mCurrentArrayBufferHandles[bindingIndex] = mTheNullBuffer.getBuffer().getHandle();
mCurrentArrayBufferOffsets[bindingIndex] = 0;
}
contextVk->invalidateVertexBuffers();
}
angle::Result VertexArrayVk::updateClientAttribs(const gl::Context *context,
GLint firstVertex,
GLsizei vertexOrIndexCount,
......
......@@ -108,11 +108,8 @@ class VertexArrayVk : public VertexArrayImpl
angle::Result syncDirtyAttrib(ContextVk *contextVk,
const gl::VertexAttribute &attrib,
const gl::VertexBinding &binding,
size_t attribIndex);
void syncDirtyBuffer(ContextVk *contextVk,
const gl::VertexBinding &binding,
size_t bindingIndex);
size_t attribIndex,
bool bufferOnly);
gl::AttribArray<VkBuffer> mCurrentArrayBufferHandles;
gl::AttribArray<VkDeviceSize> mCurrentArrayBufferOffsets;
......
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