Skip to content

Commit

Permalink
Vulkan: Implement device memory sub-allocation
Browse files Browse the repository at this point in the history
Use AMD Vulkan Memory Allocator for device memory sub-allocation.
We now have a mempool from which all glBuffer memory is allocated.
The CPU overhead involved in repeated IOCTL calls to the kernel is
reduced significantly.

Bug: angleproject:2162
Change-Id: Id7681ffe2ac3d2853141ebe34c7df7b7fdd0d55e
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2124519
Reviewed-by: Tobin Ehlis <tobine@google.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Mohan Maiya <m.maiya@samsung.com>
  • Loading branch information
Hyunchang Kim authored and Commit Bot committed Apr 14, 2020
1 parent d26fb99 commit 6e0d718
Show file tree
Hide file tree
Showing 12 changed files with 260 additions and 100 deletions.
24 changes: 9 additions & 15 deletions src/libANGLE/renderer/vulkan/BufferVk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,13 +294,12 @@ angle::Result BufferVk::copySubData(const gl::Context *context,

// Update the shadow buffer
uint8_t *srcPtr;
ANGLE_VK_TRY(contextVk, sourceBuffer->getBuffer().getDeviceMemory().map(
contextVk->getDevice(), sourceOffset, size, 0, &srcPtr));
ANGLE_TRY(sourceBuffer->getBuffer().mapWithOffset(contextVk, &srcPtr, sourceOffset));

updateShadowBuffer(srcPtr, size, destOffset);

// Unmap the source buffer
sourceBuffer->getBuffer().getDeviceMemory().unmap(contextVk->getDevice());
sourceBuffer->getBuffer().unmap(contextVk->getRenderer());
}

vk::CommandBuffer *commandBuffer = nullptr;
Expand Down Expand Up @@ -359,9 +358,8 @@ angle::Result BufferVk::mapRangeImpl(ContextVk *contextVk,
ANGLE_TRY(mBuffer.waitForIdle(contextVk));
}

ANGLE_VK_TRY(contextVk,
mBuffer.getDeviceMemory().map(contextVk->getDevice(), offset, length, 0,
reinterpret_cast<uint8_t **>(mapPtr)));
ANGLE_TRY(mBuffer.mapWithOffset(contextVk, reinterpret_cast<uint8_t **>(mapPtr),
static_cast<size_t>(offset)));
}
else
{
Expand Down Expand Up @@ -394,7 +392,7 @@ angle::Result BufferVk::unmapImpl(ContextVk *contextVk)

if (!mShadowBuffer.valid())
{
mBuffer.getDeviceMemory().unmap(contextVk->getDevice());
mBuffer.unmap(contextVk->getRenderer());
mBuffer.onExternalWrite(VK_ACCESS_HOST_WRITE_BIT);
}
else
Expand Down Expand Up @@ -450,10 +448,7 @@ angle::Result BufferVk::getIndexRange(const gl::Context *context,

ASSERT(mBuffer.valid());

const GLuint &typeBytes = gl::GetDrawElementsTypeSize(type);

ANGLE_VK_TRY(contextVk, mBuffer.getDeviceMemory().map(contextVk->getDevice(), offset,
typeBytes * count, 0, &mapPointer));
ANGLE_TRY(mBuffer.mapWithOffset(contextVk, &mapPointer, offset));
}
else
{
Expand All @@ -462,7 +457,7 @@ angle::Result BufferVk::getIndexRange(const gl::Context *context,

*outRange = gl::ComputeIndexRange(type, mapPointer, count, primitiveRestartEnabled);

mBuffer.getDeviceMemory().unmap(contextVk->getDevice());
mBuffer.unmap(renderer);
return angle::Result::Continue;
}

Expand All @@ -471,15 +466,14 @@ angle::Result BufferVk::directUpdate(ContextVk *contextVk,
size_t size,
size_t offset)
{
VkDevice device = contextVk->getDevice();
uint8_t *mapPointer = nullptr;

ANGLE_VK_TRY(contextVk, mBuffer.getDeviceMemory().map(device, offset, size, 0, &mapPointer));
ANGLE_TRY(mBuffer.mapWithOffset(contextVk, &mapPointer, offset));
ASSERT(mapPointer);

memcpy(mapPointer, data, size);

mBuffer.getDeviceMemory().unmap(device);
mBuffer.unmap(contextVk->getRenderer());
mBuffer.onExternalWrite(VK_ACCESS_HOST_WRITE_BIT);

return angle::Result::Continue;
Expand Down
9 changes: 5 additions & 4 deletions src/libANGLE/renderer/vulkan/ContextVk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2132,7 +2132,7 @@ angle::Result ContextVk::drawArraysIndirect(const gl::Context *context,
// We have instanced vertex attributes that need to be emulated for Vulkan.
// invalidate any cache and map the buffer so that we can read the indirect data.
// Mapping the buffer will cause a flush.
ANGLE_TRY(currentIndirectBuf->invalidate(this, 0, sizeof(VkDrawIndirectCommand)));
ANGLE_TRY(currentIndirectBuf->invalidate(mRenderer, 0, sizeof(VkDrawIndirectCommand)));
uint8_t *buffPtr;
ANGLE_TRY(currentIndirectBuf->map(this, &buffPtr));
const VkDrawIndirectCommand *indirectData =
Expand All @@ -2141,7 +2141,7 @@ angle::Result ContextVk::drawArraysIndirect(const gl::Context *context,
ANGLE_TRY(drawArraysInstanced(context, mode, indirectData->firstVertex,
indirectData->vertexCount, indirectData->instanceCount));

currentIndirectBuf->unmap(getDevice());
currentIndirectBuf->unmap(mRenderer);
return angle::Result::Continue;
}

Expand Down Expand Up @@ -2186,7 +2186,8 @@ angle::Result ContextVk::drawElementsIndirect(const gl::Context *context,
// We have instanced vertex attributes that need to be emulated for Vulkan.
// invalidate any cache and map the buffer so that we can read the indirect data.
// Mapping the buffer will cause a flush.
ANGLE_TRY(currentIndirectBuf->invalidate(this, 0, sizeof(VkDrawIndexedIndirectCommand)));
ANGLE_TRY(
currentIndirectBuf->invalidate(mRenderer, 0, sizeof(VkDrawIndexedIndirectCommand)));
uint8_t *buffPtr;
ANGLE_TRY(currentIndirectBuf->map(this, &buffPtr));
const VkDrawIndexedIndirectCommand *indirectData =
Expand All @@ -2195,7 +2196,7 @@ angle::Result ContextVk::drawElementsIndirect(const gl::Context *context,
ANGLE_TRY(drawElementsInstanced(context, mode, indirectData->indexCount, type, nullptr,
indirectData->instanceCount));

currentIndirectBuf->unmap(getDevice());
currentIndirectBuf->unmap(mRenderer);
return angle::Result::Continue;
}

Expand Down
16 changes: 8 additions & 8 deletions src/libANGLE/renderer/vulkan/OverlayVk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ angle::Result OverlayVk::createFont(ContextVk *contextVk)

mState.initFontData(fontData);

ANGLE_TRY(fontDataBuffer.get().flush(contextVk, 0, fontDataBuffer.get().getSize()));
fontDataBuffer.get().unmap(contextVk->getDevice());
ANGLE_TRY(fontDataBuffer.get().flush(renderer, 0, fontDataBuffer.get().getSize()));
fontDataBuffer.get().unmap(renderer);

fontDataBuffer.get().onExternalWrite(VK_ACCESS_HOST_WRITE_BIT);

Expand Down Expand Up @@ -171,8 +171,8 @@ angle::Result OverlayVk::cullWidgets(ContextVk *contextVk)
gl::Extents presentImageExtents(mPresentImageExtent.width, mPresentImageExtent.height, 1);
mState.fillEnabledWidgetCoordinates(presentImageExtents, enabledWidgets);

ANGLE_TRY(enabledWidgetsBuffer.get().flush(contextVk, 0, enabledWidgetsBuffer.get().getSize()));
enabledWidgetsBuffer.get().unmap(contextVk->getDevice());
ANGLE_TRY(enabledWidgetsBuffer.get().flush(renderer, 0, enabledWidgetsBuffer.get().getSize()));
enabledWidgetsBuffer.get().unmap(renderer);

enabledWidgetsBuffer.get().onExternalWrite(VK_ACCESS_HOST_WRITE_BIT);

Expand Down Expand Up @@ -261,10 +261,10 @@ angle::Result OverlayVk::onPresent(ContextVk *contextVk,
gl::Extents presentImageExtents(mPresentImageExtent.width, mPresentImageExtent.height, 1);
mState.fillWidgetData(presentImageExtents, textData, graphData);

ANGLE_TRY(textDataBuffer.get().flush(contextVk, 0, textDataBuffer.get().getSize()));
ANGLE_TRY(graphDataBuffer.get().flush(contextVk, 0, graphDataBuffer.get().getSize()));
textDataBuffer.get().unmap(contextVk->getDevice());
graphDataBuffer.get().unmap(contextVk->getDevice());
ANGLE_TRY(textDataBuffer.get().flush(renderer, 0, textDataBuffer.get().getSize()));
ANGLE_TRY(graphDataBuffer.get().flush(renderer, 0, graphDataBuffer.get().getSize()));
textDataBuffer.get().unmap(renderer);
graphDataBuffer.get().unmap(renderer);

UtilsVk::OverlayDrawParameters params;
params.subgroupSize[0] = mSubgroupSize[0];
Expand Down
6 changes: 5 additions & 1 deletion src/libANGLE/renderer/vulkan/RendererVk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
#include "libANGLE/renderer/vulkan/VertexArrayVk.h"
#include "libANGLE/renderer/vulkan/vk_caps_utils.h"
#include "libANGLE/renderer/vulkan/vk_format_utils.h"
#include "libANGLE/renderer/vulkan/vk_mem_alloc_wrapper.h"
#include "libANGLE/trace.h"
#include "platform/Platform.h"

Expand Down Expand Up @@ -623,6 +622,8 @@ void RendererVk::onDestroy()

mPipelineCache.destroy(mDevice);

vma::DestroyAllocator(mAllocator);

if (mGlslangInitialized)
{
GlslangRelease();
Expand Down Expand Up @@ -925,6 +926,9 @@ angle::Result RendererVk::initialize(DisplayVk *displayVk,
ANGLE_TRY(initializeDevice(displayVk, firstGraphicsQueueFamily));
}

// Create VMA allocator
ANGLE_VK_TRY(displayVk, vma::InitAllocator(mPhysicalDevice, mDevice, mInstance, &mAllocator));

// Store the physical device memory properties so we can find the right memory pools.
mMemoryProperties.init(mPhysicalDevice);

Expand Down
5 changes: 5 additions & 0 deletions src/libANGLE/renderer/vulkan/RendererVk.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "libANGLE/renderer/vulkan/vk_format_utils.h"
#include "libANGLE/renderer/vulkan/vk_helpers.h"
#include "libANGLE/renderer/vulkan/vk_internal_shaders_autogen.h"
#include "libANGLE/renderer/vulkan/vk_mem_alloc_wrapper.h"

namespace egl
{
Expand Down Expand Up @@ -100,6 +101,8 @@ class RendererVk : angle::NonCopyable
}
VkDevice getDevice() const { return mDevice; }

const VmaAllocator &getAllocator() const { return mAllocator; }

angle::Result selectPresentQueueForSurface(DisplayVk *displayVk,
VkSurfaceKHR surface,
uint32_t *presentQueueOut);
Expand Down Expand Up @@ -355,6 +358,8 @@ class RendererVk : angle::NonCopyable

// track whether we initialized (or released) glslang
bool mGlslangInitialized;

VmaAllocator mAllocator;
};

} // namespace rx
Expand Down
66 changes: 34 additions & 32 deletions src/libANGLE/renderer/vulkan/vk_helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,7 @@ angle::Result DynamicBuffer::allocate(ContextVk *contextVk,
if (mBuffer)
{
ANGLE_TRY(flush(contextVk));
mBuffer->unmap(contextVk->getDevice());
mBuffer->unmap(contextVk->getRenderer());

mInFlightBuffers.push_back(mBuffer);
mBuffer = nullptr;
Expand Down Expand Up @@ -617,7 +617,7 @@ angle::Result DynamicBuffer::flush(ContextVk *contextVk)
if (mHostVisible && (mNextAllocationOffset > mLastFlushOrInvalidateOffset))
{
ASSERT(mBuffer != nullptr);
ANGLE_TRY(mBuffer->flush(contextVk, mLastFlushOrInvalidateOffset,
ANGLE_TRY(mBuffer->flush(contextVk->getRenderer(), mLastFlushOrInvalidateOffset,
mNextAllocationOffset - mLastFlushOrInvalidateOffset));
mLastFlushOrInvalidateOffset = mNextAllocationOffset;
}
Expand All @@ -629,7 +629,7 @@ angle::Result DynamicBuffer::invalidate(ContextVk *contextVk)
if (mHostVisible && (mNextAllocationOffset > mLastFlushOrInvalidateOffset))
{
ASSERT(mBuffer != nullptr);
ANGLE_TRY(mBuffer->invalidate(contextVk, mLastFlushOrInvalidateOffset,
ANGLE_TRY(mBuffer->invalidate(contextVk->getRenderer(), mLastFlushOrInvalidateOffset,
mNextAllocationOffset - mLastFlushOrInvalidateOffset));
mLastFlushOrInvalidateOffset = mNextAllocationOffset;
}
Expand Down Expand Up @@ -700,7 +700,7 @@ void DynamicBuffer::destroy(RendererVk *renderer)

if (mBuffer)
{
mBuffer->unmap(renderer->getDevice());
mBuffer->unmap(renderer);
mBuffer->destroy(renderer);
delete mBuffer;
mBuffer = nullptr;
Expand Down Expand Up @@ -1689,22 +1689,33 @@ angle::Result BufferHelper::init(ContextVk *contextVk,
createInfo = &modifiedCreateInfo;
}

ANGLE_VK_TRY(contextVk, mBuffer.init(contextVk->getDevice(), *createInfo));
VkMemoryPropertyFlags requiredFlags =
(memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
VkMemoryPropertyFlags preferredFlags =
(memoryPropertyFlags & (~VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));

mAllocation.createBufferAndMemory(renderer->getAllocator(), createInfo, requiredFlags,
preferredFlags, &mBuffer, &mMemoryPropertyFlags);

VkDeviceSize size;
ANGLE_TRY(AllocateBufferMemory(contextVk, memoryPropertyFlags, &mMemoryPropertyFlags, nullptr,
&mBuffer, &mDeviceMemory, &size));
mCurrentQueueFamilyIndex = contextVk->getRenderer()->getQueueFamilyIndex();

if (renderer->getFeatures().allocateNonZeroMemory.enabled)
{
// This memory can't be mapped, so the buffer must be marked as a transfer destination so we
// can use a staging resource to initialize it to a non-zero value. If the memory is
// mappable we do the initialization in AllocateBufferMemory.
if ((memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0 &&
if ((mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0 &&
(requestedCreateInfo.usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT) != 0)
{
ANGLE_TRY(initializeNonZeroMemory(contextVk, size));
ANGLE_TRY(initializeNonZeroMemory(contextVk, createInfo->size));
}
else if ((mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
{
// Can map the memory.
// Pick an arbitrary value to initialize non-zero memory for sanitization.
constexpr int kNonZeroInitValue = 55;
ANGLE_TRY(InitMappableAllocation(renderer->getAllocator(), &mAllocation, mSize,
kNonZeroInitValue, mMemoryPropertyFlags));
}
}

Expand Down Expand Up @@ -1745,23 +1756,22 @@ angle::Result BufferHelper::initializeNonZeroMemory(Context *context, VkDeviceSi
void BufferHelper::destroy(RendererVk *renderer)
{
VkDevice device = renderer->getDevice();

unmap(device);
unmap(renderer);
mSize = 0;
mViewFormat = nullptr;

mBuffer.destroy(device);
mBufferView.destroy(device);
mDeviceMemory.destroy(device);
mAllocation.destroy(renderer->getAllocator());
}

void BufferHelper::release(RendererVk *renderer)
{
unmap(renderer->getDevice());
unmap(renderer);
mSize = 0;
mViewFormat = nullptr;

renderer->collectGarbageAndReinit(&mUse, &mBuffer, &mBufferView, &mDeviceMemory);
renderer->collectGarbageAndReinit(&mUse, &mBuffer, &mBufferView, &mAllocation);
}

bool BufferHelper::needsOnWriteBarrier(VkAccessFlags writeAccessType,
Expand Down Expand Up @@ -1821,47 +1831,39 @@ angle::Result BufferHelper::initBufferView(ContextVk *contextVk, const Format &f

angle::Result BufferHelper::mapImpl(ContextVk *contextVk)
{
ANGLE_VK_TRY(contextVk, mDeviceMemory.map(contextVk->getDevice(), 0, mSize, 0, &mMappedMemory));
ANGLE_VK_TRY(contextVk,
mAllocation.map(contextVk->getRenderer()->getAllocator(), &mMappedMemory));

return angle::Result::Continue;
}

void BufferHelper::unmap(VkDevice device)
void BufferHelper::unmap(RendererVk *renderer)
{
if (mMappedMemory)
{
mDeviceMemory.unmap(device);
mAllocation.unmap(renderer->getAllocator());
mMappedMemory = nullptr;
}
}

angle::Result BufferHelper::flush(ContextVk *contextVk, VkDeviceSize offset, VkDeviceSize size)
angle::Result BufferHelper::flush(RendererVk *renderer, VkDeviceSize offset, VkDeviceSize size)
{
bool hostVisible = mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
bool hostCoherent = mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
if (hostVisible && !hostCoherent)
{
VkMappedMemoryRange range = {};
range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
range.memory = mDeviceMemory.getHandle();
range.offset = offset;
range.size = size;
ANGLE_VK_TRY(contextVk, vkFlushMappedMemoryRanges(contextVk->getDevice(), 1, &range));
mAllocation.flush(renderer->getAllocator(), offset, size);
}
return angle::Result::Continue;
}

angle::Result BufferHelper::invalidate(ContextVk *contextVk, VkDeviceSize offset, VkDeviceSize size)
angle::Result BufferHelper::invalidate(RendererVk *renderer, VkDeviceSize offset, VkDeviceSize size)
{
bool hostVisible = mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
bool hostCoherent = mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
if (hostVisible && !hostCoherent)
{
VkMappedMemoryRange range = {};
range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
range.memory = mDeviceMemory.getHandle();
range.offset = offset;
range.size = size;
ANGLE_VK_TRY(contextVk, vkInvalidateMappedMemoryRanges(contextVk->getDevice(), 1, &range));
mAllocation.invalidate(renderer->getAllocator(), offset, size);
}
return angle::Result::Continue;
}
Expand Down
Loading

0 comments on commit 6e0d718

Please sign in to comment.