Cleanup: Make TexelBlockInfo a member of Format, not superclass

Bug: dawn:439
Change-Id: I1255086d29e8b85045776f183b3fb563eec0b090
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/27940
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn_native/CommandBuffer.cpp b/src/dawn_native/CommandBuffer.cpp
index 91fec29..2dae6a2 100644
--- a/src/dawn_native/CommandBuffer.cpp
+++ b/src/dawn_native/CommandBuffer.cpp
@@ -162,7 +162,6 @@
         }
     }
 
-    // TODO(jiawei.shao@intel.com): support copying with depth stencil textures
     bool IsFullBufferOverwrittenInTextureToBufferCopy(const CopyTextureToBufferCmd* copy) {
         ASSERT(copy != nullptr);
 
@@ -175,16 +174,17 @@
         }
 
         const TextureBase* texture = copy->source.texture.Get();
-        const uint64_t copyTextureDataSizePerRow = copy->copySize.width /
-                                                   texture->GetFormat().blockWidth *
-                                                   texture->GetFormat().blockByteSize;
+        const TexelBlockInfo& blockInfo =
+            texture->GetFormat().GetTexelBlockInfo(copy->source.aspect);
+        const uint64_t copyTextureDataSizePerRow =
+            copy->copySize.width / blockInfo.blockWidth * blockInfo.blockByteSize;
         if (copy->destination.bytesPerRow > copyTextureDataSizePerRow) {
             return false;
         }
 
-        const uint64_t overwrittenRangeSize =
-            copyTextureDataSizePerRow * (copy->copySize.height / texture->GetFormat().blockHeight) *
-            copy->copySize.depth;
+        const uint64_t overwrittenRangeSize = copyTextureDataSizePerRow *
+                                              (copy->copySize.height / blockInfo.blockHeight) *
+                                              copy->copySize.depth;
         if (copy->destination.buffer->GetSize() > overwrittenRangeSize) {
             return false;
         }
diff --git a/src/dawn_native/CommandEncoder.cpp b/src/dawn_native/CommandEncoder.cpp
index 88717c7..e846e11 100644
--- a/src/dawn_native/CommandEncoder.cpp
+++ b/src/dawn_native/CommandEncoder.cpp
@@ -622,12 +622,12 @@
                 DAWN_TRY(ValidateCanUseAs(destination->texture, wgpu::TextureUsage::CopyDst));
                 DAWN_TRY(ValidateTextureSampleCountInBufferCopyCommands(destination->texture));
 
+                DAWN_TRY(ValidateBufferToTextureCopyRestrictions(*destination));
                 // 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(ValidateBufferToTextureCopyRestrictions(*destination));
                 DAWN_TRY(ValidateLinearTextureData(
                     source->layout, source->buffer->GetSize(),
                     destination->texture->GetFormat().GetTexelBlockInfo(destination->aspect),
@@ -644,11 +644,12 @@
             }
 
             // In the case of one row copy bytesPerRow might not contain enough bytes
+            const TexelBlockInfo& blockInfo =
+                destination->texture->GetFormat().GetTexelBlockInfo(destination->aspect);
             uint32_t bytesPerRow = source->layout.bytesPerRow;
             if (copySize->height <= 1 && copySize->depth <= 1) {
                 bytesPerRow =
-                    Align(copySize->width * destination->texture->GetFormat().blockByteSize,
-                          kTextureBytesPerRowAlignment);
+                    Align(copySize->width * blockInfo.blockByteSize, kTextureBytesPerRowAlignment);
             }
 
             // Record the copy command.
@@ -681,12 +682,12 @@
                 DAWN_TRY(ValidateBufferCopyView(GetDevice(), *destination));
                 DAWN_TRY(ValidateCanUseAs(destination->buffer, wgpu::BufferUsage::CopyDst));
 
+                DAWN_TRY(ValidateTextureToBufferCopyRestrictions(*source));
                 // 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(ValidateTextureToBufferCopyRestrictions(*source));
                 DAWN_TRY(ValidateLinearTextureData(
                     destination->layout, destination->buffer->GetSize(),
                     source->texture->GetFormat().GetTexelBlockInfo(source->aspect), *copySize));
@@ -702,10 +703,12 @@
             }
 
             // In the case of one row copy bytesPerRow might not contain enough bytes
+            const TexelBlockInfo& blockInfo =
+                source->texture->GetFormat().GetTexelBlockInfo(source->aspect);
             uint32_t bytesPerRow = destination->layout.bytesPerRow;
             if (copySize->height <= 1 && copySize->depth <= 1) {
-                bytesPerRow = Align(copySize->width * source->texture->GetFormat().blockByteSize,
-                                    kTextureBytesPerRowAlignment);
+                bytesPerRow =
+                    Align(copySize->width * blockInfo.blockByteSize, kTextureBytesPerRowAlignment);
             }
 
             // Record the copy command.
@@ -733,15 +736,15 @@
                 DAWN_TRY(GetDevice()->ValidateObject(source->texture));
                 DAWN_TRY(GetDevice()->ValidateObject(destination->texture));
 
+                DAWN_TRY(ValidateTextureCopyView(GetDevice(), *source, *copySize));
+                DAWN_TRY(ValidateTextureCopyView(GetDevice(), *destination, *copySize));
+
                 DAWN_TRY(
                     ValidateTextureToTextureCopyRestrictions(*source, *destination, *copySize));
 
                 DAWN_TRY(ValidateTextureCopyRange(*source, *copySize));
                 DAWN_TRY(ValidateTextureCopyRange(*destination, *copySize));
 
-                DAWN_TRY(ValidateTextureCopyView(GetDevice(), *source, *copySize));
-                DAWN_TRY(ValidateTextureCopyView(GetDevice(), *destination, *copySize));
-
                 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 b412ab6..c2ac26f 100644
--- a/src/dawn_native/CommandValidation.cpp
+++ b/src/dawn_native/CommandValidation.cpp
@@ -490,16 +490,6 @@
             return DAWN_VALIDATION_ERROR("mipLevel out of range");
         }
 
-        if (textureCopy.origin.x % texture->GetFormat().blockWidth != 0) {
-            return DAWN_VALIDATION_ERROR(
-                "Offset.x must be a multiple of compressed texture format block width");
-        }
-
-        if (textureCopy.origin.y % texture->GetFormat().blockHeight != 0) {
-            return DAWN_VALIDATION_ERROR(
-                "Offset.y must be a multiple of compressed texture format block height");
-        }
-
         switch (textureCopy.aspect) {
             case wgpu::TextureAspect::All:
                 break;
@@ -560,12 +550,22 @@
         }
 
         // Validation for the texel block alignments:
-        if (copySize.width % textureCopy.texture->GetFormat().blockWidth != 0) {
+        const TexelBlockInfo& blockInfo =
+            textureCopy.texture->GetFormat().GetTexelBlockInfo(textureCopy.aspect);
+        if (textureCopy.origin.x % blockInfo.blockWidth != 0) {
+            return DAWN_VALIDATION_ERROR(
+                "Offset.x must be a multiple of compressed texture format block width");
+        }
+        if (textureCopy.origin.y % blockInfo.blockHeight != 0) {
+            return DAWN_VALIDATION_ERROR(
+                "Offset.y must be a multiple of compressed texture format block height");
+        }
+        if (copySize.width % blockInfo.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) {
+        if (copySize.height % blockInfo.blockHeight != 0) {
             return DAWN_VALIDATION_ERROR(
                 "copySize.height must be a multiple of compressed texture format block height");
         }
diff --git a/src/dawn_native/Format.cpp b/src/dawn_native/Format.cpp
index 11b71d2..53af258 100644
--- a/src/dawn_native/Format.cpp
+++ b/src/dawn_native/Format.cpp
@@ -82,21 +82,13 @@
     TexelBlockInfo Format::GetTexelBlockInfo(wgpu::TextureAspect aspect) const {
         switch (aspect) {
             case wgpu::TextureAspect::All:
-                switch (aspects) {
-                    case Aspect::Color:
-                    case Aspect::Depth:
-                    case Aspect::Stencil:
-                        break;
-                    default:
-                        UNREACHABLE();
-                }
-                return *this;
+                return blockInfo;
 
             case wgpu::TextureAspect::DepthOnly:
                 ASSERT(HasDepth());
                 switch (format) {
                     case wgpu::TextureFormat::Depth32Float:
-                        return *this;
+                        return blockInfo;
                     default:
                         UNREACHABLE();
                         break;
@@ -126,11 +118,11 @@
         switch (aspect) {
             case Aspect::Color:
                 ASSERT(aspects == aspect);
-                return *this;
+                return blockInfo;
             case Aspect::Depth:
                 switch (format) {
                     case wgpu::TextureFormat::Depth32Float:
-                        return *this;
+                        return blockInfo;
                     default:
                         UNREACHABLE();
                         break;
@@ -195,9 +187,9 @@
             internalFormat.supportsStorageUsage = supportsStorageUsage;
             internalFormat.aspects = Aspect::Color;
             internalFormat.type = type;
-            internalFormat.blockByteSize = byteSize;
-            internalFormat.blockWidth = 1;
-            internalFormat.blockHeight = 1;
+            internalFormat.blockInfo.blockByteSize = byteSize;
+            internalFormat.blockInfo.blockWidth = 1;
+            internalFormat.blockInfo.blockHeight = 1;
             AddFormat(internalFormat);
         };
 
@@ -211,9 +203,9 @@
             internalFormat.supportsStorageUsage = false;
             internalFormat.aspects = aspects;
             internalFormat.type = Type::Other;
-            internalFormat.blockByteSize = byteSize;
-            internalFormat.blockWidth = 1;
-            internalFormat.blockHeight = 1;
+            internalFormat.blockInfo.blockByteSize = byteSize;
+            internalFormat.blockInfo.blockWidth = 1;
+            internalFormat.blockInfo.blockHeight = 1;
             AddFormat(internalFormat);
         };
 
@@ -227,9 +219,9 @@
             internalFormat.supportsStorageUsage = false;
             internalFormat.aspects = Aspect::Depth;
             internalFormat.type = type;
-            internalFormat.blockByteSize = byteSize;
-            internalFormat.blockWidth = 1;
-            internalFormat.blockHeight = 1;
+            internalFormat.blockInfo.blockByteSize = byteSize;
+            internalFormat.blockInfo.blockWidth = 1;
+            internalFormat.blockInfo.blockHeight = 1;
             AddFormat(internalFormat);
         };
 
@@ -243,9 +235,9 @@
             internalFormat.supportsStorageUsage = false;
             internalFormat.aspects = Aspect::Color;
             internalFormat.type = Type::Float;
-            internalFormat.blockByteSize = byteSize;
-            internalFormat.blockWidth = width;
-            internalFormat.blockHeight = height;
+            internalFormat.blockInfo.blockByteSize = byteSize;
+            internalFormat.blockInfo.blockWidth = width;
+            internalFormat.blockInfo.blockHeight = height;
             AddFormat(internalFormat);
         };
 
diff --git a/src/dawn_native/Format.h b/src/dawn_native/Format.h
index 15c6c31..63c450e 100644
--- a/src/dawn_native/Format.h
+++ b/src/dawn_native/Format.h
@@ -39,8 +39,11 @@
     // exact number of known format.
     static constexpr size_t kKnownFormatCount = 53;
 
+    struct Format;
+    using FormatTable = std::array<Format, kKnownFormatCount>;
+
     // A wgpu::TextureFormat along with all the information about it necessary for validation.
-    struct Format : TexelBlockInfo {
+    struct Format {
         enum class Type {
             Float,
             Sint,
@@ -72,12 +75,15 @@
         // The index of the format in the list of all known formats: a unique number for each format
         // in [0, kKnownFormatCount)
         size_t GetIndex() const;
+
+      private:
+        TexelBlockInfo blockInfo;
+
+        friend FormatTable BuildFormatTable(const DeviceBase* device);
     };
 
     // Implementation details of the format table in the device.
 
-    using FormatTable = std::array<Format, kKnownFormatCount>;
-
     // Returns the index of a format in the FormatTable.
     size_t ComputeFormatIndex(wgpu::TextureFormat format);
     // Builds the format table with the extensions enabled on the device.
diff --git a/src/dawn_native/Queue.cpp b/src/dawn_native/Queue.cpp
index d658a2a..2ec53c6 100644
--- a/src/dawn_native/Queue.cpp
+++ b/src/dawn_native/Queue.cpp
@@ -378,12 +378,12 @@
             return DAWN_VALIDATION_ERROR("The sample count of textures must be 1");
         }
 
+        DAWN_TRY(ValidateBufferToTextureCopyRestrictions(*destination));
         // 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(ValidateBufferToTextureCopyRestrictions(*destination));
         DAWN_TRY(ValidateLinearTextureData(
             *dataLayout, dataSize,
             destination->texture->GetFormat().GetTexelBlockInfo(destination->aspect), *writeSize));
diff --git a/src/dawn_native/Texture.cpp b/src/dawn_native/Texture.cpp
index 8f93b46..38ce4d2 100644
--- a/src/dawn_native/Texture.cpp
+++ b/src/dawn_native/Texture.cpp
@@ -159,8 +159,9 @@
                 return DAWN_VALIDATION_ERROR("Texture has too many mip levels");
             }
 
-            if (format->isCompressed && (descriptor->size.width % format->blockWidth != 0 ||
-                                         descriptor->size.height % format->blockHeight != 0)) {
+            const TexelBlockInfo& blockInfo = format->GetTexelBlockInfo(wgpu::TextureAspect::All);
+            if (format->isCompressed && (descriptor->size.width % blockInfo.blockWidth != 0 ||
+                                         descriptor->size.height % blockInfo.blockHeight != 0)) {
                 return DAWN_VALIDATION_ERROR(
                     "The size of the texture is incompatible with the texture format");
             }
@@ -557,8 +558,9 @@
         // 4 at non-zero mipmap levels.
         if (mFormat.isCompressed) {
             // TODO(jiawei.shao@intel.com): check if there are any overflows.
-            uint32_t blockWidth = mFormat.blockWidth;
-            uint32_t blockHeight = mFormat.blockHeight;
+            const TexelBlockInfo& blockInfo = mFormat.GetTexelBlockInfo(wgpu::TextureAspect::All);
+            uint32_t blockWidth = blockInfo.blockWidth;
+            uint32_t blockHeight = blockInfo.blockHeight;
             extent.width = (extent.width + blockWidth - 1) / blockWidth * blockWidth;
             extent.height = (extent.height + blockHeight - 1) / blockHeight * blockHeight;
         }
diff --git a/src/dawn_native/d3d12/TextureD3D12.cpp b/src/dawn_native/d3d12/TextureD3D12.cpp
index 3d87186..6ccd2e3 100644
--- a/src/dawn_native/d3d12/TextureD3D12.cpp
+++ b/src/dawn_native/d3d12/TextureD3D12.cpp
@@ -952,7 +952,7 @@
                 UploadHandle uploadHandle;
                 DAWN_TRY_ASSIGN(uploadHandle,
                                 uploader->Allocate(bufferSize, device->GetPendingCommandSerial(),
-                                                   GetFormat().blockByteSize));
+                                                   blockInfo.blockByteSize));
                 memset(uploadHandle.mappedBuffer, clearColor, bufferSize);
 
                 for (uint32_t level = range.baseMipLevel;
diff --git a/src/dawn_native/metal/CommandBufferMTL.mm b/src/dawn_native/metal/CommandBufferMTL.mm
index 7891c7f..bee68d7 100644
--- a/src/dawn_native/metal/CommandBufferMTL.mm
+++ b/src/dawn_native/metal/CommandBufferMTL.mm
@@ -643,7 +643,7 @@
 
                     TextureBufferCopySplit splitCopies = ComputeTextureBufferCopySplit(
                         texture, dst.mipLevel, dst.origin, copySize, buffer->GetSize(), src.offset,
-                        src.bytesPerRow, src.rowsPerImage);
+                        src.bytesPerRow, src.rowsPerImage, dst.aspect);
 
                     for (uint32_t i = 0; i < splitCopies.count; ++i) {
                         const TextureBufferCopySplit::CopyInfo& copyInfo = splitCopies.copies[i];
@@ -693,7 +693,7 @@
 
                     TextureBufferCopySplit splitCopies = ComputeTextureBufferCopySplit(
                         texture, src.mipLevel, src.origin, copySize, buffer->GetSize(), dst.offset,
-                        dst.bytesPerRow, dst.rowsPerImage);
+                        dst.bytesPerRow, dst.rowsPerImage, src.aspect);
 
                     for (uint32_t i = 0; i < splitCopies.count; ++i) {
                         const TextureBufferCopySplit::CopyInfo& copyInfo = splitCopies.copies[i];
diff --git a/src/dawn_native/metal/TextureMTL.mm b/src/dawn_native/metal/TextureMTL.mm
index 449f338..a0b08fb 100644
--- a/src/dawn_native/metal/TextureMTL.mm
+++ b/src/dawn_native/metal/TextureMTL.mm
@@ -488,15 +488,17 @@
         } else {
             // Compute the buffer size big enough to fill the largest mip.
             Extent3D largestMipSize = GetMipLevelVirtualSize(range.baseMipLevel);
+            const TexelBlockInfo& blockInfo =
+                GetFormat().GetTexelBlockInfo(wgpu::TextureAspect::All);
 
             // Metal validation layers: sourceBytesPerRow must be at least 64.
             uint32_t largestMipBytesPerRow = std::max(
-                (largestMipSize.width / GetFormat().blockWidth) * GetFormat().blockByteSize, 64u);
+                (largestMipSize.width / blockInfo.blockWidth) * blockInfo.blockByteSize, 64u);
 
             // Metal validation layers: sourceBytesPerImage must be at least 512.
             uint64_t largestMipBytesPerImage =
                 std::max(static_cast<uint64_t>(largestMipBytesPerRow) *
-                             (largestMipSize.height / GetFormat().blockHeight),
+                             (largestMipSize.height / blockInfo.blockHeight),
                          512llu);
 
             // TODO(enga): Multiply by largestMipSize.depth and do a larger 3D copy to clear a whole
@@ -511,7 +513,7 @@
             UploadHandle uploadHandle;
             DAWN_TRY_ASSIGN(uploadHandle,
                             uploader->Allocate(bufferSize, device->GetPendingCommandSerial(),
-                                               GetFormat().blockByteSize));
+                                               blockInfo.blockByteSize));
             memset(uploadHandle.mappedBuffer, clearColor, bufferSize);
 
             id<MTLBlitCommandEncoder> encoder = commandContext->EnsureBlit();
diff --git a/src/dawn_native/metal/UtilsMetal.h b/src/dawn_native/metal/UtilsMetal.h
index d7c0a70..a7a5dee 100644
--- a/src/dawn_native/metal/UtilsMetal.h
+++ b/src/dawn_native/metal/UtilsMetal.h
@@ -47,7 +47,8 @@
                                                          uint64_t bufferSize,
                                                          uint64_t bufferOffset,
                                                          uint32_t bytesPerRow,
-                                                         uint32_t rowsPerImage);
+                                                         uint32_t rowsPerImage,
+                                                         Aspect aspect);
 
     void EnsureDestinationTextureInitialized(Texture* texture,
                                              const TextureCopy& dst,
diff --git a/src/dawn_native/metal/UtilsMetal.mm b/src/dawn_native/metal/UtilsMetal.mm
index 3b8f64c..840524b 100644
--- a/src/dawn_native/metal/UtilsMetal.mm
+++ b/src/dawn_native/metal/UtilsMetal.mm
@@ -49,9 +49,11 @@
                                                          uint64_t bufferSize,
                                                          uint64_t bufferOffset,
                                                          uint32_t bytesPerRow,
-                                                         uint32_t rowsPerImage) {
+                                                         uint32_t rowsPerImage,
+                                                         Aspect aspect) {
         TextureBufferCopySplit copy;
         const Format textureFormat = texture->GetFormat();
+        const TexelBlockInfo& blockInfo = textureFormat.GetTexelBlockInfo(aspect);
 
         // When copying textures from/to an unpacked buffer, the Metal validation layer doesn't
         // compute the correct range when checking if the buffer is big enough to contain the
@@ -70,7 +72,7 @@
 
         // We work around this limitation by detecting when Metal would complain and copy the
         // last image and row separately using tight sourceBytesPerRow or sourceBytesPerImage.
-        uint32_t dataRowsPerImage = rowsPerImage / textureFormat.blockHeight;
+        uint32_t dataRowsPerImage = rowsPerImage / blockInfo.blockHeight;
         uint32_t bytesPerImage = bytesPerRow * dataRowsPerImage;
 
         // Metal validation layer requires that if the texture's pixel format is a compressed
@@ -113,7 +115,7 @@
         }
 
         // Doing all the copy in last image except the last row.
-        uint32_t copyBlockRowCount = copyExtent.height / textureFormat.blockHeight;
+        uint32_t copyBlockRowCount = copyExtent.height / blockInfo.blockHeight;
         if (copyBlockRowCount > 1) {
             copy.copies[copy.count].bufferOffset = currentOffset;
             copy.copies[copy.count].bytesPerRow = bytesPerRow;
@@ -121,10 +123,10 @@
             copy.copies[copy.count].textureOrigin = {origin.x, origin.y,
                                                      origin.z + copyExtent.depth - 1};
 
-            ASSERT(copyExtent.height - textureFormat.blockHeight <
+            ASSERT(copyExtent.height - blockInfo.blockHeight <
                    texture->GetMipLevelVirtualSize(mipLevel).height);
             copy.copies[copy.count].copyExtent = {clampedCopyExtent.width,
-                                                  copyExtent.height - textureFormat.blockHeight, 1};
+                                                  copyExtent.height - blockInfo.blockHeight, 1};
 
             ++copy.count;
 
@@ -135,16 +137,16 @@
         // Doing the last row copy with the exact number of bytes in last row.
         // Workaround this issue in a way just like the copy to a 1D texture.
         uint32_t lastRowDataSize =
-            (copyExtent.width / textureFormat.blockWidth) * textureFormat.blockByteSize;
+            (copyExtent.width / blockInfo.blockWidth) * blockInfo.blockByteSize;
         uint32_t lastRowCopyExtentHeight =
-            textureFormat.blockHeight + clampedCopyExtent.height - copyExtent.height;
-        ASSERT(lastRowCopyExtentHeight <= textureFormat.blockHeight);
+            blockInfo.blockHeight + clampedCopyExtent.height - copyExtent.height;
+        ASSERT(lastRowCopyExtentHeight <= blockInfo.blockHeight);
 
         copy.copies[copy.count].bufferOffset = currentOffset;
         copy.copies[copy.count].bytesPerRow = lastRowDataSize;
         copy.copies[copy.count].bytesPerImage = lastRowDataSize;
         copy.copies[copy.count].textureOrigin = {
-            origin.x, origin.y + copyExtent.height - textureFormat.blockHeight,
+            origin.x, origin.y + copyExtent.height - blockInfo.blockHeight,
             origin.z + copyExtent.depth - 1};
         copy.copies[copy.count].copyExtent = {clampedCopyExtent.width, lastRowCopyExtentHeight, 1};
         ++copy.count;
diff --git a/src/dawn_native/opengl/CommandBufferGL.cpp b/src/dawn_native/opengl/CommandBufferGL.cpp
index e9e98b1..6776c02 100644
--- a/src/dawn_native/opengl/CommandBufferGL.cpp
+++ b/src/dawn_native/opengl/CommandBufferGL.cpp
@@ -540,21 +540,21 @@
                     gl.BindTexture(target, texture->GetHandle());
 
                     const Format& formatInfo = texture->GetFormat();
-                    gl.PixelStorei(
-                        GL_UNPACK_ROW_LENGTH,
-                        src.bytesPerRow / formatInfo.blockByteSize * formatInfo.blockWidth);
+                    const TexelBlockInfo& blockInfo = formatInfo.GetTexelBlockInfo(dst.aspect);
+                    gl.PixelStorei(GL_UNPACK_ROW_LENGTH, src.bytesPerRow / blockInfo.blockByteSize *
+                                                             blockInfo.blockWidth);
                     gl.PixelStorei(GL_UNPACK_IMAGE_HEIGHT, src.rowsPerImage);
 
                     if (formatInfo.isCompressed) {
-                        gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_SIZE, formatInfo.blockByteSize);
-                        gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_WIDTH, formatInfo.blockWidth);
-                        gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_HEIGHT, formatInfo.blockHeight);
+                        gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_SIZE, blockInfo.blockByteSize);
+                        gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_WIDTH, blockInfo.blockWidth);
+                        gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_HEIGHT, blockInfo.blockHeight);
                         gl.PixelStorei(GL_UNPACK_COMPRESSED_BLOCK_DEPTH, 1);
 
                         ASSERT(texture->GetDimension() == wgpu::TextureDimension::e2D);
-                        uint64_t copyDataSize = (copySize.width / formatInfo.blockWidth) *
-                                                (copySize.height / formatInfo.blockHeight) *
-                                                formatInfo.blockByteSize * copySize.depth;
+                        uint64_t copyDataSize = (copySize.width / blockInfo.blockWidth) *
+                                                (copySize.height / blockInfo.blockHeight) *
+                                                blockInfo.blockByteSize * copySize.depth;
                         Extent3D copyExtent = ComputeTextureCopyExtent(dst, copySize);
 
                         if (texture->GetArrayLayers() > 1) {
diff --git a/src/dawn_native/opengl/TextureGL.cpp b/src/dawn_native/opengl/TextureGL.cpp
index 3bc247b..9864171 100644
--- a/src/dawn_native/opengl/TextureGL.cpp
+++ b/src/dawn_native/opengl/TextureGL.cpp
@@ -289,7 +289,9 @@
                 ASSERT(range.aspects == Aspect::Color);
 
                 static constexpr uint32_t MAX_TEXEL_SIZE = 16;
-                ASSERT(GetFormat().blockByteSize <= MAX_TEXEL_SIZE);
+                const TexelBlockInfo& blockInfo = GetFormat().GetTexelBlockInfo(Aspect::Color);
+                ASSERT(blockInfo.blockByteSize <= MAX_TEXEL_SIZE);
+
                 std::array<GLbyte, MAX_TEXEL_SIZE> clearColorData;
                 clearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0 : 255;
                 clearColorData.fill(clearColor);
@@ -317,19 +319,20 @@
             ASSERT(range.aspects == Aspect::Color);
 
             // create temp buffer with clear color to copy to the texture image
-            ASSERT(kTextureBytesPerRowAlignment % GetFormat().blockByteSize == 0);
+            const TexelBlockInfo& blockInfo = GetFormat().GetTexelBlockInfo(Aspect::Color);
+            ASSERT(kTextureBytesPerRowAlignment % blockInfo.blockByteSize == 0);
             uint32_t bytesPerRow =
-                Align((GetWidth() / GetFormat().blockWidth) * GetFormat().blockByteSize,
+                Align((GetWidth() / blockInfo.blockWidth) * blockInfo.blockByteSize,
                       kTextureBytesPerRowAlignment);
 
             // Make sure that we are not rounding
-            ASSERT(bytesPerRow % GetFormat().blockByteSize == 0);
-            ASSERT(GetHeight() % GetFormat().blockHeight == 0);
+            ASSERT(bytesPerRow % blockInfo.blockByteSize == 0);
+            ASSERT(GetHeight() % blockInfo.blockHeight == 0);
 
             dawn_native::BufferDescriptor descriptor = {};
             descriptor.mappedAtCreation = true;
             descriptor.usage = wgpu::BufferUsage::CopySrc;
-            descriptor.size = bytesPerRow * (GetHeight() / GetFormat().blockHeight);
+            descriptor.size = bytesPerRow * (GetHeight() / blockInfo.blockHeight);
             if (descriptor.size > std::numeric_limits<uint32_t>::max()) {
                 return DAWN_OUT_OF_MEMORY_ERROR("Unable to allocate buffer.");
             }
@@ -345,7 +348,7 @@
 
             // Bind buffer and texture, and make the buffer to texture copy
             gl.PixelStorei(GL_UNPACK_ROW_LENGTH,
-                           (bytesPerRow / GetFormat().blockByteSize) * GetFormat().blockWidth);
+                           (bytesPerRow / blockInfo.blockByteSize) * blockInfo.blockWidth);
             gl.PixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
             for (uint32_t level = range.baseMipLevel; level < range.baseMipLevel + range.levelCount;
                  ++level) {
diff --git a/src/dawn_native/vulkan/CommandBufferVk.cpp b/src/dawn_native/vulkan/CommandBufferVk.cpp
index d8bc79b..cc05048 100644
--- a/src/dawn_native/vulkan/CommandBufferVk.cpp
+++ b/src/dawn_native/vulkan/CommandBufferVk.cpp
@@ -376,15 +376,17 @@
         const TextureCopy& dstCopy,
         const Extent3D& copySize) {
         ASSERT(srcCopy.texture->GetFormat().format == dstCopy.texture->GetFormat().format);
+        ASSERT(srcCopy.aspect == dstCopy.aspect);
         dawn_native::Format format = srcCopy.texture->GetFormat();
-        ASSERT(copySize.width % format.blockWidth == 0);
-        ASSERT(copySize.height % format.blockHeight == 0);
+        const TexelBlockInfo& blockInfo = format.GetTexelBlockInfo(srcCopy.aspect);
+        ASSERT(copySize.width % blockInfo.blockWidth == 0);
+        ASSERT(copySize.height % blockInfo.blockHeight == 0);
 
         // Create the temporary buffer. Note that We don't need to respect WebGPU's 256 alignment
         // because it isn't a hard constraint in Vulkan.
         uint64_t tempBufferSize =
-            (copySize.width / format.blockWidth * copySize.height / format.blockHeight) *
-            format.blockByteSize;
+            (copySize.width / blockInfo.blockWidth * copySize.height / blockInfo.blockHeight) *
+            blockInfo.blockByteSize;
         BufferDescriptor tempBufferDescriptor;
         tempBufferDescriptor.size = tempBufferSize;
         tempBufferDescriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
@@ -396,7 +398,8 @@
         tempBufferCopy.buffer = tempBuffer.Get();
         tempBufferCopy.rowsPerImage = copySize.height;
         tempBufferCopy.offset = 0;
-        tempBufferCopy.bytesPerRow = copySize.width / format.blockWidth * format.blockByteSize;
+        tempBufferCopy.bytesPerRow =
+            copySize.width / blockInfo.blockWidth * blockInfo.blockByteSize;
 
         VkCommandBuffer commands = recordingContext->commandBuffer;
         VkImage srcImage = ToBackend(srcCopy.texture)->GetHandle();
diff --git a/src/dawn_native/vulkan/TextureVk.cpp b/src/dawn_native/vulkan/TextureVk.cpp
index f45e2b4..83bef81 100644
--- a/src/dawn_native/vulkan/TextureVk.cpp
+++ b/src/dawn_native/vulkan/TextureVk.cpp
@@ -945,10 +945,12 @@
             }
         } else {
             // create temp buffer with clear color to copy to the texture image
+            const TexelBlockInfo& blockInfo =
+                GetFormat().GetTexelBlockInfo(wgpu::TextureAspect::All);
             uint32_t bytesPerRow =
-                Align((GetWidth() / GetFormat().blockWidth) * GetFormat().blockByteSize,
+                Align((GetWidth() / blockInfo.blockWidth) * blockInfo.blockByteSize,
                       kTextureBytesPerRowAlignment);
-            uint64_t bufferSize64 = bytesPerRow * (GetHeight() / GetFormat().blockHeight);
+            uint64_t bufferSize64 = bytesPerRow * (GetHeight() / blockInfo.blockHeight);
             if (bufferSize64 > std::numeric_limits<uint32_t>::max()) {
                 return DAWN_OUT_OF_MEMORY_ERROR("Unable to allocate buffer.");
             }
@@ -957,7 +959,7 @@
             UploadHandle uploadHandle;
             DAWN_TRY_ASSIGN(uploadHandle,
                             uploader->Allocate(bufferSize, device->GetPendingCommandSerial(),
-                                               GetFormat().blockByteSize));
+                                               blockInfo.blockByteSize));
             memset(uploadHandle.mappedBuffer, clearColor, bufferSize);
 
             // compute the buffer image copy to set the clear region of entire texture
diff --git a/src/tests/unittests/d3d12/CopySplitTests.cpp b/src/tests/unittests/d3d12/CopySplitTests.cpp
index 9a6754c..71b165d 100644
--- a/src/tests/unittests/d3d12/CopySplitTests.cpp
+++ b/src/tests/unittests/d3d12/CopySplitTests.cpp
@@ -290,13 +290,13 @@
     Texture2DCopySplit DoTest(const TextureSpec& textureSpec, const BufferSpec& bufferSpec) {
         ASSERT(textureSpec.width % textureSpec.blockWidth == 0 &&
                textureSpec.height % textureSpec.blockHeight == 0);
-        dawn_native::Format fakeFormat = {};
-        fakeFormat.blockWidth = textureSpec.blockWidth;
-        fakeFormat.blockHeight = textureSpec.blockHeight;
-        fakeFormat.blockByteSize = textureSpec.texelBlockSizeInBytes;
+        dawn_native::TexelBlockInfo blockInfo = {};
+        blockInfo.blockWidth = textureSpec.blockWidth;
+        blockInfo.blockHeight = textureSpec.blockHeight;
+        blockInfo.blockByteSize = textureSpec.texelBlockSizeInBytes;
         Texture2DCopySplit copySplit = ComputeTextureCopySplit(
             {textureSpec.x, textureSpec.y, textureSpec.z},
-            {textureSpec.width, textureSpec.height, textureSpec.depth}, fakeFormat,
+            {textureSpec.width, textureSpec.height, textureSpec.depth}, blockInfo,
             bufferSpec.offset, bufferSpec.bytesPerRow, bufferSpec.rowsPerImage);
         ValidateCopySplit(textureSpec, bufferSpec, copySplit);
         return copySplit;