Commit 254b32cb by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Make DynamicBuffer use BufferHelper

This is so that the resulting buffers can be written to by the GPU. Additionally, the class is given the ability to create host-visible or device-local buffers, making map()-on-init() optional. This is in preparation for vertex/index transformations in compute. Bug: angleproject:2958 Change-Id: Ib8f5829e33a1e49fa8f80c70dbde74f313ae49ec Reviewed-on: https://chromium-review.googlesource.com/c/1351113 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarYuly Novikov <ynovikov@chromium.org>
parent b29fccfe
......@@ -196,6 +196,10 @@ class RecordableGraphResource : public CommandGraphResource
// Sets up dependency relations. 'this' resource is the resource being read.
void addReadDependency(RecordableGraphResource *readingResource);
// Updates the in-use serial tracked for this resource. Will clear dependencies if the resource
// was not used in this set of command nodes.
void updateQueueSerial(Serial queueSerial);
// Allocates a write node via getNewWriteNode and returns a started command buffer.
// The started command buffer will render outside of a RenderPass.
// Will append to an existing command buffer/graph node if possible.
......@@ -251,10 +255,6 @@ class RecordableGraphResource : public CommandGraphResource
mCurrentWritingNode->getInsideRenderPassCommands()->valid();
}
// Updates the in-use serial tracked for this resource. Will clear dependencies if the resource
// was not used in this set of command nodes.
void updateQueueSerial(Serial queueSerial);
void startNewCommands(RendererVk *renderer);
void onWriteImpl(CommandGraphNode *writingNode, Serial currentSerial);
......
......@@ -101,9 +101,9 @@ constexpr size_t kDefaultBufferSize = kDefaultValueSize * 16;
} // anonymous namespace
// std::array only uses aggregate init. Thus we make a helper macro to reduce on code duplication.
#define INIT \
{ \
kVertexBufferUsage, kDefaultBufferSize \
#define INIT \
{ \
kVertexBufferUsage, kDefaultBufferSize, true \
}
ContextVk::ContextVk(const gl::ContextState &state, RendererVk *renderer)
......@@ -117,7 +117,7 @@ ContextVk::ContextVk(const gl::ContextState &state, RendererVk *renderer)
mCurrentDrawElementsType(GL_NONE),
mClearColorMask(kAllColorChannelsMask),
mFlipYForCurrentSurface(false),
mDriverUniformsBuffer(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, sizeof(DriverUniforms) * 16),
mDriverUniformsBuffer(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, sizeof(DriverUniforms) * 16, true),
mDriverUniformsDescriptorSet(VK_NULL_HANDLE),
mDefaultAttribBuffers{{INIT, INIT, INIT, INIT, INIT, INIT, INIT, INIT, INIT, INIT, INIT, INIT,
INIT, INIT, INIT, INIT}},
......@@ -1159,9 +1159,8 @@ angle::Result ContextVk::handleDirtyDriverUniforms(const gl::Context *context,
uint8_t *ptr = nullptr;
VkBuffer buffer = VK_NULL_HANDLE;
VkDeviceSize offset = 0;
bool newBufferAllocated = false;
ANGLE_TRY(mDriverUniformsBuffer.allocate(this, sizeof(DriverUniforms), &ptr, &buffer, &offset,
&newBufferAllocated));
nullptr));
float scaleY = isViewportFlipEnabledForDrawFBO() ? -1.0f : 1.0f;
float depthRangeNear = mState.getState().getNearPlane();
......
......@@ -123,8 +123,8 @@ FramebufferVk::FramebufferVk(RendererVk *renderer,
: FramebufferImpl(state),
mBackbuffer(backbuffer),
mActiveColorComponents(0),
mReadPixelBuffer(VK_BUFFER_USAGE_TRANSFER_DST_BIT, kMinReadPixelsBufferSize),
mBlitPixelBuffer(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, kMinReadPixelsBufferSize)
mReadPixelBuffer(VK_BUFFER_USAGE_TRANSFER_DST_BIT, kMinReadPixelsBufferSize, true),
mBlitPixelBuffer(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, kMinReadPixelsBufferSize, true)
{
mBlitPixelBuffer.init(1, renderer);
mReadPixelBuffer.init(4, renderer);
......@@ -1189,12 +1189,11 @@ angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk,
VkBuffer bufferHandle = VK_NULL_HANDLE;
uint8_t *readPixelBuffer = nullptr;
bool newBufferAllocated = false;
VkDeviceSize stagingOffset = 0;
size_t allocationSize = readFormat->pixelBytes * area.width * area.height;
ANGLE_TRY(mReadPixelBuffer.allocate(contextVk, allocationSize, &readPixelBuffer, &bufferHandle,
&stagingOffset, &newBufferAllocated));
&stagingOffset, nullptr));
VkBufferImageCopy region = {};
region.bufferImageHeight = area.height;
......
......@@ -186,7 +186,8 @@ bool ProgramVk::ShaderInfo::valid() const
// ProgramVk implementation.
ProgramVk::DefaultUniformBlock::DefaultUniformBlock()
: storage(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
kUniformBlockDynamicBufferMinSize)
kUniformBlockDynamicBufferMinSize,
true)
{}
ProgramVk::DefaultUniformBlock::~DefaultUniformBlock() = default;
......@@ -220,9 +221,7 @@ void ProgramVk::reset(RendererVk *renderer)
mDefaultShaderInfo.release(renderer);
mLineRasterShaderInfo.release(renderer);
Serial currentSerial = renderer->getCurrentQueueSerial();
renderer->releaseObject(currentSerial, &mEmptyUniformBlockStorage.memory);
renderer->releaseObject(currentSerial, &mEmptyUniformBlockStorage.buffer);
mEmptyUniformBlockStorage.release(renderer);
mDescriptorSets.clear();
mUsedDescriptorSetRange.invalidate();
......@@ -437,16 +436,10 @@ angle::Result ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext)
uniformBufferInfo.queueFamilyIndexCount = 0;
uniformBufferInfo.pQueueFamilyIndices = nullptr;
ANGLE_VK_TRY(contextVk, mEmptyUniformBlockStorage.buffer.init(contextVk->getDevice(),
uniformBufferInfo));
// Assume host visible/coherent memory available.
VkMemoryPropertyFlags flags =
(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
VkMemoryPropertyFlags flagsOut = 0;
ANGLE_TRY(AllocateBufferMemory(contextVk, flags, &flagsOut,
&mEmptyUniformBlockStorage.buffer,
&mEmptyUniformBlockStorage.memory));
ANGLE_TRY(mEmptyUniformBlockStorage.init(contextVk, uniformBufferInfo, flags));
}
}
......@@ -837,11 +830,11 @@ angle::Result ProgramVk::updateDefaultUniformsDescriptorSet(ContextVk *contextVk
if (!uniformBlock.uniformData.empty())
{
bufferInfo.buffer = uniformBlock.storage.getCurrentBufferHandle();
bufferInfo.buffer = uniformBlock.storage.getCurrentBuffer()->getBuffer().getHandle();
}
else
{
bufferInfo.buffer = mEmptyUniformBlockStorage.buffer.getHandle();
bufferInfo.buffer = mEmptyUniformBlockStorage.getBuffer().getHandle();
}
bufferInfo.offset = 0;
......
......@@ -174,7 +174,7 @@ class ProgramVk : public ProgramImpl
// This is a special "empty" placeholder buffer for when a shader has no uniforms.
// It is necessary because we want to keep a compatible pipeline layout in all cases,
// and Vulkan does not tolerate having null handles in a descriptor set.
vk::BufferAndMemory mEmptyUniformBlockStorage;
vk::BufferHelper mEmptyUniformBlockStorage;
// Descriptor sets for uniform blocks and textures for this program.
std::vector<VkDescriptorSet> mDescriptorSets;
......
......@@ -61,7 +61,7 @@ constexpr VkFormatFeatureFlags kBlitFeatureFlags =
// StagingStorage implementation.
PixelBuffer::PixelBuffer(RendererVk *renderer)
: mStagingBuffer(kStagingBufferFlags, kStagingBufferSize)
: mStagingBuffer(kStagingBufferFlags, kStagingBufferSize, true)
{
// vkCmdCopyBufferToImage must have an offset that is a multiple of 4.
// https://www.khronos.org/registry/vulkan/specs/1.0/man/html/VkBufferImageCopy.html
......@@ -125,11 +125,10 @@ angle::Result PixelBuffer::stageSubresourceUpdate(ContextVk *contextVk,
VkBuffer bufferHandle = VK_NULL_HANDLE;
uint8_t *stagingPointer = nullptr;
bool newBufferAllocated = false;
VkDeviceSize stagingOffset = 0;
size_t allocationSize = outputDepthPitch * extents.depth;
ANGLE_TRY(mStagingBuffer.allocate(contextVk, allocationSize, &stagingPointer, &bufferHandle,
&stagingOffset, &newBufferAllocated));
&stagingOffset, nullptr));
const uint8_t *source = pixels + inputSkipBytes;
......@@ -196,13 +195,12 @@ angle::Result PixelBuffer::stageSubresourceUpdateFromFramebuffer(
VkBuffer bufferHandle = VK_NULL_HANDLE;
uint8_t *stagingPointer = nullptr;
bool newBufferAllocated = false;
VkDeviceSize stagingOffset = 0;
// The destination is only one layer deep.
size_t allocationSize = outputDepthPitch;
ANGLE_TRY(mStagingBuffer.allocate(contextVk, allocationSize, &stagingPointer, &bufferHandle,
&stagingOffset, &newBufferAllocated));
&stagingOffset, nullptr));
const angle::Format &copyFormat =
GetFormatFromFormatType(formatInfo.internalFormat, formatInfo.type);
......@@ -335,9 +333,8 @@ angle::Result PixelBuffer::stageSubresourceUpdateAndGetData(ContextVk *contextVk
{
VkBuffer bufferHandle;
VkDeviceSize stagingOffset = 0;
bool newBufferAllocated = false;
ANGLE_TRY(mStagingBuffer.allocate(contextVk, allocationSize, destData, &bufferHandle,
&stagingOffset, &newBufferAllocated));
&stagingOffset, nullptr));
VkBufferImageCopy copy = {};
copy.bufferOffset = stagingOffset;
......@@ -772,11 +769,10 @@ angle::Result TextureVk::copyImageDataToBuffer(ContextVk *contextVk,
// Allocate enough memory to copy the sourceArea region of the source texture into its pixel
// buffer.
bool newBufferAllocated = false;
VkBuffer copyBufferHandle = VK_NULL_HANDLE;
VkDeviceSize sourceCopyOffset = 0;
ANGLE_TRY(mPixelBuffer.allocate(contextVk, sourceCopyAllocationSize, outDataPtr,
&copyBufferHandle, &sourceCopyOffset, &newBufferAllocated));
&copyBufferHandle, &sourceCopyOffset, nullptr));
VkBufferImageCopy region = {};
region.bufferOffset = sourceCopyOffset;
......
......@@ -26,6 +26,10 @@ namespace
constexpr size_t kDynamicVertexDataSize = 1024 * 1024;
constexpr size_t kDynamicIndexDataSize = 1024 * 8;
constexpr size_t kMaxVertexFormatAlignment = 4;
constexpr VkBufferUsageFlags kVertexBufferUsageFlags =
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
constexpr VkBufferUsageFlags kIndexBufferUsageFlags =
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
bool BindingIsAligned(const gl::VertexBinding &binding, unsigned componentSize)
{
......@@ -55,9 +59,9 @@ angle::Result StreamVertexData(ContextVk *contextVk,
} // anonymous namespace
#define INIT \
{ \
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, 1024 * 8 \
#define INIT \
{ \
kVertexBufferUsageFlags, 1024 * 8, true \
}
VertexArrayVk::VertexArrayVk(const gl::VertexArrayState &state, RendererVk *renderer)
......@@ -91,9 +95,9 @@ VertexArrayVk::VertexArrayVk(const gl::VertexArrayState &state, RendererVk *rend
mCurrentElementArrayBuffer(nullptr),
mPackedInputBindings{},
mPackedInputAttributes{},
mDynamicVertexData(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, kDynamicVertexDataSize),
mDynamicIndexData(VK_BUFFER_USAGE_INDEX_BUFFER_BIT, kDynamicIndexDataSize),
mTranslatedByteIndexData(VK_BUFFER_USAGE_INDEX_BUFFER_BIT, kDynamicIndexDataSize),
mDynamicVertexData(kVertexBufferUsageFlags, kDynamicVertexDataSize, true),
mDynamicIndexData(kIndexBufferUsageFlags, kDynamicIndexDataSize, true),
mTranslatedByteIndexData(kIndexBufferUsageFlags, kDynamicIndexDataSize, true),
mLineLoopHelper(renderer),
mDirtyLineLoopTranslation(true)
{
......
......@@ -83,15 +83,15 @@ VkImageCreateFlags GetImageCreateFlags(gl::TextureType textureType)
} // anonymous namespace
// DynamicBuffer implementation.
DynamicBuffer::DynamicBuffer(VkBufferUsageFlags usage, size_t minSize)
DynamicBuffer::DynamicBuffer(VkBufferUsageFlags usage, size_t minSize, bool hostVisible)
: mUsage(usage),
mHostVisible(hostVisible),
mMinSize(minSize),
mHostCoherent(false),
mBuffer(nullptr),
mNextAllocationOffset(0),
mLastFlushOrInvalidateOffset(0),
mSize(0),
mAlignment(0),
mMappedMemory(nullptr)
mAlignment(0)
{}
void DynamicBuffer::init(size_t alignment, RendererVk *renderer)
......@@ -114,7 +114,7 @@ DynamicBuffer::~DynamicBuffer() {}
angle::Result DynamicBuffer::allocate(Context *context,
size_t sizeInBytes,
uint8_t **ptrOut,
VkBuffer *handleOut,
VkBuffer *bufferOut,
VkDeviceSize *offsetOut,
bool *newBufferAllocatedOut)
{
......@@ -125,16 +125,19 @@ angle::Result DynamicBuffer::allocate(Context *context,
if (!checkedNextWriteOffset.IsValid() || checkedNextWriteOffset.ValueOrDie() >= mSize)
{
if (mMappedMemory)
if (mBuffer)
{
ANGLE_TRY(flush(context));
unmap(context->getDevice());
}
mBuffer->unmap(context->getDevice());
mRetainedBuffers.emplace_back(std::move(mBuffer), std::move(mMemory));
mRetainedBuffers.push_back(mBuffer);
mBuffer = nullptr;
}
mSize = std::max(sizeToAllocate, mMinSize);
std::unique_ptr<BufferHelper> buffer = std::make_unique<BufferHelper>();
VkBufferCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
createInfo.flags = 0;
......@@ -143,15 +146,13 @@ angle::Result DynamicBuffer::allocate(Context *context,
createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
createInfo.queueFamilyIndexCount = 0;
createInfo.pQueueFamilyIndices = nullptr;
ANGLE_VK_TRY(context, mBuffer.init(context->getDevice(), createInfo));
VkMemoryPropertyFlags actualMemoryPropertyFlags = 0;
ANGLE_TRY(AllocateBufferMemory(context, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
&actualMemoryPropertyFlags, &mBuffer, &mMemory));
mHostCoherent = (VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ==
(VK_MEMORY_PROPERTY_HOST_COHERENT_BIT & actualMemoryPropertyFlags));
const VkMemoryPropertyFlags memoryProperty = mHostVisible
? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
: VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
ANGLE_TRY(buffer->init(context, createInfo, memoryProperty));
mBuffer = buffer.release();
ANGLE_VK_TRY(context, mMemory.map(context->getDevice(), 0, mSize, 0, &mMappedMemory));
mNextAllocationOffset = 0;
mLastFlushOrInvalidateOffset = 0;
......@@ -165,15 +166,22 @@ angle::Result DynamicBuffer::allocate(Context *context,
*newBufferAllocatedOut = false;
}
ASSERT(mBuffer.valid());
ASSERT(mBuffer != nullptr);
if (handleOut != nullptr)
if (bufferOut != nullptr)
{
*handleOut = mBuffer.getHandle();
*bufferOut = mBuffer->getBuffer().getHandle();
}
// Optionally map() the buffer if possible
if (ptrOut)
{
ASSERT(mHostVisible);
uint8_t *mappedMemory;
ANGLE_TRY(mBuffer->map(context, &mappedMemory));
*ptrOut = mappedMemory + mNextAllocationOffset;
}
ASSERT(mMappedMemory);
*ptrOut = mMappedMemory + mNextAllocationOffset;
*offsetOut = static_cast<VkDeviceSize>(mNextAllocationOffset);
mNextAllocationOffset += static_cast<uint32_t>(sizeToAllocate);
return angle::Result::Continue();
......@@ -181,15 +189,11 @@ angle::Result DynamicBuffer::allocate(Context *context,
angle::Result DynamicBuffer::flush(Context *context)
{
if (!mHostCoherent && (mNextAllocationOffset > mLastFlushOrInvalidateOffset))
if (mHostVisible && (mNextAllocationOffset > mLastFlushOrInvalidateOffset))
{
VkMappedMemoryRange range = {};
range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
range.memory = mMemory.getHandle();
range.offset = mLastFlushOrInvalidateOffset;
range.size = mNextAllocationOffset - mLastFlushOrInvalidateOffset;
ANGLE_VK_TRY(context, vkFlushMappedMemoryRanges(context->getDevice(), 1, &range));
ASSERT(mBuffer != nullptr);
ANGLE_TRY(mBuffer->flush(context, mLastFlushOrInvalidateOffset,
mNextAllocationOffset - mLastFlushOrInvalidateOffset));
mLastFlushOrInvalidateOffset = mNextAllocationOffset;
}
return angle::Result::Continue();
......@@ -197,15 +201,11 @@ angle::Result DynamicBuffer::flush(Context *context)
angle::Result DynamicBuffer::invalidate(Context *context)
{
if (!mHostCoherent && (mNextAllocationOffset > mLastFlushOrInvalidateOffset))
if (mHostVisible && (mNextAllocationOffset > mLastFlushOrInvalidateOffset))
{
VkMappedMemoryRange range = {};
range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
range.memory = mMemory.getHandle();
range.offset = mLastFlushOrInvalidateOffset;
range.size = mNextAllocationOffset - mLastFlushOrInvalidateOffset;
ANGLE_VK_TRY(context, vkInvalidateMappedMemoryRanges(context->getDevice(), 1, &range));
ASSERT(mBuffer != nullptr);
ANGLE_TRY(mBuffer->invalidate(context, mLastFlushOrInvalidateOffset,
mNextAllocationOffset - mLastFlushOrInvalidateOffset));
mLastFlushOrInvalidateOffset = mNextAllocationOffset;
}
return angle::Result::Continue();
......@@ -213,22 +213,31 @@ angle::Result DynamicBuffer::invalidate(Context *context)
void DynamicBuffer::release(RendererVk *renderer)
{
unmap(renderer->getDevice());
reset();
releaseRetainedBuffers(renderer);
Serial currentSerial = renderer->getCurrentQueueSerial();
renderer->releaseObject(currentSerial, &mBuffer);
renderer->releaseObject(currentSerial, &mMemory);
if (mBuffer)
{
mBuffer->unmap(renderer->getDevice());
// The buffers may not have been recording commands, but they could be used to store data so
// they should live until at most this frame. For example a vertex buffer filled entirely
// by the CPU currently never gets a chance to have its serial set.
mBuffer->updateQueueSerial(renderer->getCurrentQueueSerial());
mBuffer->release(renderer);
delete mBuffer;
mBuffer = nullptr;
}
}
void DynamicBuffer::releaseRetainedBuffers(RendererVk *renderer)
{
for (BufferAndMemory &toFree : mRetainedBuffers)
for (BufferHelper *toFree : mRetainedBuffers)
{
Serial currentSerial = renderer->getCurrentQueueSerial();
renderer->releaseObject(currentSerial, &toFree.buffer);
renderer->releaseObject(currentSerial, &toFree.memory);
// See note in release().
toFree->updateQueueSerial(renderer->getCurrentQueueSerial());
toFree->release(renderer);
delete toFree;
}
mRetainedBuffers.clear();
......@@ -236,24 +245,23 @@ void DynamicBuffer::releaseRetainedBuffers(RendererVk *renderer)
void DynamicBuffer::destroy(VkDevice device)
{
unmap(device);
reset();
for (BufferAndMemory &toFree : mRetainedBuffers)
for (BufferHelper *toFree : mRetainedBuffers)
{
toFree.buffer.destroy(device);
toFree.memory.destroy(device);
toFree->destroy(device);
delete toFree;
}
mRetainedBuffers.clear();
mBuffer.destroy(device);
mMemory.destroy(device);
}
VkBuffer DynamicBuffer::getCurrentBufferHandle() const
{
return mBuffer.getHandle();
if (mBuffer)
{
mBuffer->unmap(device);
mBuffer->destroy(device);
delete mBuffer;
mBuffer = nullptr;
}
}
void DynamicBuffer::setMinimumSizeForTesting(size_t minSize)
......@@ -265,15 +273,6 @@ void DynamicBuffer::setMinimumSizeForTesting(size_t minSize)
mSize = 0;
}
void DynamicBuffer::unmap(VkDevice device)
{
if (mMappedMemory)
{
mMemory.unmap(device);
mMappedMemory = nullptr;
}
}
void DynamicBuffer::reset()
{
mSize = 0;
......@@ -730,7 +729,7 @@ void SemaphoreHelper::deinit()
// LineLoopHelper implementation.
LineLoopHelper::LineLoopHelper(RendererVk *renderer)
: mDynamicIndexBuffer(kLineLoopDynamicBufferUsage, kLineLoopDynamicBufferMinSize)
: mDynamicIndexBuffer(kLineLoopDynamicBufferUsage, kLineLoopDynamicBufferMinSize, true)
{
// We need to use an alignment of the maximum size we're going to allocate, which is
// VK_INDEX_TYPE_UINT32. When we switch from a drawElement to a drawArray call, the allocations
......@@ -884,6 +883,7 @@ BufferHelper::BufferHelper()
: RecordableGraphResource(CommandGraphResourceType::Buffer),
mMemoryPropertyFlags{},
mSize(0),
mMappedMemory(nullptr),
mCurrentWriteAccess(0),
mCurrentReadAccess(0)
{}
......@@ -900,8 +900,19 @@ angle::Result BufferHelper::init(Context *context,
&mDeviceMemory);
}
void BufferHelper::destroy(VkDevice device)
{
unmap(device);
mSize = 0;
mBuffer.destroy(device);
mBufferView.destroy(device);
mDeviceMemory.destroy(device);
}
void BufferHelper::release(RendererVk *renderer)
{
unmap(renderer->getDevice());
mSize = 0;
renderer->releaseObject(getStoredQueueSerial(), &mBuffer);
......@@ -967,6 +978,53 @@ angle::Result BufferHelper::initBufferView(Context *context, const Format &forma
return angle::Result::Continue();
}
angle::Result BufferHelper::mapImpl(Context *context)
{
ANGLE_VK_TRY(context, mDeviceMemory.map(context->getDevice(), 0, mSize, 0, &mMappedMemory));
return angle::Result::Continue();
}
void BufferHelper::unmap(VkDevice device)
{
if (mMappedMemory)
{
mDeviceMemory.unmap(device);
mMappedMemory = nullptr;
}
}
angle::Result BufferHelper::flush(Context *context, size_t offset, size_t 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(context, vkFlushMappedMemoryRanges(context->getDevice(), 1, &range));
}
return angle::Result::Continue();
}
angle::Result BufferHelper::invalidate(Context *context, size_t offset, size_t 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(context, vkInvalidateMappedMemoryRanges(context->getDevice(), 1, &range));
}
return angle::Result::Continue();
}
// ImageHelper implementation.
ImageHelper::ImageHelper()
: RecordableGraphResource(CommandGraphResourceType::Image),
......
......@@ -28,22 +28,24 @@ namespace vk
//
// Dynamic buffers are used to implement a variety of data streaming operations in Vulkan, such
// as for immediate vertex array and element array data, uniform updates, and other dynamic data.
class BufferHelper;
class DynamicBuffer : angle::NonCopyable
{
public:
DynamicBuffer(VkBufferUsageFlags usage, size_t minSize);
DynamicBuffer(VkBufferUsageFlags usage, size_t minSize, bool hostVisible);
~DynamicBuffer();
// Init is called after the buffer creation so that the alignment can be specified later.
void init(size_t alignment, RendererVk *renderer);
// This call will allocate a new region at the end of the buffer. It internally may trigger
// a new buffer to be created (which is returned in 'newBufferAllocatedOut'. This param may
// be nullptr.
// a new buffer to be created (which is returned in the optional parameter
// `newBufferAllocatedOut`). The new region will be in the returned buffer at given offset. If
// a memory pointer is given, the buffer will be automatically map()ed.
angle::Result allocate(Context *context,
size_t sizeInBytes,
uint8_t **ptrOut,
VkBuffer *handleOut,
VkBuffer *bufferOut,
VkDeviceSize *offsetOut,
bool *newBufferAllocatedOut);
......@@ -62,27 +64,24 @@ class DynamicBuffer : angle::NonCopyable
// This frees resources immediately.
void destroy(VkDevice device);
VkBuffer getCurrentBufferHandle() const;
BufferHelper *getCurrentBuffer() { return mBuffer; };
// For testing only!
void setMinimumSizeForTesting(size_t minSize);
private:
void unmap(VkDevice device);
void reset();
VkBufferUsageFlags mUsage;
bool mHostVisible;
size_t mMinSize;
Buffer mBuffer;
DeviceMemory mMemory;
bool mHostCoherent;
BufferHelper *mBuffer;
uint32_t mNextAllocationOffset;
uint32_t mLastFlushOrInvalidateOffset;
size_t mSize;
size_t mAlignment;
uint8_t *mMappedMemory;
std::vector<BufferAndMemory> mRetainedBuffers;
std::vector<BufferHelper *> mRetainedBuffers;
};
// Uses DescriptorPool to allocate descriptor sets as needed. If a descriptor pool becomes full, we
......@@ -381,6 +380,7 @@ class BufferHelper final : public RecordableGraphResource
angle::Result init(Context *context,
const VkBufferCreateInfo &createInfo,
VkMemoryPropertyFlags memoryPropertyFlags);
void destroy(VkDevice device);
void release(RendererVk *renderer);
bool valid() const { return mBuffer.valid(); }
......@@ -408,7 +408,25 @@ class BufferHelper final : public RecordableGraphResource
return angle::Result::Continue();
}
angle::Result map(Context *context, uint8_t **ptrOut)
{
if (!mMappedMemory)
{
ANGLE_TRY(mapImpl(context));
}
*ptrOut = mMappedMemory;
return angle::Result::Continue();
}
void unmap(VkDevice device);
// After a sequence of writes, call flush to ensure the data is visible to the device.
angle::Result flush(Context *context, size_t offset, size_t size);
// After a sequence of writes, call invalidate to ensure the data is visible to the host.
angle::Result invalidate(Context *context, size_t offset, size_t size);
private:
angle::Result mapImpl(Context *context);
angle::Result initBufferView(Context *context, const Format &format);
// Vulkan objects.
......@@ -419,6 +437,7 @@ class BufferHelper final : public RecordableGraphResource
// Cached properties.
VkMemoryPropertyFlags mMemoryPropertyFlags;
VkDeviceSize mSize;
uint8_t *mMappedMemory;
// For memory barriers.
VkFlags mCurrentWriteAccess;
......
......@@ -279,24 +279,6 @@ VkDevice Context::getDevice() const
return mRenderer->getDevice();
}
// BufferAndMemory implementation.
BufferAndMemory::BufferAndMemory() = default;
BufferAndMemory::BufferAndMemory(Buffer &&buffer, DeviceMemory &&deviceMemory)
: buffer(std::move(buffer)), memory(std::move(deviceMemory))
{}
BufferAndMemory::BufferAndMemory(BufferAndMemory &&other)
: buffer(std::move(other.buffer)), memory(std::move(other.memory))
{}
BufferAndMemory &BufferAndMemory::operator=(BufferAndMemory &&other)
{
buffer = std::move(other.buffer);
memory = std::move(other.memory);
return *this;
}
// CommandPool implementation.
CommandPool::CommandPool() {}
......
......@@ -738,17 +738,6 @@ angle::Result AllocateBufferMemory(vk::Context *context,
Buffer *buffer,
DeviceMemory *deviceMemoryOut);
struct BufferAndMemory final : angle::NonCopyable
{
BufferAndMemory();
BufferAndMemory(Buffer &&buffer, DeviceMemory &&deviceMemory);
BufferAndMemory(BufferAndMemory &&other);
BufferAndMemory &operator=(BufferAndMemory &&other);
Buffer buffer;
DeviceMemory memory;
};
angle::Result AllocateImageMemory(vk::Context *context,
VkMemoryPropertyFlags memoryPropertyFlags,
Image *image,
......
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