Commit 01c0d6bd by Mohan Maiya Committed by Commit Bot

Vulkan: Use dynamic buffers for staged updates

Dynamic buffers are used to perform staged updates to BufferVk objects instead of recreating staging buffers for each update. Bug: angleproject:4292 Change-Id: I0f64c821c97e0e6014e9df1d4f99e2f495838025 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2001461 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org>
parent 0d2c75f4
......@@ -40,8 +40,10 @@ inline constexpr bool isPow2(T x)
return (x & (x - 1)) == 0 && (x != 0);
}
inline int log2(int x)
template <typename T>
inline int log2(T x)
{
static_assert(std::is_integral<T>::value, "log2 must be called on an integer type.");
int r = 0;
while ((x >> r) > 1)
r++;
......
......@@ -10,6 +10,7 @@
#include "libANGLE/renderer/vulkan/BufferVk.h"
#include "common/debug.h"
#include "common/mathutil.h"
#include "common/utilities.h"
#include "libANGLE/Context.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
......@@ -30,6 +31,33 @@ static_assert(gl::isPow2(kBufferSizeGranularity), "use as alignment, must be pow
// Start with a fairly small buffer size. We can increase this dynamically as we convert more data.
constexpr size_t kConvertedArrayBufferInitialSize = 1024 * 8;
// Base size for all staging buffers
constexpr size_t kStagingBufferBaseSize = 1024;
// Fix the staging buffer size multiplier for unpack buffers, for now
constexpr size_t kUnpackBufferStagingBufferMultiplier = 1024;
size_t CalculateStagingBufferSize(gl::BufferBinding target, size_t size, size_t alignment)
{
size_t alignedSize = rx::roundUp(size, alignment);
int multiplier = std::max(gl::log2(alignedSize), 1);
switch (target)
{
case gl::BufferBinding::Array:
case gl::BufferBinding::DrawIndirect:
case gl::BufferBinding::ElementArray:
case gl::BufferBinding::Uniform:
return kStagingBufferBaseSize * multiplier;
case gl::BufferBinding::PixelUnpack:
return std::max(alignedSize,
(kStagingBufferBaseSize * kUnpackBufferStagingBufferMultiplier));
default:
return kStagingBufferBaseSize;
}
}
} // namespace
// ConversionBuffer implementation.
......@@ -80,6 +108,7 @@ void BufferVk::release(ContextVk *contextVk)
{
RendererVk *renderer = contextVk->getRenderer();
mBuffer.release(renderer);
mStagingBuffer.release(renderer);
for (ConversionBuffer &buffer : mVertexConversionBuffers)
{
......@@ -87,6 +116,18 @@ void BufferVk::release(ContextVk *contextVk)
}
}
void BufferVk::initializeStagingBuffer(ContextVk *contextVk, gl::BufferBinding target, size_t size)
{
RendererVk *rendererVk = contextVk->getRenderer();
constexpr VkImageUsageFlags kBufferUsageFlags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
size_t alignment =
static_cast<size_t>(rendererVk->getPhysicalDeviceProperties().limits.minMemoryMapAlignment);
size_t stagingBufferSize = CalculateStagingBufferSize(target, size, alignment);
mStagingBuffer.init(rendererVk, kBufferUsageFlags, alignment, stagingBufferSize, true);
}
angle::Result BufferVk::setData(const gl::Context *context,
gl::BufferBinding target,
const void *data,
......@@ -127,6 +168,9 @@ angle::Result BufferVk::setData(const gl::Context *context,
(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
ANGLE_TRY(mBuffer.init(contextVk, createInfo, memoryPropertyFlags));
// Initialize the staging buffer
initializeStagingBuffer(contextVk, target, size);
}
if (data && size > 0)
......@@ -315,25 +359,27 @@ angle::Result BufferVk::setDataImpl(ContextVk *contextVk,
// Use map when available.
if (mBuffer.isResourceInUse(contextVk))
{
vk::StagingBuffer stagingBuffer;
ANGLE_TRY(stagingBuffer.init(contextVk, static_cast<VkDeviceSize>(size),
vk::StagingUsage::Write));
uint8_t *mapPointer = nullptr;
ANGLE_VK_TRY(contextVk,
stagingBuffer.getDeviceMemory().map(device, 0, size, 0, &mapPointer));
// Acquire a "new" staging buffer
bool needToReleasePreviousBuffers = false;
uint8_t *mapPointer = nullptr;
VkDeviceSize stagingBufferOffset = 0;
ANGLE_TRY(mStagingBuffer.allocate(contextVk, size, &mapPointer, nullptr,
&stagingBufferOffset, &needToReleasePreviousBuffers));
if (needToReleasePreviousBuffers)
{
// Release previous staging buffers
mStagingBuffer.releaseInFlightBuffers(contextVk);
}
ASSERT(mapPointer);
memcpy(mapPointer, data, size);
stagingBuffer.getDeviceMemory().unmap(device);
// Enqueue a copy command on the GPU.
VkBufferCopy copyRegion = {0, offset, size};
ANGLE_TRY(mBuffer.copyFromBuffer(contextVk, stagingBuffer.getBuffer(),
VkBufferCopy copyRegion = {stagingBufferOffset, offset, size};
ANGLE_TRY(mBuffer.copyFromBuffer(contextVk, mStagingBuffer.getCurrentBuffer()->getBuffer(),
VK_ACCESS_HOST_WRITE_BIT, copyRegion));
// Immediately release staging buffer. We should probably be using a DynamicBuffer here.
stagingBuffer.release(contextVk);
mStagingBuffer.getCurrentBuffer()->onGraphAccess(contextVk->getCommandGraph());
}
else
{
......
......@@ -113,6 +113,7 @@ class BufferVk : public BufferImpl
size_t offset);
private:
void initializeStagingBuffer(ContextVk *contextVk, gl::BufferBinding target, size_t size);
angle::Result setDataImpl(ContextVk *contextVk,
const uint8_t *data,
size_t size,
......@@ -138,6 +139,9 @@ class BufferVk : public BufferImpl
vk::BufferHelper mBuffer;
// All staging buffer support is provided by a DynamicBuffer.
vk::DynamicBuffer mStagingBuffer;
// A cache of converted vertex data.
std::vector<VertexConversionBuffer> mVertexConversionBuffers;
};
......
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