public TextureView( VulkanGraphicsDevice gd, Device device, TextureCreateInfo info, TextureStorage storage, int firstLayer, int firstLevel) { _gd = gd; _device = device; Info = info; Storage = storage; FirstLayer = firstLayer; FirstLevel = firstLevel; gd.Textures.Add(this); var format = _gd.FormatCapabilities.ConvertToVkFormat(info.Format); var levels = (uint)info.Levels; var layers = (uint)info.GetLayers(); VkFormat = format; var type = info.Target.ConvertView(); var swizzleR = info.SwizzleR.Convert(); var swizzleG = info.SwizzleG.Convert(); var swizzleB = info.SwizzleB.Convert(); var swizzleA = info.SwizzleA.Convert(); if (info.Format == GAL.Format.R5G5B5A1Unorm || info.Format == GAL.Format.R5G5B5X1Unorm || info.Format == GAL.Format.R5G6B5Unorm) { var temp = swizzleR; swizzleR = swizzleB; swizzleB = temp; } else if (info.Format == GAL.Format.R4G4B4A4Unorm) { var tempR = swizzleR; var tempG = swizzleG; swizzleR = swizzleA; swizzleG = swizzleB; swizzleB = tempG; swizzleA = tempR; } var componentMapping = new ComponentMapping(swizzleR, swizzleG, swizzleB, swizzleA); var aspectFlags = info.Format.ConvertAspectFlags(info.DepthStencilMode); var aspectFlagsDepth = info.Format.ConvertAspectFlags(DepthStencilMode.Depth); var subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, layers); var subresourceRangeDepth = new ImageSubresourceRange(aspectFlagsDepth, (uint)firstLevel, levels, (uint)firstLayer, layers); unsafe Auto <DisposableImageView> CreateImageView(ComponentMapping cm, ImageSubresourceRange sr, ImageViewType viewType) { var imageCreateInfo = new ImageViewCreateInfo() { SType = StructureType.ImageViewCreateInfo, Image = storage.GetImageForViewCreation(), ViewType = viewType, Format = format, Components = cm, SubresourceRange = sr }; gd.Api.CreateImageView(device, imageCreateInfo, null, out var imageView).ThrowOnError(); return(new Auto <DisposableImageView>(new DisposableImageView(gd.Api, device, imageView), null, storage.GetImage())); } _imageView = CreateImageView(componentMapping, subresourceRange, type); // Framebuffer attachments and storage images requires a identity component mapping. var identityComponentMapping = new ComponentMapping( ComponentSwizzle.R, ComponentSwizzle.G, ComponentSwizzle.B, ComponentSwizzle.A); _imageViewIdentity = CreateImageView(identityComponentMapping, subresourceRangeDepth, type); // Framebuffer attachments also requires 3D textures to be bound as 2D array. if (info.Target == Target.Texture3D) { subresourceRange = new ImageSubresourceRange(aspectFlags, (uint)firstLevel, levels, (uint)firstLayer, (uint)info.Depth); _imageView2dArray = CreateImageView(identityComponentMapping, subresourceRange, ImageViewType.ImageViewType2DArray); } Valid = true; }
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; 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); }
public static unsafe DisposableRenderPass ToRenderPass(this ProgramPipelineState state, VulkanRenderer gd, Device device) { const int MaxAttachments = Constants.MaxRenderTargets + 1; AttachmentDescription[] attachmentDescs = null; var subpass = new SubpassDescription() { PipelineBindPoint = PipelineBindPoint.Graphics }; AttachmentReference *attachmentReferences = stackalloc AttachmentReference[MaxAttachments]; Span <int> attachmentIndices = stackalloc int[MaxAttachments]; Span <Silk.NET.Vulkan.Format> attachmentFormats = stackalloc Silk.NET.Vulkan.Format[MaxAttachments]; int attachmentCount = 0; int colorCount = 0; int maxColorAttachmentIndex = 0; for (int i = 0; i < state.AttachmentEnable.Length; i++) { if (state.AttachmentEnable[i]) { maxColorAttachmentIndex = i; attachmentFormats[attachmentCount] = gd.FormatCapabilities.ConvertToVkFormat(state.AttachmentFormats[i]); attachmentIndices[attachmentCount++] = i; colorCount++; } } if (state.DepthStencilEnable) { attachmentFormats[attachmentCount++] = gd.FormatCapabilities.ConvertToVkFormat(state.DepthStencilFormat); } if (attachmentCount != 0) { attachmentDescs = new AttachmentDescription[attachmentCount]; for (int i = 0; i < attachmentCount; i++) { int bindIndex = attachmentIndices[i]; attachmentDescs[i] = new AttachmentDescription( 0, attachmentFormats[i], TextureStorage.ConvertToSampleCountFlags((uint)state.SamplesCount), AttachmentLoadOp.Load, AttachmentStoreOp.Store, AttachmentLoadOp.Load, AttachmentStoreOp.Store, ImageLayout.General, ImageLayout.General); } int colorAttachmentsCount = colorCount; if (colorAttachmentsCount > MaxAttachments - 1) { colorAttachmentsCount = MaxAttachments - 1; } if (colorAttachmentsCount != 0) { int maxAttachmentIndex = Constants.MaxRenderTargets - 1; subpass.ColorAttachmentCount = (uint)maxAttachmentIndex + 1; subpass.PColorAttachments = &attachmentReferences[0]; // Fill with VK_ATTACHMENT_UNUSED to cover any gaps. for (int i = 0; i <= maxAttachmentIndex; i++) { subpass.PColorAttachments[i] = new AttachmentReference(Vk.AttachmentUnused, ImageLayout.Undefined); } for (int i = 0; i < colorAttachmentsCount; i++) { int bindIndex = attachmentIndices[i]; subpass.PColorAttachments[bindIndex] = new AttachmentReference((uint)i, ImageLayout.General); } } if (state.DepthStencilEnable) { uint dsIndex = (uint)attachmentCount - 1; subpass.PDepthStencilAttachment = &attachmentReferences[MaxAttachments - 1]; *subpass.PDepthStencilAttachment = new AttachmentReference(dsIndex, ImageLayout.General); } } var subpassDependency = new SubpassDependency( 0, 0, PipelineStageFlags.PipelineStageAllGraphicsBit, PipelineStageFlags.PipelineStageAllGraphicsBit, AccessFlags.AccessMemoryReadBit | AccessFlags.AccessMemoryWriteBit, AccessFlags.AccessMemoryReadBit | AccessFlags.AccessMemoryWriteBit, 0); fixed(AttachmentDescription *pAttachmentDescs = attachmentDescs) { var renderPassCreateInfo = new RenderPassCreateInfo() { SType = StructureType.RenderPassCreateInfo, PAttachments = pAttachmentDescs, AttachmentCount = attachmentDescs != null ? (uint)attachmentDescs.Length : 0, PSubpasses = &subpass, SubpassCount = 1, PDependencies = &subpassDependency, DependencyCount = 1 }; gd.Api.CreateRenderPass(device, renderPassCreateInfo, null, out var renderPass).ThrowOnError(); return(new DisposableRenderPass(gd.Api, device, renderPass)); } }