Changing validation order for linear texture data

Changed the order of validation blocks in ValidateLinearTextureData.
It doesn't match the order in spec now, but for the algorithm to
compute required bytes in copy we need the conditions which come
after the ones relating to it. Also switched the order of
ValidateLinearTextureData and ValidateTextureCopyRange for similar
reasons.

Bug: dawn:483
Change-Id: If00ae769d170ea12494258721916ec55d79e2880
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/25041
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn_native/CommandEncoder.cpp b/src/dawn_native/CommandEncoder.cpp
index da99bbd..1a387b7 100644
--- a/src/dawn_native/CommandEncoder.cpp
+++ b/src/dawn_native/CommandEncoder.cpp
@@ -656,9 +656,13 @@
                 DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst));
                 DAWN_TRY(ValidateTextureSampleCountInCopyCommands(destination->texture));
 
+                // We validate texture copy range before validating linear texture data,
+                // because in the latter we divide copyExtent.width by blockWidth and
+                // copyExtent.height by blockHeight while the divisibility conditions are
+                // checked in validating texture copy range.
+                DAWN_TRY(ValidateTextureCopyRange(*destination, *copySize));
                 DAWN_TRY(ValidateLinearTextureData(source->layout, source->buffer->GetSize(),
                                                    destination->texture->GetFormat(), *copySize));
-                DAWN_TRY(ValidateTextureCopyRange(*destination, *copySize));
 
                 mTopLevelBuffers.insert(source->buffer);
                 mTopLevelTextures.insert(destination->texture);
@@ -709,10 +713,14 @@
                 DAWN_TRY(ValidateBufferCopyView(GetDevice(), *destination));
                 DAWN_TRY(ValidateCanUseAs(destination->buffer, wgpu::BufferUsage::CopyDst));
 
+                // We validate texture copy range before validating linear texture data,
+                // because in the latter we divide copyExtent.width by blockWidth and
+                // copyExtent.height by blockHeight while the divisibility conditions are
+                // checked in validating texture copy range.
+                DAWN_TRY(ValidateTextureCopyRange(*source, *copySize));
                 DAWN_TRY(ValidateLinearTextureData(destination->layout,
                                                    destination->buffer->GetSize(),
                                                    source->texture->GetFormat(), *copySize));
-                DAWN_TRY(ValidateTextureCopyRange(*source, *copySize));
 
                 mTopLevelTextures.insert(source->texture);
                 mTopLevelBuffers.insert(destination->buffer);
diff --git a/src/dawn_native/CommandValidation.cpp b/src/dawn_native/CommandValidation.cpp
index db8714c..11a363a 100644
--- a/src/dawn_native/CommandValidation.cpp
+++ b/src/dawn_native/CommandValidation.cpp
@@ -410,11 +410,23 @@
                                          uint64_t byteSize,
                                          const Format& format,
                                          const Extent3D& copyExtent) {
+        // Validation for the texel block alignments:
+        if (layout.rowsPerImage % format.blockHeight != 0) {
+            return DAWN_VALIDATION_ERROR(
+                "rowsPerImage must be a multiple of compressed texture format block height");
+        }
+
+        if (layout.offset % format.blockByteSize != 0) {
+            return DAWN_VALIDATION_ERROR("Offset must be a multiple of the texel or block size");
+        }
+
         // Validation for the copy being in-bounds:
         if (layout.rowsPerImage != 0 && layout.rowsPerImage < copyExtent.height) {
             return DAWN_VALIDATION_ERROR("rowsPerImage must not be less than the copy height.");
         }
 
+        // We compute required bytes in copy after validating texel block alignments
+        // because the divisibility conditions are necessary for the algorithm to be valid.
         // TODO(tommek@google.com): to match the spec this should only be checked when
         // copyExtent.depth > 1.
         uint32_t requiredBytesInCopy =
@@ -427,16 +439,6 @@
                 "Required size for texture data layout exceeds the given size");
         }
 
-        // Validation for the texel block alignments:
-        if (layout.rowsPerImage % format.blockHeight != 0) {
-            return DAWN_VALIDATION_ERROR(
-                "rowsPerImage must be a multiple of compressed texture format block height");
-        }
-
-        if (layout.offset % format.blockByteSize != 0) {
-            return DAWN_VALIDATION_ERROR("Offset must be a multiple of the texel or block size");
-        }
-
         // Validation for other members in layout:
         if (layout.bytesPerRow < copyExtent.width / format.blockWidth * format.blockByteSize) {
             return DAWN_VALIDATION_ERROR(
diff --git a/src/dawn_native/Queue.cpp b/src/dawn_native/Queue.cpp
index 9ac92f3..efc7167 100644
--- a/src/dawn_native/Queue.cpp
+++ b/src/dawn_native/Queue.cpp
@@ -270,9 +270,13 @@
             return DAWN_VALIDATION_ERROR("The sample count of textures must be 1");
         }
 
+        // We validate texture copy range before validating linear texture data,
+        // because in the latter we divide copyExtent.width by blockWidth and
+        // copyExtent.height by blockHeight while the divisibility conditions are
+        // checked in validating texture copy range.
+        DAWN_TRY(ValidateTextureCopyRange(*destination, *writeSize));
         DAWN_TRY(ValidateLinearTextureData(*dataLayout, dataSize, destination->texture->GetFormat(),
                                            *writeSize));
-        DAWN_TRY(ValidateTextureCopyRange(*destination, *writeSize));
 
         return {};
     }