Remove old CompileShader methods from the Vulkan backend

This commit is contained in:
gdk 2022-06-10 21:22:44 -03:00 committed by riperiperi
parent b6764620be
commit 38ecf0f117
5 changed files with 86 additions and 134 deletions

View file

@ -1,6 +0,0 @@
using System;
namespace Ryujinx.Graphics.GAL
{
public interface IShader : IDisposable { }
}

View file

@ -1,5 +1,6 @@
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Shader; using Ryujinx.Graphics.Shader;
using Ryujinx.Graphics.Shader.Translation;
using Silk.NET.Vulkan; using Silk.NET.Vulkan;
using System; using System;
using VkFormat = Silk.NET.Vulkan.Format; using VkFormat = Silk.NET.Vulkan.Format;
@ -127,12 +128,17 @@ void main()
new[] { Constants.MaxTexturesPerStage * 2 }, new[] { Constants.MaxTexturesPerStage * 2 },
Array.Empty<int>()); Array.Empty<int>());
var colorBlitVertexShader = gd.CompileShader(ShaderStage.Vertex, vertexBindings, ColorBlitVertexShaderSource); _programColorBlit = gd.CreateProgram(new[]
var colorBlitFragmentShader = gd.CompileShader(ShaderStage.Fragment, fragmentBindings, ColorBlitFragmentShaderSource); {
var colorBlitClearAlphaFragmentShader = gd.CompileShader(ShaderStage.Fragment, fragmentBindings, ColorBlitClearAlphaFragmentShaderSource); new ShaderSource(ColorBlitVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Glsl),
new ShaderSource(ColorBlitFragmentShaderSource, fragmentBindings, ShaderStage.Fragment, TargetLanguage.Glsl),
}, new ShaderInfo(-1));
_programColorBlit = gd.CreateProgram(new[] { colorBlitVertexShader, colorBlitFragmentShader }, new ShaderInfo(-1)); _programColorBlitClearAlpha = gd.CreateProgram(new[]
_programColorBlitClearAlpha = gd.CreateProgram(new[] { colorBlitVertexShader, colorBlitClearAlphaFragmentShader }, new ShaderInfo(-1)); {
new ShaderSource(ColorBlitVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Glsl),
new ShaderSource(ColorBlitClearAlphaFragmentShaderSource, fragmentBindings, ShaderStage.Fragment, TargetLanguage.Glsl),
}, new ShaderInfo(-1));
var fragmentBindings2 = new ShaderBindings( var fragmentBindings2 = new ShaderBindings(
Array.Empty<int>(), Array.Empty<int>(),
@ -140,10 +146,11 @@ void main()
Array.Empty<int>(), Array.Empty<int>(),
Array.Empty<int>()); Array.Empty<int>());
var colorClearVertexShader = gd.CompileShader(ShaderStage.Vertex, vertexBindings, ColorClearVertexShaderSource); _programColorClear = gd.CreateProgram(new[]
var colorClearFragmentShader = gd.CompileShader(ShaderStage.Fragment, fragmentBindings2, ColorClearFragmentShaderSource); {
new ShaderSource(ColorClearVertexShaderSource, vertexBindings, ShaderStage.Vertex, TargetLanguage.Glsl),
_programColorClear = gd.CreateProgram(new[] { colorClearVertexShader, colorClearFragmentShader }, new ShaderInfo(-1)); new ShaderSource(ColorClearFragmentShaderSource, fragmentBindings2, ShaderStage.Fragment, TargetLanguage.Glsl),
}, new ShaderInfo(-1));
} }
public void Blit( public void Blit(

View file

@ -10,7 +10,7 @@ using System.Threading.Tasks;
namespace Ryujinx.Graphics.Vulkan namespace Ryujinx.Graphics.Vulkan
{ {
class Shader : IShader class Shader
{ {
// The shaderc.net dependency's Options constructor and dispose are not thread safe. // The shaderc.net dependency's Options constructor and dispose are not thread safe.
// Take this lock when using them. // Take this lock when using them.
@ -31,86 +31,33 @@ namespace Ryujinx.Graphics.Vulkan
public readonly Task CompileTask; public readonly Task CompileTask;
public unsafe Shader(Vk api, Device device, ShaderStage stage, ShaderBindings bindings, string glsl) public unsafe Shader(Vk api, Device device, ShaderSource shaderSource)
{ {
_api = api; _api = api;
_device = device; _device = device;
_stage = stage.Convert(); Bindings = shaderSource.Bindings;
_entryPointName = Marshal.StringToHGlobalAnsi("main");
Bindings = bindings;
CompileTask = Task.Run(() =>
{
glsl = glsl.Replace("gl_VertexID", "(gl_VertexIndex - gl_BaseVertex)");
glsl = glsl.Replace("gl_InstanceID", "(gl_InstanceIndex - gl_BaseInstance)");
// System.Console.WriteLine(glsl);
Options options;
lock (_shaderOptionsLock)
{
options = new Options(false)
{
SourceLanguage = SourceLanguage.Glsl,
TargetSpirVVersion = new SpirVVersion(1, 5)
};
}
options.SetTargetEnvironment(TargetEnvironment.Vulkan, EnvironmentVersion.Vulkan_1_2);
Compiler compiler = new Compiler(options);
var scr = compiler.Compile(glsl, "Ryu", GetShaderCShaderStage(stage));
lock (_shaderOptionsLock)
{
options.Dispose();
}
if (scr.Status != Status.Success)
{
Logger.Error?.Print(LogClass.Gpu, $"Shader compilation error: {scr.Status} {scr.ErrorMessage}");
CompileStatus = ProgramLinkStatus.Failure;
return;
}
var spirvBytes = new Span<byte>((void*)scr.CodePointer, (int)scr.CodeLength);
uint[] code = new uint[(scr.CodeLength + 3) / 4];
spirvBytes.CopyTo(MemoryMarshal.Cast<uint, byte>(new Span<uint>(code)).Slice(0, (int)scr.CodeLength));
fixed (uint* pCode = code)
{
var shaderModuleCreateInfo = new ShaderModuleCreateInfo()
{
SType = StructureType.ShaderModuleCreateInfo,
CodeSize = scr.CodeLength,
PCode = pCode
};
api.CreateShaderModule(device, shaderModuleCreateInfo, null, out _module).ThrowOnError();
}
CompileStatus = ProgramLinkStatus.Success;
});
}
public unsafe Shader(Vk api, Device device, ShaderStage stage, ShaderBindings bindings, byte[] spirv)
{
_api = api;
_device = device;
Bindings = bindings;
CompileStatus = ProgramLinkStatus.Incomplete; CompileStatus = ProgramLinkStatus.Incomplete;
_stage = stage.Convert(); _stage = shaderSource.Stage.Convert();
_entryPointName = Marshal.StringToHGlobalAnsi("main"); _entryPointName = Marshal.StringToHGlobalAnsi("main");
CompileTask = Task.Run(() => CompileTask = Task.Run(() =>
{ {
byte[] spirv = shaderSource.BinaryCode;
if (spirv == null)
{
spirv = GlslToSpirv(shaderSource.Code, shaderSource.Stage);
if (spirv == null)
{
CompileStatus = ProgramLinkStatus.Failure;
return;
}
}
fixed (byte* pCode = spirv) fixed (byte* pCode = spirv)
{ {
var shaderModuleCreateInfo = new ShaderModuleCreateInfo() var shaderModuleCreateInfo = new ShaderModuleCreateInfo()
@ -127,16 +74,46 @@ namespace Ryujinx.Graphics.Vulkan
}); });
} }
private static uint[] LoadShaderData(string filePath, out int codeSize) private unsafe static byte[] GlslToSpirv(string glsl, ShaderStage stage)
{ {
var fileBytes = File.ReadAllBytes(filePath); // TODO: We should generate the correct code on the shader translator instead of doing this compensation.
var shaderData = new uint[(int)Math.Ceiling(fileBytes.Length / 4f)]; glsl = glsl.Replace("gl_VertexID", "(gl_VertexIndex - gl_BaseVertex)");
glsl = glsl.Replace("gl_InstanceID", "(gl_InstanceIndex - gl_BaseInstance)");
System.Buffer.BlockCopy(fileBytes, 0, shaderData, 0, fileBytes.Length); Options options;
codeSize = fileBytes.Length; lock (_shaderOptionsLock)
{
options = new Options(false)
{
SourceLanguage = SourceLanguage.Glsl,
TargetSpirVVersion = new SpirVVersion(1, 5)
};
}
return shaderData; options.SetTargetEnvironment(TargetEnvironment.Vulkan, EnvironmentVersion.Vulkan_1_2);
Compiler compiler = new Compiler(options);
var scr = compiler.Compile(glsl, "Ryu", GetShaderCShaderStage(stage));
lock (_shaderOptionsLock)
{
options.Dispose();
}
if (scr.Status != Status.Success)
{
Logger.Error?.Print(LogClass.Gpu, $"Shader compilation error: {scr.Status} {scr.ErrorMessage}");
return null;
}
var spirvBytes = new Span<byte>((void*)scr.CodePointer, (int)scr.CodeLength);
byte[] code = new byte[(scr.CodeLength + 3) & ~3];
spirvBytes.CopyTo(code.AsSpan().Slice(0, (int)scr.CodeLength));
return code;
} }
private static ShaderKind GetShaderCShaderStage(ShaderStage stage) private static ShaderKind GetShaderCShaderStage(ShaderStage stage)

View file

@ -11,7 +11,7 @@ namespace Ryujinx.Graphics.Vulkan
class ShaderCollection : IProgram class ShaderCollection : IProgram
{ {
private readonly PipelineShaderStageCreateInfo[] _infos; private readonly PipelineShaderStageCreateInfo[] _infos;
private readonly IShader[] _shaders; private readonly Shader[] _shaders;
private readonly PipelineLayoutCacheEntry _plce; private readonly PipelineLayoutCacheEntry _plce;
@ -49,11 +49,10 @@ namespace Ryujinx.Graphics.Vulkan
private Task _compileTask; private Task _compileTask;
private bool _firstBackgroundUse; private bool _firstBackgroundUse;
public ShaderCollection(VulkanGraphicsDevice gd, Device device, IShader[] shaders) public ShaderCollection(VulkanGraphicsDevice gd, Device device, ShaderSource[] shaders)
{ {
_gd = gd; _gd = gd;
_device = device; _device = device;
_shaders = shaders;
gd.Shaders.Add(this); gd.Shaders.Add(this);
@ -67,7 +66,7 @@ namespace Ryujinx.Graphics.Vulkan
for (int i = 0; i < shaders.Length; i++) for (int i = 0; i < shaders.Length; i++)
{ {
var shader = (Shader)shaders[i]; var shader = new Shader(gd.Api, device, shaders[i]);
stages |= 1u << shader.StageFlags switch stages |= 1u << shader.StageFlags switch
{ {
@ -86,6 +85,8 @@ namespace Ryujinx.Graphics.Vulkan
internalShaders[i] = shader; internalShaders[i] = shader;
} }
_shaders = internalShaders;
_plce = gd.PipelineLayoutCache.GetOrCreate(gd, device, stages); _plce = gd.PipelineLayoutCache.GetOrCreate(gd, device, stages);
Stages = stages; Stages = stages;
@ -120,8 +121,8 @@ namespace Ryujinx.Graphics.Vulkan
public ShaderCollection( public ShaderCollection(
VulkanGraphicsDevice gd, VulkanGraphicsDevice gd,
Device device, Device device,
IShader[] shaders, ShaderSource[] sources,
ProgramPipelineState state) : this(gd, device, shaders) ProgramPipelineState state) : this(gd, device, sources)
{ {
_state = state; _state = state;
@ -131,9 +132,9 @@ namespace Ryujinx.Graphics.Vulkan
private async Task BackgroundCompilation() private async Task BackgroundCompilation()
{ {
await Task.WhenAll(_shaders.Select(shader => ((Shader)shader).CompileTask)); await Task.WhenAll(_shaders.Select(shader => shader.CompileTask));
if (_shaders.Any(shader => ((Shader)shader).CompileStatus == ProgramLinkStatus.Failure)) if (_shaders.Any(shader => shader.CompileStatus == ProgramLinkStatus.Failure))
{ {
LinkStatus = ProgramLinkStatus.Failure; LinkStatus = ProgramLinkStatus.Failure;
@ -169,7 +170,7 @@ namespace Ryujinx.Graphics.Vulkan
for (int i = 0; i < _shaders.Length; i++) for (int i = 0; i < _shaders.Length; i++)
{ {
var shader = (Shader)_shaders[i]; var shader = _shaders[i];
if (shader.CompileStatus != ProgramLinkStatus.Success) if (shader.CompileStatus != ProgramLinkStatus.Success)
{ {
@ -211,7 +212,7 @@ namespace Ryujinx.Graphics.Vulkan
PipelineState pipeline = new PipelineState(); PipelineState pipeline = new PipelineState();
pipeline.Initialize(); pipeline.Initialize();
pipeline.Stages[0] = ((Shader)_shaders[0]).GetInfo(); pipeline.Stages[0] = _shaders[0].GetInfo();
pipeline.StagesCount = 1; pipeline.StagesCount = 1;
pipeline.CreateComputePipeline(_gd, _device, this, (_gd.Pipeline as PipelineBase).PipelineCache); pipeline.CreateComputePipeline(_gd, _device, this, (_gd.Pipeline as PipelineBase).PipelineCache);
@ -236,7 +237,7 @@ namespace Ryujinx.Graphics.Vulkan
for (int i = 0; i < _shaders.Length; i++) for (int i = 0; i < _shaders.Length; i++)
{ {
stages[i] = ((Shader)_shaders[i]).GetInfo(); stages[i] = _shaders[i].GetInfo();
} }
pipeline.StagesCount = (uint)_shaders.Length; pipeline.StagesCount = (uint)_shaders.Length;

View file

@ -298,52 +298,25 @@ namespace Ryujinx.Graphics.Vulkan
_window = new ImageWindow(this, _physicalDevice, _device); _window = new ImageWindow(this, _physicalDevice, _device);
} }
public IShader CompileShader(ShaderStage stage, ShaderBindings bindings, string code)
{
return new Shader(Api, _device, stage, bindings, code);
}
public IShader CompileShader(ShaderStage stage, ShaderBindings bindings, byte[] code)
{
return new Shader(Api, _device, stage, bindings, code);
}
public BufferHandle CreateBuffer(int size) public BufferHandle CreateBuffer(int size)
{ {
return BufferManager.CreateWithHandle(this, size, false); return BufferManager.CreateWithHandle(this, size, false);
} }
public IProgram CreateProgram(IShader[] shaders, ShaderInfo info) public IProgram CreateProgram(ShaderSource[] sources, ShaderInfo info)
{ {
bool isCompute = shaders.Length == 1 && ((Shader)shaders[0]).StageFlags == ShaderStageFlags.ShaderStageComputeBit; bool isCompute = sources.Length == 1 && sources[0].Stage == ShaderStage.Compute;
if (info.BackgroundCompile && (info.State.HasValue || isCompute) && VulkanConfiguration.UseDynamicState) if (info.BackgroundCompile && (info.State.HasValue || isCompute) && VulkanConfiguration.UseDynamicState)
{ {
return new ShaderCollection(this, _device, shaders, info.State.Value); return new ShaderCollection(this, _device, sources, info.State.Value);
} }
else else
{ {
return new ShaderCollection(this, _device, shaders); return new ShaderCollection(this, _device, sources);
} }
} }
public IProgram CreateProgram(ShaderSource[] sources, ShaderInfo info)
{
IShader[] shaders = new IShader[sources.Length];
for (int index = 0; index < sources.Length; index++)
{
var source = sources[index];
var shader = source.BinaryCode != null
? CompileShader(source.Stage, source.Bindings, source.BinaryCode)
: CompileShader(source.Stage, source.Bindings, source.Code);
shaders[index] = shader;
}
return CreateProgram(shaders, info);
}
public ISampler CreateSampler(GAL.SamplerCreateInfo info) public ISampler CreateSampler(GAL.SamplerCreateInfo info)
{ {
return new SamplerHolder(this, _device, info); return new SamplerHolder(this, _device, info);