Add natural size in imageCopyExternalTexture

CopyExternalTextureForBrowser() uses external texture visible rect
as source size in previous.

But video frame natural size is the only one developer could get
from HTMLVideoElement and it means the size browser present video
on screen.

This CL add "natural size" in imageCopyExternalTexture and uses this
size as CopyExternalTextureForBrowser() source size.

Bug:dawn:1694

Change-Id: I2a3bfa8e689df11d1d13320d40ad02c7090425e5
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/123380
Commit-Queue: Shaobo Yan <shaobo.yan@intel.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/dawn.json b/dawn.json
index 9306d64..1df0d7c 100644
--- a/dawn.json
+++ b/dawn.json
@@ -1508,7 +1508,8 @@
         "tags": ["dawn"],
         "members": [
             {"name": "external texture", "type": "external texture"},
-            {"name": "origin", "type": "origin 3D"}
+            {"name": "origin", "type": "origin 3D"},
+            {"name": "natural size", "type": "extent 2D"}
         ]
     },
     "index format": {
diff --git a/src/dawn/native/CopyTextureForBrowserHelper.cpp b/src/dawn/native/CopyTextureForBrowserHelper.cpp
index 326d08e..f22ce31 100644
--- a/src/dawn/native/CopyTextureForBrowserHelper.cpp
+++ b/src/dawn/native/CopyTextureForBrowserHelper.cpp
@@ -694,18 +694,27 @@
     DAWN_TRY(device->ValidateObject(source->externalTexture));
     DAWN_TRY(source->externalTexture->ValidateCanUseInSubmitNow());
 
-    const Extent2D& sourceVisibleSize = source->externalTexture->GetVisibleSize();
+    Extent2D sourceSize;
+
+    // TODO(crbug.com/dawn/1694): Remove this workaround that use visible rect
+    // if natural size it not set after chromium side changes ready.
+    if (source->naturalSize.width == 0) {
+        sourceSize = source->externalTexture->GetVisibleSize();
+    } else {
+        sourceSize.width = source->naturalSize.width;
+        sourceSize.height = source->naturalSize.height;
+    }
 
     // All texture dimensions are in uint32_t so by doing checks in uint64_t we avoid
     // overflows.
     DAWN_INVALID_IF(
         static_cast<uint64_t>(source->origin.x) + static_cast<uint64_t>(copySize->width) >
-                static_cast<uint64_t>(sourceVisibleSize.width) ||
+                static_cast<uint64_t>(sourceSize.width) ||
             static_cast<uint64_t>(source->origin.y) + static_cast<uint64_t>(copySize->height) >
-                static_cast<uint64_t>(sourceVisibleSize.height) ||
+                static_cast<uint64_t>(sourceSize.height) ||
             static_cast<uint64_t>(source->origin.z) > 0,
-        "Texture copy range (origin: %s, copySize: %s) touches outside of %s visible size (%s).",
-        &source->origin, copySize, source->externalTexture, &sourceVisibleSize);
+        "Texture copy range (origin: %s, copySize: %s) touches outside of %s source size (%s).",
+        &source->origin, copySize, source->externalTexture, &sourceSize);
     DAWN_INVALID_IF(source->origin.z > 0, "Source has a non-zero z origin (%u).", source->origin.z);
     DAWN_INVALID_IF(
         options->internalUsage && !device->HasFeature(Feature::DawnInternalUsages),
@@ -731,8 +740,14 @@
                                            const CopyTextureForBrowserOptions* options) {
     TextureInfo info;
     info.origin = source->origin;
-    const Extent2D& visibleSize = source->externalTexture->GetVisibleSize();
-    info.size = {visibleSize.width, visibleSize.height, 1};
+    info.size = {source->naturalSize.width, source->naturalSize.height, 1};
+
+    // TODO(crbug.com/dawn/1694): Remove this workaround that use visible rect
+    // if natural size it not set after chromium side changes ready.
+    if (info.size.width == 0) {
+        const Extent2D& visibleSize = source->externalTexture->GetVisibleSize();
+        info.size = {visibleSize.width, visibleSize.height, 1};
+    }
 
     RenderPipelineBase* pipeline;
     DAWN_TRY_ASSIGN(pipeline, GetOrCreateCopyExternalTextureForBrowserPipeline(
diff --git a/src/dawn/tests/end2end/CopyExternalTextureForBrowserTests.cpp b/src/dawn/tests/end2end/CopyExternalTextureForBrowserTests.cpp
index 3bcdc33..f27bb27 100644
--- a/src/dawn/tests/end2end/CopyExternalTextureForBrowserTests.cpp
+++ b/src/dawn/tests/end2end/CopyExternalTextureForBrowserTests.cpp
@@ -40,7 +40,7 @@
 static constexpr uint32_t kWidth = 4;
 static constexpr uint32_t kHeight = 4;
 
-std::array<std::array<utils::RGBA8, 4>, 4> kDefaultSourceRGBA = {
+std::array<std::array<utils::RGBA8, 4>, 4> kDefaultExpectedRGBA = {
     std::array<utils::RGBA8, 4>(
         {utils::RGBA8::kBlack, utils::RGBA8::kBlack, utils::RGBA8::kRed, utils::RGBA8::kRed}),
     std::array<utils::RGBA8, 4>(
@@ -50,6 +50,36 @@
     std::array<utils::RGBA8, 4>(
         {utils::RGBA8::kGreen, utils::RGBA8::kGreen, utils::RGBA8::kBlue, utils::RGBA8::kBlue})};
 
+std::array<std::array<utils::RGBA8, 2>, 2> kDownScaledExpectedRGBA = {
+    std::array<utils::RGBA8, 2>({utils::RGBA8::kBlack, utils::RGBA8::kRed}),
+    std::array<utils::RGBA8, 2>({utils::RGBA8::kGreen, utils::RGBA8::kBlue})};
+
+std::array<std::array<utils::RGBA8, 8>, 8> kUpScaledExpectedRGBA = {
+    std::array<utils::RGBA8, 8>({utils::RGBA8::kBlack, utils::RGBA8::kBlack, utils::RGBA8::kBlack,
+                                 utils::RGBA8::kBlack, utils::RGBA8::kRed, utils::RGBA8::kRed,
+                                 utils::RGBA8::kRed, utils::RGBA8::kRed}),
+    std::array<utils::RGBA8, 8>({utils::RGBA8::kBlack, utils::RGBA8::kBlack, utils::RGBA8::kBlack,
+                                 utils::RGBA8::kBlack, utils::RGBA8::kRed, utils::RGBA8::kRed,
+                                 utils::RGBA8::kRed, utils::RGBA8::kRed}),
+    std::array<utils::RGBA8, 8>({utils::RGBA8::kBlack, utils::RGBA8::kBlack, utils::RGBA8::kBlack,
+                                 utils::RGBA8::kBlack, utils::RGBA8::kRed, utils::RGBA8::kRed,
+                                 utils::RGBA8::kRed, utils::RGBA8::kRed}),
+    std::array<utils::RGBA8, 8>({utils::RGBA8::kBlack, utils::RGBA8::kBlack, utils::RGBA8::kBlack,
+                                 utils::RGBA8::kBlack, utils::RGBA8::kRed, utils::RGBA8::kRed,
+                                 utils::RGBA8::kRed, utils::RGBA8::kRed}),
+    std::array<utils::RGBA8, 8>({utils::RGBA8::kGreen, utils::RGBA8::kGreen, utils::RGBA8::kGreen,
+                                 utils::RGBA8::kGreen, utils::RGBA8::kBlue, utils::RGBA8::kBlue,
+                                 utils::RGBA8::kBlue, utils::RGBA8::kBlue}),
+    std::array<utils::RGBA8, 8>({utils::RGBA8::kGreen, utils::RGBA8::kGreen, utils::RGBA8::kGreen,
+                                 utils::RGBA8::kGreen, utils::RGBA8::kBlue, utils::RGBA8::kBlue,
+                                 utils::RGBA8::kBlue, utils::RGBA8::kBlue}),
+    std::array<utils::RGBA8, 8>({utils::RGBA8::kGreen, utils::RGBA8::kGreen, utils::RGBA8::kGreen,
+                                 utils::RGBA8::kGreen, utils::RGBA8::kBlue, utils::RGBA8::kBlue,
+                                 utils::RGBA8::kBlue, utils::RGBA8::kBlue}),
+    std::array<utils::RGBA8, 8>({utils::RGBA8::kGreen, utils::RGBA8::kGreen, utils::RGBA8::kGreen,
+                                 utils::RGBA8::kGreen, utils::RGBA8::kBlue, utils::RGBA8::kBlue,
+                                 utils::RGBA8::kBlue, utils::RGBA8::kBlue})};
+
 template <typename Parent>
 class CopyExternalTextureForBrowserTests : public Parent {
   protected:
@@ -123,9 +153,10 @@
         return this->device.CreateExternalTexture(&externalDesc);
     }
 
-    std::vector<utils::RGBA8> GetDefaultExpectedData(bool flipY,
-                                                     wgpu::Origin3D srcOrigin,
-                                                     wgpu::Extent3D rect) {
+    std::vector<utils::RGBA8> GetExpectedData(bool flipY,
+                                              wgpu::Origin3D srcOrigin,
+                                              wgpu::Extent3D rect,
+                                              wgpu::Extent2D naturalSize) {
         std::vector<utils::RGBA8> expected;
         for (uint32_t rowInRect = 0; rowInRect < rect.height; ++rowInRect) {
             for (uint32_t colInRect = 0; colInRect < rect.width; ++colInRect) {
@@ -136,7 +167,14 @@
                     row = (rect.height - rowInRect - 1) + srcOrigin.y;
                 }
 
-                expected.push_back(kDefaultSourceRGBA[row][col]);
+                // Upscale case
+                if (naturalSize.width > kWidth) {
+                    expected.push_back(kUpScaledExpectedRGBA[row][col]);
+                } else if (naturalSize.width < kWidth) {
+                    expected.push_back(kDownScaledExpectedRGBA[row][col]);
+                } else {
+                    expected.push_back(kDefaultExpectedRGBA[row][col]);
+                }
             }
         }
 
@@ -144,16 +182,67 @@
     }
 };
 
-using FlipY = bool;
-using SrcOrigin = wgpu::Origin3D;
-using DstOrigin = wgpu::Origin3D;
+enum class CopyRect {
+    TopLeft,
+    TopRight,
+    BottomLeft,
+    BottomRight,
+    FullSize,
+};
 
-std::ostream& operator<<(std::ostream& o, wgpu::Origin3D origin) {
-    o << origin.x << ", " << origin.y << ", " << origin.z;
+enum class ScaleType {
+    UpScale,
+    DownScale,
+    NoScale,
+};
+
+using FlipY = bool;
+using CopySrcRect = CopyRect;
+using CopyDstRect = CopyRect;
+
+std::ostream& operator<<(std::ostream& o, ScaleType scaleType) {
+    switch (scaleType) {
+        case ScaleType::UpScale:
+            o << "UpScale";
+            break;
+        case ScaleType::DownScale:
+            o << "DownScale";
+            break;
+        case ScaleType::NoScale:
+            o << "DefaultSize";
+            break;
+        default:
+            UNREACHABLE();
+            break;
+    }
     return o;
 }
 
-DAWN_TEST_PARAM_STRUCT(CopyTestParams, SrcOrigin, DstOrigin, FlipY);
+std::ostream& operator<<(std::ostream& o, CopyRect copyRect) {
+    switch (copyRect) {
+        case CopyRect::TopLeft:
+            o << "TopLeftCopy";
+            break;
+        case CopyRect::TopRight:
+            o << "TopRightCopy";
+            break;
+        case CopyRect::BottomLeft:
+            o << "BottomLeftCopy";
+            break;
+        case CopyRect::BottomRight:
+            o << "BottomRightCopy";
+            break;
+        case CopyRect::FullSize:
+            o << "FullSizeCopy";
+            break;
+        default:
+            UNREACHABLE();
+            break;
+    }
+    return o;
+}
+
+DAWN_TEST_PARAM_STRUCT(CopyTestParams, CopySrcRect, CopyDstRect, ScaleType, FlipY);
 
 class CopyExternalTextureForBrowserTests_Basic
     : public CopyExternalTextureForBrowserTests<DawnTestWithParams<CopyTestParams>> {
@@ -161,23 +250,27 @@
     void DoBasicCopyTest(const wgpu::Origin3D& srcOrigin,
                          const wgpu::Origin3D& dstOrigin,
                          const wgpu::Extent3D& copySize,
+                         const wgpu::Extent2D& naturalSize,
+                         const wgpu::Extent3D& dstTextureSize,
                          const wgpu::CopyTextureForBrowserOptions options = {}) {
         wgpu::ExternalTexture externalTexture = CreateDefaultExternalTexture();
         wgpu::ImageCopyExternalTexture srcImageCopyExternalTexture;
         srcImageCopyExternalTexture.externalTexture = externalTexture;
         srcImageCopyExternalTexture.origin = srcOrigin;
+        srcImageCopyExternalTexture.naturalSize = naturalSize;
 
-        wgpu::Texture dstTexture =
-            Create2DTexture(device, kWidth, kHeight, wgpu::TextureFormat::RGBA8Unorm,
-                            wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc |
-                                wgpu::TextureUsage::CopyDst);
+        wgpu::Texture dstTexture = Create2DTexture(
+            device, dstTextureSize.width, dstTextureSize.height, wgpu::TextureFormat::RGBA8Unorm,
+            wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc |
+                wgpu::TextureUsage::CopyDst);
         wgpu::ImageCopyTexture dstImageCopyTexture =
             utils::CreateImageCopyTexture(dstTexture, 0, dstOrigin);
 
         queue.CopyExternalTextureForBrowser(&srcImageCopyExternalTexture, &dstImageCopyTexture,
                                             &copySize, &options);
-        std::vector<utils::RGBA8> expected =
-            GetDefaultExpectedData(options.flipY, srcOrigin, copySize);
+
+        std::vector<utils::RGBA8> expected = GetExpectedData(
+            options.flipY, srcImageCopyExternalTexture.origin, copySize, naturalSize);
 
         EXPECT_TEXTURE_EQ(expected.data(), dstTexture, dstOrigin, copySize);
     }
@@ -191,22 +284,104 @@
     wgpu::CopyTextureForBrowserOptions options = {};
     options.flipY = GetParam().mFlipY;
 
-    wgpu::Origin3D srcOrigin = GetParam().mSrcOrigin;
-    wgpu::Origin3D dstOrigin = GetParam().mDstOrigin;
+    CopyRect srcCopyRect = GetParam().mCopySrcRect;
+    CopyRect dstCopyRect = GetParam().mCopyDstRect;
+    ScaleType scaleType = GetParam().mScaleType;
 
-    wgpu::Extent3D copySize = {kWidth, kHeight};
+    // Test skip due to crbug.com/dawn/1719
+    DAWN_SUPPRESS_TEST_IF(IsWARP() && srcCopyRect != CopyRect::TopLeft &&
+                          srcCopyRect != CopyRect::FullSize && dstCopyRect != CopyRect::TopLeft &&
+                          dstCopyRect != CopyRect::FullSize && scaleType == ScaleType::DownScale);
 
-    if (srcOrigin.x != 0 || srcOrigin.y != 0 || dstOrigin.x != 0 || dstOrigin.y != 0) {
-        copySize.width = kWidth / 2;
-        copySize.height = kHeight / 2;
+    float scaleFactor = 1.0;
+
+    switch (scaleType) {
+        case ScaleType::UpScale:
+            scaleFactor = 2.0;
+            break;
+        case ScaleType::DownScale:
+            scaleFactor = 0.5;
+            break;
+        case ScaleType::NoScale:
+            break;
+        default:
+            UNREACHABLE();
+            break;
     }
 
-    DoBasicCopyTest(srcOrigin, dstOrigin, copySize, options);
+    float defaultWidth = static_cast<float>(kWidth);
+    float defaultHeight = static_cast<float>(kHeight);
+    wgpu::Extent2D naturalSize = {static_cast<uint32_t>(defaultWidth * scaleFactor),
+                                  static_cast<uint32_t>(defaultHeight * scaleFactor)};
+
+    wgpu::Origin3D srcOrigin = {};
+    wgpu::Origin3D dstOrigin = {};
+
+    // Set copy size to sub rect copy size.
+    wgpu::Extent3D copySize = {naturalSize.width / 2, naturalSize.height / 2};
+    switch (srcCopyRect) {
+        // origin = {0, 0};
+        case CopyRect::TopLeft:
+            break;
+        case CopyRect::TopRight:
+            srcOrigin.x = naturalSize.width / 2;
+            srcOrigin.y = 0;
+            break;
+        case CopyRect::BottomLeft:
+            srcOrigin.x = 0;
+            srcOrigin.y = naturalSize.height / 2;
+            break;
+        case CopyRect::BottomRight:
+            srcOrigin.x = naturalSize.width / 2;
+            srcOrigin.y = naturalSize.height / 2;
+            break;
+
+        // origin = {0, 0}, copySize = naturalSize
+        case CopyRect::FullSize:
+            copySize.width = naturalSize.width;
+            copySize.height = naturalSize.height;
+            break;
+        default:
+            UNREACHABLE();
+            break;
+    }
+
+    wgpu::Extent3D dstTextureSize = {copySize.width * 2, copySize.height * 2};
+    switch (dstCopyRect) {
+        case CopyRect::TopLeft:
+            break;
+        case CopyRect::TopRight:
+            dstOrigin.x = dstTextureSize.width / 2;
+            dstOrigin.y = 0;
+            break;
+        case CopyRect::BottomLeft:
+            dstOrigin.x = 0;
+            dstOrigin.y = dstTextureSize.height / 2;
+            break;
+        case CopyRect::BottomRight:
+            dstOrigin.x = dstTextureSize.width / 2;
+            dstOrigin.y = dstTextureSize.height / 2;
+            break;
+        case CopyRect::FullSize:
+            if (srcCopyRect != CopyRect::FullSize) {
+                dstTextureSize.width = copySize.width;
+                dstTextureSize.height = copySize.height;
+            }
+            break;
+        default:
+            UNREACHABLE();
+            break;
+    }
+
+    DoBasicCopyTest(srcOrigin, dstOrigin, copySize, naturalSize, dstTextureSize, options);
 }
 
-DAWN_INSTANTIATE_TEST_P(CopyExternalTextureForBrowserTests_Basic,
-                        {D3D12Backend(), MetalBackend(), OpenGLBackend(), OpenGLESBackend(),
-                         VulkanBackend()},
-                        std::vector<wgpu::Origin3D>({{0, 0}, {2, 0}, {0, 2}, {2, 2}}),
-                        std::vector<wgpu::Origin3D>({{0, 0}, {2, 0}, {0, 2}, {2, 2}}),
-                        std::vector<bool>({false, true}));
+DAWN_INSTANTIATE_TEST_P(
+    CopyExternalTextureForBrowserTests_Basic,
+    {D3D12Backend(), MetalBackend(), OpenGLBackend(), OpenGLESBackend(), VulkanBackend()},
+    std::vector<CopyRect>({CopyRect::TopLeft, CopyRect::TopRight, CopyRect::BottomLeft,
+                           CopyRect::BottomRight, CopyRect::FullSize}),
+    std::vector<CopyRect>({CopyRect::TopLeft, CopyRect::TopRight, CopyRect::BottomLeft,
+                           CopyRect::BottomRight, CopyRect::FullSize}),
+    std::vector<ScaleType>({ScaleType::UpScale, ScaleType::DownScale, ScaleType::NoScale}),
+    std::vector<FlipY>({false, true}));
diff --git a/src/dawn/tests/unittests/validation/CopyTextureForBrowserTests.cpp b/src/dawn/tests/unittests/validation/CopyTextureForBrowserTests.cpp
index e28dfc4..6c677db 100644
--- a/src/dawn/tests/unittests/validation/CopyTextureForBrowserTests.cpp
+++ b/src/dawn/tests/unittests/validation/CopyTextureForBrowserTests.cpp
@@ -115,6 +115,7 @@
     void TestCopyExternalTextureForBrowser(utils::Expectation expectation,
                                            wgpu::ExternalTexture srcExternalTexture,
                                            wgpu::Origin3D srcOrigin,
+                                           wgpu::Extent2D srcNaturalSize,
                                            wgpu::Texture dstTexture,
                                            uint32_t dstLevel,
                                            wgpu::Origin3D dstOrigin,
@@ -124,6 +125,7 @@
         wgpu::ImageCopyExternalTexture srcImageCopyExternalTexture;
         srcImageCopyExternalTexture.externalTexture = srcExternalTexture;
         srcImageCopyExternalTexture.origin = srcOrigin;
+        srcImageCopyExternalTexture.naturalSize = srcNaturalSize;
 
         wgpu::ImageCopyTexture dstImageCopyTexture =
             utils::CreateImageCopyTexture(dstTexture, dstLevel, dstOrigin, aspect);
@@ -528,42 +530,42 @@
     // Different copies, including some that touch the OOB condition
     {
         // Copy a region along top left boundary
-        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 0}, {4, 4, 1});
 
         // Copy entire texture
-        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 0}, {16, 16, 1});
 
         // Copy a region along bottom right boundary
-        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {8, 8, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {8, 8, 0}, {16, 16},
                                           destination, 0, {8, 8, 0}, {8, 8, 1});
 
         // Copy region into mip
-        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, {16, 16},
                                           destination, 2, {0, 0, 0}, {4, 4, 1});
 
         // Copy between slices
-        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 1}, {16, 16, 1});
     }
 
     // Empty copies are valid
     {
         // An empty copy
-        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 0}, {0, 0, 1});
 
         // An empty copy with depth = 0
-        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 0}, {0, 0, 0});
 
         // An empty copy touching the side of the source texture
-        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {16, 16, 0}, {0, 0, 1});
 
         // An empty copy touching the side of the destination texture
-        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {16, 16, 0}, {0, 0, 1});
     }
 }
@@ -582,12 +584,12 @@
                         wgpu::TextureUsage::RenderAttachment);
 
     // Incorrect destination usage causes failure: lack |RenderAttachement| usage.
-    TestCopyExternalTextureForBrowser(utils::Expectation::Failure, validSource, {0, 0, 0},
+    TestCopyExternalTextureForBrowser(utils::Expectation::Failure, validSource, {0, 0, 0}, {16, 16},
                                       noRenderAttachmentUsageDestination, 0, {0, 0, 0},
                                       {16, 16, 1});
 
     // Incorrect destination usage causes failure: lack |CopyDst| usage.
-    TestCopyExternalTextureForBrowser(utils::Expectation::Failure, validSource, {0, 0, 0},
+    TestCopyExternalTextureForBrowser(utils::Expectation::Failure, validSource, {0, 0, 0}, {16, 16},
                                       noCopyDstUsageSource, 0, {0, 0, 0}, {16, 16, 1});
 }
 
@@ -601,12 +603,12 @@
         wgpu::Texture destination =
             Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
                             wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
-        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 0}, {4, 4, 1},
                                           wgpu::TextureAspect::All, options);
 
         // Check noop copy
-        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 0}, {0, 0, 0},
                                           wgpu::TextureAspect::All, options);
     }
@@ -618,12 +620,12 @@
             Create2DTexture(device, 16, 16, 5, 4, wgpu::TextureFormat::RGBA8Unorm,
                             wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
         source.Destroy();
-        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 0}, {4, 4, 1},
                                           wgpu::TextureAspect::All, options);
 
         // Check noop copy
-        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 0}, {0, 0, 0},
                                           wgpu::TextureAspect::All, options);
     }
@@ -636,12 +638,12 @@
                             wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
 
         destination.Destroy();
-        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 0}, {4, 4, 1},
                                           wgpu::TextureAspect::All, options);
 
         // Check noop copy
-        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 0}, {0, 0, 0},
                                           wgpu::TextureAspect::All, options);
     }
@@ -657,46 +659,46 @@
     // OOB on source
     {
         // x + width overflows
-        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {1, 0, 0},
-                                          destination, 0, {0, 0, 0}, {16, 16, 1});
+        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {1, 0, 0}, {4, 4},
+                                          destination, 0, {0, 0, 0}, {4, 4, 1});
 
         // y + height overflows
-        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 1, 0},
-                                          destination, 0, {0, 0, 0}, {16, 16, 1});
+        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 1, 0}, {4, 4},
+                                          destination, 0, {0, 0, 0}, {4, 4, 1});
 
         // copy to multiple slices
-        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
-                                          destination, 0, {0, 0, 2}, {16, 16, 2});
+        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {4, 4},
+                                          destination, 0, {0, 0, 2}, {4, 4, 2});
 
         // copy origin z value is non-zero.
-        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 1},
-                                          destination, 0, {0, 0, 2}, {16, 16, 1});
+        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 1}, {4, 4},
+                                          destination, 0, {0, 0, 2}, {4, 4, 1});
     }
 
     // OOB on destination
     {
         // x + width overflows
-        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {1, 0, 0}, {16, 16, 1});
 
         // y + height overflows
-        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 1, 0}, {16, 16, 1});
 
         // non-zero mip overflows
-        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
                                           destination, 1, {0, 0, 0}, {9, 9, 1});
 
         // arrayLayer + depth OOB
-        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 4}, {16, 16, 1});
 
         // empty copy on non-existent mip fails
-        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
                                           destination, 6, {0, 0, 0}, {0, 0, 1});
 
         // empty copy on non-existent slice fails
-        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 4}, {0, 0, 1});
     }
 }
@@ -709,8 +711,8 @@
                         wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment);
 
     // Not supported dst texture format.
-    TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, destination,
-                                      0, {0, 0, 0}, {0, 0, 1});
+    TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
+                                      destination, 0, {0, 0, 0}, {0, 0, 1});
 }
 
 // Test destination texture are multisampled.
@@ -721,7 +723,7 @@
                         wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::RenderAttachment, 4);
 
     // An empty copy with dst texture sample count > 1 failure.
-    TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
+    TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
                                       destinationMultiSampled4x, 0, {0, 0, 0}, {0, 0, 1});
 }
 
@@ -744,14 +746,14 @@
         validOptions.srcTransferFunctionParameters = srcTransferFunctionParameters.data();
         validOptions.dstTransferFunctionParameters = dstTransferFunctionParameters.data();
         validOptions.conversionMatrix = conversionMatrix.data();
-        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 0}, {4, 4, 1},
                                           wgpu::TextureAspect::All, validOptions);
 
         // if no color space conversion, no need to validate related attributes
         wgpu::CopyTextureForBrowserOptions noColorSpaceConversion = options;
         noColorSpaceConversion.needsColorSpaceConversion = false;
-        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 0}, {4, 4, 1},
                                           wgpu::TextureAspect::All, noColorSpaceConversion);
     }
@@ -765,13 +767,13 @@
         std::array<float, 9> conversionMatrix = {};
         invalidOptions.dstTransferFunctionParameters = dstTransferFunctionParameters.data();
         invalidOptions.conversionMatrix = conversionMatrix.data();
-        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 0}, {4, 4, 1},
                                           wgpu::TextureAspect::All, invalidOptions);
 
         // set to nullptr
         invalidOptions.srcTransferFunctionParameters = nullptr;
-        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 0}, {4, 4, 1},
                                           wgpu::TextureAspect::All, invalidOptions);
     }
@@ -783,13 +785,13 @@
         std::array<float, 9> conversionMatrix = {};
         invalidOptions.srcTransferFunctionParameters = srcTransferFunctionParameters.data();
         invalidOptions.conversionMatrix = conversionMatrix.data();
-        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 0}, {4, 4, 1},
                                           wgpu::TextureAspect::All, invalidOptions);
 
         // set to nullptr
         invalidOptions.dstTransferFunctionParameters = nullptr;
-        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 0}, {4, 4, 1},
                                           wgpu::TextureAspect::All, invalidOptions);
     }
@@ -801,13 +803,13 @@
         std::array<float, 7> dstTransferFunctionParameters = {};
         invalidOptions.srcTransferFunctionParameters = srcTransferFunctionParameters.data();
         invalidOptions.dstTransferFunctionParameters = dstTransferFunctionParameters.data();
-        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 0}, {4, 4, 1},
                                           wgpu::TextureAspect::All, invalidOptions);
 
         // set to nullptr
         invalidOptions.conversionMatrix = nullptr;
-        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 0}, {4, 4, 1},
                                           wgpu::TextureAspect::All, invalidOptions);
     }
@@ -827,28 +829,28 @@
         options.srcAlphaMode = wgpu::AlphaMode::Premultiplied;
         options.dstAlphaMode = wgpu::AlphaMode::Premultiplied;
 
-        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 0}, {4, 4, 1},
                                           wgpu::TextureAspect::All, options);
 
         options.srcAlphaMode = wgpu::AlphaMode::Premultiplied;
         options.dstAlphaMode = wgpu::AlphaMode::Unpremultiplied;
 
-        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 0}, {4, 4, 1},
                                           wgpu::TextureAspect::All, options);
 
         options.srcAlphaMode = wgpu::AlphaMode::Unpremultiplied;
         options.dstAlphaMode = wgpu::AlphaMode::Premultiplied;
 
-        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 0}, {4, 4, 1},
                                           wgpu::TextureAspect::All, options);
 
         options.srcAlphaMode = wgpu::AlphaMode::Unpremultiplied;
         options.dstAlphaMode = wgpu::AlphaMode::Unpremultiplied;
 
-        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0},
+        TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, {16, 16},
                                           destination, 0, {0, 0, 0}, {4, 4, 1},
                                           wgpu::TextureAspect::All, options);
     }
@@ -926,8 +928,9 @@
     // usage option is on
     wgpu::CopyTextureForBrowserOptions options = {};
     options.internalUsage = true;
-    TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, destination,
-                                      0, {0, 0, 0}, {16, 16, 1}, wgpu::TextureAspect::All, options);
+    TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
+                                      destination, 0, {0, 0, 0}, {16, 16, 1},
+                                      wgpu::TextureAspect::All, options);
 }
 
 // Test that the internal usages are taken into account when interalUsage = true
@@ -941,12 +944,13 @@
                         wgpu::TextureUsage::CopyDst, 1, &internalDesc);
 
     // Without internal usage option should fail usage validation
-    TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, destination,
-                                      0, {0, 0, 0}, {16, 16, 1});
+    TestCopyExternalTextureForBrowser(utils::Expectation::Failure, source, {0, 0, 0}, {16, 16},
+                                      destination, 0, {0, 0, 0}, {16, 16, 1});
 
     // With internal usage option should pass usage validation
     wgpu::CopyTextureForBrowserOptions options = {};
     options.internalUsage = true;
-    TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, destination,
-                                      0, {0, 0, 0}, {16, 16, 1}, wgpu::TextureAspect::All, options);
+    TestCopyExternalTextureForBrowser(utils::Expectation::Success, source, {0, 0, 0}, {16, 16},
+                                      destination, 0, {0, 0, 0}, {16, 16, 1},
+                                      wgpu::TextureAspect::All, options);
 }