151 lines
4.8 KiB
C#
151 lines
4.8 KiB
C#
using Ryujinx.Common.Logging;
|
|
using Ryujinx.Graphics.GAL;
|
|
using Ryujinx.Graphics.Shader;
|
|
using Silk.NET.Shaderc;
|
|
using Silk.NET.Vulkan;
|
|
using System;
|
|
using System.Runtime.InteropServices;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Ryujinx.Graphics.Vulkan
|
|
{
|
|
class Shader : IDisposable
|
|
{
|
|
private static readonly IntPtr _ptrMainEntryPointName = Marshal.StringToHGlobalAnsi("main");
|
|
|
|
private readonly Vk _api;
|
|
private readonly Device _device;
|
|
private readonly ShaderStageFlags _stage;
|
|
|
|
private bool _disposed;
|
|
private ShaderModule _module;
|
|
|
|
public ShaderStageFlags StageFlags => _stage;
|
|
|
|
public ProgramLinkStatus CompileStatus { private set; get; }
|
|
|
|
public readonly Task CompileTask;
|
|
|
|
public unsafe Shader(Vk api, Device device, ShaderSource shaderSource)
|
|
{
|
|
_api = api;
|
|
_device = device;
|
|
|
|
CompileStatus = ProgramLinkStatus.Incomplete;
|
|
|
|
_stage = shaderSource.Stage.Convert();
|
|
|
|
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)
|
|
{
|
|
var shaderModuleCreateInfo = new ShaderModuleCreateInfo
|
|
{
|
|
SType = StructureType.ShaderModuleCreateInfo,
|
|
CodeSize = (uint)spirv.Length,
|
|
PCode = (uint*)pCode,
|
|
};
|
|
|
|
api.CreateShaderModule(device, in shaderModuleCreateInfo, null, out _module).ThrowOnError();
|
|
}
|
|
|
|
CompileStatus = ProgramLinkStatus.Success;
|
|
});
|
|
}
|
|
|
|
private unsafe static byte[] GlslToSpirv(string glsl, ShaderStage stage)
|
|
{
|
|
var api = Shaderc.GetApi();
|
|
var compiler = api.CompilerInitialize();
|
|
var options = api.CompileOptionsInitialize();
|
|
|
|
api.CompileOptionsSetSourceLanguage(options, SourceLanguage.Glsl);
|
|
api.CompileOptionsSetTargetSpirv(options, SpirvVersion.Shaderc15);
|
|
api.CompileOptionsSetTargetEnv(options, TargetEnv.Vulkan, Vk.Version12);
|
|
|
|
var scr = api.CompileIntoSpv(compiler, glsl, (nuint)glsl.Length, GetShaderCShaderStage(stage), "Ryu", "main", options);
|
|
|
|
var status = api.ResultGetCompilationStatus(scr);
|
|
|
|
if (status != CompilationStatus.Success)
|
|
{
|
|
Logger.Error?.Print(LogClass.Gpu, $"Shader compilation error: {status} {api.ResultGetErrorMessageS(scr)}");
|
|
|
|
return null;
|
|
}
|
|
|
|
var spirvBytes = new Span<byte>(api.ResultGetBytes(scr), (int)api.ResultGetLength(scr));
|
|
|
|
byte[] code = new byte[(spirvBytes.Length + 3) & ~3];
|
|
|
|
spirvBytes.CopyTo(code.AsSpan()[..spirvBytes.Length]);
|
|
|
|
api.CompilerRelease(compiler);
|
|
api.CompileOptionsRelease(options);
|
|
|
|
return code;
|
|
}
|
|
|
|
private static ShaderKind GetShaderCShaderStage(ShaderStage stage)
|
|
{
|
|
switch (stage)
|
|
{
|
|
case ShaderStage.Vertex:
|
|
return ShaderKind.GlslVertexShader;
|
|
case ShaderStage.Geometry:
|
|
return ShaderKind.GlslGeometryShader;
|
|
case ShaderStage.TessellationControl:
|
|
return ShaderKind.GlslTessControlShader;
|
|
case ShaderStage.TessellationEvaluation:
|
|
return ShaderKind.GlslTessEvaluationShader;
|
|
case ShaderStage.Fragment:
|
|
return ShaderKind.GlslFragmentShader;
|
|
case ShaderStage.Compute:
|
|
return ShaderKind.GlslComputeShader;
|
|
}
|
|
|
|
Logger.Debug?.Print(LogClass.Gpu, $"Invalid {nameof(ShaderStage)} enum value: {stage}.");
|
|
|
|
return ShaderKind.GlslVertexShader;
|
|
}
|
|
|
|
public unsafe PipelineShaderStageCreateInfo GetInfo()
|
|
{
|
|
return new PipelineShaderStageCreateInfo
|
|
{
|
|
SType = StructureType.PipelineShaderStageCreateInfo,
|
|
Stage = _stage,
|
|
Module = _module,
|
|
PName = (byte*)_ptrMainEntryPointName,
|
|
};
|
|
}
|
|
|
|
public void WaitForCompile()
|
|
{
|
|
CompileTask.Wait();
|
|
}
|
|
|
|
public unsafe void Dispose()
|
|
{
|
|
if (!_disposed)
|
|
{
|
|
_api.DestroyShaderModule(_device, _module, null);
|
|
_disposed = true;
|
|
}
|
|
}
|
|
}
|
|
}
|