Commit de309a42 by Charlie Lao Committed by Commit Bot

Vulkan: Make staging buffer per context

Right now staging buffers are per BufferVk. This will make it per ContextVk so that it can be shared among all objects that needs a staging buffer. Bug: b/161846868 Change-Id: I9c436acdacaf429a43cbdfa216927df0796f7a28 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2310962Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarCourtney Goeltzenleuchter <courtneygo@google.com> Reviewed-by: 's avatarIan Elliott <ianelliott@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Charlie Lao <cclao@google.com>
parent db88baa8
......@@ -33,33 +33,6 @@ 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;
}
}
// Buffers that have a static usage pattern will be allocated in
// device local memory to speed up access to and from the GPU.
// Dynamic usage patterns or that are frequently mapped
......@@ -163,7 +136,6 @@ void BufferVk::destroy(const gl::Context *context)
void BufferVk::release(ContextVk *contextVk)
{
RendererVk *renderer = contextVk->getRenderer();
mStagingBuffer.release(renderer);
mShadowBuffer.release();
mBufferPool.release(renderer);
mBuffer = nullptr;
......@@ -174,18 +146,6 @@ 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::initializeShadowBuffer(ContextVk *contextVk,
gl::BufferBinding target,
size_t size)
......@@ -258,9 +218,6 @@ angle::Result BufferVk::setData(const gl::Context *context,
ANGLE_TRY(acquireBufferHelper(contextVk, size, &mBuffer));
// Initialize the staging buffer
initializeStagingBuffer(contextVk, target, size);
// Initialize the shadow buffer
ANGLE_TRY(initializeShadowBuffer(contextVk, target, size));
}
......@@ -530,29 +487,23 @@ angle::Result BufferVk::stagedUpdate(ContextVk *contextVk,
size_t offset)
{
// Acquire a "new" staging buffer
bool needToReleasePreviousBuffers = false;
uint8_t *mapPointer = nullptr;
VkDeviceSize stagingBufferOffset = 0;
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);
}
vk::DynamicBuffer *stagingBuffer = contextVk->getStagingBufferStorage();
ANGLE_TRY(stagingBuffer->allocate(contextVk, size, &mapPointer, nullptr, &stagingBufferOffset,
nullptr));
ASSERT(mapPointer);
memcpy(mapPointer, data, size);
ASSERT(!mStagingBuffer.isCoherent());
ANGLE_TRY(mStagingBuffer.flush(contextVk));
mStagingBuffer.getCurrentBuffer()->onExternalWrite(VK_ACCESS_HOST_WRITE_BIT);
ASSERT(!stagingBuffer->isCoherent());
ANGLE_TRY(stagingBuffer->flush(contextVk));
stagingBuffer->getCurrentBuffer()->onExternalWrite(VK_ACCESS_HOST_WRITE_BIT);
// Enqueue a copy command on the GPU.
VkBufferCopy copyRegion = {stagingBufferOffset, offset, size};
ANGLE_TRY(
mBuffer->copyFromBuffer(contextVk, mStagingBuffer.getCurrentBuffer(), 1, &copyRegion));
mStagingBuffer.getCurrentBuffer()->retain(&contextVk->getResourceUseList());
mBuffer->copyFromBuffer(contextVk, stagingBuffer->getCurrentBuffer(), 1, &copyRegion));
return angle::Result::Continue;
}
......
......@@ -121,7 +121,6 @@ class BufferVk : public BufferImpl
bool hostVisible);
private:
void initializeStagingBuffer(ContextVk *contextVk, gl::BufferBinding target, size_t size);
angle::Result initializeShadowBuffer(ContextVk *contextVk,
gl::BufferBinding target,
size_t size);
......@@ -182,9 +181,6 @@ class BufferVk : public BufferImpl
// Pool of BufferHelpers for mBuffer to acquire from
vk::DynamicBuffer mBufferPool;
// All staging buffer support is provided by a DynamicBuffer.
vk::DynamicBuffer mStagingBuffer;
// For GPU-read only buffers glMap* latency is reduced by maintaining a copy
// of the buffer which is writeable only by the CPU. The contents are updated on all
// glData/glSubData/glCopy calls. With this, a glMap* call becomes a non-blocking
......
......@@ -752,6 +752,7 @@ void ContextVk::onDestroy(const gl::Context *context)
mDefaultUniformStorage.release(mRenderer);
mEmptyBuffer.release(mRenderer);
mStagingBufferStorage.release(mRenderer);
for (vk::DynamicBuffer &defaultBuffer : mDefaultAttribBuffers)
{
......@@ -906,6 +907,13 @@ angle::Result ContextVk::initialize()
constexpr VkMemoryPropertyFlags kMemoryType = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
ANGLE_TRY(mEmptyBuffer.init(this, emptyBufferInfo, kMemoryType));
constexpr VkImageUsageFlags kStagingBufferUsageFlags = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
size_t stagingBufferAlignment =
static_cast<size_t>(mRenderer->getPhysicalDeviceProperties().limits.minMemoryMapAlignment);
constexpr size_t kStagingBufferSize = 1024u * 1024u; // 1M
mStagingBufferStorage.init(mRenderer, kStagingBufferUsageFlags, stagingBufferAlignment,
kStagingBufferSize, true);
return angle::Result::Continue;
}
......@@ -3972,6 +3980,7 @@ angle::Result ContextVk::flushImpl(const vk::Semaphore *signalSemaphore)
driverUniform.dynamicBuffer.releaseInFlightBuffersToResourceUseList(this);
}
mDefaultUniformStorage.releaseInFlightBuffersToResourceUseList(this);
mStagingBufferStorage.releaseInFlightBuffersToResourceUseList(this);
if (mRenderer->getFeatures().enableCommandProcessingThread.enabled)
{
......
......@@ -591,6 +591,7 @@ class ContextVk : public ContextImpl, public vk::Context
void setDefaultUniformBlocksMinSizeForTesting(size_t minSize);
vk::BufferHelper &getEmptyBuffer() { return mEmptyBuffer; }
vk::DynamicBuffer *getStagingBufferStorage() { return &mStagingBufferStorage; }
private:
// Dirty bits.
......@@ -1065,15 +1066,18 @@ class ContextVk : public ContextImpl, public vk::Context
ShareGroupVk *mShareGroupVk;
// Storage for default uniforms of ProgramVks and ProgramPipelineVks.
vk::DynamicBuffer mDefaultUniformStorage;
// This is a special "empty" placeholder buffer for use when we just need a dummy buffer but not
// the data. Examples are shader that has no uniform or doesn't use all slots in the atomic
// counter buffer array, or places where there is no vertex buffer since Vulkan does not allow
// binding a null vertex buffer.
vk::BufferHelper mEmptyBuffer;
// Storage for default uniforms of ProgramVks and ProgramPipelineVks.
vk::DynamicBuffer mDefaultUniformStorage;
// All staging buffer support is provided by a DynamicBuffer.
vk::DynamicBuffer mStagingBufferStorage;
std::vector<std::string> mCommandBufferDiagnostics;
};
......
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