From f73ae3c6a3dbb261c63f25f279b354edf282f5aa Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Wed, 17 Apr 2019 22:11:22 -0700 Subject: Fixed copying compressed textures in Vulkan back-end --- .../src/DeviceContextVkImpl.cpp | 43 ++++++++++++---------- .../GraphicsEngineVulkan/src/TextureVkImpl.cpp | 22 +++++++---- 2 files changed, 38 insertions(+), 27 deletions(-) (limited to 'Graphics/GraphicsEngineVulkan') diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index d9d9b3bf..636a2598 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -1339,7 +1339,8 @@ namespace Diligent FullMipBox.MaxZ = 1; pSrcBox = &FullMipBox; } - const auto& FmtAttribs = GetDevice()->GetTextureFormatInfo(DstTexDesc.Format); + const auto& DstFmtAttribs = GetTextureFormatAttribs(DstTexDesc.Format); + const auto& SrcFmtAttribs = GetTextureFormatAttribs(SrcTexDesc.Format); if (SrcTexDesc.Usage != USAGE_STAGING && DstTexDesc.Usage != USAGE_STAGING) { VkImageCopy CopyRegion = {}; @@ -1351,9 +1352,9 @@ namespace Diligent CopyRegion.extent.depth = std::max(pSrcBox->MaxZ - pSrcBox->MinZ, 1u); VkImageAspectFlags aspectMask = 0; - if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH) + if (DstFmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH) aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - else if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL) + else if (DstFmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL) { aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; } @@ -1385,10 +1386,12 @@ namespace Diligent auto SrcMipLevelAttribs = GetMipLevelProperties(SrcTexDesc, CopyAttribs.SrcMipLevel); // address of (x,y,z) = region->bufferOffset + (((z * imageHeight) + y) * rowLength + x) * texelBlockSize; (18.4.1) SrcBufferOffset += - (pSrcBox->MinZ * SrcMipLevelAttribs.Height + pSrcBox->MinY) * SrcMipLevelAttribs.RowSize + - (FmtAttribs.ComponentType != COMPONENT_TYPE_COMPRESSED ? - pSrcBox->MinX * FmtAttribs.ComponentSize * FmtAttribs.NumComponents : - pSrcBox->MinX / FmtAttribs.BlockWidth * FmtAttribs.ComponentSize); + // For compressed-block formats, RowSize is the size of one compressed row. + // For non-compressed formats, BlockHeight is 1. + (pSrcBox->MinZ * SrcMipLevelAttribs.Height + pSrcBox->MinY) / SrcFmtAttribs.BlockHeight * SrcMipLevelAttribs.RowSize + + // For compressed-block formats, ComponentSize is the block size and NumComponents is 1. + // For non-compressed formats, BlockWidth is 1. + (pSrcBox->MinX / SrcFmtAttribs.BlockWidth) * SrcFmtAttribs.ComponentSize * SrcFmtAttribs.NumComponents; Box DstBox; DstBox.MinX = CopyAttribs.DstX; @@ -1418,10 +1421,12 @@ namespace Diligent auto DstMipLevelAttribs = GetMipLevelProperties(DstTexDesc, CopyAttribs.DstMipLevel); // address of (x,y,z) = region->bufferOffset + (((z * imageHeight) + y) * rowLength + x) * texelBlockSize; (18.4.1) DstBufferOffset += - (CopyAttribs.DstZ * DstMipLevelAttribs.Height + CopyAttribs.DstY) * DstMipLevelAttribs.RowSize * - (FmtAttribs.ComponentType != COMPONENT_TYPE_COMPRESSED ? - CopyAttribs.DstX * FmtAttribs.ComponentSize * FmtAttribs.NumComponents : - CopyAttribs.DstX / FmtAttribs.BlockWidth * FmtAttribs.ComponentSize); + // For compressed-block formats, RowSize is the size of one compressed row. + // For non-compressed formats, BlockHeight is 1. + (CopyAttribs.DstZ * DstMipLevelAttribs.Height + CopyAttribs.DstY) / DstFmtAttribs.BlockHeight * DstMipLevelAttribs.RowSize * + // For compressed-block formats, ComponentSize is the block size and NumComponents is 1. + // For non-compressed formats, BlockWidth is 1. + (CopyAttribs.DstX / DstFmtAttribs.BlockWidth) * DstFmtAttribs.ComponentSize * DstFmtAttribs.NumComponents; CopyTextureToBuffer( *pSrcTexVk, @@ -1763,10 +1768,12 @@ namespace Diligent auto MipLevelAttribs = GetMipLevelProperties(TexDesc, MipLevel); // address of (x,y,z) = region->bufferOffset + (((z * imageHeight) + y) * rowLength + x) * texelBlockSize; (18.4.1) auto MapStartOffset = SubresourceOffset + - (pMapRegion->MinZ * MipLevelAttribs.Height + pMapRegion->MinY) * MipLevelAttribs.RowSize + - (FmtAttribs.ComponentType != COMPONENT_TYPE_COMPRESSED ? - pMapRegion->MinX * FmtAttribs.ComponentSize * FmtAttribs.NumComponents : - pMapRegion->MinX / FmtAttribs.BlockWidth * FmtAttribs.ComponentSize); + // For compressed-block formats, RowSize is the size of one compressed row. + // For non-compressed formats, BlockHeight is 1. + (pMapRegion->MinZ * MipLevelAttribs.Height + pMapRegion->MinY) / FmtAttribs.BlockHeight * MipLevelAttribs.RowSize + + // For compressed-block formats, ComponentSize is the block size and NumComponents is 1. + // For non-compressed formats, BlockWidth is 1. + pMapRegion->MinX / FmtAttribs.BlockWidth * FmtAttribs.ComponentSize * FmtAttribs.NumComponents; MappedData.pData = TextureVk.GetStagingDataCPUAddress() + MapStartOffset; MappedData.Stride = MipLevelAttribs.RowSize; @@ -1779,10 +1786,8 @@ namespace Diligent // to make device writes visible to CPU reads VERIFY_EXPR(pMapRegion->MaxZ >= 1 && pMapRegion->MaxY >= 1); auto MapEndOffset = SubresourceOffset + - ((pMapRegion->MaxZ-1) * MipLevelAttribs.Height + (pMapRegion->MaxY-1)) * MipLevelAttribs.RowSize + - (FmtAttribs.ComponentType != COMPONENT_TYPE_COMPRESSED ? - pMapRegion->MaxX * FmtAttribs.ComponentSize * FmtAttribs.NumComponents : - pMapRegion->MaxX / FmtAttribs.BlockWidth * FmtAttribs.ComponentSize); + ((pMapRegion->MaxZ-1) * MipLevelAttribs.Height + (pMapRegion->MaxY-FmtAttribs.BlockHeight)) / FmtAttribs.BlockHeight * MipLevelAttribs.RowSize + + (pMapRegion->MaxX / FmtAttribs.BlockWidth) * FmtAttribs.ComponentSize * FmtAttribs.NumComponents; TextureVk.InvalidateStagingRange(MapStartOffset, MapEndOffset - MapStartOffset); } else if (MapType == MAP_WRITE) diff --git a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp index 8739397f..c6f336ee 100644 --- a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp @@ -45,9 +45,12 @@ MipLevelProperties GetMipLevelProperties(const TextureDesc& TexDesc, Uint32 MipL if (FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED) { VERIFY_EXPR(FmtAttribs.BlockWidth > 1 && FmtAttribs.BlockHeight > 1); - MipProps.Width = (MipProps.Width + FmtAttribs.BlockWidth -1) / FmtAttribs.BlockWidth; - MipProps.Height = (MipProps.Height + FmtAttribs.BlockHeight-1) / FmtAttribs.BlockHeight; - MipProps.RowSize = MipProps.Width * Uint32{FmtAttribs.ComponentSize}; // ComponentSize is the block size + VERIFY((FmtAttribs.BlockWidth & (FmtAttribs.BlockWidth-1)) == 0, "Compressed block widht is expected to be power of 2"); + VERIFY((FmtAttribs.BlockHeight & (FmtAttribs.BlockHeight-1)) == 0, "Compressed block widht is expected to be power of 2"); + // For block-compression formats, all parameters are still specified in texels rather than compressed texel blocks (18.4.1) + MipProps.Width = Align(MipProps.Width, Uint32{FmtAttribs.BlockWidth}); + MipProps.Height = Align(MipProps.Height,Uint32{FmtAttribs.BlockHeight}); + MipProps.RowSize = MipProps.Width / Uint32{FmtAttribs.BlockWidth} * Uint32{FmtAttribs.ComponentSize}; // ComponentSize is the block size } else { @@ -274,7 +277,8 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, CopyRegion.imageSubresource.layerCount = 1; VERIFY(SubResData.Stride == 0 || SubResData.Stride >= MipInfo.RowSize, "Stride is too small"); - VERIFY(SubResData.DepthStride == 0 || SubResData.DepthStride >= MipInfo.RowSize * MipInfo.Height, "Depth stride is too small"); + // For compressed-block formats, MipInfo.RowSize is the size of one row of blocks + VERIFY(SubResData.DepthStride == 0 || SubResData.DepthStride >= (MipInfo.Height / FmtAttribs.BlockHeight) * MipInfo.RowSize, "Depth stride is too small"); // bufferOffset must be a multiple of 4 (18.4) // If the calling command's VkImage parameter is a compressed image, bufferOffset @@ -330,14 +334,16 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters, VERIFY_EXPR(MipInfo.Depth == CopyRegion.imageExtent.depth); VERIFY(SubResData.Stride == 0 || SubResData.Stride >= MipInfo.RowSize, "Stride is too small"); - VERIFY(SubResData.DepthStride == 0 || SubResData.DepthStride >= MipInfo.RowSize * MipInfo.Height, "Depth stride is too small"); + // For compressed-block formats, MipInfo.RowSize is the size of one row of blocks + VERIFY(SubResData.DepthStride == 0 || SubResData.DepthStride >= (MipInfo.Height / FmtAttribs.BlockHeight) * MipInfo.RowSize, "Depth stride is too small"); for(Uint32 z=0; z < MipInfo.Depth; ++z) { - for(Uint32 y=0; y < MipInfo.Height; ++y) + for(Uint32 y=0; y < MipInfo.Height; y += FmtAttribs.BlockHeight) { - memcpy(StagingData + CopyRegion.bufferOffset + (y + z * MipInfo.Height) * MipInfo.RowSize, - reinterpret_cast(SubResData.pData) + y * SubResData.Stride + z * SubResData.DepthStride, + memcpy(StagingData + CopyRegion.bufferOffset + ((y + z * MipInfo.Height) / FmtAttribs.BlockHeight) * MipInfo.RowSize, + // SubResData.Stride must be the stride of one row of compressed blocks + reinterpret_cast(SubResData.pData) + (y/FmtAttribs.BlockHeight) * SubResData.Stride + z * SubResData.DepthStride, MipInfo.RowSize); } } -- cgit v1.2.3