Test all formats used as readonly storage texture in StorageTextureTests
This patch changes all the tests related to read-only storage textures
in dawn_end2end_tests StorageTextureTests to make them test all the
texture formats that support being used as storage textures in WebGPU.
BUG=dawn:267
TEST=dawn_end2end_tests
Change-Id: I4d6ddbee638a787a2dcfc626bd4963a9b9043772
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/22640
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
diff --git a/src/tests/end2end/CompressedTextureFormatTests.cpp b/src/tests/end2end/CompressedTextureFormatTests.cpp
index b29729a..0845ad8 100644
--- a/src/tests/end2end/CompressedTextureFormatTests.cpp
+++ b/src/tests/end2end/CompressedTextureFormatTests.cpp
@@ -18,6 +18,7 @@
#include "common/Constants.h"
#include "common/Math.h"
#include "utils/ComboRenderPipelineDescriptor.h"
+#include "utils/TextureFormatUtils.h"
#include "utils/WGPUHelpers.h"
// The helper struct to configure the copies between buffers and textures.
@@ -66,7 +67,7 @@
} else {
bufferRowPitchInBytes =
copyWidthInBlockAtLevel *
- CompressedFormatBlockSizeInBytes(copyConfig.textureDescriptor.format);
+ utils::GetTexelBlockSizeInBytes(copyConfig.textureDescriptor.format);
}
uint32_t uploadBufferSize =
copyConfig.bufferOffset + bufferRowPitchInBytes * copyHeightInBlockAtLevel;
@@ -259,31 +260,6 @@
return dstTexture;
}
- // Return the BC block size in bytes.
- static 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;
- }
- }
-
// Return the pre-prepared one-block BC texture data.
static std::vector<uint8_t> GetOneBlockBCFormatTextureData(wgpu::TextureFormat bcFormat) {
switch (bcFormat) {
@@ -841,7 +817,7 @@
for (wgpu::TextureFormat format : kBCFormats) {
config.textureDescriptor.format = format;
- const uint32_t blockSizeInBytes = CompressedFormatBlockSizeInBytes(format);
+ const uint32_t blockSizeInBytes = utils::GetTexelBlockSizeInBytes(format);
const uint32_t blockCountPerRowPitch = config.bytesPerRowAlignment / blockSizeInBytes;
config.bufferOffset = (blockCountPerRowPitch - blockCountPerRow) * blockSizeInBytes;
@@ -877,7 +853,7 @@
for (wgpu::TextureFormat format : kBCFormats) {
config.textureDescriptor.format = format;
- const uint32_t blockSizeInBytes = CompressedFormatBlockSizeInBytes(format);
+ const uint32_t blockSizeInBytes = utils::GetTexelBlockSizeInBytes(format);
const uint32_t blockCountPerRowPitch = config.bytesPerRowAlignment / blockSizeInBytes;
config.bufferOffset = (blockCountPerRowPitch - blockCountPerRow) * blockSizeInBytes +
@@ -911,7 +887,7 @@
for (wgpu::TextureFormat format : kBCFormats) {
config.textureDescriptor.format = format;
- const uint32_t blockSizeInBytes = CompressedFormatBlockSizeInBytes(format);
+ const uint32_t blockSizeInBytes = utils::GetTexelBlockSizeInBytes(format);
const uint32_t blockCountPerRowPitch = config.bytesPerRowAlignment / blockSizeInBytes;
config.bufferOffset =
(blockCountPerRowPitch - blockCountPerRow + kExceedRowBlockCount) * blockSizeInBytes;
@@ -941,7 +917,7 @@
for (wgpu::TextureFormat format : kBCFormats) {
config.textureDescriptor.format = format;
- const uint32_t blockSizeInBytes = CompressedFormatBlockSizeInBytes(format);
+ const uint32_t blockSizeInBytes = utils::GetTexelBlockSizeInBytes(format);
const uint32_t blockCountPerRowPitch = config.bytesPerRowAlignment / blockSizeInBytes;
config.bufferOffset =
diff --git a/src/tests/end2end/StorageTextureTests.cpp b/src/tests/end2end/StorageTextureTests.cpp
index 799f9ec..1cd8fe1 100644
--- a/src/tests/end2end/StorageTextureTests.cpp
+++ b/src/tests/end2end/StorageTextureTests.cpp
@@ -16,17 +16,309 @@
#include "common/Assert.h"
#include "common/Constants.h"
+#include "common/Math.h"
#include "utils/ComboRenderPipelineDescriptor.h"
+#include "utils/TextureFormatUtils.h"
#include "utils/WGPUHelpers.h"
class StorageTextureTests : public DawnTest {
public:
- // TODO(jiawei.shao@intel.com): support all formats that can be used in storage textures.
- static std::vector<uint32_t> GetExpectedData(uint32_t arrayLayerCount = 1) {
- constexpr size_t kDataCountPerLayer = kWidth * kHeight;
- std::vector<uint32_t> outputData(kDataCountPerLayer * arrayLayerCount);
- for (uint32_t i = 0; i < outputData.size(); ++i) {
- outputData[i] = i + 1u;
+ static void FillExpectedData(void* pixelValuePtr,
+ wgpu::TextureFormat format,
+ uint32_t x,
+ uint32_t y,
+ uint32_t arrayLayer) {
+ const uint32_t pixelValue = 1 + x + kWidth * (y + kHeight * arrayLayer);
+ ASSERT(pixelValue <= 255u / 4);
+
+ switch (format) {
+ // 32-bit unsigned integer formats
+ case wgpu::TextureFormat::R32Uint: {
+ uint32_t* valuePtr = static_cast<uint32_t*>(pixelValuePtr);
+ *valuePtr = pixelValue;
+ break;
+ }
+
+ case wgpu::TextureFormat::RG32Uint: {
+ uint32_t* valuePtr = static_cast<uint32_t*>(pixelValuePtr);
+ valuePtr[0] = pixelValue;
+ valuePtr[1] = pixelValue * 2;
+ break;
+ }
+
+ case wgpu::TextureFormat::RGBA32Uint: {
+ uint32_t* valuePtr = static_cast<uint32_t*>(pixelValuePtr);
+ valuePtr[0] = pixelValue;
+ valuePtr[1] = pixelValue * 2;
+ valuePtr[2] = pixelValue * 3;
+ valuePtr[3] = pixelValue * 4;
+ break;
+ }
+
+ // 32-bit signed integer formats
+ case wgpu::TextureFormat::R32Sint: {
+ int32_t* valuePtr = static_cast<int32_t*>(pixelValuePtr);
+ *valuePtr = static_cast<int32_t>(pixelValue);
+ break;
+ }
+
+ case wgpu::TextureFormat::RG32Sint: {
+ int32_t* valuePtr = static_cast<int32_t*>(pixelValuePtr);
+ valuePtr[0] = static_cast<int32_t>(pixelValue);
+ valuePtr[1] = -static_cast<int32_t>(pixelValue);
+ break;
+ }
+
+ case wgpu::TextureFormat::RGBA32Sint: {
+ int32_t* valuePtr = static_cast<int32_t*>(pixelValuePtr);
+ valuePtr[0] = static_cast<int32_t>(pixelValue);
+ valuePtr[1] = -static_cast<int32_t>(pixelValue);
+ valuePtr[2] = static_cast<int32_t>(pixelValue * 2);
+ valuePtr[3] = -static_cast<int32_t>(pixelValue * 2);
+ break;
+ }
+
+ // 32-bit float formats
+ case wgpu::TextureFormat::R32Float: {
+ float_t* valuePtr = static_cast<float_t*>(pixelValuePtr);
+ *valuePtr = static_cast<float_t>(pixelValue * 1.1f);
+ break;
+ }
+
+ case wgpu::TextureFormat::RG32Float: {
+ float_t* valuePtr = static_cast<float_t*>(pixelValuePtr);
+ valuePtr[0] = static_cast<float_t>(pixelValue * 1.1f);
+ valuePtr[1] = -static_cast<float_t>(pixelValue * 2.2f);
+ break;
+ }
+
+ case wgpu::TextureFormat::RGBA32Float: {
+ float_t* valuePtr = static_cast<float_t*>(pixelValuePtr);
+ valuePtr[0] = static_cast<float_t>(pixelValue * 1.1f);
+ valuePtr[1] = -static_cast<float_t>(pixelValue * 1.1f);
+ valuePtr[2] = static_cast<float_t>(pixelValue * 2.2f);
+ valuePtr[3] = -static_cast<float_t>(pixelValue * 2.2f);
+ break;
+ }
+
+ // 16-bit (unsigned integer, signed integer and float) 4-component formats
+ case wgpu::TextureFormat::RGBA16Uint: {
+ uint16_t* valuePtr = static_cast<uint16_t*>(pixelValuePtr);
+ valuePtr[0] = static_cast<uint16_t>(pixelValue);
+ valuePtr[1] = static_cast<uint16_t>(pixelValue * 2);
+ valuePtr[2] = static_cast<uint16_t>(pixelValue * 3);
+ valuePtr[3] = static_cast<uint16_t>(pixelValue * 4);
+ break;
+ }
+ case wgpu::TextureFormat::RGBA16Sint: {
+ int16_t* valuePtr = static_cast<int16_t*>(pixelValuePtr);
+ valuePtr[0] = static_cast<int16_t>(pixelValue);
+ valuePtr[1] = -static_cast<int16_t>(pixelValue);
+ valuePtr[2] = static_cast<int16_t>(pixelValue * 2);
+ valuePtr[3] = -static_cast<int16_t>(pixelValue * 2);
+ break;
+ }
+
+ case wgpu::TextureFormat::RGBA16Float: {
+ uint16_t* valuePtr = static_cast<uint16_t*>(pixelValuePtr);
+ valuePtr[0] = Float32ToFloat16(static_cast<float_t>(pixelValue));
+ valuePtr[1] = Float32ToFloat16(-static_cast<float_t>(pixelValue));
+ valuePtr[2] = Float32ToFloat16(static_cast<float_t>(pixelValue * 2));
+ valuePtr[3] = Float32ToFloat16(-static_cast<float_t>(pixelValue * 2));
+ break;
+ }
+
+ // 8-bit (normalized/non-normalized signed/unsigned integer) 4-component formats
+ case wgpu::TextureFormat::RGBA8Unorm:
+ case wgpu::TextureFormat::RGBA8Uint: {
+ RGBA8* valuePtr = static_cast<RGBA8*>(pixelValuePtr);
+ *valuePtr = RGBA8(pixelValue, pixelValue * 2, pixelValue * 3, pixelValue * 4);
+ break;
+ }
+
+ case wgpu::TextureFormat::RGBA8Snorm:
+ case wgpu::TextureFormat::RGBA8Sint: {
+ int8_t* valuePtr = static_cast<int8_t*>(pixelValuePtr);
+ valuePtr[0] = static_cast<int8_t>(pixelValue);
+ valuePtr[1] = -static_cast<int8_t>(pixelValue);
+ valuePtr[2] = static_cast<int8_t>(pixelValue) * 2;
+ valuePtr[3] = -static_cast<int8_t>(pixelValue) * 2;
+ break;
+ }
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+
+ std::string GetGLSLImageDeclaration(wgpu::TextureFormat format,
+ std::string accessQualifier,
+ bool is2DArray) {
+ std::ostringstream ostream;
+ ostream << "layout(set = 0, binding = 0, " << utils::GetGLSLImageFormatQualifier(format)
+ << ") uniform " << accessQualifier << " "
+ << utils::GetColorTextureComponentTypePrefix(format) << "image2D";
+ if (is2DArray) {
+ ostream << "Array";
+ }
+ ostream << " storageImage;";
+ return ostream.str();
+ }
+
+ const char* GetExpectedPixelValue(wgpu::TextureFormat format) {
+ switch (format) {
+ // non-normalized unsigned integer formats
+ case wgpu::TextureFormat::R32Uint:
+ return "uvec4(value, 0, 0, 1u)";
+
+ case wgpu::TextureFormat::RG32Uint:
+ return "uvec4(value, value * 2, 0, 1);";
+
+ case wgpu::TextureFormat::RGBA8Uint:
+ case wgpu::TextureFormat::RGBA16Uint:
+ case wgpu::TextureFormat::RGBA32Uint:
+ return "uvec4(value, value * 2, value * 3, value * 4);";
+
+ // non-normalized signed integer formats
+ case wgpu::TextureFormat::R32Sint:
+ return "ivec4(value, 0, 0, 1)";
+
+ case wgpu::TextureFormat::RG32Sint:
+ return "ivec4(value, -value, 0, 1);";
+
+ case wgpu::TextureFormat::RGBA8Sint:
+ case wgpu::TextureFormat::RGBA16Sint:
+ case wgpu::TextureFormat::RGBA32Sint:
+ return "ivec4(value, -value, value * 2, -value * 2);";
+
+ // float formats
+ case wgpu::TextureFormat::R32Float:
+ return "vec4(value * 1.1f, 0, 0, 1);";
+
+ case wgpu::TextureFormat::RG32Float:
+ return "vec4(value * 1.1f, -(value * 2.2f), 0, 1);";
+
+ case wgpu::TextureFormat::RGBA16Float:
+ return "vec4(value, -float(value), float(value * 2), -float(value * 2));";
+
+ case wgpu::TextureFormat::RGBA32Float:
+ return "vec4(value * 1.1f, -(value * 1.1f), value * 2.2f, -(value * 2.2f));";
+
+ // normalized signed/unsigned integer formats
+ case wgpu::TextureFormat::RGBA8Unorm:
+ return "vec4(value / 255.0, value / 255.0 * 2, value / 255.0 * 3, value / 255.0 * "
+ "4);";
+
+ case wgpu::TextureFormat::RGBA8Snorm:
+ return "vec4(value / 127.0, -(value / 127.0), (value * 2 / 127.0), -(value * 2 / "
+ "127.0));";
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+
+ const char* GetGLSLComparisonFunction(wgpu::TextureFormat format) {
+ switch (format) {
+ // non-normalized unsigned integer formats
+ case wgpu::TextureFormat::R32Uint:
+ case wgpu::TextureFormat::RG32Uint:
+ case wgpu::TextureFormat::RGBA8Uint:
+ case wgpu::TextureFormat::RGBA16Uint:
+ case wgpu::TextureFormat::RGBA32Uint:
+ return R"(bool IsEqualTo(uvec4 pixel, uvec4 expected) {
+ return pixel == expected;
+ })";
+
+ // non-normalized signed integer formats
+ case wgpu::TextureFormat::R32Sint:
+ case wgpu::TextureFormat::RG32Sint:
+ case wgpu::TextureFormat::RGBA8Sint:
+ case wgpu::TextureFormat::RGBA16Sint:
+ case wgpu::TextureFormat::RGBA32Sint:
+ return R"(bool IsEqualTo(ivec4 pixel, ivec4 expected) {
+ return pixel == expected;
+ })";
+
+ // float formats
+ case wgpu::TextureFormat::R32Float:
+ case wgpu::TextureFormat::RG32Float:
+ case wgpu::TextureFormat::RGBA16Float:
+ case wgpu::TextureFormat::RGBA32Float:
+ return R"(bool IsEqualTo(vec4 pixel, vec4 expected) {
+ return pixel == expected;
+ })";
+
+ // normalized signed/unsigned integer formats
+ case wgpu::TextureFormat::RGBA8Unorm:
+ case wgpu::TextureFormat::RGBA8Snorm:
+ // On Windows Intel drivers the tests will fail if tolerance <= 0.00000001f.
+ return R"(bool IsEqualTo(vec4 pixel, vec4 expected) {
+ const float tolerance = 0.0000001f;
+ return all(lessThan(abs(pixel - expected), vec4(tolerance)));
+ })";
+
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ return "";
+ }
+
+ std::string CommonReadOnlyTestCode(wgpu::TextureFormat format, bool is2DArray = false) {
+ std::ostringstream ostream;
+
+ const char* prefix = utils::GetColorTextureComponentTypePrefix(format);
+
+ ostream << GetGLSLImageDeclaration(format, "readonly", is2DArray) << "\n"
+ << GetGLSLComparisonFunction(format) << "bool doTest() {\n";
+ if (is2DArray) {
+ ostream << R"(ivec3 size = imageSize(storageImage);
+ const uint layerCount = size.z;)";
+ } else {
+ ostream << R"(ivec2 size = imageSize(storageImage);
+ const uint layerCount = 1;)";
+ }
+ ostream << R"(for (uint layer = 0; layer < layerCount; ++layer) {
+ for (uint y = 0; y < size.y; ++y) {
+ for (uint x = 0; x < size.x; ++x) {
+ uint value = 1 + x + size.x * (y + size.y * layer);
+ )"
+ << prefix << "vec4 expected = " << GetExpectedPixelValue(format) << ";\n"
+ << prefix << R"(vec4 pixel = imageLoad(storageImage, )";
+ if (is2DArray) {
+ ostream << "ivec3(x, y, layer));";
+ } else {
+ ostream << "ivec2(x, y));";
+ }
+ ostream << R"(
+ if (!IsEqualTo(pixel, expected)) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ })";
+
+ return ostream.str();
+ }
+
+ static std::vector<uint8_t> GetExpectedData(wgpu::TextureFormat format,
+ uint32_t arrayLayerCount = 1) {
+ const uint32_t texelSizeInBytes = utils::GetTexelBlockSizeInBytes(format);
+
+ std::vector<uint8_t> outputData(texelSizeInBytes * kWidth * kHeight * arrayLayerCount);
+
+ for (uint32_t i = 0; i < outputData.size() / texelSizeInBytes; ++i) {
+ uint8_t* pixelValuePtr = &outputData[i * texelSizeInBytes];
+ const uint32_t x = i % kWidth;
+ const uint32_t y = (i % (kWidth * kHeight)) / kWidth;
+ const uint32_t arrayLayer = i / (kWidth * kHeight);
+ FillExpectedData(pixelValuePtr, format, x, y, arrayLayer);
}
return outputData;
@@ -55,24 +347,27 @@
return device.CreateBuffer(&descriptor);
}
- // TODO(jiawei.shao@intel.com): support all formats that can be used in storage textures.
- wgpu::Texture CreateTextureWithTestData(const std::vector<uint32_t>& initialTextureData,
- uint32_t texelSize) {
+ wgpu::Texture CreateTextureWithTestData(const std::vector<uint8_t>& initialTextureData,
+ wgpu::TextureFormat format) {
+ uint32_t texelSize = utils::GetTexelBlockSizeInBytes(format);
ASSERT(kWidth * texelSize <= kTextureBytesPerRowAlignment);
+ const uint32_t bytesPerTextureRow = texelSize * kWidth;
const uint32_t arrayLayerCount =
- static_cast<uint32_t>(initialTextureData.size() / (kWidth * kHeight));
+ static_cast<uint32_t>(initialTextureData.size() / texelSize / (kWidth * kHeight));
const size_t uploadBufferSize =
- kTextureBytesPerRowAlignment * (kHeight * arrayLayerCount - 1) + kWidth * texelSize;
+ kTextureBytesPerRowAlignment * (kHeight * arrayLayerCount - 1) +
+ kWidth * bytesPerTextureRow;
- std::vector<uint32_t> uploadBufferData(uploadBufferSize / texelSize);
- const size_t texelCountPerRow = kTextureBytesPerRowAlignment / texelSize;
+ std::vector<uint8_t> uploadBufferData(uploadBufferSize);
for (uint32_t layer = 0; layer < arrayLayerCount; ++layer) {
- const size_t initialDataOffset = kWidth * kHeight * layer;
+ const size_t initialDataOffset = bytesPerTextureRow * kHeight * layer;
for (size_t y = 0; y < kHeight; ++y) {
- for (size_t x = 0; x < kWidth; ++x) {
- uint32_t data = initialTextureData[initialDataOffset + kWidth * y + x];
- size_t indexInUploadBuffer = (kHeight * layer + y) * texelCountPerRow + x;
+ for (size_t x = 0; x < bytesPerTextureRow; ++x) {
+ uint8_t data =
+ initialTextureData[initialDataOffset + bytesPerTextureRow * y + x];
+ size_t indexInUploadBuffer =
+ (kHeight * layer + y) * kTextureBytesPerRowAlignment + x;
uploadBufferData[indexInUploadBuffer] = data;
}
}
@@ -81,9 +376,9 @@
utils::CreateBufferFromData(device, uploadBufferData.data(), uploadBufferSize,
wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst);
- wgpu::Texture outputTexture = CreateTexture(
- wgpu::TextureFormat::R32Uint, wgpu::TextureUsage::Storage | wgpu::TextureUsage::CopyDst,
- kWidth, kHeight, arrayLayerCount);
+ wgpu::Texture outputTexture =
+ CreateTexture(format, wgpu::TextureUsage::Storage | wgpu::TextureUsage::CopyDst, kWidth,
+ kHeight, arrayLayerCount);
const wgpu::Extent3D copyExtent = {kWidth, kHeight, 1};
@@ -235,10 +530,10 @@
void CheckOutputStorageTexture(wgpu::Texture writeonlyStorageTexture,
uint32_t texelSize,
- const std::vector<uint32_t>& expectedData) {
+ const std::vector<uint8_t>& expectedData) {
// Copy the content from the write-only storage texture to the result buffer.
const uint32_t arrayLayerCount =
- static_cast<uint32_t>(expectedData.size() / (kWidth * kHeight));
+ static_cast<uint32_t>(expectedData.size() / texelSize / (kWidth * kHeight));
wgpu::Buffer resultBuffer = CreateEmptyBufferForTextureCopy(texelSize, arrayLayerCount);
const wgpu::Extent3D copyExtent = {kWidth, kHeight, 1};
@@ -266,9 +561,10 @@
for (size_t y = 0; y < kHeight; ++y) {
const size_t resultBufferOffset =
kTextureBytesPerRowAlignment * (kHeight * layer + y);
- const size_t expectedDataOffset = kWidth * (kHeight * layer + y);
- EXPECT_BUFFER_U32_RANGE_EQ(expectedData.data() + expectedDataOffset, resultBuffer,
- resultBufferOffset, kWidth);
+ const size_t expectedDataOffset = texelSize * kWidth * (kHeight * layer + y);
+ EXPECT_BUFFER_U32_RANGE_EQ(
+ reinterpret_cast<const uint32_t*>(expectedData.data() + expectedDataOffset),
+ resultBuffer, resultBufferOffset, kWidth);
}
}
}
@@ -284,20 +580,6 @@
gl_PointSize = 1.0f;
})";
- const char* kCommonReadOnlyTestCode_uimage2D = R"(
- bool doTest() {
- for (uint y = 0; y < 4; ++y) {
- for (uint x = 0; x < 4; ++x) {
- uvec4 expected = uvec4(1u + x + y * 4u, 0, 0, 1u);
- uvec4 pixel = imageLoad(srcImage, ivec2(x, y));
- if (pixel != expected) {
- return false;
- }
- }
- }
- return true;
- })";
-
const char* kCommonWriteOnlyTestCode_uimage2D = R"(
#version 450
layout(set = 0, binding = 0, r32ui) uniform writeonly uimage2D dstImage;
@@ -348,23 +630,27 @@
// bug in spvc parser is fixed.
DAWN_SKIP_TEST_IF(IsD3D12() && IsSpvcParserBeingUsed());
- // Prepare the read-only storage texture and fill it with the expected data.
- // TODO(jiawei.shao@intel.com): test more texture formats.
- constexpr uint32_t kTexelSizeR32Uint = 4u;
- const std::vector<uint32_t> kInitialTextureData = GetExpectedData();
- wgpu::Texture readonlyStorageTexture =
- CreateTextureWithTestData(kInitialTextureData, kTexelSizeR32Uint);
+ for (wgpu::TextureFormat format : utils::kAllTextureFormats) {
+ if (!utils::TextureFormatSupportsStorageTexture(format)) {
+ continue;
+ }
- // Create a compute shader that reads the pixels from the read-only storage texture and writes 1
- // to DstBuffer if they all have to expected value.
- const std::string kComputeShader = std::string(R"(
- #version 450
- layout (set = 0, binding = 0, r32ui) uniform readonly uimage2D srcImage;
- layout (set = 0, binding = 1, std430) buffer DstBuffer {
- uint result;
- } dstBuffer;)") + kCommonReadOnlyTestCode_uimage2D +
- R"(
- void main() {
+ // Prepare the read-only storage texture and fill it with the expected data.
+ const std::vector<uint8_t> kInitialTextureData = GetExpectedData(format);
+ wgpu::Texture readonlyStorageTexture =
+ CreateTextureWithTestData(kInitialTextureData, format);
+
+ // Create a compute shader that reads the pixels from the read-only storage texture and
+ // writes 1 to DstBuffer if they all have to expected value.
+ std::ostringstream csStream;
+ csStream << R"(
+ #version 450
+ layout(set = 0, binding = 1, std430) buffer DstBuffer {
+ uint result;
+ } dstBuffer;
+ )" << CommonReadOnlyTestCode(format)
+ << R"(
+ void main() {
if (doTest()) {
dstBuffer.result = 1;
} else {
@@ -372,7 +658,8 @@
}
})";
- CheckResultInStorageBuffer(readonlyStorageTexture, kComputeShader);
+ CheckResultInStorageBuffer(readonlyStorageTexture, csStream.str());
+ }
}
// Test that read-only storage textures are supported in vertex shader.
@@ -383,20 +670,24 @@
// bug in spvc parser is fixed.
DAWN_SKIP_TEST_IF(IsSpvcParserBeingUsed());
- // Prepare the read-only storage texture and fill it with the expected data.
- // TODO(jiawei.shao@intel.com): test more texture formats
- constexpr uint32_t kTexelSizeR32Uint = 4u;
- const std::vector<uint32_t> kInitialTextureData = GetExpectedData();
- wgpu::Texture readonlyStorageTexture =
- CreateTextureWithTestData(kInitialTextureData, kTexelSizeR32Uint);
+ for (wgpu::TextureFormat format : utils::kAllTextureFormats) {
+ if (!utils::TextureFormatSupportsStorageTexture(format)) {
+ continue;
+ }
- // Create a rendering pipeline that reads the pixels from the read-only storage texture and uses
- // green as the output color, otherwise uses red instead.
- const std::string kVertexShader = std::string(R"(
+ // Prepare the read-only storage texture and fill it with the expected data.
+ const std::vector<uint8_t> kInitialTextureData = GetExpectedData(format);
+ wgpu::Texture readonlyStorageTexture =
+ CreateTextureWithTestData(kInitialTextureData, format);
+
+ // Create a rendering pipeline that reads the pixels from the read-only storage texture and
+ // uses green as the output color, otherwise uses red instead.
+ std::ostringstream vsStream;
+ vsStream << R"(
#version 450
- layout(set = 0, binding = 0, r32ui) uniform readonly uimage2D srcImage;
- layout(location = 0) out vec4 o_color;)") +
- kCommonReadOnlyTestCode_uimage2D + R"(
+ layout(location = 0) out vec4 o_color;
+ )" << CommonReadOnlyTestCode(format)
+ << R"(
void main() {
gl_Position = vec4(0.f, 0.f, 0.f, 1.f);
if (doTest()) {
@@ -406,14 +697,15 @@
}
gl_PointSize = 1.0f;
})";
- const char* kFragmentShader = R"(
+ const char* kFragmentShader = R"(
#version 450
layout(location = 0) in vec4 o_color;
layout(location = 0) out vec4 fragColor;
void main() {
fragColor = o_color;
})";
- CheckDrawsGreen(kVertexShader.c_str(), kFragmentShader, readonlyStorageTexture);
+ CheckDrawsGreen(vsStream.str().c_str(), kFragmentShader, readonlyStorageTexture);
+ }
}
// Test that read-only storage textures are supported in fragment shader.
@@ -424,21 +716,25 @@
// bug in spvc parser is fixed.
DAWN_SKIP_TEST_IF(IsSpvcParserBeingUsed());
- // Prepare the read-only storage texture and fill it with the expected data.
- // TODO(jiawei.shao@intel.com): test more texture formats
- constexpr uint32_t kTexelSizeR32Uint = 4u;
- const std::vector<uint32_t> kInitialTextureData = GetExpectedData();
- wgpu::Texture readonlyStorageTexture =
- CreateTextureWithTestData(kInitialTextureData, kTexelSizeR32Uint);
+ for (wgpu::TextureFormat format : utils::kAllTextureFormats) {
+ if (!utils::TextureFormatSupportsStorageTexture(format)) {
+ continue;
+ }
- // Create a rendering pipeline that reads the pixels from the read-only storage texture and uses
- // green as the output color if the pixel value is expected, otherwise uses red instead.
- const char* kVertexShader = kSimpleVertexShader;
- const std::string kFragmentShader = std::string(R"(
+ // Prepare the read-only storage texture and fill it with the expected data.
+ const std::vector<uint8_t> kInitialTextureData = GetExpectedData(format);
+ wgpu::Texture readonlyStorageTexture =
+ CreateTextureWithTestData(kInitialTextureData, format);
+
+ // Create a rendering pipeline that reads the pixels from the read-only storage texture and
+ // uses green as the output color if the pixel value is expected, otherwise uses red
+ // instead.
+ std::ostringstream fsStream;
+ fsStream << R"(
#version 450
- layout(set = 0, binding = 0, r32ui) uniform readonly uimage2D srcImage;
- layout(location = 0) out vec4 o_color;)") +
- kCommonReadOnlyTestCode_uimage2D + R"(
+ layout(location = 0) out vec4 o_color;
+ )" << CommonReadOnlyTestCode(format)
+ << R"(
void main() {
if (doTest()) {
o_color = vec4(0.f, 1.f, 0.f, 1.f);
@@ -446,7 +742,8 @@
o_color = vec4(1.f, 0.f, 0.f, 1.f);
}
})";
- CheckDrawsGreen(kVertexShader, kFragmentShader.c_str(), readonlyStorageTexture);
+ CheckDrawsGreen(kSimpleVertexShader, fsStream.str().c_str(), readonlyStorageTexture);
+ }
}
// Test that write-only storage textures are supported in compute shader.
@@ -465,7 +762,8 @@
WriteIntoStorageTextureInComputePass(writeonlyStorageTexture,
kCommonWriteOnlyTestCode_uimage2D);
- CheckOutputStorageTexture(writeonlyStorageTexture, kTexelSizeR32Uint, GetExpectedData());
+ CheckOutputStorageTexture(writeonlyStorageTexture, kTexelSizeR32Uint,
+ GetExpectedData(wgpu::TextureFormat::R32Uint));
}
// Test that write-only storage textures are supported in fragment shader.
@@ -484,7 +782,8 @@
WriteIntoStorageTextureInRenderPass(writeonlyStorageTexture, kSimpleVertexShader,
kCommonWriteOnlyTestCode_uimage2D);
- CheckOutputStorageTexture(writeonlyStorageTexture, kTexelSizeR32Uint, GetExpectedData());
+ CheckOutputStorageTexture(writeonlyStorageTexture, kTexelSizeR32Uint,
+ GetExpectedData(wgpu::TextureFormat::R32Uint));
}
// Verify 2D array read-only storage texture works correctly.
@@ -497,34 +796,23 @@
constexpr uint32_t kArrayLayerCount = 3u;
- constexpr uint32_t kTexelSizeR32Uint = 4u;
- const std::vector<uint32_t> initialTextureData = GetExpectedData(kArrayLayerCount);
+ constexpr wgpu::TextureFormat kTextureFormat = wgpu::TextureFormat::R32Uint;
+
+ const std::vector<uint8_t> initialTextureData =
+ GetExpectedData(kTextureFormat, kArrayLayerCount);
wgpu::Texture readonlyStorageTexture =
- CreateTextureWithTestData(initialTextureData, kTexelSizeR32Uint);
+ CreateTextureWithTestData(initialTextureData, kTextureFormat);
// Create a compute shader that reads the pixels from the read-only storage texture and writes 1
// to DstBuffer if they all have to expected value.
- const char* kComputeShader = R"(
+ std::ostringstream csStream;
+ csStream << R"(
#version 450
- layout (set = 0, binding = 0, r32ui) uniform readonly uimage2DArray srcImage;
layout (set = 0, binding = 1, std430) buffer DstBuffer {
uint result;
} dstBuffer;
- bool doTest() {
- ivec3 size = imageSize(srcImage);
- for (uint layer = 0; layer < size.z; ++layer) {
- for (uint y = 0; y < size.y; ++y) {
- for (uint x = 0; x < size.x; ++x) {
- uint expected = 1u + x + size.x * (y + size.y * layer);
- uvec4 pixel = imageLoad(srcImage, ivec3(x, y, layer));
- if (pixel != uvec4(expected, 0, 0, 1u)) {
- return false;
- }
- }
- }
- }
- return true;
- }
+ )" << CommonReadOnlyTestCode(kTextureFormat, true)
+ << R"(
void main() {
if (doTest()) {
dstBuffer.result = 1;
@@ -533,7 +821,7 @@
}
})";
- CheckResultInStorageBuffer(readonlyStorageTexture, kComputeShader);
+ CheckResultInStorageBuffer(readonlyStorageTexture, csStream.str());
}
// Verify 2D array write-only storage texture works correctly.
@@ -570,7 +858,7 @@
constexpr uint32_t kTexelSizeR32Uint = 4u;
CheckOutputStorageTexture(writeonlyStorageTexture, kTexelSizeR32Uint,
- GetExpectedData(kArrayLayerCount));
+ GetExpectedData(wgpu::TextureFormat::R32Uint, kArrayLayerCount));
}
DAWN_INSTANTIATE_TEST(StorageTextureTests,
@@ -581,10 +869,16 @@
class StorageTextureZeroInitTests : public StorageTextureTests {
public:
- static std::vector<uint32_t> GetExpectedData() {
- constexpr size_t kDataCount = kWidth * kHeight;
- std::vector<uint32_t> outputData(kDataCount, 0);
- outputData[0] = 1u;
+ static std::vector<uint8_t> GetExpectedData() {
+ constexpr wgpu::TextureFormat kTextureFormat = wgpu::TextureFormat::R32Uint;
+
+ const uint32_t texelSizeInBytes = utils::GetTexelBlockSizeInBytes(kTextureFormat);
+ const size_t kDataCount = texelSizeInBytes * kWidth * kHeight;
+ std::vector<uint8_t> outputData(kDataCount, 0);
+
+ uint32_t* outputDataPtr = reinterpret_cast<uint32_t*>(&outputData[0]);
+ *outputDataPtr = 1u;
+
return outputData;
}
diff --git a/src/tests/unittests/validation/StorageTextureValidationTests.cpp b/src/tests/unittests/validation/StorageTextureValidationTests.cpp
index 22d6734..52f0f85 100644
--- a/src/tests/unittests/validation/StorageTextureValidationTests.cpp
+++ b/src/tests/unittests/validation/StorageTextureValidationTests.cpp
@@ -20,78 +20,6 @@
class StorageTextureValidationTests : public ValidationTest {
protected:
- static const char* GetGLSLImageFormatQualifier(wgpu::TextureFormat textureFormat) {
- switch (textureFormat) {
- case wgpu::TextureFormat::R8Unorm:
- return "r8";
- case wgpu::TextureFormat::R8Snorm:
- return "r8_snorm";
- case wgpu::TextureFormat::R8Uint:
- return "r8ui";
- case wgpu::TextureFormat::R8Sint:
- return "r8i";
- case wgpu::TextureFormat::R16Uint:
- return "r16ui";
- case wgpu::TextureFormat::R16Sint:
- return "r16i";
- case wgpu::TextureFormat::R16Float:
- return "r16f";
- case wgpu::TextureFormat::RG8Unorm:
- return "rg8";
- case wgpu::TextureFormat::RG8Snorm:
- return "rg8_snorm";
- case wgpu::TextureFormat::RG8Uint:
- return "rg8ui";
- case wgpu::TextureFormat::RG8Sint:
- return "rg8i";
- case wgpu::TextureFormat::R32Float:
- return "r32f";
- case wgpu::TextureFormat::R32Uint:
- return "r32ui";
- case wgpu::TextureFormat::R32Sint:
- return "r32i";
- case wgpu::TextureFormat::RG16Uint:
- return "rg16ui";
- case wgpu::TextureFormat::RG16Sint:
- return "rg16i";
- case wgpu::TextureFormat::RG16Float:
- return "rg16f";
- case wgpu::TextureFormat::RGBA8Unorm:
- return "rgba8";
- case wgpu::TextureFormat::RGBA8Snorm:
- return "rgba8_snorm";
- case wgpu::TextureFormat::RGBA8Uint:
- return "rgba8ui";
- case wgpu::TextureFormat::RGBA8Sint:
- return "rgba8i";
- case wgpu::TextureFormat::RGB10A2Unorm:
- return "rgb10_a2";
- case wgpu::TextureFormat::RG11B10Float:
- return "r11f_g11f_b10f";
- case wgpu::TextureFormat::RG32Float:
- return "rg32f";
- case wgpu::TextureFormat::RG32Uint:
- return "rg32ui";
- case wgpu::TextureFormat::RG32Sint:
- return "rg32i";
- case wgpu::TextureFormat::RGBA16Uint:
- return "rgba16ui";
- case wgpu::TextureFormat::RGBA16Sint:
- return "rgba16i";
- case wgpu::TextureFormat::RGBA16Float:
- return "rgba16f";
- case wgpu::TextureFormat::RGBA32Float:
- return "rgba32f";
- case wgpu::TextureFormat::RGBA32Uint:
- return "rgba32ui";
- case wgpu::TextureFormat::RGBA32Sint:
- return "rgba32i";
- default:
- UNREACHABLE();
- return "";
- }
- }
-
static const char* GetGLSLFloatImageTypeDeclaration(wgpu::TextureViewDimension dimension) {
switch (dimension) {
case wgpu::TextureViewDimension::e1D:
@@ -117,7 +45,7 @@
wgpu::BindingType storageTextureBindingType,
wgpu::TextureFormat textureFormat,
wgpu::TextureViewDimension textureViewDimension = wgpu::TextureViewDimension::e2D) {
- const char* glslImageFormatQualifier = GetGLSLImageFormatQualifier(textureFormat);
+ const char* glslImageFormatQualifier = utils::GetGLSLImageFormatQualifier(textureFormat);
const char* textureComponentTypePrefix =
utils::GetColorTextureComponentTypePrefix(textureFormat);
return CreateComputeShaderWithStorageTexture(
diff --git a/src/utils/TextureFormatUtils.cpp b/src/utils/TextureFormatUtils.cpp
index 634417c..795d1f9 100644
--- a/src/utils/TextureFormatUtils.cpp
+++ b/src/utils/TextureFormatUtils.cpp
@@ -86,4 +86,172 @@
return false;
}
}
+
+ uint32_t GetTexelBlockSizeInBytes(wgpu::TextureFormat textureFormat) {
+ switch (textureFormat) {
+ case wgpu::TextureFormat::R8Unorm:
+ case wgpu::TextureFormat::R8Snorm:
+ case wgpu::TextureFormat::R8Uint:
+ case wgpu::TextureFormat::R8Sint:
+ return 1u;
+
+ 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:
+ return 2u;
+
+ 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:
+ return 4u;
+
+ case wgpu::TextureFormat::RG32Float:
+ case wgpu::TextureFormat::RG32Uint:
+ case wgpu::TextureFormat::RG32Sint:
+ case wgpu::TextureFormat::RGBA16Uint:
+ case wgpu::TextureFormat::RGBA16Sint:
+ case wgpu::TextureFormat::RGBA16Float:
+ return 8u;
+
+ case wgpu::TextureFormat::RGBA32Float:
+ case wgpu::TextureFormat::RGBA32Uint:
+ case wgpu::TextureFormat::RGBA32Sint:
+ return 16u;
+
+ case wgpu::TextureFormat::BC1RGBAUnorm:
+ case wgpu::TextureFormat::BC1RGBAUnormSrgb:
+ case wgpu::TextureFormat::BC4RUnorm:
+ case wgpu::TextureFormat::BC4RSnorm:
+ return 8u;
+
+ 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 16u;
+
+ case wgpu::TextureFormat::Depth32Float:
+ case wgpu::TextureFormat::Depth24Plus:
+ case wgpu::TextureFormat::Depth24PlusStencil8:
+ case wgpu::TextureFormat::Undefined:
+ default:
+ UNREACHABLE();
+ return 0u;
+ }
+ }
+
+ const char* GetGLSLImageFormatQualifier(wgpu::TextureFormat textureFormat) {
+ switch (textureFormat) {
+ case wgpu::TextureFormat::R8Unorm:
+ return "r8";
+ case wgpu::TextureFormat::R8Snorm:
+ return "r8_snorm";
+ case wgpu::TextureFormat::R8Uint:
+ return "r8ui";
+ case wgpu::TextureFormat::R8Sint:
+ return "r8i";
+ case wgpu::TextureFormat::R16Uint:
+ return "r16ui";
+ case wgpu::TextureFormat::R16Sint:
+ return "r16i";
+ case wgpu::TextureFormat::R16Float:
+ return "r16f";
+ case wgpu::TextureFormat::RG8Unorm:
+ return "rg8";
+ case wgpu::TextureFormat::RG8Snorm:
+ return "rg8_snorm";
+ case wgpu::TextureFormat::RG8Uint:
+ return "rg8ui";
+ case wgpu::TextureFormat::RG8Sint:
+ return "rg8i";
+ case wgpu::TextureFormat::R32Float:
+ return "r32f";
+ case wgpu::TextureFormat::R32Uint:
+ return "r32ui";
+ case wgpu::TextureFormat::R32Sint:
+ return "r32i";
+ case wgpu::TextureFormat::RG16Uint:
+ return "rg16ui";
+ case wgpu::TextureFormat::RG16Sint:
+ return "rg16i";
+ case wgpu::TextureFormat::RG16Float:
+ return "rg16f";
+ case wgpu::TextureFormat::RGBA8Unorm:
+ return "rgba8";
+ case wgpu::TextureFormat::RGBA8Snorm:
+ return "rgba8_snorm";
+ case wgpu::TextureFormat::RGBA8Uint:
+ return "rgba8ui";
+ case wgpu::TextureFormat::RGBA8Sint:
+ return "rgba8i";
+ case wgpu::TextureFormat::RGB10A2Unorm:
+ return "rgb10_a2";
+ case wgpu::TextureFormat::RG11B10Float:
+ return "r11f_g11f_b10f";
+ case wgpu::TextureFormat::RG32Float:
+ return "rg32f";
+ case wgpu::TextureFormat::RG32Uint:
+ return "rg32ui";
+ case wgpu::TextureFormat::RG32Sint:
+ return "rg32i";
+ case wgpu::TextureFormat::RGBA16Uint:
+ return "rgba16ui";
+ case wgpu::TextureFormat::RGBA16Sint:
+ return "rgba16i";
+ case wgpu::TextureFormat::RGBA16Float:
+ return "rgba16f";
+ case wgpu::TextureFormat::RGBA32Float:
+ return "rgba32f";
+ case wgpu::TextureFormat::RGBA32Uint:
+ return "rgba32ui";
+ case wgpu::TextureFormat::RGBA32Sint:
+ return "rgba32i";
+
+ case wgpu::TextureFormat::RGBA8UnormSrgb:
+ case wgpu::TextureFormat::BGRA8Unorm:
+ case wgpu::TextureFormat::BGRA8UnormSrgb:
+ 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:
+ case wgpu::TextureFormat::Depth32Float:
+ case wgpu::TextureFormat::Depth24Plus:
+ case wgpu::TextureFormat::Depth24PlusStencil8:
+ case wgpu::TextureFormat::Undefined:
+ UNREACHABLE();
+ return "";
+ }
+ }
} // namespace utils
diff --git a/src/utils/TextureFormatUtils.h b/src/utils/TextureFormatUtils.h
index bbd5f0c..2976e94 100644
--- a/src/utils/TextureFormatUtils.h
+++ b/src/utils/TextureFormatUtils.h
@@ -53,6 +53,9 @@
const char* GetColorTextureComponentTypePrefix(wgpu::TextureFormat textureFormat);
bool TextureFormatSupportsStorageTexture(wgpu::TextureFormat format);
+
+ uint32_t GetTexelBlockSizeInBytes(wgpu::TextureFormat textureFormat);
+ const char* GetGLSLImageFormatQualifier(wgpu::TextureFormat textureFormat);
} // namespace utils
#endif