3838namespace Diligent
3939{
4040
41+ namespace
42+ {
43+
4144VkImageCreateInfo TextureDescToVkImageCreateInfo (const TextureDesc& Desc, const RenderDeviceVkImpl* pRenderDeviceVk) noexcept
4245{
4346 const bool IsMemoryless = (Desc.MiscFlags & MISC_TEXTURE_FLAG_MEMORYLESS) != 0 ;
@@ -143,6 +146,59 @@ VkImageCreateInfo TextureDescToVkImageCreateInfo(const TextureDesc& Desc, const
143146 return ImageCI;
144147}
145148
149+ VkImageLayout VkImageLayoutFromUsage (VkImageUsageFlags Usage)
150+ {
151+ if ((Usage & (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) != 0 )
152+ return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
153+
154+ if ((Usage & VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT) != 0 )
155+ return VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT;
156+
157+ if ((Usage & VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR) != 0 )
158+ return VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
159+
160+ if ((Usage & VK_IMAGE_USAGE_STORAGE_BIT) != 0 )
161+ return VK_IMAGE_LAYOUT_GENERAL;
162+
163+ if ((Usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0 )
164+ return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
165+
166+ if ((Usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0 )
167+ return VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL_KHR;
168+
169+ VERIFY ((Usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) != 0 , " TRANSFER_SRC_BIT should always be set" );
170+ return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
171+ }
172+
173+ bool CheckHostImageCopySupport (const VulkanUtilities::VulkanLogicalDevice& LogicalDevice,
174+ const VulkanUtilities::VulkanPhysicalDevice& PhysicalDevice,
175+ const VkImageCreateInfo& ImageCI)
176+ {
177+ if (!LogicalDevice.GetEnabledExtFeatures ().HostImageCopy .hostImageCopy )
178+ return false ;
179+
180+ VkFormatProperties3 vkFormatProps3{};
181+ VkFormatProperties VkFormatProps = PhysicalDevice.GetPhysicalDeviceFormatProperties (ImageCI.format , &vkFormatProps3);
182+
183+ if ((vkFormatProps3.optimalTilingFeatures & VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT_EXT) == 0 )
184+ return false ;
185+
186+ const VulkanUtilities::VulkanPhysicalDevice::ExtensionProperties& ExtProps = PhysicalDevice.GetExtProperties ();
187+ const VkPhysicalDeviceHostImageCopyPropertiesEXT& HostImageCopyProps = ExtProps.HostImageCopy ;
188+
189+ const VkImageLayout DstLayout = VkImageLayoutFromUsage (ImageCI.usage );
190+
191+ auto LayoutSupported = [](const VkImageLayout* pLayouts, uint32_t LayoutCount, VkImageLayout Layout) {
192+ return std::find (pLayouts, pLayouts + LayoutCount, Layout) != pLayouts + LayoutCount;
193+ };
194+
195+ if (!LayoutSupported (HostImageCopyProps.pCopyDstLayouts , HostImageCopyProps.copyDstLayoutCount , DstLayout))
196+ return false ;
197+
198+ return true ;
199+ }
200+
201+ } // namespace
146202
147203TextureVkImpl::TextureVkImpl (IReferenceCounters* pRefCounters,
148204 FixedBlockMemoryAllocator& TexViewObjAllocator,
@@ -179,6 +235,11 @@ TextureVkImpl::TextureVkImpl(IReferenceCounters* pRefCounters,
179235
180236 VkImageCreateInfo ImageCI = TextureDescToVkImageCreateInfo (m_Desc, pRenderDeviceVk);
181237
238+ const bool InitContent = pInitData != nullptr && pInitData->pSubResources != nullptr && pInitData->NumSubresources > 0 ;
239+ const bool UseHostImageCopy = InitContent && CheckHostImageCopySupport (LogicalDevice, pRenderDeviceVk->GetPhysicalDevice (), ImageCI);
240+ if (UseHostImageCopy)
241+ ImageCI.usage |= VK_IMAGE_USAGE_HOST_TRANSFER_BIT;
242+
182243 const std::vector<uint32_t > QueueFamilyIndices = PlatformMisc::CountOneBits (m_Desc.ImmediateContextMask ) > 1 ?
183244 GetDevice ()->ConvertCmdQueueIdsToQueueFamilies (m_Desc.ImmediateContextMask ) :
184245 std::vector<uint32_t >{};
@@ -223,10 +284,23 @@ TextureVkImpl::TextureVkImpl(IReferenceCounters* pRefCounters,
223284 VkResult err = LogicalDevice.BindImageMemory (m_VulkanImage, Memory, AlignedOffset);
224285 CHECK_VK_ERROR_AND_THROW (err, " Failed to bind image memory" );
225286
226- if (pInitData != nullptr && pInitData->pSubResources != nullptr && pInitData->NumSubresources > 0 )
227- InitializeTextureContent (*pInitData, FmtAttribs, ImageCI);
287+ if (InitContent)
288+ {
289+ bool InitializedOnHost = false ;
290+ if (UseHostImageCopy)
291+ {
292+ InitializedOnHost = InitializeContentOnHost (*pInitData, FmtAttribs, ImageCI);
293+ }
294+
295+ if (!InitializedOnHost)
296+ {
297+ InitializeContentOnDevice (*pInitData, FmtAttribs, ImageCI);
298+ }
299+ }
228300 else
301+ {
229302 SetState (RESOURCE_STATE_UNDEFINED);
303+ }
230304 }
231305 }
232306 else if (m_Desc.Usage == USAGE_STAGING)
@@ -241,9 +315,100 @@ TextureVkImpl::TextureVkImpl(IReferenceCounters* pRefCounters,
241315 VERIFY_EXPR (IsInKnownState ());
242316}
243317
244- void TextureVkImpl::InitializeTextureContent (const TextureData& InitData,
245- const TextureFormatAttribs& FmtAttribs,
246- const VkImageCreateInfo& ImageCI) noexcept (false )
318+ bool TextureVkImpl::InitializeContentOnHost (const TextureData& InitData,
319+ const TextureFormatAttribs& FmtAttribs,
320+ const VkImageCreateInfo& ImageCI) noexcept (false )
321+ {
322+ const VulkanUtilities::VulkanLogicalDevice& LogicalDevice = GetDevice ()->GetLogicalDevice ();
323+ VERIFY_EXPR (LogicalDevice.GetEnabledExtFeatures ().HostImageCopy .hostImageCopy );
324+
325+ Uint32 ExpectedNumSubresources = ImageCI.mipLevels * ImageCI.arrayLayers ;
326+ if (InitData.NumSubresources != ExpectedNumSubresources)
327+ LOG_ERROR_AND_THROW (" Incorrect number of subresources in init data. " , ExpectedNumSubresources, " expected, while " , InitData.NumSubresources , " provided" );
328+
329+ VERIFY (FmtAttribs.ComponentType != COMPONENT_TYPE_DEPTH_STENCIL, " Initializing depth-stencil texture is currently not supported." );
330+ const VkImageAspectFlags aspectMask = ComponentTypeToVkAspectMask (FmtAttribs.ComponentType );
331+
332+ std::vector<VkMemoryToImageCopyEXT> vkCopyRegions (InitData.NumSubresources );
333+
334+ Uint32 subres = 0 ;
335+ for (Uint32 layer = 0 ; layer < ImageCI.arrayLayers ; ++layer)
336+ {
337+ for (Uint32 mip = 0 ; mip < ImageCI.mipLevels ; ++mip)
338+ {
339+ const TextureSubResData& SubResData = InitData.pSubResources [subres];
340+ VkMemoryToImageCopyEXT& vkCopyInfo = vkCopyRegions[subres];
341+ MipLevelProperties MipInfo = GetMipLevelProperties (m_Desc, mip);
342+
343+ vkCopyInfo.sType = VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY_EXT;
344+ vkCopyInfo.pNext = nullptr ;
345+ vkCopyInfo.pHostPointer = SubResData.pData ;
346+
347+ const Uint32 PixelSize = FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED ?
348+ Uint32{FmtAttribs.ComponentSize } :
349+ Uint32{FmtAttribs.ComponentSize } * Uint32{FmtAttribs.NumComponents };
350+ if ((SubResData.Stride % PixelSize) != 0 )
351+ {
352+ LOG_DVP_WARNING_MESSAGE (" Unable to initialize texture '" , m_Desc.Name , " ' on host: subresource " , subres, " has stride " , SubResData.Stride ,
353+ " that is not multiple of pixel size " , PixelSize, " . The content will be initialized on device." );
354+ return false ;
355+ }
356+ vkCopyInfo.memoryRowLength = FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED ?
357+ static_cast <uint32_t >(SubResData.Stride * FmtAttribs.BlockWidth / FmtAttribs.ComponentSize ) :
358+ static_cast <uint32_t >(SubResData.Stride / PixelSize);
359+
360+ if ((SubResData.DepthStride % SubResData.Stride ) != 0 )
361+ {
362+ LOG_DVP_WARNING_MESSAGE (" Unable to initialize texture '" , m_Desc.Name , " ' on host: subresource " , subres, " has depth stride " , SubResData.DepthStride ,
363+ " that is not multiple of row stride " , SubResData.Stride , " . The content will be initialized on device." );
364+ return false ;
365+ }
366+ vkCopyInfo.memoryImageHeight = static_cast <uint32_t >(SubResData.DepthStride * FmtAttribs.BlockHeight / SubResData.Stride );
367+
368+ vkCopyInfo.imageSubresource .aspectMask = aspectMask;
369+ vkCopyInfo.imageSubresource .mipLevel = mip;
370+ vkCopyInfo.imageSubresource .baseArrayLayer = layer;
371+ vkCopyInfo.imageSubresource .layerCount = 1 ;
372+
373+ vkCopyInfo.imageOffset = {0 , 0 , 0 };
374+ vkCopyInfo.imageExtent = {MipInfo.LogicalWidth , MipInfo.LogicalHeight , MipInfo.Depth };
375+
376+ ++subres;
377+ }
378+ }
379+
380+ VkHostImageLayoutTransitionInfoEXT vkLayoutTransitionInfo{};
381+ vkLayoutTransitionInfo.sType = VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO_EXT;
382+ vkLayoutTransitionInfo.image = m_VulkanImage;
383+ vkLayoutTransitionInfo.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
384+ vkLayoutTransitionInfo.newLayout = VkImageLayoutFromUsage (ImageCI.usage );
385+
386+ vkLayoutTransitionInfo.subresourceRange .aspectMask = aspectMask;
387+ vkLayoutTransitionInfo.subresourceRange .baseArrayLayer = 0 ;
388+ vkLayoutTransitionInfo.subresourceRange .layerCount = VK_REMAINING_ARRAY_LAYERS;
389+ vkLayoutTransitionInfo.subresourceRange .baseMipLevel = 0 ;
390+ vkLayoutTransitionInfo.subresourceRange .levelCount = VK_REMAINING_MIP_LEVELS;
391+ LogicalDevice.HostTransitionImageLayout (vkLayoutTransitionInfo);
392+
393+ VkCopyMemoryToImageInfoEXT vkCopyInfo{};
394+ vkCopyInfo.sType = VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO_EXT;
395+ vkCopyInfo.pNext = nullptr ;
396+ vkCopyInfo.flags = 0 ;
397+ vkCopyInfo.dstImage = m_VulkanImage;
398+ vkCopyInfo.dstImageLayout = vkLayoutTransitionInfo.newLayout ;
399+ vkCopyInfo.regionCount = static_cast <uint32_t >(vkCopyRegions.size ());
400+ vkCopyInfo.pRegions = vkCopyRegions.data ();
401+
402+ LogicalDevice.CopyMemoryToImage (vkCopyInfo);
403+
404+ SetState (VkImageLayoutToResourceState (vkCopyInfo.dstImageLayout ));
405+
406+ return true ;
407+ }
408+
409+ void TextureVkImpl::InitializeContentOnDevice (const TextureData& InitData,
410+ const TextureFormatAttribs& FmtAttribs,
411+ const VkImageCreateInfo& ImageCI) noexcept (false )
247412{
248413 const VulkanUtilities::VulkanLogicalDevice& LogicalDevice = GetDevice ()->GetLogicalDevice ();
249414
@@ -258,18 +423,8 @@ void TextureVkImpl::InitializeTextureContent(const TextureData& InitDat
258423 VulkanUtilities::VulkanCommandBuffer CmdBuffer;
259424 GetDevice ()->AllocateTransientCmdPool (CmdQueueInd, CmdPool, CmdBuffer, " Transient command pool to copy staging data to a device buffer" );
260425
261- VkImageAspectFlags aspectMask = 0 ;
262- if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH)
263- aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
264- else if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL)
265- {
266- UNSUPPORTED (" Initializing depth-stencil texture is not currently supported" );
267- // Only single aspect bit must be specified when copying texture data
268-
269- aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
270- }
271- else
272- aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
426+ VERIFY (FmtAttribs.ComponentType != COMPONENT_TYPE_DEPTH_STENCIL, " Initializing depth-stencil texture is currently not supported." );
427+ const VkImageAspectFlags aspectMask = ComponentTypeToVkAspectMask (FmtAttribs.ComponentType );
273428
274429 // For either clear or copy command, dst layout must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
275430 VkImageSubresourceRange SubresRange;
0 commit comments