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 ...@@ -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. // Start with a fairly small buffer size. We can increase this dynamically as we convert more data.
constexpr size_t kConvertedArrayBufferInitialSize = 1024 * 8; 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 // Buffers that have a static usage pattern will be allocated in
// device local memory to speed up access to and from the GPU. // device local memory to speed up access to and from the GPU.
// Dynamic usage patterns or that are frequently mapped // Dynamic usage patterns or that are frequently mapped
...@@ -163,7 +136,6 @@ void BufferVk::destroy(const gl::Context *context) ...@@ -163,7 +136,6 @@ void BufferVk::destroy(const gl::Context *context)
void BufferVk::release(ContextVk *contextVk) void BufferVk::release(ContextVk *contextVk)
{ {
RendererVk *renderer = contextVk->getRenderer(); RendererVk *renderer = contextVk->getRenderer();
mStagingBuffer.release(renderer);
mShadowBuffer.release(); mShadowBuffer.release();
mBufferPool.release(renderer); mBufferPool.release(renderer);
mBuffer = nullptr; mBuffer = nullptr;
...@@ -174,18 +146,6 @@ void BufferVk::release(ContextVk *contextVk) ...@@ -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, angle::Result BufferVk::initializeShadowBuffer(ContextVk *contextVk,
gl::BufferBinding target, gl::BufferBinding target,
size_t size) size_t size)
...@@ -258,9 +218,6 @@ angle::Result BufferVk::setData(const gl::Context *context, ...@@ -258,9 +218,6 @@ angle::Result BufferVk::setData(const gl::Context *context,
ANGLE_TRY(acquireBufferHelper(contextVk, size, &mBuffer)); ANGLE_TRY(acquireBufferHelper(contextVk, size, &mBuffer));
// Initialize the staging buffer
initializeStagingBuffer(contextVk, target, size);
// Initialize the shadow buffer // Initialize the shadow buffer
ANGLE_TRY(initializeShadowBuffer(contextVk, target, size)); ANGLE_TRY(initializeShadowBuffer(contextVk, target, size));
} }
...@@ -530,29 +487,23 @@ angle::Result BufferVk::stagedUpdate(ContextVk *contextVk, ...@@ -530,29 +487,23 @@ angle::Result BufferVk::stagedUpdate(ContextVk *contextVk,
size_t offset) size_t offset)
{ {
// Acquire a "new" staging buffer // Acquire a "new" staging buffer
bool needToReleasePreviousBuffers = false; uint8_t *mapPointer = nullptr;
uint8_t *mapPointer = nullptr; VkDeviceSize stagingBufferOffset = 0;
VkDeviceSize stagingBufferOffset = 0;
ANGLE_TRY(mStagingBuffer.allocate(contextVk, size, &mapPointer, nullptr, &stagingBufferOffset, vk::DynamicBuffer *stagingBuffer = contextVk->getStagingBufferStorage();
&needToReleasePreviousBuffers)); ANGLE_TRY(stagingBuffer->allocate(contextVk, size, &mapPointer, nullptr, &stagingBufferOffset,
if (needToReleasePreviousBuffers) nullptr));
{
// Release previous staging buffers
mStagingBuffer.releaseInFlightBuffers(contextVk);
}
ASSERT(mapPointer); ASSERT(mapPointer);
memcpy(mapPointer, data, size); memcpy(mapPointer, data, size);
ASSERT(!mStagingBuffer.isCoherent()); ASSERT(!stagingBuffer->isCoherent());
ANGLE_TRY(mStagingBuffer.flush(contextVk)); ANGLE_TRY(stagingBuffer->flush(contextVk));
mStagingBuffer.getCurrentBuffer()->onExternalWrite(VK_ACCESS_HOST_WRITE_BIT); stagingBuffer->getCurrentBuffer()->onExternalWrite(VK_ACCESS_HOST_WRITE_BIT);
// 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( ANGLE_TRY(
mBuffer->copyFromBuffer(contextVk, mStagingBuffer.getCurrentBuffer(), 1, &copyRegion)); mBuffer->copyFromBuffer(contextVk, stagingBuffer->getCurrentBuffer(), 1, &copyRegion));
mStagingBuffer.getCurrentBuffer()->retain(&contextVk->getResourceUseList());
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -121,7 +121,6 @@ class BufferVk : public BufferImpl ...@@ -121,7 +121,6 @@ class BufferVk : public BufferImpl
bool hostVisible); bool hostVisible);
private: private:
void initializeStagingBuffer(ContextVk *contextVk, gl::BufferBinding target, size_t size);
angle::Result initializeShadowBuffer(ContextVk *contextVk, angle::Result initializeShadowBuffer(ContextVk *contextVk,
gl::BufferBinding target, gl::BufferBinding target,
size_t size); size_t size);
...@@ -182,9 +181,6 @@ class BufferVk : public BufferImpl ...@@ -182,9 +181,6 @@ class BufferVk : public BufferImpl
// Pool of BufferHelpers for mBuffer to acquire from // Pool of BufferHelpers for mBuffer to acquire from
vk::DynamicBuffer mBufferPool; 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 // 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 // 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 // glData/glSubData/glCopy calls. With this, a glMap* call becomes a non-blocking
......
...@@ -752,6 +752,7 @@ void ContextVk::onDestroy(const gl::Context *context) ...@@ -752,6 +752,7 @@ void ContextVk::onDestroy(const gl::Context *context)
mDefaultUniformStorage.release(mRenderer); mDefaultUniformStorage.release(mRenderer);
mEmptyBuffer.release(mRenderer); mEmptyBuffer.release(mRenderer);
mStagingBufferStorage.release(mRenderer);
for (vk::DynamicBuffer &defaultBuffer : mDefaultAttribBuffers) for (vk::DynamicBuffer &defaultBuffer : mDefaultAttribBuffers)
{ {
...@@ -906,6 +907,13 @@ angle::Result ContextVk::initialize() ...@@ -906,6 +907,13 @@ angle::Result ContextVk::initialize()
constexpr VkMemoryPropertyFlags kMemoryType = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; constexpr VkMemoryPropertyFlags kMemoryType = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
ANGLE_TRY(mEmptyBuffer.init(this, emptyBufferInfo, kMemoryType)); 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; return angle::Result::Continue;
} }
...@@ -3972,6 +3980,7 @@ angle::Result ContextVk::flushImpl(const vk::Semaphore *signalSemaphore) ...@@ -3972,6 +3980,7 @@ angle::Result ContextVk::flushImpl(const vk::Semaphore *signalSemaphore)
driverUniform.dynamicBuffer.releaseInFlightBuffersToResourceUseList(this); driverUniform.dynamicBuffer.releaseInFlightBuffersToResourceUseList(this);
} }
mDefaultUniformStorage.releaseInFlightBuffersToResourceUseList(this); mDefaultUniformStorage.releaseInFlightBuffersToResourceUseList(this);
mStagingBufferStorage.releaseInFlightBuffersToResourceUseList(this);
if (mRenderer->getFeatures().enableCommandProcessingThread.enabled) if (mRenderer->getFeatures().enableCommandProcessingThread.enabled)
{ {
......
...@@ -591,6 +591,7 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -591,6 +591,7 @@ class ContextVk : public ContextImpl, public vk::Context
void setDefaultUniformBlocksMinSizeForTesting(size_t minSize); void setDefaultUniformBlocksMinSizeForTesting(size_t minSize);
vk::BufferHelper &getEmptyBuffer() { return mEmptyBuffer; } vk::BufferHelper &getEmptyBuffer() { return mEmptyBuffer; }
vk::DynamicBuffer *getStagingBufferStorage() { return &mStagingBufferStorage; }
private: private:
// Dirty bits. // Dirty bits.
...@@ -1065,15 +1066,18 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -1065,15 +1066,18 @@ class ContextVk : public ContextImpl, public vk::Context
ShareGroupVk *mShareGroupVk; 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 // 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 // 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 // counter buffer array, or places where there is no vertex buffer since Vulkan does not allow
// binding a null vertex buffer. // binding a null vertex buffer.
vk::BufferHelper mEmptyBuffer; 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; 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