Add storage texture case reading from read-only then writing into write-only
This case verifies that reading from one read-only storage texture then writing into another write-only storage texture in one dispatch are supported in compute shader. Bug: dawn:458 Change-Id: If1b4c13da067fa39b45a378b54c22a4162695c8d Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/23040 Commit-Queue: Jiawei Shao <jiawei.shao@intel.com> Reviewed-by: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Jiawei Shao <jiawei.shao@intel.com>
This commit is contained in:
parent
90ad1a34dd
commit
667238b97d
|
@ -154,15 +154,16 @@ class StorageTextureTests : public DawnTest {
|
||||||
|
|
||||||
std::string GetGLSLImageDeclaration(wgpu::TextureFormat format,
|
std::string GetGLSLImageDeclaration(wgpu::TextureFormat format,
|
||||||
std::string accessQualifier,
|
std::string accessQualifier,
|
||||||
bool is2DArray) {
|
bool is2DArray,
|
||||||
|
uint32_t binding) {
|
||||||
std::ostringstream ostream;
|
std::ostringstream ostream;
|
||||||
ostream << "layout(set = 0, binding = 0, " << utils::GetGLSLImageFormatQualifier(format)
|
ostream << "layout(set = 0, binding = " << binding << ", "
|
||||||
<< ") uniform " << accessQualifier << " "
|
<< utils::GetGLSLImageFormatQualifier(format) << ") uniform " << accessQualifier
|
||||||
<< utils::GetColorTextureComponentTypePrefix(format) << "image2D";
|
<< " " << utils::GetColorTextureComponentTypePrefix(format) << "image2D";
|
||||||
if (is2DArray) {
|
if (is2DArray) {
|
||||||
ostream << "Array";
|
ostream << "Array";
|
||||||
}
|
}
|
||||||
ostream << " storageImage;";
|
ostream << " storageImage" << binding << ";";
|
||||||
return ostream.str();
|
return ostream.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,13 +274,13 @@ class StorageTextureTests : public DawnTest {
|
||||||
|
|
||||||
const char* prefix = utils::GetColorTextureComponentTypePrefix(format);
|
const char* prefix = utils::GetColorTextureComponentTypePrefix(format);
|
||||||
|
|
||||||
ostream << GetGLSLImageDeclaration(format, "readonly", is2DArray) << "\n"
|
ostream << GetGLSLImageDeclaration(format, "readonly", is2DArray, 0) << "\n"
|
||||||
<< GetGLSLComparisonFunction(format) << "bool doTest() {\n";
|
<< GetGLSLComparisonFunction(format) << "bool doTest() {\n";
|
||||||
if (is2DArray) {
|
if (is2DArray) {
|
||||||
ostream << R"(ivec3 size = imageSize(storageImage);
|
ostream << R"(ivec3 size = imageSize(storageImage0);
|
||||||
const uint layerCount = size.z;)";
|
const uint layerCount = size.z;)";
|
||||||
} else {
|
} else {
|
||||||
ostream << R"(ivec2 size = imageSize(storageImage);
|
ostream << R"(ivec2 size = imageSize(storageImage0);
|
||||||
const uint layerCount = 1;)";
|
const uint layerCount = 1;)";
|
||||||
}
|
}
|
||||||
ostream << R"(for (uint layer = 0; layer < layerCount; ++layer) {
|
ostream << R"(for (uint layer = 0; layer < layerCount; ++layer) {
|
||||||
|
@ -288,7 +289,7 @@ class StorageTextureTests : public DawnTest {
|
||||||
uint value = )"
|
uint value = )"
|
||||||
<< kComputeExpectedValueGLSL << ";\n"
|
<< kComputeExpectedValueGLSL << ";\n"
|
||||||
<< prefix << "vec4 expected = " << GetExpectedPixelValue(format) << ";\n"
|
<< prefix << "vec4 expected = " << GetExpectedPixelValue(format) << ";\n"
|
||||||
<< prefix << R"(vec4 pixel = imageLoad(storageImage, )";
|
<< prefix << R"(vec4 pixel = imageLoad(storageImage0, )";
|
||||||
if (is2DArray) {
|
if (is2DArray) {
|
||||||
ostream << "ivec3(x, y, layer));";
|
ostream << "ivec3(x, y, layer));";
|
||||||
} else {
|
} else {
|
||||||
|
@ -314,16 +315,16 @@ class StorageTextureTests : public DawnTest {
|
||||||
|
|
||||||
ostream << R"(
|
ostream << R"(
|
||||||
#version 450
|
#version 450
|
||||||
)" << GetGLSLImageDeclaration(format, "writeonly", is2DArray)
|
)" << GetGLSLImageDeclaration(format, "writeonly", is2DArray, 0)
|
||||||
<< R"(
|
<< R"(
|
||||||
void main() {
|
void main() {
|
||||||
)";
|
)";
|
||||||
if (is2DArray) {
|
if (is2DArray) {
|
||||||
ostream << R"(ivec3 size = imageSize(storageImage);
|
ostream << R"(ivec3 size = imageSize(storageImage0);
|
||||||
const uint layerCount = size.z;
|
const uint layerCount = size.z;
|
||||||
)";
|
)";
|
||||||
} else {
|
} else {
|
||||||
ostream << R"(ivec2 size = imageSize(storageImage);
|
ostream << R"(ivec2 size = imageSize(storageImage0);
|
||||||
const uint layerCount = 1;
|
const uint layerCount = 1;
|
||||||
)";
|
)";
|
||||||
}
|
}
|
||||||
|
@ -340,7 +341,7 @@ class StorageTextureTests : public DawnTest {
|
||||||
ostream << "ivec2 texcoord = ivec2(x, y);\n";
|
ostream << "ivec2 texcoord = ivec2(x, y);\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
ostream << R"( imageStore(storageImage, texcoord, expected);
|
ostream << R"( imageStore(storageImage0, texcoord, expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -349,6 +350,44 @@ class StorageTextureTests : public DawnTest {
|
||||||
return ostream.str();
|
return ostream.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string CommonReadWriteTestCode(wgpu::TextureFormat format, bool is2DArray = false) {
|
||||||
|
std::ostringstream ostream;
|
||||||
|
|
||||||
|
ostream << R"(
|
||||||
|
#version 450
|
||||||
|
)" << GetGLSLImageDeclaration(format, "writeonly", is2DArray, 0)
|
||||||
|
<< GetGLSLImageDeclaration(format, "readonly", is2DArray, 1) << R"(
|
||||||
|
void main() {
|
||||||
|
)";
|
||||||
|
if (is2DArray) {
|
||||||
|
ostream << R"(ivec3 size = imageSize(storageImage0);
|
||||||
|
const uint layerCount = size.z;
|
||||||
|
)";
|
||||||
|
} else {
|
||||||
|
ostream << R"(ivec2 size = imageSize(storageImage0);
|
||||||
|
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) {)"
|
||||||
|
"\n";
|
||||||
|
if (is2DArray) {
|
||||||
|
ostream << "ivec3 texcoord = ivec3(x, y, layer);\n";
|
||||||
|
} else {
|
||||||
|
ostream << "ivec2 texcoord = ivec2(x, y);\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
ostream
|
||||||
|
<< R"( imageStore(storageImage0, texcoord, imageLoad(storageImage1, texcoord));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})";
|
||||||
|
return ostream.str();
|
||||||
|
}
|
||||||
|
|
||||||
static std::vector<uint8_t> GetExpectedData(wgpu::TextureFormat format,
|
static std::vector<uint8_t> GetExpectedData(wgpu::TextureFormat format,
|
||||||
uint32_t arrayLayerCount = 1) {
|
uint32_t arrayLayerCount = 1) {
|
||||||
const uint32_t texelSizeInBytes = utils::GetTexelBlockSizeInBytes(format);
|
const uint32_t texelSizeInBytes = utils::GetTexelBlockSizeInBytes(format);
|
||||||
|
@ -570,6 +609,25 @@ class StorageTextureTests : public DawnTest {
|
||||||
queue.Submit(1, &commandBuffer);
|
queue.Submit(1, &commandBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ReadWriteIntoStorageTextureInComputePass(wgpu::Texture readonlyStorageTexture,
|
||||||
|
wgpu::Texture writeonlyStorageTexture,
|
||||||
|
const char* computeShader) {
|
||||||
|
// Create a compute pipeline that writes the expected pixel values into the storage texture.
|
||||||
|
wgpu::ComputePipeline pipeline = CreateComputePipeline(computeShader);
|
||||||
|
wgpu::BindGroup bindGroup = utils::MakeBindGroup(
|
||||||
|
device, pipeline.GetBindGroupLayout(0),
|
||||||
|
{{0, writeonlyStorageTexture.CreateView()}, {1, readonlyStorageTexture.CreateView()}});
|
||||||
|
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
wgpu::ComputePassEncoder computePassEncoder = encoder.BeginComputePass();
|
||||||
|
computePassEncoder.SetBindGroup(0, bindGroup);
|
||||||
|
computePassEncoder.SetPipeline(pipeline);
|
||||||
|
computePassEncoder.Dispatch(1);
|
||||||
|
computePassEncoder.EndPass();
|
||||||
|
wgpu::CommandBuffer commandBuffer = encoder.Finish();
|
||||||
|
queue.Submit(1, &commandBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
void CheckOutputStorageTexture(wgpu::Texture writeonlyStorageTexture,
|
void CheckOutputStorageTexture(wgpu::Texture writeonlyStorageTexture,
|
||||||
wgpu::TextureFormat format,
|
wgpu::TextureFormat format,
|
||||||
uint32_t arrayLayerCount = 1) {
|
uint32_t arrayLayerCount = 1) {
|
||||||
|
@ -818,6 +876,45 @@ TEST_P(StorageTextureTests, WriteonlyStorageTextureInComputeShader) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that reading from one read-only storage texture then writing into another write-only storage
|
||||||
|
// texture in one dispatch are supported in compute shader.
|
||||||
|
TEST_P(StorageTextureTests, ReadWriteDifferentStorageTextureInOneDispatchInComputeShader) {
|
||||||
|
// When we run dawn_end2end_tests with "--use-spvc-parser", extracting the binding type of a
|
||||||
|
// read-only image will always return shaderc_spvc_binding_type_writeonly_storage_texture.
|
||||||
|
// TODO(jiawei.shao@intel.com): enable this test when we specify "--use-spvc-parser" after the
|
||||||
|
// bug in spvc parser is fixed.
|
||||||
|
DAWN_SKIP_TEST_IF(IsD3D12() && IsSpvcParserBeingUsed());
|
||||||
|
|
||||||
|
for (wgpu::TextureFormat format : utils::kAllTextureFormats) {
|
||||||
|
if (!utils::TextureFormatSupportsStorageTexture(format)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(jiawei.shao@intel.com): investigate why this test fails with RGBA8Snorm on Linux
|
||||||
|
// Intel OpenGL driver.
|
||||||
|
if (format == wgpu::TextureFormat::RGBA8Snorm && IsIntel() && IsOpenGL() && IsLinux()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare the read-only storage texture.
|
||||||
|
const std::vector<uint8_t> kInitialTextureData = GetExpectedData(format);
|
||||||
|
wgpu::Texture readonlyStorageTexture =
|
||||||
|
CreateTextureWithTestData(kInitialTextureData, format);
|
||||||
|
|
||||||
|
// Prepare the write-only storage texture.
|
||||||
|
wgpu::Texture writeonlyStorageTexture =
|
||||||
|
CreateTexture(format, wgpu::TextureUsage::Storage | wgpu::TextureUsage::CopySrc);
|
||||||
|
|
||||||
|
// Write the expected pixel values into the write-only storage texture.
|
||||||
|
const std::string computeShader = CommonReadWriteTestCode(format);
|
||||||
|
ReadWriteIntoStorageTextureInComputePass(readonlyStorageTexture, writeonlyStorageTexture,
|
||||||
|
computeShader.c_str());
|
||||||
|
|
||||||
|
// Verify the pixel data in the write-only storage texture is expected.
|
||||||
|
CheckOutputStorageTexture(writeonlyStorageTexture, format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Test that write-only storage textures are supported in fragment shader.
|
// Test that write-only storage textures are supported in fragment shader.
|
||||||
TEST_P(StorageTextureTests, WriteonlyStorageTextureInFragmentShader) {
|
TEST_P(StorageTextureTests, WriteonlyStorageTextureInFragmentShader) {
|
||||||
// When we run dawn_end2end_tests with "--use-spvc-parser", extracting the binding type of a
|
// When we run dawn_end2end_tests with "--use-spvc-parser", extracting the binding type of a
|
||||||
|
|
Loading…
Reference in New Issue