Vulkan: clear nonrenderable texture color formats
Clears nonrenderable color formats and adds a clearValue enum to help
share the code path between zero and nonzero clears.
Bug: dawn:145
Change-Id: I285521cae0ee71625602b949888b21481a05fb8e
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/10021
Commit-Queue: Natasha Lee <natlee@microsoft.com>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
diff --git a/src/dawn_native/Texture.h b/src/dawn_native/Texture.h
index 066a7d7..e5c59ee 100644
--- a/src/dawn_native/Texture.h
+++ b/src/dawn_native/Texture.h
@@ -43,7 +43,7 @@
class TextureBase : public ObjectBase {
public:
enum class TextureState { OwnedInternal, OwnedExternal, Destroyed };
-
+ enum class ClearValue { Zero, NonZero };
TextureBase(DeviceBase* device, const TextureDescriptor* descriptor, TextureState state);
static TextureBase* MakeError(DeviceBase* device);
diff --git a/src/dawn_native/vulkan/CommandBufferVk.cpp b/src/dawn_native/vulkan/CommandBufferVk.cpp
index 7b1c7fe..bc25ea2 100644
--- a/src/dawn_native/vulkan/CommandBufferVk.cpp
+++ b/src/dawn_native/vulkan/CommandBufferVk.cpp
@@ -27,6 +27,7 @@
#include "dawn_native/vulkan/RenderPassCache.h"
#include "dawn_native/vulkan/RenderPipelineVk.h"
#include "dawn_native/vulkan/TextureVk.h"
+#include "dawn_native/vulkan/UtilsVulkan.h"
namespace dawn_native { namespace vulkan {
@@ -43,59 +44,6 @@
}
}
- // Vulkan SPEC requires the source/destination region specified by each element of
- // pRegions must be a region that is contained within srcImage/dstImage. Here the size of
- // the image refers to the virtual size, while Dawn validates texture copy extent with the
- // physical size, so we need to re-calculate the texture copy extent to ensure it should fit
- // in the virtual size of the subresource.
- Extent3D ComputeTextureCopyExtent(const TextureCopy& textureCopy,
- const Extent3D& copySize) {
- Extent3D validTextureCopyExtent = copySize;
- const TextureBase* texture = textureCopy.texture.Get();
- Extent3D virtualSizeAtLevel = texture->GetMipLevelVirtualSize(textureCopy.mipLevel);
- if (textureCopy.origin.x + copySize.width > virtualSizeAtLevel.width) {
- ASSERT(texture->GetFormat().isCompressed);
- validTextureCopyExtent.width = virtualSizeAtLevel.width - textureCopy.origin.x;
- }
- if (textureCopy.origin.y + copySize.height > virtualSizeAtLevel.height) {
- ASSERT(texture->GetFormat().isCompressed);
- validTextureCopyExtent.height = virtualSizeAtLevel.height - textureCopy.origin.y;
- }
-
- return validTextureCopyExtent;
- }
-
- VkBufferImageCopy ComputeBufferImageCopyRegion(const BufferCopy& bufferCopy,
- const TextureCopy& textureCopy,
- const Extent3D& copySize) {
- const Texture* texture = ToBackend(textureCopy.texture.Get());
-
- VkBufferImageCopy region;
-
- region.bufferOffset = bufferCopy.offset;
- // In Vulkan the row length is in texels while it is in bytes for Dawn
- const Format& format = texture->GetFormat();
- ASSERT(bufferCopy.rowPitch % format.blockByteSize == 0);
- region.bufferRowLength = bufferCopy.rowPitch / format.blockByteSize * format.blockWidth;
- region.bufferImageHeight = bufferCopy.imageHeight;
-
- region.imageSubresource.aspectMask = texture->GetVkAspectMask();
- region.imageSubresource.mipLevel = textureCopy.mipLevel;
- region.imageSubresource.baseArrayLayer = textureCopy.arrayLayer;
- region.imageSubresource.layerCount = 1;
-
- region.imageOffset.x = textureCopy.origin.x;
- region.imageOffset.y = textureCopy.origin.y;
- region.imageOffset.z = textureCopy.origin.z;
-
- Extent3D imageExtent = ComputeTextureCopyExtent(textureCopy, copySize);
- region.imageExtent.width = imageExtent.width;
- region.imageExtent.height = imageExtent.height;
- region.imageExtent.depth = copySize.depth;
-
- return region;
- }
-
VkImageCopy ComputeImageCopyRegion(const TextureCopy& srcCopy,
const TextureCopy& dstCopy,
const Extent3D& copySize) {
diff --git a/src/dawn_native/vulkan/TextureVk.cpp b/src/dawn_native/vulkan/TextureVk.cpp
index ad21992..fc2e031 100644
--- a/src/dawn_native/vulkan/TextureVk.cpp
+++ b/src/dawn_native/vulkan/TextureVk.cpp
@@ -16,9 +16,11 @@
#include "dawn_native/VulkanBackend.h"
#include "dawn_native/vulkan/AdapterVk.h"
+#include "dawn_native/vulkan/BufferVk.h"
#include "dawn_native/vulkan/CommandRecordingContext.h"
#include "dawn_native/vulkan/DeviceVk.h"
#include "dawn_native/vulkan/FencedDeleter.h"
+#include "dawn_native/vulkan/UtilsVulkan.h"
namespace dawn_native { namespace vulkan {
@@ -453,33 +455,8 @@
ASSERT(false);
}
if (device->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) {
- VkImageSubresourceRange range = {};
- range.aspectMask = GetVkAspectMask();
- range.baseMipLevel = 0;
- range.levelCount = GetNumMipLevels();
- range.baseArrayLayer = 0;
- range.layerCount = GetArrayLayers();
- TransitionUsageNow(ToBackend(GetDevice())->GetPendingRecordingContext(),
- dawn::TextureUsageBit::CopyDst);
-
- if (GetFormat().HasDepthOrStencil()) {
- VkClearDepthStencilValue clear_color[1];
- clear_color[0].depth = 1.0f;
- clear_color[0].stencil = 1u;
- ToBackend(GetDevice())
- ->fn.CmdClearDepthStencilImage(
- ToBackend(GetDevice())->GetPendingCommandBuffer(), GetHandle(),
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, clear_color, 1, &range);
- } else {
- // TODO(natlee@microsoft.com): use correct union member depending on the texture
- // format
- VkClearColorValue clear_color = {{1.0, 1.0, 1.0, 1.0}};
-
- ToBackend(GetDevice())
- ->fn.CmdClearColorImage(ToBackend(GetDevice())->GetPendingCommandBuffer(),
- GetHandle(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- &clear_color, 1, &range);
- }
+ ClearTexture(ToBackend(GetDevice())->GetPendingRecordingContext(), 0, GetNumMipLevels(),
+ 0, GetArrayLayers(), TextureBase::ClearValue::NonZero);
}
}
@@ -679,36 +656,80 @@
uint32_t baseMipLevel,
uint32_t levelCount,
uint32_t baseArrayLayer,
- uint32_t layerCount) {
+ uint32_t layerCount,
+ TextureBase::ClearValue clearValue) {
VkImageSubresourceRange range = {};
range.aspectMask = GetVkAspectMask();
range.baseMipLevel = baseMipLevel;
range.levelCount = levelCount;
range.baseArrayLayer = baseArrayLayer;
range.layerCount = layerCount;
+ uint8_t clearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0 : 1;
TransitionUsageNow(recordingContext, dawn::TextureUsageBit::CopyDst);
if (GetFormat().HasDepthOrStencil()) {
- VkClearDepthStencilValue clear_color[1];
- clear_color[0].depth = 0.0f;
- clear_color[0].stencil = 0u;
+ VkClearDepthStencilValue clearDepthStencilValue[1];
+ clearDepthStencilValue[0].depth = clearColor;
+ clearDepthStencilValue[0].stencil = clearColor;
ToBackend(GetDevice())
->fn.CmdClearDepthStencilImage(recordingContext->commandBuffer, GetHandle(),
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, clear_color, 1,
- &range);
- } else {
- VkClearColorValue clear_color[1];
- clear_color[0].float32[0] = 0.0f;
- clear_color[0].float32[1] = 0.0f;
- clear_color[0].float32[2] = 0.0f;
- clear_color[0].float32[3] = 0.0f;
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ clearDepthStencilValue, 1, &range);
+ } else if (GetFormat().isRenderable) {
+ VkClearColorValue clearColorValue = {{clearColor, clearColor, clearColor, clearColor}};
ToBackend(GetDevice())
->fn.CmdClearColorImage(recordingContext->commandBuffer, GetHandle(),
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, clear_color, 1,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColorValue, 1,
&range);
+ } else {
+ // TODO(natlee@microsoft.com): test compressed textures are cleared
+ // create temp buffer with clear color to copy to the texture image
+ dawn_native::vulkan::Device* device =
+ reinterpret_cast<dawn_native::vulkan::Device*>(GetDevice());
+ dawn_native::BufferDescriptor descriptor;
+ descriptor.size = (GetSize().width / GetFormat().blockWidth) *
+ (GetSize().height / GetFormat().blockHeight) *
+ GetFormat().blockByteSize;
+ descriptor.nextInChain = nullptr;
+ descriptor.usage = dawn::BufferUsageBit::CopySrc | dawn::BufferUsageBit::MapWrite;
+ std::unique_ptr<Buffer> srcBuffer =
+ std::make_unique<dawn_native::vulkan::Buffer>(device, &descriptor);
+ uint8_t* clearBuffer = nullptr;
+ device->ConsumedError(srcBuffer->MapAtCreation(&clearBuffer));
+ std::fill(reinterpret_cast<uint32_t*>(clearBuffer),
+ reinterpret_cast<uint32_t*>(clearBuffer + descriptor.size), clearColor);
+
+ // compute the buffer image copy to set the clear region of entire texture
+ dawn_native::BufferCopy bufferCopy;
+ bufferCopy.buffer = srcBuffer.get();
+ bufferCopy.imageHeight = 0;
+ bufferCopy.offset = 0;
+ bufferCopy.rowPitch = 0;
+
+ dawn_native::TextureCopy textureCopy;
+ textureCopy.texture = this;
+ textureCopy.origin = {0, 0, 0};
+ textureCopy.mipLevel = baseMipLevel;
+ textureCopy.arrayLayer = baseArrayLayer;
+
+ Extent3D copySize = {GetSize().width, GetSize().height, 1};
+
+ VkBufferImageCopy region =
+ ComputeBufferImageCopyRegion(bufferCopy, textureCopy, copySize);
+
+ // copy the clear buffer to the texture image
+ srcBuffer->TransitionUsageNow(recordingContext, dawn::BufferUsageBit::CopySrc);
+ ToBackend(GetDevice())
+ ->fn.CmdCopyBufferToImage(recordingContext->commandBuffer, srcBuffer->GetHandle(),
+ GetHandle(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1,
+ ®ion);
}
- SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer, layerCount);
- GetDevice()->IncrementLazyClearCountForTesting();
+
+ if (clearValue == TextureBase::ClearValue::Zero) {
+ SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer,
+ layerCount);
+ GetDevice()->IncrementLazyClearCountForTesting();
+ }
}
void Texture::EnsureSubresourceContentInitialized(CommandRecordingContext* recordingContext,
@@ -729,7 +750,8 @@
// If subresource has not been initialized, clear it to black as it could contain dirty
// bits from recycled memory
- ClearTexture(recordingContext, baseMipLevel, levelCount, baseArrayLayer, layerCount);
+ ClearTexture(recordingContext, baseMipLevel, levelCount, baseArrayLayer, layerCount,
+ TextureBase::ClearValue::Zero);
}
}
diff --git a/src/dawn_native/vulkan/TextureVk.h b/src/dawn_native/vulkan/TextureVk.h
index 52236d3..75f7a54 100644
--- a/src/dawn_native/vulkan/TextureVk.h
+++ b/src/dawn_native/vulkan/TextureVk.h
@@ -75,7 +75,8 @@
uint32_t baseMipLevel,
uint32_t levelCount,
uint32_t baseArrayLayer,
- uint32_t layerCount);
+ uint32_t layerCount,
+ TextureBase::ClearValue);
VkImage mHandle = VK_NULL_HANDLE;
DeviceMemoryAllocation mMemoryAllocation;
diff --git a/src/dawn_native/vulkan/UtilsVulkan.cpp b/src/dawn_native/vulkan/UtilsVulkan.cpp
index 723a6bb..dd81f3f 100644
--- a/src/dawn_native/vulkan/UtilsVulkan.cpp
+++ b/src/dawn_native/vulkan/UtilsVulkan.cpp
@@ -15,6 +15,9 @@
#include "dawn_native/vulkan/UtilsVulkan.h"
#include "common/Assert.h"
+#include "dawn_native/Format.h"
+#include "dawn_native/vulkan/Forward.h"
+#include "dawn_native/vulkan/TextureVk.h"
namespace dawn_native { namespace vulkan {
@@ -41,4 +44,55 @@
}
}
+ // Vulkan SPEC requires the source/destination region specified by each element of
+ // pRegions must be a region that is contained within srcImage/dstImage. Here the size of
+ // the image refers to the virtual size, while Dawn validates texture copy extent with the
+ // physical size, so we need to re-calculate the texture copy extent to ensure it should fit
+ // in the virtual size of the subresource.
+ Extent3D ComputeTextureCopyExtent(const TextureCopy& textureCopy, const Extent3D& copySize) {
+ Extent3D validTextureCopyExtent = copySize;
+ const TextureBase* texture = textureCopy.texture.Get();
+ Extent3D virtualSizeAtLevel = texture->GetMipLevelVirtualSize(textureCopy.mipLevel);
+ if (textureCopy.origin.x + copySize.width > virtualSizeAtLevel.width) {
+ ASSERT(texture->GetFormat().isCompressed);
+ validTextureCopyExtent.width = virtualSizeAtLevel.width - textureCopy.origin.x;
+ }
+ if (textureCopy.origin.y + copySize.height > virtualSizeAtLevel.height) {
+ ASSERT(texture->GetFormat().isCompressed);
+ validTextureCopyExtent.height = virtualSizeAtLevel.height - textureCopy.origin.y;
+ }
+
+ return validTextureCopyExtent;
+ }
+
+ VkBufferImageCopy ComputeBufferImageCopyRegion(const BufferCopy& bufferCopy,
+ const TextureCopy& textureCopy,
+ const Extent3D& copySize) {
+ const Texture* texture = ToBackend(textureCopy.texture.Get());
+
+ VkBufferImageCopy region;
+
+ region.bufferOffset = bufferCopy.offset;
+ // In Vulkan the row length is in texels while it is in bytes for Dawn
+ const Format& format = texture->GetFormat();
+ ASSERT(bufferCopy.rowPitch % format.blockByteSize == 0);
+ region.bufferRowLength = bufferCopy.rowPitch / format.blockByteSize * format.blockWidth;
+ region.bufferImageHeight = bufferCopy.imageHeight;
+
+ region.imageSubresource.aspectMask = texture->GetVkAspectMask();
+ region.imageSubresource.mipLevel = textureCopy.mipLevel;
+ region.imageSubresource.baseArrayLayer = textureCopy.arrayLayer;
+ region.imageSubresource.layerCount = 1;
+
+ region.imageOffset.x = textureCopy.origin.x;
+ region.imageOffset.y = textureCopy.origin.y;
+ region.imageOffset.z = textureCopy.origin.z;
+
+ Extent3D imageExtent = ComputeTextureCopyExtent(textureCopy, copySize);
+ region.imageExtent.width = imageExtent.width;
+ region.imageExtent.height = imageExtent.height;
+ region.imageExtent.depth = copySize.depth;
+
+ return region;
+ }
}} // namespace dawn_native::vulkan
diff --git a/src/dawn_native/vulkan/UtilsVulkan.h b/src/dawn_native/vulkan/UtilsVulkan.h
index 80fa2da..8f4b5ac 100644
--- a/src/dawn_native/vulkan/UtilsVulkan.h
+++ b/src/dawn_native/vulkan/UtilsVulkan.h
@@ -16,12 +16,18 @@
#define DAWNNATIVE_VULKAN_UTILSVULKAN_H_
#include "common/vulkan_platform.h"
+#include "dawn_native/Commands.h"
#include "dawn_native/dawn_platform.h"
namespace dawn_native { namespace vulkan {
VkCompareOp ToVulkanCompareOp(dawn::CompareFunction op);
+ Extent3D ComputeTextureCopyExtent(const TextureCopy& textureCopy, const Extent3D& copySize);
+ VkBufferImageCopy ComputeBufferImageCopyRegion(const BufferCopy& bufferCopy,
+ const TextureCopy& textureCopy,
+ const Extent3D& copySize);
+
}} // namespace dawn_native::vulkan
#endif // DAWNNATIVE_VULKAN_UTILSVULKAN_H_