Commit 6e7d7296 by Alexis Hetu Committed by Commit Bot

Fix clearing compressed textures with Vulkan backend

When making sure a texture's data is initialized in ANGLE, it is illegal to attempt to clear it when using the Vulkan backend. The Vulkan spec, regarding vkCmdClearColorImage, mentions that: "image must not have a compressed or depth/stencil format" The proper way of initializing the memory of a compressed image in Vulkan is to do a buffer to image copy instead. This was added to ImageHelper::stageRobustResourceClear() so that it may now handle compressed textures properly. Bug: angleproject:4092 Change-Id: I073ed0603d9e92e787b9be8992751dbc0c8978db Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2165636Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Commit-Queue: Alexis Hétu <sugoi@chromium.org>
parent d6c7bac9
...@@ -1515,11 +1515,10 @@ angle::Result TextureVk::initializeContents(const gl::Context *context, ...@@ -1515,11 +1515,10 @@ angle::Result TextureVk::initializeContents(const gl::Context *context,
contextVk->getRenderer()->getFormat(desc.format.info->sizedInternalFormat); contextVk->getRenderer()->getFormat(desc.format.info->sizedInternalFormat);
ASSERT(mImage); ASSERT(mImage);
mImage->stageRobustResourceClear(imageIndex, format);
// Note that we cannot ensure the image is initialized because we might be calling subImage // Note that we cannot ensure the image is initialized because we might be calling subImage
// on a non-complete cube map. // on a non-complete cube map.
return angle::Result::Continue; return mImage->stageRobustResourceClear(contextVk, desc.size, imageIndex, format);
} }
void TextureVk::releaseOwnershipOfImage(const gl::Context *context) void TextureVk::releaseOwnershipOfImage(const gl::Context *context)
......
...@@ -2464,7 +2464,7 @@ void ImageHelper::clear(VkImageAspectFlags aspectFlags, ...@@ -2464,7 +2464,7 @@ void ImageHelper::clear(VkImageAspectFlags aspectFlags,
uint32_t layerCount, uint32_t layerCount,
CommandBuffer *commandBuffer) CommandBuffer *commandBuffer)
{ {
const angle::Format &angleFormat = mFormat->intendedFormat(); const angle::Format &angleFormat = mFormat->actualImageFormat();
bool isDepthStencil = angleFormat.depthBits > 0 || angleFormat.stencilBits > 0; bool isDepthStencil = angleFormat.depthBits > 0 || angleFormat.stencilBits > 0;
if (isDepthStencil) if (isDepthStencil)
...@@ -2474,6 +2474,8 @@ void ImageHelper::clear(VkImageAspectFlags aspectFlags, ...@@ -2474,6 +2474,8 @@ void ImageHelper::clear(VkImageAspectFlags aspectFlags,
} }
else else
{ {
ASSERT(!angleFormat.isBlock);
clearColor(value.color, mipLevel, 1, baseArrayLayer, layerCount, commandBuffer); clearColor(value.color, mipLevel, 1, baseArrayLayer, layerCount, commandBuffer);
} }
} }
...@@ -3119,14 +3121,54 @@ void ImageHelper::stageSubresourceClear(const gl::ImageIndex &index) ...@@ -3119,14 +3121,54 @@ void ImageHelper::stageSubresourceClear(const gl::ImageIndex &index)
appendSubresourceUpdate(SubresourceUpdate(aspectFlags, clearValue, index)); appendSubresourceUpdate(SubresourceUpdate(aspectFlags, clearValue, index));
} }
void ImageHelper::stageRobustResourceClear(const gl::ImageIndex &index, const vk::Format &format) angle::Result ImageHelper::stageRobustResourceClear(ContextVk *contextVk,
const gl::Extents &glExtents,
const gl::ImageIndex &index,
const vk::Format &format)
{ {
const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(format.actualImageFormat()); const angle::Format &imageFormat = format.actualImageFormat();
const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(imageFormat);
// Robust clears must only be staged if we do not have any prior data for this subresource. // Robust clears must only be staged if we do not have any prior data for this subresource.
ASSERT(!isUpdateStaged(index.getLevelIndex(), index.getLayerIndex())); ASSERT(!isUpdateStaged(index.getLevelIndex(), index.getLayerIndex()));
VkClearValue clearValue = GetClearValue(format); VkClearValue clearValue = GetClearValue(format);
appendSubresourceUpdate(SubresourceUpdate(aspectFlags, clearValue, index));
if (imageFormat.isBlock)
{
// This only supports doing an initial clear to 0, not clearing to a specific encoded RGBA
// value
ASSERT((clearValue.color.int32[0] == 0) && (clearValue.color.int32[1] == 0) &&
(clearValue.color.int32[2] == 0) && (clearValue.color.int32[3] == 0));
const gl::InternalFormat &formatInfo =
gl::GetSizedInternalFormatInfo(imageFormat.glInternalFormat);
GLuint totalSize;
ANGLE_VK_CHECK_MATH(contextVk,
formatInfo.computeCompressedImageSize(glExtents, &totalSize));
VkBuffer bufferHandle = VK_NULL_HANDLE;
uint8_t *stagingPointer = nullptr;
VkDeviceSize stagingOffset = 0;
ANGLE_TRY(mStagingBuffer.allocate(contextVk, totalSize, &stagingPointer, &bufferHandle,
&stagingOffset, nullptr));
memset(stagingPointer, 0, totalSize);
VkBufferImageCopy copyRegion = {};
copyRegion.imageExtent.width = glExtents.width;
copyRegion.imageExtent.height = glExtents.height;
copyRegion.imageExtent.depth = glExtents.depth;
copyRegion.imageSubresource.aspectMask = aspectFlags;
copyRegion.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
copyRegion.imageSubresource.layerCount = index.getLayerCount();
appendSubresourceUpdate(SubresourceUpdate(mStagingBuffer.getCurrentBuffer(), copyRegion));
}
else
{
appendSubresourceUpdate(SubresourceUpdate(aspectFlags, clearValue, index));
}
return angle::Result::Continue;
} }
void ImageHelper::stageClearIfEmulatedFormat(Context *context) void ImageHelper::stageClearIfEmulatedFormat(Context *context)
......
...@@ -918,7 +918,10 @@ class ImageHelper final : public Resource, public angle::Subject ...@@ -918,7 +918,10 @@ class ImageHelper final : public Resource, public angle::Subject
const VkImageType imageType); const VkImageType imageType);
// Stage a clear based on robust resource init. // Stage a clear based on robust resource init.
void stageRobustResourceClear(const gl::ImageIndex &index, const vk::Format &format); angle::Result stageRobustResourceClear(ContextVk *contextVk,
const gl::Extents &glExtents,
const gl::ImageIndex &index,
const vk::Format &format);
void stageSubresourceClear(const gl::ImageIndex &index); void stageSubresourceClear(const gl::ImageIndex &index);
// This will use the underlying dynamic buffer to allocate some memory to be used as a src or // This will use the underlying dynamic buffer to allocate some memory to be used as a src or
......
...@@ -1686,8 +1686,6 @@ TEST_P(RobustResourceInitTestES3, CompressedSubImage) ...@@ -1686,8 +1686,6 @@ TEST_P(RobustResourceInitTestES3, CompressedSubImage)
{ {
ANGLE_SKIP_TEST_IF(!hasGLExtension()); ANGLE_SKIP_TEST_IF(!hasGLExtension());
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_dxt1")); ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_dxt1"));
// http://anglebug.com/4092
ANGLE_SKIP_TEST_IF(IsVulkan());
constexpr int width = 8; constexpr int width = 8;
constexpr int height = 8; constexpr int height = 8;
......
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