diff --git a/src/dawn_native/CommandBuffer.cpp b/src/dawn_native/CommandBuffer.cpp index 91fec29f18..2dae6a28d9 100644 --- a/src/dawn_native/CommandBuffer.cpp +++ b/src/dawn_native/CommandBuffer.cpp @@ -162,7 +162,6 @@ namespace dawn_native { } } - // TODO(jiawei.shao@intel.com): support copying with depth stencil textures bool IsFullBufferOverwrittenInTextureToBufferCopy(const CopyTextureToBufferCmd* copy) { ASSERT(copy != nullptr); @@ -175,16 +174,17 @@ namespace dawn_native { } 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 88717c7110..e846e11cfb 100644 --- a/src/dawn_native/CommandEncoder.cpp +++ b/src/dawn_native/CommandEncoder.cpp @@ -622,12 +622,12 @@ namespace dawn_native { 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 @@ namespace dawn_native { } // 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 @@ namespace dawn_native { 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 @@ namespace dawn_native { } // 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 @@ namespace dawn_native { 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 b412ab6501..c2ac26f2ac 100644 --- a/src/dawn_native/CommandValidation.cpp +++ b/src/dawn_native/CommandValidation.cpp @@ -490,16 +490,6 @@ namespace dawn_native { 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 @@ namespace dawn_native { } // 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 11b71d269b..53af2588f6 100644 --- a/src/dawn_native/Format.cpp +++ b/src/dawn_native/Format.cpp @@ -82,21 +82,13 @@ namespace dawn_native { 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 @@ namespace dawn_native { 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 @@ namespace dawn_native { 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 @@ namespace dawn_native { 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 @@ namespace dawn_native { 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 @@ namespace dawn_native { 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 15c6c311a3..63c450e3b7 100644 --- a/src/dawn_native/Format.h +++ b/src/dawn_native/Format.h @@ -39,8 +39,11 @@ namespace dawn_native { // exact number of known format. static constexpr size_t kKnownFormatCount = 53; + struct Format; + using FormatTable = std::array; + // 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 @@ namespace dawn_native { // 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; - // 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 d658a2a646..2ec53c6cf6 100644 --- a/src/dawn_native/Queue.cpp +++ b/src/dawn_native/Queue.cpp @@ -378,12 +378,12 @@ namespace dawn_native { 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 8f93b46ddf..38ce4d209a 100644 --- a/src/dawn_native/Texture.cpp +++ b/src/dawn_native/Texture.cpp @@ -159,8 +159,9 @@ namespace dawn_native { 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 @@ namespace dawn_native { // 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 3d87186e4a..6ccd2e3e4c 100644 --- a/src/dawn_native/d3d12/TextureD3D12.cpp +++ b/src/dawn_native/d3d12/TextureD3D12.cpp @@ -952,7 +952,7 @@ namespace dawn_native { namespace d3d12 { 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 7891c7f6ce..bee68d7a57 100644 --- a/src/dawn_native/metal/CommandBufferMTL.mm +++ b/src/dawn_native/metal/CommandBufferMTL.mm @@ -643,7 +643,7 @@ namespace dawn_native { namespace metal { 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 @@ namespace dawn_native { namespace metal { 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 449f338951..a0b08fbe5a 100644 --- a/src/dawn_native/metal/TextureMTL.mm +++ b/src/dawn_native/metal/TextureMTL.mm @@ -488,15 +488,17 @@ namespace dawn_native { namespace metal { } 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(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 @@ namespace dawn_native { namespace metal { UploadHandle uploadHandle; DAWN_TRY_ASSIGN(uploadHandle, uploader->Allocate(bufferSize, device->GetPendingCommandSerial(), - GetFormat().blockByteSize)); + blockInfo.blockByteSize)); memset(uploadHandle.mappedBuffer, clearColor, bufferSize); id encoder = commandContext->EnsureBlit(); diff --git a/src/dawn_native/metal/UtilsMetal.h b/src/dawn_native/metal/UtilsMetal.h index d7c0a70e52..a7a5dee0db 100644 --- a/src/dawn_native/metal/UtilsMetal.h +++ b/src/dawn_native/metal/UtilsMetal.h @@ -47,7 +47,8 @@ namespace dawn_native { namespace metal { 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 3b8f64c0d8..840524b8af 100644 --- a/src/dawn_native/metal/UtilsMetal.mm +++ b/src/dawn_native/metal/UtilsMetal.mm @@ -49,9 +49,11 @@ namespace dawn_native { namespace metal { 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 @@ namespace dawn_native { namespace metal { // 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 @@ namespace dawn_native { namespace metal { } // 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 @@ namespace dawn_native { namespace metal { 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 @@ namespace dawn_native { namespace metal { // 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 e9e98b101c..6776c020bf 100644 --- a/src/dawn_native/opengl/CommandBufferGL.cpp +++ b/src/dawn_native/opengl/CommandBufferGL.cpp @@ -540,21 +540,21 @@ namespace dawn_native { namespace opengl { 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 3bc247b907..98641713be 100644 --- a/src/dawn_native/opengl/TextureGL.cpp +++ b/src/dawn_native/opengl/TextureGL.cpp @@ -289,7 +289,9 @@ namespace dawn_native { namespace opengl { 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 clearColorData; clearColor = (clearValue == TextureBase::ClearValue::Zero) ? 0 : 255; clearColorData.fill(clearColor); @@ -317,19 +319,20 @@ namespace dawn_native { namespace opengl { 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::max()) { return DAWN_OUT_OF_MEMORY_ERROR("Unable to allocate buffer."); } @@ -345,7 +348,7 @@ namespace dawn_native { namespace opengl { // 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 d8bc79ba5c..cc05048637 100644 --- a/src/dawn_native/vulkan/CommandBufferVk.cpp +++ b/src/dawn_native/vulkan/CommandBufferVk.cpp @@ -376,15 +376,17 @@ namespace dawn_native { namespace vulkan { 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 @@ namespace dawn_native { namespace vulkan { 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 f45e2b467b..83bef81847 100644 --- a/src/dawn_native/vulkan/TextureVk.cpp +++ b/src/dawn_native/vulkan/TextureVk.cpp @@ -945,10 +945,12 @@ namespace dawn_native { namespace vulkan { } } 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::max()) { return DAWN_OUT_OF_MEMORY_ERROR("Unable to allocate buffer."); } @@ -957,7 +959,7 @@ namespace dawn_native { namespace vulkan { 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 9a6754c10b..71b165d572 100644 --- a/src/tests/unittests/d3d12/CopySplitTests.cpp +++ b/src/tests/unittests/d3d12/CopySplitTests.cpp @@ -290,13 +290,13 @@ class CopySplitTest : public testing::Test { 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;