summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngineVulkan
diff options
context:
space:
mode:
authorEgor Yusov <egor.yusov@gmail.com>2019-04-11 15:39:32 +0000
committerEgor Yusov <egor.yusov@gmail.com>2019-04-11 15:39:32 +0000
commit8ad6ca05f069b59af9544bc99bed7e5d1f785950 (patch)
tree0dd6d845177796fb24902f8baa88484922c99e37 /Graphics/GraphicsEngineVulkan
parentAdded render target format validation when creating a PSO (diff)
downloadDiligentCore-8ad6ca05f069b59af9544bc99bed7e5d1f785950.tar.gz
DiligentCore-8ad6ca05f069b59af9544bc99bed7e5d1f785950.zip
Reworked automatic mipmap generation in Vulkan backend to support sRGB textures, enable mipmap generation for partial texture views and optimize state transitions
Diffstat (limited to 'Graphics/GraphicsEngineVulkan')
-rw-r--r--Graphics/GraphicsEngineVulkan/include/GenerateMipsVkHelper.h4
-rw-r--r--Graphics/GraphicsEngineVulkan/include/TextureViewVkImpl.h29
-rw-r--r--Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h18
-rw-r--r--Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h18
-rw-r--r--Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.h1
-rw-r--r--Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp6
-rw-r--r--Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp203
-rw-r--r--Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp14
-rw-r--r--Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp190
-rw-r--r--Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp7
10 files changed, 348 insertions, 142 deletions
diff --git a/Graphics/GraphicsEngineVulkan/include/GenerateMipsVkHelper.h b/Graphics/GraphicsEngineVulkan/include/GenerateMipsVkHelper.h
index 4c878ae7..17b20d4b 100644
--- a/Graphics/GraphicsEngineVulkan/include/GenerateMipsVkHelper.h
+++ b/Graphics/GraphicsEngineVulkan/include/GenerateMipsVkHelper.h
@@ -49,11 +49,15 @@ namespace Diligent
void GenerateMips(TextureViewVkImpl& TexView, DeviceContextVkImpl& Ctx, IShaderResourceBinding& SRB);
void CreateSRB(IShaderResourceBinding** ppSRB);
+ void WarmUpCache(TEXTURE_FORMAT Fmt);
private:
std::array<RefCntAutoPtr<IPipelineState>, 4> CreatePSOs(TEXTURE_FORMAT Fmt);
std::array<RefCntAutoPtr<IPipelineState>, 4>& FindPSOs (TEXTURE_FORMAT Fmt);
+ VkImageLayout GenerateMipsCS (TextureViewVkImpl& TexView, DeviceContextVkImpl& Ctx, IShaderResourceBinding& SRB, VkImageSubresourceRange& SubresRange);
+ VkImageLayout GenerateMipsBlit(TextureViewVkImpl& TexView, DeviceContextVkImpl& Ctx, IShaderResourceBinding& SRB, VkImageSubresourceRange& SubresRange);
+
RenderDeviceVkImpl& m_DeviceVkImpl;
std::mutex m_PSOMutex;
diff --git a/Graphics/GraphicsEngineVulkan/include/TextureViewVkImpl.h b/Graphics/GraphicsEngineVulkan/include/TextureViewVkImpl.h
index 8989c245..2e69e34e 100644
--- a/Graphics/GraphicsEngineVulkan/include/TextureViewVkImpl.h
+++ b/Graphics/GraphicsEngineVulkan/include/TextureViewVkImpl.h
@@ -54,9 +54,36 @@ public:
VkImageView GetVulkanImageView()const override final{return m_ImageView;}
+ bool HasMipLevelViews() const
+ {
+ return m_MipLevelViews != nullptr;
+ }
+
+ TextureViewVkImpl* GetMipLevelSRV(Uint32 MipLevel)
+ {
+ VERIFY_EXPR(m_MipLevelViews != nullptr && MipLevel < m_Desc.NumMipLevels);
+ return m_MipLevelViews[MipLevel*2].get();
+ }
+
+ TextureViewVkImpl* GetMipLevelUAV(Uint32 MipLevel)
+ {
+ VERIFY_EXPR(m_MipLevelViews != nullptr && MipLevel < m_Desc.NumMipLevels);
+ return m_MipLevelViews[MipLevel*2 + 1].get();
+ }
+
+ using MipLevelViewAutoPtrType = std::unique_ptr<TextureViewVkImpl, STDDeleter<TextureViewVkImpl, FixedBlockMemoryAllocator> >;
+
+ void AssignMipLevelViews(MipLevelViewAutoPtrType* MipLevelViews)
+ {
+ m_MipLevelViews = MipLevelViews;
+ }
+
protected:
/// Vulkan image view descriptor handle
- VulkanUtilities::ImageViewWrapper m_ImageView;
+ VulkanUtilities::ImageViewWrapper m_ImageView;
+
+ /// Individual mip level views used for mipmap generation
+ MipLevelViewAutoPtrType* m_MipLevelViews = nullptr;
};
}
diff --git a/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h b/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h
index 33f07b79..d3d0883a 100644
--- a/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h
+++ b/Graphics/GraphicsEngineVulkan/include/TextureVkImpl.h
@@ -83,17 +83,6 @@ public:
return vkImage;
}
- ITextureView* GetMipLevelSRV(Uint32 MipLevel)
- {
- return m_MipLevelSRV[MipLevel].get();
- }
-
- ITextureView* GetMipLevelUAV(Uint32 MipLevel)
- {
- return m_MipLevelUAV[MipLevel].get();
- }
-
-
void SetLayout(VkImageLayout Layout)override final;
VkImageLayout GetLayout()const override final;
@@ -116,16 +105,15 @@ protected:
void CreateViewInternal( const struct TextureViewDesc& ViewDesc, ITextureView** ppView, bool bIsDefaultView )override;
//void PrepareVkInitData(const TextureData &InitData, Uint32 NumSubresources, std::vector<Vk_SUBRESOURCE_DATA> &VkInitData);
+ bool CheckCSBasedMipGenerationSupport(VkFormat vkFmt)const;
+
VulkanUtilities::ImageViewWrapper CreateImageView(TextureViewDesc &ViewDesc);
VulkanUtilities::ImageWrapper m_VulkanImage;
VulkanUtilities::BufferWrapper m_StagingBuffer;
VulkanUtilities::VulkanMemoryAllocation m_MemoryAllocation;
VkDeviceSize m_StagingDataAlignedOffset;
-
- // Texture views needed for mipmap generation
- std::vector<std::unique_ptr<TextureViewVkImpl, STDDeleter<TextureViewVkImpl, FixedBlockMemoryAllocator> > > m_MipLevelSRV;
- std::vector<std::unique_ptr<TextureViewVkImpl, STDDeleter<TextureViewVkImpl, FixedBlockMemoryAllocator> > > m_MipLevelUAV;
+ bool m_bCSBasedMipGenerationSupported = false;
};
}
diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h
index 3d35c581..8fc47e3b 100644
--- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h
+++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h
@@ -394,6 +394,24 @@ namespace VulkanUtilities
vkCmdCopyImageToBuffer(m_VkCmdBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions);
}
+ void BlitImage(VkImage srcImage,
+ VkImageLayout srcImageLayout,
+ VkImage dstImage,
+ VkImageLayout dstImageLayout,
+ uint32_t regionCount,
+ const VkImageBlit* pRegions,
+ VkFilter filter)
+ {
+ VERIFY_EXPR(m_VkCmdBuffer != VK_NULL_HANDLE);
+ if (m_State.RenderPass != VK_NULL_HANDLE)
+ {
+ // Blit must be performed outside of render pass.
+ EndRenderPass();
+ }
+
+ vkCmdBlitImage(m_VkCmdBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions, filter);
+ }
+
void FlushBarriers();
void SetVkCmdBuffer(VkCommandBuffer VkCmdBuffer)
diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.h
index 7056268f..a264c80c 100644
--- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.h
+++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanPhysicalDevice.h
@@ -48,6 +48,7 @@ namespace VulkanUtilities
uint32_t GetMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties)const;
const VkPhysicalDeviceProperties& GetProperties() const {return m_Properties;}
const VkPhysicalDeviceFeatures& GetFeatures() const {return m_Features; }
+ VkFormatProperties GetPhysicalDeviceFormatProperties(VkFormat imageFormat)const;
private:
VulkanPhysicalDevice(VkPhysicalDevice vkDevice);
diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
index 384a342d..03eb0992 100644
--- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp
@@ -2023,7 +2023,11 @@ namespace Diligent
void DeviceContextVkImpl::TransitionImageLayout(TextureVkImpl& TextureVk, VkImageLayout OldLayout, VkImageLayout NewLayout, const VkImageSubresourceRange& SubresRange)
{
- VERIFY(TextureVk.GetLayout() != NewLayout, "The texture is already transitioned to correct layout");
+ // Note that the method may be used to transition texture subresources when global texture state is not altered,
+ // so the debug check below can't be used
+ // VERIFY(!TextureVk.IsInKnownState() || TextureVk.GetLayout() != NewLayout, "The texture is already transitioned to correct layout");
+
+ VERIFY(OldLayout != NewLayout, "Old and new layouts are the same");
EnsureVkCmdBuffer();
auto vkImg = TextureVk.GetVkImage();
m_CommandBuffer.TransitionImageLayout(vkImg, OldLayout, NewLayout, SubresRange);
diff --git a/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp b/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp
index 3f4a716c..58b2b122 100644
--- a/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/GenerateMipsVkHelper.cpp
@@ -176,8 +176,6 @@ namespace Diligent
FindPSOs(TEX_FORMAT_RGBA8_UNORM);
FindPSOs(TEX_FORMAT_BGRA8_UNORM);
- FindPSOs(TEX_FORMAT_RGBA8_UNORM_SRGB);
- FindPSOs(TEX_FORMAT_BGRA8_UNORM_SRGB);
}
void GenerateMipsVkHelper::CreateSRB(IShaderResourceBinding** ppSRB)
@@ -196,31 +194,29 @@ namespace Diligent
return it->second;
}
+ void GenerateMipsVkHelper::WarmUpCache(TEXTURE_FORMAT Fmt)
+ {
+ FindPSOs(Fmt);
+ }
+
void GenerateMipsVkHelper::GenerateMips(TextureViewVkImpl& TexView, DeviceContextVkImpl& Ctx, IShaderResourceBinding& SRB)
{
auto* pTexVk = TexView.GetTexture<TextureVkImpl>();
- const auto& TexDesc = pTexVk->GetDesc();
-
if (!pTexVk->IsInKnownState())
{
- LOG_ERROR_MESSAGE("Unable to generate mips for texture '", TexDesc.Name, "' because the texture state is unknown");
+ LOG_ERROR_MESSAGE("Unable to generate mips for texture '", pTexVk->GetDesc().Name, "' because the texture state is unknown");
return;
}
- const auto& ViewDesc = TexView.GetDesc();
- auto* pSrcMipVar = SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "SrcMip");
- IShaderResourceVariable* pOutMipVar[4] =
- {
- SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "OutMip0"),
- SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "OutMip1"),
- SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "OutMip2"),
- SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "OutMip3")
- };
+ DEV_CHECK_ERR(TexView.GetDesc().NumMipLevels > 1, "Number of mip levels in the view must be greater than 1");
- auto& PSOs = FindPSOs(ViewDesc.Format);
+ const auto OriginalState = pTexVk->GetState();
+ const auto OriginalLayout = pTexVk->GetLayout();
+ const auto& TexDesc = pTexVk->GetDesc();
+ const auto& ViewDesc = TexView.GetDesc();
- const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format);
- VkImageSubresourceRange SubresRange;
+ const auto& FmtAttribs = GetTextureFormatAttribs(ViewDesc.Format);
+ VkImageSubresourceRange SubresRange = {};
if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH)
SubresRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
else if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL)
@@ -232,27 +228,84 @@ namespace Diligent
}
else
SubresRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- SubresRange.baseArrayLayer = 0;
- SubresRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
+ SubresRange.baseArrayLayer = ViewDesc.FirstArraySlice;
+ SubresRange.layerCount = ViewDesc.NumArraySlices;
+ SubresRange.baseMipLevel = ViewDesc.MostDetailedMip;
+ SubresRange.levelCount = 1;
+
+ VkImageLayout AffectedMipLevelLayout;
+ if (TexView.HasMipLevelViews())
+ {
+ AffectedMipLevelLayout = GenerateMipsCS(TexView, Ctx, SRB, SubresRange);
+ }
+ else
+ {
+ AffectedMipLevelLayout = GenerateMipsBlit(TexView, Ctx, SRB, SubresRange);
+ }
+
+ // All affected mip levels are now in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL state
+ if (AffectedMipLevelLayout != OriginalLayout)
+ {
+ bool IsAllSlices = (TexDesc.Type != RESOURCE_DIM_TEX_1D_ARRAY &&
+ TexDesc.Type != RESOURCE_DIM_TEX_2D_ARRAY &&
+ TexDesc.Type != RESOURCE_DIM_TEX_CUBE_ARRAY) ||
+ TexDesc.ArraySize == ViewDesc.NumArraySlices;
+ bool IsAllMips = ViewDesc.NumMipLevels == TexDesc.MipLevels;
+ if (IsAllSlices && IsAllMips)
+ {
+ pTexVk->SetLayout(AffectedMipLevelLayout);
+ }
+ else
+ {
+ SubresRange.baseMipLevel = ViewDesc.MostDetailedMip;
+ SubresRange.levelCount = ViewDesc.NumMipLevels;
+ // Transition all affected subresources back to original layout
+ Ctx.TransitionImageLayout(*pTexVk, AffectedMipLevelLayout, OriginalLayout, SubresRange);
+ VERIFY_EXPR(pTexVk->GetLayout() == OriginalLayout);
+ }
+ }
+ }
+
+ VkImageLayout GenerateMipsVkHelper::GenerateMipsCS(TextureViewVkImpl& TexView, DeviceContextVkImpl& Ctx, IShaderResourceBinding& SRB, VkImageSubresourceRange& SubresRange)
+ {
+ auto* pTexVk = TexView.GetTexture<TextureVkImpl>();
+ const auto& TexDesc = pTexVk->GetDesc();
+
+ VERIFY(TexDesc.Type == RESOURCE_DIM_TEX_2D || TexDesc.Type == RESOURCE_DIM_TEX_2D_ARRAY,
+ "CS-based mipmap generation is only supported for 2D textures and texture arrays");
+
+ const auto& ViewDesc = TexView.GetDesc();
+ auto* pSrcMipVar = SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "SrcMip");
+ IShaderResourceVariable* pOutMipVar[4] =
+ {
+ SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "OutMip0"),
+ SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "OutMip1"),
+ SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "OutMip2"),
+ SRB.GetVariableByName(SHADER_TYPE_COMPUTE, "OutMip3")
+ };
+
+ auto& PSOs = FindPSOs(ViewDesc.Format);
- const auto CurrState = pTexVk->GetState();
- const auto CurrLayout = ResourceStateToVkImageLayout(CurrState);
+ const auto OriginalState = pTexVk->GetState();
+ const auto OriginalLayout = pTexVk->GetLayout();
// Transition the lowest mip level to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
- SubresRange.baseMipLevel = 0;
- SubresRange.levelCount = 1;
- if (CurrState != RESOURCE_STATE_SHADER_RESOURCE)
- Ctx.TransitionTextureState(*pTexVk, CurrState, RESOURCE_STATE_SHADER_RESOURCE, false, &SubresRange);
+ SubresRange.baseMipLevel = ViewDesc.MostDetailedMip;
+ SubresRange.levelCount = 1;
+ if (OriginalState != RESOURCE_STATE_SHADER_RESOURCE)
+ Ctx.TransitionTextureState(*pTexVk, OriginalState, RESOURCE_STATE_SHADER_RESOURCE, false /*UpdateTextureState*/, &SubresRange);
VERIFY_EXPR(ResourceStateToVkImageLayout(RESOURCE_STATE_SHADER_RESOURCE) == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
- for (uint32_t TopMip = 0; TopMip < TexDesc.MipLevels - 1; )
+ // Note that mip levels are relative to the view's most detailed mip
+ auto LowestMip = ViewDesc.NumMipLevels - 1;
+ for (uint32_t TopMip = 0; TopMip < LowestMip; )
{
// In Vulkan all subresources of a view must be transitioned to the same layout, so
// we can't bind the entire texture and have to bind single mip level at a time
- pSrcMipVar->Set(pTexVk->GetMipLevelSRV(TopMip));
+ pSrcMipVar->Set(TexView.GetMipLevelSRV(TopMip));
- uint32_t SrcWidth = std::max(TexDesc.Width >> TopMip, 1u);
- uint32_t SrcHeight = std::max(TexDesc.Height >> TopMip, 1u);
+ uint32_t SrcWidth = std::max(TexDesc.Width >> (TopMip + ViewDesc.MostDetailedMip), 1u);
+ uint32_t SrcHeight = std::max(TexDesc.Height >> (TopMip + ViewDesc.MostDetailedMip), 1u);
uint32_t DstWidth = std::max(SrcWidth >> 1, 1u);
uint32_t DstHeight = std::max(SrcHeight >> 1, 1u);
@@ -268,8 +321,8 @@ namespace Diligent
// in the low bits. Zeros indicate we can divide by two without truncating.
uint32_t AdditionalMips = PlatformMisc::GetLSB(DstWidth | DstHeight);
uint32_t NumMips = 1 + (AdditionalMips > 3 ? 3 : AdditionalMips);
- if (TopMip + NumMips > TexDesc.MipLevels - 1)
- NumMips = TexDesc.MipLevels - 1 - TopMip;
+ if (TopMip + NumMips > LowestMip)
+ NumMips = LowestMip - TopMip;
// These are clamped to 1 after computing additional mips because clamped
// dimensions should not limit us from downsampling multiple times. (E.g.
@@ -286,7 +339,7 @@ namespace Diligent
Int32 NumMipLevels; // Number of OutMips to write: [1, 4]
Int32 ArraySlice;
Int32 Dummy;
- float TexelSize[2]; // 1.0 / OutMip1.Dimensions
+ float TexelSize[2]; // 1.0 / OutMip1.Dimensions
};
MapHelper<CBData> MappedData(&Ctx, m_ConstantsCB, MAP_WRITE, MAP_FLAG_DISCARD);
@@ -294,8 +347,8 @@ namespace Diligent
{
static_cast<Int32>(TopMip),
static_cast<Int32>(NumMips),
- static_cast<Int32>(ViewDesc.FirstArraySlice),
- 0,
+ 0, // Array slices are relative to the view's first array slice
+ 0, // Unused
{1.0f / static_cast<float>(DstWidth), 1.0f / static_cast<float>(DstHeight)}
};
}
@@ -303,14 +356,14 @@ namespace Diligent
constexpr const Uint32 MaxMipsHandledByCS = 4; // Max number of mip levels processed by one CS shader invocation
for (Uint32 u = 0; u < MaxMipsHandledByCS; ++u)
{
- auto* MipLevelUAV = pTexVk->GetMipLevelUAV(std::min(TopMip + u + 1, TexDesc.MipLevels - 1));
+ auto* MipLevelUAV = TexView.GetMipLevelUAV(std::min(TopMip + u + 1, LowestMip));
pOutMipVar[u]->Set(MipLevelUAV);
}
- SubresRange.baseMipLevel = TopMip + 1;
- SubresRange.levelCount = std::min(4u, TexDesc.MipLevels - (TopMip + 1));
- if (CurrLayout != VK_IMAGE_LAYOUT_GENERAL)
- Ctx.TransitionImageLayout(*pTexVk, CurrLayout, VK_IMAGE_LAYOUT_GENERAL, SubresRange);
+ SubresRange.baseMipLevel = ViewDesc.MostDetailedMip + TopMip + 1;
+ SubresRange.levelCount = std::min(4u, LowestMip - TopMip);
+ if (OriginalLayout != VK_IMAGE_LAYOUT_GENERAL)
+ Ctx.TransitionImageLayout(*pTexVk, OriginalLayout, VK_IMAGE_LAYOUT_GENERAL, SubresRange);
Ctx.CommitShaderResources(&SRB, RESOURCE_STATE_TRANSITION_MODE_NONE);
DispatchComputeAttribs DispatchAttrs((DstWidth + 7) / 8, (DstHeight + 7) / 8, ViewDesc.NumArraySlices);
@@ -321,8 +374,74 @@ namespace Diligent
TopMip += NumMips;
}
- // All mip levels are now in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL state
- pTexVk->SetState(RESOURCE_STATE_SHADER_RESOURCE);
- VERIFY_EXPR(pTexVk->GetLayout() == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+ return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ }
+
+ VkImageLayout GenerateMipsVkHelper::GenerateMipsBlit(TextureViewVkImpl& TexView, DeviceContextVkImpl& Ctx, IShaderResourceBinding& SRB, VkImageSubresourceRange& SubresRange)
+ {
+ auto* pTexVk = TexView.GetTexture<TextureVkImpl>();
+ const auto& TexDesc = pTexVk->GetDesc();
+ const auto& ViewDesc = TexView.GetDesc();
+ auto vkImage = pTexVk->GetVkImage();
+
+ const auto OriginalState = pTexVk->GetState();
+ const auto OriginalLayout = ResourceStateToVkImageLayout(OriginalState);
+
+ VkImageBlit BlitRegion = {};
+ BlitRegion.srcSubresource.baseArrayLayer = ViewDesc.FirstArraySlice;
+ BlitRegion.srcSubresource.layerCount = ViewDesc.NumArraySlices;
+ BlitRegion.srcSubresource.aspectMask = SubresRange.aspectMask;
+ BlitRegion.dstSubresource.baseArrayLayer = BlitRegion.srcSubresource.baseArrayLayer;
+ BlitRegion.dstSubresource.layerCount = BlitRegion.srcSubresource.layerCount;
+ BlitRegion.dstSubresource.aspectMask = BlitRegion.srcSubresource.aspectMask;
+ BlitRegion.srcOffsets[0] = VkOffset3D{0, 0, 0};
+ BlitRegion.dstOffsets[0] = VkOffset3D{0, 0, 0};
+
+ SubresRange.baseMipLevel = ViewDesc.MostDetailedMip;
+ SubresRange.levelCount = 1;
+ if (OriginalState != RESOURCE_STATE_COPY_SOURCE)
+ Ctx.TransitionTextureState(*pTexVk, OriginalState, RESOURCE_STATE_COPY_SOURCE, false /*UpdateTextureState*/, &SubresRange);
+
+ auto& CmdBuffer = Ctx.GetCommandBuffer();
+ for (uint32_t mip = ViewDesc.MostDetailedMip + 1; mip < ViewDesc.MostDetailedMip + ViewDesc.NumMipLevels; ++mip)
+ {
+ BlitRegion.srcSubresource.mipLevel = mip-1;
+ BlitRegion.dstSubresource.mipLevel = mip;
+
+ BlitRegion.srcOffsets[1] =
+ VkOffset3D
+ {
+ static_cast<int32_t>(std::max(TexDesc.Width >> (mip-1), 1u)),
+ static_cast<int32_t>(std::max(TexDesc.Height >> (mip-1), 1u)),
+ 1
+ };
+ BlitRegion.dstOffsets[1] =
+ VkOffset3D
+ {
+ static_cast<int32_t>(std::max(TexDesc.Width >> mip, 1u)),
+ static_cast<int32_t>(std::max(TexDesc.Height >> mip, 1u)),
+ 1
+ };
+ if (TexDesc.Type == RESOURCE_DIM_TEX_3D)
+ {
+ BlitRegion.srcOffsets[1].z = std::max(TexDesc.Depth >> (mip-1), 1u);
+ BlitRegion.dstOffsets[1].z = std::max(TexDesc.Depth >> mip, 1u);
+ }
+
+ SubresRange.baseMipLevel = mip;
+ if (OriginalLayout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
+ Ctx.TransitionImageLayout(*pTexVk, OriginalLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, SubresRange);
+
+ CmdBuffer.BlitImage(vkImage,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // must be VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL
+ vkImage,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL
+ 1,
+ &BlitRegion,
+ VK_FILTER_LINEAR);
+ Ctx.TransitionImageLayout(*pTexVk, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, SubresRange);
+ }
+
+ return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
}
}
diff --git a/Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp
index f12d217a..8ad690fa 100644
--- a/Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/TextureViewVkImpl.cpp
@@ -34,14 +34,24 @@ TextureViewVkImpl::TextureViewVkImpl( IReferenceCounters* pRefCo
const TextureViewDesc& ViewDesc,
ITexture* pTexture,
VulkanUtilities::ImageViewWrapper&& ImgView,
- bool bIsDefaultView ) :
+ bool bIsDefaultView) :
TTextureViewBase( pRefCounters, pDevice, ViewDesc, pTexture, bIsDefaultView ),
- m_ImageView(std::move(ImgView))
+ m_ImageView (std::move(ImgView))
{
}
TextureViewVkImpl::~TextureViewVkImpl()
{
+ if (m_MipLevelViews != nullptr)
+ {
+ for (Uint32 MipView=0; MipView < m_Desc.NumMipLevels * 2; ++MipView)
+ {
+ m_MipLevelViews[MipView].~MipLevelViewAutoPtrType();
+ }
+ // Memory allocated in TextureVkImpl::CreateViewInternal()
+ GetRawAllocator().Free(m_MipLevelViews);
+ }
+
if(m_Desc.ViewType == TEXTURE_VIEW_DEPTH_STENCIL || m_Desc.ViewType == TEXTURE_VIEW_RENDER_TARGET)
m_pDevice->GetFramebufferCache().OnDestroyImageView(m_ImageView);
m_pDevice->SafeReleaseDeviceObject(std::move(m_ImageView), m_pTexture->GetDesc().CommandQueueMask);
diff --git a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp
index 6c4e08a0..4d05b81f 100644
--- a/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/TextureVkImpl.cpp
@@ -69,9 +69,6 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters,
LOG_ERROR_AND_THROW("Static textures must be initialized with data at creation time: pInitData can't be null");
const auto& FmtAttribs = GetTextureFormatAttribs(m_Desc.Format);
- if ((m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS) != 0 && FmtAttribs.IsTypeless)
- LOG_ERROR_AND_THROW("Textures created with MISC_TEXTURE_FLAG_GENERATE_MIPS flag can't use typeless formats. The following format was provided: ", FmtAttribs.Name, " when attempting to create texture '", m_Desc.Name, "'");
-
const auto& LogicalDevice = pRenderDeviceVk->GetLogicalDevice();
if (m_Desc.Usage == USAGE_STATIC || m_Desc.Usage == USAGE_DEFAULT || m_Desc.Usage == USAGE_DYNAMIC)
@@ -100,28 +97,26 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters,
LOG_ERROR_AND_THROW("Unknown texture type");
}
+ TEXTURE_FORMAT InternalTexFmt = m_Desc.Format;
if (FmtAttribs.IsTypeless)
{
- TEXTURE_VIEW_TYPE DefaultTexView;
- if(m_Desc.BindFlags & BIND_DEPTH_STENCIL)
- DefaultTexView = TEXTURE_VIEW_DEPTH_STENCIL;
+ TEXTURE_VIEW_TYPE PrimaryViewType;
+ if (m_Desc.BindFlags & BIND_DEPTH_STENCIL)
+ PrimaryViewType = TEXTURE_VIEW_DEPTH_STENCIL;
else if (m_Desc.BindFlags & BIND_UNORDERED_ACCESS)
- DefaultTexView = TEXTURE_VIEW_UNORDERED_ACCESS;
+ PrimaryViewType = TEXTURE_VIEW_UNORDERED_ACCESS;
else if (m_Desc.BindFlags & BIND_RENDER_TARGET)
- DefaultTexView = TEXTURE_VIEW_RENDER_TARGET;
+ PrimaryViewType = TEXTURE_VIEW_RENDER_TARGET;
else
- DefaultTexView = TEXTURE_VIEW_SHADER_RESOURCE;
- auto DefaultViewFormat = GetDefaultTextureViewFormat(m_Desc, DefaultTexView);
- ImageCI.format = TexFormatToVkFormat(DefaultViewFormat);
- }
- else
- {
- ImageCI.format = TexFormatToVkFormat(m_Desc.Format);
+ PrimaryViewType = TEXTURE_VIEW_SHADER_RESOURCE;
+ InternalTexFmt = GetDefaultTextureViewFormat(m_Desc, PrimaryViewType);
}
+
+ ImageCI.format = TexFormatToVkFormat(InternalTexFmt);
- ImageCI.extent.width = m_Desc.Width;
+ ImageCI.extent.width = m_Desc.Width;
ImageCI.extent.height = (m_Desc.Type == RESOURCE_DIM_TEX_1D || m_Desc.Type == RESOURCE_DIM_TEX_1D_ARRAY) ? 1 : m_Desc.Height;
- ImageCI.extent.depth = (m_Desc.Type == RESOURCE_DIM_TEX_3D) ? m_Desc.Depth : 1;
+ ImageCI.extent.depth = (m_Desc.Type == RESOURCE_DIM_TEX_3D) ? m_Desc.Depth : 1;
ImageCI.mipLevels = m_Desc.MipLevels;
if (m_Desc.Type == RESOURCE_DIM_TEX_1D_ARRAY ||
@@ -146,7 +141,7 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters,
// VK_IMAGE_USAGE_TRANSFER_DST_BIT is required for vkCmdClearDepthStencilImage()
ImageCI.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
}
- if ((m_Desc.BindFlags & BIND_UNORDERED_ACCESS) || (m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS))
+ if (m_Desc.BindFlags & BIND_UNORDERED_ACCESS)
{
ImageCI.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
}
@@ -155,6 +150,28 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters,
ImageCI.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
}
+ if (m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS)
+ {
+ if (CheckCSBasedMipGenerationSupport(ImageCI.format))
+ {
+ ImageCI.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
+ m_bCSBasedMipGenerationSupported = true;
+ // TODO: warm-up generate mips PSO cache
+ }
+ else
+ {
+ const auto& PhysicalDevice = pRenderDeviceVk->GetPhysicalDevice();
+ auto FmtProperties = PhysicalDevice.GetPhysicalDeviceFormatProperties(ImageCI.format); (void)FmtProperties;
+ DEV_CHECK_ERR((FmtProperties.optimalTilingFeatures & (VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT)) == (VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT),
+ "Texture format ", GetTextureFormatAttribs(InternalTexFmt).Name, " does not support blitting. "
+ "Automatic mipmap generation can't be done neither by CS nor by blitting.");
+
+ DEV_CHECK_ERR((FmtProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT) != 0,
+ "Texture format ", GetTextureFormatAttribs(InternalTexFmt).Name, " does not support linear filtering. "
+ "Automatic mipmap generation can't be done neither by CS nor by blitting.");
+ }
+ }
+
ImageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
ImageCI.queueFamilyIndexCount = 0;
ImageCI.pQueueFamilyIndices = nullptr;
@@ -384,60 +401,6 @@ TextureVkImpl :: TextureVkImpl(IReferenceCounters* pRefCounters,
Uint32 QueueIndex = 0;
pRenderDeviceVk->ExecuteAndDisposeTransientCmdBuff(QueueIndex, vkCmdBuff, std::move(CmdPool));
}
-
-
- if(m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS)
- {
- if (m_Desc.Type != RESOURCE_DIM_TEX_2D && m_Desc.Type != RESOURCE_DIM_TEX_2D_ARRAY)
- {
- LOG_ERROR_AND_THROW("Mipmap generation is only supported for 2D textures and texture arrays");
- }
-
- m_MipLevelUAV.reserve(m_Desc.MipLevels);
- for(Uint32 MipLevel = 0; MipLevel < m_Desc.MipLevels; ++MipLevel)
- {
- // Create mip level UAV
- TextureViewDesc UAVDesc;
- std::stringstream name_ss;
- name_ss << "Mip " << MipLevel << " UAV for texture '" << m_Desc.Name << "'";
- auto name = name_ss.str();
- UAVDesc.Name = name.c_str();
- // Always create texture array UAV
- UAVDesc.TextureDim = RESOURCE_DIM_TEX_2D_ARRAY;
- UAVDesc.ViewType = TEXTURE_VIEW_UNORDERED_ACCESS;
- UAVDesc.FirstArraySlice = 0;
- UAVDesc.NumArraySlices = m_Desc.ArraySize;
- UAVDesc.MostDetailedMip = MipLevel;
- if (m_Desc.Format == TEX_FORMAT_RGBA8_UNORM_SRGB)
- UAVDesc.Format = TEX_FORMAT_RGBA8_UNORM;
- ITextureView* pMipUAV = nullptr;
- CreateViewInternal( UAVDesc, &pMipUAV, true );
- m_MipLevelUAV.emplace_back(ValidatedCast<TextureViewVkImpl>(pMipUAV), STDDeleter<TextureViewVkImpl, FixedBlockMemoryAllocator>(TexViewObjAllocator));
- }
- VERIFY_EXPR(m_MipLevelUAV.size() == m_Desc.MipLevels);
-
- m_MipLevelSRV.reserve(m_Desc.MipLevels);
- for(Uint32 MipLevel = 0; MipLevel < m_Desc.MipLevels; ++MipLevel)
- {
- // Create mip level SRV
- TextureViewDesc TexArraySRVDesc;
- std::stringstream name_ss;
- name_ss << "Mip " << MipLevel << " SRV for texture '" << m_Desc.Name << "'";
- auto name = name_ss.str();
- TexArraySRVDesc.Name = name.c_str();
- // Alaways create texture array view
- TexArraySRVDesc.TextureDim = RESOURCE_DIM_TEX_2D_ARRAY;
- TexArraySRVDesc.ViewType = TEXTURE_VIEW_SHADER_RESOURCE;
- TexArraySRVDesc.FirstArraySlice = 0;
- TexArraySRVDesc.NumArraySlices = m_Desc.ArraySize;
- TexArraySRVDesc.MostDetailedMip = MipLevel;
- TexArraySRVDesc.NumMipLevels = 1;
- ITextureView* pMipLevelSRV = nullptr;
- CreateViewInternal( TexArraySRVDesc, &pMipLevelSRV, true );
- m_MipLevelSRV.emplace_back(ValidatedCast<TextureViewVkImpl>(pMipLevelSRV), STDDeleter<TextureViewVkImpl, FixedBlockMemoryAllocator>(TexViewObjAllocator));
- }
- VERIFY_EXPR(m_MipLevelSRV.size() == m_Desc.MipLevels);
- }
}
else if(m_Desc.Usage == USAGE_STAGING)
{
@@ -549,7 +512,7 @@ TextureVkImpl::TextureVkImpl(IReferenceCounters* pRefCounters,
IMPLEMENT_QUERY_INTERFACE( TextureVkImpl, IID_TextureVk, TTextureBase )
-void TextureVkImpl::CreateViewInternal( const struct TextureViewDesc &ViewDesc, ITextureView **ppView, bool bIsDefaultView )
+void TextureVkImpl::CreateViewInternal(const TextureViewDesc& ViewDesc, ITextureView** ppView, bool bIsDefaultView)
{
VERIFY( ppView != nullptr, "View pointer address is null" );
if( !ppView )return;
@@ -559,22 +522,71 @@ void TextureVkImpl::CreateViewInternal( const struct TextureViewDesc &ViewDesc,
try
{
- auto &TexViewAllocator = m_pDevice->GetTexViewObjAllocator();
+ auto& TexViewAllocator = m_pDevice->GetTexViewObjAllocator();
VERIFY( &TexViewAllocator == &m_dbgTexViewObjAllocator, "Texture view allocator does not match allocator provided during texture initialization" );
auto UpdatedViewDesc = ViewDesc;
CorrectTextureViewDesc( UpdatedViewDesc );
VulkanUtilities::ImageViewWrapper ImgView = CreateImageView(UpdatedViewDesc);
-
auto pViewVk = NEW_RC_OBJ(TexViewAllocator, "TextureViewVkImpl instance", TextureViewVkImpl, bIsDefaultView ? this : nullptr)
- (GetDevice(), UpdatedViewDesc, this, std::move(ImgView), bIsDefaultView );
+ (GetDevice(), UpdatedViewDesc, this, std::move(ImgView), bIsDefaultView);
VERIFY( pViewVk->GetDesc().ViewType == ViewDesc.ViewType, "Incorrect view type" );
- if( bIsDefaultView )
+ if (bIsDefaultView)
*ppView = pViewVk;
else
pViewVk->QueryInterface(IID_TextureView, reinterpret_cast<IObject**>(ppView) );
+
+
+ if ((UpdatedViewDesc.Flags & TEXTURE_VIEW_FLAG_ALLOW_MIP_MAP_GENERATION) != 0 &&
+ m_bCSBasedMipGenerationSupported &&
+ CheckCSBasedMipGenerationSupport(TexFormatToVkFormat(pViewVk->GetDesc().Format)))
+ {
+ auto* pMipLevelViewsRawMem = ALLOCATE(GetRawAllocator(), "Raw memory for mip level views", sizeof(TextureViewVkImpl::MipLevelViewAutoPtrType) * UpdatedViewDesc.NumMipLevels * 2);
+ auto* pMipLevelViews = reinterpret_cast<TextureViewVkImpl::MipLevelViewAutoPtrType*>(pMipLevelViewsRawMem);
+ for (Uint32 MipLevel = 0; MipLevel < UpdatedViewDesc.NumMipLevels; ++MipLevel)
+ {
+ auto CreateMipLevelView = [&](TEXTURE_VIEW_TYPE ViewType, Uint32 MipLevel, TextureViewVkImpl::MipLevelViewAutoPtrType* ppMipLevelView)
+ {
+ TextureViewDesc MipLevelViewDesc = pViewVk->GetDesc();
+ // Always create texture array views
+ std::stringstream name_ss;
+ name_ss << "Internal " << (ViewType == TEXTURE_VIEW_SHADER_RESOURCE ? "SRV" : "UAV")
+ << " of mip level " << MipLevel << " of texture view '" << pViewVk->GetDesc().Name << "'";
+ auto name = name_ss.str();
+ MipLevelViewDesc.Name = name.c_str();
+ MipLevelViewDesc.TextureDim = RESOURCE_DIM_TEX_2D_ARRAY;
+ MipLevelViewDesc.ViewType = ViewType;
+ MipLevelViewDesc.MostDetailedMip += MipLevel;
+ MipLevelViewDesc.NumMipLevels = 1;
+
+ if (ViewType == TEXTURE_VIEW_UNORDERED_ACCESS)
+ {
+ if (MipLevelViewDesc.Format == TEX_FORMAT_RGBA8_UNORM_SRGB)
+ MipLevelViewDesc.Format = TEX_FORMAT_RGBA8_UNORM;
+ }
+
+ VulkanUtilities::ImageViewWrapper ImgView = CreateImageView(MipLevelViewDesc);
+ // Attach to parent view
+ auto pMipLevelViewVk = NEW_RC_OBJ(TexViewAllocator, "TextureViewVkImpl instance", TextureViewVkImpl, pViewVk)
+ (GetDevice(), MipLevelViewDesc, this, std::move(ImgView), bIsDefaultView);
+ new (ppMipLevelView) TextureViewVkImpl::MipLevelViewAutoPtrType(pMipLevelViewVk, STDDeleter<TextureViewVkImpl, FixedBlockMemoryAllocator>(TexViewAllocator));
+ };
+
+ if ((MipLevel % 4) == 0)
+ {
+ // Mip levles are generated 4 at a time, so we only need SRV for every 4-th level
+ CreateMipLevelView(TEXTURE_VIEW_SHADER_RESOURCE, MipLevel, &pMipLevelViews[MipLevel * 2]);
+ }
+ else
+ {
+ new (&pMipLevelViews[MipLevel * 2]) TextureViewVkImpl::MipLevelViewAutoPtrType{};
+ }
+ CreateMipLevelView(TEXTURE_VIEW_UNORDERED_ACCESS, MipLevel, &pMipLevelViews[MipLevel * 2 + 1]);
+ }
+ pViewVk->AssignMipLevelViews(pMipLevelViews);
+ }
}
catch( const std::runtime_error & )
{
@@ -638,11 +650,11 @@ VulkanUtilities::ImageViewWrapper TextureVkImpl::CreateImageView(TextureViewDesc
else
{
ImageViewCI.viewType = VK_IMAGE_VIEW_TYPE_3D;
- Uint32 MipDepth = std::max(m_Desc.Depth >> ViewDesc.MostDetailedMip, 1U);
+ Uint32 MipDepth = std::max(Uint32{m_Desc.Depth} >> Uint32{ViewDesc.MostDetailedMip}, 1U);
if (ViewDesc.FirstDepthSlice != 0 || ViewDesc.NumDepthSlices != MipDepth)
{
- LOG_ERROR("3D texture view '", (ViewDesc.Name ? ViewDesc.Name : ""), "' (most detailed mip: ", ViewDesc.MostDetailedMip,
- "; mip levels: ", ViewDesc.NumMipLevels, "; first slice: ", ViewDesc.FirstDepthSlice,
+ LOG_ERROR("3D texture view '", (ViewDesc.Name ? ViewDesc.Name : ""), "' (most detailed mip: ", Uint32{ViewDesc.MostDetailedMip},
+ "; mip levels: ", Uint32{ViewDesc.NumMipLevels}, "; first slice: ", ViewDesc.FirstDepthSlice,
"; num depth slices: ", ViewDesc.NumDepthSlices, ") of texture '", m_Desc.Name, "' does not references"
" all depth slices (", MipDepth, ") in the mip level. 3D texture views in Vulkan must address all depth slices." );
ViewDesc.FirstDepthSlice = 0;
@@ -663,7 +675,7 @@ VulkanUtilities::ImageViewWrapper TextureVkImpl::CreateImageView(TextureViewDesc
}
TEXTURE_FORMAT CorrectedViewFormat = ViewDesc.Format;
- if(m_Desc.BindFlags & BIND_DEPTH_STENCIL)
+ if (m_Desc.BindFlags & BIND_DEPTH_STENCIL)
CorrectedViewFormat = GetDefaultTextureViewFormat(CorrectedViewFormat, TEXTURE_VIEW_DEPTH_STENCIL, m_Desc.BindFlags);
ImageViewCI.format = TexFormatToVkFormat(CorrectedViewFormat);
ImageViewCI.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
@@ -736,6 +748,22 @@ VulkanUtilities::ImageViewWrapper TextureVkImpl::CreateImageView(TextureViewDesc
return LogicalDevice.CreateImageView(ImageViewCI, ViewName.c_str());
}
+bool TextureVkImpl::CheckCSBasedMipGenerationSupport(VkFormat vkFmt)const
+{
+ VERIFY_EXPR(m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS);
+ if (m_Desc.Type == RESOURCE_DIM_TEX_2D || m_Desc.Type == RESOURCE_DIM_TEX_2D_ARRAY)
+ {
+ const auto& PhysicalDevice = m_pDevice->GetPhysicalDevice();
+ auto FmtProperties = PhysicalDevice.GetPhysicalDeviceFormatProperties(vkFmt);
+ if ((FmtProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) != 0)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void TextureVkImpl::SetLayout(VkImageLayout Layout)
{
SetState(VkImageLayoutToResourceState(Layout));
diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp
index d9766c52..2a5b010e 100644
--- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp
+++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp
@@ -191,4 +191,11 @@ namespace VulkanUtilities
}
return InvalidMemoryTypeIndex;
}
+
+ VkFormatProperties VulkanPhysicalDevice::GetPhysicalDeviceFormatProperties(VkFormat imageFormat)const
+ {
+ VkFormatProperties formatProperties;
+ vkGetPhysicalDeviceFormatProperties(m_VkDevice, imageFormat, &formatProperties);
+ return formatProperties;
+ }
}