summaryrefslogtreecommitdiffstats
path: root/Graphics
diff options
context:
space:
mode:
authorEgor Yusov <egor.yusov@gmail.com>2018-08-30 05:33:33 +0000
committerEgor Yusov <egor.yusov@gmail.com>2018-08-30 05:33:33 +0000
commit7dcb7b4a2c5965a90a7fdd5fd1950d5a1036900a (patch)
tree7559c64aebaaae5a2c4a2f7a2de7e22377191af2 /Graphics
parentFixed debug checks (diff)
downloadDiligentCore-7dcb7b4a2c5965a90a7fdd5fd1950d5a1036900a.tar.gz
DiligentCore-7dcb7b4a2c5965a90a7fdd5fd1950d5a1036900a.zip
Fixed handling of small compressed texture subresources
Diffstat (limited to 'Graphics')
-rw-r--r--Graphics/GraphicsEngine/interface/GraphicsTypes.h21
-rw-r--r--Graphics/GraphicsEngine/src/Texture.cpp63
-rw-r--r--Graphics/GraphicsEngineD3D11/src/TextureBaseD3D11.cpp22
-rw-r--r--Graphics/GraphicsEngineD3D12/include/TextureD3D12Impl.h10
-rw-r--r--Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp62
-rw-r--r--Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp30
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/Texture1DArray_OGL.cpp4
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/Texture1D_OGL.cpp4
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/Texture2DArray_OGL.cpp20
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/Texture2D_OGL.cpp18
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/Texture3D_OGL.cpp6
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/TextureCubeArray_OGL.cpp18
-rw-r--r--Graphics/GraphicsEngineOpenGL/src/TextureCube_OGL.cpp18
-rw-r--r--Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp54
14 files changed, 245 insertions, 105 deletions
diff --git a/Graphics/GraphicsEngine/interface/GraphicsTypes.h b/Graphics/GraphicsEngine/interface/GraphicsTypes.h
index 8201ebd6..4ac6148a 100644
--- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h
+++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h
@@ -1394,21 +1394,12 @@ namespace Diligent
/// Box
struct Box
{
- Uint32 MinX; ///< Minimal X coordinate. Default value is 0
- Uint32 MaxX; ///< Maximal X coordinate. Default value is 0
- Uint32 MinY; ///< Minimal Y coordinate. Default value is 0
- Uint32 MaxY; ///< Maximal Y coordinate. Default value is 0
- Uint32 MinZ; ///< Minimal Z coordinate. Default value is 0
- Uint32 MaxZ; ///< Maximal Z coordinate. Default value is 1
-
- /// Constructor intializes the structure
- Box(Uint32 _MinX = 0, Uint32 _MaxX = 0,
- Uint32 _MinY = 0, Uint32 _MaxY = 0,
- Uint32 _MinZ = 0, Uint32 _MaxZ = 1) :
- MinX(_MinX), MaxX(_MaxX),
- MinY(_MinY), MaxY(_MaxY),
- MinZ(_MinZ), MaxZ(_MaxZ)
- {}
+ Uint32 MinX = 0; ///< Minimal X coordinate. Default value is 0
+ Uint32 MaxX = 0; ///< Maximal X coordinate. Default value is 0
+ Uint32 MinY = 0; ///< Minimal Y coordinate. Default value is 0
+ Uint32 MaxY = 0; ///< Maximal Y coordinate. Default value is 0
+ Uint32 MinZ = 0; ///< Minimal Z coordinate. Default value is 0
+ Uint32 MaxZ = 1; ///< Maximal Z coordinate. Default value is 1
};
diff --git a/Graphics/GraphicsEngine/src/Texture.cpp b/Graphics/GraphicsEngine/src/Texture.cpp
index 9b78202f..1bb69c72 100644
--- a/Graphics/GraphicsEngine/src/Texture.cpp
+++ b/Graphics/GraphicsEngine/src/Texture.cpp
@@ -133,14 +133,34 @@ void ValidateTextureRegion(const TextureDesc& TexDesc, Uint32 MipLevel, Uint32 S
VERIFY_TEX_PARAMS( Slice == 0, "Array slice (", Slice, ") must be 0 for non-array textures" );
}
+ const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format);
Uint32 MipWidth = std::max(TexDesc.Width >> MipLevel, 1U);
- VERIFY_TEX_PARAMS( Box.MaxX <= MipWidth, "Region max X coordinate (", Box.MaxX, ") is out of allowed range [0, ", MipWidth, "]" );
+ if(FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED)
+ {
+ VERIFY_EXPR( (FmtAttribs.BlockWidth & (FmtAttribs.BlockWidth-1)) == 0);
+ Uint32 BlockAlignedMipWidth = (MipWidth + (FmtAttribs.BlockWidth-1)) & ~(FmtAttribs.BlockWidth-1);
+ VERIFY_TEX_PARAMS( Box.MaxX <= BlockAlignedMipWidth, "Region max X coordinate (", Box.MaxX, ") is out of allowed range [0, ", BlockAlignedMipWidth, "]" );
+ VERIFY_TEX_PARAMS( (Box.MinX % FmtAttribs.BlockWidth) == 0, "For compressed formats, update region min x (", Box.MinX, ") must be a multiple of block width (", FmtAttribs.BlockWidth, ")" );
+ VERIFY_TEX_PARAMS( (Box.MaxX % FmtAttribs.BlockWidth) == 0 || Box.MaxX == MipWidth, "For compressed formats, update region max x (", Box.MaxX, ") must be a multiple of block width (", FmtAttribs.BlockWidth, ") or equal the mip level width (", MipWidth, ")" );
+ }
+ else
+ VERIFY_TEX_PARAMS( Box.MaxX <= MipWidth, "Region max X coordinate (", Box.MaxX, ") is out of allowed range [0, ", MipWidth, "]" );
+
if (TexDesc.Type != RESOURCE_DIM_TEX_1D &&
TexDesc.Type != RESOURCE_DIM_TEX_1D_ARRAY)
{
Uint32 MipHeight = std::max(TexDesc.Height >> MipLevel, 1U);
- VERIFY_TEX_PARAMS( Box.MaxY <= MipHeight, "Region max Y coordinate (", Box.MaxY, ") is out of allowed range [0, ", MipHeight, "]" );
+ if(FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED)
+ {
+ VERIFY_EXPR( (FmtAttribs.BlockHeight & (FmtAttribs.BlockHeight-1)) == 0);
+ Uint32 BlockAlignedMipHeight = (MipHeight + (FmtAttribs.BlockHeight-1)) & ~(FmtAttribs.BlockHeight-1);
+ VERIFY_TEX_PARAMS( Box.MaxY <= BlockAlignedMipHeight, "Region max Y coordinate (", Box.MaxY, ") is out of allowed range [0, ", BlockAlignedMipHeight, "]" );
+ VERIFY_TEX_PARAMS( (Box.MinY % FmtAttribs.BlockHeight) == 0, "For compressed formats, update region min y (", Box.MinY, ") must be a multiple of block height (", FmtAttribs.BlockHeight, ")" );
+ VERIFY_TEX_PARAMS( (Box.MaxY % FmtAttribs.BlockHeight) == 0 || Box.MaxY == MipHeight, "For compressed formats, update region max y (", Box.MaxY, ") must be a multiple of block height (", FmtAttribs.BlockHeight, ") or equal the mip level height (", MipHeight, ")" );
+ }
+ else
+ VERIFY_TEX_PARAMS( Box.MaxY <= MipHeight, "Region max Y coordinate (", Box.MaxY, ") is out of allowed range [0, ", MipHeight, "]" );
}
if (TexDesc.Type == RESOURCE_DIM_TEX_3D)
@@ -148,14 +168,10 @@ void ValidateTextureRegion(const TextureDesc& TexDesc, Uint32 MipLevel, Uint32 S
Uint32 MipDepth = std::max(TexDesc.Depth >> MipLevel, 1U);
VERIFY_TEX_PARAMS( Box.MaxZ <= MipDepth, "Region max Z coordinate (", Box.MaxZ, ") is out of allowed range [0, ", MipDepth, "]" );
}
-
- const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format);
- if (FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED)
+ else
{
- VERIFY_TEX_PARAMS( (Box.MinX % FmtAttribs.BlockWidth) == 0, "For compressed formats update region min x (", Box.MinX, ") must be a multiple of block width (", FmtAttribs.BlockWidth, ")" );
- VERIFY_TEX_PARAMS( (Box.MaxX % FmtAttribs.BlockWidth) == 0, "For compressed formats update region max x (", Box.MaxX, ") must be a multiple of block width (", FmtAttribs.BlockWidth, ")" );
- VERIFY_TEX_PARAMS( (Box.MinY % FmtAttribs.BlockHeight) == 0, "For compressed formats update region min y (", Box.MinY, ") must be a multiple of block height (", FmtAttribs.BlockHeight, ")" );
- VERIFY_TEX_PARAMS( (Box.MaxY % FmtAttribs.BlockHeight) == 0, "For compressed formats update region max y (", Box.MaxY, ") must be a multiple of block height (", FmtAttribs.BlockHeight, ")" );
+ VERIFY_TEX_PARAMS( Box.MinZ == 0, "Region min Z (", Box.MinZ, ") must be 0 for all but 3D textures" );
+ VERIFY_TEX_PARAMS( Box.MaxZ == 1, "Region max Z (", Box.MaxZ, ") must be 1 for all but 3D textures" );
}
#endif
}
@@ -171,14 +187,31 @@ void ValidateUpdateDataParams( const TextureDesc& TexDesc, Uint32 MipLevel, Uint
VERIFY_TEX_PARAMS( (SubresData.Stride & 0x03) == 0, "Texture data stride (", SubresData.Stride, ") must be at least 32-bit aligned" );
VERIFY_TEX_PARAMS( (SubresData.DepthStride & 0x03) == 0, "Texture data depth stride (", SubresData.DepthStride, ") must be at least 32-bit aligned" );
- const auto UpdateRegionWidth = DstBox.MaxX - DstBox.MinX;
- const auto UpdateRegionHeight = DstBox.MaxY - DstBox.MinY;
+ auto UpdateRegionWidth = DstBox.MaxX - DstBox.MinX;
+ auto UpdateRegionHeight = DstBox.MaxY - DstBox.MinY;
+ auto UpdateRegionDepth = DstBox.MaxZ - DstBox.MinZ;
const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format);
- const Uint32 RowSize = FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED ?
- UpdateRegionWidth / Uint32{FmtAttribs.BlockWidth} * Uint32{FmtAttribs.ComponentSize} :
- UpdateRegionWidth * Uint32{FmtAttribs.ComponentSize} * Uint32{FmtAttribs.NumComponents};
+ Uint32 RowSize = 0;
+ Uint32 RowCount = 0;
+ if (FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED)
+ {
+ // Align update region size by the block size. This is only necessary when updating
+ // coarse mip levels. Otherwise UpdateRegionWidth/Height should be multiples of block size
+ VERIFY_EXPR( (FmtAttribs.BlockWidth & (FmtAttribs.BlockWidth-1)) == 0);
+ VERIFY_EXPR( (FmtAttribs.BlockHeight & (FmtAttribs.BlockHeight-1)) == 0);
+ UpdateRegionWidth = (UpdateRegionWidth + (FmtAttribs.BlockWidth-1)) & ~(FmtAttribs.BlockWidth -1);
+ UpdateRegionHeight = (UpdateRegionHeight + (FmtAttribs.BlockHeight-1)) & ~(FmtAttribs.BlockHeight-1);
+ RowSize = UpdateRegionWidth / Uint32{FmtAttribs.BlockWidth} * Uint32{FmtAttribs.ComponentSize};
+ RowCount = UpdateRegionHeight / FmtAttribs.BlockHeight;
+ }
+ else
+ {
+ RowSize = UpdateRegionWidth * Uint32{FmtAttribs.ComponentSize} * Uint32{FmtAttribs.NumComponents};
+ RowCount = UpdateRegionHeight;
+ }
DEV_CHECK_ERR(SubresData.Stride >= RowSize, "Source data stride (", SubresData.Stride, ") is below the image row size (", RowSize, ")");
- DEV_CHECK_ERR(SubresData.DepthStride == 0 || SubresData.DepthStride >= SubresData.Stride * (UpdateRegionHeight / FmtAttribs.BlockHeight), "Source data depth stride (", SubresData.DepthStride, ") is below the image plane size (", SubresData.Stride * UpdateRegionHeight, ")");
+ const Uint32 PlaneSize = SubresData.Stride * RowCount;
+ DEV_CHECK_ERR(UpdateRegionDepth == 1 || SubresData.DepthStride >= PlaneSize, "Source data depth stride (", SubresData.DepthStride, ") is below the image plane size (", PlaneSize, ")");
#endif
}
diff --git a/Graphics/GraphicsEngineD3D11/src/TextureBaseD3D11.cpp b/Graphics/GraphicsEngineD3D11/src/TextureBaseD3D11.cpp
index 44fc2dc6..c9762716 100644
--- a/Graphics/GraphicsEngineD3D11/src/TextureBaseD3D11.cpp
+++ b/Graphics/GraphicsEngineD3D11/src/TextureBaseD3D11.cpp
@@ -158,12 +158,24 @@ void TextureBaseD3D11::UpdateData( IDeviceContext* pContext, Uint32 MipLevel, Ui
auto* pd3d11DeviceContext = static_cast<DeviceContextD3D11Impl*>(pContext)->GetD3D11DeviceContext();
D3D11_BOX D3D11Box;
- D3D11Box.left = DstBox.MinX;
- D3D11Box.right = DstBox.MaxX;
- D3D11Box.top = DstBox.MinY;
+ D3D11Box.left = DstBox.MinX;
+ D3D11Box.right = DstBox.MaxX;
+ D3D11Box.top = DstBox.MinY;
D3D11Box.bottom = DstBox.MaxY;
- D3D11Box.front = DstBox.MinZ;
- D3D11Box.back = DstBox.MaxZ;
+ D3D11Box.front = DstBox.MinZ;
+ D3D11Box.back = DstBox.MaxZ;
+ const auto& FmtAttribs = GetTextureFormatAttribs(m_Desc.Format);
+ if (FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED)
+ {
+ // Align update region by the compressed block size
+ VERIFY( (D3D11Box.left % FmtAttribs.BlockWidth) == 0, "Update region min x (", D3D11Box.left, ") must be multiple of a compressed block width (", FmtAttribs.BlockWidth, ")");
+ VERIFY( (FmtAttribs.BlockWidth & (FmtAttribs.BlockWidth-1)) == 0, "Compressed block width (", FmtAttribs.BlockWidth, ") is expected to be power of 2");
+ D3D11Box.right = (D3D11Box.right + FmtAttribs.BlockWidth-1) & ~(FmtAttribs.BlockWidth-1);
+
+ VERIFY( (D3D11Box.top % FmtAttribs.BlockHeight) == 0, "Update region min y (", D3D11Box.top, ") must be multiple of a compressed block height (", FmtAttribs.BlockHeight, ")");
+ VERIFY( (FmtAttribs.BlockHeight & (FmtAttribs.BlockHeight-1)) == 0, "Compressed block height (", FmtAttribs.BlockHeight, ") is expected to be power of 2");
+ D3D11Box.bottom = (D3D11Box.bottom + FmtAttribs.BlockHeight-1) & ~(FmtAttribs.BlockHeight-1);
+ }
auto SubresIndex = D3D11CalcSubresource(MipLevel, Slice, m_Desc.MipLevels);
pd3d11DeviceContext->UpdateSubresource(m_pd3d11Texture, SubresIndex, &D3D11Box, SubresData.pData, SubresData.Stride, SubresData.DepthStride);
}
diff --git a/Graphics/GraphicsEngineD3D12/include/TextureD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/TextureD3D12Impl.h
index 65f0d493..95430ade 100644
--- a/Graphics/GraphicsEngineD3D12/include/TextureD3D12Impl.h
+++ b/Graphics/GraphicsEngineD3D12/include/TextureD3D12Impl.h
@@ -58,13 +58,13 @@ public:
ID3D12Resource* pTexture);
~TextureD3D12Impl();
- virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface )override;
+ virtual void QueryInterface( const Diligent::INTERFACE_ID &IID, IObject **ppInterface )override final;
- virtual void UpdateData( IDeviceContext *pContext, Uint32 MipLevel, Uint32 Slice, const Box &DstBox, const TextureSubResData &SubresData )override;
+ virtual void UpdateData( IDeviceContext *pContext, Uint32 MipLevel, Uint32 Slice, const Box &DstBox, const TextureSubResData &SubresData )override final;
//virtual void CopyData(CTexture *pSrcTexture, Uint32 SrcOffset, Uint32 DstOffset, Uint32 Size);
- virtual void Map( IDeviceContext *pContext, Uint32 Subresource, MAP_TYPE MapType, Uint32 MapFlags, MappedTextureSubresource &MappedData )override;
- virtual void Unmap( IDeviceContext *pContext, Uint32 Subresource, MAP_TYPE MapType, Uint32 MapFlags )override;
+ virtual void Map( IDeviceContext *pContext, Uint32 Subresource, MAP_TYPE MapType, Uint32 MapFlags, MappedTextureSubresource &MappedData )override final;
+ virtual void Unmap( IDeviceContext *pContext, Uint32 Subresource, MAP_TYPE MapType, Uint32 MapFlags )override final;
virtual ID3D12Resource* GetD3D12Texture(){ return GetD3D12Resource(); }
@@ -94,7 +94,7 @@ public:
}
protected:
- void CreateViewInternal( const struct TextureViewDesc &ViewDesc, ITextureView **ppView, bool bIsDefaultView )override;
+ void CreateViewInternal( const struct TextureViewDesc &ViewDesc, ITextureView **ppView, bool bIsDefaultView )override final;
//void PrepareD3D12InitData(const TextureData &InitData, Uint32 NumSubresources, std::vector<D3D12_SUBRESOURCE_DATA> &D3D12InitData);
void CreateSRV( TextureViewDesc &SRVDesc, D3D12_CPU_DESCRIPTOR_HANDLE SRVHandle );
diff --git a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp
index b30925b0..ab1ae905 100644
--- a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp
+++ b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp
@@ -794,8 +794,15 @@ namespace Diligent
Footpring.Footprint.Format = TexFormatToDXGI_Format(TexDesc.Format);
Footpring.Footprint.RowPitch = static_cast<UINT>(SrcStride);
- VERIFY(Footpring.Footprint.RowPitch * Footpring.Footprint.Height * Footpring.Footprint.Depth <= BufferSize, "Buffer is not large enough");
- VERIFY(SrcDepthStride == 0 || static_cast<UINT>(SrcDepthStride) == Footpring.Footprint.RowPitch * Footpring.Footprint.Height, "Depth stride must be equal to the size 2D level");
+
+#ifdef _DEBUG
+ {
+ const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format);
+ const Uint32 RowCount = std::max((Footpring.Footprint.Height/FmtAttribs.BlockHeight), 1u);
+ VERIFY(BufferSize >= Footpring.Footprint.RowPitch * RowCount * Footpring.Footprint.Depth, "Buffer is not large enough");
+ VERIFY(Footpring.Footprint.Depth == 1 || static_cast<UINT>(SrcDepthStride) == Footpring.Footprint.RowPitch * RowCount, "Depth stride must be equal to the size of 2D plane");
+ }
+#endif
D3D12_BOX D3D12SrcBox;
D3D12SrcBox.left = 0;
@@ -847,24 +854,41 @@ namespace Diligent
const auto& TexDesc = pTextureD3D12->GetDesc();
const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format);
VERIFY_EXPR(DstBox.MaxX > DstBox.MinX && DstBox.MaxY > DstBox.MinY && DstBox.MaxZ > DstBox.MinZ);
- const auto UpdateRegionWidth = DstBox.MaxX - DstBox.MinX;
- const auto UpdateRegionHeight = DstBox.MaxY - DstBox.MinY;
- const auto UpdateRegionDepth = DstBox.MaxZ - DstBox.MinZ;
- const Uint32 RowSize = FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED ?
- UpdateRegionWidth / Uint32{FmtAttribs.BlockWidth} * Uint32{FmtAttribs.ComponentSize} :
- UpdateRegionWidth * Uint32{FmtAttribs.ComponentSize} * Uint32{FmtAttribs.NumComponents};
- VERIFY(SrcStride >= RowSize, "Source data stride (", SrcStride, ") is below the image row size (", RowSize, ")");
- VERIFY(SrcDepthStride == 0 || SrcDepthStride >= SrcStride * (UpdateRegionHeight / FmtAttribs.BlockHeight), "Source data depth stride (", SrcDepthStride, ") is below the image plane size (", SrcStride * UpdateRegionHeight, ")");
+ auto UpdateRegionWidth = DstBox.MaxX - DstBox.MinX;
+ auto UpdateRegionHeight = DstBox.MaxY - DstBox.MinY;
+ auto UpdateRegionDepth = DstBox.MaxZ - DstBox.MinZ;
+ Uint32 RowSize = 0;
+ Uint32 RowCount = 0;
+ if(FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED)
+ {
+ // Box must be aligned by the calling function
+ VERIFY_EXPR((UpdateRegionWidth % FmtAttribs.BlockWidth) == 0);
+ VERIFY_EXPR((UpdateRegionHeight % FmtAttribs.BlockHeight) == 0);
+ RowSize = UpdateRegionWidth / Uint32{FmtAttribs.BlockWidth} * Uint32{FmtAttribs.ComponentSize};
+ RowCount = UpdateRegionHeight / FmtAttribs.BlockHeight;
+ }
+ else
+ {
+ RowSize = UpdateRegionWidth * Uint32{FmtAttribs.ComponentSize} * Uint32{FmtAttribs.NumComponents};
+ RowCount = UpdateRegionHeight;
+ }
+#ifdef _DEBUG
+ {
+ VERIFY(SrcStride >= RowSize, "Source data stride (", SrcStride, ") is below the image row size (", RowSize, ")");
+ const Uint32 PlaneSize = SrcStride * RowCount;
+ VERIFY(UpdateRegionDepth == 1 || SrcDepthStride >= PlaneSize, "Source data depth stride (", SrcDepthStride, ") is below the image plane size (", PlaneSize, ")");
+ }
+#endif
// RowPitch must be a multiple of 256 (aka. D3D12_TEXTURE_DATA_PITCH_ALIGNMENT)
- const auto BufferDataStride = (RowSize + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT-1) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT-1);
- const auto BufferDataDepthStride = UpdateRegionHeight * BufferDataStride;
- const auto MemorySize = UpdateRegionDepth * BufferDataDepthStride;
- const auto UploadSpace = AllocateDynamicSpace(MemorySize, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
- const auto AlignedOffset = (UploadSpace.Offset + (D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT-1)) & ~(D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT-1);
+ const auto AlignedStride = (RowSize + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT-1) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT-1);
+ const auto AlignedDepthStride = RowCount * AlignedStride;
+ const auto MemorySize = UpdateRegionDepth * AlignedDepthStride;
+ const auto UploadSpace = AllocateDynamicSpace(MemorySize, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
+ const auto AlignedOffset = (UploadSpace.Offset + (D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT-1)) & ~(D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT-1);
for(Uint32 slice = 0; slice < UpdateRegionDepth; ++slice)
{
- for(Uint32 row = 0; row < UpdateRegionHeight / FmtAttribs.BlockHeight; ++row)
+ for(Uint32 row = 0; row < RowCount; ++row)
{
const auto* pSrcPtr =
reinterpret_cast<const Uint8*>(pSrcData)
@@ -873,13 +897,13 @@ namespace Diligent
auto* pDstPtr =
reinterpret_cast<Uint8*>(UploadSpace.CPUAddress)
+ (AlignedOffset - UploadSpace.Offset)
- + row * BufferDataStride
- + slice * BufferDataDepthStride;
+ + row * AlignedStride
+ + slice * AlignedDepthStride;
memcpy(pDstPtr, pSrcPtr, RowSize);
}
}
- CopyTextureRegion(UploadSpace.pBuffer, static_cast<Uint32>(AlignedOffset), BufferDataStride, BufferDataDepthStride, MemorySize, pTextureD3D12, DstSubResIndex, DstBox);
+ CopyTextureRegion(UploadSpace.pBuffer, static_cast<Uint32>(AlignedOffset), AlignedStride, AlignedDepthStride, MemorySize, pTextureD3D12, DstSubResIndex, DstBox);
}
void DeviceContextD3D12Impl::GenerateMips(TextureViewD3D12Impl* pTexView)
diff --git a/Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp
index 77d8894f..2ea0938e 100644
--- a/Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp
+++ b/Graphics/GraphicsEngineD3D12/src/TextureD3D12Impl.cpp
@@ -409,12 +409,38 @@ void TextureD3D12Impl::UpdateData( IDeviceContext* pContext,
{
TTextureBase::UpdateData( pContext, MipLevel, Slice, DstBox, SubresData );
+ Box BlockAlignedBox;
+ const auto& FmtAttribs = GetTextureFormatAttribs(m_Desc.Format);
+ const Box* pBox = nullptr;
+ if (FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED)
+ {
+ // Align update region by the compressed block size
+
+ VERIFY( (DstBox.MinX % FmtAttribs.BlockWidth) == 0, "Update region min x (", DstBox.MinX, ") must be multiple of a compressed block width (", FmtAttribs.BlockWidth, ")");
+ BlockAlignedBox.MinX = DstBox.MinX;
+ VERIFY( (FmtAttribs.BlockWidth & (FmtAttribs.BlockWidth-1)) == 0, "Compressed block width (", FmtAttribs.BlockWidth, ") is expected to be power of 2");
+ BlockAlignedBox.MaxX = (DstBox.MaxX + FmtAttribs.BlockWidth-1) & ~(FmtAttribs.BlockWidth-1);
+
+ VERIFY( (DstBox.MinY % FmtAttribs.BlockHeight) == 0, "Update region min y (", DstBox.MinY, ") must be multiple of a compressed block height (", FmtAttribs.BlockHeight, ")");
+ BlockAlignedBox.MinY = DstBox.MinY;
+ VERIFY( (FmtAttribs.BlockHeight & (FmtAttribs.BlockHeight-1)) == 0, "Compressed block height (", FmtAttribs.BlockHeight, ") is expected to be power of 2");
+ BlockAlignedBox.MaxY = (DstBox.MaxY + FmtAttribs.BlockHeight-1) & ~(FmtAttribs.BlockHeight-1);
+
+ BlockAlignedBox.MinZ = DstBox.MinZ;
+ BlockAlignedBox.MaxZ = DstBox.MaxZ;
+
+ pBox = &BlockAlignedBox;
+ }
+ else
+ {
+ pBox = &DstBox;
+ }
auto *pCtxD3D12 = ValidatedCast<DeviceContextD3D12Impl>(pContext);
auto DstSubResIndex = D3D12CalcSubresource(MipLevel, Slice, 0, m_Desc.MipLevels, m_Desc.ArraySize);
if (SubresData.pSrcBuffer == nullptr)
- pCtxD3D12->UpdateTextureRegion(SubresData.pData, SubresData.Stride, SubresData.DepthStride, this, DstSubResIndex, DstBox);
+ pCtxD3D12->UpdateTextureRegion(SubresData.pData, SubresData.Stride, SubresData.DepthStride, this, DstSubResIndex, *pBox);
else
- pCtxD3D12->CopyTextureRegion(SubresData.pSrcBuffer, 0, SubresData.Stride, SubresData.DepthStride, this, DstSubResIndex, DstBox);
+ pCtxD3D12->CopyTextureRegion(SubresData.pSrcBuffer, 0, SubresData.Stride, SubresData.DepthStride, this, DstSubResIndex, *pBox);
}
void TextureD3D12Impl :: CopyData(IDeviceContext* pContext,
diff --git a/Graphics/GraphicsEngineOpenGL/src/Texture1DArray_OGL.cpp b/Graphics/GraphicsEngineOpenGL/src/Texture1DArray_OGL.cpp
index d636f8b4..57478e47 100644
--- a/Graphics/GraphicsEngineOpenGL/src/Texture1DArray_OGL.cpp
+++ b/Graphics/GraphicsEngineOpenGL/src/Texture1DArray_OGL.cpp
@@ -66,8 +66,8 @@ Texture1DArray_OGL::Texture1DArray_OGL( IReferenceCounters *pRefCounters,
{
for(Uint32 Mip = 0; Mip < m_Desc.MipLevels; ++Mip)
{
- Box DstBox(0, std::max(m_Desc.Width>>Mip, 1U),
- 0, 1 );
+ Box DstBox{0, std::max(m_Desc.Width>>Mip, 1U),
+ 0, 1 };
// UpdateData() is a virtual function. If we try to call it through vtbl from here,
// we will get into TextureBaseGL::UpdateData(), because instance of Texture1DArray_OGL
// is not fully constructed yet.
diff --git a/Graphics/GraphicsEngineOpenGL/src/Texture1D_OGL.cpp b/Graphics/GraphicsEngineOpenGL/src/Texture1D_OGL.cpp
index 2a4a1fd7..f5ee0def 100644
--- a/Graphics/GraphicsEngineOpenGL/src/Texture1D_OGL.cpp
+++ b/Graphics/GraphicsEngineOpenGL/src/Texture1D_OGL.cpp
@@ -64,8 +64,8 @@ Texture1D_OGL::Texture1D_OGL( IReferenceCounters *pRefCounters,
{
for(Uint32 Mip = 0; Mip < m_Desc.MipLevels; ++Mip)
{
- Box DstBox(0, std::max(m_Desc.Width>>Mip, 1U),
- 0, 1);
+ Box DstBox{0, std::max(m_Desc.Width>>Mip, 1U),
+ 0, 1};
// UpdateData() is a virtual function. If we try to call it through vtbl from here,
// we will get into TextureBaseGL::UpdateData(), because instance of Texture1D_OGL
// is not fully constructed yet.
diff --git a/Graphics/GraphicsEngineOpenGL/src/Texture2DArray_OGL.cpp b/Graphics/GraphicsEngineOpenGL/src/Texture2DArray_OGL.cpp
index 5368281a..e1cc57c1 100644
--- a/Graphics/GraphicsEngineOpenGL/src/Texture2DArray_OGL.cpp
+++ b/Graphics/GraphicsEngineOpenGL/src/Texture2DArray_OGL.cpp
@@ -84,8 +84,8 @@ Texture2DArray_OGL::Texture2DArray_OGL( IReferenceCounters *pRefCounters,
{
for(Uint32 Mip = 0; Mip < m_Desc.MipLevels; ++Mip)
{
- Box DstBox(0, std::max(m_Desc.Width >>Mip, 1U),
- 0, std::max(m_Desc.Height>>Mip, 1U) );
+ Box DstBox{0, std::max(m_Desc.Width >>Mip, 1U),
+ 0, std::max(m_Desc.Height>>Mip, 1U)};
// UpdateData() is a virtual function. If we try to call it through vtbl from here,
// we will get into TextureBaseGL::UpdateData(), because instance of Texture2DArray_OGL
// is not fully constructed yet.
@@ -147,9 +147,11 @@ void Texture2DArray_OGL::UpdateData(IDeviceContext *pContext, Uint32 MipLevel, U
if( TransferAttribs.IsCompressed )
{
- VERIFY( (DstBox.MinX % 4) == 0 && (DstBox.MinY % 4) == 0 &&
- ((DstBox.MaxX % 4) == 0 || DstBox.MaxX == std::max(m_Desc.Width >>MipLevel, 1U)) &&
- ((DstBox.MaxY % 4) == 0 || DstBox.MaxY == std::max(m_Desc.Height>>MipLevel, 1U)),
+ auto MipWidth = std::max(m_Desc.Width >> MipLevel, 1U);
+ auto MipHeight = std::max(m_Desc.Height >> MipLevel, 1U);
+ VERIFY( (DstBox.MinX % 4) == 0 && (DstBox.MinY % 4) == 0 &&
+ ((DstBox.MaxX % 4) == 0 || DstBox.MaxX == MipWidth) &&
+ ((DstBox.MaxY % 4) == 0 || DstBox.MaxY == MipHeight),
"Compressed texture update region must be 4 pixel-aligned" );
const auto &FmtAttribs = GetTextureFormatAttribs(m_Desc.Format);
auto BlockBytesInRow = ((DstBox.MaxX - DstBox.MinX + 3)/4) * Uint32{FmtAttribs.ComponentSize};
@@ -158,12 +160,16 @@ void Texture2DArray_OGL::UpdateData(IDeviceContext *pContext, Uint32 MipLevel, U
//glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
//glPixelStorei(GL_UNPACK_COMPRESSED_BLOCK_WIDTH, 0);
+ auto UpdateRegionWidth = DstBox.MaxX - DstBox.MinX;
+ auto UpdateRegionHeight = DstBox.MaxY - DstBox.MinY;
+ UpdateRegionWidth = std::min(UpdateRegionWidth, MipWidth - DstBox.MinX);
+ UpdateRegionHeight = std::min(UpdateRegionHeight, MipHeight - DstBox.MinY);
glCompressedTexSubImage3D(m_BindTarget, MipLevel,
DstBox.MinX,
DstBox.MinY,
Slice,
- DstBox.MaxX - DstBox.MinX,
- DstBox.MaxY - DstBox.MinY,
+ UpdateRegionWidth,
+ UpdateRegionHeight,
1,
// The format must be the same compressed-texture format previously
// specified by glTexStorage2D() (thank you OpenGL for another useless
diff --git a/Graphics/GraphicsEngineOpenGL/src/Texture2D_OGL.cpp b/Graphics/GraphicsEngineOpenGL/src/Texture2D_OGL.cpp
index f4171812..631b44ca 100644
--- a/Graphics/GraphicsEngineOpenGL/src/Texture2D_OGL.cpp
+++ b/Graphics/GraphicsEngineOpenGL/src/Texture2D_OGL.cpp
@@ -88,8 +88,8 @@ Texture2D_OGL::Texture2D_OGL( IReferenceCounters *pRefCounters,
{
for(Uint32 Mip = 0; Mip < m_Desc.MipLevels; ++Mip)
{
- Box DstBox(0, std::max(m_Desc.Width >>Mip, 1U),
- 0, std::max(m_Desc.Height>>Mip, 1U) );
+ Box DstBox{0, std::max(m_Desc.Width >>Mip, 1U),
+ 0, std::max(m_Desc.Height>>Mip, 1U)};
// UpdateData() is a virtual function. If we try to call it through vtbl from here,
// we will get into TextureBaseGL::UpdateData(), because instance of Texture2D_OGL
// is not fully constructed yet.
@@ -149,9 +149,11 @@ void Texture2D_OGL::UpdateData( IDeviceContext *pContext, Uint32 MipLevel, Uint3
if( TransferAttribs.IsCompressed )
{
+ auto MipWidth = std::max(m_Desc.Width >> MipLevel, 1U);
+ auto MipHeight = std::max(m_Desc.Height >> MipLevel, 1U);
VERIFY( (DstBox.MinX % 4) == 0 && (DstBox.MinY % 4) == 0 &&
- ((DstBox.MaxX % 4) == 0 || DstBox.MaxX == std::max(m_Desc.Width >>MipLevel, 1U)) &&
- ((DstBox.MaxY % 4) == 0 || DstBox.MaxY == std::max(m_Desc.Height>>MipLevel, 1U)),
+ ((DstBox.MaxX % 4) == 0 || DstBox.MaxX == MipWidth) &&
+ ((DstBox.MaxY % 4) == 0 || DstBox.MaxY == MipHeight),
"Compressed texture update region must be 4 pixel-aligned" );
const auto &FmtAttribs = GetTextureFormatAttribs(m_Desc.Format);
auto BlockBytesInRow = ((DstBox.MaxX - DstBox.MinX + 3)/4) * Uint32{FmtAttribs.ComponentSize};
@@ -160,11 +162,15 @@ void Texture2D_OGL::UpdateData( IDeviceContext *pContext, Uint32 MipLevel, Uint3
//glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
//glPixelStorei(GL_UNPACK_COMPRESSED_BLOCK_WIDTH, 0);
+ auto UpdateRegionWidth = DstBox.MaxX - DstBox.MinX;
+ auto UpdateRegionHeight = DstBox.MaxY - DstBox.MinY;
+ UpdateRegionWidth = std::min(UpdateRegionWidth, MipWidth - DstBox.MinX);
+ UpdateRegionHeight = std::min(UpdateRegionHeight, MipHeight - DstBox.MinY);
glCompressedTexSubImage2D(m_BindTarget, MipLevel,
DstBox.MinX,
DstBox.MinY,
- DstBox.MaxX - DstBox.MinX,
- DstBox.MaxY - DstBox.MinY,
+ UpdateRegionWidth,
+ UpdateRegionHeight,
// The format must be the same compressed-texture format previously
// specified by glTexStorage2D() (thank you OpenGL for another useless
// parameter that is nothing but the source of confusion), otherwise
diff --git a/Graphics/GraphicsEngineOpenGL/src/Texture3D_OGL.cpp b/Graphics/GraphicsEngineOpenGL/src/Texture3D_OGL.cpp
index 51b52c88..6fb7645a 100644
--- a/Graphics/GraphicsEngineOpenGL/src/Texture3D_OGL.cpp
+++ b/Graphics/GraphicsEngineOpenGL/src/Texture3D_OGL.cpp
@@ -66,9 +66,9 @@ Texture3D_OGL::Texture3D_OGL( IReferenceCounters *pRefCounters,
{
for(Uint32 Mip = 0; Mip < m_Desc.MipLevels; ++Mip)
{
- Box DstBox(0, std::max(m_Desc.Width >>Mip, 1U),
- 0, std::max(m_Desc.Height>>Mip, 1U),
- 0, std::max(m_Desc.Depth >>Mip, 1U));
+ Box DstBox{0, std::max(m_Desc.Width >>Mip, 1U),
+ 0, std::max(m_Desc.Height>>Mip, 1U),
+ 0, std::max(m_Desc.Depth >>Mip, 1U)};
// UpdateData() is a virtual function. If we try to call it through vtbl from here,
// we will get into TextureBaseGL::UpdateData(), because instance of Texture3D_OGL
// is not fully constructed yet.
diff --git a/Graphics/GraphicsEngineOpenGL/src/TextureCubeArray_OGL.cpp b/Graphics/GraphicsEngineOpenGL/src/TextureCubeArray_OGL.cpp
index 3851d31f..eddea87a 100644
--- a/Graphics/GraphicsEngineOpenGL/src/TextureCubeArray_OGL.cpp
+++ b/Graphics/GraphicsEngineOpenGL/src/TextureCubeArray_OGL.cpp
@@ -73,8 +73,8 @@ TextureCubeArray_OGL::TextureCubeArray_OGL( IReferenceCounters *pRefCounters,
{
for(Uint32 Mip = 0; Mip < m_Desc.MipLevels; ++Mip)
{
- Box DstBox(0, std::max(m_Desc.Width >>Mip, 1U),
- 0, std::max(m_Desc.Height>>Mip, 1U) );
+ Box DstBox{0, std::max(m_Desc.Width >>Mip, 1U),
+ 0, std::max(m_Desc.Height>>Mip, 1U)};
// UpdateData() is a virtual function. If we try to call it through vtbl from here,
// we will get into TextureBaseGL::UpdateData(), because instance of TextureCubeArray_OGL
// is not fully constructed yet.
@@ -133,9 +133,11 @@ void TextureCubeArray_OGL::UpdateData( IDeviceContext *pContext, Uint32 MipLevel
if( TransferAttribs.IsCompressed )
{
+ auto MipWidth = std::max(m_Desc.Width >> MipLevel, 1U);
+ auto MipHeight = std::max(m_Desc.Height >> MipLevel, 1U);
VERIFY( (DstBox.MinX % 4) == 0 && (DstBox.MinY % 4) == 0 &&
- ((DstBox.MaxX % 4) == 0 || DstBox.MaxX == std::max(m_Desc.Width >>MipLevel, 1U)) &&
- ((DstBox.MaxY % 4) == 0 || DstBox.MaxY == std::max(m_Desc.Height>>MipLevel, 1U)),
+ ((DstBox.MaxX % 4) == 0 || DstBox.MaxX == MipWidth) &&
+ ((DstBox.MaxY % 4) == 0 || DstBox.MaxY == MipHeight),
"Compressed texture update region must be 4 pixel-aligned" );
const auto &FmtAttribs = GetTextureFormatAttribs(m_Desc.Format);
auto BlockBytesInRow = ((DstBox.MaxX - DstBox.MinX + 3)/4) * Uint32{FmtAttribs.ComponentSize};
@@ -146,12 +148,16 @@ void TextureCubeArray_OGL::UpdateData( IDeviceContext *pContext, Uint32 MipLevel
//glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
//glPixelStorei(GL_UNPACK_COMPRESSED_BLOCK_WIDTH, 0);
+ auto UpdateRegionWidth = DstBox.MaxX - DstBox.MinX;
+ auto UpdateRegionHeight = DstBox.MaxY - DstBox.MinY;
+ UpdateRegionWidth = std::min(UpdateRegionWidth, MipWidth - DstBox.MinX);
+ UpdateRegionHeight = std::min(UpdateRegionHeight, MipHeight - DstBox.MinY);
glCompressedTexSubImage3D(m_BindTarget, MipLevel,
DstBox.MinX,
DstBox.MinY,
Slice,
- DstBox.MaxX - DstBox.MinX,
- DstBox.MaxY - DstBox.MinY,
+ UpdateRegionWidth,
+ UpdateRegionHeight,
1,
// The format must be the same compressed-texture format previously
// specified by glTexStorage2D() (thank you OpenGL for another useless
diff --git a/Graphics/GraphicsEngineOpenGL/src/TextureCube_OGL.cpp b/Graphics/GraphicsEngineOpenGL/src/TextureCube_OGL.cpp
index 508ee6b2..ce7fe1d5 100644
--- a/Graphics/GraphicsEngineOpenGL/src/TextureCube_OGL.cpp
+++ b/Graphics/GraphicsEngineOpenGL/src/TextureCube_OGL.cpp
@@ -71,8 +71,8 @@ TextureCube_OGL::TextureCube_OGL( IReferenceCounters *pRefCounters,
{
for(Uint32 Mip = 0; Mip < m_Desc.MipLevels; ++Mip)
{
- Box DstBox(0, std::max(m_Desc.Width >>Mip, 1U),
- 0, std::max(m_Desc.Height>>Mip, 1U) );
+ Box DstBox{0, std::max(m_Desc.Width >>Mip, 1U),
+ 0, std::max(m_Desc.Height>>Mip, 1U)};
// UpdateData() is a virtual function. If we try to call it through vtbl from here,
// we will get into TextureBaseGL::UpdateData(), because instance of TextureCube_OGL
// is not fully constructed yet.
@@ -147,9 +147,11 @@ void TextureCube_OGL::UpdateData( IDeviceContext *pContext, Uint32 MipLevel, Uin
if( TransferAttribs.IsCompressed )
{
+ auto MipWidth = std::max(m_Desc.Width >> MipLevel, 1U);
+ auto MipHeight = std::max(m_Desc.Height >> MipLevel, 1U);
VERIFY( (DstBox.MinX % 4) == 0 && (DstBox.MinY % 4) == 0 &&
- ((DstBox.MaxX % 4) == 0 || DstBox.MaxX == std::max(m_Desc.Width >>MipLevel, 1U)) &&
- ((DstBox.MaxY % 4) == 0 || DstBox.MaxY == std::max(m_Desc.Height>>MipLevel, 1U)),
+ ((DstBox.MaxX % 4) == 0 || DstBox.MaxX == MipWidth) &&
+ ((DstBox.MaxY % 4) == 0 || DstBox.MaxY == MipHeight),
"Compressed texture update region must be 4 pixel-aligned" );
const auto &FmtAttribs = GetTextureFormatAttribs(m_Desc.Format);
auto BlockBytesInRow = ((DstBox.MaxX - DstBox.MinX + 3)/4) * Uint32{FmtAttribs.ComponentSize};
@@ -161,11 +163,15 @@ void TextureCube_OGL::UpdateData( IDeviceContext *pContext, Uint32 MipLevel, Uin
// Texture must be bound as GL_TEXTURE_CUBE_MAP, but glCompressedTexSubImage2D()
// takes one of GL_TEXTURE_CUBE_MAP_POSITIVE_X ... GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
+ auto UpdateRegionWidth = DstBox.MaxX - DstBox.MinX;
+ auto UpdateRegionHeight = DstBox.MaxY - DstBox.MinY;
+ UpdateRegionWidth = std::min(UpdateRegionWidth, MipWidth - DstBox.MinX);
+ UpdateRegionHeight = std::min(UpdateRegionHeight, MipHeight - DstBox.MinY);
glCompressedTexSubImage2D(CubeMapFaceBindTarget, MipLevel,
DstBox.MinX,
DstBox.MinY,
- DstBox.MaxX - DstBox.MinX,
- DstBox.MaxY - DstBox.MinY,
+ UpdateRegionWidth,
+ UpdateRegionHeight,
// The format must be the same compressed-texture format previously
// specified by glTexStorage2D() (thank you OpenGL for another useless
// parameter that is nothing but the source of confusion), otherwise
diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
index 7810cdce..c9ffb87f 100644
--- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
@@ -1135,23 +1135,49 @@ namespace Diligent
VERIFY(TexDesc.SampleCount == 1, "Only single-sample textures can be updated with vkCmdCopyBufferToImage()");
const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format);
VERIFY_EXPR(DstBox.MaxX > DstBox.MinX && DstBox.MaxY > DstBox.MinY && DstBox.MaxZ > DstBox.MinZ);
- const auto UpdateRegionWidth = DstBox.MaxX - DstBox.MinX;
- const auto UpdateRegionHeight = DstBox.MaxY - DstBox.MinY;
- const auto UpdateRegionDepth = DstBox.MaxZ - DstBox.MinZ;
- const Uint32 RowSize = FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED ?
- UpdateRegionWidth / Uint32{FmtAttribs.BlockWidth} * Uint32{FmtAttribs.ComponentSize} :
- UpdateRegionWidth * Uint32{FmtAttribs.ComponentSize} * Uint32{FmtAttribs.NumComponents};
+ auto UpdateRegionWidth = DstBox.MaxX - DstBox.MinX;
+ auto UpdateRegionHeight = DstBox.MaxY - DstBox.MinY;
+ auto UpdateRegionDepth = DstBox.MaxZ - DstBox.MinZ;
+ Uint32 RowSize = 0;
+ Uint32 RowCount = 0;
+ if(FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED)
+ {
+ // Align update region size by the block size. This is only necessary when updating
+ // coarse mip levels. Otherwise UpdateRegionWidth/Height should be multiples of block size
+ const auto BlockAlignedRegionWidth = (UpdateRegionWidth + (FmtAttribs.BlockWidth-1)) & ~(FmtAttribs.BlockWidth -1);
+ const auto BlockAlignedRegionHeight = (UpdateRegionHeight + (FmtAttribs.BlockHeight-1)) & ~(FmtAttribs.BlockHeight-1);
+ RowSize = BlockAlignedRegionWidth / Uint32{FmtAttribs.BlockWidth} * Uint32{FmtAttribs.ComponentSize};
+ RowCount = BlockAlignedRegionHeight / FmtAttribs.BlockHeight;
+
+ // (imageExtent.width + imageOffset.x) must be less than or equal to the image subresource width, and
+ // (imageExtent.height + imageOffset.y) must be less than or equal to the image subresource height (18.4),
+ // so we need to clamp UpdateRegionWidth and Height
+ const Uint32 MipWidth = std::max(TexDesc.Width >> MipLevel, 1u);
+ const Uint32 MipHeight = std::max(TexDesc.Height >> MipLevel, 1u);
+ VERIFY_EXPR(MipWidth > DstBox.MinX);
+ UpdateRegionWidth = std::min(UpdateRegionWidth, MipWidth - DstBox.MinX);
+ VERIFY_EXPR(MipHeight > DstBox.MinY);
+ UpdateRegionHeight = std::min(UpdateRegionHeight, MipHeight - DstBox.MinY);
+ }
+ else
+ {
+ RowSize = UpdateRegionWidth * Uint32{FmtAttribs.ComponentSize} * Uint32{FmtAttribs.NumComponents};
+ RowCount = UpdateRegionHeight;
+ }
+#ifdef _DEBUG
VERIFY(SrcStride >= RowSize, "Source data stride (", SrcStride, ") is below the image row size (", RowSize, ")");
- VERIFY(SrcDepthStride == 0 || SrcDepthStride >= SrcStride * (UpdateRegionHeight / FmtAttribs.BlockHeight), "Source data depth stride (", SrcDepthStride, ") is below the image plane size (", SrcStride * UpdateRegionHeight, ")");
+ const Uint32 PlaneSize = SrcStride * RowCount;
+ VERIFY(UpdateRegionDepth == 1 || SrcDepthStride >= PlaneSize, "Source data depth stride (", SrcDepthStride, ") is below the image plane size (", PlaneSize, ")");
+#endif
const auto BufferDataStride = RowSize;
- const auto BufferDataDepthStride = UpdateRegionHeight * BufferDataStride;
- auto MemorySize = UpdateRegionDepth * BufferDataDepthStride;
- size_t Alignment = 4;
- auto UploadSpace = AllocateDynamicSpace(MemorySize + static_cast<Uint32>(Alignment));
+ const auto BufferDataDepthStride = (UpdateRegionHeight / FmtAttribs.BlockHeight) * BufferDataStride;
+ const auto MemorySize = UpdateRegionDepth * BufferDataDepthStride;
+ size_t Alignment = 4;
+ auto UploadSpace = AllocateDynamicSpace(MemorySize + static_cast<Uint32>(Alignment));
auto AlignedOffset = (UploadSpace.Offset + (Alignment-1)) & ~(Alignment-1);
for(Uint32 slice = 0; slice < UpdateRegionDepth; ++slice)
{
- for(Uint32 row = 0; row < UpdateRegionHeight / FmtAttribs.BlockHeight; ++row)
+ for(Uint32 row = 0; row < RowCount; ++row)
{
const auto* pSrcPtr =
reinterpret_cast<const Uint8*>(pSrcData)
@@ -1201,6 +1227,10 @@ namespace Diligent
CopyRegion.imageSubresource.baseArrayLayer = Slice;
CopyRegion.imageSubresource.layerCount = 1;
CopyRegion.imageSubresource.mipLevel = MipLevel;
+ // - imageOffset.x and (imageExtent.width + imageOffset.x) must both be greater than or equal to 0 and
+ // less than or equal to the image subresource width (18.4)
+ // - imageOffset.y and (imageExtent.height + imageOffset.y) must both be greater than or equal to 0 and
+ // less than or equal to the image subresource height (18.4)
CopyRegion.imageOffset = VkOffset3D{static_cast<int32_t>(DstBox.MinX), static_cast<int32_t>(DstBox.MinY), static_cast<int32_t>(DstBox.MinZ)};
CopyRegion.imageExtent = VkExtent3D{UpdateRegionWidth, UpdateRegionHeight, UpdateRegionDepth};