Rephrasing CopyBufferToTexture validation

Moved some of the validation helper functions from CommandEncoder.cpp
to CommandValidation.cpp. This will make them accessible for
Queue::WriteTexture. Also introduced ValidateLinearTextureData
and ValidateTextureCopyRange which combine already implemented
checks in a way that's defined in WebGPU spec.

Bug: dawn:483
Change-Id: I04304c5e4906f3745c6adf75758fae179c6ffcfe
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/24283
Commit-Queue: Tomek Ponitka <tommek@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/dawn.json b/dawn.json
index 69eb5b4..1d900cb 100644
--- a/dawn.json
+++ b/dawn.json
@@ -1536,6 +1536,15 @@
             {"name": "origin", "type": "origin 3D"}
         ]
     },
+    "texture data layout": {
+        "category": "structure",
+        "extensible": true,
+        "members": [
+            {"name": "offset", "type": "uint64_t", "default": 0},
+            {"name": "bytes per row", "type": "uint32_t"},
+            {"name": "rows per image", "type": "uint32_t", "default": 0}
+        ]
+    },
     "texture descriptor": {
         "category": "structure",
         "extensible": true,
diff --git a/src/dawn_native/CommandEncoder.cpp b/src/dawn_native/CommandEncoder.cpp
index 23e2403..dab2c16 100644
--- a/src/dawn_native/CommandEncoder.cpp
+++ b/src/dawn_native/CommandEncoder.cpp
@@ -38,55 +38,6 @@
 
     namespace {
 
-        // TODO(jiawei.shao@intel.com): add validations on the texture-to-texture copies within the
-        // same texture.
-        MaybeError ValidateCopySizeFitsInTexture(const TextureCopyView& textureCopy,
-                                                 const Extent3D& copySize) {
-            const TextureBase* texture = textureCopy.texture;
-            if (textureCopy.mipLevel >= texture->GetNumMipLevels()) {
-                return DAWN_VALIDATION_ERROR("Copy mipLevel out of range");
-            }
-
-            Extent3D mipSize = texture->GetMipLevelPhysicalSize(textureCopy.mipLevel);
-            // For 2D textures, include the array layer as depth so it can be checked with other
-            // dimensions.
-            ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D);
-            mipSize.depth = texture->GetArrayLayers();
-
-            // All texture dimensions are in uint32_t so by doing checks in uint64_t we avoid
-            // overflows.
-            if (static_cast<uint64_t>(textureCopy.origin.x) +
-                        static_cast<uint64_t>(copySize.width) >
-                    static_cast<uint64_t>(mipSize.width) ||
-                static_cast<uint64_t>(textureCopy.origin.y) +
-                        static_cast<uint64_t>(copySize.height) >
-                    static_cast<uint64_t>(mipSize.height) ||
-                static_cast<uint64_t>(textureCopy.origin.z) +
-                        static_cast<uint64_t>(copySize.depth) >
-                    static_cast<uint64_t>(mipSize.depth)) {
-                return DAWN_VALIDATION_ERROR("Copy would touch outside of the texture");
-            }
-
-            return {};
-        }
-
-        MaybeError ValidateCopySizeFitsInBuffer(const Ref<BufferBase>& buffer,
-                                                uint64_t offset,
-                                                uint64_t size) {
-            uint64_t bufferSize = buffer->GetSize();
-            bool fitsInBuffer = offset <= bufferSize && (size <= (bufferSize - offset));
-            if (!fitsInBuffer) {
-                return DAWN_VALIDATION_ERROR("Copy would overflow the buffer");
-            }
-
-            return {};
-        }
-
-        MaybeError ValidateCopySizeFitsInBuffer(const BufferCopyView& bufferCopy,
-                                                uint64_t dataSize) {
-            return ValidateCopySizeFitsInBuffer(bufferCopy.buffer, bufferCopy.offset, dataSize);
-        }
-
         MaybeError ValidateB2BCopyAlignment(uint64_t dataSize,
                                             uint64_t srcOffset,
                                             uint64_t dstOffset) {
@@ -104,31 +55,6 @@
             return {};
         }
 
-        MaybeError ValidateTexelBufferOffset(const BufferCopyView& bufferCopy,
-                                             const Format& format) {
-            if (bufferCopy.offset % format.blockByteSize != 0) {
-                return DAWN_VALIDATION_ERROR(
-                    "Buffer offset must be a multiple of the texel or block size");
-            }
-
-            return {};
-        }
-
-        MaybeError ValidateRowsPerImage(const Format& format,
-                                        uint32_t rowsPerImage,
-                                        uint32_t copyHeight) {
-            if (rowsPerImage < copyHeight) {
-                return DAWN_VALIDATION_ERROR("rowsPerImage must not be less than the copy height.");
-            }
-
-            if (rowsPerImage % format.blockHeight != 0) {
-                return DAWN_VALIDATION_ERROR(
-                    "rowsPerImage must be a multiple of compressed texture format block height");
-            }
-
-            return {};
-        }
-
         MaybeError ValidateTextureSampleCountInCopyCommands(const TextureBase* texture) {
             if (texture->GetSampleCount() > 1) {
                 return DAWN_VALIDATION_ERROR("The sample count of textures must be 1");
@@ -193,77 +119,6 @@
             return {};
         }
 
-        MaybeError ComputeTextureCopyBufferSize(const Format& textureFormat,
-                                                const Extent3D& copySize,
-                                                uint32_t bytesPerRow,
-                                                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 {};
-        }
-
-        MaybeError ValidateBytesPerRow(const Format& format,
-                                       const Extent3D& copySize,
-                                       uint32_t bytesPerRow) {
-            if (bytesPerRow % kTextureBytesPerRowAlignment != 0) {
-                return DAWN_VALIDATION_ERROR("bytesPerRow must be a multiple of 256");
-            }
-
-            if (bytesPerRow < copySize.width / format.blockWidth * format.blockByteSize) {
-                return DAWN_VALIDATION_ERROR(
-                    "bytesPerRow must not be less than the number of bytes per row");
-            }
-
-            return {};
-        }
-
-        MaybeError ValidateImageOrigin(const Format& format, const Origin3D& offset) {
-            if (offset.x % format.blockWidth != 0) {
-                return DAWN_VALIDATION_ERROR(
-                    "Offset.x must be a multiple of compressed texture format block width");
-            }
-
-            if (offset.y % format.blockHeight != 0) {
-                return DAWN_VALIDATION_ERROR(
-                    "Offset.y must be a multiple of compressed texture format block height");
-            }
-
-            return {};
-        }
-
-        MaybeError ValidateImageCopySize(const Format& format, const Extent3D& extent) {
-            if (extent.width % format.blockWidth != 0) {
-                return DAWN_VALIDATION_ERROR(
-                    "Extent.width must be a multiple of compressed texture format block width");
-            }
-
-            if (extent.height % format.blockHeight != 0) {
-                return DAWN_VALIDATION_ERROR(
-                    "Extent.height must be a multiple of compressed texture format block height");
-            }
-
-            return {};
-        }
-
         MaybeError ValidateCanUseAs(const BufferBase* buffer, wgpu::BufferUsage usage) {
             ASSERT(wgpu::HasZeroOrOneBits(usage));
             if (!(buffer->GetUsage() & usage)) {
@@ -692,10 +547,26 @@
             DAWN_TRY_ASSIGN(fixedDest, FixTextureCopyView(GetDevice(), destination));
             destination = &fixedDest;
 
-            // Validate objects before doing the defaulting.
             if (GetDevice()->IsValidationEnabled()) {
-                DAWN_TRY(GetDevice()->ValidateObject(source->buffer));
-                DAWN_TRY(GetDevice()->ValidateObject(destination->texture));
+                DAWN_TRY(ValidateBufferCopyView(GetDevice(), *source));
+                DAWN_TRY(ValidateCanUseAs(source->buffer, wgpu::BufferUsage::CopySrc));
+
+                DAWN_TRY(ValidateTextureCopyView(GetDevice(), *destination));
+                DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst));
+                DAWN_TRY(ValidateTextureSampleCountInCopyCommands(destination->texture));
+
+                TextureDataLayout sourceAsTextureDataLayout;
+                sourceAsTextureDataLayout.offset = source->offset;
+                sourceAsTextureDataLayout.bytesPerRow = source->bytesPerRow;
+                sourceAsTextureDataLayout.rowsPerImage = source->rowsPerImage;
+
+                DAWN_TRY(ValidateLinearTextureData(sourceAsTextureDataLayout,
+                                                   source->buffer->GetSize(),
+                                                   destination->texture->GetFormat(), *copySize));
+                DAWN_TRY(ValidateTextureCopyRange(*destination, *copySize));
+
+                mTopLevelBuffers.insert(source->buffer);
+                mTopLevelTextures.insert(destination->texture);
             }
 
             // Compute default value for rowsPerImage
@@ -704,35 +575,6 @@
                 defaultedRowsPerImage = copySize->height;
             }
 
-            // Perform the rest of the validation using the default values.
-            if (GetDevice()->IsValidationEnabled()) {
-                DAWN_TRY(ValidateTextureSampleCountInCopyCommands(destination->texture));
-
-                DAWN_TRY(ValidateRowsPerImage(destination->texture->GetFormat(),
-                                              defaultedRowsPerImage, copySize->height));
-                DAWN_TRY(
-                    ValidateImageOrigin(destination->texture->GetFormat(), destination->origin));
-                DAWN_TRY(ValidateImageCopySize(destination->texture->GetFormat(), *copySize));
-
-                uint32_t bufferCopySize = 0;
-                DAWN_TRY(ValidateBytesPerRow(destination->texture->GetFormat(), *copySize,
-                                             source->bytesPerRow));
-
-                DAWN_TRY(ComputeTextureCopyBufferSize(destination->texture->GetFormat(), *copySize,
-                                                      source->bytesPerRow, defaultedRowsPerImage,
-                                                      &bufferCopySize));
-
-                DAWN_TRY(ValidateCopySizeFitsInTexture(*destination, *copySize));
-                DAWN_TRY(ValidateCopySizeFitsInBuffer(*source, bufferCopySize));
-                DAWN_TRY(ValidateTexelBufferOffset(*source, destination->texture->GetFormat()));
-
-                DAWN_TRY(ValidateCanUseAs(source->buffer, wgpu::BufferUsage::CopySrc));
-                DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst));
-
-                mTopLevelBuffers.insert(source->buffer);
-                mTopLevelTextures.insert(destination->texture);
-            }
-
             // Record the copy command.
             CopyBufferToTextureCmd* copy =
                 allocator->Allocate<CopyBufferToTextureCmd>(Command::CopyBufferToTexture);
@@ -759,10 +601,26 @@
             DAWN_TRY_ASSIGN(fixedSrc, FixTextureCopyView(GetDevice(), source));
             source = &fixedSrc;
 
-            // Validate objects before doing the defaulting.
             if (GetDevice()->IsValidationEnabled()) {
-                DAWN_TRY(GetDevice()->ValidateObject(source->texture));
-                DAWN_TRY(GetDevice()->ValidateObject(destination->buffer));
+                DAWN_TRY(ValidateTextureCopyView(GetDevice(), *source));
+                DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc));
+                DAWN_TRY(ValidateTextureSampleCountInCopyCommands(source->texture));
+
+                DAWN_TRY(ValidateBufferCopyView(GetDevice(), *destination));
+                DAWN_TRY(ValidateCanUseAs(destination->buffer, wgpu::BufferUsage::CopyDst));
+
+                TextureDataLayout dstAsTextureDataLayout;
+                dstAsTextureDataLayout.offset = destination->offset;
+                dstAsTextureDataLayout.bytesPerRow = destination->bytesPerRow;
+                dstAsTextureDataLayout.rowsPerImage = destination->rowsPerImage;
+
+                DAWN_TRY(ValidateLinearTextureData(dstAsTextureDataLayout,
+                                                   destination->buffer->GetSize(),
+                                                   source->texture->GetFormat(), *copySize));
+                DAWN_TRY(ValidateTextureCopyRange(*source, *copySize));
+
+                mTopLevelTextures.insert(source->texture);
+                mTopLevelBuffers.insert(destination->buffer);
             }
 
             // Compute default value for rowsPerImage
@@ -771,33 +629,6 @@
                 defaultedRowsPerImage = copySize->height;
             }
 
-            // Perform the rest of the validation using the default values.
-            if (GetDevice()->IsValidationEnabled()) {
-                DAWN_TRY(ValidateTextureSampleCountInCopyCommands(source->texture));
-
-                DAWN_TRY(ValidateRowsPerImage(source->texture->GetFormat(), defaultedRowsPerImage,
-                                              copySize->height));
-                DAWN_TRY(ValidateImageOrigin(source->texture->GetFormat(), source->origin));
-                DAWN_TRY(ValidateImageCopySize(source->texture->GetFormat(), *copySize));
-
-                uint32_t bufferCopySize = 0;
-                DAWN_TRY(ValidateBytesPerRow(source->texture->GetFormat(), *copySize,
-                                             destination->bytesPerRow));
-                DAWN_TRY(ComputeTextureCopyBufferSize(source->texture->GetFormat(), *copySize,
-                                                      destination->bytesPerRow,
-                                                      defaultedRowsPerImage, &bufferCopySize));
-
-                DAWN_TRY(ValidateCopySizeFitsInTexture(*source, *copySize));
-                DAWN_TRY(ValidateCopySizeFitsInBuffer(*destination, bufferCopySize));
-                DAWN_TRY(ValidateTexelBufferOffset(*destination, source->texture->GetFormat()));
-
-                DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc));
-                DAWN_TRY(ValidateCanUseAs(destination->buffer, wgpu::BufferUsage::CopyDst));
-
-                mTopLevelTextures.insert(source->texture);
-                mTopLevelBuffers.insert(destination->buffer);
-            }
-
             // Record the copy command.
             CopyTextureToBufferCmd* copy =
                 allocator->Allocate<CopyTextureToBufferCmd>(Command::CopyTextureToBuffer);
@@ -834,14 +665,11 @@
                 DAWN_TRY(
                     ValidateTextureToTextureCopyRestrictions(*source, *destination, *copySize));
 
-                DAWN_TRY(ValidateImageOrigin(source->texture->GetFormat(), source->origin));
-                DAWN_TRY(ValidateImageCopySize(source->texture->GetFormat(), *copySize));
-                DAWN_TRY(
-                    ValidateImageOrigin(destination->texture->GetFormat(), destination->origin));
-                DAWN_TRY(ValidateImageCopySize(destination->texture->GetFormat(), *copySize));
+                DAWN_TRY(ValidateTextureCopyRange(*source, *copySize));
+                DAWN_TRY(ValidateTextureCopyRange(*destination, *copySize));
 
-                DAWN_TRY(ValidateCopySizeFitsInTexture(*source, *copySize));
-                DAWN_TRY(ValidateCopySizeFitsInTexture(*destination, *copySize));
+                DAWN_TRY(ValidateTextureCopyView(GetDevice(), *source));
+                DAWN_TRY(ValidateTextureCopyView(GetDevice(), *destination));
 
                 DAWN_TRY(ValidateCanUseAs(source->texture, wgpu::TextureUsage::CopySrc));
                 DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst));
diff --git a/src/dawn_native/CommandValidation.cpp b/src/dawn_native/CommandValidation.cpp
index 0a96c85..019ebb4 100644
--- a/src/dawn_native/CommandValidation.cpp
+++ b/src/dawn_native/CommandValidation.cpp
@@ -19,6 +19,7 @@
 #include "dawn_native/Buffer.h"
 #include "dawn_native/CommandBufferStateTracker.h"
 #include "dawn_native/Commands.h"
+#include "dawn_native/Device.h"
 #include "dawn_native/PassResourceUsage.h"
 #include "dawn_native/QuerySet.h"
 #include "dawn_native/RenderBundle.h"
@@ -119,6 +120,36 @@
             return {};
         }
 
+        void ComputeRequiredBytesInCopy(const Format& textureFormat,
+                                        const Extent3D& copySize,
+                                        uint32_t bytesPerRow,
+                                        uint32_t rowsPerImage,
+                                        uint32_t* result) {
+            // Default value for rowsPerImage
+            if (rowsPerImage == 0) {
+                rowsPerImage = copySize.height;
+            }
+            ASSERT(rowsPerImage >= copySize.height);
+            if (copySize.width == 0 || copySize.height == 0 || copySize.depth == 0) {
+                *result = 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);
+            *result = (slicePitch * (copySize.depth - 1)) + sliceSize;
+        }
+
     }  // namespace
 
     MaybeError ValidateCanPopDebugGroup(uint64_t debugGroupStackSize) {
@@ -369,4 +400,127 @@
                static_cast<uint64_t>(maxStart);
     }
 
+    MaybeError ValidateCopySizeFitsInBuffer(const Ref<BufferBase>& buffer,
+                                            uint64_t offset,
+                                            uint64_t size) {
+        uint64_t bufferSize = buffer->GetSize();
+        bool fitsInBuffer = offset <= bufferSize && (size <= (bufferSize - offset));
+        if (!fitsInBuffer) {
+            return DAWN_VALIDATION_ERROR("Copy would overflow the buffer");
+        }
+
+        return {};
+    }
+
+    MaybeError ValidateLinearTextureData(const TextureDataLayout& layout,
+                                         uint64_t byteSize,
+                                         const Format& format,
+                                         const Extent3D& copyExtent) {
+        // 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.");
+        }
+
+        // TODO(tommek@google.com): to match the spec this should only be checked when
+        // copyExtent.depth > 1.
+        uint32_t requiredBytesInCopy = 0;
+        ComputeRequiredBytesInCopy(format, copyExtent, layout.bytesPerRow, layout.rowsPerImage,
+                                   &requiredBytesInCopy);
+
+        bool fitsInData =
+            layout.offset <= byteSize && (requiredBytesInCopy <= (byteSize - layout.offset));
+        if (!fitsInData) {
+            return DAWN_VALIDATION_ERROR(
+                "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(
+                "bytesPerRow must not be less than the number of bytes per row");
+        }
+
+        // TODO(tommek@google.com): to match the spec there should be another condition here
+        // on rowsPerImage >= copyExtent.height if copyExtent.depth > 1.
+
+        return {};
+    }
+
+    MaybeError ValidateBufferCopyView(DeviceBase const* device,
+                                      const BufferCopyView& bufferCopyView) {
+        DAWN_TRY(device->ValidateObject(bufferCopyView.buffer));
+        if (bufferCopyView.bytesPerRow % kTextureBytesPerRowAlignment != 0) {
+            return DAWN_VALIDATION_ERROR("bytesPerRow must be a multiple of 256");
+        }
+        return {};
+    }
+
+    MaybeError ValidateTextureCopyView(DeviceBase const* device,
+                                       const TextureCopyView& textureCopy) {
+        DAWN_TRY(device->ValidateObject(textureCopy.texture));
+        if (textureCopy.mipLevel >= textureCopy.texture->GetNumMipLevels()) {
+            return DAWN_VALIDATION_ERROR("mipLevel out of range");
+        }
+
+        if (textureCopy.origin.x % textureCopy.texture->GetFormat().blockWidth != 0) {
+            return DAWN_VALIDATION_ERROR(
+                "Offset.x must be a multiple of compressed texture format block width");
+        }
+
+        if (textureCopy.origin.y % textureCopy.texture->GetFormat().blockHeight != 0) {
+            return DAWN_VALIDATION_ERROR(
+                "Offset.y must be a multiple of compressed texture format block height");
+        }
+
+        return {};
+    }
+
+    MaybeError ValidateTextureCopyRange(const TextureCopyView& textureCopy,
+                                        const Extent3D& copySize) {
+        // TODO(jiawei.shao@intel.com): add validations on the texture-to-texture copies within the
+        // same texture.
+        const TextureBase* texture = textureCopy.texture;
+
+        // Validation for the copy being in-bounds:
+        Extent3D mipSize = texture->GetMipLevelPhysicalSize(textureCopy.mipLevel);
+        // For 2D textures, include the array layer as depth so it can be checked with other
+        // dimensions.
+        ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D);
+        mipSize.depth = texture->GetArrayLayers();
+
+        // All texture dimensions are in uint32_t so by doing checks in uint64_t we avoid
+        // overflows.
+        if (static_cast<uint64_t>(textureCopy.origin.x) + static_cast<uint64_t>(copySize.width) >
+                static_cast<uint64_t>(mipSize.width) ||
+            static_cast<uint64_t>(textureCopy.origin.y) + static_cast<uint64_t>(copySize.height) >
+                static_cast<uint64_t>(mipSize.height) ||
+            static_cast<uint64_t>(textureCopy.origin.z) + static_cast<uint64_t>(copySize.depth) >
+                static_cast<uint64_t>(mipSize.depth)) {
+            return DAWN_VALIDATION_ERROR("Touching outside of the texture");
+        }
+
+        // Validation for the texel block alignments:
+        if (copySize.width % textureCopy.texture->GetFormat().blockWidth != 0) {
+            return DAWN_VALIDATION_ERROR(
+                "copySize.width must be a multiple of compressed texture format block width");
+        }
+
+        if (copySize.height % textureCopy.texture->GetFormat().blockHeight != 0) {
+            return DAWN_VALIDATION_ERROR(
+                "copySize.height must be a multiple of compressed texture format block height");
+        }
+
+        return {};
+    }
+
 }  // namespace dawn_native
diff --git a/src/dawn_native/CommandValidation.h b/src/dawn_native/CommandValidation.h
index 49da94d..34ff7a4 100644
--- a/src/dawn_native/CommandValidation.h
+++ b/src/dawn_native/CommandValidation.h
@@ -17,6 +17,7 @@
 
 #include "dawn_native/CommandAllocator.h"
 #include "dawn_native/Error.h"
+#include "dawn_native/Texture.h"
 
 #include <vector>
 
@@ -39,6 +40,28 @@
 
     MaybeError ValidateTimestampQuery(QuerySetBase* querySet, uint32_t queryIndex);
 
+    MaybeError ValidateLinearTextureData(const TextureDataLayout& layout,
+                                         uint64_t byteSize,
+                                         const Format& format,
+                                         const Extent3D& copyExtent);
+    MaybeError ValidateTextureCopyRange(const TextureCopyView& textureCopyView,
+                                        const Extent3D& copySize);
+
+    MaybeError ValidateBufferCopyView(DeviceBase const* device,
+                                      const BufferCopyView& bufferCopyView);
+    MaybeError ValidateTextureCopyView(DeviceBase const* device,
+                                       const TextureCopyView& textureCopyView);
+
+    MaybeError ValidateRowsPerImage(const Format& format,
+                                    uint32_t rowsPerImage,
+                                    uint32_t copyHeight);
+    MaybeError ValidateBytesPerRow(const Format& format,
+                                   const Extent3D& copySize,
+                                   uint32_t bytesPerRow);
+    MaybeError ValidateCopySizeFitsInBuffer(const Ref<BufferBase>& buffer,
+                                            uint64_t offset,
+                                            uint64_t size);
+
     bool IsRangeOverlapped(uint32_t startA, uint32_t startB, uint32_t length);
 
 }  // namespace dawn_native