From 81d62d7ca99fc1469fc9cf5ff698fc64d8e26eb8 Mon Sep 17 00:00:00 2001 From: Yunchao He Date: Fri, 26 Aug 2022 21:23:47 +0000 Subject: [PATCH] Texture corruption issue: add tests for a few rendering types The original tests for texture corruption only contain WriteTexture and B2TCopy, this change adds more write types like rendering a constant color, rendering from texture sampling, and rendering from textureLoad, all of which need a render pipeline and shaders. The new tests manifest that: For a given 2d-array texture dimension, if WriteTexture and B2TCopy fail, rendering, sampling and textureLoad also fail, and vice versa. Bug: dawn:949, dawn:1507 Change-Id: I28035fe3dd84d36c01befd7fd8ff9d78b312446a Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/100061 Commit-Queue: Yunchao He Reviewed-by: Kai Ninomiya Kokoro: Kokoro --- .../tests/end2end/TextureCorruptionTests.cpp | 194 +++++++++++++++--- 1 file changed, 160 insertions(+), 34 deletions(-) diff --git a/src/dawn/tests/end2end/TextureCorruptionTests.cpp b/src/dawn/tests/end2end/TextureCorruptionTests.cpp index dc6b6658b4..13a265b983 100644 --- a/src/dawn/tests/end2end/TextureCorruptionTests.cpp +++ b/src/dawn/tests/end2end/TextureCorruptionTests.cpp @@ -16,10 +16,27 @@ #include "dawn/common/Math.h" #include "dawn/tests/DawnTest.h" +#include "dawn/utils/ComboRenderPipelineDescriptor.h" #include "dawn/utils/WGPUHelpers.h" +// 2D array textures with particular dimensions may corrupt on some devices. This test creates some +// 2d-array textures with different dimensions, and test them one by one. For each sub-test, the +// tested texture is written via different methods, then read back from the texture and verify the +// data. + +constexpr wgpu::TextureFormat kFormat = wgpu::TextureFormat::RGBA8Unorm; + namespace { -enum class WriteType { WriteTexture, B2TCopy }; +enum class WriteType { + WriteTexture, // Write the tested texture via writeTexture API + B2TCopy, // Write the tested texture via B2T copy + RenderConstant, // Write the tested texture via rendering the whole rectangle with solid color + // (0xFFFFFFFF) + RenderFromTextureSample, // Write the tested texture via sampling from a temp texture and + // writing the sampled data + RenderFromTextureLoad // Write the tested texture via textureLoad() from a temp texture and + // writing the loaded data +}; std::ostream& operator<<(std::ostream& o, WriteType writeType) { switch (writeType) { @@ -29,6 +46,15 @@ std::ostream& operator<<(std::ostream& o, WriteType writeType) { case WriteType::B2TCopy: o << "B2TCopy"; break; + case WriteType::RenderConstant: + o << "RenderConstant"; + break; + case WriteType::RenderFromTextureSample: + o << "RenderFromTextureSample"; + break; + case WriteType::RenderFromTextureLoad: + o << "RenderFromTextureLoad"; + break; } return o; } @@ -37,11 +63,7 @@ using TextureFormat = wgpu::TextureFormat; using TextureWidth = uint32_t; using TextureHeight = uint32_t; -DAWN_TEST_PARAM_STRUCT(TextureCorruptionTestsParams, - TextureFormat, - TextureWidth, - TextureHeight, - WriteType); +DAWN_TEST_PARAM_STRUCT(TextureCorruptionTestsParams, TextureWidth, TextureHeight, WriteType); } // namespace @@ -50,8 +72,8 @@ class TextureCorruptionTests : public DawnTestWithParams data(elementNumInTotal, 0); for (uint32_t i = 0; i < copySize.height; ++i) { for (uint32_t j = 0; j < copySize.width; ++j) { - for (uint32_t k = 0; k < elementNumPerTexel; ++k) { - data[i * elementNumPerRow + j * elementNumPerTexel + k] = copyValue; - copyValue++; + if (type == WriteType::RenderFromTextureSample || + type == WriteType::RenderConstant) { + // Fill a simple and constant value (0xFFFFFFFF) in the whole buffer for + // texture sampling and rendering because either sampling operation will + // lead to precision loss or rendering a solid color is easier to implement and + // compare. + data[i * elementNumPerRow + j] = 0xFFFFFFFF; + } else { + data[i * elementNumPerRow + j] = srcValue; + srcValue++; } } } - // Copy data into the texture via B2T copy or WriteTexture + // Write data into the given layer via various write types wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); - switch (GetParam().mWriteType) { + switch (type) { case WriteType::B2TCopy: { queue.WriteBuffer(buffer, 0, data.data(), bufferSize); encoder.CopyBufferToTexture(&imageCopyBuffer, &imageCopyTexture, ©Size); @@ -100,54 +131,149 @@ class TextureCorruptionTests : public DawnTestWithParams @builtin(position) vec4 { + var pos = array, 6>( + vec2(-1.0, 1.0), + vec2(-1.0, -1.0), + vec2( 1.0, 1.0), + vec2( 1.0, 1.0), + vec2(-1.0, -1.0), + vec2( 1.0, -1.0)); + return vec4(pos[VertexIndex], 0.0, 1.0); + })"); + + if (type == WriteType::RenderConstant) { + pipelineDescriptor.cFragment.module = utils::CreateShaderModule(device, R"( + @fragment + fn main(@builtin(position) FragCoord : vec4) -> @location(0) vec4 { + return vec4(1.0, 1.0, 1.0, 1.0); + })"); + } else if (type == WriteType::RenderFromTextureSample) { + pipelineDescriptor.cFragment.module = utils::CreateShaderModule(device, R"( + @group(0) @binding(0) var samp : sampler; + @group(0) @binding(1) var tex : texture_2d; + + @fragment + fn main(@builtin(position) FragCoord : vec4) -> @location(0) vec4 { + return textureSample(tex, samp, FragCoord.xy); + })"); + } else { + pipelineDescriptor.cFragment.module = utils::CreateShaderModule(device, R"( + @group(0) @binding(0) var tex : texture_2d; + + @fragment + fn main(@builtin(position) Fragcoord: vec4) -> @location(0) vec4 { + return textureLoad(tex, vec2(Fragcoord.xy), 0); + })"); + } + + wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDescriptor); + + utils::ComboRenderPassDescriptor renderPassDescriptor({renderView}); + wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDescriptor); + pass.SetPipeline(pipeline); + if (type != WriteType::RenderConstant) { + wgpu::BindGroup bindGroup; + if (type == WriteType::RenderFromTextureLoad) { + bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0), + {{0, samplerView}}); + } else { + bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0), + {{0, device.CreateSampler()}, {1, samplerView}}); + } + pass.SetBindGroup(0, bindGroup); + } + pass.Draw(6); + pass.End(); + } + + wgpu::Texture Create2DTexture(const wgpu::Extent3D size) { + wgpu::TextureDescriptor texDesc = {}; + texDesc.dimension = wgpu::TextureDimension::e2D; + texDesc.size = size; + texDesc.mipLevelCount = 1; + texDesc.format = kFormat; + texDesc.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc | + wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding; + return device.CreateTexture(&texDesc); + } }; -TEST_P(TextureCorruptionTests, CopyTests) { +TEST_P(TextureCorruptionTests, Tests) { DAWN_SUPPRESS_TEST_IF(IsWARP()); uint32_t width = GetParam().mTextureWidth; uint32_t height = GetParam().mTextureHeight; uint32_t depthOrArrayLayerCount = 2; - wgpu::TextureFormat format = GetParam().mTextureFormat; wgpu::Extent3D textureSize = {width, height, depthOrArrayLayerCount}; - // Pre-allocate textures. The incorrect copy may corrupt neighboring textures or layers. - wgpu::TextureDescriptor texDesc = {}; - texDesc.dimension = wgpu::TextureDimension::e2D; - texDesc.size = textureSize; - texDesc.mipLevelCount = 1; - texDesc.format = format; - texDesc.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc; + // Pre-allocate textures. The incorrect write type may corrupt neighboring textures or layers. std::vector textures; uint32_t texNum = 2; for (uint32_t i = 0; i < texNum; ++i) { - textures.push_back(device.CreateTexture(&texDesc)); + textures.push_back(Create2DTexture(textureSize)); } - // Copy data and verify the result one by one for every layer of every texture - uint32_t copyValue = 100000000; + // Write data and verify the result one by one for every layer of every texture + uint32_t srcValue = 100000000; for (uint32_t i = 0; i < texNum; ++i) { for (uint32_t j = 0; j < depthOrArrayLayerCount; ++j) { - DoTest(textures[i], textureSize, j, copyValue, utils::GetTexelBlockSizeInBytes(format)) - << "texNum: " << i << ", layer: " << j; - copyValue += 100000000; + DoTest(textures[i], textureSize, j, srcValue) << "texNum: " << i << ", layer: " << j; + srcValue += 100000000; } } } DAWN_INSTANTIATE_TEST_P(TextureCorruptionTests, {D3D12Backend()}, - {wgpu::TextureFormat::RGBA8Unorm, wgpu::TextureFormat::RGBA16Uint, - wgpu::TextureFormat::RGBA32Uint}, {100u, 200u, 300u, 400u, 500u, 600u, 700u, 800u, 900u, 1000u, 1200u}, {100u, 200u}, - {WriteType::WriteTexture, WriteType::B2TCopy}); + {WriteType::WriteTexture, WriteType::B2TCopy, WriteType::RenderConstant, + WriteType::RenderFromTextureSample, WriteType::RenderFromTextureLoad});