Commit 57dd97aa by Jamie Madill Committed by Commit Bot

Vulkan: Add helper for allocating image memory.

Also refactors some memory index searching code that was duplicated. This will lead the way to having more code reuse for our Renderbuffers implementation in Vulkan, and for other types of Texture. Bug: angleproject:2347 Change-Id: I49cbd77328c01f945d66f92e6ec4ba7c552abeff Reviewed-on: https://chromium-review.googlesource.com/904684 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarYuly Novikov <ynovikov@chromium.org>
parent fbb1c792
......@@ -68,7 +68,11 @@ gl::Error BufferVk::setData(const gl::Context *context,
createInfo.pQueueFamilyIndices = nullptr;
ANGLE_TRY(mBuffer.init(device, createInfo));
ANGLE_TRY(vk::AllocateBufferMemory(contextVk, size, &mBuffer, &mBufferMemory,
// Assume host vislble/coherent memory available.
VkMemoryPropertyFlags flags =
(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
ANGLE_TRY(vk::AllocateBufferMemory(contextVk, flags, &mBuffer, &mBufferMemory,
&mCurrentRequiredSize));
}
......
......@@ -263,9 +263,8 @@ gl::Error FramebufferVk::readPixels(const gl::Context *context,
vk::Image *readImage = renderTarget->image;
vk::StagingImage stagingImage;
ANGLE_TRY(renderer->createStagingImage(TextureDimension::TEX_2D, *renderTarget->format,
renderTarget->extents, vk::StagingUsage::Read,
&stagingImage));
ANGLE_TRY(stagingImage.init(contextVk, TextureDimension::TEX_2D, *renderTarget->format,
renderTarget->extents, vk::StagingUsage::Read));
vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(recordWriteCommands(renderer, &commandBuffer));
......
......@@ -62,7 +62,10 @@ gl::Error InitDefaultUniformBlock(const gl::Context *context,
ANGLE_TRY(storageOut->buffer.init(device, uniformBufferInfo));
ANGLE_TRY(AllocateBufferMemory(vk::GetImpl(context), blockSize, &storageOut->buffer,
// Assume host vislble/coherent memory available.
VkMemoryPropertyFlags flags =
(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
ANGLE_TRY(AllocateBufferMemory(vk::GetImpl(context), flags, &storageOut->buffer,
&storageOut->memory, requiredSizeOut));
return gl::NoError();
......@@ -357,8 +360,11 @@ gl::Error ProgramVk::initDefaultUniformBlocks(const gl::Context *glContext)
ANGLE_TRY(mEmptyUniformBlockStorage.buffer.init(device, uniformBufferInfo));
// Assume host vislble/coherent memory available.
VkMemoryPropertyFlags flags =
(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
size_t requiredSize = 0;
ANGLE_TRY(AllocateBufferMemory(contextVk, 1, &mEmptyUniformBlockStorage.buffer,
ANGLE_TRY(AllocateBufferMemory(contextVk, flags, &mEmptyUniformBlockStorage.buffer,
&mEmptyUniformBlockStorage.memory, &requiredSize));
}
......
......@@ -720,17 +720,6 @@ vk::Error RendererVk::submitFrame(const VkSubmitInfo &submitInfo, vk::CommandBuf
return vk::NoError();
}
vk::Error RendererVk::createStagingImage(TextureDimension dimension,
const vk::Format &format,
const gl::Extents &extent,
vk::StagingUsage usage,
vk::StagingImage *imageOut)
{
ANGLE_TRY(imageOut->init(mDevice, mCurrentQueueFamilyIndex, mMemoryProperties, dimension,
format.vkTextureFormat, extent, usage));
return vk::NoError();
}
GlslangWrapper *RendererVk::getGlslangWrapper()
{
return mGlslangWrapper;
......
......@@ -63,12 +63,6 @@ class RendererVk : angle::NonCopyable
const gl::Extensions &getNativeExtensions() const;
const gl::Limitations &getNativeLimitations() const;
vk::Error createStagingImage(TextureDimension dimension,
const vk::Format &format,
const gl::Extents &extent,
vk::StagingUsage usage,
vk::StagingImage *imageOut);
GlslangWrapper *getGlslangWrapper();
Serial getCurrentQueueSerial() const;
......
......@@ -113,22 +113,10 @@ gl::Error TextureVk::setImage(const gl::Context *context,
ANGLE_TRY(mImage.init(device, imageInfo));
// Allocate the device memory for the image.
// TODO(jmadill): Use more intelligent device memory allocation.
VkMemoryRequirements memoryRequirements;
mImage.getMemoryRequirements(device, &memoryRequirements);
uint32_t memoryIndex = renderer->getMemoryProperties().findCompatibleMemoryIndex(
memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VkMemoryAllocateInfo allocateInfo;
allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocateInfo.pNext = nullptr;
allocateInfo.allocationSize = memoryRequirements.size;
allocateInfo.memoryTypeIndex = memoryIndex;
ANGLE_TRY(mDeviceMemory.allocate(device, allocateInfo));
ANGLE_TRY(mImage.bindMemory(device, mDeviceMemory));
VkMemoryPropertyFlags flags = (VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
size_t requiredSize = 0;
ANGLE_TRY(
vk::AllocateImageMemory(contextVk, flags, &mImage, &mDeviceMemory, &requiredSize));
VkImageViewCreateInfo viewInfo;
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
......@@ -220,8 +208,8 @@ gl::Error TextureVk::setSubImageImpl(ContextVk *contextVk,
const vk::Format &vkFormat = *mRenderTarget.format;
vk::StagingImage stagingImage;
ANGLE_TRY(renderer->createStagingImage(TextureDimension::TEX_2D, vkFormat, size,
vk::StagingUsage::Write, &stagingImage));
ANGLE_TRY(stagingImage.init(contextVk, TextureDimension::TEX_2D, vkFormat, size,
vk::StagingUsage::Write));
GLuint inputRowPitch = 0;
ANGLE_TRY_RESULT(
......
......@@ -147,6 +147,49 @@ bool HasValidationLayers(const std::vector<VkLayerProperties> &layerProps)
return true;
}
vk::Error FindAndAllocateCompatibleMemory(VkDevice device,
const vk::MemoryProperties &memoryProperties,
VkMemoryPropertyFlags memoryPropertyFlags,
const VkMemoryRequirements &memoryRequirements,
vk::DeviceMemory *deviceMemoryOut)
{
uint32_t memoryTypeIndex = 0;
ANGLE_TRY(memoryProperties.findCompatibleMemoryIndex(memoryRequirements, memoryPropertyFlags,
&memoryTypeIndex));
VkMemoryAllocateInfo allocInfo;
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.pNext = nullptr;
allocInfo.memoryTypeIndex = memoryTypeIndex;
allocInfo.allocationSize = memoryRequirements.size;
ANGLE_TRY(deviceMemoryOut->allocate(device, allocInfo));
return vk::NoError();
}
template <typename T>
vk::Error AllocateBufferOrImageMemory(ContextVk *contextVk,
VkMemoryPropertyFlags memoryPropertyFlags,
T *bufferOrImage,
vk::DeviceMemory *deviceMemoryOut,
size_t *requiredSizeOut)
{
VkDevice device = contextVk->getDevice();
const vk::MemoryProperties &memoryProperties = contextVk->getRenderer()->getMemoryProperties();
// Call driver to determine memory requirements.
VkMemoryRequirements memoryRequirements;
bufferOrImage->getMemoryRequirements(device, &memoryRequirements);
// The requirements size is not always equal to the specified API size.
*requiredSizeOut = static_cast<size_t>(memoryRequirements.size);
ANGLE_TRY(FindAndAllocateCompatibleMemory(device, memoryProperties, memoryPropertyFlags,
memoryRequirements, deviceMemoryOut));
ANGLE_TRY(bufferOrImage->bindMemory(device, *deviceMemoryOut));
return vk::NoError();
}
} // anonymous namespace
const char *g_VkLoaderLayersPathEnv = "VK_LAYER_PATH";
......@@ -809,21 +852,22 @@ void StagingImage::destroy(VkDevice device)
mDeviceMemory.destroy(device);
}
Error StagingImage::init(VkDevice device,
uint32_t queueFamilyIndex,
const vk::MemoryProperties &memoryProperties,
Error StagingImage::init(ContextVk *contextVk,
TextureDimension dimension,
VkFormat format,
const Format &format,
const gl::Extents &extent,
StagingUsage usage)
{
VkDevice device = contextVk->getDevice();
uint32_t queueFamilyIndex = contextVk->getRenderer()->getQueueFamilyIndex();
VkImageCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.imageType = VK_IMAGE_TYPE_2D;
createInfo.format = format;
createInfo.format = format.vkTextureFormat;
createInfo.extent.width = static_cast<uint32_t>(extent.width);
createInfo.extent.height = static_cast<uint32_t>(extent.height);
createInfo.extent.depth = static_cast<uint32_t>(extent.depth);
......@@ -843,28 +887,14 @@ Error StagingImage::init(VkDevice device,
ANGLE_TRY(mImage.init(device, createInfo));
VkMemoryRequirements memoryRequirements;
mImage.getMemoryRequirements(device, &memoryRequirements);
// Find the right kind of memory index.
// Allocate and bind host visible and coherent Image memory.
// TODO(ynovikov): better approach would be to request just visible memory,
// and call vkInvalidateMappedMemoryRanges if the allocated memory is not coherent.
// This would solve potential issues of:
// 1) not having (enough) coherent memory and 2) coherent memory being slower
uint32_t memoryIndex = memoryProperties.findCompatibleMemoryIndex(
memoryRequirements.memoryTypeBits,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
VkMemoryAllocateInfo allocateInfo;
allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocateInfo.pNext = nullptr;
allocateInfo.allocationSize = memoryRequirements.size;
allocateInfo.memoryTypeIndex = memoryIndex;
ANGLE_TRY(mDeviceMemory.allocate(device, allocateInfo));
ANGLE_TRY(mImage.bindMemory(device, mDeviceMemory));
mSize = memoryRequirements.size;
VkMemoryPropertyFlags memoryPropertyFlags =
(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
ANGLE_TRY(AllocateImageMemory(contextVk, memoryPropertyFlags, &mImage, &mDeviceMemory, &mSize));
return NoError();
}
......@@ -903,6 +933,12 @@ Error Buffer::bindMemory(VkDevice device, const DeviceMemory &deviceMemory)
return NoError();
}
void Buffer::getMemoryRequirements(VkDevice device, VkMemoryRequirements *memoryRequirementsOut)
{
ASSERT(valid());
vkGetBufferMemoryRequirements(device, mHandle, memoryRequirementsOut);
}
// ShaderModule implementation.
ShaderModule::ShaderModule()
{
......@@ -1077,24 +1113,30 @@ void MemoryProperties::init(VkPhysicalDevice physicalDevice)
ASSERT(mMemoryProperties.memoryTypeCount > 0);
}
uint32_t MemoryProperties::findCompatibleMemoryIndex(uint32_t bitMask, uint32_t propertyFlags) const
Error MemoryProperties::findCompatibleMemoryIndex(const VkMemoryRequirements &memoryRequirements,
VkMemoryPropertyFlags memoryPropertyFlags,
uint32_t *typeIndexOut) const
{
ASSERT(mMemoryProperties.memoryTypeCount > 0);
ASSERT(mMemoryProperties.memoryTypeCount > 0 && mMemoryProperties.memoryTypeCount <= 32);
// TODO(jmadill): Cache compatible memory indexes after finding them once.
for (size_t memoryIndex : angle::BitSet32<32>(bitMask))
// Find a compatible memory pool index. If the index doesn't change, we could cache it.
// Not finding a valid memory pool means an out-of-spec driver, or internal error.
// TODO(jmadill): Determine if it is possible to cache indexes.
// TODO(jmadill): More efficient memory allocation.
for (size_t memoryIndex : angle::BitSet32<32>(memoryRequirements.memoryTypeBits))
{
ASSERT(memoryIndex < mMemoryProperties.memoryTypeCount);
if ((mMemoryProperties.memoryTypes[memoryIndex].propertyFlags & propertyFlags) ==
propertyFlags)
if ((mMemoryProperties.memoryTypes[memoryIndex].propertyFlags & memoryPropertyFlags) ==
memoryPropertyFlags)
{
return static_cast<uint32_t>(memoryIndex);
*typeIndexOut = static_cast<uint32_t>(memoryIndex);
return NoError();
}
}
UNREACHABLE();
return std::numeric_limits<uint32_t>::max();
// TODO(jmadill): Add error message to error.
return vk::Error(VK_ERROR_INCOMPATIBLE_DRIVER);
}
// StagingBuffer implementation.
......@@ -1121,9 +1163,11 @@ vk::Error StagingBuffer::init(ContextVk *contextVk, VkDeviceSize size, StagingUs
createInfo.queueFamilyIndexCount = 0;
createInfo.pQueueFamilyIndices = nullptr;
VkMemoryPropertyFlags flags =
(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
ANGLE_TRY(mBuffer.init(contextVk->getDevice(), createInfo));
ANGLE_TRY(AllocateBufferMemory(contextVk, static_cast<size_t>(size), &mBuffer, &mDeviceMemory,
&mSize));
ANGLE_TRY(AllocateBufferMemory(contextVk, flags, &mBuffer, &mDeviceMemory, &mSize));
return vk::NoError();
}
......@@ -1134,60 +1178,24 @@ void StagingBuffer::dumpResources(Serial serial, std::vector<vk::GarbageObject>
mDeviceMemory.dumpResources(serial, garbageQueue);
}
Optional<uint32_t> FindMemoryType(const VkPhysicalDeviceMemoryProperties &memoryProps,
const VkMemoryRequirements &requirements,
uint32_t propertyFlagMask)
{
for (uint32_t typeIndex = 0; typeIndex < memoryProps.memoryTypeCount; ++typeIndex)
{
if ((requirements.memoryTypeBits & (1u << typeIndex)) != 0 &&
((memoryProps.memoryTypes[typeIndex].propertyFlags & propertyFlagMask) ==
propertyFlagMask))
{
return typeIndex;
}
}
return Optional<uint32_t>::Invalid();
}
Error AllocateBufferMemory(ContextVk *contextVk,
size_t size,
VkMemoryPropertyFlags memoryPropertyFlags,
Buffer *buffer,
DeviceMemory *deviceMemoryOut,
size_t *requiredSizeOut)
{
VkDevice device = contextVk->getDevice();
// Find a compatible memory pool index. If the index doesn't change, we could cache it.
// Not finding a valid memory pool means an out-of-spec driver, or internal error.
// TODO(jmadill): More efficient memory allocation.
VkMemoryRequirements memoryRequirements;
vkGetBufferMemoryRequirements(device, buffer->getHandle(), &memoryRequirements);
// The requirements size is not always equal to the specified API size.
ASSERT(memoryRequirements.size >= size);
*requiredSizeOut = static_cast<size_t>(memoryRequirements.size);
VkPhysicalDeviceMemoryProperties memoryProperties;
vkGetPhysicalDeviceMemoryProperties(contextVk->getRenderer()->getPhysicalDevice(),
&memoryProperties);
auto memoryTypeIndex =
FindMemoryType(memoryProperties, memoryRequirements,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
ANGLE_VK_CHECK(memoryTypeIndex.valid(), VK_ERROR_INCOMPATIBLE_DRIVER);
VkMemoryAllocateInfo allocInfo;
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.pNext = nullptr;
allocInfo.memoryTypeIndex = memoryTypeIndex.value();
allocInfo.allocationSize = memoryRequirements.size;
ANGLE_TRY(deviceMemoryOut->allocate(device, allocInfo));
ANGLE_TRY(buffer->bindMemory(device, *deviceMemoryOut));
return AllocateBufferOrImageMemory(contextVk, memoryPropertyFlags, buffer, deviceMemoryOut,
requiredSizeOut);
}
return NoError();
Error AllocateImageMemory(ContextVk *contextVk,
VkMemoryPropertyFlags memoryPropertyFlags,
Image *image,
DeviceMemory *deviceMemoryOut,
size_t *requiredSizeOut)
{
return AllocateBufferOrImageMemory(contextVk, memoryPropertyFlags, image, deviceMemoryOut,
requiredSizeOut);
}
// GarbageObject implementation.
......
......@@ -115,18 +115,6 @@ GetImplType<T> *GetImpl(const T *glObject)
return GetImplAs<GetImplType<T>>(glObject);
}
class MemoryProperties final : angle::NonCopyable
{
public:
MemoryProperties();
void init(VkPhysicalDevice physicalDevice);
uint32_t findCompatibleMemoryIndex(uint32_t bitMask, uint32_t propertyFlags) const;
private:
VkPhysicalDeviceMemoryProperties mMemoryProperties;
};
class Error final
{
public:
......@@ -292,6 +280,20 @@ class WrappedObject : angle::NonCopyable
HandleT mHandle;
};
class MemoryProperties final : angle::NonCopyable
{
public:
MemoryProperties();
void init(VkPhysicalDevice physicalDevice);
Error findCompatibleMemoryIndex(const VkMemoryRequirements &memoryRequirements,
VkMemoryPropertyFlags memoryPropertyFlags,
uint32_t *indexOut) const;
private:
VkPhysicalDeviceMemoryProperties mMemoryProperties;
};
class CommandPool final : public WrappedObject<CommandPool, VkCommandPool>
{
public:
......@@ -481,6 +483,7 @@ class Buffer final : public WrappedObject<Buffer, VkBuffer>
Error init(VkDevice device, const VkBufferCreateInfo &createInfo);
Error bindMemory(VkDevice device, const DeviceMemory &deviceMemory);
void getMemoryRequirements(VkDevice device, VkMemoryRequirements *memoryRequirementsOut);
};
class ShaderModule final : public WrappedObject<ShaderModule, VkShaderModule>
......@@ -559,11 +562,9 @@ class StagingImage final : angle::NonCopyable
StagingImage(StagingImage &&other);
void destroy(VkDevice device);
vk::Error init(VkDevice device,
uint32_t queueFamilyIndex,
const MemoryProperties &memoryProperties,
vk::Error init(ContextVk *contextVk,
TextureDimension dimension,
VkFormat format,
const Format &format,
const gl::Extents &extent,
StagingUsage usage);
......@@ -578,7 +579,7 @@ class StagingImage final : angle::NonCopyable
private:
Image mImage;
DeviceMemory mDeviceMemory;
VkDeviceSize mSize;
size_t mSize;
};
// Similar to StagingImage, for Buffers.
......@@ -641,12 +642,8 @@ class ObjectAndSerial final : angle::NonCopyable
Serial mQueueSerial;
};
Optional<uint32_t> FindMemoryType(const VkPhysicalDeviceMemoryProperties &memoryProps,
const VkMemoryRequirements &requirements,
uint32_t propertyFlagMask);
Error AllocateBufferMemory(ContextVk *contextVk,
size_t size,
VkMemoryPropertyFlags memoryPropertyFlags,
Buffer *buffer,
DeviceMemory *deviceMemoryOut,
size_t *requiredSizeOut);
......@@ -657,6 +654,12 @@ struct BufferAndMemory final : private angle::NonCopyable
vk::DeviceMemory memory;
};
Error AllocateImageMemory(ContextVk *contextVk,
VkMemoryPropertyFlags memoryPropertyFlags,
Image *image,
DeviceMemory *deviceMemoryOut,
size_t *requiredSizeOut);
} // namespace vk
namespace gl_vk
......
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