aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanImage.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Ava/Ui/Backend/Vulkan/VulkanImage.cs')
-rw-r--r--Ryujinx.Ava/Ui/Backend/Vulkan/VulkanImage.cs167
1 files changed, 167 insertions, 0 deletions
diff --git a/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanImage.cs b/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanImage.cs
new file mode 100644
index 00000000..343ba760
--- /dev/null
+++ b/Ryujinx.Ava/Ui/Backend/Vulkan/VulkanImage.cs
@@ -0,0 +1,167 @@
+using System;
+using Avalonia;
+using Silk.NET.Vulkan;
+
+namespace Ryujinx.Ava.Ui.Vulkan
+{
+ internal class VulkanImage : IDisposable
+ {
+ private readonly VulkanDevice _device;
+ private readonly VulkanPhysicalDevice _physicalDevice;
+ private readonly VulkanCommandBufferPool _commandBufferPool;
+ private ImageLayout _currentLayout;
+ private AccessFlags _currentAccessFlags;
+ private ImageUsageFlags _imageUsageFlags { get; }
+ private ImageView? _imageView { get; set; }
+ private DeviceMemory _imageMemory { get; set; }
+
+ internal Image? InternalHandle { get; private set; }
+ internal Format Format { get; }
+ internal ImageAspectFlags AspectFlags { get; private set; }
+
+ public ulong Handle => InternalHandle?.Handle ?? 0;
+ public ulong ViewHandle => _imageView?.Handle ?? 0;
+ public uint UsageFlags => (uint)_imageUsageFlags;
+ public ulong MemoryHandle => _imageMemory.Handle;
+ public uint MipLevels { get; private set; }
+ public PixelSize Size { get; }
+ public ulong MemorySize { get; private set; }
+ public uint CurrentLayout => (uint)_currentLayout;
+
+ public VulkanImage(
+ VulkanDevice device,
+ VulkanPhysicalDevice physicalDevice,
+ VulkanCommandBufferPool commandBufferPool,
+ uint format,
+ PixelSize size,
+ uint mipLevels = 0)
+ {
+ _device = device;
+ _physicalDevice = physicalDevice;
+ _commandBufferPool = commandBufferPool;
+ Format = (Format)format;
+ Size = size;
+ MipLevels = mipLevels;
+ _imageUsageFlags =
+ ImageUsageFlags.ImageUsageColorAttachmentBit | ImageUsageFlags.ImageUsageTransferDstBit |
+ ImageUsageFlags.ImageUsageTransferSrcBit | ImageUsageFlags.ImageUsageSampledBit;
+
+ Initialize();
+ }
+
+ public unsafe void Initialize()
+ {
+ if (!InternalHandle.HasValue)
+ {
+ MipLevels = MipLevels != 0 ? MipLevels : (uint)Math.Floor(Math.Log(Math.Max(Size.Width, Size.Height), 2));
+
+ var imageCreateInfo = new ImageCreateInfo
+ {
+ SType = StructureType.ImageCreateInfo,
+ ImageType = ImageType.ImageType2D,
+ Format = Format,
+ Extent = new Extent3D((uint?)Size.Width, (uint?)Size.Height, 1),
+ MipLevels = MipLevels,
+ ArrayLayers = 1,
+ Samples = SampleCountFlags.SampleCount1Bit,
+ Tiling = Tiling,
+ Usage = _imageUsageFlags,
+ SharingMode = SharingMode.Exclusive,
+ InitialLayout = ImageLayout.Undefined,
+ Flags = ImageCreateFlags.ImageCreateMutableFormatBit
+ };
+
+ _device.Api.CreateImage(_device.InternalHandle, imageCreateInfo, null, out var image).ThrowOnError();
+ InternalHandle = image;
+
+ _device.Api.GetImageMemoryRequirements(_device.InternalHandle, InternalHandle.Value,
+ out var memoryRequirements);
+
+ var memoryAllocateInfo = new MemoryAllocateInfo
+ {
+ SType = StructureType.MemoryAllocateInfo,
+ AllocationSize = memoryRequirements.Size,
+ MemoryTypeIndex = (uint)VulkanMemoryHelper.FindSuitableMemoryTypeIndex(
+ _physicalDevice,
+ memoryRequirements.MemoryTypeBits, MemoryPropertyFlags.MemoryPropertyDeviceLocalBit)
+ };
+
+ _device.Api.AllocateMemory(_device.InternalHandle, memoryAllocateInfo, null,
+ out var imageMemory);
+
+ _imageMemory = imageMemory;
+
+ _device.Api.BindImageMemory(_device.InternalHandle, InternalHandle.Value, _imageMemory, 0);
+
+ MemorySize = memoryRequirements.Size;
+
+ var componentMapping = new ComponentMapping(
+ ComponentSwizzle.Identity,
+ ComponentSwizzle.Identity,
+ ComponentSwizzle.Identity,
+ ComponentSwizzle.Identity);
+
+ AspectFlags = ImageAspectFlags.ImageAspectColorBit;
+
+ var subresourceRange = new ImageSubresourceRange(AspectFlags, 0, MipLevels, 0, 1);
+
+ var imageViewCreateInfo = new ImageViewCreateInfo
+ {
+ SType = StructureType.ImageViewCreateInfo,
+ Image = InternalHandle.Value,
+ ViewType = ImageViewType.ImageViewType2D,
+ Format = Format,
+ Components = componentMapping,
+ SubresourceRange = subresourceRange
+ };
+
+ _device.Api
+ .CreateImageView(_device.InternalHandle, imageViewCreateInfo, null, out var imageView)
+ .ThrowOnError();
+
+ _imageView = imageView;
+
+ _currentLayout = ImageLayout.Undefined;
+
+ TransitionLayout(ImageLayout.ColorAttachmentOptimal, AccessFlags.AccessNoneKhr);
+ }
+ }
+
+ public ImageTiling Tiling => ImageTiling.Optimal;
+
+ internal void TransitionLayout(ImageLayout destinationLayout, AccessFlags destinationAccessFlags)
+ {
+ var commandBuffer = _commandBufferPool.CreateCommandBuffer();
+ commandBuffer.BeginRecording();
+
+ VulkanMemoryHelper.TransitionLayout(_device, commandBuffer.InternalHandle, InternalHandle.Value,
+ _currentLayout,
+ _currentAccessFlags,
+ destinationLayout, destinationAccessFlags,
+ MipLevels);
+
+ commandBuffer.EndRecording();
+
+ commandBuffer.Submit();
+
+ _currentLayout = destinationLayout;
+ _currentAccessFlags = destinationAccessFlags;
+ }
+
+ public void TransitionLayout(uint destinationLayout, uint destinationAccessFlags)
+ {
+ TransitionLayout((ImageLayout)destinationLayout, (AccessFlags)destinationAccessFlags);
+ }
+
+ public unsafe void Dispose()
+ {
+ _device.Api.DestroyImageView(_device.InternalHandle, _imageView.Value, null);
+ _device.Api.DestroyImage(_device.InternalHandle, InternalHandle.Value, null);
+ _device.Api.FreeMemory(_device.InternalHandle, _imageMemory, null);
+
+ _imageView = default;
+ InternalHandle = default;
+ _imageMemory = default;
+ }
+ }
+}