diff options
Diffstat (limited to 'Ryujinx.Graphics.Vulkan/HelperShader.cs')
-rw-r--r-- | Ryujinx.Graphics.Vulkan/HelperShader.cs | 207 |
1 files changed, 162 insertions, 45 deletions
diff --git a/Ryujinx.Graphics.Vulkan/HelperShader.cs b/Ryujinx.Graphics.Vulkan/HelperShader.cs index ce373409..8b20dd1a 100644 --- a/Ryujinx.Graphics.Vulkan/HelperShader.cs +++ b/Ryujinx.Graphics.Vulkan/HelperShader.cs @@ -20,9 +20,10 @@ namespace Ryujinx.Graphics.Vulkan private readonly IProgram _programColorBlitClearAlpha; private readonly IProgram _programColorClear; private readonly IProgram _programStrideChange; - private readonly IProgram _programColorCopyBetweenMsNonMs; private readonly IProgram _programConvertIndexBuffer; private readonly IProgram _programConvertIndirectData; + private readonly IProgram _programColorCopyToNonMs; + private readonly IProgram _programColorDrawToMs; public HelperShader(VulkanRenderer gd, Device device) { @@ -32,13 +33,13 @@ namespace Ryujinx.Graphics.Vulkan _samplerLinear = gd.CreateSampler(GAL.SamplerCreateInfo.Create(MinFilter.Linear, MagFilter.Linear)); _samplerNearest = gd.CreateSampler(GAL.SamplerCreateInfo.Create(MinFilter.Nearest, MagFilter.Nearest)); - var vertexBindings = new ShaderBindings( + var colorBlitVertexBindings = new ShaderBindings( new[] { 1 }, Array.Empty<int>(), Array.Empty<int>(), Array.Empty<int>()); - var fragmentBindings = new ShaderBindings( + var colorBlitFragmentBindings = new ShaderBindings( Array.Empty<int>(), Array.Empty<int>(), new[] { 0 }, @@ -46,17 +47,17 @@ namespace Ryujinx.Graphics.Vulkan _programColorBlit = gd.CreateProgramWithMinimalLayout(new[] { - new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv), - new ShaderSource(ShaderBinaries.ColorBlitFragmentShaderSource, fragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv), + new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, colorBlitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv), + new ShaderSource(ShaderBinaries.ColorBlitFragmentShaderSource, colorBlitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv), }); _programColorBlitClearAlpha = gd.CreateProgramWithMinimalLayout(new[] { - new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv), - new ShaderSource(ShaderBinaries.ColorBlitClearAlphaFragmentShaderSource, fragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv), + new ShaderSource(ShaderBinaries.ColorBlitVertexShaderSource, colorBlitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv), + new ShaderSource(ShaderBinaries.ColorBlitClearAlphaFragmentShaderSource, colorBlitFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv), }); - var fragmentBindings2 = new ShaderBindings( + var colorClearFragmentBindings = new ShaderBindings( Array.Empty<int>(), Array.Empty<int>(), Array.Empty<int>(), @@ -64,8 +65,8 @@ namespace Ryujinx.Graphics.Vulkan _programColorClear = gd.CreateProgramWithMinimalLayout(new[] { - new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv), - new ShaderSource(ShaderBinaries.ColorClearFragmentShaderSource, fragmentBindings2, ShaderStage.Fragment, TargetLanguage.Spirv), + new ShaderSource(ShaderBinaries.ColorClearVertexShaderSource, colorBlitVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv), + new ShaderSource(ShaderBinaries.ColorClearFragmentShaderSource, colorClearFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv), }); var strideChangeBindings = new ShaderBindings( @@ -79,18 +80,33 @@ namespace Ryujinx.Graphics.Vulkan new ShaderSource(ShaderBinaries.ChangeBufferStrideShaderSource, strideChangeBindings, ShaderStage.Compute, TargetLanguage.Spirv), }); - var colorCopyMSBindings = new ShaderBindings( + var colorCopyToNonMsBindings = new ShaderBindings( new[] { 0 }, Array.Empty<int>(), new[] { 0 }, new[] { 0 }); - _programColorCopyBetweenMsNonMs = gd.CreateProgramWithMinimalLayout(new[] + _programColorCopyToNonMs = gd.CreateProgramWithMinimalLayout(new[] { - new ShaderSource(ShaderBinaries.ColorCopyBetweenMsNonMs, colorCopyMSBindings, ShaderStage.Compute, TargetLanguage.Spirv), - }, new[] + new ShaderSource(ShaderBinaries.ColorCopyToNonMsComputeShaderSource, colorCopyToNonMsBindings, ShaderStage.Compute, TargetLanguage.Spirv), + }); + + var colorDrawToMsVertexBindings = new ShaderBindings( + Array.Empty<int>(), + Array.Empty<int>(), + Array.Empty<int>(), + Array.Empty<int>()); + + var colorDrawToMsFragmentBindings = new ShaderBindings( + new[] { 0 }, + Array.Empty<int>(), + new[] { 0 }, + Array.Empty<int>()); + + _programColorDrawToMs = gd.CreateProgramWithMinimalLayout(new[] { - new SpecDescription((0, SpecConstType.Int32)) + new ShaderSource(ShaderBinaries.ColorDrawToMsVertexShaderSource, colorDrawToMsVertexBindings, ShaderStage.Vertex, TargetLanguage.Spirv), + new ShaderSource(ShaderBinaries.ColorDrawToMsFragmentShaderSource, colorDrawToMsFragmentBindings, ShaderStage.Fragment, TargetLanguage.Spirv), }); var convertIndexBufferBindings = new ShaderBindings( @@ -509,35 +525,17 @@ namespace Ryujinx.Graphics.Vulkan public void CopyMSToNonMS(VulkanRenderer gd, CommandBufferScoped cbs, TextureView src, TextureView dst, int srcLayer, int dstLayer, int depth) { - CopyMS(gd, cbs, src, dst, srcLayer, dstLayer, depth, src.Info.Samples, dst.Info.Width, dst.Info.Height); - } - - public void CopyNonMSToMS(VulkanRenderer gd, CommandBufferScoped cbs, TextureView src, TextureView dst, int srcLayer, int dstLayer, int depth) - { - CopyMS(gd, cbs, src, dst, srcLayer, dstLayer, depth, dst.Info.Samples, src.Info.Width, src.Info.Height); - } - - private void CopyMS( - VulkanRenderer gd, - CommandBufferScoped cbs, - TextureView src, - TextureView dst, - int srcLayer, - int dstLayer, - int depth, - int samples, - int nonMSWidth, - int nonMSHeight) - { const int ParamsBufferSize = 16; Span<int> shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)]; + int samples = src.Info.Samples; + // X and Y are the expected texture samples. // Z and W are the actual texture samples used. // They may differ if the GPU does not support the samples count requested and we had to use a lower amount. (shaderParams[0], shaderParams[1]) = GetSampleCountXYLog2(samples); - (shaderParams[2], shaderParams[3]) = GetSampleCountXYLog2((int)TextureStorage.ConvertToSampleCountFlags((uint)samples)); + (shaderParams[2], shaderParams[3]) = GetSampleCountXYLog2((int)TextureStorage.ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)samples)); var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize, false); @@ -559,17 +557,12 @@ namespace Ryujinx.Graphics.Vulkan _pipeline.SetCommandBuffer(cbs); - _pipeline.SetProgram(_programColorCopyBetweenMsNonMs); + _pipeline.SetProgram(_programColorCopyToNonMs); var format = GetFormat(src.Info.BytesPerPixel); - int dispatchX = (nonMSWidth + 31) / 32; - int dispatchY = (nonMSHeight + 31) / 32; - - // Specialize shader. - bool srcIsMs = src.Info.Target.IsMultisample(); - int conversionType = srcIsMs ? src.Info.BytesPerPixel : -src.Info.BytesPerPixel; - _pipeline.Specialize(conversionType); + int dispatchX = (dst.Info.Width + 31) / 32; + int dispatchY = (dst.Info.Height + 31) / 32; _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) }); @@ -621,6 +614,129 @@ namespace Ryujinx.Graphics.Vulkan 1); } + public void CopyNonMSToMS(VulkanRenderer gd, CommandBufferScoped cbs, TextureView src, TextureView dst, int srcLayer, int dstLayer, int depth) + { + const int ParamsBufferSize = 16; + + Span<int> shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)]; + + int samples = dst.Info.Samples; + + // X and Y are the expected texture samples. + // Z and W are the actual texture samples used. + // They may differ if the GPU does not support the samples count requested and we had to use a lower amount. + (shaderParams[0], shaderParams[1]) = GetSampleCountXYLog2(samples); + (shaderParams[2], shaderParams[3]) = GetSampleCountXYLog2((int)TextureStorage.ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)samples)); + + var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize, false); + + gd.BufferManager.SetData<int>(bufferHandle, 0, shaderParams); + + TextureView.InsertImageBarrier( + gd.Api, + cbs.CommandBuffer, + src.GetImage().Get(cbs).Value, + TextureStorage.DefaultAccessMask, + AccessFlags.AccessShaderReadBit, + PipelineStageFlags.PipelineStageAllCommandsBit, + PipelineStageFlags.PipelineStageFragmentShaderBit, + ImageAspectFlags.ImageAspectColorBit, + src.FirstLayer + srcLayer, + src.FirstLevel, + depth, + 1); + + _pipeline.SetCommandBuffer(cbs); + + _pipeline.SetProgram(_programColorDrawToMs); + + Span<GAL.Viewport> viewports = stackalloc GAL.Viewport[1]; + + var rect = new Rectangle<float>(0, 0, dst.Width, dst.Height); + + viewports[0] = new GAL.Viewport( + rect, + ViewportSwizzle.PositiveX, + ViewportSwizzle.PositiveY, + ViewportSwizzle.PositiveZ, + ViewportSwizzle.PositiveW, + 0f, + 1f); + + Span<Rectangle<int>> scissors = stackalloc Rectangle<int>[1]; + + scissors[0] = new Rectangle<int>(0, 0, dst.Width, dst.Height); + + _pipeline.SetRenderTargetColorMasks(new uint[] { 0xf }); + _pipeline.SetScissors(scissors); + _pipeline.SetViewports(viewports, false); + _pipeline.SetPrimitiveTopology(GAL.PrimitiveTopology.TriangleStrip); + + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) }); + + var format = GetFormat(src.Info.BytesPerPixel); + var vkFormat = FormatTable.GetFormat(format); + + if (src.Info.Target == Target.Texture2DMultisampleArray || + dst.Info.Target == Target.Texture2DMultisampleArray) + { + for (int z = 0; z < depth; z++) + { + var srcView = Create2DLayerView(src, srcLayer + z, format); + var dstView = Create2DLayerView(dst, dstLayer + z); + + _pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, srcView, null); + _pipeline.SetRenderTarget( + ((TextureView)dstView).GetView(format).GetImageViewForAttachment(), + (uint)dst.Width, + (uint)dst.Height, + (uint)samples, + false, + vkFormat); + + _pipeline.Draw(4, 1, 0, 0); + + srcView.Release(); + dstView.Release(); + } + } + else + { + var srcView = Create2DLayerView(src, srcLayer, format); + + _pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, srcView, null); + _pipeline.SetRenderTarget( + dst.GetView(format).GetImageViewForAttachment(), + (uint)dst.Width, + (uint)dst.Height, + (uint)samples, + false, + vkFormat); + + _pipeline.Draw(4, 1, 0, 0); + + srcView.Release(); + } + + gd.BufferManager.Delete(bufferHandle); + + _pipeline.Finish(gd, cbs); + + TextureView.InsertImageBarrier( + gd.Api, + cbs.CommandBuffer, + dst.GetImage().Get(cbs).Value, + AccessFlags.AccessColorAttachmentWriteBit, + TextureStorage.DefaultAccessMask, + PipelineStageFlags.PipelineStageFragmentShaderBit, + PipelineStageFlags.PipelineStageAllCommandsBit, + ImageAspectFlags.ImageAspectColorBit, + dst.FirstLayer + dstLayer, + dst.FirstLevel, + depth, + 1); + } + private static (int, int) GetSampleCountXYLog2(int samples) { int samplesInXLog2 = 0; @@ -834,9 +950,10 @@ namespace Ryujinx.Graphics.Vulkan _programColorBlit.Dispose(); _programColorClear.Dispose(); _programStrideChange.Dispose(); - _programColorCopyBetweenMsNonMs.Dispose(); _programConvertIndexBuffer.Dispose(); _programConvertIndirectData.Dispose(); + _programColorCopyToNonMs.Dispose(); + _programColorDrawToMs.Dispose(); _samplerNearest.Dispose(); _samplerLinear.Dispose(); _pipeline.Dispose(); |