Implement copy for 3D texture on D3D12: non-zero mip

The change implements copy non-zero mip level for 3D textures
on D3D12 when the texture has multiple mip levels. The texture
size on level 0 can be either 256-byte aligned or 256-byte
unaligned(its size is non-power-of-two).

Bug: dawn:547

Change-Id: I8ed74fa587cfd814e7f526173dcb653d0a252a1e
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/51201
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Yunchao He <yunchao.he@intel.com>
This commit is contained in:
Yunchao He 2021-06-09 16:01:08 +00:00 committed by Dawn LUCI CQ
parent aec5b98670
commit e5b9903cc1
4 changed files with 95 additions and 12 deletions

View File

@ -151,8 +151,8 @@ class CopyTests_T2B : public CopyTests {
// Layout for initial data upload to texture. // Layout for initial data upload to texture.
// Some parts of this result are also reused later. // Some parts of this result are also reused later.
const utils::TextureDataCopyLayout copyLayout = const utils::TextureDataCopyLayout copyLayout =
utils::GetTextureDataCopyLayoutForTexture2DAtLevel( utils::GetTextureDataCopyLayoutForTextureAtLevel(
textureSpec.format, textureSpec.textureSize, textureSpec.copyLevel); textureSpec.format, textureSpec.textureSize, textureSpec.copyLevel, dimension);
// Initialize the source texture // Initialize the source texture
std::vector<RGBA8> textureArrayData = GetExpectedTextureDataRGBA8(copyLayout); std::vector<RGBA8> textureArrayData = GetExpectedTextureDataRGBA8(copyLayout);
@ -279,8 +279,8 @@ class CopyTests_B2T : public CopyTests {
queue.Submit(1, &commands); queue.Submit(1, &commands);
const utils::TextureDataCopyLayout copyLayout = const utils::TextureDataCopyLayout copyLayout =
utils::GetTextureDataCopyLayoutForTexture2DAtLevel( utils::GetTextureDataCopyLayoutForTextureAtLevel(
textureSpec.format, textureSpec.textureSize, textureSpec.copyLevel, textureSpec.format, textureSpec.textureSize, textureSpec.copyLevel, dimension,
bufferSpec.rowsPerImage); bufferSpec.rowsPerImage);
uint32_t copyLayer = copySize.depthOrArrayLayers; uint32_t copyLayer = copySize.depthOrArrayLayers;
@ -367,11 +367,11 @@ class CopyTests_T2T : public CopyTests {
// Create an upload buffer and use it to populate the current slice of the texture in // Create an upload buffer and use it to populate the current slice of the texture in
// `level` mip level // `level` mip level
const utils::TextureDataCopyLayout srcDataCopyLayout = const utils::TextureDataCopyLayout srcDataCopyLayout =
utils::GetTextureDataCopyLayoutForTexture2DAtLevel( utils::GetTextureDataCopyLayoutForTextureAtLevel(
format, format,
{srcSpec.textureSize.width, srcSpec.textureSize.height, {srcSpec.textureSize.width, srcSpec.textureSize.height,
copySize.depthOrArrayLayers}, copySize.depthOrArrayLayers},
srcSpec.copyLevel); srcSpec.copyLevel, srcDimension);
// Initialize the source texture // Initialize the source texture
const std::vector<uint8_t> srcTextureCopyData = GetExpectedTextureData(srcDataCopyLayout); const std::vector<uint8_t> srcTextureCopyData = GetExpectedTextureData(srcDataCopyLayout);
@ -397,11 +397,11 @@ class CopyTests_T2T : public CopyTests {
// Copy the data from the srcSpec.copyOrigin.z-th layer to (srcSpec.copyOrigin.z + // Copy the data from the srcSpec.copyOrigin.z-th layer to (srcSpec.copyOrigin.z +
// copySize.depthOrArrayLayers)-th layer of dstTexture to outputBuffer // copySize.depthOrArrayLayers)-th layer of dstTexture to outputBuffer
const utils::TextureDataCopyLayout dstDataCopyLayout = const utils::TextureDataCopyLayout dstDataCopyLayout =
utils::GetTextureDataCopyLayoutForTexture2DAtLevel( utils::GetTextureDataCopyLayoutForTextureAtLevel(
format, format,
{dstSpec.textureSize.width, dstSpec.textureSize.height, {dstSpec.textureSize.width, dstSpec.textureSize.height,
copySize.depthOrArrayLayers}, copySize.depthOrArrayLayers},
dstSpec.copyLevel); dstSpec.copyLevel, dstDimension);
wgpu::BufferDescriptor outputBufferDescriptor; wgpu::BufferDescriptor outputBufferDescriptor;
outputBufferDescriptor.size = dstDataCopyLayout.byteLength; outputBufferDescriptor.size = dstDataCopyLayout.byteLength;
outputBufferDescriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst; outputBufferDescriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
@ -1161,6 +1161,44 @@ TEST_P(CopyTests_T2B, Texture3DCopyHeightIsOneCopyWidthIsSmall) {
DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D); DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D);
} }
// Test that copying texture 3D array mips with 256-byte aligned sizes works
TEST_P(CopyTests_T2B, Texture3DMipAligned) {
constexpr uint32_t kWidth = 256;
constexpr uint32_t kHeight = 128;
constexpr uint32_t kDepth = 64u;
TextureSpec defaultTextureSpec;
defaultTextureSpec.textureSize = {kWidth, kHeight, kDepth};
for (unsigned int i = 1; i < 6; ++i) {
TextureSpec textureSpec = defaultTextureSpec;
textureSpec.copyLevel = i;
textureSpec.levelCount = i + 1;
DoTest(textureSpec, MinimumBufferSpec(kWidth >> i, kHeight >> i, kDepth >> i),
{kWidth >> i, kHeight >> i, kDepth >> i}, wgpu::TextureDimension::e3D);
}
}
// Test that copying texture 3D array mips with 256-byte unaligned sizes works
TEST_P(CopyTests_T2B, Texture3DMipUnaligned) {
constexpr uint32_t kWidth = 261;
constexpr uint32_t kHeight = 123;
constexpr uint32_t kDepth = 69u;
TextureSpec defaultTextureSpec;
defaultTextureSpec.textureSize = {kWidth, kHeight, kDepth};
for (unsigned int i = 1; i < 6; ++i) {
TextureSpec textureSpec = defaultTextureSpec;
textureSpec.copyLevel = i;
textureSpec.levelCount = i + 1;
DoTest(textureSpec, MinimumBufferSpec(kWidth >> i, kHeight >> i, kDepth >> i),
{kWidth >> i, kHeight >> i, kDepth >> i}, wgpu::TextureDimension::e3D);
}
}
// TODO(yunchao.he@intel.com): add T2B tests for 3D textures, like RowPitch, // TODO(yunchao.he@intel.com): add T2B tests for 3D textures, like RowPitch,
// RowsPerImage, buffer offset, partial depth range, non-zero level, etc. // RowsPerImage, buffer offset, partial depth range, non-zero level, etc.
@ -1740,6 +1778,44 @@ TEST_P(CopyTests_B2T, Texture3DCopyHeightIsOneCopyWidthIsSmall) {
DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D); DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kDepth}, wgpu::TextureDimension::e3D);
} }
// Test that copying texture 3D array mips with 256-byte aligned sizes works
TEST_P(CopyTests_B2T, Texture3DMipAligned) {
constexpr uint32_t kWidth = 256;
constexpr uint32_t kHeight = 128;
constexpr uint32_t kDepth = 64u;
TextureSpec defaultTextureSpec;
defaultTextureSpec.textureSize = {kWidth, kHeight, kDepth};
for (unsigned int i = 1; i < 6; ++i) {
TextureSpec textureSpec = defaultTextureSpec;
textureSpec.copyLevel = i;
textureSpec.levelCount = i + 1;
DoTest(textureSpec, MinimumBufferSpec(kWidth >> i, kHeight >> i, kDepth >> i),
{kWidth >> i, kHeight >> i, kDepth >> i}, wgpu::TextureDimension::e3D);
}
}
// Test that copying texture 3D array mips with 256-byte unaligned sizes works
TEST_P(CopyTests_B2T, Texture3DMipUnaligned) {
constexpr uint32_t kWidth = 261;
constexpr uint32_t kHeight = 123;
constexpr uint32_t kDepth = 69u;
TextureSpec defaultTextureSpec;
defaultTextureSpec.textureSize = {kWidth, kHeight, kDepth};
for (unsigned int i = 1; i < 6; ++i) {
TextureSpec textureSpec = defaultTextureSpec;
textureSpec.copyLevel = i;
textureSpec.levelCount = i + 1;
DoTest(textureSpec, MinimumBufferSpec(kWidth >> i, kHeight >> i, kDepth >> i),
{kWidth >> i, kHeight >> i, kDepth >> i}, wgpu::TextureDimension::e3D);
}
}
// TODO(yunchao.he@intel.com): add more tests like RowPitch, RowsPerImage, buffer offset, partial // TODO(yunchao.he@intel.com): add more tests like RowPitch, RowsPerImage, buffer offset, partial
// depth range, non-zero level, etc. // depth range, non-zero level, etc.

View File

@ -247,7 +247,7 @@ class CopyTextureForBrowserTests : public DawnTest {
wgpu::Texture srcTexture = device.CreateTexture(&srcDescriptor); wgpu::Texture srcTexture = device.CreateTexture(&srcDescriptor);
const utils::TextureDataCopyLayout srcCopyLayout = const utils::TextureDataCopyLayout srcCopyLayout =
utils::GetTextureDataCopyLayoutForTexture2DAtLevel( utils::GetTextureDataCopyLayoutForTextureAtLevel(
kTextureFormat, kTextureFormat,
{srcSpec.textureSize.width, srcSpec.textureSize.height, {srcSpec.textureSize.width, srcSpec.textureSize.height,
copySize.depthOrArrayLayers}, copySize.depthOrArrayLayers},
@ -293,7 +293,7 @@ class CopyTextureForBrowserTests : public DawnTest {
if (testSubRectCopy) { if (testSubRectCopy) {
// For subrect copy tests, dst texture use kTextureFormat always. // For subrect copy tests, dst texture use kTextureFormat always.
const utils::TextureDataCopyLayout dstCopyLayout = const utils::TextureDataCopyLayout dstCopyLayout =
utils::GetTextureDataCopyLayoutForTexture2DAtLevel( utils::GetTextureDataCopyLayoutForTextureAtLevel(
kTextureFormat, kTextureFormat,
{dstSpec.textureSize.width, dstSpec.textureSize.height, {dstSpec.textureSize.width, dstSpec.textureSize.height,
copySize.depthOrArrayLayers}, copySize.depthOrArrayLayers},

View File

@ -31,10 +31,11 @@ namespace utils {
return Align(bytesPerBlock * (width / blockWidth), kTextureBytesPerRowAlignment); return Align(bytesPerBlock * (width / blockWidth), kTextureBytesPerRowAlignment);
} }
TextureDataCopyLayout GetTextureDataCopyLayoutForTexture2DAtLevel( TextureDataCopyLayout GetTextureDataCopyLayoutForTextureAtLevel(
wgpu::TextureFormat format, wgpu::TextureFormat format,
wgpu::Extent3D textureSizeAtLevel0, wgpu::Extent3D textureSizeAtLevel0,
uint32_t mipmapLevel, uint32_t mipmapLevel,
wgpu::TextureDimension dimension,
uint32_t rowsPerImage) { uint32_t rowsPerImage) {
// Compressed texture formats not supported in this function yet. // Compressed texture formats not supported in this function yet.
ASSERT(utils::GetTextureFormatBlockWidth(format) == 1); ASSERT(utils::GetTextureFormatBlockWidth(format) == 1);
@ -45,6 +46,11 @@ namespace utils {
std::max(textureSizeAtLevel0.height >> mipmapLevel, 1u), std::max(textureSizeAtLevel0.height >> mipmapLevel, 1u),
textureSizeAtLevel0.depthOrArrayLayers}; textureSizeAtLevel0.depthOrArrayLayers};
if (dimension == wgpu::TextureDimension::e3D) {
layout.mipSize.depthOrArrayLayers =
std::max(textureSizeAtLevel0.depthOrArrayLayers >> mipmapLevel, 1u);
}
layout.bytesPerRow = GetMinimumBytesPerRow(format, layout.mipSize.width); layout.bytesPerRow = GetMinimumBytesPerRow(format, layout.mipSize.width);
if (rowsPerImage == wgpu::kCopyStrideUndefined) { if (rowsPerImage == wgpu::kCopyStrideUndefined) {

View File

@ -31,10 +31,11 @@ namespace utils {
}; };
uint32_t GetMinimumBytesPerRow(wgpu::TextureFormat format, uint32_t width); uint32_t GetMinimumBytesPerRow(wgpu::TextureFormat format, uint32_t width);
TextureDataCopyLayout GetTextureDataCopyLayoutForTexture2DAtLevel( TextureDataCopyLayout GetTextureDataCopyLayoutForTextureAtLevel(
wgpu::TextureFormat format, wgpu::TextureFormat format,
wgpu::Extent3D textureSizeAtLevel0, wgpu::Extent3D textureSizeAtLevel0,
uint32_t mipmapLevel, uint32_t mipmapLevel,
wgpu::TextureDimension dimension = wgpu::TextureDimension::e2D,
uint32_t rowsPerImage = wgpu::kCopyStrideUndefined); uint32_t rowsPerImage = wgpu::kCopyStrideUndefined);
uint64_t RequiredBytesInCopy(uint64_t bytesPerRow, uint64_t RequiredBytesInCopy(uint64_t bytesPerRow,