diff options
Diffstat (limited to 'Ryujinx.Graphics.Vulkan/ImageWindow.cs')
-rw-r--r-- | Ryujinx.Graphics.Vulkan/ImageWindow.cs | 198 |
1 files changed, 133 insertions, 65 deletions
diff --git a/Ryujinx.Graphics.Vulkan/ImageWindow.cs b/Ryujinx.Graphics.Vulkan/ImageWindow.cs index 5dd23155..69302fdf 100644 --- a/Ryujinx.Graphics.Vulkan/ImageWindow.cs +++ b/Ryujinx.Graphics.Vulkan/ImageWindow.cs @@ -7,7 +7,9 @@ namespace Ryujinx.Graphics.Vulkan { class ImageWindow : WindowBase, IWindow, IDisposable { - private const int ImageCount = 5; + internal const VkFormat Format = VkFormat.R8G8B8A8Unorm; + + private const int ImageCount = 3; private const int SurfaceWidth = 1280; private const int SurfaceHeight = 720; @@ -18,52 +20,49 @@ namespace Ryujinx.Graphics.Vulkan private Auto<DisposableImage>[] _images; private Auto<DisposableImageView>[] _imageViews; private Auto<MemoryAllocation>[] _imageAllocationAuto; + private ImageState[] _states; + private PresentImageInfo[] _presentedImages; + private FenceHolder[] _fences; + private ulong[] _imageSizes; private ulong[] _imageOffsets; - private Semaphore _imageAvailableSemaphore; - private Semaphore _renderFinishedSemaphore; - private int _width = SurfaceWidth; private int _height = SurfaceHeight; - private VkFormat _format; private bool _recreateImages; private int _nextImage; - internal new bool ScreenCaptureRequested { get; set; } - public unsafe ImageWindow(VulkanRenderer gd, PhysicalDevice physicalDevice, Device device) { _gd = gd; _physicalDevice = physicalDevice; _device = device; - _format = VkFormat.R8G8B8A8Unorm; - _images = new Auto<DisposableImage>[ImageCount]; _imageAllocationAuto = new Auto<MemoryAllocation>[ImageCount]; _imageSizes = new ulong[ImageCount]; _imageOffsets = new ulong[ImageCount]; + _states = new ImageState[ImageCount]; + _presentedImages = new PresentImageInfo[ImageCount]; CreateImages(); - - var semaphoreCreateInfo = new SemaphoreCreateInfo() - { - SType = StructureType.SemaphoreCreateInfo - }; - - gd.Api.CreateSemaphore(device, semaphoreCreateInfo, null, out _imageAvailableSemaphore).ThrowOnError(); - gd.Api.CreateSemaphore(device, semaphoreCreateInfo, null, out _renderFinishedSemaphore).ThrowOnError(); } private void RecreateImages() { for (int i = 0; i < ImageCount; i++) { - _imageViews[i]?.Dispose(); - _imageAllocationAuto[i]?.Dispose(); - _images[i]?.Dispose(); + lock (_states[i]) + { + _states[i].IsValid = false; + _fences[i]?.Wait(); + _fences[i]?.Put(); + _imageViews[i]?.Dispose(); + _imageAllocationAuto[i]?.Dispose(); + _images[i]?.Dispose(); + } } + _presentedImages = null; CreateImages(); } @@ -71,34 +70,35 @@ namespace Ryujinx.Graphics.Vulkan private unsafe void CreateImages() { _imageViews = new Auto<DisposableImageView>[ImageCount]; + _fences = new FenceHolder[ImageCount]; + _presentedImages = new PresentImageInfo[ImageCount]; + _nextImage = 0; var cbs = _gd.CommandBufferPool.Rent(); - for (int i = 0; i < _images.Length; i++) + + var imageCreateInfo = new ImageCreateInfo { - var imageCreateInfo = new ImageCreateInfo - { - SType = StructureType.ImageCreateInfo, - ImageType = ImageType.ImageType2D, - Format = _format, - Extent = - new Extent3D((uint?)_width, - (uint?)_height, 1), - MipLevels = 1, - ArrayLayers = 1, - Samples = SampleCountFlags.SampleCount1Bit, - Tiling = ImageTiling.Optimal, - Usage = ImageUsageFlags.ImageUsageColorAttachmentBit | ImageUsageFlags.ImageUsageTransferSrcBit | ImageUsageFlags.ImageUsageTransferDstBit, - SharingMode = SharingMode.Exclusive, - InitialLayout = ImageLayout.Undefined, - Flags = ImageCreateFlags.ImageCreateMutableFormatBit - }; + SType = StructureType.ImageCreateInfo, + ImageType = ImageType.ImageType2D, + Format = Format, + Extent = new Extent3D((uint?)_width, (uint?)_height, 1), + MipLevels = 1, + ArrayLayers = 1, + Samples = SampleCountFlags.SampleCount1Bit, + Tiling = ImageTiling.Optimal, + Usage = ImageUsageFlags.ImageUsageColorAttachmentBit | ImageUsageFlags.ImageUsageTransferSrcBit | ImageUsageFlags.ImageUsageTransferDstBit, + SharingMode = SharingMode.Exclusive, + InitialLayout = ImageLayout.Undefined, + Flags = ImageCreateFlags.ImageCreateMutableFormatBit + }; + for (int i = 0; i < _images.Length; i++) + { _gd.Api.CreateImage(_device, imageCreateInfo, null, out var image).ThrowOnError(); _images[i] = new Auto<DisposableImage>(new DisposableImage(_gd.Api, _device, image)); _gd.Api.GetImageMemoryRequirements(_device, image, out var memoryRequirements); - var allocation = _gd.MemoryAllocator.AllocateDeviceMemory(_physicalDevice, memoryRequirements, MemoryPropertyFlags.MemoryPropertyDeviceLocalBit); _imageSizes[i] = allocation.Size; @@ -108,7 +108,7 @@ namespace Ryujinx.Graphics.Vulkan _gd.Api.BindImageMemory(_device, image, allocation.Memory, allocation.Offset); - _imageViews[i] = CreateImageView(image, _format); + _imageViews[i] = CreateImageView(image, Format); Transition( cbs.CommandBuffer, @@ -116,7 +116,9 @@ namespace Ryujinx.Graphics.Vulkan 0, 0, ImageLayout.Undefined, - ImageLayout.ColorAttachmentOptimal); + ImageLayout.TransferSrcOptimal); + + _states[i] = new ImageState(); } _gd.CommandBufferPool.Return(cbs); @@ -165,7 +167,7 @@ namespace Ryujinx.Graphics.Vulkan image.GetUnsafe().Value, 0, AccessFlags.AccessTransferWriteBit, - ImageLayout.ColorAttachmentOptimal, + ImageLayout.TransferSrcOptimal, ImageLayout.General); var view = (TextureView)texture; @@ -232,7 +234,7 @@ namespace Ryujinx.Graphics.Vulkan _imageViews[_nextImage], _width, _height, - _format, + Format, new Extents2D(srcX0, srcY0, srcX1, srcY1), new Extents2D(dstX0, dstY1, dstX1, dstY0), true, @@ -244,7 +246,7 @@ namespace Ryujinx.Graphics.Vulkan 0, 0, ImageLayout.General, - ImageLayout.ColorAttachmentOptimal); + ImageLayout.TransferSrcOptimal); _gd.CommandBufferPool.Return( cbs, @@ -252,12 +254,30 @@ namespace Ryujinx.Graphics.Vulkan stackalloc[] { PipelineStageFlags.PipelineStageColorAttachmentOutputBit }, null); - var memory = _imageAllocationAuto[_nextImage].GetUnsafe().Memory; - var presentInfo = new PresentImageInfo(image.GetUnsafe().Value, memory, _imageSizes[_nextImage], _imageOffsets[_nextImage], _renderFinishedSemaphore, _imageAvailableSemaphore); + _fences[_nextImage]?.Put(); + _fences[_nextImage] = cbs.GetFence(); + cbs.GetFence().Get(); + + PresentImageInfo info = _presentedImages[_nextImage]; + + if (info == null) + { + info = new PresentImageInfo( + image, + _imageAllocationAuto[_nextImage], + _device, + _physicalDevice, + _imageSizes[_nextImage], + _imageOffsets[_nextImage], + new Extent2D((uint)_width, (uint)_height), + _states[_nextImage]); + + _presentedImages[_nextImage] = info; + } - swapBuffersCallback(presentInfo); + swapBuffersCallback(info); - _nextImage %= ImageCount; + _nextImage = (_nextImage + 1) % ImageCount; } private unsafe void Transition( @@ -320,11 +340,11 @@ namespace Ryujinx.Graphics.Vulkan { unsafe { - _gd.Api.DestroySemaphore(_device, _renderFinishedSemaphore, null); - _gd.Api.DestroySemaphore(_device, _imageAvailableSemaphore, null); - for (int i = 0; i < ImageCount; i++) { + _states[i].IsValid = false; + _fences[i]?.Wait(); + _fences[i]?.Put(); _imageViews[i]?.Dispose(); _imageAllocationAuto[i]?.Dispose(); _images[i]?.Dispose(); @@ -337,25 +357,73 @@ namespace Ryujinx.Graphics.Vulkan { Dispose(true); } + + public override void ChangeVSyncMode(bool vsyncEnabled) { } + } + + public class ImageState + { + private bool _isValid = true; + + public bool IsValid + { + get => _isValid; + internal set + { + _isValid = value; + + StateChanged?.Invoke(this, _isValid); + } + } + + public event EventHandler<bool> StateChanged; } public class PresentImageInfo { - public Image Image { get; } - public DeviceMemory Memory { get; } - public ulong MemorySize { get; set; } - public ulong MemoryOffset { get; set; } - public Semaphore ReadySemaphore { get; } - public Semaphore AvailableSemaphore { get; } - - public PresentImageInfo(Image image, DeviceMemory memory, ulong memorySize, ulong memoryOffset, Semaphore readySemaphore, Semaphore availableSemaphore) + private readonly Auto<DisposableImage> _image; + private readonly Auto<MemoryAllocation> _memory; + + public Image Image => _image.GetUnsafe().Value; + + public DeviceMemory Memory => _memory.GetUnsafe().Memory; + + public Device Device { get; } + public PhysicalDevice PhysicalDevice { get; } + public ulong MemorySize { get; } + public ulong MemoryOffset { get; } + public Extent2D Extent { get; } + public ImageState State { get; internal set; } + internal PresentImageInfo( + Auto<DisposableImage> image, + Auto<MemoryAllocation> memory, + Device device, + PhysicalDevice physicalDevice, + ulong memorySize, + ulong memoryOffset, + Extent2D extent2D, + ImageState state) + { + _image = image; + _memory = memory; + Device = device; + PhysicalDevice = physicalDevice; + MemorySize = memorySize; + MemoryOffset = memoryOffset; + Extent = extent2D; + State = state; + } + + public void Get() + { + _memory.IncrementReferenceCount(); + _image.IncrementReferenceCount(); + } + + public void Put() { - this.Image = image; - this.Memory = memory; - this.MemorySize = memorySize; - this.MemoryOffset = memoryOffset; - this.ReadySemaphore = readySemaphore; - this.AvailableSemaphore = availableSemaphore; + _memory.DecrementReferenceCount(); + _image.DecrementReferenceCount(); } } }
\ No newline at end of file |