diff options
| author | Egor Yusov <egor.yusov@gmail.com> | 2018-08-29 01:42:05 +0000 |
|---|---|---|
| committer | Egor Yusov <egor.yusov@gmail.com> | 2018-08-29 01:42:05 +0000 |
| commit | 7eb25b6f0d717156a106300f72646758a044d70c (patch) | |
| tree | c3abaec4412a6752a8559f417e699a7a630bd716 /Graphics/GraphicsEngineVulkan | |
| parent | Fixed https://github.com/DiligentGraphics/DiligentCore/issues/27 (alignment i... (diff) | |
| download | DiligentCore-7eb25b6f0d717156a106300f72646758a044d70c.tar.gz DiligentCore-7eb25b6f0d717156a106300f72646758a044d70c.zip | |
Implemented UpdateTexture in Vulkan
Diffstat (limited to 'Graphics/GraphicsEngineVulkan')
4 files changed, 105 insertions, 73 deletions
diff --git a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h index 8fd6cf1a..3e02d775 100644 --- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h @@ -125,9 +125,15 @@ public: void CopyBufferRegion(class BufferVkImpl* pSrcBuffVk, class BufferVkImpl* pDstBuffVk, Uint64 SrcOffset, Uint64 DstOffset, Uint64 NumBytes); void CopyTextureRegion(class TextureVkImpl* pSrcTexture, class TextureVkImpl* pDstTexture, const VkImageCopy &CopyRegion); -#if 0 - void CopyTextureRegion(IBuffer* pSrcBuffer, Uint32 SrcStride, Uint32 SrcDepthStride, class TextureVkImpl* pTextureVk, Uint32 DstSubResIndex, const Box &DstBox); -#endif + + void UpdateTextureRegion(const void* pSrcData, + Uint32 SrcStride, + Uint32 SrcDepthStride, + class TextureVkImpl& TextureVk, + Uint32 MipLevel, + Uint32 Slice, + const Box& DstBox); + void GenerateMips(class TextureViewVkImpl& TexView) { m_GenerateMipsHelper->GenerateMips(TexView, *this, *m_GenerateMipsSRB); diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h index 9859af10..f5e6f3c1 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h @@ -357,6 +357,22 @@ namespace VulkanUtilities vkCmdCopyImage(m_VkCmdBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions); } + void CopyBufferToImage(VkBuffer srcBuffer, + VkImage dstImage, + VkImageLayout dstImageLayout, + uint32_t regionCount, + const VkBufferImageCopy* pRegions) + { + VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE); + if (m_State.RenderPass != VK_NULL_HANDLE) + { + // Copy operations must be performed outside of render pass. + EndRenderPass(); + } + + vkCmdCopyBufferToImage(m_VkCmdBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions); + } + void FlushBarriers(); void SetVkCmdBuffer(VkCommandBuffer VkCmdBuffer) diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index c6746b1d..13f93285 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -1123,68 +1123,89 @@ namespace Diligent ++m_State.NumCommands; } -#if 0 - void DeviceContextVkImpl::CopyTextureRegion(IBuffer *pSrcBuffer, Uint32 SrcStride, Uint32 SrcDepthStride, class TextureVkImpl *pTextureVk, Uint32 DstSubResIndex, const Box &DstBox) + void DeviceContextVkImpl::UpdateTextureRegion(const void* pSrcData, + Uint32 SrcStride, + Uint32 SrcDepthStride, + TextureVkImpl& TextureVk, + Uint32 MipLevel, + Uint32 Slice, + const Box& DstBox) { - auto *pBufferVk = ValidatedCast<BufferVkImpl>(pSrcBuffer); - const auto& TexDesc = pTextureVk->GetDesc(); - VERIFY(pBufferVk->GetState() == Vk_RESOURCE_STATE_GENERIC_READ, "Staging buffer is expected to always be in Vk_RESOURCE_STATE_GENERIC_READ state"); - - auto *pCmdCtx = RequestCmdContext(); - auto *pCmdList = pCmdCtx->GetCommandList(); - auto TextureState = pTextureVk->GetState(); - Vk_RESOURCE_BARRIER BarrierDesc; - BarrierDesc.Type = Vk_RESOURCE_BARRIER_TYPE_TRANSITION; - BarrierDesc.Transition.pResource = pTextureVk->GetVkResource(); - BarrierDesc.Transition.Subresource = DstSubResIndex; - BarrierDesc.Transition.StateBefore = TextureState; - BarrierDesc.Transition.StateAfter = Vk_RESOURCE_STATE_COPY_DEST; - BarrierDesc.Flags = Vk_RESOURCE_BARRIER_FLAG_NONE; - bool StateTransitionRequired = (TextureState & Vk_RESOURCE_STATE_COPY_DEST) != Vk_RESOURCE_STATE_COPY_DEST; - if (StateTransitionRequired) - pCmdList->ResourceBarrier(1, &BarrierDesc); - - Vk_TEXTURE_COPY_LOCATION DstLocation; - DstLocation.Type = Vk_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - DstLocation.pResource = pTextureVk->GetVkResource(); - DstLocation.SubresourceIndex = static_cast<UINT>(DstSubResIndex); - - Vk_TEXTURE_COPY_LOCATION SrcLocation; - SrcLocation.Type = Vk_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - SrcLocation.pResource = pBufferVk->GetVkResource(); - Vk_PLACED_SUBRESOURCE_FOOTPRINT &Footpring = SrcLocation.PlacedFootprint; - Footpring.Offset = 0; - Footpring.Footprint.Width = static_cast<UINT>(DstBox.MaxX - DstBox.MinX); - Footpring.Footprint.Height = static_cast<UINT>(DstBox.MaxY - DstBox.MinY); - Footpring.Footprint.Depth = static_cast<UINT>(DstBox.MaxZ - DstBox.MinZ); // Depth cannot be 0 - Footpring.Footprint.Format = TexFormatToDXGI_Format(TexDesc.Format); - - Footpring.Footprint.RowPitch = static_cast<UINT>(SrcStride); - VERIFY(Footpring.Footprint.RowPitch * Footpring.Footprint.Height * Footpring.Footprint.Depth <= pBufferVk->GetDesc().uiSizeInBytes, "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"); - - Vk_BOX VkSrcBox; - VkSrcBox.left = 0; - VkSrcBox.right = Footpring.Footprint.Width; - VkSrcBox.top = 0; - VkSrcBox.bottom = Footpring.Footprint.Height; - VkSrcBox.front = 0; - VkSrcBox.back = Footpring.Footprint.Depth; - pCmdCtx->GetCommandList()->CopyTextureRegion( &DstLocation, - static_cast<UINT>( DstBox.MinX ), - static_cast<UINT>( DstBox.MinY ), - static_cast<UINT>( DstBox.MinZ ), - &SrcLocation, &VkSrcBox); + const auto& TexDesc = TextureVk.GetDesc(); + 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); + auto UpdateRegionWidth = DstBox.MaxX - DstBox.MinX; + auto UpdateRegionHeight = DstBox.MaxY - DstBox.MinY; + auto UpdateRegionDepth = DstBox.MaxZ - DstBox.MinZ; + auto BufferDataStride = UpdateRegionWidth * Uint32{FmtAttribs.ComponentSize} * Uint32{FmtAttribs.NumComponents}; + auto BufferDataDepthStride = UpdateRegionHeight * BufferDataStride; + 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; ++row) + { + const auto* pSrcPtr = + reinterpret_cast<const Uint8*>(pSrcData) + + row * SrcStride + + slice * SrcDepthStride; + auto* pDstPtr = + UploadSpace.pDynamicMemMgr->GetCPUAddress() + + AlignedOffset + + row * BufferDataStride + + slice * BufferDataDepthStride; + + memcpy(pDstPtr, pSrcPtr, BufferDataStride); + } + } - ++m_State.NumCommands; - if (StateTransitionRequired) + EnsureVkCmdBuffer(); + if (TextureVk.GetLayout() != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { - std::swap(BarrierDesc.Transition.StateBefore, BarrierDesc.Transition.StateAfter); - pCmdList->ResourceBarrier(1, &BarrierDesc); + TransitionImageLayout(TextureVk, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); } + + VkBufferImageCopy CopyRegion = {}; + CopyRegion.bufferOffset = AlignedOffset; // must be a multiple of 4 (18.4) + + // bufferRowLength and bufferImageHeight specify the data in buffer memory as a subregion of a larger two- or + // three-dimensional image, and control the addressing calculations of data in buffer memory. If either of these + // values is zero, that aspect of the buffer memory is considered to be tightly packed according to the imageExtent (18.4). + CopyRegion.bufferRowLength = 0; + CopyRegion.bufferImageHeight = 0; + + // The aspectMask member of imageSubresource must only have a single bit set (18.4) + if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH) + CopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + else if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL) + { + UNSUPPORTED("Updating depth-stencil texture is not currently supported"); + // When copying to or from a depth or stencil aspect, the data in buffer memory uses a layout + // that is a (mostly) tightly packed representation of the depth or stencil data. + // To copy both the depth and stencil aspects of a depth/stencil format, two entries in + // pRegions can be used, where one specifies the depth aspect in imageSubresource, and the + // other specifies the stencil aspect (18.4) + } + else + CopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + + CopyRegion.imageSubresource.baseArrayLayer = Slice; + CopyRegion.imageSubresource.layerCount = 1; + CopyRegion.imageSubresource.mipLevel = MipLevel; + 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}; + + m_CommandBuffer.CopyBufferToImage( + UploadSpace.pDynamicMemMgr->GetVkBuffer(), + TextureVk.GetVkImage(), + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL (18.4) + 1, + &CopyRegion); } -#endif void DeviceContextVkImpl::FinishCommandList(class ICommandList **ppCommandList) { diff --git a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp index 5eca60f7..72910ab8 100644 --- a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp @@ -469,24 +469,13 @@ TextureVkImpl :: ~TextureVkImpl() m_pDevice->SafeReleaseVkObject(std::move(m_MemoryAllocation)); } -void TextureVkImpl::UpdateData( IDeviceContext *pContext, Uint32 MipLevel, Uint32 Slice, const Box &DstBox, const TextureSubResData &SubresData ) +void TextureVkImpl::UpdateData( IDeviceContext *pContext, Uint32 MipLevel, Uint32 Slice, const Box& DstBox, const TextureSubResData& SubresData ) { TTextureBase::UpdateData( pContext, MipLevel, Slice, DstBox, SubresData ); - if (SubresData.pSrcBuffer == nullptr) - { - LOG_ERROR("Vk does not allow updating texture subresource from CPU memory"); - return; - } - VERIFY( m_Desc.Usage == USAGE_DEFAULT, "Only default usage resources can be updated with UpdateData()" ); - -#if 0 auto *pCtxVk = ValidatedCast<DeviceContextVkImpl>(pContext); - - auto DstSubResIndex = VkCalcSubresource(MipLevel, Slice, 0, m_Desc.MipLevels, m_Desc.ArraySize); - - pCtxVk->CopyTextureRegion(SubresData.pSrcBuffer, SubresData.Stride, SubresData.DepthStride, this, DstSubResIndex, DstBox); -#endif + //pCtxVk->CopyTextureRegion(SubresData.pSrcBuffer, SubresData.Stride, SubresData.DepthStride, this, DstSubResIndex, DstBox); + pCtxVk->UpdateTextureRegion(SubresData.pData, SubresData.Stride, SubresData.DepthStride, *this, MipLevel, Slice, DstBox); } void TextureVkImpl :: CopyData(IDeviceContext* pContext, |
