Added validation tests for copying to 2d-array textures
Added validation tests for CommandEncoder::CopyB2T, CommandEncoder::CopyT2B and Queue::WriteTexture which involve copying or writing to multiple layers of a 2d-array texture. Bug: dawn:483 Change-Id: I23f580dff86cd2512a94b41c9c0ce795122a045e Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/24443 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org> Commit-Queue: Tomek Ponitka <tommek@google.com>
This commit is contained in:
parent
dab10eae8a
commit
c98988de11
|
@ -16,6 +16,7 @@
|
|||
#include "common/Constants.h"
|
||||
#include "common/Math.h"
|
||||
#include "tests/unittests/validation/ValidationTest.h"
|
||||
#include "utils/TextureFormatUtils.h"
|
||||
#include "utils/WGPUHelpers.h"
|
||||
|
||||
class CopyCommandTest : public ValidationTest {
|
||||
|
@ -53,7 +54,7 @@ class CopyCommandTest : public ValidationTest {
|
|||
uint32_t height,
|
||||
uint32_t depth,
|
||||
wgpu::TextureFormat format = wgpu::TextureFormat::RGBA8Unorm) {
|
||||
uint32_t bytesPerPixel = utils::TextureFormatPixelSize(format);
|
||||
uint32_t bytesPerPixel = utils::GetTexelBlockSizeInBytes(format);
|
||||
uint32_t bytesPerRow = Align(width * bytesPerPixel, kTextureBytesPerRowAlignment);
|
||||
return (bytesPerRow * (height - 1) + width * bytesPerPixel) * depth;
|
||||
}
|
||||
|
@ -124,6 +125,55 @@ class CopyCommandTest : public ValidationTest {
|
|||
|
||||
ValidateExpectation(encoder, expectation);
|
||||
}
|
||||
|
||||
void TestBothTBCopies(utils::Expectation expectation,
|
||||
wgpu::Buffer buffer,
|
||||
uint64_t bufferOffset,
|
||||
uint32_t bufferBytesPerRow,
|
||||
uint32_t rowsPerImage,
|
||||
wgpu::Texture texture,
|
||||
uint32_t level,
|
||||
wgpu::Origin3D origin,
|
||||
wgpu::Extent3D extent3D) {
|
||||
TestB2TCopy(expectation, buffer, bufferOffset, bufferBytesPerRow, rowsPerImage, texture,
|
||||
level, origin, extent3D);
|
||||
TestT2BCopy(expectation, texture, level, origin, buffer, bufferOffset, bufferBytesPerRow,
|
||||
rowsPerImage, extent3D);
|
||||
}
|
||||
|
||||
void TestBothT2TCopies(utils::Expectation expectation,
|
||||
wgpu::Texture texture1,
|
||||
uint32_t level1,
|
||||
wgpu::Origin3D origin1,
|
||||
wgpu::Texture texture2,
|
||||
uint32_t level2,
|
||||
wgpu::Origin3D origin2,
|
||||
wgpu::Extent3D extent3D) {
|
||||
TestT2TCopy(expectation, texture1, level1, origin1, texture2, level2, origin2, extent3D);
|
||||
TestT2TCopy(expectation, texture2, level2, origin2, texture1, level1, origin1, extent3D);
|
||||
}
|
||||
|
||||
void TestBothTBCopiesExactBufferSize(uint32_t bufferBytesPerRow,
|
||||
uint32_t rowsPerImage,
|
||||
wgpu::Texture texture,
|
||||
wgpu::TextureFormat textureFormat,
|
||||
wgpu::Origin3D origin,
|
||||
wgpu::Extent3D extent3D) {
|
||||
// Check the minimal valid bufferSize.
|
||||
uint64_t bufferSize =
|
||||
utils::RequiredBytesInCopy(bufferBytesPerRow, rowsPerImage, extent3D, textureFormat);
|
||||
wgpu::Buffer source =
|
||||
CreateBuffer(bufferSize, wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst);
|
||||
TestBothTBCopies(utils::Expectation::Success, source, 0, bufferBytesPerRow, rowsPerImage,
|
||||
texture, 0, origin, extent3D);
|
||||
|
||||
// Check bufferSize was indeed minimal.
|
||||
uint64_t invalidSize = bufferSize - 1;
|
||||
wgpu::Buffer invalidSource =
|
||||
CreateBuffer(invalidSize, wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst);
|
||||
TestBothTBCopies(utils::Expectation::Failure, invalidSource, 0, bufferBytesPerRow,
|
||||
rowsPerImage, texture, 0, origin, extent3D);
|
||||
}
|
||||
};
|
||||
|
||||
class CopyCommandTest_B2B : public CopyCommandTest {};
|
||||
|
@ -1344,33 +1394,6 @@ class CopyCommandTest_CompressedTextureFormats : public CopyCommandTest {
|
|||
kUsage, 1);
|
||||
}
|
||||
|
||||
void TestBothTBCopies(utils::Expectation expectation,
|
||||
wgpu::Buffer buffer,
|
||||
uint64_t bufferOffset,
|
||||
uint32_t bufferBytesPerRow,
|
||||
uint32_t rowsPerImage,
|
||||
wgpu::Texture texture,
|
||||
uint32_t level,
|
||||
wgpu::Origin3D origin,
|
||||
wgpu::Extent3D extent3D) {
|
||||
TestB2TCopy(expectation, buffer, bufferOffset, bufferBytesPerRow, rowsPerImage, texture,
|
||||
level, origin, extent3D);
|
||||
TestT2BCopy(expectation, texture, level, origin, buffer, bufferOffset, bufferBytesPerRow,
|
||||
rowsPerImage, extent3D);
|
||||
}
|
||||
|
||||
void TestBothT2TCopies(utils::Expectation expectation,
|
||||
wgpu::Texture texture1,
|
||||
uint32_t level1,
|
||||
wgpu::Origin3D origin1,
|
||||
wgpu::Texture texture2,
|
||||
uint32_t level2,
|
||||
wgpu::Origin3D origin2,
|
||||
wgpu::Extent3D extent3D) {
|
||||
TestT2TCopy(expectation, texture1, level1, origin1, texture2, level2, origin2, extent3D);
|
||||
TestT2TCopy(expectation, texture2, level2, origin2, texture1, level1, origin1, extent3D);
|
||||
}
|
||||
|
||||
static constexpr uint32_t kWidth = 16;
|
||||
static constexpr uint32_t kHeight = 16;
|
||||
};
|
||||
|
@ -1386,14 +1409,14 @@ TEST_F(CopyCommandTest_CompressedTextureFormats, BufferOffset) {
|
|||
|
||||
// Valid usages of BufferOffset in B2T and T2B copies with compressed texture formats.
|
||||
{
|
||||
uint32_t validBufferOffset = utils::CompressedFormatBlockSizeInBytes(bcFormat);
|
||||
uint32_t validBufferOffset = utils::GetTexelBlockSizeInBytes(bcFormat);
|
||||
TestBothTBCopies(utils::Expectation::Success, buffer, validBufferOffset, 256, 4,
|
||||
texture, 0, {0, 0, 0}, {4, 4, 1});
|
||||
}
|
||||
|
||||
// Failures on invalid bufferOffset.
|
||||
{
|
||||
uint32_t kInvalidBufferOffset = utils::CompressedFormatBlockSizeInBytes(bcFormat) / 2;
|
||||
uint32_t kInvalidBufferOffset = utils::GetTexelBlockSizeInBytes(bcFormat) / 2;
|
||||
TestBothTBCopies(utils::Expectation::Failure, buffer, kInvalidBufferOffset, 256, 4,
|
||||
texture, 0, {0, 0, 0}, {4, 4, 1});
|
||||
}
|
||||
|
@ -1426,7 +1449,7 @@ TEST_F(CopyCommandTest_CompressedTextureFormats, BytesPerRow) {
|
|||
for (wgpu::TextureFormat bcFormat : utils::kBCFormats) {
|
||||
wgpu::Texture texture = Create2DTexture(bcFormat, 1, kTestWidth, kTestHeight);
|
||||
uint32_t inValidBytesPerRow =
|
||||
kTestWidth / 4 * utils::CompressedFormatBlockSizeInBytes(bcFormat);
|
||||
kTestWidth / 4 * utils::GetTexelBlockSizeInBytes(bcFormat);
|
||||
ASSERT_NE(0u, inValidBytesPerRow % 256);
|
||||
TestBothTBCopies(utils::Expectation::Failure, buffer, 0, inValidBytesPerRow, 4,
|
||||
texture, 0, {0, 0, 0}, {kTestWidth, 4, 1});
|
||||
|
@ -1438,7 +1461,7 @@ TEST_F(CopyCommandTest_CompressedTextureFormats, BytesPerRow) {
|
|||
for (wgpu::TextureFormat bcFormat : utils::kBCFormats) {
|
||||
wgpu::Texture texture = Create2DTexture(bcFormat, 1, kTestWidth, kTestHeight);
|
||||
uint32_t smallestValidBytesPerRow =
|
||||
Align(kTestWidth / 4 * utils::CompressedFormatBlockSizeInBytes(bcFormat), 256);
|
||||
Align(kTestWidth / 4 * utils::GetTexelBlockSizeInBytes(bcFormat), 256);
|
||||
TestBothTBCopies(utils::Expectation::Success, buffer, 0, smallestValidBytesPerRow,
|
||||
4, texture, 0, {0, 0, 0}, {kTestWidth, 4, 1});
|
||||
}
|
||||
|
@ -1574,3 +1597,66 @@ TEST_F(CopyCommandTest_CompressedTextureFormats, ImageExtent) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test copies between buffer and multiple array layers of an uncompressed texture
|
||||
TEST_F(CopyCommandTest, CopyToMultipleArrayLayers) {
|
||||
wgpu::Texture destination =
|
||||
CopyCommandTest::Create2DTexture(4, 2, 1, 5, wgpu::TextureFormat::RGBA8Unorm,
|
||||
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc);
|
||||
|
||||
// Copy to all array layers
|
||||
TestBothTBCopiesExactBufferSize(256, 2, destination, wgpu::TextureFormat::RGBA8Unorm, {0, 0, 0},
|
||||
{4, 2, 5});
|
||||
|
||||
// Copy to the highest array layer
|
||||
TestBothTBCopiesExactBufferSize(256, 2, destination, wgpu::TextureFormat::RGBA8Unorm, {0, 0, 4},
|
||||
{4, 2, 1});
|
||||
|
||||
// Copy to array layers in the middle
|
||||
TestBothTBCopiesExactBufferSize(256, 2, destination, wgpu::TextureFormat::RGBA8Unorm, {0, 0, 1},
|
||||
{4, 2, 3});
|
||||
|
||||
// Copy with a non-packed rowsPerImage
|
||||
TestBothTBCopiesExactBufferSize(256, 3, destination, wgpu::TextureFormat::RGBA8Unorm, {0, 0, 0},
|
||||
{4, 2, 5});
|
||||
|
||||
// Copy with bytesPerRow = 512
|
||||
TestBothTBCopiesExactBufferSize(512, 2, destination, wgpu::TextureFormat::RGBA8Unorm, {0, 0, 1},
|
||||
{4, 2, 3});
|
||||
}
|
||||
|
||||
// Test copies between buffer and multiple array layers of a compressed texture
|
||||
TEST_F(CopyCommandTest_CompressedTextureFormats, CopyToMultipleArrayLayers) {
|
||||
for (wgpu::TextureFormat bcFormat : utils::kBCFormats) {
|
||||
wgpu::Texture texture = CopyCommandTest::Create2DTexture(
|
||||
12, 16, 1, 20, bcFormat, wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc);
|
||||
|
||||
// Copy to all array layers
|
||||
TestBothTBCopiesExactBufferSize(256, 16, texture, bcFormat, {0, 0, 0}, {12, 16, 20});
|
||||
|
||||
// Copy to the highest array layer
|
||||
TestBothTBCopiesExactBufferSize(256, 16, texture, bcFormat, {0, 0, 19}, {12, 16, 1});
|
||||
|
||||
// Copy to array layers in the middle
|
||||
TestBothTBCopiesExactBufferSize(256, 16, texture, bcFormat, {0, 0, 1}, {12, 16, 18});
|
||||
|
||||
// Copy touching the texture corners with a non-packed rowsPerImage
|
||||
TestBothTBCopiesExactBufferSize(256, 24, texture, bcFormat, {4, 4, 4}, {8, 12, 16});
|
||||
|
||||
// rowsPerImage needs to be a multiple of blockHeight
|
||||
{
|
||||
wgpu::Buffer source =
|
||||
CreateBuffer(8192, wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst);
|
||||
TestBothTBCopies(utils::Expectation::Failure, source, 0, 256, 6, texture, 0, {0, 0, 0},
|
||||
{4, 4, 1});
|
||||
}
|
||||
|
||||
// rowsPerImage must be a multiple of blockHeight even with an empty copy
|
||||
{
|
||||
wgpu::Buffer source =
|
||||
CreateBuffer(0, wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst);
|
||||
TestBothTBCopies(utils::Expectation::Failure, source, 0, 256, 2, texture, 0, {0, 0, 0},
|
||||
{0, 0, 0});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@
|
|||
#include "tests/unittests/validation/ValidationTest.h"
|
||||
|
||||
#include "common/Math.h"
|
||||
#include "utils/TextureFormatUtils.h"
|
||||
#include "utils/WGPUHelpers.h"
|
||||
|
||||
namespace {
|
||||
|
@ -45,21 +46,6 @@ namespace {
|
|||
return tex;
|
||||
}
|
||||
|
||||
uint64_t RequiredBytesInCopy(uint32_t bytesPerRow,
|
||||
uint32_t rowsPerImage,
|
||||
wgpu::Extent3D copyExtent,
|
||||
wgpu::TextureFormat format = wgpu::TextureFormat::RGBA8Unorm) {
|
||||
if (copyExtent.width == 0 || copyExtent.height == 0 || copyExtent.depth == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
uint64_t bytesPerImage = bytesPerRow * rowsPerImage;
|
||||
uint64_t bytesInLastSlice =
|
||||
bytesPerRow * (copyExtent.height - 1) +
|
||||
(copyExtent.width * utils::TextureFormatPixelSize(format));
|
||||
return bytesPerImage * (copyExtent.depth - 1) + bytesInLastSlice;
|
||||
}
|
||||
}
|
||||
|
||||
void TestWriteTexture(size_t dataSize,
|
||||
uint32_t dataOffset,
|
||||
uint32_t dataBytesPerRow,
|
||||
|
@ -81,12 +67,30 @@ namespace {
|
|||
queue.WriteTexture(&textureCopyView, data.data(), dataSize, &textureDataLayout, &size);
|
||||
}
|
||||
|
||||
void TestWriteTextureExactDataSize(uint32_t bytesPerRow,
|
||||
uint32_t rowsPerImage,
|
||||
wgpu::Texture texture,
|
||||
wgpu::TextureFormat textureFormat,
|
||||
wgpu::Origin3D origin,
|
||||
wgpu::Extent3D extent3D) {
|
||||
// Check the minimal valid dataSize.
|
||||
uint64_t dataSize =
|
||||
utils::RequiredBytesInCopy(bytesPerRow, rowsPerImage, extent3D, textureFormat);
|
||||
TestWriteTexture(dataSize, 0, bytesPerRow, rowsPerImage, texture, 0, origin, extent3D);
|
||||
|
||||
// Check dataSize was indeed minimal.
|
||||
uint64_t invalidSize = dataSize - 1;
|
||||
ASSERT_DEVICE_ERROR(TestWriteTexture(invalidSize, 0, bytesPerRow, rowsPerImage, texture,
|
||||
0, origin, extent3D));
|
||||
}
|
||||
|
||||
wgpu::Queue queue;
|
||||
};
|
||||
|
||||
// Test the success case for WriteTexture
|
||||
TEST_F(QueueWriteTextureValidationTest, Success) {
|
||||
const uint64_t dataSize = RequiredBytesInCopy(256, 0, {4, 4, 1});
|
||||
const uint64_t dataSize =
|
||||
utils::RequiredBytesInCopy(256, 0, {4, 4, 1}, wgpu::TextureFormat::RGBA8Unorm);
|
||||
wgpu::Texture destination = Create2DTexture({16, 16, 4}, 5, wgpu::TextureFormat::RGBA8Unorm,
|
||||
wgpu::TextureUsage::CopyDst);
|
||||
|
||||
|
@ -131,7 +135,8 @@ namespace {
|
|||
|
||||
// Test OOB conditions on the data
|
||||
TEST_F(QueueWriteTextureValidationTest, OutOfBoundsOnData) {
|
||||
const uint64_t dataSize = RequiredBytesInCopy(256, 0, {4, 4, 1});
|
||||
const uint64_t dataSize =
|
||||
utils::RequiredBytesInCopy(256, 0, {4, 4, 1}, wgpu::TextureFormat::RGBA8Unorm);
|
||||
wgpu::Texture destination = Create2DTexture({16, 16, 1}, 5, wgpu::TextureFormat::RGBA8Unorm,
|
||||
wgpu::TextureUsage::CopyDst);
|
||||
|
||||
|
@ -143,14 +148,15 @@ namespace {
|
|||
ASSERT_DEVICE_ERROR(
|
||||
TestWriteTexture(dataSize, 4, 256, 0, destination, 0, {0, 0, 0}, {4, 4, 1}));
|
||||
|
||||
// OOB on the data because RequiredBytesInCopy overflows
|
||||
// OOB on the data because utils::RequiredBytesInCopy overflows
|
||||
ASSERT_DEVICE_ERROR(
|
||||
TestWriteTexture(dataSize, 0, 512, 0, destination, 0, {0, 0, 0}, {4, 3, 1}));
|
||||
|
||||
// Not OOB on the data although bytes per row * height overflows
|
||||
// but RequiredBytesInCopy * depth does not overflow
|
||||
// but utils::RequiredBytesInCopy * depth does not overflow
|
||||
{
|
||||
uint32_t sourceDataSize = RequiredBytesInCopy(256, 0, {7, 3, 1});
|
||||
uint32_t sourceDataSize =
|
||||
utils::RequiredBytesInCopy(256, 0, {7, 3, 1}, wgpu::TextureFormat::RGBA8Unorm);
|
||||
ASSERT_TRUE(256 * 3 > sourceDataSize) << "bytes per row * height should overflow data";
|
||||
|
||||
TestWriteTexture(sourceDataSize, 0, 256, 0, destination, 0, {0, 0, 0}, {7, 3, 1});
|
||||
|
@ -159,7 +165,8 @@ namespace {
|
|||
|
||||
// Test OOB conditions on the texture
|
||||
TEST_F(QueueWriteTextureValidationTest, OutOfBoundsOnTexture) {
|
||||
const uint64_t dataSize = RequiredBytesInCopy(256, 0, {4, 4, 1});
|
||||
const uint64_t dataSize =
|
||||
utils::RequiredBytesInCopy(256, 0, {4, 4, 1}, wgpu::TextureFormat::RGBA8Unorm);
|
||||
wgpu::Texture destination = Create2DTexture({16, 16, 2}, 5, wgpu::TextureFormat::RGBA8Unorm,
|
||||
wgpu::TextureUsage::CopyDst);
|
||||
|
||||
|
@ -186,7 +193,8 @@ namespace {
|
|||
|
||||
// Test that we force Depth=1 on writes to 2D textures
|
||||
TEST_F(QueueWriteTextureValidationTest, DepthConstraintFor2DTextures) {
|
||||
const uint64_t dataSize = RequiredBytesInCopy(0, 0, {0, 0, 2});
|
||||
const uint64_t dataSize =
|
||||
utils::RequiredBytesInCopy(0, 0, {0, 0, 2}, wgpu::TextureFormat::RGBA8Unorm);
|
||||
wgpu::Texture destination = Create2DTexture({16, 16, 1}, 5, wgpu::TextureFormat::RGBA8Unorm,
|
||||
wgpu::TextureUsage::CopyDst);
|
||||
|
||||
|
@ -197,7 +205,8 @@ namespace {
|
|||
|
||||
// Test WriteTexture with incorrect texture usage
|
||||
TEST_F(QueueWriteTextureValidationTest, IncorrectUsage) {
|
||||
const uint64_t dataSize = RequiredBytesInCopy(256, 0, {4, 4, 1});
|
||||
const uint64_t dataSize =
|
||||
utils::RequiredBytesInCopy(256, 0, {4, 4, 1}, wgpu::TextureFormat::RGBA8Unorm);
|
||||
wgpu::Texture sampled = Create2DTexture({16, 16, 1}, 5, wgpu::TextureFormat::RGBA8Unorm,
|
||||
wgpu::TextureUsage::Sampled);
|
||||
|
||||
|
@ -226,7 +235,8 @@ namespace {
|
|||
|
||||
// Test that if rowsPerImage is greater than 0, it must be at least copy height.
|
||||
TEST_F(QueueWriteTextureValidationTest, ImageHeightConstraint) {
|
||||
uint64_t dataSize = RequiredBytesInCopy(256, 0, {4, 4, 1});
|
||||
uint64_t dataSize =
|
||||
utils::RequiredBytesInCopy(256, 0, {4, 4, 1}, wgpu::TextureFormat::RGBA8Unorm);
|
||||
wgpu::Texture destination = Create2DTexture({16, 16, 1}, 1, wgpu::TextureFormat::RGBA8Unorm,
|
||||
wgpu::TextureUsage::CopyDst);
|
||||
|
||||
|
@ -246,7 +256,8 @@ namespace {
|
|||
|
||||
// Test WriteTexture with incorrect data offset usage
|
||||
TEST_F(QueueWriteTextureValidationTest, IncorrectDataOffset) {
|
||||
uint64_t dataSize = RequiredBytesInCopy(256, 0, {4, 4, 1});
|
||||
uint64_t dataSize =
|
||||
utils::RequiredBytesInCopy(256, 0, {4, 4, 1}, wgpu::TextureFormat::RGBA8Unorm);
|
||||
wgpu::Texture destination = Create2DTexture({16, 16, 1}, 5, wgpu::TextureFormat::RGBA8Unorm,
|
||||
wgpu::TextureUsage::CopyDst);
|
||||
|
||||
|
@ -259,7 +270,8 @@ namespace {
|
|||
|
||||
// Test multisampled textures can be used in WriteTexture.
|
||||
TEST_F(QueueWriteTextureValidationTest, WriteToMultisampledTexture) {
|
||||
uint64_t dataSize = RequiredBytesInCopy(256, 0, {2, 2, 1});
|
||||
uint64_t dataSize =
|
||||
utils::RequiredBytesInCopy(256, 0, {2, 2, 1}, wgpu::TextureFormat::RGBA8Unorm);
|
||||
wgpu::Texture destination = Create2DTexture({2, 2, 1}, 1, wgpu::TextureFormat::RGBA8Unorm,
|
||||
wgpu::TextureUsage::CopyDst, 4);
|
||||
|
||||
|
@ -316,11 +328,11 @@ namespace {
|
|||
{
|
||||
for (wgpu::TextureFormat format : kFormats) {
|
||||
uint32_t validDataSize =
|
||||
RequiredBytesInCopy(kBytesPerRow, 0, {kWidth, kHeight, 1}, format);
|
||||
utils::RequiredBytesInCopy(kBytesPerRow, 0, {kWidth, kHeight, 1}, format);
|
||||
wgpu::Texture destination =
|
||||
Create2DTexture({kWidth, kHeight, 1}, 1, format, wgpu::TextureUsage::CopyDst);
|
||||
|
||||
// Verify the return value of RequiredBytesInCopu() is exactly the minimum valid
|
||||
// Verify the return value of RequiredBytesInCopy() is exactly the minimum valid
|
||||
// data size in this test.
|
||||
{
|
||||
uint32_t invalidDataSize = validDataSize - 1;
|
||||
|
@ -339,7 +351,8 @@ namespace {
|
|||
|
||||
// Test write from data to mip map of non square texture
|
||||
TEST_F(QueueWriteTextureValidationTest, WriteToMipmapOfNonSquareTexture) {
|
||||
uint64_t dataSize = RequiredBytesInCopy(256, 0, {4, 2, 1});
|
||||
uint64_t dataSize =
|
||||
utils::RequiredBytesInCopy(256, 0, {4, 2, 1}, wgpu::TextureFormat::RGBA8Unorm);
|
||||
uint32_t maxMipmapLevel = 3;
|
||||
wgpu::Texture destination =
|
||||
Create2DTexture({4, 2, 1}, maxMipmapLevel, wgpu::TextureFormat::RGBA8Unorm,
|
||||
|
@ -362,6 +375,33 @@ namespace {
|
|||
{0, 0, 0}, {2, 2, 1}));
|
||||
}
|
||||
|
||||
// Test writes to multiple array layers of an uncompressed texture
|
||||
TEST_F(QueueWriteTextureValidationTest, WriteToMultipleArrayLayers) {
|
||||
wgpu::Texture destination = QueueWriteTextureValidationTest::Create2DTexture(
|
||||
{4, 2, 5}, 1, wgpu::TextureFormat::RGBA8Unorm,
|
||||
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc);
|
||||
|
||||
// Write to all array layers
|
||||
TestWriteTextureExactDataSize(256, 2, destination, wgpu::TextureFormat::RGBA8Unorm,
|
||||
{0, 0, 0}, {4, 2, 5});
|
||||
|
||||
// Write to the highest array layer
|
||||
TestWriteTextureExactDataSize(256, 2, destination, wgpu::TextureFormat::RGBA8Unorm,
|
||||
{0, 0, 4}, {4, 2, 1});
|
||||
|
||||
// Write to array layers in the middle
|
||||
TestWriteTextureExactDataSize(256, 2, destination, wgpu::TextureFormat::RGBA8Unorm,
|
||||
{0, 0, 1}, {4, 2, 3});
|
||||
|
||||
// Copy with a non-packed rowsPerImage
|
||||
TestWriteTextureExactDataSize(256, 3, destination, wgpu::TextureFormat::RGBA8Unorm,
|
||||
{0, 0, 0}, {4, 2, 5});
|
||||
|
||||
// Copy with bytesPerRow = 500
|
||||
TestWriteTextureExactDataSize(500, 2, destination, wgpu::TextureFormat::RGBA8Unorm,
|
||||
{0, 0, 1}, {4, 2, 3});
|
||||
}
|
||||
|
||||
class WriteTextureTest_CompressedTextureFormats : public QueueWriteTextureValidationTest {
|
||||
public:
|
||||
WriteTextureTest_CompressedTextureFormats() : QueueWriteTextureValidationTest() {
|
||||
|
@ -403,14 +443,14 @@ namespace {
|
|||
|
||||
// Valid usages of data offset.
|
||||
{
|
||||
uint32_t validDataOffset = utils::CompressedFormatBlockSizeInBytes(bcFormat);
|
||||
uint32_t validDataOffset = utils::GetTexelBlockSizeInBytes(bcFormat);
|
||||
QueueWriteTextureValidationTest::TestWriteTexture(512, validDataOffset, 256, 4,
|
||||
texture, 0, {0, 0, 0}, {4, 4, 1});
|
||||
}
|
||||
|
||||
// Failures on invalid data offset.
|
||||
{
|
||||
uint32_t kInvalidDataOffset = utils::CompressedFormatBlockSizeInBytes(bcFormat) / 2;
|
||||
uint32_t kInvalidDataOffset = utils::GetTexelBlockSizeInBytes(bcFormat) / 2;
|
||||
ASSERT_DEVICE_ERROR(TestWriteTexture(512, kInvalidDataOffset, 256, 4, texture, 0,
|
||||
{0, 0, 0}, {4, 4, 1}));
|
||||
}
|
||||
|
@ -439,7 +479,7 @@ namespace {
|
|||
for (wgpu::TextureFormat bcFormat : utils::kBCFormats) {
|
||||
wgpu::Texture texture = Create2DTexture(bcFormat, 1, kTestWidth, kTestHeight);
|
||||
uint32_t ValidBytesPerRow =
|
||||
kTestWidth / 4 * utils::CompressedFormatBlockSizeInBytes(bcFormat);
|
||||
kTestWidth / 4 * utils::GetTexelBlockSizeInBytes(bcFormat);
|
||||
ASSERT_NE(0u, ValidBytesPerRow % 256);
|
||||
TestWriteTexture(1024, 0, ValidBytesPerRow, 4, texture, 0, {0, 0, 0},
|
||||
{kTestWidth, 4, 1});
|
||||
|
@ -568,4 +608,32 @@ namespace {
|
|||
}
|
||||
}
|
||||
|
||||
// Test writes to multiple array layers of a compressed texture
|
||||
TEST_F(WriteTextureTest_CompressedTextureFormats, WriteToMultipleArrayLayers) {
|
||||
for (wgpu::TextureFormat bcFormat : utils::kBCFormats) {
|
||||
wgpu::Texture texture = QueueWriteTextureValidationTest::Create2DTexture(
|
||||
{12, 16, 20}, 1, bcFormat,
|
||||
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc);
|
||||
|
||||
// Write to all array layers
|
||||
TestWriteTextureExactDataSize(256, 16, texture, bcFormat, {0, 0, 0}, {12, 16, 20});
|
||||
|
||||
// Write to the highest array layer
|
||||
TestWriteTextureExactDataSize(256, 16, texture, bcFormat, {0, 0, 19}, {12, 16, 1});
|
||||
|
||||
// Write to array layers in the middle
|
||||
TestWriteTextureExactDataSize(256, 16, texture, bcFormat, {0, 0, 1}, {12, 16, 18});
|
||||
|
||||
// Write touching the texture corners with a non-packed rowsPerImage
|
||||
TestWriteTextureExactDataSize(256, 24, texture, bcFormat, {4, 4, 4}, {8, 12, 16});
|
||||
|
||||
// rowsPerImage needs to be a multiple of blockHeight
|
||||
ASSERT_DEVICE_ERROR(
|
||||
TestWriteTexture(8192, 0, 256, 6, texture, 0, {0, 0, 0}, {4, 4, 1}));
|
||||
|
||||
// rowsPerImage must be a multiple of blockHeight even with an empty write
|
||||
ASSERT_DEVICE_ERROR(TestWriteTexture(0, 0, 256, 2, texture, 0, {0, 0, 0}, {0, 0, 0}));
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
|
@ -119,6 +119,7 @@ namespace utils {
|
|||
case wgpu::TextureFormat::BGRA8UnormSrgb:
|
||||
case wgpu::TextureFormat::RGB10A2Unorm:
|
||||
case wgpu::TextureFormat::RG11B10Float:
|
||||
case wgpu::TextureFormat::Depth32Float:
|
||||
return 4u;
|
||||
|
||||
case wgpu::TextureFormat::RG32Float:
|
||||
|
@ -152,9 +153,138 @@ namespace utils {
|
|||
case wgpu::TextureFormat::BC7RGBAUnormSrgb:
|
||||
return 16u;
|
||||
|
||||
case wgpu::TextureFormat::Depth24Plus:
|
||||
case wgpu::TextureFormat::Depth24PlusStencil8:
|
||||
case wgpu::TextureFormat::Undefined:
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return 0u;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t GetTextureFormatBlockWidth(wgpu::TextureFormat textureFormat) {
|
||||
switch (textureFormat) {
|
||||
case wgpu::TextureFormat::R8Unorm:
|
||||
case wgpu::TextureFormat::R8Snorm:
|
||||
case wgpu::TextureFormat::R8Uint:
|
||||
case wgpu::TextureFormat::R8Sint:
|
||||
case wgpu::TextureFormat::R16Uint:
|
||||
case wgpu::TextureFormat::R16Sint:
|
||||
case wgpu::TextureFormat::R16Float:
|
||||
case wgpu::TextureFormat::RG8Unorm:
|
||||
case wgpu::TextureFormat::RG8Snorm:
|
||||
case wgpu::TextureFormat::RG8Uint:
|
||||
case wgpu::TextureFormat::RG8Sint:
|
||||
case wgpu::TextureFormat::R32Float:
|
||||
case wgpu::TextureFormat::R32Uint:
|
||||
case wgpu::TextureFormat::R32Sint:
|
||||
case wgpu::TextureFormat::RG16Uint:
|
||||
case wgpu::TextureFormat::RG16Sint:
|
||||
case wgpu::TextureFormat::RG16Float:
|
||||
case wgpu::TextureFormat::RGBA8Unorm:
|
||||
case wgpu::TextureFormat::RGBA8UnormSrgb:
|
||||
case wgpu::TextureFormat::RGBA8Snorm:
|
||||
case wgpu::TextureFormat::RGBA8Uint:
|
||||
case wgpu::TextureFormat::RGBA8Sint:
|
||||
case wgpu::TextureFormat::BGRA8Unorm:
|
||||
case wgpu::TextureFormat::BGRA8UnormSrgb:
|
||||
case wgpu::TextureFormat::RGB10A2Unorm:
|
||||
case wgpu::TextureFormat::RG11B10Float:
|
||||
case wgpu::TextureFormat::RG32Float:
|
||||
case wgpu::TextureFormat::RG32Uint:
|
||||
case wgpu::TextureFormat::RG32Sint:
|
||||
case wgpu::TextureFormat::RGBA16Uint:
|
||||
case wgpu::TextureFormat::RGBA16Sint:
|
||||
case wgpu::TextureFormat::RGBA16Float:
|
||||
case wgpu::TextureFormat::RGBA32Float:
|
||||
case wgpu::TextureFormat::RGBA32Uint:
|
||||
case wgpu::TextureFormat::RGBA32Sint:
|
||||
case wgpu::TextureFormat::Depth32Float:
|
||||
case wgpu::TextureFormat::Depth24Plus:
|
||||
case wgpu::TextureFormat::Depth24PlusStencil8:
|
||||
return 1u;
|
||||
|
||||
case wgpu::TextureFormat::BC1RGBAUnorm:
|
||||
case wgpu::TextureFormat::BC1RGBAUnormSrgb:
|
||||
case wgpu::TextureFormat::BC4RUnorm:
|
||||
case wgpu::TextureFormat::BC4RSnorm:
|
||||
case wgpu::TextureFormat::BC2RGBAUnorm:
|
||||
case wgpu::TextureFormat::BC2RGBAUnormSrgb:
|
||||
case wgpu::TextureFormat::BC3RGBAUnorm:
|
||||
case wgpu::TextureFormat::BC3RGBAUnormSrgb:
|
||||
case wgpu::TextureFormat::BC5RGUnorm:
|
||||
case wgpu::TextureFormat::BC5RGSnorm:
|
||||
case wgpu::TextureFormat::BC6HRGBUfloat:
|
||||
case wgpu::TextureFormat::BC6HRGBSfloat:
|
||||
case wgpu::TextureFormat::BC7RGBAUnorm:
|
||||
case wgpu::TextureFormat::BC7RGBAUnormSrgb:
|
||||
return 4u;
|
||||
|
||||
case wgpu::TextureFormat::Undefined:
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return 0u;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t GetTextureFormatBlockHeight(wgpu::TextureFormat textureFormat) {
|
||||
switch (textureFormat) {
|
||||
case wgpu::TextureFormat::R8Unorm:
|
||||
case wgpu::TextureFormat::R8Snorm:
|
||||
case wgpu::TextureFormat::R8Uint:
|
||||
case wgpu::TextureFormat::R8Sint:
|
||||
case wgpu::TextureFormat::R16Uint:
|
||||
case wgpu::TextureFormat::R16Sint:
|
||||
case wgpu::TextureFormat::R16Float:
|
||||
case wgpu::TextureFormat::RG8Unorm:
|
||||
case wgpu::TextureFormat::RG8Snorm:
|
||||
case wgpu::TextureFormat::RG8Uint:
|
||||
case wgpu::TextureFormat::RG8Sint:
|
||||
case wgpu::TextureFormat::R32Float:
|
||||
case wgpu::TextureFormat::R32Uint:
|
||||
case wgpu::TextureFormat::R32Sint:
|
||||
case wgpu::TextureFormat::RG16Uint:
|
||||
case wgpu::TextureFormat::RG16Sint:
|
||||
case wgpu::TextureFormat::RG16Float:
|
||||
case wgpu::TextureFormat::RGBA8Unorm:
|
||||
case wgpu::TextureFormat::RGBA8UnormSrgb:
|
||||
case wgpu::TextureFormat::RGBA8Snorm:
|
||||
case wgpu::TextureFormat::RGBA8Uint:
|
||||
case wgpu::TextureFormat::RGBA8Sint:
|
||||
case wgpu::TextureFormat::BGRA8Unorm:
|
||||
case wgpu::TextureFormat::BGRA8UnormSrgb:
|
||||
case wgpu::TextureFormat::RGB10A2Unorm:
|
||||
case wgpu::TextureFormat::RG11B10Float:
|
||||
case wgpu::TextureFormat::RG32Float:
|
||||
case wgpu::TextureFormat::RG32Uint:
|
||||
case wgpu::TextureFormat::RG32Sint:
|
||||
case wgpu::TextureFormat::RGBA16Uint:
|
||||
case wgpu::TextureFormat::RGBA16Sint:
|
||||
case wgpu::TextureFormat::RGBA16Float:
|
||||
case wgpu::TextureFormat::RGBA32Float:
|
||||
case wgpu::TextureFormat::RGBA32Uint:
|
||||
case wgpu::TextureFormat::RGBA32Sint:
|
||||
case wgpu::TextureFormat::Depth32Float:
|
||||
case wgpu::TextureFormat::Depth24Plus:
|
||||
case wgpu::TextureFormat::Depth24PlusStencil8:
|
||||
return 1u;
|
||||
|
||||
case wgpu::TextureFormat::BC1RGBAUnorm:
|
||||
case wgpu::TextureFormat::BC1RGBAUnormSrgb:
|
||||
case wgpu::TextureFormat::BC4RUnorm:
|
||||
case wgpu::TextureFormat::BC4RSnorm:
|
||||
case wgpu::TextureFormat::BC2RGBAUnorm:
|
||||
case wgpu::TextureFormat::BC2RGBAUnormSrgb:
|
||||
case wgpu::TextureFormat::BC3RGBAUnorm:
|
||||
case wgpu::TextureFormat::BC3RGBAUnormSrgb:
|
||||
case wgpu::TextureFormat::BC5RGUnorm:
|
||||
case wgpu::TextureFormat::BC5RGSnorm:
|
||||
case wgpu::TextureFormat::BC6HRGBUfloat:
|
||||
case wgpu::TextureFormat::BC6HRGBSfloat:
|
||||
case wgpu::TextureFormat::BC7RGBAUnorm:
|
||||
case wgpu::TextureFormat::BC7RGBAUnormSrgb:
|
||||
return 4u;
|
||||
|
||||
case wgpu::TextureFormat::Undefined:
|
||||
default:
|
||||
UNREACHABLE();
|
||||
|
|
|
@ -55,6 +55,8 @@ namespace utils {
|
|||
bool TextureFormatSupportsStorageTexture(wgpu::TextureFormat format);
|
||||
|
||||
uint32_t GetTexelBlockSizeInBytes(wgpu::TextureFormat textureFormat);
|
||||
uint32_t GetTextureFormatBlockWidth(wgpu::TextureFormat textureFormat);
|
||||
uint32_t GetTextureFormatBlockHeight(wgpu::TextureFormat textureFormat);
|
||||
const char* GetGLSLImageFormatQualifier(wgpu::TextureFormat textureFormat);
|
||||
} // namespace utils
|
||||
|
||||
|
|
|
@ -418,19 +418,6 @@ namespace utils {
|
|||
return layout;
|
||||
}
|
||||
|
||||
// TODO(jiawei.shao@intel.com): support more pixel formats
|
||||
uint32_t TextureFormatPixelSize(wgpu::TextureFormat format) {
|
||||
switch (format) {
|
||||
case wgpu::TextureFormat::RG8Unorm:
|
||||
return 2;
|
||||
case wgpu::TextureFormat::RGBA8Unorm:
|
||||
return 4;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const std::array<wgpu::TextureFormat, 14> kBCFormats = {
|
||||
wgpu::TextureFormat::BC1RGBAUnorm, wgpu::TextureFormat::BC1RGBAUnormSrgb,
|
||||
wgpu::TextureFormat::BC2RGBAUnorm, wgpu::TextureFormat::BC2RGBAUnormSrgb,
|
||||
|
@ -440,27 +427,22 @@ namespace utils {
|
|||
wgpu::TextureFormat::BC6HRGBUfloat, wgpu::TextureFormat::BC6HRGBSfloat,
|
||||
wgpu::TextureFormat::BC7RGBAUnorm, wgpu::TextureFormat::BC7RGBAUnormSrgb};
|
||||
|
||||
uint32_t CompressedFormatBlockSizeInBytes(wgpu::TextureFormat format) {
|
||||
switch (format) {
|
||||
case wgpu::TextureFormat::BC1RGBAUnorm:
|
||||
case wgpu::TextureFormat::BC1RGBAUnormSrgb:
|
||||
case wgpu::TextureFormat::BC4RSnorm:
|
||||
case wgpu::TextureFormat::BC4RUnorm:
|
||||
return 8;
|
||||
case wgpu::TextureFormat::BC2RGBAUnorm:
|
||||
case wgpu::TextureFormat::BC2RGBAUnormSrgb:
|
||||
case wgpu::TextureFormat::BC3RGBAUnorm:
|
||||
case wgpu::TextureFormat::BC3RGBAUnormSrgb:
|
||||
case wgpu::TextureFormat::BC5RGSnorm:
|
||||
case wgpu::TextureFormat::BC5RGUnorm:
|
||||
case wgpu::TextureFormat::BC6HRGBSfloat:
|
||||
case wgpu::TextureFormat::BC6HRGBUfloat:
|
||||
case wgpu::TextureFormat::BC7RGBAUnorm:
|
||||
case wgpu::TextureFormat::BC7RGBAUnormSrgb:
|
||||
return 16;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
uint64_t RequiredBytesInCopy(uint64_t bytesPerRow,
|
||||
uint64_t rowsPerImage,
|
||||
wgpu::Extent3D copyExtent,
|
||||
wgpu::TextureFormat textureFormat) {
|
||||
if (copyExtent.width == 0 || copyExtent.height == 0 || copyExtent.depth == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
uint32_t blockSize = utils::GetTexelBlockSizeInBytes(textureFormat);
|
||||
uint32_t blockWidth = utils::GetTextureFormatBlockWidth(textureFormat);
|
||||
uint32_t blockHeight = utils::GetTextureFormatBlockHeight(textureFormat);
|
||||
|
||||
uint64_t texelBlockRowsPerImage = rowsPerImage / blockHeight;
|
||||
uint64_t bytesPerImage = bytesPerRow * texelBlockRowsPerImage;
|
||||
uint64_t bytesInLastSlice = bytesPerRow * (copyExtent.height / blockHeight - 1) +
|
||||
(copyExtent.width / blockWidth * blockSize);
|
||||
return bytesPerImage * (copyExtent.depth - 1) + bytesInLastSlice;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "common/Constants.h"
|
||||
#include "utils/TextureFormatUtils.h"
|
||||
|
||||
namespace utils {
|
||||
|
||||
|
@ -151,9 +152,12 @@ namespace utils {
|
|||
uint32_t mipmapLevel,
|
||||
uint32_t rowsPerImage);
|
||||
|
||||
uint32_t TextureFormatPixelSize(wgpu::TextureFormat format);
|
||||
extern const std::array<wgpu::TextureFormat, 14> kBCFormats;
|
||||
uint32_t CompressedFormatBlockSizeInBytes(wgpu::TextureFormat format);
|
||||
|
||||
uint64_t RequiredBytesInCopy(uint64_t bytesPerRow,
|
||||
uint64_t rowsPerImage,
|
||||
wgpu::Extent3D copyExtent,
|
||||
wgpu::TextureFormat textureFormat);
|
||||
|
||||
} // namespace utils
|
||||
|
||||
|
|
Loading…
Reference in New Issue