Fix a bug in ComputeTextureCopyBufferSize with empty copySize

This patch fixes a bug in buffer-to-texture and texture-to-buffer copies
when copySize.height == 0 or copySize.depth == 0. Previously we miss the
checks if either copySize.height or copySize.depth is 0 before doing
(copySize.height / blockHeight - 1) and (copySize.depth - 1) thus we
will get incorrect results because of arithmetic overflows.

This patch fixes this bug by adding the missed check and adds the
related regression tests in dawn_unittests

BUG=dawn:453
TEST=dawn_unittests

Change-Id: I970e420c0fa7f0b61c656365bef079c123a59e6a
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/23520
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
diff --git a/src/dawn_native/CommandEncoder.cpp b/src/dawn_native/CommandEncoder.cpp
index b79e350..5b8bc64 100644
--- a/src/dawn_native/CommandEncoder.cpp
+++ b/src/dawn_native/CommandEncoder.cpp
@@ -198,14 +198,23 @@
                                                 uint32_t rowsPerImage,
                                                 uint32_t* bufferSize) {
             ASSERT(rowsPerImage >= copySize.height);
+            if (copySize.width == 0 || copySize.height == 0 || copySize.depth == 0) {
+                *bufferSize = 0;
+                return {};
+            }
+
             uint32_t blockByteSize = textureFormat.blockByteSize;
             uint32_t blockWidth = textureFormat.blockWidth;
             uint32_t blockHeight = textureFormat.blockHeight;
 
             // TODO(cwallez@chromium.org): check for overflows
             uint32_t slicePitch = bytesPerRow * rowsPerImage / blockWidth;
+
+            ASSERT(copySize.height >= 1);
             uint32_t sliceSize = bytesPerRow * (copySize.height / blockHeight - 1) +
                                  (copySize.width / blockWidth) * blockByteSize;
+
+            ASSERT(copySize.depth >= 1);
             *bufferSize = (slicePitch * (copySize.depth - 1)) + sliceSize;
 
             return {};
diff --git a/src/tests/unittests/validation/CopyCommandsValidationTests.cpp b/src/tests/unittests/validation/CopyCommandsValidationTests.cpp
index 634dfb6..53e4bd4 100644
--- a/src/tests/unittests/validation/CopyCommandsValidationTests.cpp
+++ b/src/tests/unittests/validation/CopyCommandsValidationTests.cpp
@@ -364,6 +364,12 @@
         // An empty copy touching the side of the texture
         TestB2TCopy(utils::Expectation::Success, source, 0, 0, 0, destination, 0, {16, 16, 0},
                     {0, 0, 1});
+        // An empty copy with depth = 1 and bytesPerRow > 0
+        TestB2TCopy(utils::Expectation::Success, source, 0, kTextureBytesPerRowAlignment, 0,
+                    destination, 0, {0, 0, 0}, {0, 0, 1});
+        // An empty copy with height > 0, depth = 0, bytesPerRow > 0 and rowsPerImage > 0
+        TestB2TCopy(utils::Expectation::Success, source, 0, kTextureBytesPerRowAlignment, 16,
+                    destination, 0, {0, 0, 0}, {0, 1, 0});
     }
 }