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