blob: 637af47e76c3ae4dfa01d9a55f71218b5af00959 [file] [log] [blame]
//
// Copyright 2022 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Suballocation.cpp:
// Implements class methods for BufferBlock and Suballocation and other related classes
//
// #include "libANGLE/renderer/vulkan/vk_utils.h"
#include "libANGLE/renderer/vulkan/Suballocation.h"
#include "libANGLE/Context.h"
#include "libANGLE/renderer/vulkan/vk_mem_alloc_wrapper.h"
#include "libANGLE/renderer/vulkan/vk_renderer.h"
namespace rx
{
namespace vk
{
// BufferBlock implementation.
BufferBlock::BufferBlock()
: mMemoryPropertyFlags(0),
mSize(0),
mAllocatedBufferSize(0),
mMemoryAllocationType(MemoryAllocationType::InvalidEnum),
mMemoryTypeIndex(kInvalidMemoryTypeIndex),
mMappedMemory(nullptr)
{}
BufferBlock::BufferBlock(BufferBlock &&other)
: mVirtualBlock(std::move(other.mVirtualBlock)),
mBuffer(std::move(other.mBuffer)),
mDeviceMemory(std::move(other.mDeviceMemory)),
mMemoryPropertyFlags(other.mMemoryPropertyFlags),
mSize(other.mSize),
mAllocatedBufferSize(other.mAllocatedBufferSize),
mMemoryAllocationType(other.mMemoryAllocationType),
mMemoryTypeIndex(other.mMemoryTypeIndex),
mMappedMemory(other.mMappedMemory),
mSerial(other.mSerial),
mCountRemainsEmpty(0)
{}
BufferBlock &BufferBlock::operator=(BufferBlock &&other)
{
std::swap(mVirtualBlock, other.mVirtualBlock);
std::swap(mBuffer, other.mBuffer);
std::swap(mDeviceMemory, other.mDeviceMemory);
std::swap(mMemoryPropertyFlags, other.mMemoryPropertyFlags);
std::swap(mSize, other.mSize);
std::swap(mAllocatedBufferSize, other.mAllocatedBufferSize);
std::swap(mMemoryAllocationType, other.mMemoryAllocationType);
std::swap(mMemoryTypeIndex, other.mMemoryTypeIndex);
std::swap(mMappedMemory, other.mMappedMemory);
std::swap(mSerial, other.mSerial);
std::swap(mCountRemainsEmpty, other.mCountRemainsEmpty);
return *this;
}
BufferBlock::~BufferBlock()
{
ASSERT(!mVirtualBlock.valid());
ASSERT(!mBuffer.valid());
ASSERT(!mDeviceMemory.valid());
}
void BufferBlock::destroy(Renderer *renderer)
{
VkDevice device = renderer->getDevice();
if (mMappedMemory)
{
unmap(device);
}
renderer->onMemoryDealloc(mMemoryAllocationType, mAllocatedBufferSize, mMemoryTypeIndex,
mDeviceMemory.getHandle());
mVirtualBlock.destroy(device);
mBuffer.destroy(device);
mDeviceMemory.destroy(device);
}
VkResult BufferBlock::init(ErrorContext *context,
Buffer &buffer,
uint32_t memoryTypeIndex,
vma::VirtualBlockCreateFlags flags,
DeviceMemory &deviceMemory,
VkMemoryPropertyFlags memoryPropertyFlags,
VkDeviceSize size)
{
Renderer *renderer = context->getRenderer();
ASSERT(!mVirtualBlock.valid());
ASSERT(!mBuffer.valid());
ASSERT(!mDeviceMemory.valid());
VK_RESULT_TRY(mVirtualBlock.init(renderer->getDevice(), flags, size));
mBuffer = std::move(buffer);
mDeviceMemory = std::move(deviceMemory);
mMemoryPropertyFlags = memoryPropertyFlags;
mSize = size;
mAllocatedBufferSize = size;
mMemoryAllocationType = MemoryAllocationType::Buffer;
mMemoryTypeIndex = memoryTypeIndex;
mMappedMemory = nullptr;
mSerial = renderer->getResourceSerialFactory().generateBufferSerial();
return VK_SUCCESS;
}
void BufferBlock::initWithoutVirtualBlock(ErrorContext *context,
Buffer &buffer,
MemoryAllocationType memoryAllocationType,
uint32_t memoryTypeIndex,
DeviceMemory &deviceMemory,
VkMemoryPropertyFlags memoryPropertyFlags,
VkDeviceSize size,
VkDeviceSize allocatedBufferSize)
{
Renderer *renderer = context->getRenderer();
ASSERT(!mVirtualBlock.valid());
ASSERT(!mBuffer.valid());
ASSERT(!mDeviceMemory.valid());
mBuffer = std::move(buffer);
mDeviceMemory = std::move(deviceMemory);
mMemoryPropertyFlags = memoryPropertyFlags;
mSize = size;
mAllocatedBufferSize = allocatedBufferSize;
mMemoryAllocationType = memoryAllocationType;
mMemoryTypeIndex = memoryTypeIndex;
mMappedMemory = nullptr;
mSerial = renderer->getResourceSerialFactory().generateBufferSerial();
}
VkResult BufferBlock::map(const VkDevice device)
{
ASSERT(mMappedMemory == nullptr);
return mDeviceMemory.map(device, 0, mAllocatedBufferSize, 0, &mMappedMemory);
}
void BufferBlock::unmap(const VkDevice device)
{
mDeviceMemory.unmap(device);
mMappedMemory = nullptr;
}
VkResult BufferBlock::allocate(VkDeviceSize size,
VkDeviceSize alignment,
VmaVirtualAllocation *allocationOut,
VkDeviceSize *offsetOut)
{
std::unique_lock<angle::SimpleMutex> lock(mVirtualBlockMutex);
mCountRemainsEmpty = 0;
return mVirtualBlock.allocate(size, alignment, allocationOut, offsetOut);
}
void BufferBlock::free(VmaVirtualAllocation allocation, VkDeviceSize offset)
{
std::unique_lock<angle::SimpleMutex> lock(mVirtualBlockMutex);
mVirtualBlock.free(allocation, offset);
}
int32_t BufferBlock::getAndIncrementEmptyCounter()
{
return ++mCountRemainsEmpty;
}
void BufferBlock::calculateStats(vma::StatInfo *pStatInfo) const
{
std::unique_lock<angle::SimpleMutex> lock(mVirtualBlockMutex);
mVirtualBlock.calculateStats(pStatInfo);
}
// BufferSuballocation implementation.
VkResult BufferSuballocation::map(ErrorContext *context)
{
return mBufferBlock->map(context->getDevice());
}
void BufferSuballocation::flush(Renderer *renderer)
{
if (!isCoherent())
{
const VkDeviceSize nonCoherentAtomSize =
renderer->getPhysicalDeviceProperties().limits.nonCoherentAtomSize;
VkMappedMemoryRange mappedRange = {};
mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
mappedRange.memory = mBufferBlock->getDeviceMemory().getHandle();
mappedRange.offset = getOffset();
mappedRange.size = roundUp<VkDeviceSize>(mSize, nonCoherentAtomSize);
ASSERT(mappedRange.size <= mBufferBlock->getAllocatedBufferSize());
mBufferBlock->getDeviceMemory().flush(renderer->getDevice(), mappedRange);
}
}
void BufferSuballocation::invalidate(Renderer *renderer)
{
if (!isCoherent())
{
const VkDeviceSize nonCoherentAtomSize =
renderer->getPhysicalDeviceProperties().limits.nonCoherentAtomSize;
VkMappedMemoryRange mappedRange = {};
mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
mappedRange.memory = mBufferBlock->getDeviceMemory().getHandle();
mappedRange.offset = getOffset();
mappedRange.size = roundUp<VkDeviceSize>(mSize, nonCoherentAtomSize);
ASSERT(mappedRange.size <= mBufferBlock->getAllocatedBufferSize());
mBufferBlock->getDeviceMemory().invalidate(renderer->getDevice(), mappedRange);
}
}
// BufferSuballocationGarbage implementation.
bool BufferSuballocationGarbage::destroyIfComplete(Renderer *renderer)
{
if (renderer->hasResourceUseFinished(mLifetime))
{
mBuffer.destroy(renderer->getDevice());
mSuballocation.destroy(renderer);
return true;
}
return false;
}
bool BufferSuballocationGarbage::hasResourceUseSubmitted(Renderer *renderer) const
{
return renderer->hasResourceUseSubmitted(mLifetime);
}
} // namespace vk
} // namespace rx