From d8fa7f9dc4304973265461c076883053d87e52dd Mon Sep 17 00:00:00 2001 From: assiduous Date: Wed, 30 Sep 2020 18:24:40 -0700 Subject: Unified staging buffer offset processing in Vulkan and GL --- .../interface/GraphicsAccessories.hpp | 62 ++++++++++++++++++++-- .../src/GraphicsAccessories.cpp | 39 ++++++++++++-- .../GraphicsEngineOpenGL/include/TextureBaseGL.hpp | 2 +- .../src/DeviceContextGLImpl.cpp | 36 +++++-------- .../GraphicsEngineOpenGL/src/TextureBaseGL.cpp | 34 +----------- .../GraphicsEngineVulkan/include/TextureVkImpl.hpp | 7 +-- .../src/DeviceContextVkImpl.cpp | 47 ++++++++-------- .../GraphicsEngineVulkan/src/TextureVkImpl.cpp | 2 +- 8 files changed, 133 insertions(+), 96 deletions(-) (limited to 'Graphics') diff --git a/Graphics/GraphicsAccessories/interface/GraphicsAccessories.hpp b/Graphics/GraphicsAccessories/interface/GraphicsAccessories.hpp index 47ded2c1..08544b0e 100644 --- a/Graphics/GraphicsAccessories/interface/GraphicsAccessories.hpp +++ b/Graphics/GraphicsAccessories/interface/GraphicsAccessories.hpp @@ -458,7 +458,7 @@ static_assert(SHADER_TYPE_AMPLIFICATION == (1 << ASInd), "ASInd is not consisten static_assert(SHADER_TYPE_MESH == (1 << MSInd), "MSInd is not consistent with SHADER_TYPE_MESH"); static_assert(SHADER_TYPE_LAST == (1 << LastShaderInd), "LastShaderInd is not consistent with SHADER_TYPE_LAST"); -// clang-format off +// clang-format on inline SHADER_TYPE GetShaderTypeFromIndex(Int32 Index) { @@ -471,9 +471,61 @@ bool IsConsistentShaderType(SHADER_TYPE ShaderType, PIPELINE_TYPE Pipelin Int32 GetShaderTypePipelineIndex(SHADER_TYPE ShaderType, PIPELINE_TYPE PipelineType); SHADER_TYPE GetShaderTypeFromPipelineIndex(Int32 Index, PIPELINE_TYPE PipelineType); -Uint32 GetStagingTextureSubresOffset(const TextureDesc& TexDesc, - Uint32 ArraySlice, - Uint32 MipLevel, - Uint32 Alignment); +/// Returns an offset from the beginning of the buffer backing a staging texture +/// to the specified location within the given subresource. +/// +/// \param [in] TexDesc - Staging texture description. +/// \param [in] ArraySlice - Array slice. +/// \param [in] MipLevel - Mip level. +/// \param [in] Alignment - Subresource alignment. The alignment is applied +/// to whole subresources only, but not to the row/depth strides. +/// In other words, there may be padding between subresources, but +/// texels in every subresource are assumed to be tightly packed. +/// \param [in] LocationX - X location within the subresoure. +/// \param [in] LocationY - Y location within the subresoure. +/// \param [in] LocationZ - Z location within the subresoure. +/// +/// \return Offset from the beginning of the buffer to the given location. +/// +/// \remarks Alignment is applied to the subresource sizes, such that the beginning of data +/// of every subresource starts at an offset aligned by 'Alignment'. The alignment +/// is not applied to the row/depth strides and texels in all subresources are assumed +/// to be tightly packed. +/// +/// Subres 0 +/// stride +/// |<-------------->| +/// |________________| Subres 1 +/// | | stride +/// | | |<------->| +// | | |_________| +/// | Subres 0 | | | +/// | | | Subres 1| +/// | | | | _ +/// |________________| |_________| ... |_| +/// A A A +/// | | | +/// Buffer start Subres 1 offset, Subres N offset, +/// aligned by 'Alignment' aligned by 'Alignment' +/// +Uint32 GetStagingTextureLocationOffset(const TextureDesc& TexDesc, + Uint32 ArraySlice, + Uint32 MipLevel, + Uint32 Alignment, + Uint32 LocationX, + Uint32 LocationY, + Uint32 LocationZ); + +/// Returns an offset from the beginning of the buffer backing a staging texture +/// to the given subresource. +/// Texels within subresources are assumed to be tightly packed. There is no padding +/// except between whole subresources. +inline Uint32 GetStagingTextureSubresourceOffset(const TextureDesc& TexDesc, + Uint32 ArraySlice, + Uint32 MipLevel, + Uint32 Alignment) +{ + return GetStagingTextureLocationOffset(TexDesc, ArraySlice, MipLevel, Alignment, 0, 0, 0); +} } // namespace Diligent diff --git a/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp b/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp index 193a4989..780562df 100644 --- a/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp +++ b/Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp @@ -1396,10 +1396,13 @@ SHADER_TYPE GetShaderTypeFromPipelineIndex(Int32 Index, PIPELINE_TYPE PipelineTy } -Uint32 GetStagingTextureSubresOffset(const TextureDesc& TexDesc, - Uint32 ArraySlice, - Uint32 MipLevel, - Uint32 Alignment) +Uint32 GetStagingTextureLocationOffset(const TextureDesc& TexDesc, + Uint32 ArraySlice, + Uint32 MipLevel, + Uint32 Alignment, + Uint32 LocationX, + Uint32 LocationY, + Uint32 LocationZ) { VERIFY_EXPR(ArraySlice < TexDesc.ArraySize && MipLevel < TexDesc.MipLevels || ArraySlice == TexDesc.ArraySize && MipLevel == 0); @@ -1427,6 +1430,34 @@ Uint32 GetStagingTextureSubresOffset(const TextureDesc& TexDesc, Offset += Align(MipInfo.MipSize, Alignment); } + if (ArraySlice == TexDesc.ArraySize) + { + VERIFY(LocationX == 0 && LocationY == 0 && LocationZ == 0, + "Staging buffer size is requested: location must be (0,0,0)."); + } + else if (LocationX != 0 || LocationY != 0 || LocationZ != 0) + { + const auto& MipLevelAttribs = GetMipLevelProperties(TexDesc, MipLevel); + const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format); + VERIFY(LocationX < MipLevelAttribs.LogicalWidth && LocationY < MipLevelAttribs.LogicalHeight && LocationZ < MipLevelAttribs.Depth, + "Specified location is out of bounds"); + if (FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED) + { + VERIFY((LocationX % FmtAttribs.BlockWidth) == 0 && (LocationY % FmtAttribs.BlockHeight) == 0, + "For compressed texture formats, location must be a multiple of compressed block size."); + } + + // For compressed-block formats, RowSize is the size of one compressed row. + // For non-compressed formats, BlockHeight is 1. + Offset += (LocationZ * MipLevelAttribs.StorageHeight + LocationY) / FmtAttribs.BlockHeight * MipLevelAttribs.RowSize; + + // For non-compressed formats, BlockWidth is 1. + Offset += (LocationX / FmtAttribs.BlockWidth) * FmtAttribs.GetElementSize(); + + // Note: this addressing complies with how Vulkan addresses textures when copying data to/from buffer: + // address of (x,y,z) = bufferOffset + (((z * imageHeight) + y) * rowLength + x) * texelBlockSize; (18.4.1) + } + return Offset; } diff --git a/Graphics/GraphicsEngineOpenGL/include/TextureBaseGL.hpp b/Graphics/GraphicsEngineOpenGL/include/TextureBaseGL.hpp index 81dc8fc0..b5b0517d 100644 --- a/Graphics/GraphicsEngineOpenGL/include/TextureBaseGL.hpp +++ b/Graphics/GraphicsEngineOpenGL/include/TextureBaseGL.hpp @@ -114,7 +114,7 @@ public: const Box& DstBox, const TextureSubResData& SubresData) = 0; - static Uint32 GetPBODataOffset(const TextureDesc& TexDesc, Uint32 ArraySlice, Uint32 MipLevel); + static constexpr Uint32 PBOOffsetAlignment = 4; IBuffer* GetPBO() { diff --git a/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp index d1ef575e..f4ef1136 100644 --- a/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp @@ -1500,20 +1500,15 @@ void DeviceContextGLImpl::CopyTexture(const CopyTextureAttribs& CopyAttribs) if (SrcTexDesc.Usage == USAGE_STAGING && DstTexDesc.Usage != USAGE_STAGING) { TextureSubResData SubresData; - SubresData.pData = nullptr; - SubresData.pSrcBuffer = pSrcTexGL->GetPBO(); - SubresData.SrcOffset = TextureBaseGL::GetPBODataOffset(SrcTexDesc, CopyAttribs.SrcSlice, CopyAttribs.SrcMipLevel); + SubresData.pData = nullptr; + SubresData.pSrcBuffer = pSrcTexGL->GetPBO(); + SubresData.SrcOffset = + GetStagingTextureLocationOffset(SrcTexDesc, CopyAttribs.SrcSlice, CopyAttribs.SrcMipLevel, + TextureBaseGL::PBOOffsetAlignment, + pSrcBox->MinX, pSrcBox->MinY, pSrcBox->MinZ); SubresData.Stride = SrcMipLevelAttribs.RowSize; SubresData.DepthStride = SrcMipLevelAttribs.DepthSliceSize; - const auto& SrcFmtAttribs = GetTextureFormatAttribs(SrcTexDesc.Format); - SubresData.SrcOffset += - // For compressed-block formats, RowSize is the size of one compressed row. - // For non-compressed formats, BlockHeight is 1. - (pSrcBox->MinZ * SrcMipLevelAttribs.StorageHeight + pSrcBox->MinY) / SrcFmtAttribs.BlockHeight * SrcMipLevelAttribs.RowSize + - // For non-compressed formats, BlockWidth is 1. - (pSrcBox->MinX / SrcFmtAttribs.BlockWidth) * SrcFmtAttribs.GetElementSize(); - Box DstBox; DstBox.MinX = CopyAttribs.DstX; DstBox.MinY = CopyAttribs.DstY; @@ -1561,17 +1556,12 @@ void DeviceContextGLImpl::CopyTexture(const CopyTextureAttribs& CopyAttribs) auto* pDstBuffer = ValidatedCast(pDstTexGL->GetPBO()); VERIFY(pDstBuffer != nullptr, "Internal staging buffer must not be null"); - auto DstOffset = TextureBaseGL::GetPBODataOffset(DstTexDesc, CopyAttribs.DstSlice, CopyAttribs.DstMipLevel); - - auto DstMipLevelAttribs = GetMipLevelProperties(DstTexDesc, CopyAttribs.DstMipLevel); - - const auto& DstFmtAttribs = GetTextureFormatAttribs(DstTexDesc.Format); - DstOffset += - // For compressed-block formats, RowSize is the size of one compressed row. - // For non-compressed formats, BlockHeight is 1. - (CopyAttribs.DstZ * DstMipLevelAttribs.StorageHeight + CopyAttribs.DstY) / DstFmtAttribs.BlockHeight * DstMipLevelAttribs.RowSize + - // For non-compressed formats, BlockWidth is 1. - (CopyAttribs.DstX / DstFmtAttribs.BlockWidth) * DstFmtAttribs.GetElementSize(); + // GetStagingTextureLocationOffset assumes pixels are tightly packed in every subresource - no padding + // except between subresources. + const auto DstOffset = + GetStagingTextureLocationOffset(DstTexDesc, CopyAttribs.DstSlice, CopyAttribs.DstMipLevel, + TextureBaseGL::PBOOffsetAlignment, + CopyAttribs.DstX, CopyAttribs.DstY, CopyAttribs.DstZ); m_ContextState.BindBuffer(GL_PIXEL_PACK_BUFFER, pDstBuffer->GetGLHandle(), true); @@ -1606,7 +1596,7 @@ void DeviceContextGLImpl::MapTextureSubresource(ITexture* pTextu const auto& TexDesc = pTexGL->GetDesc(); if (TexDesc.Usage == USAGE_STAGING) { - auto PBOOffset = TextureBaseGL::GetPBODataOffset(TexDesc, ArraySlice, MipLevel); + auto PBOOffset = GetStagingTextureSubresourceOffset(TexDesc, ArraySlice, MipLevel, TextureBaseGL::PBOOffsetAlignment); auto MipLevelAttribs = GetMipLevelProperties(TexDesc, MipLevel); auto pPBO = ValidatedCast(pTexGL->GetPBO()); pPBO->MapRange(m_ContextState, MapType, MapFlags, PBOOffset, MipLevelAttribs.MipSize, MappedData.pData); diff --git a/Graphics/GraphicsEngineOpenGL/src/TextureBaseGL.cpp b/Graphics/GraphicsEngineOpenGL/src/TextureBaseGL.cpp index af63e560..564d16cb 100644 --- a/Graphics/GraphicsEngineOpenGL/src/TextureBaseGL.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/TextureBaseGL.cpp @@ -40,38 +40,6 @@ namespace Diligent { - -Uint32 TextureBaseGL::GetPBODataOffset(const TextureDesc& TexDesc, Uint32 ArraySlice, Uint32 MipLevel) -{ - VERIFY_EXPR(ArraySlice < TexDesc.ArraySize && MipLevel < TexDesc.MipLevels || ArraySlice == TexDesc.ArraySize && MipLevel == 0); - - Uint32 Offset = 0; - if (ArraySlice > 0) - { - Uint32 ArraySliceSize = 0; - for (Uint32 mip = 0; mip < TexDesc.MipLevels; ++mip) - { - auto MipInfo = GetMipLevelProperties(TexDesc, mip); - ArraySliceSize += Align(MipInfo.MipSize, Uint32{4}); - } - - Offset = ArraySliceSize; - if (TexDesc.Type == RESOURCE_DIM_TEX_1D_ARRAY || - TexDesc.Type == RESOURCE_DIM_TEX_2D_ARRAY || - TexDesc.Type == RESOURCE_DIM_TEX_CUBE || - TexDesc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY) - Offset *= ArraySlice; - } - - for (Uint32 mip = 0; mip < MipLevel; ++mip) - { - auto MipInfo = GetMipLevelProperties(TexDesc, mip); - Offset += Align(MipInfo.MipSize, Uint32{4}); - } - - return Offset; -} - TextureBaseGL::TextureBaseGL(IReferenceCounters* pRefCounters, FixedBlockMemoryAllocator& TexViewObjAllocator, RenderDeviceGLImpl* pDeviceGL, @@ -106,7 +74,7 @@ TextureBaseGL::TextureBaseGL(IReferenceCounters* pRefCounters, StagingBuffName += '\''; StagingBufferDesc.Name = StagingBuffName.c_str(); - StagingBufferDesc.uiSizeInBytes = GetPBODataOffset(m_Desc, m_Desc.ArraySize, 0); + StagingBufferDesc.uiSizeInBytes = GetStagingTextureSubresourceOffset(m_Desc, m_Desc.ArraySize, 0, PBOOffsetAlignment); StagingBufferDesc.Usage = USAGE_STAGING; StagingBufferDesc.CPUAccessFlags = TexDesc.CPUAccessFlags; diff --git a/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.hpp b/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.hpp index b04babec..7ca629ad 100644 --- a/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.hpp +++ b/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.hpp @@ -99,11 +99,8 @@ public: void InvalidateStagingRange(VkDeviceSize Offset, VkDeviceSize Size); - // bufferOffset must be a multiple of 4 (18.4) - // If the calling command's VkImage parameter is a compressed image, bufferOffset - // must be a multiple of the compressed texel block size in bytes (18.4). This - // is automatically guaranteed as MipWidth and MipHeight are rounded to block size. - static constexpr Uint32 StagingDataAlignment = 4; + // Buffer offset must be a multiple of 4 (18.4) + static constexpr Uint32 StagingBufferOffsetAlignment = 4; protected: void CreateViewInternal(const struct TextureViewDesc& ViewDesc, ITextureView** ppView, bool bIsDefaultView) override; diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index f14e7f9c..2d7b9591 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -1590,8 +1590,7 @@ void DeviceContextVkImpl::CopyTexture(const CopyTextureAttribs& CopyAttribs) FullMipBox.MaxZ = MipLevelAttribs.Depth; pSrcBox = &FullMipBox; } - const auto& DstFmtAttribs = GetTextureFormatAttribs(DstTexDesc.Format); - const auto& SrcFmtAttribs = GetTextureFormatAttribs(SrcTexDesc.Format); + if (SrcTexDesc.Usage != USAGE_STAGING && DstTexDesc.Usage != USAGE_STAGING) { VkImageCopy CopyRegion = {}; @@ -1603,6 +1602,8 @@ void DeviceContextVkImpl::CopyTexture(const CopyTextureAttribs& CopyAttribs) CopyRegion.extent.height = std::max(pSrcBox->MaxY - pSrcBox->MinY, 1u); CopyRegion.extent.depth = std::max(pSrcBox->MaxZ - pSrcBox->MinZ, 1u); + const auto& DstFmtAttribs = GetTextureFormatAttribs(DstTexDesc.Format); + VkImageAspectFlags aspectMask = 0; if (DstFmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH) aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; @@ -1634,15 +1635,18 @@ void DeviceContextVkImpl::CopyTexture(const CopyTextureAttribs& CopyAttribs) DEV_CHECK_ERR((SrcTexDesc.CPUAccessFlags & CPU_ACCESS_WRITE), "Attempting to copy from staging texture that was not created with CPU_ACCESS_WRITE flag"); DEV_CHECK_ERR(pSrcTexVk->GetState() == RESOURCE_STATE_COPY_SOURCE, "Source staging texture must permanently be in RESOURCE_STATE_COPY_SOURCE state"); - auto SrcBufferOffset = GetStagingTextureSubresOffset(SrcTexDesc, CopyAttribs.SrcSlice, CopyAttribs.SrcMipLevel, TextureVkImpl::StagingDataAlignment); - auto SrcMipLevelAttribs = GetMipLevelProperties(SrcTexDesc, CopyAttribs.SrcMipLevel); // address of (x,y,z) = region->bufferOffset + (((z * imageHeight) + y) * rowLength + x) * texelBlockSize; (18.4.1) - SrcBufferOffset += - // For compressed-block formats, RowSize is the size of one compressed row. - // For non-compressed formats, BlockHeight is 1. - (pSrcBox->MinZ * SrcMipLevelAttribs.StorageHeight + pSrcBox->MinY) / SrcFmtAttribs.BlockHeight * SrcMipLevelAttribs.RowSize + - // For non-compressed formats, BlockWidth is 1. - (pSrcBox->MinX / SrcFmtAttribs.BlockWidth) * SrcFmtAttribs.GetElementSize(); + + // bufferOffset must be a multiple of 4 (18.4) + // If the calling command's VkImage parameter is a compressed image, bufferOffset + // must be a multiple of the compressed texel block size in bytes (18.4). This + // is automatically guaranteed as MipWidth and MipHeight are rounded to block size. + + const auto SrcBufferOffset = + GetStagingTextureLocationOffset(SrcTexDesc, CopyAttribs.SrcSlice, CopyAttribs.SrcMipLevel, + TextureVkImpl::StagingBufferOffsetAlignment, + pSrcBox->MinX, pSrcBox->MinY, pSrcBox->MinZ); + const auto SrcMipLevelAttribs = GetMipLevelProperties(SrcTexDesc, CopyAttribs.SrcMipLevel); Box DstBox; DstBox.MinX = CopyAttribs.DstX; @@ -1655,7 +1659,7 @@ void DeviceContextVkImpl::CopyTexture(const CopyTextureAttribs& CopyAttribs) CopyBufferToTexture( pSrcTexVk->GetVkStagingBuffer(), SrcBufferOffset, - SrcMipLevelAttribs.StorageWidth, + SrcMipLevelAttribs.StorageWidth, // GetStagingTextureLocationOffset assumes texels are tightly packed *pDstTexVk, DstBox, CopyAttribs.DstMipLevel, @@ -1667,17 +1671,12 @@ void DeviceContextVkImpl::CopyTexture(const CopyTextureAttribs& CopyAttribs) DEV_CHECK_ERR((DstTexDesc.CPUAccessFlags & CPU_ACCESS_READ), "Attempting to copy to staging texture that was not created with CPU_ACCESS_READ flag"); DEV_CHECK_ERR(pDstTexVk->GetState() == RESOURCE_STATE_COPY_DEST, "Destination staging texture must permanently be in RESOURCE_STATE_COPY_DEST state"); - auto DstBufferOffset = - GetStagingTextureSubresOffset(DstTexDesc, CopyAttribs.DstSlice, CopyAttribs.DstMipLevel, - TextureVkImpl::StagingDataAlignment); - const auto DstMipLevelAttribs = GetMipLevelProperties(DstTexDesc, CopyAttribs.DstMipLevel); // address of (x,y,z) = region->bufferOffset + (((z * imageHeight) + y) * rowLength + x) * texelBlockSize; (18.4.1) - DstBufferOffset += - // For compressed-block formats, RowSize is the size of one compressed row. - // For non-compressed formats, BlockHeight is 1. - (CopyAttribs.DstZ * DstMipLevelAttribs.StorageHeight + CopyAttribs.DstY) / DstFmtAttribs.BlockHeight * DstMipLevelAttribs.RowSize * - // For non-compressed formats, BlockWidth is 1. - (CopyAttribs.DstX / DstFmtAttribs.BlockWidth) * DstFmtAttribs.GetElementSize(); + const auto DstBufferOffset = + GetStagingTextureLocationOffset(DstTexDesc, CopyAttribs.DstSlice, CopyAttribs.DstMipLevel, + TextureVkImpl::StagingBufferOffsetAlignment, + CopyAttribs.DstX, CopyAttribs.DstY, CopyAttribs.DstZ); + const auto DstMipLevelAttribs = GetMipLevelProperties(DstTexDesc, CopyAttribs.DstMipLevel); CopyTextureToBuffer( *pSrcTexVk, @@ -1687,7 +1686,8 @@ void DeviceContextVkImpl::CopyTexture(const CopyTextureAttribs& CopyAttribs) CopyAttribs.SrcTextureTransitionMode, pDstTexVk->GetVkStagingBuffer(), DstBufferOffset, - DstMipLevelAttribs.StorageWidth); + DstMipLevelAttribs.StorageWidth // GetStagingTextureLocationOffset assumes texels are tightly packed + ); } else { @@ -2010,8 +2010,7 @@ void DeviceContextVkImpl::MapTextureSubresource(ITexture* pTextu else if (TexDesc.Usage == USAGE_STAGING) { auto SubresourceOffset = - GetStagingTextureSubresOffset(TexDesc, ArraySlice, MipLevel, - TextureVkImpl::StagingDataAlignment); + GetStagingTextureSubresourceOffset(TexDesc, ArraySlice, MipLevel, TextureVkImpl::StagingBufferOffsetAlignment); const auto MipLevelAttribs = GetMipLevelProperties(TexDesc, MipLevel); // address of (x,y,z) = region->bufferOffset + (((z * imageHeight) + y) * rowLength + x) * texelBlockSize; (18.4.1) auto MapStartOffset = SubresourceOffset + diff --git a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp index 8a37df0c..313de089 100644 --- a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp @@ -408,7 +408,7 @@ TextureVkImpl::TextureVkImpl(IReferenceCounters* pRefCounters, VkStagingBuffCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; VkStagingBuffCI.pNext = nullptr; VkStagingBuffCI.flags = 0; - VkStagingBuffCI.size = GetStagingTextureSubresOffset(m_Desc, m_Desc.ArraySize, 0, StagingDataAlignment); + VkStagingBuffCI.size = GetStagingTextureSubresourceOffset(m_Desc, m_Desc.ArraySize, 0, StagingBufferOffsetAlignment); // clang-format off DEV_CHECK_ERR((m_Desc.CPUAccessFlags & (CPU_ACCESS_READ | CPU_ACCESS_WRITE)) == CPU_ACCESS_READ || -- cgit v1.2.3