ryujinx/Ryujinx.Graphics.Vulkan/Effects/FxaaPostProcessingEffect.cs
riperiperi 9f1cf6458c
Vulkan: Migrate buffers between memory types to improve GPU performance (#4540)
* Initial implementation of migration between memory heaps

- Missing OOM handling
- Missing `_map` data safety when remapping
  - Copy may not have completed yet (needs some kind of fence)
  - Map may be unmapped before it is done being used. (needs scoped access)
- SSBO accesses are all "writes" - maybe pass info in another way.
- Missing keeping map type when resizing buffers (should this be done?)

* Ensure migrated data is in place before flushing.

* Fix issue where old waitable would be signalled.

- There is a real issue where existing Auto<> references need to be replaced.

* Swap bound Auto<> instances when swapping buffer backing

* Fix conversion buffers

* Don't try move buffers if the host has shared memory.

* Make GPU methods return PinnedSpan with scope

* Storage Hint

* Fix stupidity

* Fix rebase

* Tweak rules

Attempt to sidestep BOTW slowdown

* Remove line

* Migrate only when command buffers flush

* Change backing swap log to debug

* Address some feedback

* Disallow backing swap when the flush lock is held by the current thread

* Make PinnedSpan from ReadOnlySpan explicitly unsafe

* Fix some small issues

- Index buffer swap fixed
- Allocate DeviceLocal buffers using a separate block list to images.

* Remove alternative flags

* Address feedback
2023-03-19 17:56:48 -03:00

127 lines
4.5 KiB
C#

using Ryujinx.Common;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Shader;
using Ryujinx.Graphics.Shader.Translation;
using Silk.NET.Vulkan;
using System;
namespace Ryujinx.Graphics.Vulkan.Effects
{
internal partial class FxaaPostProcessingEffect : IPostProcessingEffect
{
private readonly VulkanRenderer _renderer;
private ISampler _samplerLinear;
private ShaderCollection _shaderProgram;
private PipelineHelperShader _pipeline;
private TextureView _texture;
public FxaaPostProcessingEffect(VulkanRenderer renderer, Device device)
{
_renderer = renderer;
_pipeline = new PipelineHelperShader(renderer, device);
Initialize();
}
public void Dispose()
{
_shaderProgram.Dispose();
_pipeline.Dispose();
_samplerLinear.Dispose();
_texture?.Dispose();
}
private void Initialize()
{
_pipeline.Initialize();
var shader = EmbeddedResources.Read("Ryujinx.Graphics.Vulkan/Effects/Shaders/Fxaa.spv");
var computeBindings = new ShaderBindings(
new[] { 2 },
Array.Empty<int>(),
new[] { 1 },
new[] { 0 });
_samplerLinear = _renderer.CreateSampler(GAL.SamplerCreateInfo.Create(MinFilter.Linear, MagFilter.Linear));
_shaderProgram = _renderer.CreateProgramWithMinimalLayout(new[]
{
new ShaderSource(shader, computeBindings, ShaderStage.Compute, TargetLanguage.Spirv)
});
}
public TextureView Run(TextureView view, CommandBufferScoped cbs, int width, int height)
{
if (_texture == null || _texture.Width != view.Width || _texture.Height != view.Height)
{
_texture?.Dispose();
var info = view.Info;
if (view.Info.Format.IsBgr())
{
info = new TextureCreateInfo(info.Width,
info.Height,
info.Depth,
info.Levels,
info.Samples,
info.BlockWidth,
info.BlockHeight,
info.BytesPerPixel,
info.Format,
info.DepthStencilMode,
info.Target,
info.SwizzleB,
info.SwizzleG,
info.SwizzleR,
info.SwizzleA);
}
_texture = _renderer.CreateTexture(info, view.ScaleFactor) as TextureView;
}
_pipeline.SetCommandBuffer(cbs);
_pipeline.SetProgram(_shaderProgram);
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, view, _samplerLinear);
ReadOnlySpan<float> resolutionBuffer = stackalloc float[] { view.Width, view.Height };
int rangeSize = resolutionBuffer.Length * sizeof(float);
var bufferHandle = _renderer.BufferManager.CreateWithHandle(_renderer, rangeSize);
_renderer.BufferManager.SetData(bufferHandle, 0, resolutionBuffer);
var bufferRanges = new BufferRange(bufferHandle, 0, rangeSize);
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, bufferRanges) });
Span<GAL.Viewport> viewports = stackalloc GAL.Viewport[1];
viewports[0] = new GAL.Viewport(
new Rectangle<float>(0, 0, view.Width, view.Height),
ViewportSwizzle.PositiveX,
ViewportSwizzle.PositiveY,
ViewportSwizzle.PositiveZ,
ViewportSwizzle.PositiveW,
0f,
1f);
Span<Rectangle<int>> scissors = stackalloc Rectangle<int>[1];
var dispatchX = BitUtils.DivRoundUp(view.Width, IPostProcessingEffect.LocalGroupSize);
var dispatchY = BitUtils.DivRoundUp(view.Height, IPostProcessingEffect.LocalGroupSize);
_pipeline.SetScissors(stackalloc[] { new Rectangle<int>(0, 0, view.Width, view.Height) });
_pipeline.SetViewports(viewports, false);
_pipeline.SetImage(0, _texture, GAL.Format.R8G8B8A8Unorm);
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
_renderer.BufferManager.Delete(bufferHandle);
_pipeline.ComputeBarrier();
_pipeline.Finish();
return _texture;
}
}
}