diff --git a/src/Ryujinx.Graphics.Vulkan/BarrierBatch.cs b/src/Ryujinx.Graphics.Vulkan/BarrierBatch.cs index e744dc0b4..a8bb2bde5 100644 --- a/src/Ryujinx.Graphics.Vulkan/BarrierBatch.cs +++ b/src/Ryujinx.Graphics.Vulkan/BarrierBatch.cs @@ -46,7 +46,14 @@ namespace Ryujinx.Graphics.Vulkan public static (AccessFlags Access, PipelineStageFlags Stages) GetSubpassAccessSuperset(VulkanRenderer gd) { - AccessFlags access = BufferAccess; + AccessFlags access = BufferAccess | + AccessFlags.ShaderReadBit | + AccessFlags.ShaderWriteBit | + AccessFlags.ColorAttachmentReadBit | + AccessFlags.ColorAttachmentWriteBit | + AccessFlags.DepthStencilAttachmentReadBit | + AccessFlags.DepthStencilAttachmentWriteBit; + PipelineStageFlags stages = PipelineStageFlags.AllGraphicsBit; if (gd.TransformFeedbackApi != null) @@ -58,7 +65,7 @@ namespace Ryujinx.Graphics.Vulkan return (access, stages); } - private readonly record struct StageFlags : IEquatable + private readonly record struct StageFlags { public readonly PipelineStageFlags Source; public readonly PipelineStageFlags Dest; diff --git a/src/Ryujinx.Graphics.Vulkan/TextureCopy.cs b/src/Ryujinx.Graphics.Vulkan/TextureCopy.cs index 45cddd772..fce3726a8 100644 --- a/src/Ryujinx.Graphics.Vulkan/TextureCopy.cs +++ b/src/Ryujinx.Graphics.Vulkan/TextureCopy.cs @@ -15,6 +15,8 @@ namespace Ryujinx.Graphics.Vulkan Image dstImage, TextureCreateInfo srcInfo, TextureCreateInfo dstInfo, + TextureCreateInfo srcStorageInfo, + TextureCreateInfo dstStorageInfo, Extents2D srcRegion, Extents2D dstRegion, int srcLayer, @@ -40,6 +42,13 @@ namespace Ryujinx.Graphics.Vulkan return (xy1, xy2); } + static (Offset3D, Offset3D) ClampOffsetsToMip(Offset3D xy1, Offset3D xy2, int mipW, int mipH) + { + return ( + new Offset3D(Math.Min(xy1.X, mipW), Math.Min(xy1.Y, mipH), xy1.Z), + new Offset3D(Math.Min(xy2.X, mipW), Math.Min(xy2.Y, mipH), xy2.Z)); + } + if (srcAspectFlags == 0) { srcAspectFlags = srcInfo.Format.ConvertAspectFlags(); @@ -80,6 +89,14 @@ namespace Ryujinx.Graphics.Vulkan (srcOffsets.Element0, srcOffsets.Element1) = ExtentsToOffset3D(srcRegion, srcInfo.Width, srcInfo.Height, level); (dstOffsets.Element0, dstOffsets.Element1) = ExtentsToOffset3D(dstRegion, dstInfo.Width, dstInfo.Height, level); + int srcMipW = Math.Max(1, srcStorageInfo.Width >> (int)copySrcLevel); + int srcMipH = Math.Max(1, srcStorageInfo.Height >> (int)copySrcLevel); + int dstMipW = Math.Max(1, dstStorageInfo.Width >> (int)copyDstLevel); + int dstMipH = Math.Max(1, dstStorageInfo.Height >> (int)copyDstLevel); + + (srcOffsets.Element0, srcOffsets.Element1) = ClampOffsetsToMip(srcOffsets.Element0, srcOffsets.Element1, srcMipW, srcMipH); + (dstOffsets.Element0, dstOffsets.Element1) = ClampOffsetsToMip(dstOffsets.Element0, dstOffsets.Element1, dstMipW, dstMipH); + var region = new ImageBlit { SrcSubresource = srcSl, @@ -121,6 +138,8 @@ namespace Ryujinx.Graphics.Vulkan Image dstImage, TextureCreateInfo srcInfo, TextureCreateInfo dstInfo, + TextureCreateInfo srcStorageInfo, + TextureCreateInfo dstStorageInfo, int srcViewLayer, int dstViewLayer, int srcViewLevel, @@ -151,6 +170,8 @@ namespace Ryujinx.Graphics.Vulkan dstImage, srcInfo, dstInfo, + srcStorageInfo, + dstStorageInfo, srcViewLayer, dstViewLayer, srcViewLevel, @@ -186,6 +207,8 @@ namespace Ryujinx.Graphics.Vulkan Image dstImage, TextureCreateInfo srcInfo, TextureCreateInfo dstInfo, + TextureCreateInfo srcStorageInfo, + TextureCreateInfo dstStorageInfo, int srcViewLayer, int dstViewLayer, int srcViewLevel, @@ -314,6 +337,14 @@ namespace Ryujinx.Graphics.Vulkan int copyWidth = sizeInBlocks ? BitUtils.DivRoundUp(width, blockWidth) : width; int copyHeight = sizeInBlocks ? BitUtils.DivRoundUp(height, blockHeight) : height; + int srcMipW = Math.Max(1, srcStorageInfo.Width >> (srcViewLevel + srcLevel + level)); + int srcMipH = Math.Max(1, srcStorageInfo.Height >> (srcViewLevel + srcLevel + level)); + int dstMipW = Math.Max(1, dstStorageInfo.Width >> (dstViewLevel + dstLevel + level)); + int dstMipH = Math.Max(1, dstStorageInfo.Height >> (dstViewLevel + dstLevel + level)); + + copyWidth = Math.Min(copyWidth, Math.Min(srcMipW, dstMipW)); + copyHeight = Math.Min(copyHeight, Math.Min(srcMipH, dstMipH)); + var extent = new Extent3D((uint)copyWidth, (uint)copyHeight, (uint)srcDepth); if (srcInfo.Samples > 1 && srcInfo.Samples != dstInfo.Samples) diff --git a/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs b/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs index aa30399d6..7c04336d3 100644 --- a/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs +++ b/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs @@ -67,6 +67,8 @@ namespace Ryujinx.Graphics.Vulkan public VkFormat VkFormat { get; } + public ImageUsageFlags UsageFlags { get; } + public unsafe TextureStorage( VulkanRenderer gd, Device device, @@ -93,7 +95,8 @@ namespace Ryujinx.Graphics.Vulkan var sampleCountFlags = ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)info.Samples); - var usage = GetImageUsage(info.Format, info.Target, gd.Capabilities); + ImageUsageFlags usage = GetImageUsage(info.Format, info.Target, gd.Capabilities, isMsImageStorageSupported); + UsageFlags = usage; var flags = ImageCreateFlags.CreateMutableFormatBit | ImageCreateFlags.CreateExtendedUsageBit; @@ -159,7 +162,7 @@ namespace Ryujinx.Graphics.Vulkan _imageAuto = new Auto(new DisposableImage(_gd.Api, device, _image)); - InitialTransition(ImageLayout.Preinitialized, ImageLayout.General); + InitialTransition(ImageLayout.Undefined, ImageLayout.General); } _slices = new TextureSliceInfo[levels * _depthOrLayers]; @@ -307,7 +310,7 @@ namespace Ryujinx.Graphics.Vulkan } } - public static ImageUsageFlags GetImageUsage(Format format, Target target, in HardwareCapabilities capabilities) + public static ImageUsageFlags GetImageUsage(Format format, Target target, in HardwareCapabilities capabilities, bool isMsImageStorageSupported) { var usage = DefaultUsageFlags; @@ -320,8 +323,6 @@ namespace Ryujinx.Graphics.Vulkan usage |= ImageUsageFlags.ColorAttachmentBit; } - bool isMsImageStorageSupported = capabilities.SupportsShaderStorageImageMultisample; - if (format.IsImageCompatible() && (isMsImageStorageSupported || !target.IsMultisample())) { usage |= ImageUsageFlags.StorageBit; diff --git a/src/Ryujinx.Graphics.Vulkan/TextureView.cs b/src/Ryujinx.Graphics.Vulkan/TextureView.cs index 924b3babf..d210fc3d0 100644 --- a/src/Ryujinx.Graphics.Vulkan/TextureView.cs +++ b/src/Ryujinx.Graphics.Vulkan/TextureView.cs @@ -64,7 +64,8 @@ namespace Ryujinx.Graphics.Vulkan bool isMsImageStorageSupported = gd.Capabilities.SupportsShaderStorageImageMultisample || !info.Target.IsMultisample(); var format = _gd.FormatCapabilities.ConvertToVkFormat(info.Format, isMsImageStorageSupported); - var usage = TextureStorage.GetImageUsage(info.Format, info.Target, gd.Capabilities); + var usage = TextureStorage.GetImageUsage(info.Format, info.Target, gd.Capabilities, isMsImageStorageSupported) & storage.UsageFlags; + var levels = (uint)info.Levels; var layers = (uint)info.GetLayers(); @@ -130,6 +131,8 @@ namespace Ryujinx.Graphics.Vulkan shaderUsage |= ImageUsageFlags.StorageBit; } + shaderUsage &= storage.UsageFlags; + _imageView = CreateImageView(componentMapping, subresourceRange, type, shaderUsage); // Framebuffer attachments and storage images requires a identity component mapping. @@ -254,6 +257,8 @@ namespace Ryujinx.Graphics.Vulkan dstImage, src.Info, dst.Info, + src.Storage.Info, + dst.Storage.Info, src.FirstLayer, dst.FirstLayer, src.FirstLevel, @@ -307,6 +312,8 @@ namespace Ryujinx.Graphics.Vulkan dstImage, src.Info, dst.Info, + src.Storage.Info, + dst.Storage.Info, src.FirstLayer, dst.FirstLayer, src.FirstLevel, @@ -382,6 +389,8 @@ namespace Ryujinx.Graphics.Vulkan dst.GetImage().Get(cbs).Value, src.Info, dst.Info, + src.Storage.Info, + dst.Storage.Info, src.FirstLayer, dst.FirstLayer, src.FirstLevel, @@ -407,6 +416,8 @@ namespace Ryujinx.Graphics.Vulkan dst.GetImage().Get(cbs).Value, src.Info, dst.Info, + src.Storage.Info, + dst.Storage.Info, srcRegion, dstRegion, src.FirstLayer, @@ -460,6 +471,8 @@ namespace Ryujinx.Graphics.Vulkan dstImage.Get(cbs).Value, src.Info, dst.Info, + src.Storage.Info, + dst.Storage.Info, srcRegion, dstRegion, src.FirstLayer, diff --git a/src/Ryujinx.Graphics.Vulkan/VertexBufferState.cs b/src/Ryujinx.Graphics.Vulkan/VertexBufferState.cs index f4d512f92..c28fe5cd5 100644 --- a/src/Ryujinx.Graphics.Vulkan/VertexBufferState.cs +++ b/src/Ryujinx.Graphics.Vulkan/VertexBufferState.cs @@ -67,9 +67,7 @@ namespace Ryujinx.Graphics.Vulkan int stride = (_stride + (alignment - 1)) & -alignment; int newSize = (_size / _stride) * stride; - var buffer = autoBuffer.Get(cbs, 0, newSize).Value; - - updater.BindVertexBuffer(cbs, binding, buffer, 0, (ulong)newSize, (ulong)stride); + updater.BindVertexBuffer(cbs, binding, autoBuffer, 0, newSize, (ulong)stride); _buffer = autoBuffer; @@ -92,11 +90,7 @@ namespace Ryujinx.Graphics.Vulkan if (autoBuffer != null) { - int offset = _offset; - bool mirrorable = _size <= VertexBufferMaxMirrorable; - var buffer = mirrorable ? autoBuffer.GetMirrorable(cbs, ref offset, _size, out _).Value : autoBuffer.Get(cbs, offset, _size).Value; - - updater.BindVertexBuffer(cbs, binding, buffer, (ulong)offset, (ulong)_size, (ulong)_stride); + updater.BindVertexBuffer(cbs, binding, autoBuffer, _offset, _size, (ulong)_stride); } } diff --git a/src/Ryujinx.Graphics.Vulkan/VertexBufferUpdater.cs b/src/Ryujinx.Graphics.Vulkan/VertexBufferUpdater.cs index 94269dd76..8927d2264 100644 --- a/src/Ryujinx.Graphics.Vulkan/VertexBufferUpdater.cs +++ b/src/Ryujinx.Graphics.Vulkan/VertexBufferUpdater.cs @@ -15,6 +15,10 @@ namespace Ryujinx.Graphics.Vulkan private readonly NativeArray _sizes; private readonly NativeArray _strides; + private readonly Auto[] _bufferAutos; + private readonly int[] _bufferOffsetsForGet; + private readonly int[] _bufferSizesForGet; + public VertexBufferUpdater(VulkanRenderer gd) { _gd = gd; @@ -23,9 +27,13 @@ namespace Ryujinx.Graphics.Vulkan _offsets = new NativeArray(Constants.MaxVertexBuffers); _sizes = new NativeArray(Constants.MaxVertexBuffers); _strides = new NativeArray(Constants.MaxVertexBuffers); + + _bufferAutos = new Auto[Constants.MaxVertexBuffers]; + _bufferOffsetsForGet = new int[Constants.MaxVertexBuffers]; + _bufferSizesForGet = new int[Constants.MaxVertexBuffers]; } - public void BindVertexBuffer(CommandBufferScoped cbs, uint binding, VkBuffer buffer, ulong offset, ulong size, ulong stride) + public void BindVertexBuffer(CommandBufferScoped cbs, uint binding, Auto autoBuffer, int offset, int size, ulong stride) { if (_count == 0) { @@ -39,9 +47,11 @@ namespace Ryujinx.Graphics.Vulkan int index = (int)_count; - _buffers[index] = buffer; - _offsets[index] = offset; - _sizes[index] = size; + _bufferAutos[index] = autoBuffer; + _bufferOffsetsForGet[index] = offset; + _bufferSizesForGet[index] = size; + _offsets[index] = (ulong)offset; + _sizes[index] = (ulong)size; _strides[index] = stride; _count++; @@ -51,6 +61,12 @@ namespace Ryujinx.Graphics.Vulkan { if (_count != 0) { + for (int i = 0; i < _count; i++) + { + _buffers[i] = _bufferAutos[i].Get(cbs, _bufferOffsetsForGet[i], _bufferSizesForGet[i]).Value; + _bufferAutos[i] = null; + } + if (_gd.Capabilities.SupportsExtendedDynamicState) { _gd.ExtendedDynamicStateApi.CmdBindVertexBuffers2( diff --git a/src/Ryujinx.Graphics.Vulkan/Window.cs b/src/Ryujinx.Graphics.Vulkan/Window.cs index a449ccd3b..eca7580e4 100644 --- a/src/Ryujinx.Graphics.Vulkan/Window.cs +++ b/src/Ryujinx.Graphics.Vulkan/Window.cs @@ -351,7 +351,7 @@ namespace Ryujinx.Graphics.Vulkan { if (availableFormats == null || availableFormats.Length == 0) { - return new SurfaceFormatKHR(VkFormat.B8G8R8A8Unorm, (ColorSpaceKHR)0); + return new SurfaceFormatKHR(VkFormat.B8G8R8A8Unorm, 0); } if (availableFormats.Length == 1 && availableFormats[0].Format == VkFormat.Undefined) @@ -559,14 +559,14 @@ namespace Ryujinx.Graphics.Vulkan { if (_effect != null) { - var emptySems = Array.Empty(); - var waitStagesCO = new PipelineStageFlags[] { PipelineStageFlags.ColorAttachmentOutputBit }; + _gd.FlushAllCommands(); + var emptySems = Array.Empty(); + var waitStagesCO = new[] { PipelineStageFlags.ColorAttachmentOutputBit }; _gd.CommandBufferPool.Return( cbs, emptySems, waitStagesCO, emptySems); - _gd.FlushAllCommands(); cbs.GetFence().Wait(); cbs = _gd.CommandBufferPool.Rent(); } @@ -642,11 +642,13 @@ namespace Ryujinx.Graphics.Vulkan ImageLayout.PresentSrcKhr); } - var waitSems = new Silk.NET.Vulkan.Semaphore[] { _imageAvailableSemaphores[semaphoreIndex] }; - var waitStages = new PipelineStageFlags[] { PipelineStageFlags.ColorAttachmentOutputBit }; // Important on Android - var signalSems = new Silk.NET.Vulkan.Semaphore[] { _renderFinishedSemaphores[semaphoreIndex] }; + var waitSems = new[] { _imageAvailableSemaphores[semaphoreIndex] }; + var waitStages = new[] { PipelineStageFlags.ColorAttachmentOutputBit }; // Important on Android + var signalSems = new[] { _renderFinishedSemaphores[semaphoreIndex] }; _gd.CommandBufferPool.Return(cbs, waitSems, waitStages, signalSems); + _gd.FlushAllCommands(); + PresentOne(_gd, _renderFinishedSemaphores[semaphoreIndex], _swapchain, nextImage); swapBuffersCallback?.Invoke(); @@ -654,11 +656,11 @@ namespace Ryujinx.Graphics.Vulkan private static unsafe void PresentOne( VulkanRenderer gd, - Silk.NET.Vulkan.Semaphore signal, + Semaphore signal, SwapchainKHR swapchain, uint imageIndex) { - Silk.NET.Vulkan.Semaphore* pWait = stackalloc Silk.NET.Vulkan.Semaphore[1]; + Semaphore* pWait = stackalloc Semaphore[1]; SwapchainKHR* pSwap = stackalloc SwapchainKHR[1]; uint* pImageIndex = stackalloc uint[1];