summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngineVulkan
diff options
context:
space:
mode:
authorEgor Yusov <egor.yusov@gmail.com>2018-09-02 19:03:43 +0000
committerEgor Yusov <egor.yusov@gmail.com>2018-09-02 19:03:43 +0000
commite9963a8d675a251b8d28d3da2a5678f217709782 (patch)
tree3a77ffbbbc799ff99342cbe014fe0ba5f2ca4787 /Graphics/GraphicsEngineVulkan
parentFixed build error (diff)
downloadDiligentCore-e9963a8d675a251b8d28d3da2a5678f217709782.tar.gz
DiligentCore-e9963a8d675a251b8d28d3da2a5678f217709782.zip
Implemented texture mapping in Vulkan (fixed https://github.com/DiligentGraphics/DiligentCore/issues/28)
Diffstat (limited to 'Graphics/GraphicsEngineVulkan')
-rw-r--r--Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h56
-rw-r--r--Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp166
-rw-r--r--Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp28
3 files changed, 201 insertions, 49 deletions
diff --git a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h
index 3e02d775..b6ce62e6 100644
--- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h
+++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h
@@ -40,6 +40,7 @@
#include "BufferVKImpl.h"
#include "TextureViewVKImpl.h"
#include "PipelineStateVKImpl.h"
+#include "HashUtils.h"
namespace Diligent
{
@@ -134,6 +135,18 @@ public:
Uint32 Slice,
const Box& DstBox);
+ void MapTexture(TextureVkImpl& TextureVk,
+ Uint32 MipLevel,
+ Uint32 ArraySlice,
+ MAP_TYPE MapType,
+ Uint32 MapFlags,
+ const Box& MapRegion,
+ MappedTextureSubresource& MappedData);
+
+ void UnmapTexture(TextureVkImpl& TextureVk,
+ Uint32 MipLevel,
+ Uint32 ArraySlice);
+
void GenerateMips(class TextureViewVkImpl& TexView)
{
m_GenerateMipsHelper->GenerateMips(TexView, *this, *m_GenerateMipsSRB);
@@ -180,6 +193,25 @@ private:
inline void DisposeCurrentCmdBuffer(Uint64 FenceValue);
void ReleaseStaleContextResources(Uint64 SubmittedCmdBufferNumber, Uint64 SubmittedFenceValue, Uint64 CompletedFenceValue);
+ struct TextureUploadSpace
+ {
+ VulkanDynamicAllocation Allocation;
+ Uint32 AlignedOffset = 0;
+ Uint32 Stride = 0;
+ Uint32 DepthStride = 0;
+ Uint32 RowSize = 0;
+ Uint32 RowCount = 0;
+ Box Region;
+ };
+ TextureUploadSpace AllocateTextureUploadSpace(const TextureDesc& TexDesc,
+ Uint32 MipLevel,
+ const Box& Region);
+ void WriteTextureUploadRegion(TextureVkImpl& TextureVk,
+ TextureUploadSpace& UploadSpace,
+ Uint32 MipLevel,
+ Uint32 ArraySlice);
+
+
void DvpLogRenderPass_PSOMismatch();
VulkanUtilities::VulkanCommandBuffer m_CommandBuffer;
@@ -221,6 +253,30 @@ private:
std::unordered_map<BufferVkImpl*, VulkanUploadAllocation> m_UploadAllocations;
+ struct MappedTextureKey
+ {
+ TextureVkImpl* const Texture;
+ Uint32 const MipLevel;
+ Uint32 const ArraySlice;
+
+ bool operator == (const MappedTextureKey& rhs)const
+ {
+ return Texture == rhs.Texture &&
+ MipLevel == rhs.MipLevel &&
+ ArraySlice == rhs.ArraySlice;
+ }
+ struct Hasher
+ {
+ size_t operator()(const MappedTextureKey& Key)const
+ {
+ return ComputeHash(Key.Texture, Key.MipLevel, Key.ArraySlice);
+ }
+ };
+ };
+ std::unordered_map<MappedTextureKey, TextureUploadSpace, MappedTextureKey::Hasher> m_MappedTextures;
+
+
+
VulkanUploadHeap m_UploadHeap;
DescriptorPoolManager m_DynamicDescriptorPool;
diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
index 6598b71e..1078b943 100644
--- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
@@ -1123,23 +1123,17 @@ namespace Diligent
++m_State.NumCommands;
}
- void DeviceContextVkImpl::UpdateTextureRegion(const void* pSrcData,
- Uint32 SrcStride,
- Uint32 SrcDepthStride,
- TextureVkImpl& TextureVk,
- Uint32 MipLevel,
- Uint32 Slice,
- const Box& DstBox)
+ DeviceContextVkImpl::TextureUploadSpace DeviceContextVkImpl::AllocateTextureUploadSpace(
+ const TextureDesc& TexDesc,
+ Uint32 MipLevel,
+ const Box& Region)
{
- const auto& TexDesc = TextureVk.GetDesc();
- VERIFY(TexDesc.SampleCount == 1, "Only single-sample textures can be updated with vkCmdCopyBufferToImage()");
+ TextureUploadSpace UploadSpace;
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;
- Uint32 RowSize = 0;
- Uint32 RowCount = 0;
+ VERIFY_EXPR(Region.MaxX > Region.MinX && Region.MaxY > Region.MinY && Region.MaxZ > Region.MinZ);
+ auto UpdateRegionWidth = Region.MaxX - Region.MinX;
+ auto UpdateRegionHeight = Region.MaxY - Region.MinY;
+ auto UpdateRegionDepth = Region.MaxZ - Region.MinZ;
if(FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED)
{
// Align update region size by the block size. This is only necessary when updating
@@ -1148,54 +1142,80 @@ namespace Diligent
VERIFY_EXPR( (FmtAttribs.BlockHeight & (FmtAttribs.BlockHeight-1)) == 0 );
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;
+ UploadSpace.RowSize = BlockAlignedRegionWidth / Uint32{FmtAttribs.BlockWidth} * Uint32{FmtAttribs.ComponentSize};
+ UploadSpace.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);
+ VERIFY_EXPR(MipWidth > Region.MinX);
+ UpdateRegionWidth = std::min(UpdateRegionWidth, MipWidth - Region.MinX);
+ VERIFY_EXPR(MipHeight > Region.MinY);
+ UpdateRegionHeight = std::min(UpdateRegionHeight, MipHeight - Region.MinY);
}
else
{
- RowSize = UpdateRegionWidth * Uint32{FmtAttribs.ComponentSize} * Uint32{FmtAttribs.NumComponents};
- RowCount = UpdateRegionHeight;
+ UploadSpace.RowSize = UpdateRegionWidth * Uint32{FmtAttribs.ComponentSize} * Uint32{FmtAttribs.NumComponents};
+ UploadSpace.RowCount = UpdateRegionHeight;
}
+
+ UploadSpace.Stride = UploadSpace.RowSize;
+ UploadSpace.DepthStride = UploadSpace.RowCount * UploadSpace.Stride;
+ const auto MemorySize = UpdateRegionDepth * UploadSpace.DepthStride;
+ size_t Alignment = 4;
+ UploadSpace.Allocation = AllocateDynamicSpace(MemorySize + static_cast<Uint32>(Alignment));
+ UploadSpace.AlignedOffset = static_cast<Uint32>((UploadSpace.Allocation.Offset + (Alignment-1)) & ~(Alignment-1));
+ UploadSpace.Region = Region;
+
+ return UploadSpace;
+ }
+
+
+ void DeviceContextVkImpl::UpdateTextureRegion(const void* pSrcData,
+ Uint32 SrcStride,
+ Uint32 SrcDepthStride,
+ TextureVkImpl& TextureVk,
+ Uint32 MipLevel,
+ Uint32 Slice,
+ const Box& DstBox)
+ {
+ const auto& TexDesc = TextureVk.GetDesc();
+ VERIFY(TexDesc.SampleCount == 1, "Only single-sample textures can be updated with vkCmdCopyBufferToImage()");
+ auto UploadSpace = AllocateTextureUploadSpace(TexDesc, MipLevel, DstBox);
+ const auto UpdateRegionDepth = UploadSpace.Region.MaxZ - UploadSpace.Region.MinZ;
+
#ifdef _DEBUG
- VERIFY(SrcStride >= RowSize, "Source data stride (", SrcStride, ") is below the image row size (", RowSize, ")");
- const Uint32 PlaneSize = SrcStride * RowCount;
+ VERIFY(SrcStride >= UploadSpace.RowSize, "Source data stride (", SrcStride, ") is below the image row size (", UploadSpace.RowSize, ")");
+ const Uint32 PlaneSize = SrcStride * UploadSpace.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 = RowCount * 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 < RowCount; ++row)
+ for(Uint32 DepthSlice = 0; DepthSlice < UpdateRegionDepth; ++DepthSlice)
+ {
+ for(Uint32 row = 0; row < UploadSpace.RowCount; ++row)
{
const auto* pSrcPtr =
reinterpret_cast<const Uint8*>(pSrcData)
- + row * SrcStride
- + slice * SrcDepthStride;
+ + row * SrcStride
+ + DepthSlice * SrcDepthStride;
auto* pDstPtr =
- UploadSpace.pDynamicMemMgr->GetCPUAddress()
- + AlignedOffset
- + row * BufferDataStride
- + slice * BufferDataDepthStride;
+ UploadSpace.Allocation.pDynamicMemMgr->GetCPUAddress()
+ + UploadSpace.AlignedOffset
+ + row * UploadSpace.Stride
+ + DepthSlice * UploadSpace.DepthStride;
- memcpy(pDstPtr, pSrcPtr, RowSize);
+ memcpy(pDstPtr, pSrcPtr, UploadSpace.RowSize);
}
}
+ WriteTextureUploadRegion(TextureVk, UploadSpace, MipLevel, Slice);
+ }
-
+ void DeviceContextVkImpl::WriteTextureUploadRegion(TextureVkImpl& TextureVk,
+ TextureUploadSpace& UploadSpace,
+ Uint32 MipLevel,
+ Uint32 ArraySlice)
+ {
EnsureVkCmdBuffer();
if (TextureVk.GetLayout() != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
{
@@ -1203,7 +1223,7 @@ namespace Diligent
}
VkBufferImageCopy CopyRegion = {};
- CopyRegion.bufferOffset = AlignedOffset; // must be a multiple of 4 (18.4)
+ CopyRegion.bufferOffset = UploadSpace.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
@@ -1211,6 +1231,8 @@ namespace Diligent
CopyRegion.bufferRowLength = 0;
CopyRegion.bufferImageHeight = 0;
+ const auto& TexDesc = TextureVk.GetDesc();
+ const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format);
// 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;
@@ -1226,24 +1248,74 @@ namespace Diligent
else
CopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- CopyRegion.imageSubresource.baseArrayLayer = Slice;
+ CopyRegion.imageSubresource.baseArrayLayer = ArraySlice;
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};
+ const auto& Region = UploadSpace.Region;
+ CopyRegion.imageOffset =
+ VkOffset3D
+ {
+ static_cast<int32_t>(Region.MinX),
+ static_cast<int32_t>(Region.MinY),
+ static_cast<int32_t>(Region.MinZ)
+ };
+ CopyRegion.imageExtent =
+ VkExtent3D
+ {
+ static_cast<uint32_t>(Region.MaxX - Region.MinX),
+ static_cast<uint32_t>(Region.MaxY - Region.MinY),
+ static_cast<uint32_t>(Region.MaxZ - Region.MinZ)
+ };
m_CommandBuffer.CopyBufferToImage(
- UploadSpace.pDynamicMemMgr->GetVkBuffer(),
+ UploadSpace.Allocation.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);
}
+ void DeviceContextVkImpl::MapTexture( TextureVkImpl& TextureVk,
+ Uint32 MipLevel,
+ Uint32 ArraySlice,
+ MAP_TYPE MapType,
+ Uint32 MapFlags,
+ const Box& MapRegion,
+ MappedTextureSubresource& MappedData )
+ {
+ const auto& TexDesc = TextureVk.GetDesc();
+ auto UploadSpace = AllocateTextureUploadSpace(TexDesc, MipLevel, MapRegion);
+ MappedData.pData = reinterpret_cast<Uint8*>(UploadSpace.Allocation.pDynamicMemMgr->GetCPUAddress()) + UploadSpace.AlignedOffset;
+ MappedData.Stride = UploadSpace.Stride;
+ MappedData.DepthStride = UploadSpace.DepthStride;
+
+ auto it = m_MappedTextures.emplace(MappedTextureKey{&TextureVk, MipLevel, ArraySlice}, std::move(UploadSpace));
+ if(!it.second)
+ LOG_ERROR_MESSAGE("Mip level ", MipLevel, ", slice ", ArraySlice, " of texture '", TexDesc.Name, "' has already been mapped");
+ }
+
+ void DeviceContextVkImpl::UnmapTexture( TextureVkImpl& TextureVk,
+ Uint32 MipLevel,
+ Uint32 ArraySlice)
+ {
+ const auto& TexDesc = TextureVk.GetDesc();
+ auto UploadSpaceIt = m_MappedTextures.find(MappedTextureKey{&TextureVk, MipLevel, ArraySlice});
+ if(UploadSpaceIt != m_MappedTextures.end())
+ {
+ auto& UploadSpace = UploadSpaceIt->second;
+ WriteTextureUploadRegion(TextureVk, UploadSpace, MipLevel, ArraySlice);
+ m_MappedTextures.erase(UploadSpaceIt);
+ }
+ else
+ {
+ LOG_ERROR_MESSAGE("Failed to unmap mip level ", MipLevel, ", slice ", ArraySlice, " of texture '", TexDesc.Name, "'. The texture has either been unmapped already or has not been mapped");
+ }
+ }
+
void DeviceContextVkImpl::FinishCommandList(class ICommandList **ppCommandList)
{
if (m_CommandBuffer.GetState().RenderPass != VK_NULL_HANDLE)
diff --git a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp
index 5cff0d89..f975e8f7 100644
--- a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp
@@ -564,13 +564,37 @@ void TextureVkImpl :: Map(IDeviceContext* pContext,
MappedTextureSubresource& MappedData)
{
TTextureBase::Map(pContext, MipLevel, ArraySlice, MapType, MapFlags, pMapRegion, MappedData);
- UNEXPECTED("TextureVkImpl::Map() is not implemented");
+
+ auto* pDeviceContextVk = ValidatedCast<DeviceContextVkImpl>(pContext);
+ MappedData = MappedTextureSubresource{};
+
+ Box FullExtentBox;
+ if (pMapRegion == nullptr)
+ {
+ FullExtentBox.MaxX = std::max(m_Desc.Width >> MipLevel, 1u);
+ FullExtentBox.MaxY = std::max(m_Desc.Height >> MipLevel, 1u);
+ if (m_Desc.Type == RESOURCE_DIM_TEX_3D)
+ FullExtentBox.MaxZ = std::max(m_Desc.Depth >> MipLevel, 1u);
+ pMapRegion = &FullExtentBox;
+ }
+
+ if(MapType == MAP_WRITE)
+ {
+ if( (MapFlags & (MAP_FLAG_DISCARD | MAP_FLAG_DO_NOT_SYNCHRONIZE)) != 0 )
+ LOG_WARNING_MESSAGE_ONCE("Mapping textures with flags MAP_FLAG_DISCARD or MAP_FLAG_DO_NOT_SYNCHRONIZE has no effect in Vulkan backend");
+ pDeviceContextVk->MapTexture(*this, MipLevel, ArraySlice, MapType, MapFlags, *pMapRegion, MappedData);
+ }
+ else
+ {
+ LOG_ERROR("Textures can currently only be mapped for writing in D3D12 backend");
+ }
}
void TextureVkImpl::Unmap(IDeviceContext *pContext, Uint32 MipLevel, Uint32 ArraySlice)
{
TTextureBase::Unmap(pContext, MipLevel, ArraySlice);
- UNEXPECTED("TextureVkImpl::Unmap() is not implemented");
+ auto* pDeviceContextVk = ValidatedCast<DeviceContextVkImpl>(pContext);
+ pDeviceContextVk->UnmapTexture(*this, MipLevel, ArraySlice);
}
VulkanUtilities::ImageViewWrapper TextureVkImpl::CreateImageView(TextureViewDesc& ViewDesc)