Support BC5 formats on Vulkan

This patch supports BC5 formats on Vulkan backends and adds related
Dawn end2end tests.

For the textures with BC formats, they could have non-multiple-of-4
sizes on the non-zero mipmap levels in sampling, but we are still
required to provide texture data in complete 4x4 blocks in texture
copies because that is the size of which they are stored in GPU memory.

In this patch, we refer the term "physical memory size" as the memory
size of the texture subresource in GPU memory, and the term "virtual
memory size" as the size used in texture sampling. As Dawn requires
the Extent3D in texture copies must fit in the physical memory size,
while Vulkan requires it must fit in the virtual memory size, this
patch recalculates the imageExtent to ensure it always follow this
Vulkan validation rules.

For Dawn end2end tests, note that we use pure green and pure red for
the textures because BC5 does not support SRGB formats. Furthermore,
"CopyPartofTextureSubResourceIntoNonZeroMipmapLevel" is skipped in
this patch because there is an issue on the T2T copies from a region
within the virtual size of one texture to another one that exceeds
the virtual size of another texture in Vulkan SPEC.

BUG=dawn:42
TEST=dawn_end2end_tests

Change-Id: I17518cd335fb13125cb753bbf879bc06eb20e426
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/8260
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
This commit is contained in:
Jiawei Shao
2019-07-02 23:55:55 +00:00
committed by Commit Bot service account
parent c246494dbf
commit 72508d6d06
11 changed files with 616 additions and 15 deletions

View File

@@ -39,7 +39,7 @@ namespace dawn_native {
bool IsCompleteSubresourceCopiedTo(const TextureBase* texture,
const Extent3D copySize,
const uint32_t mipLevel) {
Extent3D extent = texture->GetMipLevelSize(mipLevel);
Extent3D extent = texture->GetMipLevelPhysicalSize(mipLevel);
if (extent.depth == copySize.depth && extent.width == copySize.width &&
extent.height == copySize.height) {

View File

@@ -47,7 +47,7 @@ namespace dawn_native {
// overflows.
uint64_t level = textureCopy.level;
Extent3D extent = texture->GetMipLevelSize(level);
Extent3D extent = texture->GetMipLevelPhysicalSize(level);
if (uint64_t(textureCopy.origin.x) + uint64_t(copySize.width) >
static_cast<uint64_t>(extent.width) ||

View File

@@ -543,11 +543,16 @@ namespace dawn_native {
return mSampleCount > 1;
}
Extent3D TextureBase::GetMipLevelSize(uint64_t level) const {
Extent3D TextureBase::GetMipLevelVirtualSize(uint64_t level) const {
Extent3D extent;
extent.width = std::max(mSize.width >> level, 1u);
extent.height = std::max(mSize.height >> level, 1u);
extent.depth = std::max(mSize.depth >> level, 1u);
return extent;
}
Extent3D TextureBase::GetMipLevelPhysicalSize(uint64_t level) const {
Extent3D extent = GetMipLevelVirtualSize(level);
// Compressed Textures will have paddings if their width or height is not a multiple of
// 4 at non-zero mipmap levels.

View File

@@ -99,7 +99,13 @@ namespace dawn_native {
bool IsMultisampledTexture() const;
Extent3D GetMipLevelSize(uint64_t level) const;
// For a texture with non-block-compressed texture format, its physical size is always equal
// to its virtual size. For a texture with block compressed texture format, the physical
// size is the one with paddings if necessary, which is always a multiple of the block size
// and used in texture copying. The virtual size is the one without paddings, which is not
// required to be a multiple of the block size and used in texture sampling.
Extent3D GetMipLevelPhysicalSize(uint64_t level) const;
Extent3D GetMipLevelVirtualSize(uint64_t level) const;
// Dawn API
TextureViewBase* CreateDefaultView();

View File

@@ -41,6 +41,28 @@ namespace dawn_native { namespace vulkan {
}
}
// 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.level);
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) {
@@ -50,7 +72,9 @@ namespace dawn_native { namespace vulkan {
region.bufferOffset = bufferCopy.offset;
// In Vulkan the row length is in texels while it is in bytes for Dawn
region.bufferRowLength = bufferCopy.rowPitch / texture->GetFormat().blockByteSize;
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();
@@ -62,8 +86,9 @@ namespace dawn_native { namespace vulkan {
region.imageOffset.y = textureCopy.origin.y;
region.imageOffset.z = textureCopy.origin.z;
region.imageExtent.width = copySize.width;
region.imageExtent.height = copySize.height;
Extent3D imageExtent = ComputeTextureCopyExtent(textureCopy, copySize);
region.imageExtent.width = imageExtent.width;
region.imageExtent.height = imageExtent.height;
region.imageExtent.depth = copySize.depth;
return region;
@@ -95,9 +120,14 @@ namespace dawn_native { namespace vulkan {
region.dstOffset.y = dstCopy.origin.y;
region.dstOffset.z = dstCopy.origin.z;
region.extent.width = copySize.width;
region.extent.height = copySize.height;
region.extent.depth = copySize.depth;
Extent3D imageExtentDst = ComputeTextureCopyExtent(dstCopy, copySize);
// TODO(jiawei.shao@intel.com): add workaround for the case that imageExtentSrc is not
// equal to imageExtentDst. For example when copySize fits in the virtual size of the
// source image but does not fit in the one of the destination image.
Extent3D imageExtent = imageExtentDst;
region.extent.width = imageExtent.width;
region.extent.height = imageExtent.height;
region.extent.depth = imageExtent.depth;
return region;
}

View File

@@ -341,6 +341,9 @@ namespace dawn_native { namespace vulkan {
// Always require imageCubeArray because it is a core Dawn feature
usedKnobs.features.imageCubeArray = VK_TRUE;
// TODO(jiawei.shao@intel.com): support BC formats as extension
usedKnobs.features.textureCompressionBC = VK_TRUE;
// Find a universal queue family
{
constexpr uint32_t kUniversalFlags =

View File

@@ -577,6 +577,12 @@ namespace dawn_native { namespace vulkan {
}
if (!IsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer,
layerCount)) {
// TODO(jiawei.shao@intel.com): initialize textures in BC formats with Buffer-to-Texture
// copies.
if (GetFormat().isCompressed) {
return;
}
// If subresource has not been initialized, clear it to black as it could contain dirty
// bits from recycled memory
ClearTexture(commands, baseMipLevel, levelCount, baseArrayLayer, layerCount);