mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2025-02-21 00:23:36 +00:00
Add minimal pipeline layouts that only contains used bindings
They are used by helper shaders, the intention is avoiding needing to recompile the shaders (from GLSL to SPIR-V) if the bindings changes on the translated guest shaders
This commit is contained in:
parent
38ecf0f117
commit
400ed2d96d
7 changed files with 195 additions and 39 deletions
|
@ -32,7 +32,7 @@ void main()
|
|||
|
||||
private const string ColorBlitFragmentShaderSource = @"#version 450 core
|
||||
|
||||
layout (binding = 128, set = 2) uniform sampler2D tex;
|
||||
layout (binding = 0, set = 2) uniform sampler2D tex;
|
||||
|
||||
layout (location = 0) in vec2 tex_coord;
|
||||
layout (location = 0) out vec4 colour;
|
||||
|
@ -44,7 +44,7 @@ void main()
|
|||
|
||||
private const string ColorBlitClearAlphaFragmentShaderSource = @"#version 450 core
|
||||
|
||||
layout (binding = 128, set = 2) uniform sampler2D tex;
|
||||
layout (binding = 0, set = 2) uniform sampler2D tex;
|
||||
|
||||
layout (location = 0) in vec2 tex_coord;
|
||||
layout (location = 0) out vec4 colour;
|
||||
|
@ -125,20 +125,20 @@ void main()
|
|||
var fragmentBindings = new ShaderBindings(
|
||||
Array.Empty<int>(),
|
||||
Array.Empty<int>(),
|
||||
new[] { Constants.MaxTexturesPerStage * 2 },
|
||||
new[] { 0 },
|
||||
Array.Empty<int>());
|
||||
|
||||
_programColorBlit = gd.CreateProgram(new[]
|
||||
_programColorBlit = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ColorBlitVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Glsl),
|
||||
new ShaderSource(ColorBlitFragmentShaderSource, fragmentBindings, ShaderStage.Fragment, TargetLanguage.Glsl),
|
||||
}, new ShaderInfo(-1));
|
||||
});
|
||||
|
||||
_programColorBlitClearAlpha = gd.CreateProgram(new[]
|
||||
_programColorBlitClearAlpha = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ColorBlitVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Glsl),
|
||||
new ShaderSource(ColorBlitClearAlphaFragmentShaderSource, fragmentBindings, ShaderStage.Fragment, TargetLanguage.Glsl),
|
||||
}, new ShaderInfo(-1));
|
||||
});
|
||||
|
||||
var fragmentBindings2 = new ShaderBindings(
|
||||
Array.Empty<int>(),
|
||||
|
@ -146,11 +146,11 @@ void main()
|
|||
Array.Empty<int>(),
|
||||
Array.Empty<int>());
|
||||
|
||||
_programColorClear = gd.CreateProgram(new[]
|
||||
_programColorClear = gd.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(ColorClearVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Glsl),
|
||||
new ShaderSource(ColorClearFragmentShaderSource, fragmentBindings2, ShaderStage.Fragment, TargetLanguage.Glsl),
|
||||
}, new ShaderInfo(-1));
|
||||
});
|
||||
}
|
||||
|
||||
public void Blit(
|
||||
|
@ -191,7 +191,7 @@ void main()
|
|||
|
||||
var sampler = linearFilter ? _samplerLinear : _samplerNearest;
|
||||
|
||||
_pipeline.SetTextureAndSampler(ShaderStage.Fragment, Constants.MaxTexturesPerStage * 2, src, sampler);
|
||||
_pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, src, sampler);
|
||||
|
||||
Span<float> region = stackalloc float[RegionBufferSize / sizeof(float)];
|
||||
|
||||
|
@ -328,7 +328,7 @@ void main()
|
|||
{
|
||||
const int RegionBufferSize = 16;
|
||||
|
||||
pipeline.SetTextureAndSampler(ShaderStage.Fragment, Constants.MaxTexturesPerStage * 2, src, srcSampler);
|
||||
pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, src, srcSampler);
|
||||
|
||||
Span<float> region = stackalloc float[RegionBufferSize / sizeof(float)];
|
||||
|
||||
|
|
|
@ -1,14 +1,25 @@
|
|||
using Ryujinx.Graphics.GAL;
|
||||
using Silk.NET.Vulkan;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
class PipelineLayoutCache
|
||||
{
|
||||
private PipelineLayoutCacheEntry[] _plce;
|
||||
private readonly PipelineLayoutCacheEntry[] _plce;
|
||||
private readonly List<PipelineLayoutCacheEntry> _plceMinimal;
|
||||
|
||||
public PipelineLayoutCache()
|
||||
{
|
||||
_plce = new PipelineLayoutCacheEntry[1 << Constants.MaxShaderStages];
|
||||
_plceMinimal = new List<PipelineLayoutCacheEntry>();
|
||||
}
|
||||
|
||||
public PipelineLayoutCacheEntry Create(VulkanGraphicsDevice gd, Device device, ShaderSource[] shaders)
|
||||
{
|
||||
var plce = new PipelineLayoutCacheEntry(gd, device, shaders);
|
||||
_plceMinimal.Add(plce);
|
||||
return plce;
|
||||
}
|
||||
|
||||
public PipelineLayoutCacheEntry GetOrCreate(VulkanGraphicsDevice gd, Device device, uint stages)
|
||||
|
@ -29,6 +40,13 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
{
|
||||
_plce[i]?.Dispose();
|
||||
}
|
||||
|
||||
foreach (var plce in _plceMinimal)
|
||||
{
|
||||
plce.Dispose();
|
||||
}
|
||||
|
||||
_plceMinimal.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using Ryujinx.Graphics.GAL;
|
||||
using Silk.NET.Vulkan;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
@ -15,16 +16,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
private readonly int[] _dsCacheCursor;
|
||||
private int _dsLastCbIndex;
|
||||
|
||||
private readonly uint _stages;
|
||||
|
||||
public PipelineLayoutCacheEntry(VulkanGraphicsDevice gd, Device device, uint stages)
|
||||
private PipelineLayoutCacheEntry(VulkanGraphicsDevice gd, Device device)
|
||||
{
|
||||
_gd = gd;
|
||||
_device = device;
|
||||
_stages = stages;
|
||||
|
||||
DescriptorSetLayouts = PipelineLayoutFactory.Create(gd, device, stages, out var pipelineLayout);
|
||||
PipelineLayout = pipelineLayout;
|
||||
|
||||
_dsCache = new List<Auto<DescriptorSetCollection>>[CommandBufferPool.MaxCommandBuffers][];
|
||||
|
||||
|
@ -41,6 +36,18 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
_dsCacheCursor = new int[PipelineBase.DescriptorSetLayouts];
|
||||
}
|
||||
|
||||
public PipelineLayoutCacheEntry(VulkanGraphicsDevice gd, Device device, uint stages) : this(gd, device)
|
||||
{
|
||||
DescriptorSetLayouts = PipelineLayoutFactory.Create(gd, device, stages, out var pipelineLayout);
|
||||
PipelineLayout = pipelineLayout;
|
||||
}
|
||||
|
||||
public PipelineLayoutCacheEntry(VulkanGraphicsDevice gd, Device device, ShaderSource[] shaders) : this(gd, device)
|
||||
{
|
||||
DescriptorSetLayouts = PipelineLayoutFactory.CreateMinimal(gd, device, shaders, out var pipelineLayout);
|
||||
PipelineLayout = pipelineLayout;
|
||||
}
|
||||
|
||||
public Auto<DescriptorSetCollection> GetNewDescriptorSetCollection(
|
||||
VulkanGraphicsDevice gd,
|
||||
int commandBufferIndex,
|
||||
|
@ -75,28 +82,25 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
{
|
||||
if (disposing)
|
||||
{
|
||||
unsafe
|
||||
for (int i = 0; i < _dsCache.Length; i++)
|
||||
{
|
||||
for (int i = 0; i < _dsCache.Length; i++)
|
||||
for (int j = 0; j < _dsCache[i].Length; j++)
|
||||
{
|
||||
for (int y = 0; y < _dsCache[i].Length; y++)
|
||||
for (int k = 0; k < _dsCache[i][j].Count; k++)
|
||||
{
|
||||
for (int z = 0; z < _dsCache[i][y].Count; z++)
|
||||
{
|
||||
_dsCache[i][y][z].Dispose();
|
||||
}
|
||||
|
||||
_dsCache[i][y].Clear();
|
||||
_dsCache[i][j][k].Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
_gd.Api.DestroyPipelineLayout(_device, PipelineLayout, null);
|
||||
|
||||
for (int i = 0; i < DescriptorSetLayouts.Length; i++)
|
||||
{
|
||||
_gd.Api.DestroyDescriptorSetLayout(_device, DescriptorSetLayouts[i], null);
|
||||
_dsCache[i][j].Clear();
|
||||
}
|
||||
}
|
||||
|
||||
_gd.Api.DestroyPipelineLayout(_device, PipelineLayout, null);
|
||||
|
||||
for (int i = 0; i < DescriptorSetLayouts.Length; i++)
|
||||
{
|
||||
_gd.Api.DestroyDescriptorSetLayout(_device, DescriptorSetLayouts[i], null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
using Silk.NET.Vulkan;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Silk.NET.Vulkan;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
static class PipelineLayoutFactory
|
||||
{
|
||||
private const ShaderStageFlags SupportBufferStages =
|
||||
ShaderStageFlags.ShaderStageVertexBit |
|
||||
ShaderStageFlags.ShaderStageFragmentBit |
|
||||
ShaderStageFlags.ShaderStageComputeBit;
|
||||
|
||||
public static unsafe DescriptorSetLayout[] Create(VulkanGraphicsDevice gd, Device device, uint stages, out PipelineLayout layout)
|
||||
{
|
||||
int stagesCount = BitOperations.PopCount(stages);
|
||||
|
@ -23,7 +30,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
Binding = 0,
|
||||
DescriptorType = DescriptorType.UniformBuffer,
|
||||
DescriptorCount = 1,
|
||||
StageFlags = ShaderStageFlags.ShaderStageVertexBit | ShaderStageFlags.ShaderStageFragmentBit | ShaderStageFlags.ShaderStageComputeBit
|
||||
StageFlags = SupportBufferStages
|
||||
};
|
||||
|
||||
int iter = 0;
|
||||
|
@ -128,5 +135,126 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
return layouts;
|
||||
}
|
||||
|
||||
public static unsafe DescriptorSetLayout[] CreateMinimal(VulkanGraphicsDevice gd, Device device, ShaderSource[] shaders, out PipelineLayout layout)
|
||||
{
|
||||
int stagesCount = shaders.Length;
|
||||
|
||||
int uCount = 0;
|
||||
int tCount = 0;
|
||||
int iCount = 0;
|
||||
|
||||
foreach (var shader in shaders)
|
||||
{
|
||||
uCount += shader.Bindings.UniformBufferBindings.Count;
|
||||
tCount += shader.Bindings.TextureBindings.Count;
|
||||
iCount += shader.Bindings.ImageBindings.Count;
|
||||
}
|
||||
|
||||
DescriptorSetLayoutBinding* uLayoutBindings = stackalloc DescriptorSetLayoutBinding[uCount];
|
||||
DescriptorSetLayoutBinding* sLayoutBindings = stackalloc DescriptorSetLayoutBinding[stagesCount];
|
||||
DescriptorSetLayoutBinding* tLayoutBindings = stackalloc DescriptorSetLayoutBinding[tCount];
|
||||
DescriptorSetLayoutBinding* iLayoutBindings = stackalloc DescriptorSetLayoutBinding[iCount];
|
||||
|
||||
uLayoutBindings[0] = new DescriptorSetLayoutBinding
|
||||
{
|
||||
Binding = 0,
|
||||
DescriptorType = DescriptorType.UniformBuffer,
|
||||
DescriptorCount = 1,
|
||||
StageFlags = SupportBufferStages
|
||||
};
|
||||
|
||||
int uIndex = 0;
|
||||
int sIndex = 0;
|
||||
int tIndex = 0;
|
||||
int iIndex = 0;
|
||||
|
||||
foreach (var shader in shaders)
|
||||
{
|
||||
var stageFlags = shader.Stage.Convert();
|
||||
|
||||
void Set(DescriptorSetLayoutBinding* bindings, DescriptorType type, ref int start, IEnumerable<int> bds)
|
||||
{
|
||||
foreach (var b in bds)
|
||||
{
|
||||
bindings[start++] = new DescriptorSetLayoutBinding
|
||||
{
|
||||
Binding = (uint)b,
|
||||
DescriptorType = type,
|
||||
DescriptorCount = 1,
|
||||
StageFlags = stageFlags
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void SetStorage(DescriptorSetLayoutBinding* bindings, ref int start, int count)
|
||||
{
|
||||
bindings[start++] = new DescriptorSetLayoutBinding
|
||||
{
|
||||
Binding = (uint)start,
|
||||
DescriptorType = DescriptorType.StorageBuffer,
|
||||
DescriptorCount = (uint)count,
|
||||
StageFlags = stageFlags
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: Support buffer textures and images here.
|
||||
// This is only used for the helper shaders on the backkend, and we don't use buffer textures on them
|
||||
// so far, so it's not really necessary right now.
|
||||
Set(uLayoutBindings, DescriptorType.UniformBuffer, ref uIndex, shader.Bindings.UniformBufferBindings);
|
||||
SetStorage(sLayoutBindings, ref sIndex, shader.Bindings.StorageBufferBindings.Count);
|
||||
Set(tLayoutBindings, DescriptorType.CombinedImageSampler, ref tIndex, shader.Bindings.TextureBindings);
|
||||
Set(iLayoutBindings, DescriptorType.StorageImage, ref iIndex, shader.Bindings.ImageBindings);
|
||||
}
|
||||
|
||||
DescriptorSetLayout[] layouts = new DescriptorSetLayout[PipelineFull.DescriptorSetLayouts];
|
||||
|
||||
var uDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()
|
||||
{
|
||||
SType = StructureType.DescriptorSetLayoutCreateInfo,
|
||||
PBindings = uLayoutBindings,
|
||||
BindingCount = (uint)uCount
|
||||
};
|
||||
|
||||
var sDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()
|
||||
{
|
||||
SType = StructureType.DescriptorSetLayoutCreateInfo,
|
||||
PBindings = sLayoutBindings,
|
||||
BindingCount = (uint)stagesCount
|
||||
};
|
||||
|
||||
var tDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()
|
||||
{
|
||||
SType = StructureType.DescriptorSetLayoutCreateInfo,
|
||||
PBindings = tLayoutBindings,
|
||||
BindingCount = (uint)tCount
|
||||
};
|
||||
|
||||
var iDescriptorSetLayoutCreateInfo = new DescriptorSetLayoutCreateInfo()
|
||||
{
|
||||
SType = StructureType.DescriptorSetLayoutCreateInfo,
|
||||
PBindings = iLayoutBindings,
|
||||
BindingCount = (uint)iCount
|
||||
};
|
||||
|
||||
gd.Api.CreateDescriptorSetLayout(device, uDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.UniformSetIndex]).ThrowOnError();
|
||||
gd.Api.CreateDescriptorSetLayout(device, sDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.StorageSetIndex]).ThrowOnError();
|
||||
gd.Api.CreateDescriptorSetLayout(device, tDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.TextureSetIndex]).ThrowOnError();
|
||||
gd.Api.CreateDescriptorSetLayout(device, iDescriptorSetLayoutCreateInfo, null, out layouts[PipelineFull.ImageSetIndex]).ThrowOnError();
|
||||
|
||||
fixed (DescriptorSetLayout* pLayouts = layouts)
|
||||
{
|
||||
var pipelineLayoutCreateInfo = new PipelineLayoutCreateInfo()
|
||||
{
|
||||
SType = StructureType.PipelineLayoutCreateInfo,
|
||||
PSetLayouts = pLayouts,
|
||||
SetLayoutCount = PipelineFull.DescriptorSetLayouts
|
||||
};
|
||||
|
||||
gd.Api.CreatePipelineLayout(device, &pipelineLayoutCreateInfo, null, out layout).ThrowOnError();
|
||||
}
|
||||
|
||||
return layouts;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ using Ryujinx.Graphics.Shader;
|
|||
using shaderc;
|
||||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
private Task _compileTask;
|
||||
private bool _firstBackgroundUse;
|
||||
|
||||
public ShaderCollection(VulkanGraphicsDevice gd, Device device, ShaderSource[] shaders)
|
||||
public ShaderCollection(VulkanGraphicsDevice gd, Device device, ShaderSource[] shaders, bool isMinimal = false)
|
||||
{
|
||||
_gd = gd;
|
||||
_device = device;
|
||||
|
@ -87,7 +87,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
_shaders = internalShaders;
|
||||
|
||||
_plce = gd.PipelineLayoutCache.GetOrCreate(gd, device, stages);
|
||||
_plce = isMinimal
|
||||
? gd.PipelineLayoutCache.Create(gd, device, shaders)
|
||||
: gd.PipelineLayoutCache.GetOrCreate(gd, device, stages);
|
||||
|
||||
Stages = stages;
|
||||
|
||||
|
|
|
@ -317,6 +317,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
}
|
||||
}
|
||||
|
||||
internal ShaderCollection CreateProgramWithMinimalLayout(ShaderSource[] sources)
|
||||
{
|
||||
return new ShaderCollection(this, _device, sources, isMinimal: true);
|
||||
}
|
||||
|
||||
public ISampler CreateSampler(GAL.SamplerCreateInfo info)
|
||||
{
|
||||
return new SamplerHolder(this, _device, info);
|
||||
|
|
Loading…
Reference in a new issue