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, ...@@ -2202,8 +2202,8 @@ angle::Result BufferHelper::init(Context *context,
// Can map the memory. // Can map the memory.
// Pick an arbitrary value to initialize non-zero memory for sanitization. // Pick an arbitrary value to initialize non-zero memory for sanitization.
constexpr int kNonZeroInitValue = 55; constexpr int kNonZeroInitValue = 55;
ANGLE_TRY(InitMappableAllocation(allocator, &mAllocation, mSize, kNonZeroInitValue, ANGLE_TRY(InitMappableAllocation(context, allocator, &mAllocation, mSize,
mMemoryPropertyFlags)); kNonZeroInitValue, mMemoryPropertyFlags));
} }
} }
...@@ -2608,9 +2608,8 @@ void ImageHelper::resetImageWeakReference() ...@@ -2608,9 +2608,8 @@ void ImageHelper::resetImageWeakReference()
angle::Result ImageHelper::initializeNonZeroMemory(Context *context, VkDeviceSize size) angle::Result ImageHelper::initializeNonZeroMemory(Context *context, VkDeviceSize size)
{ {
// The staging buffer memory is non-zero-initialized in 'init'. const angle::Format &angleFormat = mFormat->actualImageFormat();
vk::StagingBuffer stagingBuffer; bool isCompressedFormat = angleFormat.isBlock;
ANGLE_TRY(stagingBuffer.init(context, size, vk::StagingUsage::Write));
RendererVk *renderer = context->getRenderer(); RendererVk *renderer = context->getRenderer();
...@@ -2621,13 +2620,78 @@ angle::Result ImageHelper::initializeNonZeroMemory(Context *context, VkDeviceSiz ...@@ -2621,13 +2620,78 @@ angle::Result ImageHelper::initializeNonZeroMemory(Context *context, VkDeviceSiz
forceChangeLayoutAndQueue(getAspectFlags(), ImageLayout::TransferDst, mCurrentQueueFamilyIndex, forceChangeLayoutAndQueue(getAspectFlags(), ImageLayout::TransferDst, mCurrentQueueFamilyIndex,
&commandBuffer); &commandBuffer);
VkBufferImageCopy copyRegion = {}; vk::StagingBuffer stagingBuffer;
copyRegion.imageExtent = mExtents;
copyRegion.imageSubresource.aspectMask = getAspectFlags(); if (isCompressedFormat)
copyRegion.imageSubresource.layerCount = 1; {
// 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, commandBuffer.clearColorImage(mImage, getCurrentLayout(), clearValue, 1, &subresource);
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copyRegion); }
else
{
VkClearDepthStencilValue clearValue;
clearValue.depth = kInitValueFloat;
clearValue.stencil = kInitValue;
commandBuffer.clearDepthStencilImage(mImage, getCurrentLayout(), clearValue, 1,
&subresource);
}
}
ANGLE_VK_TRY(context, commandBuffer.end()); ANGLE_VK_TRY(context, commandBuffer.end());
...@@ -2635,7 +2699,10 @@ angle::Result ImageHelper::initializeNonZeroMemory(Context *context, VkDeviceSiz ...@@ -2635,7 +2699,10 @@ angle::Result ImageHelper::initializeNonZeroMemory(Context *context, VkDeviceSiz
ANGLE_TRY(renderer->queueSubmitOneOff(context, std::move(commandBuffer), ANGLE_TRY(renderer->queueSubmitOneOff(context, std::move(commandBuffer),
egl::ContextPriority::Medium, nullptr, &serial)); egl::ContextPriority::Medium, nullptr, &serial));
stagingBuffer.collectGarbage(renderer, serial); if (isCompressedFormat)
{
stagingBuffer.collectGarbage(renderer, serial);
}
mUse.updateSerialOneOff(serial); mUse.updateSerialOneOff(serial);
return angle::Result::Continue; return angle::Result::Continue;
...@@ -2656,16 +2723,7 @@ angle::Result ImageHelper::initMemory(Context *context, ...@@ -2656,16 +2723,7 @@ angle::Result ImageHelper::initMemory(Context *context,
// Can't map the memory. Use a staging resource. // Can't map the memory. Use a staging resource.
if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
{ {
// Only currently works with single-sampled color images with one mip/layer. ANGLE_TRY(initializeNonZeroMemory(context, size));
if (mLevelCount == 1 && mLayerCount == 1 &&
getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT && mSamples == 1)
{
ANGLE_TRY(initializeNonZeroMemory(context, size));
}
else
{
UNIMPLEMENTED();
}
} }
} }
...@@ -2882,8 +2940,9 @@ gl::Extents ImageHelper::getLevelExtents(uint32_t level) const ...@@ -2882,8 +2940,9 @@ gl::Extents ImageHelper::getLevelExtents(uint32_t level) const
// you shrink the extents by half. // you shrink the extents by half.
uint32_t width = std::max(mExtents.width >> level, 1u); uint32_t width = std::max(mExtents.width >> level, 1u);
uint32_t height = std::max(mExtents.height >> 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 gl::Extents ImageHelper::getLevelExtents2D(uint32_t level) const
......
...@@ -36,6 +36,10 @@ namespace rx ...@@ -36,6 +36,10 @@ namespace rx
{ {
namespace 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) VkImageUsageFlags GetStagingBufferUsageFlags(vk::StagingUsage usage)
{ {
switch (usage) switch (usage)
...@@ -60,9 +64,6 @@ angle::Result FindAndAllocateCompatibleMemory(vk::Context *context, ...@@ -60,9 +64,6 @@ angle::Result FindAndAllocateCompatibleMemory(vk::Context *context,
const void *extraAllocationInfo, const void *extraAllocationInfo,
vk::DeviceMemory *deviceMemoryOut) vk::DeviceMemory *deviceMemoryOut)
{ {
// Pick an arbitrary value to initialize non-zero memory for sanitization.
constexpr int kNonZeroInitValue = 55;
VkDevice device = context->getDevice(); VkDevice device = context->getDevice();
uint32_t memoryTypeIndex = 0; uint32_t memoryTypeIndex = 0;
...@@ -422,6 +423,15 @@ angle::Result StagingBuffer::init(Context *context, VkDeviceSize size, StagingUs ...@@ -422,6 +423,15 @@ angle::Result StagingBuffer::init(Context *context, VkDeviceSize size, StagingUs
renderer->getFeatures().persistentlyMappedBuffers.enabled, renderer->getFeatures().persistentlyMappedBuffers.enabled,
&memoryTypeIndex, &mBuffer, &mAllocation)); &memoryTypeIndex, &mBuffer, &mAllocation));
mSize = static_cast<size_t>(size); 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; return angle::Result::Continue;
} }
...@@ -443,14 +453,15 @@ void StagingBuffer::collectGarbage(RendererVk *renderer, Serial serial) ...@@ -443,14 +453,15 @@ void StagingBuffer::collectGarbage(RendererVk *renderer, Serial serial)
renderer->collectGarbage(std::move(sharedUse), std::move(garbageList)); 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, Allocation *allocation,
VkDeviceSize size, VkDeviceSize size,
int value, int value,
VkMemoryPropertyFlags memoryPropertyFlags) VkMemoryPropertyFlags memoryPropertyFlags)
{ {
uint8_t *mapPointer; uint8_t *mapPointer;
allocation->map(allocator, &mapPointer); ANGLE_VK_TRY(context, allocation->map(allocator, &mapPointer));
memset(mapPointer, value, static_cast<size_t>(size)); memset(mapPointer, value, static_cast<size_t>(size));
if ((memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0) if ((memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0)
......
...@@ -323,13 +323,14 @@ class StagingBuffer final : angle::NonCopyable ...@@ -323,13 +323,14 @@ class StagingBuffer final : angle::NonCopyable
size_t mSize; size_t mSize;
}; };
angle::Result InitMappableAllocation(const vk::Allocator &allocator, angle::Result InitMappableAllocation(Context *context,
const vk::Allocator &allocator,
Allocation *allocation, Allocation *allocation,
VkDeviceSize size, VkDeviceSize size,
int value, int value,
VkMemoryPropertyFlags memoryPropertyFlags); VkMemoryPropertyFlags memoryPropertyFlags);
angle::Result InitMappableDeviceMemory(vk::Context *context, angle::Result InitMappableDeviceMemory(Context *context,
vk::DeviceMemory *deviceMemory, vk::DeviceMemory *deviceMemory,
VkDeviceSize size, VkDeviceSize size,
int value, int value,
......
...@@ -1879,8 +1879,6 @@ TEST_P(RobustResourceInitTest, SurfaceInitializedAfterSwap) ...@@ -1879,8 +1879,6 @@ TEST_P(RobustResourceInitTest, SurfaceInitializedAfterSwap)
TEST_P(RobustResourceInitTestES31, Multisample2DTexture) TEST_P(RobustResourceInitTestES31, Multisample2DTexture)
{ {
ANGLE_SKIP_TEST_IF(!hasGLExtension()); ANGLE_SKIP_TEST_IF(!hasGLExtension());
// http://anglebug.com/4092
ANGLE_SKIP_TEST_IF(IsVulkan());
GLTexture texture; GLTexture texture;
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 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