Commit 6e0d718a by Hyunchang Kim Committed by Commit Bot

Vulkan: Implement device memory sub-allocation

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/+/2124519Reviewed-by: 's avatarTobin Ehlis <tobine@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Mohan Maiya <m.maiya@samsung.com>
parent d26fb99e
......@@ -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;
......@@ -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
{
......@@ -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
......@@ -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
{
......@@ -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;
}
......@@ -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;
......
......@@ -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 =
......@@ -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;
}
......@@ -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 =
......@@ -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;
}
......
......@@ -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);
......@@ -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);
......@@ -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];
......
......@@ -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"
......@@ -623,6 +622,8 @@ void RendererVk::onDestroy()
mPipelineCache.destroy(mDevice);
vma::DestroyAllocator(mAllocator);
if (mGlslangInitialized)
{
GlslangRelease();
......@@ -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);
......
......@@ -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
{
......@@ -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);
......@@ -355,6 +358,8 @@ class RendererVk : angle::NonCopyable
// track whether we initialized (or released) glslang
bool mGlslangInitialized;
VmaAllocator mAllocator;
};
} // namespace rx
......
......@@ -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;
......@@ -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;
}
......@@ -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;
}
......@@ -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;
......@@ -1689,11 +1689,14 @@ 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)
......@@ -1701,10 +1704,18 @@ angle::Result BufferHelper::init(ContextVk *contextVk,
// 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));
}
}
......@@ -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,
......@@ -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;
}
......
......@@ -553,7 +553,6 @@ class BufferHelper final : public Resource
bool valid() const { return mBuffer.valid(); }
const Buffer &getBuffer() const { return mBuffer; }
const DeviceMemory &getDeviceMemory() const { return mDeviceMemory; }
VkDeviceSize getSize() const { return mSize; }
bool isHostVisible() const
{
......@@ -595,13 +594,22 @@ class BufferHelper final : public Resource
*ptrOut = mMappedMemory;
return angle::Result::Continue;
}
void unmap(VkDevice device);
angle::Result mapWithOffset(ContextVk *contextVk, uint8_t **ptrOut, size_t offset)
{
uint8_t *mapBufPointer;
ANGLE_TRY(map(contextVk, &mapBufPointer));
*ptrOut = mapBufPointer + offset;
return angle::Result::Continue;
}
void unmap(RendererVk *renderer);
// After a sequence of writes, call flush to ensure the data is visible to the device.
angle::Result flush(ContextVk *contextVk, VkDeviceSize offset, VkDeviceSize size);
angle::Result flush(RendererVk *renderer, VkDeviceSize offset, VkDeviceSize size);
// After a sequence of writes, call invalidate to ensure the data is visible to the host.
angle::Result invalidate(ContextVk *contextVk, VkDeviceSize offset, VkDeviceSize size);
angle::Result invalidate(RendererVk *renderer, VkDeviceSize offset, VkDeviceSize size);
void changeQueue(uint32_t newQueueFamilyIndex, CommandBuffer *commandBuffer);
......@@ -641,7 +649,7 @@ class BufferHelper final : public Resource
// Vulkan objects.
Buffer mBuffer;
BufferView mBufferView;
DeviceMemory mDeviceMemory;
Allocation mAllocation;
// Cached properties.
VkMemoryPropertyFlags mMemoryPropertyFlags;
......
......@@ -14,30 +14,70 @@
namespace vma
{
VkResult InitAllocator(VkPhysicalDevice physicalDevice,
VkDevice device,
VkInstance instance,
VmaAllocator *pAllocator)
{
VmaVulkanFunctions funcs;
funcs.vkGetPhysicalDeviceProperties = vkGetPhysicalDeviceProperties;
funcs.vkGetPhysicalDeviceMemoryProperties = vkGetPhysicalDeviceMemoryProperties;
funcs.vkAllocateMemory = vkAllocateMemory;
funcs.vkFreeMemory = vkFreeMemory;
funcs.vkMapMemory = vkMapMemory;
funcs.vkUnmapMemory = vkUnmapMemory;
funcs.vkFlushMappedMemoryRanges = vkFlushMappedMemoryRanges;
funcs.vkInvalidateMappedMemoryRanges = vkInvalidateMappedMemoryRanges;
funcs.vkBindBufferMemory = vkBindBufferMemory;
funcs.vkBindImageMemory = vkBindImageMemory;
funcs.vkGetBufferMemoryRequirements = vkGetBufferMemoryRequirements;
funcs.vkGetImageMemoryRequirements = vkGetImageMemoryRequirements;
funcs.vkCreateBuffer = vkCreateBuffer;
funcs.vkDestroyBuffer = vkDestroyBuffer;
funcs.vkCreateImage = vkCreateImage;
funcs.vkDestroyImage = vkDestroyImage;
funcs.vkCmdCopyBuffer = vkCmdCopyBuffer;
funcs.vkGetBufferMemoryRequirements2KHR = vkGetBufferMemoryRequirements2KHR;
funcs.vkGetImageMemoryRequirements2KHR = vkGetImageMemoryRequirements2KHR;
VmaAllocatorCreateInfo allocatorInfo = {};
allocatorInfo.physicalDevice = physicalDevice;
allocatorInfo.device = device;
allocatorInfo.instance = instance;
allocatorInfo.pVulkanFunctions = &funcs;
return vmaCreateAllocator(&allocatorInfo, pAllocator);
}
void DestroyAllocator(VmaAllocator allocator)
{
vmaDestroyAllocator(allocator);
}
void FreeMemory(VmaAllocator allocator, VmaAllocation allocation)
{
vmaFreeMemory(allocator, allocation);
}
VkResult CreateBuffer(VmaAllocator allocator,
const VkBufferCreateInfo *pBufferCreateInfo,
VkMemoryPropertyFlags requiredFlags,
VkMemoryPropertyFlags preferredFlags,
uint32_t *pMemoryTypeIndexOut,
VkBuffer *pBuffer,
VmaAllocation *pAllocation)
{
VkResult result;
VmaAllocationCreateInfo allocationCreateInfo = {};
allocationCreateInfo.requiredFlags = requiredFlags;
allocationCreateInfo.preferredFlags = preferredFlags;
VmaAllocationInfo allocationInfo = {};
return vmaCreateBuffer(allocator, pBufferCreateInfo, &allocationCreateInfo, pBuffer,
pAllocation, &allocationInfo);
}
void DestroyBuffer(VmaAllocator allocator, VkBuffer buffer, VmaAllocation allocation)
{
vmaDestroyBuffer(allocator, buffer, allocation);
}
result = vmaCreateBuffer(allocator, pBufferCreateInfo, &allocationCreateInfo, pBuffer,
pAllocation, &allocationInfo);
*pMemoryTypeIndexOut = allocationInfo.memoryType;
void GetMemoryProperties(VmaAllocator allocator,
const VkPhysicalDeviceMemoryProperties **ppPhysicalDeviceMemoryProperties)
{
return vmaGetMemoryProperties(allocator, ppPhysicalDeviceMemoryProperties);
return result;
}
void GetMemoryTypeProperties(VmaAllocator allocator,
......
......@@ -13,27 +13,27 @@
#include <volk.h>
VK_DEFINE_HANDLE(VmaAllocator)
VK_DEFINE_HANDLE(VmaPool)
VK_DEFINE_HANDLE(VmaAllocation)
VK_DEFINE_HANDLE(VmaDefragmentationContext)
namespace vma
{
VkResult InitAllocator(VkPhysicalDevice physicalDevice,
VkDevice device,
VkInstance instance,
VmaAllocator *pAllocator);
// Please add additional functions or parameters here as needed.
void DestroyAllocator(VmaAllocator allocator);
void FreeMemory(VmaAllocator allocator, VmaAllocation allocation);
VkResult CreateBuffer(VmaAllocator allocator,
const VkBufferCreateInfo *pBufferCreateInfo,
VkMemoryPropertyFlags requiredFlags,
VkMemoryPropertyFlags preferredFlags,
uint32_t *pMemoryTypeIndexOut,
VkBuffer *pBuffer,
VmaAllocation *pAllocation);
void DestroyBuffer(VmaAllocator allocator, VkBuffer buffer, VmaAllocation allocation);
void GetMemoryProperties(VmaAllocator allocator,
const VkPhysicalDeviceMemoryProperties **ppPhysicalDeviceMemoryProperties);
void GetMemoryTypeProperties(VmaAllocator allocator,
uint32_t memoryTypeIndex,
VkMemoryPropertyFlags *pFlags);
......
......@@ -15,6 +15,7 @@
#include "libANGLE/renderer/vulkan/DisplayVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/ResourceVk.h"
#include "libANGLE/renderer/vulkan/vk_mem_alloc_wrapper.h"
namespace angle
{
......@@ -383,10 +384,11 @@ angle::Result MemoryProperties::findCompatibleMemoryIndex(
// StagingBuffer implementation.
StagingBuffer::StagingBuffer() : mSize(0) {}
void StagingBuffer::destroy(VkDevice device)
void StagingBuffer::destroy(RendererVk *renderer)
{
VkDevice device = renderer->getDevice();
mBuffer.destroy(device);
mDeviceMemory.destroy(device);
mAllocation.destroy(renderer->getAllocator());
mSize = 0;
}
......@@ -401,14 +403,15 @@ angle::Result StagingBuffer::init(Context *context, VkDeviceSize size, StagingUs
createInfo.queueFamilyIndexCount = 0;
createInfo.pQueueFamilyIndices = nullptr;
VkMemoryPropertyFlags flags =
(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
VkMemoryPropertyFlags memoryPropertyOutFlags;
VkMemoryPropertyFlags preferredFlags = 0;
VkMemoryPropertyFlags requiredFlags =
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
mAllocation.createBufferAndMemory(context->getRenderer()->getAllocator(), &createInfo,
requiredFlags, preferredFlags, &mBuffer,
&memoryPropertyOutFlags);
ANGLE_VK_TRY(context, mBuffer.init(context->getDevice(), createInfo));
VkMemoryPropertyFlags flagsOut = 0;
VkDeviceSize sizeIgnored;
ANGLE_TRY(AllocateBufferMemory(context, flags, &flagsOut, nullptr, &mBuffer, &mDeviceMemory,
&sizeIgnored));
mSize = static_cast<size_t>(size);
return angle::Result::Continue;
}
......@@ -416,14 +419,14 @@ angle::Result StagingBuffer::init(Context *context, VkDeviceSize size, StagingUs
void StagingBuffer::release(ContextVk *contextVk)
{
contextVk->addGarbage(&mBuffer);
contextVk->addGarbage(&mDeviceMemory);
contextVk->addGarbage(&mAllocation);
}
void StagingBuffer::collectGarbage(RendererVk *renderer, Serial serial)
{
vk::GarbageList garbageList;
garbageList.emplace_back(vk::GetGarbage(&mBuffer));
garbageList.emplace_back(vk::GetGarbage(&mDeviceMemory));
garbageList.emplace_back(vk::GetGarbage(&mAllocation));
vk::SharedResourceUse sharedUse;
sharedUse.init();
......@@ -431,6 +434,26 @@ void StagingBuffer::collectGarbage(RendererVk *renderer, Serial serial)
renderer->collectGarbage(std::move(sharedUse), std::move(garbageList));
}
angle::Result InitMappableAllocation(VmaAllocator allocator,
Allocation *allocation,
VkDeviceSize size,
int value,
VkMemoryPropertyFlags memoryPropertyFlags)
{
uint8_t *mapPointer;
allocation->map(allocator, &mapPointer);
memset(mapPointer, value, static_cast<size_t>(size));
if ((memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0)
{
allocation->flush(allocator, 0, size);
}
allocation->unmap(allocator);
return angle::Result::Continue;
}
angle::Result InitMappableDeviceMemory(Context *context,
DeviceMemory *deviceMemory,
VkDeviceSize size,
......@@ -622,6 +645,9 @@ void GarbageObject::destroy(RendererVk *renderer)
case HandleType::QueryPool:
vkDestroyQueryPool(device, (VkQueryPool)mHandle, nullptr);
break;
case HandleType::Allocation:
vma::FreeMemory(renderer->getAllocator(), (VmaAllocation)mHandle);
break;
default:
UNREACHABLE();
break;
......
......@@ -314,22 +314,26 @@ class StagingBuffer final : angle::NonCopyable
StagingBuffer();
void release(ContextVk *contextVk);
void collectGarbage(RendererVk *renderer, Serial serial);
void destroy(VkDevice device);
void destroy(RendererVk *renderer);
angle::Result init(Context *context, VkDeviceSize size, StagingUsage usage);
Buffer &getBuffer() { return mBuffer; }
const Buffer &getBuffer() const { return mBuffer; }
DeviceMemory &getDeviceMemory() { return mDeviceMemory; }
const DeviceMemory &getDeviceMemory() const { return mDeviceMemory; }
size_t getSize() const { return mSize; }
private:
Buffer mBuffer;
DeviceMemory mDeviceMemory;
Allocation mAllocation;
size_t mSize;
};
angle::Result InitMappableAllocation(VmaAllocator allocator,
Allocation *allcation,
VkDeviceSize size,
int value,
VkMemoryPropertyFlags memoryPropertyFlags);
angle::Result InitMappableDeviceMemory(vk::Context *context,
vk::DeviceMemory *deviceMemory,
VkDeviceSize size,
......
......@@ -14,6 +14,7 @@
#include "volk.h"
#include "libANGLE/renderer/renderer_utils.h"
#include "libANGLE/renderer/vulkan/vk_mem_alloc_wrapper.h"
namespace rx
{
......@@ -46,7 +47,8 @@ namespace vk
FUNC(RenderPass) \
FUNC(Sampler) \
FUNC(Semaphore) \
FUNC(ShaderModule)
FUNC(ShaderModule) \
FUNC(Allocation)
#define ANGLE_COMMA_SEP_FUNC(TYPE) TYPE,
......@@ -93,6 +95,7 @@ class WrappedObject : angle::NonCopyable
{
public:
HandleT getHandle() const { return mHandle; }
void setHandle(HandleT handle) { mHandle = handle; }
bool valid() const { return (mHandle != VK_NULL_HANDLE); }
const HandleT *ptr() const { return &mHandle; }
......@@ -453,6 +456,24 @@ class DeviceMemory final : public WrappedObject<DeviceMemory, VkDeviceMemory>
void unmap(VkDevice device) const;
};
class Allocation final : public WrappedObject<Allocation, VmaAllocation>
{
public:
Allocation() = default;
void destroy(VmaAllocator allocator);
VkResult createBufferAndMemory(VmaAllocator allocator,
const VkBufferCreateInfo *pBufferCreateInfo,
VkMemoryPropertyFlags requiredFlags,
VkMemoryPropertyFlags preferredFlags,
Buffer *buffer,
VkMemoryPropertyFlags *pMemPropertyOut);
VkResult map(VmaAllocator allocator, uint8_t **mapPointer) const;
void unmap(VmaAllocator allocator) const;
void flush(VmaAllocator allocator, VkDeviceSize offset, VkDeviceSize size);
void invalidate(VmaAllocator allocator, VkDeviceSize offset, VkDeviceSize size);
};
class RenderPass final : public WrappedObject<RenderPass, VkRenderPass>
{
public:
......@@ -1294,6 +1315,61 @@ ANGLE_INLINE void DeviceMemory::unmap(VkDevice device) const
vkUnmapMemory(device, mHandle);
}
// Allocation implementation.
ANGLE_INLINE void Allocation::destroy(VmaAllocator allocator)
{
if (valid())
{
vma::FreeMemory(allocator, mHandle);
mHandle = VK_NULL_HANDLE;
}
}
ANGLE_INLINE VkResult Allocation::createBufferAndMemory(VmaAllocator allocator,
const VkBufferCreateInfo *pBufferCreateInfo,
VkMemoryPropertyFlags requiredFlags,
VkMemoryPropertyFlags preferredFlags,
Buffer *buffer,
VkMemoryPropertyFlags *pMemPropertyOut)
{
ASSERT(!valid());
VkResult result;
uint32_t memoryTypeIndex;
VkBuffer bufferHandle;
result = vma::CreateBuffer(allocator, pBufferCreateInfo, requiredFlags, preferredFlags,
&memoryTypeIndex, &bufferHandle, &mHandle);
vma::GetMemoryTypeProperties(allocator, memoryTypeIndex, pMemPropertyOut);
buffer->setHandle(bufferHandle);
return result;
}
ANGLE_INLINE VkResult Allocation::map(VmaAllocator allocator, uint8_t **mapPointer) const
{
ASSERT(valid());
return vma::MapMemory(allocator, mHandle, (void **)mapPointer);
}
ANGLE_INLINE void Allocation::unmap(VmaAllocator allocator) const
{
ASSERT(valid());
vma::UnmapMemory(allocator, mHandle);
}
ANGLE_INLINE void Allocation::flush(VmaAllocator allocator, VkDeviceSize offset, VkDeviceSize size)
{
ASSERT(valid());
vma::FlushAllocation(allocator, mHandle, offset, size);
}
ANGLE_INLINE void Allocation::invalidate(VmaAllocator allocator,
VkDeviceSize offset,
VkDeviceSize size)
{
ASSERT(valid());
vma::InvalidateAllocation(allocator, mHandle, offset, size);
}
// RenderPass implementation.
ANGLE_INLINE void RenderPass::destroy(VkDevice device)
{
......
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