private void CopyToImpl(CommandBufferScoped cbs, TextureView dst, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter) { var src = this; var srcFormat = GetCompatibleGalFormat(src.Info.Format); var dstFormat = GetCompatibleGalFormat(dst.Info.Format); bool srcUsesStorageFormat = src.VkFormat == src.Storage.VkFormat; bool dstUsesStorageFormat = dst.VkFormat == dst.Storage.VkFormat; int layers = Math.Min(dst.Info.GetDepthOrLayers(), src.Info.GetDepthOrLayers()); int levels = Math.Min(dst.Info.Levels, src.Info.Levels); if (srcUsesStorageFormat && dstUsesStorageFormat) { if ((srcRegion.X1 | dstRegion.X1) == 0 && (srcRegion.Y1 | dstRegion.Y1) == 0 && srcRegion.X2 == src.Width && srcRegion.Y2 == src.Height && dstRegion.X2 == dst.Width && dstRegion.Y2 == dst.Height && src.Width == dst.Width && src.Height == dst.Height && src.VkFormat == dst.VkFormat) { TextureCopy.Copy( _gd.Api, cbs.CommandBuffer, src.GetImage().Get(cbs).Value, dst.GetImage().Get(cbs).Value, src.Info, dst.Info, src.FirstLayer, dst.FirstLayer, src.FirstLevel, dst.FirstLevel, 0, 0, 0, 0, layers, levels); return; } else if (_gd.FormatCapabilities.FormatSupports(srcFormat, FormatFeatureFlags.FormatFeatureBlitSrcBit) && _gd.FormatCapabilities.FormatSupports(dstFormat, FormatFeatureFlags.FormatFeatureBlitDstBit)) { TextureCopy.Blit( _gd.Api, cbs.CommandBuffer, src.GetImage().Get(cbs).Value, dst.GetImage().Get(cbs).Value, src.Info, dst.Info, srcRegion, dstRegion, src.FirstLayer, dst.FirstLayer, src.FirstLevel, dst.FirstLevel, layers, levels, linearFilter); return; } else if (srcFormat == GAL.Format.D32FloatS8Uint && srcFormat == dstFormat && SupportsBlitFromD32FS8ToD32FAndS8()) { var d32StorageInfo = TextureStorage.NewCreateInfoWith(src.Info, GAL.Format.D32Float, 4); var s8StorageInfo = TextureStorage.NewCreateInfoWith(dst.Info, GAL.Format.S8Uint, 1); using var d32Storage = _gd.CreateTextureStorage(d32StorageInfo, dst.Storage.ScaleFactor); using var s8Storage = _gd.CreateTextureStorage(s8StorageInfo, dst.Storage.ScaleFactor); void BlitAndCopy(ref TextureCreateInfo info, TextureStorage storage, ImageAspectFlags aspectFlags) { TextureCopy.Blit( _gd.Api, cbs.CommandBuffer, src.GetImage().Get(cbs).Value, storage.GetImage().Get(cbs).Value, src.Info, info, srcRegion, dstRegion, src.FirstLayer, 0, src.FirstLevel, 0, layers, levels, false, aspectFlags, aspectFlags); TextureCopy.Copy( _gd.Api, cbs.CommandBuffer, storage.GetImage().Get(cbs).Value, dst.GetImage().Get(cbs).Value, info, dst.Info, 0, dst.FirstLayer, 0, dst.FirstLevel, 0, 0, 0, 0, layers, levels); } BlitAndCopy(ref d32StorageInfo, d32Storage, ImageAspectFlags.ImageAspectDepthBit); BlitAndCopy(ref s8StorageInfo, s8Storage, ImageAspectFlags.ImageAspectStencilBit); return; } } if (VulkanConfiguration.UseSlowSafeBlitOnAmd && _gd.Vendor == Vendor.Amd && src.Info.Target == Target.Texture2D && dst.Info.Target == Target.Texture2D && !dst.Info.Format.IsDepthOrStencil()) { _gd.HelperShader.Blit( _gd, src, dst.GetIdentityImageView(), dst.Width, dst.Height, dst.VkFormat, srcRegion, dstRegion, linearFilter); return; } Auto <DisposableImage> srcImage; Auto <DisposableImage> dstImage; if (dst.Info.Format.IsDepthOrStencil()) { srcImage = src.Storage.CreateAliasedColorForDepthStorageUnsafe(srcFormat).GetImage(); dstImage = dst.Storage.CreateAliasedColorForDepthStorageUnsafe(dstFormat).GetImage(); } else { srcImage = src.Storage.CreateAliasedStorageUnsafe(srcFormat).GetImage(); dstImage = dst.Storage.CreateAliasedStorageUnsafe(dstFormat).GetImage(); } TextureCopy.Blit( _gd.Api, cbs.CommandBuffer, srcImage.Get(cbs).Value, dstImage.Get(cbs).Value, src.Info, dst.Info, srcRegion, dstRegion, src.FirstLevel, dst.FirstLevel, src.FirstLayer, dst.FirstLayer, layers, levels, linearFilter, ImageAspectFlags.ImageAspectColorBit, ImageAspectFlags.ImageAspectColorBit); }
private static void CopyMSToNonMS( VulkanRenderer gd, CommandBufferScoped cbs, TextureView src, TextureView dst, Image srcImage, Image dstImage, int srcLayer, int dstLayer, int srcLevel, int dstLevel, int layers, int levels) { bool differentFormats = src.Info.Format != dst.Info.Format; var target = src.Info.Target switch { Target.Texture2D => Target.Texture2DMultisample, Target.Texture2DArray => Target.Texture2DMultisampleArray, Target.Texture2DMultisampleArray => Target.Texture2DArray, _ => Target.Texture2D }; var intermmediateTarget = differentFormats ? dst.Info.Target : target; using var intermmediate = CreateIntermmediateTexture(gd, src, ref dst._info, intermmediateTarget, layers, levels); var intermmediateImage = intermmediate.GetImage().Get(cbs).Value; if (differentFormats) { // If the formats are different, the resolve would perform format conversion. // So we need yet another intermmediate texture and do a copy to reinterpret the // data into the correct (destination) format, without doing any sort of conversion. using var intermmediate2 = CreateIntermmediateTexture(gd, src, ref src._info, target, layers, levels); var intermmediate2Image = intermmediate2.GetImage().Get(cbs).Value; TextureCopy.Copy( gd.Api, cbs.CommandBuffer, srcImage, intermmediate2Image, src.Info, intermmediate2.Info, src.FirstLayer, 0, src.FirstLevel, 0, srcLayer, 0, srcLevel, 0, layers, levels); TextureCopy.Copy( gd.Api, cbs.CommandBuffer, intermmediate2Image, intermmediateImage, intermmediate2.Info, intermmediate.Info, 0, 0, 0, 0, 0, 0, 0, 0, layers, levels); } else { TextureCopy.Copy( gd.Api, cbs.CommandBuffer, srcImage, intermmediateImage, src.Info, intermmediate.Info, src.FirstLayer, 0, src.FirstLevel, 0, srcLayer, 0, srcLevel, 0, layers, levels); } var srcRegion = new Extents2D(0, 0, src.Width, src.Height); var dstRegion = new Extents2D(0, 0, dst.Width, dst.Height); TextureCopy.Blit( gd.Api, cbs.CommandBuffer, intermmediateImage, dstImage, intermmediate.Info, dst.Info, srcRegion, dstRegion, 0, dst.FirstLevel + dstLevel, 0, dst.FirstLayer + dstLayer, layers, levels, true, ImageAspectFlags.ImageAspectColorBit, ImageAspectFlags.ImageAspectColorBit); }
private static void BlitDepthStencilWithBuffer( VulkanRenderer gd, CommandBufferScoped cbs, TextureView src, TextureView dst, Extents2D srcRegion, Extents2D dstRegion) { int drBaseX = Math.Min(dstRegion.X1, dstRegion.X2); int drBaseY = Math.Min(dstRegion.Y1, dstRegion.Y2); int drWidth = Math.Abs(dstRegion.X2 - dstRegion.X1); int drHeight = Math.Abs(dstRegion.Y2 - dstRegion.Y1); var drOriginZero = new Extents2D( dstRegion.X1 - drBaseX, dstRegion.Y1 - drBaseY, dstRegion.X2 - drBaseX, dstRegion.Y2 - drBaseY); var d32SrcStorageInfo = TextureStorage.NewCreateInfoWith(ref src._info, GAL.Format.D32Float, 4); var d32DstStorageInfo = TextureStorage.NewCreateInfoWith(ref dst._info, GAL.Format.D32Float, 4, drWidth, drHeight); var s8SrcStorageInfo = TextureStorage.NewCreateInfoWith(ref src._info, GAL.Format.S8Uint, 1); var s8DstStorageInfo = TextureStorage.NewCreateInfoWith(ref dst._info, GAL.Format.S8Uint, 1, drWidth, drHeight); using var d32SrcStorage = gd.CreateTextureStorage(d32SrcStorageInfo, src.Storage.ScaleFactor); using var d32DstStorage = gd.CreateTextureStorage(d32DstStorageInfo, dst.Storage.ScaleFactor); using var s8SrcStorage = gd.CreateTextureStorage(s8SrcStorageInfo, src.Storage.ScaleFactor); using var s8DstStorage = gd.CreateTextureStorage(s8DstStorageInfo, dst.Storage.ScaleFactor); void SlowBlit(TextureStorage srcTemp, TextureStorage dstTemp, ImageAspectFlags aspectFlags) { int levels = Math.Min(src.Info.Levels, dst.Info.Levels); int srcSize = 0; int dstSize = 0; for (int l = 0; l < levels; l++) { srcSize += srcTemp.Info.GetMipSize2D(l); dstSize += dstTemp.Info.GetMipSize2D(l); } using var srcTempBuffer = gd.BufferManager.Create(gd, srcSize, deviceLocal: true); using var dstTempBuffer = gd.BufferManager.Create(gd, dstSize, deviceLocal: true); src.Storage.CopyFromOrToBuffer( cbs.CommandBuffer, srcTempBuffer.GetBuffer().Get(cbs, 0, srcSize).Value, src.GetImage().Get(cbs).Value, srcSize, to: true, 0, 0, src.FirstLayer, src.FirstLevel, 1, levels, true, aspectFlags, false); BufferHolder.InsertBufferBarrier( gd, cbs.CommandBuffer, srcTempBuffer.GetBuffer().Get(cbs, 0, srcSize).Value, AccessFlags.AccessTransferWriteBit, AccessFlags.AccessTransferReadBit, PipelineStageFlags.PipelineStageTransferBit, PipelineStageFlags.PipelineStageTransferBit, 0, srcSize); srcTemp.CopyFromOrToBuffer( cbs.CommandBuffer, srcTempBuffer.GetBuffer().Get(cbs, 0, srcSize).Value, srcTemp.GetImage().Get(cbs).Value, srcSize, to: false, 0, 0, 0, 0, 1, levels, true, aspectFlags, false); InsertImageBarrier( gd.Api, cbs.CommandBuffer, srcTemp.GetImage().Get(cbs).Value, AccessFlags.AccessTransferWriteBit, AccessFlags.AccessTransferReadBit, PipelineStageFlags.PipelineStageTransferBit, PipelineStageFlags.PipelineStageTransferBit, aspectFlags, 0, 0, 1, levels); TextureCopy.Blit( gd.Api, cbs.CommandBuffer, srcTemp.GetImage().Get(cbs).Value, dstTemp.GetImage().Get(cbs).Value, srcTemp.Info, dstTemp.Info, srcRegion, drOriginZero, 0, 0, 0, 0, 1, levels, false, aspectFlags, aspectFlags); InsertImageBarrier( gd.Api, cbs.CommandBuffer, dstTemp.GetImage().Get(cbs).Value, AccessFlags.AccessTransferWriteBit, AccessFlags.AccessTransferReadBit, PipelineStageFlags.PipelineStageTransferBit, PipelineStageFlags.PipelineStageTransferBit, aspectFlags, 0, 0, 1, levels); dstTemp.CopyFromOrToBuffer( cbs.CommandBuffer, dstTempBuffer.GetBuffer().Get(cbs, 0, dstSize).Value, dstTemp.GetImage().Get(cbs).Value, dstSize, to: true, 0, 0, 0, 0, 1, levels, true, aspectFlags, false); BufferHolder.InsertBufferBarrier( gd, cbs.CommandBuffer, dstTempBuffer.GetBuffer().Get(cbs, 0, dstSize).Value, AccessFlags.AccessTransferWriteBit, AccessFlags.AccessTransferReadBit, PipelineStageFlags.PipelineStageTransferBit, PipelineStageFlags.PipelineStageTransferBit, 0, dstSize); dst.Storage.CopyFromOrToBuffer( cbs.CommandBuffer, dstTempBuffer.GetBuffer().Get(cbs, 0, dstSize).Value, dst.GetImage().Get(cbs).Value, dstSize, to: false, drBaseX, drBaseY, dst.FirstLayer, dst.FirstLevel, 1, levels, true, aspectFlags, false); } SlowBlit(d32SrcStorage, d32DstStorage, ImageAspectFlags.ImageAspectDepthBit); SlowBlit(s8SrcStorage, s8DstStorage, ImageAspectFlags.ImageAspectStencilBit); }
private void CopyToImpl(CommandBufferScoped cbs, TextureView dst, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter) { var src = this; var srcFormat = GetCompatibleGalFormat(src.Info.Format); var dstFormat = GetCompatibleGalFormat(dst.Info.Format); bool srcUsesStorageFormat = src.VkFormat == src.Storage.VkFormat; bool dstUsesStorageFormat = dst.VkFormat == dst.Storage.VkFormat; if (srcUsesStorageFormat && dstUsesStorageFormat) { if ((srcRegion.X1 | dstRegion.X1) == 0 && (srcRegion.Y1 | dstRegion.Y1) == 0 && srcRegion.X2 == src.Width && srcRegion.Y2 == src.Height && dstRegion.X2 == dst.Width && dstRegion.Y2 == dst.Height && src.Width == dst.Width && src.Height == dst.Height && src.VkFormat == dst.VkFormat) { TextureCopy.Copy( _gd.Api, cbs.CommandBuffer, src.GetImage().Get(cbs).Value, dst.GetImage().Get(cbs).Value, src.Info, dst.Info, src.FirstLayer, dst.FirstLayer, src.FirstLevel, dst.FirstLevel, 0, 0, 0, 0, 1, 1); return; } else if (_gd.FormatCapabilities.FormatSupports(srcFormat, FormatFeatureFlags.FormatFeatureBlitSrcBit) && _gd.FormatCapabilities.FormatSupports(dstFormat, FormatFeatureFlags.FormatFeatureBlitDstBit)) { TextureCopy.Blit( _gd.Api, cbs.CommandBuffer, src.GetImage().Get(cbs).Value, dst.GetImage().Get(cbs).Value, src.Info, dst.Info, srcRegion, dstRegion, src.FirstLayer, dst.FirstLayer, src.FirstLevel, dst.FirstLevel, linearFilter); return; } } Auto <DisposableImage> srcImage; Auto <DisposableImage> dstImage; if (dst.Info.Format.IsDepthOrStencil()) { srcImage = src.Storage.CreateAliasedColorForDepthStorageUnsafe(srcFormat).GetImage(); dstImage = dst.Storage.CreateAliasedColorForDepthStorageUnsafe(dstFormat).GetImage(); } else { srcImage = src.Storage.CreateAliasedStorageUnsafe(srcFormat).GetImage(); dstImage = dst.Storage.CreateAliasedStorageUnsafe(dstFormat).GetImage(); } TextureCopy.Blit( _gd.Api, cbs.CommandBuffer, srcImage.Get(cbs).Value, dstImage.Get(cbs).Value, src.Info, dst.Info, srcRegion, dstRegion, src.FirstLevel, dst.FirstLevel, src.FirstLayer, dst.FirstLayer, linearFilter, forceColorAspect: true); }