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)
{
......
......@@ -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