Commit cf8422c2 by Mohan Maiya Committed by Commit Bot

Vulkan: Acquire a new BufferHelper from the pool based on a threshold

We acquire a new BufferHelper from the pool when the app updates the data of the entire buffer. In scenarios where the app updates say, 60% of the buffer it would still be benificial to acquire a new buffer and copy over the remaining 40% of data from the old buffer to the new one. This reduces the transfer workload from 60% to 40% of buffer size. Currently the threshold is set to 50% of buffer size. Bug: angleproject:4380 Change-Id: I12576c585230e771d4c1a4352fab93dd3db2ecef Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2204655 Commit-Queue: Mohan Maiya <m.maiya@samsung.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 258d94f6
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "libANGLE/renderer/vulkan/BufferVk.h" #include "libANGLE/renderer/vulkan/BufferVk.h"
#include "common/FixedVector.h"
#include "common/debug.h" #include "common/debug.h"
#include "common/mathutil.h" #include "common/mathutil.h"
#include "common/utilities.h" #include "common/utilities.h"
...@@ -103,6 +104,13 @@ ANGLE_INLINE VkMemoryPropertyFlags GetPreferredMemoryType(gl::BufferBinding targ ...@@ -103,6 +104,13 @@ ANGLE_INLINE VkMemoryPropertyFlags GetPreferredMemoryType(gl::BufferBinding targ
return kHostCachedFlags; return kHostCachedFlags;
} }
} }
ANGLE_INLINE bool SubDataSizeMeetsThreshold(size_t subDataSize, size_t bufferSize)
{
// A sub data update with size > 50% of buffer size meets the threshold
// to acquire a new BufferHelper from the pool.
return subDataSize > (bufferSize / 2);
}
} // namespace } // namespace
// ConversionBuffer implementation. // ConversionBuffer implementation.
...@@ -506,12 +514,56 @@ angle::Result BufferVk::stagedUpdate(ContextVk *contextVk, ...@@ -506,12 +514,56 @@ angle::Result BufferVk::stagedUpdate(ContextVk *contextVk,
// Enqueue a copy command on the GPU. // Enqueue a copy command on the GPU.
VkBufferCopy copyRegion = {stagingBufferOffset, offset, size}; VkBufferCopy copyRegion = {stagingBufferOffset, offset, size};
ANGLE_TRY(mBuffer->copyFromBuffer(contextVk, mStagingBuffer.getCurrentBuffer(), copyRegion)); ANGLE_TRY(
mBuffer->copyFromBuffer(contextVk, mStagingBuffer.getCurrentBuffer(), 1, &copyRegion));
mStagingBuffer.getCurrentBuffer()->retain(&contextVk->getResourceUseList()); mStagingBuffer.getCurrentBuffer()->retain(&contextVk->getResourceUseList());
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result BufferVk::acquireAndUpdate(ContextVk *contextVk,
const uint8_t *data,
size_t size,
size_t offset)
{
// Here we acquire a new BufferHelper and directUpdate() the new buffer.
// If the subData size was less than the buffer's size we additionally enqueue
// a GPU copy of the remaining regions from the old mBuffer to the new one.
vk::BufferHelper *src = mBuffer;
size_t offsetAfterSubdata = (offset + size);
bool updateRegionBeforeSubData = (offset > 0);
bool updateRegionAfterSubData = (offsetAfterSubdata < static_cast<size_t>(mState.getSize()));
if (updateRegionBeforeSubData || updateRegionAfterSubData)
{
src->retain(&contextVk->getResourceUseList());
}
ANGLE_TRY(acquireBufferHelper(contextVk, size, &mBuffer));
ANGLE_TRY(directUpdate(contextVk, data, size, offset));
constexpr int kMaxCopyRegions = 2;
angle::FixedVector<VkBufferCopy, kMaxCopyRegions> copyRegions;
if (updateRegionBeforeSubData)
{
copyRegions.push_back({0, 0, offset});
}
if (updateRegionAfterSubData)
{
copyRegions.push_back({offsetAfterSubdata, offsetAfterSubdata,
(static_cast<size_t>(mState.getSize()) - offsetAfterSubdata)});
}
if (!copyRegions.empty())
{
ANGLE_TRY(mBuffer->copyFromBuffer(contextVk, src, static_cast<uint32_t>(copyRegions.size()),
copyRegions.data()));
}
return angle::Result::Continue;
}
angle::Result BufferVk::setDataImpl(ContextVk *contextVk, angle::Result BufferVk::setDataImpl(ContextVk *contextVk,
const uint8_t *data, const uint8_t *data,
size_t size, size_t size,
...@@ -521,15 +573,14 @@ angle::Result BufferVk::setDataImpl(ContextVk *contextVk, ...@@ -521,15 +573,14 @@ angle::Result BufferVk::setDataImpl(ContextVk *contextVk,
updateShadowBuffer(data, size, offset); updateShadowBuffer(data, size, offset);
// if the buffer is currently in use // if the buffer is currently in use
// if size matches mBuffer's size, acquire a new BufferHelper from the pool // if sub data size meets threshold, acquire a new BufferHelper from the pool
// else stage an update // else stage an update
// else update the buffer directly // else update the buffer directly
if (mBuffer->isCurrentlyInUse(contextVk->getLastCompletedQueueSerial())) if (mBuffer->isCurrentlyInUse(contextVk->getLastCompletedQueueSerial()))
{ {
if (size == static_cast<size_t>(mState.getSize())) if (SubDataSizeMeetsThreshold(size, static_cast<size_t>(mState.getSize())))
{ {
ANGLE_TRY(acquireBufferHelper(contextVk, size, &mBuffer)); ANGLE_TRY(acquireAndUpdate(contextVk, data, size, offset));
ANGLE_TRY(directUpdate(contextVk, data, size, offset));
} }
else else
{ {
......
...@@ -139,6 +139,10 @@ class BufferVk : public BufferImpl ...@@ -139,6 +139,10 @@ class BufferVk : public BufferImpl
const uint8_t *data, const uint8_t *data,
size_t size, size_t size,
size_t offset); size_t offset);
angle::Result acquireAndUpdate(ContextVk *contextVk,
const uint8_t *data,
size_t size,
size_t offset);
angle::Result setDataImpl(ContextVk *contextVk, angle::Result setDataImpl(ContextVk *contextVk,
const uint8_t *data, const uint8_t *data,
size_t size, size_t size,
......
...@@ -2224,14 +2224,15 @@ void BufferHelper::release(RendererVk *renderer) ...@@ -2224,14 +2224,15 @@ void BufferHelper::release(RendererVk *renderer)
angle::Result BufferHelper::copyFromBuffer(ContextVk *contextVk, angle::Result BufferHelper::copyFromBuffer(ContextVk *contextVk,
BufferHelper *srcBuffer, BufferHelper *srcBuffer,
const VkBufferCopy &copyRegion) uint32_t regionCount,
const VkBufferCopy *copyRegions)
{ {
CommandBuffer *commandBuffer = nullptr; CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(contextVk->onBufferTransferRead(srcBuffer)); ANGLE_TRY(contextVk->onBufferTransferRead(srcBuffer));
ANGLE_TRY(contextVk->onBufferTransferWrite(this)); ANGLE_TRY(contextVk->onBufferTransferWrite(this));
ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer)); ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
commandBuffer->copyBuffer(srcBuffer->getBuffer(), mBuffer, 1, &copyRegion); commandBuffer->copyBuffer(srcBuffer->getBuffer(), mBuffer, regionCount, copyRegions);
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -716,7 +716,8 @@ class BufferHelper final : public Resource ...@@ -716,7 +716,8 @@ class BufferHelper final : public Resource
// Also implicitly sets up the correct barriers. // Also implicitly sets up the correct barriers.
angle::Result copyFromBuffer(ContextVk *contextVk, angle::Result copyFromBuffer(ContextVk *contextVk,
BufferHelper *srcBuffer, BufferHelper *srcBuffer,
const VkBufferCopy &copyRegion); uint32_t regionCount,
const VkBufferCopy *copyRegions);
// Note: currently only one view is allowed. If needs be, multiple views can be created // Note: currently only one view is allowed. If needs be, multiple views can be created
// based on format. // based on format.
......
...@@ -27,8 +27,8 @@ struct BufferSubDataParams final : public RenderTestParams ...@@ -27,8 +27,8 @@ struct BufferSubDataParams final : public RenderTestParams
minorVersion = 0; minorVersion = 0;
windowWidth = 512; windowWidth = 512;
windowHeight = 512; windowHeight = 512;
updateSize = 3000; updateSize = 32000;
bufferSize = 40000000; bufferSize = 40000;
iterationsPerStep = kIterationsPerStep; iterationsPerStep = kIterationsPerStep;
updateRate = 1; updateRate = 1;
} }
......
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