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 @@
#include "libANGLE/renderer/vulkan/BufferVk.h"
#include "common/FixedVector.h"
#include "common/debug.h"
#include "common/mathutil.h"
#include "common/utilities.h"
......@@ -103,6 +104,13 @@ ANGLE_INLINE VkMemoryPropertyFlags GetPreferredMemoryType(gl::BufferBinding targ
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
// ConversionBuffer implementation.
......@@ -506,12 +514,56 @@ angle::Result BufferVk::stagedUpdate(ContextVk *contextVk,
// Enqueue a copy command on the GPU.
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());
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,
const uint8_t *data,
size_t size,
......@@ -521,15 +573,14 @@ angle::Result BufferVk::setDataImpl(ContextVk *contextVk,
updateShadowBuffer(data, size, offset);
// 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 update the buffer directly
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(directUpdate(contextVk, data, size, offset));
ANGLE_TRY(acquireAndUpdate(contextVk, data, size, offset));
}
else
{
......
......@@ -139,6 +139,10 @@ class BufferVk : public BufferImpl
const uint8_t *data,
size_t size,
size_t offset);
angle::Result acquireAndUpdate(ContextVk *contextVk,
const uint8_t *data,
size_t size,
size_t offset);
angle::Result setDataImpl(ContextVk *contextVk,
const uint8_t *data,
size_t size,
......
......@@ -2224,14 +2224,15 @@ void BufferHelper::release(RendererVk *renderer)
angle::Result BufferHelper::copyFromBuffer(ContextVk *contextVk,
BufferHelper *srcBuffer,
const VkBufferCopy &copyRegion)
uint32_t regionCount,
const VkBufferCopy *copyRegions)
{
CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(contextVk->onBufferTransferRead(srcBuffer));
ANGLE_TRY(contextVk->onBufferTransferWrite(this));
ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
commandBuffer->copyBuffer(srcBuffer->getBuffer(), mBuffer, 1, &copyRegion);
commandBuffer->copyBuffer(srcBuffer->getBuffer(), mBuffer, regionCount, copyRegions);
return angle::Result::Continue;
}
......
......@@ -716,7 +716,8 @@ class BufferHelper final : public Resource
// Also implicitly sets up the correct barriers.
angle::Result copyFromBuffer(ContextVk *contextVk,
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
// based on format.
......
......@@ -27,8 +27,8 @@ struct BufferSubDataParams final : public RenderTestParams
minorVersion = 0;
windowWidth = 512;
windowHeight = 512;
updateSize = 3000;
bufferSize = 40000000;
updateSize = 32000;
bufferSize = 40000;
iterationsPerStep = kIterationsPerStep;
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