From a827aa2c29aa41346e95e6ac58a752709beb5977 Mon Sep 17 00:00:00 2001 From: "Yan, Shaobo" Date: Tue, 1 Dec 2020 03:37:37 +0000 Subject: [PATCH] CopyTextureForBrowser: Use large triangle to avoid arithmetic precision In previous internal shader, we draw a just fit-in rectangle to do the copy. But there is arithmetic precision issues in border pixels when copy from a large texture. ANGLE handle the same issue by drawing a large triangle. Dawn adopte the same idea here BUG=dawn:465 Change-Id: I2366e28b1e96e7a33116a170023a5138d8c9f770 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/33900 Reviewed-by: Shaobo Yan Reviewed-by: Austin Eng Commit-Queue: Shaobo Yan --- .../CopyTextureForBrowserHelper.cpp | 62 ++++++++----------- .../end2end/CopyTextureForBrowserTests.cpp | 60 ++++++++++++++++++ 2 files changed, 86 insertions(+), 36 deletions(-) diff --git a/src/dawn_native/CopyTextureForBrowserHelper.cpp b/src/dawn_native/CopyTextureForBrowserHelper.cpp index 67ff65c27f..24ba6f132d 100644 --- a/src/dawn_native/CopyTextureForBrowserHelper.cpp +++ b/src/dawn_native/CopyTextureForBrowserHelper.cpp @@ -32,50 +32,42 @@ namespace dawn_native { namespace { - - // TODO(shaobo.yan@intel.com): Use ANGLE's strategy(render a large triangle) to handle - // transform and border interop issue. + // TODO(shaobo.yan@intel.com) : Support premultiplay-alpha, flipY. static const char sCopyTextureForBrowserVertex[] = R"( [[block]] struct Uniforms { - [[offset(0)]] rotation : mat4x4; + [[offset(0)]] u_scale : vec2; + [[offset(8)]] u_offset : vec2; }; - const pos : array, 6> = 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)); - - const texUV : array, 6> = array, 6>( - vec2(1.0, 0.0), - vec2(1.0, 1.0), - vec2(0.0, 1.0), - vec2(1.0, 0.0), - vec2(0.0, 1.0), - vec2(0.0, 0.0)); - - [[location(0)]] var texCoord: vec2; + const texcoord : array, 3> = array, 3>( + vec2(-0.5, 0.0), + vec2( 1.5, 0.0), + vec2( 0.5, 2.0)); + [[location(0)]] var v_texcoord: vec2; [[builtin(position)]] var Position : vec4; [[builtin(vertex_idx)]] var VertexIndex : u32; [[binding(0), set(0)]] var uniforms : Uniforms; - [[stage(vertex)]] - fn main() -> void { - Position = uniforms.rotation * vec4(pos[VertexIndex], 0.0, 1.0); - texCoord = texUV[VertexIndex]; - return; + [[stage(vertex)]] fn main() -> void { + Position = vec4((texcoord[VertexIndex] * 2.0 - vec2(1.0, 1.0)), 0.0, 1.0); + + # Texture coordinate takes top-left as origin point. We need to map the + # texture to triangle carefully. + v_texcoord = (texcoord[VertexIndex] * vec2(1.0, -1.0) + vec2(0.0, 1.0)) * + uniforms.u_scale + uniforms.u_offset; } )"; static const char sPassthrough2D4ChannelFrag[] = R"( [[binding(1), set(0)]] var mySampler: sampler; [[binding(2), set(0)]] var myTexture: texture_sampled_2d; - [[location(0)]] var texCoord : vec2; + [[location(0)]] var v_texcoord : vec2; [[location(0)]] var rgbaColor : vec4; - [[stage(fragment)]] - fn main() -> void { - rgbaColor = textureSample(myTexture, mySampler, texCoord); - return; + [[stage(fragment)]] fn main() -> void { + # Clamp the texcoord and discard the out-of-bound pixels. + var clampedTexcoord : vec2 = + clamp(v_texcoord, vec2(0.0, 0.0), vec2(1.0, 1.0)); + if (all(clampedTexcoord == v_texcoord)) { + rgbaColor = textureSample(myTexture, mySampler, v_texcoord); + } } )"; @@ -224,10 +216,8 @@ namespace dawn_native { // TODO(shaobo.yan@intel.com): Will use scale vector and offset vector to replace the // 4x4 rotation matrix here. const float rotationMatrix[] = { - 1.0, 0.0, 0.0, 0.0, // - 0.0, 1.0, 0.0, 0.0, // - 0.0, 0.0, 1.0, 0.0, // - 0.0, 0.0, 0.0, 1.0, // + 1.0, 1.0, // scale + 0.0, 0.0 // offset }; BufferDescriptor rotationUniformDesc = {}; @@ -290,7 +280,7 @@ namespace dawn_native { // the copy from src texture to dst texture with transformation. passEncoder->SetPipeline(pipeline); passEncoder->SetBindGroup(0, bindGroup.Get()); - passEncoder->Draw(6); + passEncoder->Draw(3); passEncoder->EndPass(); // Finsh encoding. diff --git a/src/tests/end2end/CopyTextureForBrowserTests.cpp b/src/tests/end2end/CopyTextureForBrowserTests.cpp index c38cbeea8e..146e274b8b 100644 --- a/src/tests/end2end/CopyTextureForBrowserTests.cpp +++ b/src/tests/end2end/CopyTextureForBrowserTests.cpp @@ -176,6 +176,66 @@ TEST_P(CopyTextureForBrowserTests, PassthroughCopy) { DoTest(textureSpec, textureSpec, {kWidth, kHeight, 1}); } +TEST_P(CopyTextureForBrowserTests, VerifyCopyOnXDirection) { + // These tests fails due to crbug.com/tint/63. + DAWN_SKIP_TEST_IF(IsSwiftshader()); + DAWN_SKIP_TEST_IF(IsVulkan()); + DAWN_SKIP_TEST_IF(IsD3D12() && IsBackendValidationEnabled()); + + // OpenGL tests fails due to 'WriteTexture' unimplemented. + // Related bug : crbug.com/dawn/483 + DAWN_SKIP_TEST_IF(IsOpenGL()); + + constexpr uint32_t kWidth = 1000; + constexpr uint32_t kHeight = 1; + + TextureSpec textureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.level = 0; + textureSpec.textureSize = {kWidth, kHeight, 1}; + DoTest(textureSpec, textureSpec, {kWidth, kHeight, 1}); +} + +TEST_P(CopyTextureForBrowserTests, VerifyCopyOnYDirection) { + // These tests fails due to crbug.com/tint/63. + DAWN_SKIP_TEST_IF(IsSwiftshader()); + DAWN_SKIP_TEST_IF(IsVulkan()); + DAWN_SKIP_TEST_IF(IsD3D12() && IsBackendValidationEnabled()); + + // OpenGL tests fails due to 'WriteTexture' unimplemented. + // Related bug : crbug.com/dawn/483 + DAWN_SKIP_TEST_IF(IsOpenGL()); + + constexpr uint32_t kWidth = 1; + constexpr uint32_t kHeight = 1000; + + TextureSpec textureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.level = 0; + textureSpec.textureSize = {kWidth, kHeight, 1}; + DoTest(textureSpec, textureSpec, {kWidth, kHeight, 1}); +} + +TEST_P(CopyTextureForBrowserTests, VerifyCopyFromLargeTexture) { + // These tests fails due to crbug.com/tint/63. + DAWN_SKIP_TEST_IF(IsSwiftshader()); + DAWN_SKIP_TEST_IF(IsVulkan()); + DAWN_SKIP_TEST_IF(IsD3D12() && IsBackendValidationEnabled()); + + // OpenGL tests fails due to 'WriteTexture' unimplemented. + // Related bug : crbug.com/dawn/483 + DAWN_SKIP_TEST_IF(IsOpenGL()); + + constexpr uint32_t kWidth = 899; + constexpr uint32_t kHeight = 999; + + TextureSpec textureSpec; + textureSpec.copyOrigin = {0, 0, 0}; + textureSpec.level = 0; + textureSpec.textureSize = {kWidth, kHeight, 1}; + DoTest(textureSpec, textureSpec, {kWidth, kHeight, 1}); +} + DAWN_INSTANTIATE_TEST(CopyTextureForBrowserTests, D3D12Backend(), MetalBackend(),