From 6e0d718a48d8fb5e66a6f8a1838adbf8c7f5ff4c Mon Sep 17 00:00:00 2001 From: Hyunchang Kim Date: Tue, 31 Mar 2020 18:41:57 +0900 Subject: [PATCH] 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/+/2124519 Reviewed-by: Tobin Ehlis Reviewed-by: Jamie Madill Commit-Queue: Mohan Maiya --- src/libANGLE/renderer/vulkan/BufferVk.cpp | 24 +++--- src/libANGLE/renderer/vulkan/ContextVk.cpp | 9 ++- src/libANGLE/renderer/vulkan/OverlayVk.cpp | 16 ++-- src/libANGLE/renderer/vulkan/RendererVk.cpp | 6 +- src/libANGLE/renderer/vulkan/RendererVk.h | 5 ++ src/libANGLE/renderer/vulkan/vk_helpers.cpp | 66 ++++++++-------- src/libANGLE/renderer/vulkan/vk_helpers.h | 18 +++-- .../renderer/vulkan/vk_mem_alloc_wrapper.cpp | 62 ++++++++++++--- .../renderer/vulkan/vk_mem_alloc_wrapper.h | 16 ++-- src/libANGLE/renderer/vulkan/vk_utils.cpp | 48 +++++++++--- src/libANGLE/renderer/vulkan/vk_utils.h | 12 ++- src/libANGLE/renderer/vulkan/vk_wrapper.h | 78 ++++++++++++++++++- 12 files changed, 260 insertions(+), 100 deletions(-) diff --git a/src/libANGLE/renderer/vulkan/BufferVk.cpp b/src/libANGLE/renderer/vulkan/BufferVk.cpp index b3c6296e9cdd4..c98218f1ee5f3 100644 --- a/src/libANGLE/renderer/vulkan/BufferVk.cpp +++ b/src/libANGLE/renderer/vulkan/BufferVk.cpp @@ -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(mapPtr))); + ANGLE_TRY(mBuffer.mapWithOffset(contextVk, reinterpret_cast(mapPtr), + static_cast(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; diff --git a/src/libANGLE/renderer/vulkan/ContextVk.cpp b/src/libANGLE/renderer/vulkan/ContextVk.cpp index c1c6f6525fa70..1557dbc11b509 100644 --- a/src/libANGLE/renderer/vulkan/ContextVk.cpp +++ b/src/libANGLE/renderer/vulkan/ContextVk.cpp @@ -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; } diff --git a/src/libANGLE/renderer/vulkan/OverlayVk.cpp b/src/libANGLE/renderer/vulkan/OverlayVk.cpp index 9b62d70e8f5ae..f62469afd68bd 100644 --- a/src/libANGLE/renderer/vulkan/OverlayVk.cpp +++ b/src/libANGLE/renderer/vulkan/OverlayVk.cpp @@ -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]; diff --git a/src/libANGLE/renderer/vulkan/RendererVk.cpp b/src/libANGLE/renderer/vulkan/RendererVk.cpp index 41a60c251d0e9..32358ec6487a9 100644 --- a/src/libANGLE/renderer/vulkan/RendererVk.cpp +++ b/src/libANGLE/renderer/vulkan/RendererVk.cpp @@ -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); diff --git a/src/libANGLE/renderer/vulkan/RendererVk.h b/src/libANGLE/renderer/vulkan/RendererVk.h index 0d82ceae8557a..47dba80550468 100644 --- a/src/libANGLE/renderer/vulkan/RendererVk.h +++ b/src/libANGLE/renderer/vulkan/RendererVk.h @@ -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 diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.cpp b/src/libANGLE/renderer/vulkan/vk_helpers.cpp index 8e0721c4f438e..da3abad48dca5 100644 --- a/src/libANGLE/renderer/vulkan/vk_helpers.cpp +++ b/src/libANGLE/renderer/vulkan/vk_helpers.cpp @@ -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; } diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.h b/src/libANGLE/renderer/vulkan/vk_helpers.h index 02a15628f2952..681b1693b94af 100644 --- a/src/libANGLE/renderer/vulkan/vk_helpers.h +++ b/src/libANGLE/renderer/vulkan/vk_helpers.h @@ -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; diff --git a/src/libANGLE/renderer/vulkan/vk_mem_alloc_wrapper.cpp b/src/libANGLE/renderer/vulkan/vk_mem_alloc_wrapper.cpp index 1f12fb686472e..5c23e7aa0fca7 100644 --- a/src/libANGLE/renderer/vulkan/vk_mem_alloc_wrapper.cpp +++ b/src/libANGLE/renderer/vulkan/vk_mem_alloc_wrapper.cpp @@ -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, diff --git a/src/libANGLE/renderer/vulkan/vk_mem_alloc_wrapper.h b/src/libANGLE/renderer/vulkan/vk_mem_alloc_wrapper.h index 26bf67442834f..2153bf0c3ac95 100644 --- a/src/libANGLE/renderer/vulkan/vk_mem_alloc_wrapper.h +++ b/src/libANGLE/renderer/vulkan/vk_mem_alloc_wrapper.h @@ -13,27 +13,27 @@ #include 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); diff --git a/src/libANGLE/renderer/vulkan/vk_utils.cpp b/src/libANGLE/renderer/vulkan/vk_utils.cpp index fc944a63afac6..44258ef16792b 100644 --- a/src/libANGLE/renderer/vulkan/vk_utils.cpp +++ b/src/libANGLE/renderer/vulkan/vk_utils.cpp @@ -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); 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)); + + 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; diff --git a/src/libANGLE/renderer/vulkan/vk_utils.h b/src/libANGLE/renderer/vulkan/vk_utils.h index a7c6a2b1551e5..dee8c6a63b341 100644 --- a/src/libANGLE/renderer/vulkan/vk_utils.h +++ b/src/libANGLE/renderer/vulkan/vk_utils.h @@ -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, diff --git a/src/libANGLE/renderer/vulkan/vk_wrapper.h b/src/libANGLE/renderer/vulkan/vk_wrapper.h index ecb6f581a7663..a17bcb42566d9 100644 --- a/src/libANGLE/renderer/vulkan/vk_wrapper.h +++ b/src/libANGLE/renderer/vulkan/vk_wrapper.h @@ -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 void unmap(VkDevice device) const; }; +class Allocation final : public WrappedObject +{ + 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 { 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) {