Commit 6cb8345f by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Non-zero memory initialization for all images

This was only implemented for single-level, single-layer, single-sample color images. This change implements clear for all images. Additionally, the move to VMA broke the initialization of the staging buffer, so even for the supported case, the image was being initialized with uninitialized data. Bug: angleproject:4092 Bug: angleproject:4551 Change-Id: Ic2eee3f8454a93f1bcf3ca725afabcdc693047e1 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2249376Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent c70b8f84
......@@ -2202,8 +2202,8 @@ angle::Result BufferHelper::init(Context *context,
// Can map the memory.
// Pick an arbitrary value to initialize non-zero memory for sanitization.
constexpr int kNonZeroInitValue = 55;
ANGLE_TRY(InitMappableAllocation(allocator, &mAllocation, mSize, kNonZeroInitValue,
mMemoryPropertyFlags));
ANGLE_TRY(InitMappableAllocation(context, allocator, &mAllocation, mSize,
kNonZeroInitValue, mMemoryPropertyFlags));
}
}
......@@ -2608,9 +2608,8 @@ void ImageHelper::resetImageWeakReference()
angle::Result ImageHelper::initializeNonZeroMemory(Context *context, VkDeviceSize size)
{
// The staging buffer memory is non-zero-initialized in 'init'.
vk::StagingBuffer stagingBuffer;
ANGLE_TRY(stagingBuffer.init(context, size, vk::StagingUsage::Write));
const angle::Format &angleFormat = mFormat->actualImageFormat();
bool isCompressedFormat = angleFormat.isBlock;
RendererVk *renderer = context->getRenderer();
......@@ -2621,13 +2620,78 @@ angle::Result ImageHelper::initializeNonZeroMemory(Context *context, VkDeviceSiz
forceChangeLayoutAndQueue(getAspectFlags(), ImageLayout::TransferDst, mCurrentQueueFamilyIndex,
&commandBuffer);
VkBufferImageCopy copyRegion = {};
copyRegion.imageExtent = mExtents;
copyRegion.imageSubresource.aspectMask = getAspectFlags();
copyRegion.imageSubresource.layerCount = 1;
vk::StagingBuffer stagingBuffer;
if (isCompressedFormat)
{
// If format is compressed, set its contents through buffer copies.
// The staging buffer memory is non-zero-initialized in 'init'.
ANGLE_TRY(stagingBuffer.init(context, size, vk::StagingUsage::Write));
for (uint32_t level = 0; level < mLevelCount; ++level)
{
VkBufferImageCopy copyRegion = {};
gl_vk::GetExtent(getLevelExtents(level), &copyRegion.imageExtent);
copyRegion.imageSubresource.aspectMask = getAspectFlags();
copyRegion.imageSubresource.layerCount = mLayerCount;
// If image has depth and stencil, copy to each individually per Vulkan spec.
bool hasBothDepthAndStencil = isCombinedDepthStencilFormat();
if (hasBothDepthAndStencil)
{
copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
}
commandBuffer.copyBufferToImage(stagingBuffer.getBuffer().getHandle(), mImage,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copyRegion);
if (hasBothDepthAndStencil)
{
copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
commandBuffer.copyBufferToImage(stagingBuffer.getBuffer().getHandle(), mImage,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1,
&copyRegion);
}
}
}
else
{
// Otherwise issue clear commands.
VkImageSubresourceRange subresource = {};
subresource.aspectMask = getAspectFlags();
subresource.baseMipLevel = 0;
subresource.levelCount = mLevelCount;
subresource.baseArrayLayer = 0;
subresource.layerCount = mLayerCount;
// Arbitrary value to initialize the memory with. Note: the given uint value, reinterpreted
// as float is about 0.7.
constexpr uint32_t kInitValue = 0x3F345678;
constexpr float kInitValueFloat = 0.12345f;
if ((subresource.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0)
{
VkClearColorValue clearValue;
clearValue.uint32[0] = kInitValue;
clearValue.uint32[1] = kInitValue;
clearValue.uint32[2] = kInitValue;
clearValue.uint32[3] = kInitValue;
commandBuffer.copyBufferToImage(stagingBuffer.getBuffer().getHandle(), mImage,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copyRegion);
commandBuffer.clearColorImage(mImage, getCurrentLayout(), clearValue, 1, &subresource);
}
else
{
VkClearDepthStencilValue clearValue;
clearValue.depth = kInitValueFloat;
clearValue.stencil = kInitValue;
commandBuffer.clearDepthStencilImage(mImage, getCurrentLayout(), clearValue, 1,
&subresource);
}
}
ANGLE_VK_TRY(context, commandBuffer.end());
......@@ -2635,7 +2699,10 @@ angle::Result ImageHelper::initializeNonZeroMemory(Context *context, VkDeviceSiz
ANGLE_TRY(renderer->queueSubmitOneOff(context, std::move(commandBuffer),
egl::ContextPriority::Medium, nullptr, &serial));
stagingBuffer.collectGarbage(renderer, serial);
if (isCompressedFormat)
{
stagingBuffer.collectGarbage(renderer, serial);
}
mUse.updateSerialOneOff(serial);
return angle::Result::Continue;
......@@ -2656,16 +2723,7 @@ angle::Result ImageHelper::initMemory(Context *context,
// Can't map the memory. Use a staging resource.
if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
{
// Only currently works with single-sampled color images with one mip/layer.
if (mLevelCount == 1 && mLayerCount == 1 &&
getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT && mSamples == 1)
{
ANGLE_TRY(initializeNonZeroMemory(context, size));
}
else
{
UNIMPLEMENTED();
}
ANGLE_TRY(initializeNonZeroMemory(context, size));
}
}
......@@ -2882,8 +2940,9 @@ gl::Extents ImageHelper::getLevelExtents(uint32_t level) const
// you shrink the extents by half.
uint32_t width = std::max(mExtents.width >> level, 1u);
uint32_t height = std::max(mExtents.height >> level, 1u);
uint32_t depth = std::max(mExtents.depth >> level, 1u);
return gl::Extents(width, height, mExtents.depth);
return gl::Extents(width, height, depth);
}
gl::Extents ImageHelper::getLevelExtents2D(uint32_t level) const
......
......@@ -36,6 +36,10 @@ namespace rx
{
namespace
{
// Pick an arbitrary value to initialize non-zero memory for sanitization. Note that 0x3F3F3F3F
// as float is about 0.75.
constexpr int kNonZeroInitValue = 0x3F;
VkImageUsageFlags GetStagingBufferUsageFlags(vk::StagingUsage usage)
{
switch (usage)
......@@ -60,9 +64,6 @@ angle::Result FindAndAllocateCompatibleMemory(vk::Context *context,
const void *extraAllocationInfo,
vk::DeviceMemory *deviceMemoryOut)
{
// Pick an arbitrary value to initialize non-zero memory for sanitization.
constexpr int kNonZeroInitValue = 55;
VkDevice device = context->getDevice();
uint32_t memoryTypeIndex = 0;
......@@ -422,6 +423,15 @@ angle::Result StagingBuffer::init(Context *context, VkDeviceSize size, StagingUs
renderer->getFeatures().persistentlyMappedBuffers.enabled,
&memoryTypeIndex, &mBuffer, &mAllocation));
mSize = static_cast<size_t>(size);
// Wipe memory to an invalid value when the 'allocateNonZeroMemory' feature is enabled. The
// invalid values ensures our testing doesn't assume zero-initialized memory.
if (renderer->getFeatures().allocateNonZeroMemory.enabled)
{
ANGLE_TRY(vk::InitMappableAllocation(context, allocator, &mAllocation, size,
kNonZeroInitValue, requiredFlags));
}
return angle::Result::Continue;
}
......@@ -443,14 +453,15 @@ void StagingBuffer::collectGarbage(RendererVk *renderer, Serial serial)
renderer->collectGarbage(std::move(sharedUse), std::move(garbageList));
}
angle::Result InitMappableAllocation(const vk::Allocator &allocator,
angle::Result InitMappableAllocation(Context *context,
const vk::Allocator &allocator,
Allocation *allocation,
VkDeviceSize size,
int value,
VkMemoryPropertyFlags memoryPropertyFlags)
{
uint8_t *mapPointer;
allocation->map(allocator, &mapPointer);
ANGLE_VK_TRY(context, allocation->map(allocator, &mapPointer));
memset(mapPointer, value, static_cast<size_t>(size));
if ((memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0)
......
......@@ -323,13 +323,14 @@ class StagingBuffer final : angle::NonCopyable
size_t mSize;
};
angle::Result InitMappableAllocation(const vk::Allocator &allocator,
angle::Result InitMappableAllocation(Context *context,
const vk::Allocator &allocator,
Allocation *allocation,
VkDeviceSize size,
int value,
VkMemoryPropertyFlags memoryPropertyFlags);
angle::Result InitMappableDeviceMemory(vk::Context *context,
angle::Result InitMappableDeviceMemory(Context *context,
vk::DeviceMemory *deviceMemory,
VkDeviceSize size,
int value,
......
......@@ -1879,8 +1879,6 @@ TEST_P(RobustResourceInitTest, SurfaceInitializedAfterSwap)
TEST_P(RobustResourceInitTestES31, Multisample2DTexture)
{
ANGLE_SKIP_TEST_IF(!hasGLExtension());
// http://anglebug.com/4092
ANGLE_SKIP_TEST_IF(IsVulkan());
GLTexture texture;
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texture);
......
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