ryujinx/src/Ryujinx.Graphics.Vulkan/Shader.cs
TSRBerry 801b71a128
[Ryujinx.Graphics.Vulkan] Address dotnet-format issues (#5378)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0060 warnings

* Silence dotnet format IDE0059 warnings

* Address dotnet format CA1816 warnings

* Fix new dotnet-format issues after rebase

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Format if-blocks correctly

* Another rebase, another dotnet format run

* Run dotnet format whitespace after rebase

* Run dotnet format style after rebase

* Run dotnet format analyzers after rebase

* Run dotnet format style after rebase

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Disable 'prefer switch expression' rule

* Add comments to disabled warnings

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Run dotnet format after rebase

* Address IDE0251 warnings

* Address a few disabled IDE0060 warnings

* Silence IDE0060 in .editorconfig

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* First dotnet format pass

* Fix naming rule violations

* Remove redundant code

* Rename generics

* Address review feedback

* Remove SetOrigin
2023-07-01 12:31:42 +02:00

161 lines
4.9 KiB
C#

using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Shader;
using shaderc;
using Silk.NET.Vulkan;
using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
namespace Ryujinx.Graphics.Vulkan
{
class Shader : IDisposable
{
// The shaderc.net dependency's Options constructor and dispose are not thread safe.
// Take this lock when using them.
private static readonly object _shaderOptionsLock = new();
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, shaderModuleCreateInfo, null, out _module).ThrowOnError();
}
CompileStatus = ProgramLinkStatus.Success;
});
}
private unsafe static byte[] GlslToSpirv(string glsl, ShaderStage stage)
{
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(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()[..(int)scr.CodeLength]);
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;
}
}
}
}