public unsafe void Mipmaps() { PhysicalDevice physicalDevice = _renderer.Params.PhysicalDevice; Vk vk = _renderer.Vk; vk.GetPhysicalDeviceFormatProperties(physicalDevice, _format, out FormatProperties formatProperties); if (!formatProperties.OptimalTilingFeatures.HasFlag(FormatFeatureFlags.FormatFeatureSampledImageFilterLinearBit)) // bitting not supported. { return; } CommandBuffer commandBuffer = BeginImageCommandBuffer(); uint mipWidth = Size.X; uint mipHeight = Size.Y; ImageMemoryBarrier barrier = new() { SType = StructureType.ImageMemoryBarrier, Image = _image, SrcQueueFamilyIndex = Vk.QueueFamilyIgnored, DstQueueFamilyIndex = Vk.QueueFamilyIgnored, SubresourceRange = new ImageSubresourceRange() { AspectMask = ImageAspectFlags.ImageAspectColorBit, BaseArrayLayer = 0, LayerCount = 1, BaseMipLevel = 0, LevelCount = 1 } }; for (uint i = 1; i < _mipLevelCount; i++) { barrier.SubresourceRange.BaseMipLevel = i - 1; barrier.OldLayout = ImageLayout.TransferDstOptimal; barrier.NewLayout = ImageLayout.TransferSrcOptimal; barrier.SrcAccessMask = AccessFlags.AccessTransferWriteBit; barrier.DstAccessMask = AccessFlags.AccessTransferReadBit; vk.CmdPipelineBarrier(commandBuffer, PipelineStageFlags.PipelineStageTransferBit, PipelineStageFlags.PipelineStageTransferBit, 0, 0, null, 0, null, 1, barrier); ImageBlit blit = new() { SrcOffsets = new ImageBlit.SrcOffsetsBuffer() { Element0 = new Offset3D() { X = 0, Y = 0, Z = 0, }, Element1 = new Offset3D() { X = (int)mipWidth, Y = (int)mipHeight, Z = 1 } }, SrcSubresource = new ImageSubresourceLayers() { AspectMask = ImageAspectFlags.ImageAspectColorBit, MipLevel = i - 1, BaseArrayLayer = 0, LayerCount = 1 }, DstOffsets = new ImageBlit.DstOffsetsBuffer() { Element0 = new Offset3D() { X = 0, Y = 0, Z = 0 }, Element1 = new Offset3D() { X = (int)((mipWidth > 1) ? mipWidth / 2 : 1), Y = (int)((mipHeight > 1) ? mipHeight / 2 : 1), Z = 1 } }, DstSubresource = new ImageSubresourceLayers() { AspectMask = ImageAspectFlags.ImageAspectColorBit, MipLevel = i, BaseArrayLayer = 0, LayerCount = 1 } }; vk.CmdBlitImage(commandBuffer, _image, ImageLayout.TransferSrcOptimal, _image, ImageLayout.TransferDstOptimal, 1, blit, HasFlag(ImageFlags.Nearest) ? Filter.Nearest : Filter.Linear); barrier.OldLayout = ImageLayout.TransferSrcOptimal; barrier.NewLayout = ImageLayout.ShaderReadOnlyOptimal; barrier.SrcAccessMask = AccessFlags.AccessTransferReadBit; barrier.DstAccessMask = AccessFlags.AccessShaderReadBit; vk.CmdPipelineBarrier(commandBuffer, PipelineStageFlags.PipelineStageTransferBit, PipelineStageFlags.PipelineStageFragmentShaderBit, 0, 0, null, 0, null, 1, barrier); mipWidth /= 2; mipHeight /= 2; } barrier.SubresourceRange.BaseMipLevel = _mipLevelCount - 1; barrier.OldLayout = ImageLayout.TransferDstOptimal; barrier.NewLayout = ImageLayout.ShaderReadOnlyOptimal; barrier.SrcAccessMask = AccessFlags.AccessTransferWriteBit; barrier.DstAccessMask = AccessFlags.AccessShaderReadBit; vk.CmdPipelineBarrier(commandBuffer, PipelineStageFlags.PipelineStageTransferBit, PipelineStageFlags.PipelineStageFragmentShaderBit, 0, 0, null, 0, null, 1, barrier); EndImageCommandBuffer(commandBuffer); }